Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions debian/libxapp1.symbols
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
libxapp.so.1 libxapp1 #MINVER#
_favorite_vfs_file_new_for_info@Base 2.0.7
_xapp_favorites_get_display_names@Base 2.0.7
(optional)_xapp_wayland_update_icon_name@Base 3.3.1
(optional)_xapp_wayland_update_progress@Base 3.3.1
(optional)_xapp_wayland_window_unrealized@Base 3.3.1
_xapp_x11_set_xid_icon_name@Base 3.3.1
_xapp_x11_set_xid_progress@Base 3.3.1
_xapp_x11_set_xid_progress_pulse@Base 3.3.1
_xapp_x11_update_icon_name@Base 3.3.1
_xapp_x11_update_progress@Base 3.3.1
create_blanking_window@Base 1.4.9
debug_flag_to_string@Base 2.4.2
fav_uri_to_display_name@Base 2.0.7
Expand Down
35 changes: 34 additions & 1 deletion libxapp/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,39 @@ if gtk_layer_shell_dep.found()
libxapp_c_args += '-DHAVE_GTK_LAYER_SHELL=1'
endif

# XAppGtkWindow display-server backends. The X11 backend (the _NET_WM_XAPP_*
# window properties) is always built; the Wayland backend (the private
# xapp-shell protocol) is built when the wayland tooling is available. Kept out
# of the introspected sources below - they expose no public API.
xapp_backend_sources = [ 'xapp-gtk-window-x11.c' ]
xapp_wayland_generated = []

wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true)
wayland_client_dep = dependency('wayland-client', required: false)
gdk_wayland_dep = dependency('gdk-wayland-3.0', required: false)

if wayland_scanner_dep.found() and wayland_client_dep.found() and gdk_wayland_dep.found()
wayland_scanner = find_program(wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'),
native: true)

xapp_shell_client_header = custom_target('xapp-shell client header',
input: 'xapp-shell.xml',
output: 'xapp-shell-client-protocol.h',
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])

xapp_shell_code = custom_target('xapp-shell code',
input: 'xapp-shell.xml',
output: 'xapp-shell-protocol.c',
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'])

xapp_wayland_generated = [ xapp_shell_client_header, xapp_shell_code ]
xapp_backend_sources += 'xapp-gtk-window-wayland.c'

libdeps += wayland_client_dep
libdeps += gdk_wayland_dep
libxapp_c_args += '-DHAVE_WAYLAND=1'
endif

favorite_vfs_sources = [
'favorite-vfs-file.c',
'favorite-vfs-file-enumerator.c',
Expand Down Expand Up @@ -105,7 +138,7 @@ xapp_enums = gnome.mkenums_simple('xapp-enums',
)

libxapp = library('xapp',
sources : xapp_headers + xapp_sources + xapp_enums + dbus_headers + favorite_vfs_sources + xapp_debug,
sources : xapp_headers + xapp_sources + xapp_enums + dbus_headers + favorite_vfs_sources + xapp_debug + xapp_backend_sources + xapp_wayland_generated,
include_directories: [top_inc],
version: meson.project_version(),
soversion: '1',
Expand Down
36 changes: 36 additions & 0 deletions libxapp/xapp-gtk-window-backend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef __XAPP_GTK_WINDOW_BACKEND_H__
#define __XAPP_GTK_WINDOW_BACKEND_H__

#include <gtk/gtk.h>

G_BEGIN_DECLS

/* X11 backend - always built.
* Each setter is a no-op when the default display is not an X11 display. */
void _xapp_x11_update_icon_name (GtkWindow *window,
const gchar *icon_str);
void _xapp_x11_update_progress (GtkWindow *window,
guint progress,
gboolean pulse);
void _xapp_x11_set_xid_icon_name (gulong xid,
const gchar *icon_str);
void _xapp_x11_set_xid_progress (gulong xid,
gint progress);
void _xapp_x11_set_xid_progress_pulse (gulong xid,
gboolean pulse);

#ifdef HAVE_WAYLAND
/* Wayland backend - drives the private xapp-shell protocol.
* Each setter is a no-op when the window is not a Wayland window or the
* compositor does not implement xapp-shell. */
void _xapp_wayland_update_icon_name (GtkWindow *window,
const gchar *icon_str);
void _xapp_wayland_update_progress (GtkWindow *window,
guint progress,
gboolean pulse);
void _xapp_wayland_window_unrealized (GtkWindow *window);
#endif

G_END_DECLS

#endif /* __XAPP_GTK_WINDOW_BACKEND_H__ */
202 changes: 202 additions & 0 deletions libxapp/xapp-gtk-window-wayland.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#include <config.h>

#include <gdk/gdk.h>
#include <gdk/gdkwayland.h>
#include <wayland-client.h>

#include "xapp-gtk-window-backend.h"
#include "xapp-shell-client-protocol.h"

#define DISPLAY_DATA_KEY "xapp-wayland-shell-data"
#define SURFACE_DATA_KEY "xapp-wayland-surface"

typedef struct
{
struct xapp_shell1 *shell;
uint32_t capabilities;
} XAppWaylandShell;

static void
shell_handle_capabilities (void *data,
struct xapp_shell1 *shell,
uint32_t capabilities)
{
XAppWaylandShell *wd = data;

wd->capabilities = capabilities;
}

static const struct xapp_shell1_listener shell_listener = {
shell_handle_capabilities,
};

static void
registry_handle_global (void *data,
struct wl_registry *registry,
uint32_t id,
const char *interface,
uint32_t version)
{
XAppWaylandShell *wd = data;

if (g_strcmp0 (interface, xapp_shell1_interface.name) == 0)
{
wd->shell = wl_registry_bind (registry, id, &xapp_shell1_interface,
MIN (version, 1u));
xapp_shell1_add_listener (wd->shell, &shell_listener, wd);
}
}

static void
registry_handle_global_remove (void *data,
struct wl_registry *registry,
uint32_t id)
{
}

static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove,
};

static void
free_shell_data (gpointer data)
{
XAppWaylandShell *wd = data;

if (wd->shell)
xapp_shell1_destroy (wd->shell);

g_free (wd);
}

/* Bind (once per display) the xapp_shell1 global from the registry, using a
* private event queue so our blocking roundtrips don't dispatch GTK's events. */
static XAppWaylandShell *
ensure_shell (GdkDisplay *display)
{
XAppWaylandShell *wd;
struct wl_display *wl_display;
struct wl_event_queue *queue;
struct wl_registry *registry;

if (!GDK_IS_WAYLAND_DISPLAY (display))
return NULL;

wd = g_object_get_data (G_OBJECT (display), DISPLAY_DATA_KEY);
if (wd)
return wd;

wd = g_new0 (XAppWaylandShell, 1);

wl_display = gdk_wayland_display_get_wl_display (GDK_WAYLAND_DISPLAY (display));
queue = wl_display_create_queue (wl_display);
registry = wl_display_get_registry (wl_display);
wl_proxy_set_queue ((struct wl_proxy *) registry, queue);
wl_registry_add_listener (registry, &registry_listener, wd);

/* First roundtrip processes the globals (binding the shell, if present). */
if (wl_display_roundtrip_queue (wl_display, queue) < 0)
g_warning ("XAppGtkWindow: Wayland roundtrip failed while querying for the xapp-shell global");
/* Second roundtrip processes the shell's 'capabilities' event. */
if (wd->shell && wl_display_roundtrip_queue (wl_display, queue) < 0)
g_warning ("XAppGtkWindow: Wayland roundtrip failed while querying xapp-shell capabilities");

wl_registry_destroy (registry);

/* The shell proxy must outlive the temporary queue, so move it back to the
* default queue. It receives no further events. */
if (wd->shell)
wl_proxy_set_queue ((struct wl_proxy *) wd->shell, NULL);

wl_event_queue_destroy (queue);

g_object_set_data_full (G_OBJECT (display), DISPLAY_DATA_KEY,
wd, free_shell_data);
return wd;
}

static struct xapp_surface1 *
ensure_xapp_surface (GtkWindow *window,
XAppWaylandShell *wd)
{
GdkWindow *gdk_window;
struct wl_surface *wl_surface;
struct xapp_surface1 *xapp_surface;

xapp_surface = g_object_get_data (G_OBJECT (window), SURFACE_DATA_KEY);
if (xapp_surface)
return xapp_surface;

gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
if (gdk_window == NULL || !GDK_IS_WAYLAND_WINDOW (gdk_window))
return NULL;

wl_surface = gdk_wayland_window_get_wl_surface (gdk_window);
if (wl_surface == NULL)
return NULL;

xapp_surface = xapp_shell1_get_xapp_surface (wd->shell, wl_surface);
g_object_set_data_full (G_OBJECT (window), SURFACE_DATA_KEY,
xapp_surface,
(GDestroyNotify) xapp_surface1_destroy);
return xapp_surface;
}

static void
flush_display (GdkDisplay *display)
{
wl_display_flush (gdk_wayland_display_get_wl_display (GDK_WAYLAND_DISPLAY (display)));
}

void
_xapp_wayland_update_icon_name (GtkWindow *window,
const gchar *icon_str)
{
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (window));
XAppWaylandShell *wd;
struct xapp_surface1 *xapp_surface;

wd = ensure_shell (display);
if (wd == NULL || wd->shell == NULL ||
!(wd->capabilities & XAPP_SHELL1_CAPABILITY_ICON_NAME))
return;

xapp_surface = ensure_xapp_surface (window, wd);
if (xapp_surface == NULL)
return;

xapp_surface1_set_icon_name (xapp_surface, icon_str);
flush_display (display);
}

void
_xapp_wayland_update_progress (GtkWindow *window,
guint progress,
gboolean pulse)
{
GdkDisplay *display = gtk_widget_get_display (GTK_WIDGET (window));
XAppWaylandShell *wd;
struct xapp_surface1 *xapp_surface;

wd = ensure_shell (display);
if (wd == NULL || wd->shell == NULL ||
!(wd->capabilities & XAPP_SHELL1_CAPABILITY_PROGRESS))
return;

xapp_surface = ensure_xapp_surface (window, wd);
if (xapp_surface == NULL)
return;

xapp_surface1_set_progress (xapp_surface, (int32_t) progress);
xapp_surface1_set_progress_pulse (xapp_surface, pulse ? 1 : 0);
flush_display (display);
}

void
_xapp_wayland_window_unrealized (GtkWindow *window)
{
/* Drops the cached xapp_surface1 (destroying it via its GDestroyNotify) so
* a fresh one is created against the new wl_surface on the next realize. */
g_object_set_data (G_OBJECT (window), SURFACE_DATA_KEY, NULL);
}
Loading
Loading