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
This commit is contained in:
parent
cad9e14463
commit
a26ded47d9
7 changed files with 344 additions and 32 deletions
30
protocol/gtk-shell.xml
Normal file
30
protocol/gtk-shell.xml
Normal file
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
>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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue