diff --git a/protocol/gtk-shell.xml b/protocol/gtk-shell.xml
new file mode 100644
index 000000000..e2cc4f455
--- /dev/null
+++ b/protocol/gtk-shell.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index c07e44331..1c6195d37 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 f7769d091..3ca2b0a99 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 13ee3bbdb..73452cc27 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);
+ meta_window_set_title (window, new_title);
- if (window->frame)
- meta_ui_set_frame_title (window->screen->ui,
- window->frame->xwindow,
- window->title);
-
- g_object_notify (G_OBJECT (window), "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 5e87e5881..199799d24 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 deccf3474..1ce77f72d 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -37,6 +37,7 @@
#include
#include
+#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,
+ >k_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, >k_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,
+ >k_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 3926091c7..5957bceae 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