[gnome-builder] meson-templates: added Gtk4 C template



commit 62f49ddbc54db46ad44cc5a9f1ff06e08b202adc
Author: Günther Wagner <info gunibert de>
Date:   Sun Jul 18 16:38:57 2021 +0200

    meson-templates: added Gtk4 C template
    
    Introduce the first Gtk4 C template. Reworked also the example shown. It
    contains a application menu, shortcuts window, about dialog.

 .../meson-templates/meson-templates.gresource.xml  |   5 +
 src/plugins/meson-templates/meson_templates.py     |  88 ++++++++++++++++-
 src/plugins/meson-templates/resources/flatpak.json |   3 +
 .../meson-templates/resources/src/application.c    | 107 +++++++++++++++++++++
 .../meson-templates/resources/src/application.h    |  16 +++
 .../resources/src/hello.gresource.xml              |   3 +
 .../meson-templates/resources/src/help-overlay.ui  |  29 ++++++
 .../meson-templates/resources/src/main-gtk4.c      |  40 ++++++++
 .../resources/src/meson-c-vala.build               |   5 +
 .../meson-templates/resources/src/window-gtk4.ui   |  43 +++++++++
 10 files changed, 336 insertions(+), 3 deletions(-)
---
diff --git a/src/plugins/meson-templates/meson-templates.gresource.xml 
b/src/plugins/meson-templates/meson-templates.gresource.xml
index 5eff3df59..dbc7d1d2a 100644
--- a/src/plugins/meson-templates/meson-templates.gresource.xml
+++ b/src/plugins/meson-templates/meson-templates.gresource.xml
@@ -2,6 +2,8 @@
 <gresources>
   <gresource prefix="/plugins/meson_templates">
     <file compressed="true">resources/src/window.ui</file>
+    <file compressed="true">resources/src/window-gtk4.ui</file>
+    <file compressed="true">resources/src/help-overlay.ui</file>
     <file compressed="true">resources/src/window.js.tmpl</file>
     <file compressed="true">resources/src/meson-py.build</file>
     <file compressed="true">resources/src/window.h</file>
@@ -13,11 +15,14 @@
     <file compressed="true">resources/src/meson-rs.build</file>
     <file compressed="true">resources/src/hello.c</file>
     <file compressed="true">resources/src/hello.h</file>
+    <file compressed="true">resources/src/application.c</file>
+    <file compressed="true">resources/src/application.h</file>
     <file compressed="true">resources/src/__init__.py</file>
     <file compressed="true">resources/src/meson-c-vala.build</file>
     <file compressed="true">resources/src/meson-empty.build</file>
     <file compressed="true">resources/src/main.js.tmpl</file>
     <file compressed="true">resources/src/main.c</file>
+    <file compressed="true">resources/src/main-gtk4.c</file>
     <file compressed="true">resources/src/main-cli.c</file>
     <file compressed="true">resources/src/main.cpp</file>
     <file compressed="true">resources/src/main-cli.cpp</file>
diff --git a/src/plugins/meson-templates/meson_templates.py b/src/plugins/meson-templates/meson_templates.py
index 0cb974b73..b2001e429 100644
--- a/src/plugins/meson-templates/meson_templates.py
+++ b/src/plugins/meson-templates/meson_templates.py
@@ -33,7 +33,8 @@ _ = Ide.gettext
 
 class LibraryTemplateProvider(GObject.Object, Ide.TemplateProvider):
     def do_get_project_templates(self):
-        return [GnomeProjectTemplate(),
+        return [GnomeGTK4ProjectTemplate(),
+                GnomeProjectTemplate(),
                 LibraryProjectTemplate(),
                 CLIProjectTemplate(),
                 EmptyProjectTemplate()]
@@ -143,7 +144,8 @@ class MesonTemplate(Ide.TemplateBase, Ide.ProjectTemplate):
         scope.get('PreFix').assign_string(PreFix)
         scope.get('prefix_').assign_string(prefix_)
         scope.get('PREFIX').assign_string(PREFIX)
-
+        scope.get('spaces').assign_string(" " * len(prefix_))
+        scope.get('Spaces').assign_string(" " * len(PreFix))
 
         enable_gnome = isinstance(self, GnomeProjectTemplate)
         scope.get('project_version').assign_string('0.1.0')
@@ -246,7 +248,7 @@ class GnomeProjectTemplate(MesonTemplate):
     def __init__(self):
         super().__init__(
             'gnome-app',
-            _('GNOME Application'),
+            _('GNOME Application GTK+-3.0'),
             'pattern-gnome',
             _('Create a new GNOME application'),
             ['C', 'C++', 'C♯', 'Python', 'JavaScript', 'Vala', 'Rust'],
@@ -320,6 +322,86 @@ class GnomeProjectTemplate(MesonTemplate):
 
         files[meson_file] = 'src/meson.build'
 
+class GnomeGTK4ProjectTemplate(MesonTemplate):
+    def __init__(self):
+        super().__init__(
+            'gnome-app-gtk4',
+            _('GNOME Application GTK4'),
+            'pattern-gnome',
+            _('Create a new GNOME GTK4 application'),
+            ['C'],
+            0
+         )
+
+    def prepare_files(self, files):
+        # Shared files
+        files['resources/flatpak.json'] = '%(appid)s.json'
+        files['resources/data/hello.desktop.in'] = 'data/%(appid)s.desktop.in'
+        files['resources/data/hello.appdata.xml.in'] = 'data/%(appid)s.appdata.xml.in'
+        files['resources/data/hello.gschema.xml'] = 'data/%(appid)s.gschema.xml'
+        files['resources/data/meson.build'] = 'data/meson.build'
+        files['resources/data/icons/meson.build'] = 'data/icons/meson.build'
+        files['resources/data/icons/hicolor/scalable/apps/hello.svg'] = 
'data/icons/hicolor/scalable/apps/%(appid)s.svg'
+        files['resources/data/icons/hicolor/symbolic/apps/hello-symbolic.svg'] = 
'data/icons/hicolor/symbolic/apps/%(appid)s-symbolic.svg'
+        files['resources/build-aux/meson/postinstall.py'] = 'build-aux/meson/postinstall.py'
+        files['resources/po/LINGUAS'] = 'po/LINGUAS'
+        files['resources/po/meson.build'] = 'po/meson.build'
+        files['resources/po/POTFILES'] = 'po/POTFILES'
+        files['resources/src/help-overlay.ui'] = 'src/gtk/help-overlay.ui'
+        window_ui_name = 'src/window.ui'
+        resource_name = 'src/%(prefix)s.gresource.xml'
+        meson_file = 'resources/src/meson-c-vala.build'
+
+        if self.language == 'c':
+            files['resources/src/main-gtk4.c'] = 'src/main.c'
+            files['resources/src/window.c'] = 'src/%(prefix)s-window.c'
+            files['resources/src/window.h'] = 'src/%(prefix)s-window.h'
+            files['resources/src/application.c'] = 'src/%(prefix)s-application.c'
+            files['resources/src/application.h'] = 'src/%(prefix)s-application.h'
+            window_ui_name = 'src/%(prefix)s-window.ui'
+        elif self.language == 'c++':
+            files['resources/src/main.cpp'] = 'src/main.cpp'
+            files['resources/src/window.cpp'] = 'src/%(prefix)s-window.cpp'
+            files['resources/src/window.hpp'] = 'src/%(prefix)s-window.h'
+            window_ui_name = 'src/%(prefix)s-window.ui'
+        elif self.language == 'c♯':
+            files['resources/src/main.cs'] = 'src/main.cs'
+            files['resources/src/application.in'] = 'src/%(exec_name)s.in'
+            files['resources/flatpak-gtksharp.json.tmpl'] = '%(appid)s.json'
+            meson_file = 'resources/src/meson-cs.build'
+            resource_name = None
+            window_ui_name = None
+        elif self.language == 'vala':
+            files['resources/src/main.vala'] = 'src/main.vala'
+            files['resources/src/window.vala'] = 'src/window.vala'
+        elif self.language == 'javascript':
+            files['resources/src/main.js.tmpl'] = 'src/main.js'
+            files['resources/src/hello.js.in'] = 'src/%(appid)s.in'
+            files['resources/src/window.js.tmpl'] = 'src/window.js'
+            files['resources/src/hello.src.gresource.xml'] = 'src/%(appid)s.src.gresource.xml'
+            resource_name = 'src/%(appid)s.data.gresource.xml'
+            meson_file = 'resources/src/meson-js.build'
+        elif self.language == 'python':
+            files['resources/src/hello.py.in'] = 'src/%(name)s.in'
+            files['resources/src/__init__.py'] = 'src/__init__.py'
+            files['resources/src/window.py'] = 'src/window.py'
+            files['resources/src/main.py'] = 'src/main.py'
+            meson_file = 'resources/src/meson-py.build'
+        elif self.language == 'rust':
+            files['resources/src/config.rs.in'] = 'src/config.rs.in'
+            files['resources/src/main.rs'] = 'src/main.rs'
+            files['resources/src/window.rs'] = 'src/window.rs'
+            files['resources/src/Cargo.lock'] = 'Cargo.lock'
+            files['resources/src/Cargo.toml'] = 'Cargo.toml'
+            files['resources/build-aux/cargo.sh'] = 'build-aux/cargo.sh'
+            meson_file = 'resources/src/meson-rs.build'
+
+        if resource_name:
+            files['resources/src/hello.gresource.xml'] = resource_name
+        if window_ui_name:
+            files['resources/src/window-gtk4.ui'] = window_ui_name
+
+        files[meson_file] = 'src/meson.build'
 
 class LibraryProjectTemplate(MesonTemplate):
     def __init__(self):
diff --git a/src/plugins/meson-templates/resources/flatpak.json 
b/src/plugins/meson-templates/resources/flatpak.json
index 9574c9e09..9eba876b4 100644
--- a/src/plugins/meson-templates/resources/flatpak.json
+++ b/src/plugins/meson-templates/resources/flatpak.json
@@ -13,6 +13,9 @@
         "--share=network",
         "--share=ipc",
         "--socket=fallback-x11",
+{{if template == "gnome-app-gtk4"}}
+        "--device=dri",
+{{endif}}
         "--socket=wayland"
     ],
 {{if language == "rust"}}
diff --git a/src/plugins/meson-templates/resources/src/application.c 
b/src/plugins/meson-templates/resources/src/application.c
new file mode 100644
index 000000000..ae844bd22
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/application.c
@@ -0,0 +1,107 @@
+{{include "license.c"}}
+
+#include "{{prefix}}-application.h"
+#include "{{prefix}}-window.h"
+
+struct _{{PreFix}}Application
+{
+  GtkApplication parent_instance;
+};
+
+G_DEFINE_TYPE ({{PreFix}}Application, {{prefix_}}_application, GTK_TYPE_APPLICATION)
+
+{{PreFix}}Application *
+{{prefix_}}_application_new (gchar *application_id,
+{{spaces}}                  GApplicationFlags  flags)
+{
+  return g_object_new ({{PREFIX}}_TYPE_APPLICATION,
+                       "application-id", application_id,
+                       "flags", flags,
+                       NULL);
+}
+
+static void
+{{prefix_}}_application_finalize (GObject *object)
+{
+  {{PreFix}}Application *self = ({{PreFix}}Application *)object;
+
+  G_OBJECT_CLASS ({{prefix_}}_application_parent_class)->finalize (object);
+}
+
+static void
+{{prefix_}}_application_activate (GApplication *app)
+{
+  GtkWindow *window;
+
+  /* It's good practice to check your parameters at the beginning of the
+   * function. It helps catch errors early and in development instead of
+   * by your users.
+   */
+  g_assert (GTK_IS_APPLICATION (app));
+
+  /* Get the current window or create one if necessary. */
+  window = gtk_application_get_active_window (GTK_APPLICATION (app));
+  if (window == NULL)
+    window = g_object_new ({{PREFIX}}_TYPE_WINDOW,
+                           "application", app,
+                           "default-width", 600,
+                           "default-height", 300,
+                           NULL);
+
+  /* Ask the window manager/compositor to present the window. */
+  gtk_window_present (window);
+}
+
+
+static void
+{{prefix_}}_application_class_init ({{PreFix}}ApplicationClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
+
+  object_class->finalize = {{prefix_}}_application_finalize;
+
+  /*
+   * We connect to the activate callback to create a window when the application
+   * has been launched. Additionally, this callback notifies us when the user
+   * tries to launch a "second instance" of the application. When they try
+   * to do that, we'll just present any existing window.
+   */
+  app_class->activate = {{prefix_}}_application_activate;
+}
+
+static void
+{{prefix_}}_application_show_about (GSimpleAction *action,
+{{spaces}}                         GVariant      *parameter,
+{{spaces}}                         gpointer       user_data)
+{
+  {{PreFix}}Application *self = {{PREFIX}}_APPLICATION (user_data);
+  GtkWindow *window = NULL;
+  const gchar *authors[] = {"{{author}}", NULL};
+
+  g_return_if_fail ({{PREFIX}}_IS_APPLICATION (self));
+
+  window = gtk_application_get_active_window (GTK_APPLICATION (self));
+
+  gtk_show_about_dialog (window,
+                         "program-name", "{{name}}",
+                         "authors", authors,
+                         "version", "{{project_version}}",
+                         NULL);
+}
+
+
+static void
+{{prefix_}}_application_init ({{PreFix}}Application *self)
+{
+  GSimpleAction *quit_action = g_simple_action_new ("quit", NULL);
+  g_signal_connect_swapped (quit_action, "activate", G_CALLBACK (g_application_quit), self);
+  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (quit_action));
+
+  GSimpleAction *about_action = g_simple_action_new ("about", NULL);
+  g_signal_connect (about_action, "activate", G_CALLBACK ({{prefix_}}_application_show_about), self);
+  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (about_action));
+
+  const char *accels[] = {"<primary>q", NULL};
+  gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.quit", accels);
+}
diff --git a/src/plugins/meson-templates/resources/src/application.h 
b/src/plugins/meson-templates/resources/src/application.h
new file mode 100644
index 000000000..d4a9bada0
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/application.h
@@ -0,0 +1,16 @@
+{{include "license.h"}}
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define {{PREFIX}}_TYPE_APPLICATION ({{prefix_}}_application_get_type())
+
+G_DECLARE_FINAL_TYPE ({{PreFix}}Application, {{prefix_}}_application, {{PREFIX}}, APPLICATION, 
GtkApplication)
+
+{{PreFix}}Application *{{prefix_}}_application_new (gchar *application_id,
+{{Spaces}}{{spaces}}                               GApplicationFlags  flags);
+
+G_END_DECLS
diff --git a/src/plugins/meson-templates/resources/src/hello.gresource.xml 
b/src/plugins/meson-templates/resources/src/hello.gresource.xml
index ff0db9372..bc5275809 100644
--- a/src/plugins/meson-templates/resources/src/hello.gresource.xml
+++ b/src/plugins/meson-templates/resources/src/hello.gresource.xml
@@ -2,5 +2,8 @@
 <gresources>
   <gresource prefix="{{appid_path}}">
     <file>{{ui_file}}</file>
+{{if template == "gnome-app-gtk4"}}
+    <file>gtk/help-overlay.ui</file>
+{{end}}
   </gresource>
 </gresources>
diff --git a/src/plugins/meson-templates/resources/src/help-overlay.ui 
b/src/plugins/meson-templates/resources/src/help-overlay.ui
new file mode 100644
index 000000000..ef12f02e8
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/help-overlay.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkShortcutsWindow" id="help_overlay">
+    <property name="modal">True</property>
+    <child>
+      <object class="GtkShortcutsSection">
+        <property name="section-name">shortcuts</property>
+        <property name="max-height">10</property>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes" context="shortcut window">General</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes" context="shortcut window">Show Shortcuts</property>
+                <property name="action-name">win.show-help-overlay</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes" context="shortcut window">Quit</property>
+                <property name="action-name">app.quit</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/src/plugins/meson-templates/resources/src/main-gtk4.c 
b/src/plugins/meson-templates/resources/src/main-gtk4.c
new file mode 100644
index 000000000..5dd33a8db
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/main-gtk4.c
@@ -0,0 +1,40 @@
+{{include "license.c"}}
+
+#include <glib/gi18n.h>
+
+#include "{{prefix}}-config.h"
+#include "{{prefix}}-application.h"
+
+int
+main (int   argc,
+      char *argv[])
+{
+  g_autoptr({{PreFix}}Application) app = NULL;
+  int ret;
+
+  /* Set up gettext translations */
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+  textdomain (GETTEXT_PACKAGE);
+
+  /*
+   * Create a new GtkApplication. The application manages our main loop,
+   * application windows, integration with the window manager/compositor, and
+   * desktop features such as file opening and single-instance applications.
+   */
+  app = {{prefix_}}_application_new ("{{appid}}", G_APPLICATION_FLAGS_NONE);
+
+  /*
+   * Run the application. This function will block until the application
+   * exits. Upon return, we have our exit code to return to the shell. (This
+   * is the code you see when you do `echo $?` after running a command in a
+   * terminal.
+   *
+   * Since GtkApplication inherits from GApplication, we use the parent class
+   * method "run". But we need to cast, which is what the "G_APPLICATION()"
+   * macro does.
+   */
+  ret = g_application_run (G_APPLICATION (app), argc, argv);
+
+  return ret;
+}
diff --git a/src/plugins/meson-templates/resources/src/meson-c-vala.build 
b/src/plugins/meson-templates/resources/src/meson-c-vala.build
index baf5414d4..a9abe1061 100644
--- a/src/plugins/meson-templates/resources/src/meson-c-vala.build
+++ b/src/plugins/meson-templates/resources/src/meson-c-vala.build
@@ -2,6 +2,9 @@
 {{if language == "c"}}
   'main.c',
   '{{prefix}}-window.c',
+  {{if template == "gnome-app-gtk4"}}
+  '{{prefix}}-application.c',
+  {{end}}
 {{else if language == "c++"}}
   'main.cpp',
   '{{prefix}}-window.cpp',
@@ -14,6 +17,8 @@
 {{name_}}_deps = [
 {{if language == "c++"}}
   dependency('gtkmm-3.0', version: '>= 3.18'),
+{{else if template == "gnome-app-gtk4"}}
+  dependency('gtk4'),
 {{else}}
   dependency('gio-2.0', version: '>= 2.50'),
   dependency('gtk+-3.0', version: '>= 3.22'),
diff --git a/src/plugins/meson-templates/resources/src/window-gtk4.ui 
b/src/plugins/meson-templates/resources/src/window-gtk4.ui
new file mode 100644
index 000000000..27cbb075b
--- /dev/null
+++ b/src/plugins/meson-templates/resources/src/window-gtk4.ui
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="{{PreFix}}Window" parent="GtkApplicationWindow">
+    <property name="default-width">600</property>
+    <property name="default-height">300</property>
+    <child type="titlebar">
+      <object class="GtkHeaderBar" id="header_bar">
+        <child type="end">
+          <object class="GtkMenuButton">
+            <property name="icon-name">open-menu-symbolic</property>
+            <property name="menu-model">primary_menu</property>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="label">
+        <property name="label">Hello, World!</property>
+        <attributes>
+          <attribute name="weight" value="bold"/>
+          <attribute name="scale" value="2"/>
+        </attributes>
+      </object>
+    </child>
+  </template>
+
+  <menu id="primary_menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">_Preferences</attribute>
+        <attribute name="action">app.preferences</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
+        <attribute name="action">win.show-help-overlay</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_About GTK Rust Template</attribute>
+        <attribute name="action">app.about</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]