[mutter/wayland] Add a private gtk-mutter protocol



commit a26ded47d9e80a2de4b8ade86e33f0c4f6b1b965
Author: Giovanni Campagna <gcampagn redhat com>
Date:   Fri Aug 30 09:40:36 2013 +0200

    Add a private gtk-mutter protocol
    
    Add a new interface, gtk_shell, than can be used by gtk to
    retrieve a surface extension called gtk_surface, which will be
    used to communicate with mutter all the GTK extensions to EWMH
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707128
    
    Add support for GTK application menus
    
    To do so, we need to be able to set surface state before creating
    the MetaWindow, so we introduce MetaWaylandSurfaceInitialState as
    a staging area.
    The gtk-shell-surface implementation would either write to the
    initial state, or directly to the window.
    
    At the same, implement set_title and set_class too, because it's
    easy enough.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707128

 protocol/gtk-shell.xml             |   30 ++++++
 src/Makefile.am                    |    3 +
 src/core/window-private.h          |   13 +++
 src/core/window-props.c            |   43 +++------
 src/core/window.c                  |   80 +++++++++++++++-
 src/wayland/meta-wayland-surface.c |  188 +++++++++++++++++++++++++++++++++++-
 src/wayland/meta-wayland-surface.h |   21 ++++
 7 files changed, 345 insertions(+), 33 deletions(-)
---
diff --git a/protocol/gtk-shell.xml b/protocol/gtk-shell.xml
new file mode 100644
index 0000000..e2cc4f4
--- /dev/null
+++ b/protocol/gtk-shell.xml
@@ -0,0 +1,30 @@
+<protocol name="gtk">
+
+  <interface name="gtk_shell" version="1">
+    <enum name="capability">
+      <entry name="global_app_menu" value="1"/>
+      <entry name="global_menu_bar" value="2"/>
+    </enum>
+
+    <event name="capabilities">
+      <arg name="capabilities" type="uint"/>
+    </event>
+
+    <request name="get_gtk_surface">
+      <arg name="gtk_surface" type="new_id" interface="gtk_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="gtk_surface" version="1">
+    <request name="set_dbus_properties">
+      <arg name="application_id" type="string" allow-null="true"/>
+      <arg name="app_menu_path" type="string" allow-null="true"/>
+      <arg name="menubar_path" type="string" allow-null="true"/>
+      <arg name="window_object_path" type="string" allow-null="true"/>
+      <arg name="application_object_path" type="string" allow-null="true"/>
+      <arg name="unique_bus_name" type="string" allow-null="true"/>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/src/Makefile.am b/src/Makefile.am
index c07e443..1c6195d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,6 +40,9 @@ mutter_built_sources = \
        $(dbus_xrandr_built_sources)            \
        mutter-enum-types.h                     \
        mutter-enum-types.c                     \
+       wayland/gtk-shell-protocol.c            \
+       wayland/gtk-shell-server-protocol.h     \
+       wayland/gtk-shell-client-protocol.h     \
        wayland/xserver-protocol.c              \
        wayland/xserver-server-protocol.h       \
        wayland/xserver-client-protocol.h
diff --git a/src/core/window-private.h b/src/core/window-private.h
index f7769d0..3ca2b0a 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -703,4 +703,17 @@ void meta_window_set_shape_region         (MetaWindow     *window,
                                            cairo_region_t *region);
 void meta_window_update_shape_region_x11  (MetaWindow *window);
 
+void meta_window_set_title                (MetaWindow *window,
+                                           const char *title);
+void meta_window_set_wm_class             (MetaWindow *window,
+                                           const char *wm_class,
+                                           const char *wm_instance);
+void meta_window_set_gtk_dbus_properties  (MetaWindow *window,
+                                           const char *application_id,
+                                           const char *unique_bus_name,
+                                           const char *appmenu_path,
+                                           const char *menubar_path,
+                                           const char *application_object_path,
+                                           const char *window_object_path);
+
 #endif
diff --git a/src/core/window-props.c b/src/core/window-props.c
index 13ee3bb..73452cc 100644
--- a/src/core/window-props.c
+++ b/src/core/window-props.c
@@ -489,28 +489,19 @@ static void
 set_window_title (MetaWindow *window,
                   const char *title)
 {
-  char *str;
+  char *new_title = NULL;
  
   gboolean modified =
     set_title_text (window,
                     window->using_net_wm_visible_name,
                     title,
                     window->display->atom__NET_WM_VISIBLE_NAME,
-                    &window->title);
+                    &new_title);
   window->using_net_wm_visible_name = modified;
   
-  /* strndup is a hack since GNU libc has broken %.10s */
-  str = g_strndup (window->title, 10);
-  g_free (window->desc);
-  window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str);
-  g_free (str);
-
-  if (window->frame)
-    meta_ui_set_frame_title (window->screen->ui,
-                             window->frame->xwindow,
-                             window->title);
-
-  g_object_notify (G_OBJECT (window), "title");
+  meta_window_set_title (window, new_title);
+
+  g_free (new_title);
 }
 
 static void
@@ -875,23 +866,15 @@ reload_wm_class (MetaWindow    *window,
                  MetaPropValue *value,
                  gboolean       initial)
 {
-  if (window->res_class)
-    g_free (window->res_class);
-  if (window->res_name)
-    g_free (window->res_name);
-
-  window->res_class = NULL;
-  window->res_name = NULL;
-
   if (value->type != META_PROP_VALUE_INVALID)
-    { 
-      if (value->v.class_hint.res_name)
-        window->res_name = g_strdup (value->v.class_hint.res_name);
-
-      if (value->v.class_hint.res_class)
-        window->res_class = g_strdup (value->v.class_hint.res_class);
-
-      g_object_notify (G_OBJECT (window), "wm-class");
+    {
+      meta_window_set_wm_class (window,
+                                value->v.class_hint.res_class,
+                                value->v.class_hint.res_name);
+    }
+  else
+    {
+      meta_window_set_wm_class (window, NULL, NULL);
     }
 
   meta_verbose ("Window %s class: '%s' name: '%s'\n",
diff --git a/src/core/window.c b/src/core/window.c
index 5e87e58..199799d 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1064,7 +1064,10 @@ meta_window_new_shared (MetaDisplay         *display,
   window->xgroup_leader = None;
   meta_window_compute_group (window);
 
-  meta_window_load_initial_properties (window);
+  if (client_type == META_WINDOW_CLIENT_TYPE_X11)
+    meta_window_load_initial_properties (window);
+  else
+    meta_wayland_surface_set_initial_state (window->surface, window);
 
   if (!window->override_redirect &&
       client_type == META_WINDOW_CLIENT_TYPE_X11)
@@ -11467,3 +11470,78 @@ meta_window_can_close (MetaWindow *window)
 {
   return window->has_close_func;
 }
+
+void
+meta_window_set_title (MetaWindow *window,
+                       const char *title)
+{
+  char *str;
+
+  g_free (window->title);
+  window->title = g_strdup (title);
+
+  /* strndup is a hack since GNU libc has broken %.10s */
+  str = g_strndup (window->title, 10);
+  g_free (window->desc);
+  window->desc = g_strdup_printf ("0x%lx (%s)", window->xwindow, str);
+  g_free (str);
+
+  if (window->frame)
+    meta_ui_set_frame_title (window->screen->ui,
+                             window->frame->xwindow,
+                             window->title);
+
+  g_object_notify (G_OBJECT (window), "title");
+}
+
+void
+meta_window_set_wm_class (MetaWindow *window,
+                          const char *wm_class,
+                          const char *wm_instance)
+{
+  g_free (window->res_class);
+  g_free (window->res_name);
+
+  window->res_name = g_strdup (wm_instance);
+  window->res_class = g_strdup (wm_class);
+
+  g_object_notify (G_OBJECT (window), "wm-class");
+}
+
+void
+meta_window_set_gtk_dbus_properties (MetaWindow *window,
+                                     const char *application_id,
+                                     const char *unique_bus_name,
+                                     const char *appmenu_path,
+                                     const char *menubar_path,
+                                     const char *application_object_path,
+                                     const char *window_object_path)
+{
+  g_object_freeze_notify (G_OBJECT (window));
+
+  g_free (window->gtk_application_id);
+  window->gtk_application_id = g_strdup (application_id);
+  g_object_notify (G_OBJECT (window), "gtk-application-id");
+
+  g_free (window->gtk_unique_bus_name);
+  window->gtk_unique_bus_name = g_strdup (unique_bus_name);
+  g_object_notify (G_OBJECT (window), "gtk-unique-bus-name");
+
+  g_free (window->gtk_app_menu_object_path);
+  window->gtk_app_menu_object_path = g_strdup (appmenu_path);
+  g_object_notify (G_OBJECT (window), "gtk-app-menu-object-path");
+
+  g_free (window->gtk_menubar_object_path);
+  window->gtk_menubar_object_path = g_strdup (menubar_path);
+  g_object_notify (G_OBJECT (window), "gtk-menubar-object-path");
+
+  g_free (window->gtk_application_object_path);
+  window->gtk_application_object_path = g_strdup (application_object_path);
+  g_object_notify (G_OBJECT (window), "gtk-application-object-path");
+
+  g_free (window->gtk_window_object_path);
+  window->gtk_window_object_path = g_strdup (window_object_path);
+  g_object_notify (G_OBJECT (window), "gtk-window-object-path");
+
+  g_object_thaw_notify (G_OBJECT (window));
+}
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index deccf34..1ce77f7 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -37,6 +37,7 @@
 #include <unistd.h>
 
 #include <wayland-server.h>
+#include "gtk-shell-server-protocol.h"
 
 #include "meta-wayland-private.h"
 #include "meta-xwayland-private.h"
@@ -56,6 +57,9 @@
 #include "meta-weston-launch.h"
 #include "monitor-private.h"
 
+static void ensure_initial_state (MetaWaylandSurface *surface);
+static void free_initial_state   (MetaWaylandSurfaceInitialState *surface);
+
 static void
 surface_process_damage (MetaWaylandSurface *surface,
                         cairo_region_t *region)
@@ -336,6 +340,9 @@ meta_wayland_surface_free (MetaWaylandSurface *surface)
   MetaWaylandCompositor *compositor = surface->compositor;
   MetaWaylandFrameCallback *cb, *next;
 
+  if (surface->initial_state)
+    free_initial_state (surface->initial_state);
+
   compositor->surfaces = g_list_remove (compositor->surfaces, surface);
 
   meta_wayland_buffer_reference (&surface->buffer_ref, NULL);
@@ -737,7 +744,15 @@ shell_surface_set_title (struct wl_client *client,
   MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
   MetaWaylandSurface *surface = extension->surface;
 
-  g_warning ("TODO: support shell_surface_set_title request");
+  if (surface->window)
+    meta_window_set_title (surface->window, title);
+  else
+    {
+      ensure_initial_state (surface);
+
+      g_free (surface->initial_state->title);
+      surface->initial_state->title = g_strdup (title);
+    }
 }
 
 static void
@@ -748,7 +763,15 @@ shell_surface_set_class (struct wl_client *client,
   MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
   MetaWaylandSurface *surface = extension->surface;
 
-  g_warning ("TODO: support shell_surface_set_class request");
+  if (surface->window)
+    meta_window_set_wm_class (surface->window, class_, class_);
+  else
+    {
+      ensure_initial_state (surface);
+
+      g_free (surface->initial_state->wm_class);
+      surface->initial_state->wm_class = g_strdup (class_);
+    }
 }
 
 static const struct wl_shell_surface_interface meta_wayland_shell_surface_interface =
@@ -852,6 +875,111 @@ bind_shell (struct wl_client *client,
   wl_resource_set_implementation (resource, &meta_wayland_shell_interface, data, NULL);
 }
 
+static void
+set_dbus_properties (struct wl_client   *client,
+                    struct wl_resource *resource,
+                    const char         *application_id,
+                    const char         *app_menu_path,
+                    const char         *menubar_path,
+                    const char         *window_object_path,
+                    const char         *application_object_path,
+                    const char         *unique_bus_name)
+{
+  MetaWaylandSurfaceExtension *extension = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = extension->surface;
+
+  if (surface == NULL)
+    {
+      wl_resource_post_error (resource,
+                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "object is not associated with a toplevel surface");
+      return;
+    }
+
+  if (surface->window)
+    {
+      meta_window_set_gtk_dbus_properties (surface->window,
+                                          application_id,
+                                          unique_bus_name,
+                                          app_menu_path,
+                                          menubar_path,
+                                          application_object_path,
+                                          window_object_path);
+    }
+  else
+    {
+      MetaWaylandSurfaceInitialState *initial;
+
+      ensure_initial_state (surface);
+      initial = surface->initial_state;
+
+      g_free (initial->gtk_application_id);
+      initial->gtk_application_id = g_strdup (application_id);
+
+      g_free (initial->gtk_unique_bus_name);
+      initial->gtk_unique_bus_name = g_strdup (unique_bus_name);
+
+      g_free (initial->gtk_app_menu_path);
+      initial->gtk_app_menu_path = g_strdup (app_menu_path);
+
+      g_free (initial->gtk_menubar_path);
+      initial->gtk_menubar_path = g_strdup (menubar_path);
+
+      g_free (initial->gtk_application_object_path);
+      initial->gtk_application_object_path = g_strdup (application_object_path);
+
+      g_free (initial->gtk_window_object_path);
+      initial->gtk_window_object_path = g_strdup (window_object_path);
+    }
+}
+
+static const struct gtk_surface_interface meta_wayland_gtk_surface_interface =
+{
+  set_dbus_properties
+};
+
+static void
+get_gtk_surface (struct wl_client *client,
+                struct wl_resource *resource,
+                guint32 id,
+                struct wl_resource *surface_resource)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+
+  if (surface->has_gtk_surface)
+    {
+      wl_resource_post_error (surface_resource,
+                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "wl_shell::get_gtk_surface already requested");
+      return;
+    }
+
+  create_surface_extension (client, resource, id, surface,
+                           &gtk_surface_interface,
+                           &meta_wayland_gtk_surface_interface);
+  surface->has_gtk_surface = TRUE;
+}
+
+static const struct gtk_shell_interface meta_wayland_gtk_shell_interface =
+{
+  get_gtk_surface
+};
+
+static void
+bind_gtk_shell (struct wl_client *client,
+               void             *data,
+               guint32           version,
+               guint32           id)
+{
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client, &gtk_shell_interface, version, id);
+  wl_resource_set_implementation (resource, &meta_wayland_gtk_shell_interface, data, NULL);
+
+  /* FIXME: ask the plugin */
+  gtk_shell_send_capabilities (resource, GTK_SHELL_CAPABILITY_GLOBAL_APP_MENU);
+}
+
 void
 meta_wayland_init_shell (MetaWaylandCompositor *compositor)
 {
@@ -859,5 +987,61 @@ meta_wayland_init_shell (MetaWaylandCompositor *compositor)
                        &wl_shell_interface, 1,
                        compositor, bind_shell) == NULL)
     g_error ("Failed to register a global shell object");
+
+  if (wl_global_create (compositor->wayland_display,
+                       &gtk_shell_interface, 1,
+                       compositor, bind_gtk_shell) == NULL)
+    g_error ("Failed to register a global gtk-shell object");
 }
 
+void
+meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
+                                       MetaWindow         *window)
+{
+  MetaWaylandSurfaceInitialState *initial = surface->initial_state;
+
+  if (initial == NULL)
+    return;
+
+  if (initial->title)
+    meta_window_set_title (window, initial->title);
+
+  if (initial->wm_class)
+    meta_window_set_wm_class (window, initial->wm_class, initial->wm_class);
+
+  meta_window_set_gtk_dbus_properties (window,
+                                      initial->gtk_application_id,
+                                      initial->gtk_unique_bus_name,
+                                      initial->gtk_app_menu_path,
+                                      initial->gtk_menubar_path,
+                                      initial->gtk_application_object_path,
+                                      initial->gtk_window_object_path);
+
+  free_initial_state (initial);
+  surface->initial_state = NULL;
+}
+
+static void
+ensure_initial_state (MetaWaylandSurface *surface)
+{
+  if (surface->initial_state)
+    return;
+
+  surface->initial_state = g_slice_new0 (MetaWaylandSurfaceInitialState);
+}
+
+static void
+free_initial_state (MetaWaylandSurfaceInitialState *initial)
+{
+  g_free (initial->title);
+  g_free (initial->wm_class);
+
+  g_free (initial->gtk_application_id);
+  g_free (initial->gtk_unique_bus_name);
+  g_free (initial->gtk_app_menu_path);
+  g_free (initial->gtk_menubar_path);
+  g_free (initial->gtk_application_object_path);
+  g_free (initial->gtk_window_object_path);
+
+  g_slice_free (MetaWaylandSurfaceInitialState, initial);
+}
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 3926091..5957bce 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -65,6 +65,19 @@ typedef struct
   struct wl_list frame_callback_list;
 } MetaWaylandDoubleBufferedState;
 
+typedef struct
+{
+  char *title;
+  char *wm_class;
+
+  char *gtk_application_id;
+  char *gtk_unique_bus_name;
+  char *gtk_app_menu_path;
+  char *gtk_menubar_path;
+  char *gtk_application_object_path;
+  char *gtk_window_object_path;
+} MetaWaylandSurfaceInitialState;
+
 struct _MetaWaylandSurface
 {
   struct wl_resource *resource;
@@ -75,9 +88,14 @@ struct _MetaWaylandSurface
   MetaWaylandBufferReference buffer_ref;
   MetaWindow *window;
   gboolean has_shell_surface;
+  gboolean has_gtk_surface;
 
   /* All the pending state, that wl_surface.commit will apply. */
   MetaWaylandDoubleBufferedState pending;
+
+  /* All the initial state, that wl_shell_surface.set_* will apply
+     (through meta_window_new_for_wayland) */
+  MetaWaylandSurfaceInitialState *initial_state;
 };
 
 typedef struct
@@ -95,4 +113,7 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit
                                                 guint32                version);
 void                meta_wayland_surface_free   (MetaWaylandSurface    *surface);
 
+void                meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
+                                                           MetaWindow         *window);
+
 #endif


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