diff --git a/debian/libmuffin0.symbols b/debian/libmuffin0.symbols index 999b34fad..35952ccd3 100644 --- a/debian/libmuffin0.symbols +++ b/debian/libmuffin0.symbols @@ -2637,6 +2637,7 @@ libmuffin.so.0 libmuffin0 #MINVER# meta_window_get_sandboxed_app_id@Base 5.3.0 meta_window_get_stable_sequence@Base 5.3.0 meta_window_get_startup_id@Base 5.3.0 + meta_window_get_tag@Base 6.4.1 meta_window_get_tile_match@Base 5.3.0 meta_window_get_title@Base 5.3.0 meta_window_get_transient_for@Base 5.3.0 diff --git a/src/core/window-private.h b/src/core/window-private.h index 6a41f3767..72274a6cf 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -203,6 +203,8 @@ struct _MetaWindow char *sm_client_id; char *wm_client_machine; + char *tag; + char *startup_id; char *muffin_hints; char *sandboxed_app_id; @@ -912,4 +914,7 @@ gboolean meta_window_is_focus_async (MetaWindow *window); gboolean meta_window_calculate_bounds (MetaWindow *window, int *bounds_width, int *bounds_height); + +void meta_window_set_tag (MetaWindow *window, + const char *tag); #endif diff --git a/src/core/window.c b/src/core/window.c index f3b18a792..4dd8193b9 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -219,6 +219,7 @@ enum PROP_PROGRESS_PULSE, PROP_TILE_MODE, PROP_OPACITY, + PROP_TAG, PROP_LAST, }; @@ -352,6 +353,7 @@ meta_window_finalize (GObject *object) g_free (window->gtk_app_menu_object_path); g_free (window->gtk_menubar_object_path); g_free (window->placement.rule); + g_free (window->tag); G_OBJECT_CLASS (meta_window_parent_class)->finalize (object); } @@ -453,6 +455,9 @@ meta_window_get_property(GObject *object, case PROP_OPACITY: g_value_set_uint (value, win->opacity); break; + case PROP_TAG: + g_value_set_string (value, win->tag); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -674,6 +679,12 @@ meta_window_class_init (MetaWindowClass *klass) 0xFF, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_props[PROP_TAG] = + g_param_spec_string ("tag", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, PROP_LAST, obj_props); window_signals[WORKSPACE_CHANGED] = @@ -9526,3 +9537,29 @@ meta_window_calculate_bounds (MetaWindow *window, return FALSE; } } + +void +meta_window_set_tag (MetaWindow *window, + const char *tag) +{ + if (g_set_str (&window->tag, tag)) + g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_TAG]); +} + +/** + * meta_window_get_tag: + * @window: A #MetaWindow + * + * Get a tag associated to the window. + * Under wayland the tag can be set using the toplevel tag protocol, + * and under x11 it falls back to using `NET_WM_WINDOW_TAG` atom. + * + * Returns: (nullable): An associated toplevel tag + */ +const char * +meta_window_get_tag (MetaWindow *window) +{ + g_return_val_if_fail (META_IS_WINDOW (window), NULL); + + return window->tag; +} diff --git a/src/meson.build b/src/meson.build index 8a11856e5..056306e81 100644 --- a/src/meson.build +++ b/src/meson.build @@ -587,6 +587,8 @@ if have_wayland 'wayland/meta-wayland-xdg-shell.h', 'wayland/meta-wayland-xdg-dialog.c', 'wayland/meta-wayland-xdg-dialog.h', + 'wayland/meta-wayland-xdg-toplevel-tag.c', + 'wayland/meta-wayland-xdg-toplevel-tag.h', 'wayland/meta-window-wayland.c', 'wayland/meta-window-wayland.h', 'wayland/meta-window-xwayland.c', @@ -811,6 +813,7 @@ if have_wayland ['xdg-foreign', 'unstable', 'v2', ], ['xdg-output', 'unstable', 'v1', ], ['xdg-shell', 'stable', ], + ['xdg-toplevel-tag-v1', 'private', ], ['xwayland-keyboard-grab', 'unstable', 'v1', ], ] if have_wayland_eglstream diff --git a/src/meta/window.h b/src/meta/window.h index 252129f6f..7ed58f7da 100644 --- a/src/meta/window.h +++ b/src/meta/window.h @@ -469,4 +469,7 @@ void meta_window_set_opacity (MetaWindow *window, META_EXPORT guint8 meta_window_get_opacity (MetaWindow *window); +META_EXPORT +const char * meta_window_get_tag (MetaWindow *window); + #endif diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h index c9e9e911d..1a9fb4496 100644 --- a/src/wayland/meta-wayland-versions.h +++ b/src/wayland/meta-wayland-versions.h @@ -56,5 +56,6 @@ #define META_WP_VIEWPORTER_VERSION 1 #define META_XDG_DIALOG_VERSION 1 #define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1 +#define META_XDG_TOPLEVEL_TAG_V1_VERSION 1 #endif diff --git a/src/wayland/meta-wayland-xdg-toplevel-tag.c b/src/wayland/meta-wayland-xdg-toplevel-tag.c new file mode 100644 index 000000000..628289fb4 --- /dev/null +++ b/src/wayland/meta-wayland-xdg-toplevel-tag.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: + * Bilal Elmoussaoui + */ + +#include "config.h" + +#include "wayland/meta-wayland-xdg-toplevel-tag.h" + +#include + +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-versions.h" +#include "wayland/meta-wayland-xdg-shell.h" + +#include "xdg-toplevel-tag-v1-server-protocol.h" + +static void +xdg_toplevel_tag_manager_destroy (struct wl_client *client, + struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +xdg_toplevel_tag_manager_set_toplevel_tag (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *toplevel_resource, + const char *tag) +{ + MetaWaylandXdgToplevel *xdg_toplevel; + MetaWaylandSurfaceRole *surface_role; + MetaWaylandSurface *surface; + MetaWindow *window; + + if (!toplevel_resource) + return; + + xdg_toplevel = wl_resource_get_user_data (toplevel_resource); + surface_role = META_WAYLAND_SURFACE_ROLE (xdg_toplevel); + surface = meta_wayland_surface_role_get_surface (surface_role); + window = meta_wayland_surface_get_window (surface); + + meta_window_set_tag (window, tag); +} + +static void +xdg_toplevel_tag_manager_set_toplevel_tag_description (struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *toplevel, + const char *tag_description) +{ + /* We don't make use of the toplevel tag description */ +} + +static const struct xdg_toplevel_tag_manager_v1_interface meta_xdg_toplevel_tag_interface = { + xdg_toplevel_tag_manager_destroy, + xdg_toplevel_tag_manager_set_toplevel_tag, + xdg_toplevel_tag_manager_set_toplevel_tag_description, +}; + + +static void +bind_xdg_toplevel_tag (struct wl_client *client, + void *data, + uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, + &xdg_toplevel_tag_manager_v1_interface, + META_XDG_TOPLEVEL_TAG_V1_VERSION, + id); + + wl_resource_set_implementation (resource, + &meta_xdg_toplevel_tag_interface, + NULL, NULL); +} + +void +meta_wayland_xdg_toplevel_tag_init (MetaWaylandCompositor *compositor) +{ + if (wl_global_create (compositor->wayland_display, + &xdg_toplevel_tag_manager_v1_interface, + META_XDG_TOPLEVEL_TAG_V1_VERSION, + NULL, + bind_xdg_toplevel_tag) == NULL) + g_error ("Failed to register a global xdg-toplevel-tag object"); +} diff --git a/src/wayland/meta-wayland-xdg-toplevel-tag.h b/src/wayland/meta-wayland-xdg-toplevel-tag.h new file mode 100644 index 000000000..58f32fd28 --- /dev/null +++ b/src/wayland/meta-wayland-xdg-toplevel-tag.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: + * Bilal Elmoussaoui + */ + +#pragma once + +#include + +#include "wayland/meta-wayland-types.h" + +void meta_wayland_xdg_toplevel_tag_init (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 524fd02f3..fd9659b86 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -45,6 +45,7 @@ #include "wayland/meta-wayland-tablet-manager.h" #include "wayland/meta-wayland-xdg-dialog.h" #include "wayland/meta-wayland-xdg-foreign.h" +#include "wayland/meta-wayland-xdg-toplevel-tag.h" #include "wayland/meta-xwayland-grab-keyboard.h" #include "wayland/meta-xwayland-private.h" #include "wayland/meta-xwayland.h" @@ -440,6 +441,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *wayland_compositor) meta_wayland_surface_inhibit_shortcuts_dialog_init (); meta_wayland_text_input_init (compositor); meta_wayland_init_xdg_wm_dialog (compositor); + meta_wayland_xdg_toplevel_tag_init (compositor); /* Xwayland specific protocol, needs to be filtered out for all other clients */ if (meta_xwayland_grab_keyboard_init (compositor)) diff --git a/src/wayland/protocol/xdg-toplevel-tag-v1.xml b/src/wayland/protocol/xdg-toplevel-tag-v1.xml new file mode 100644 index 000000000..5e20bdf45 --- /dev/null +++ b/src/wayland/protocol/xdg-toplevel-tag-v1.xml @@ -0,0 +1,85 @@ + + + + Copyright © 2024 Xaver Hugl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + In order to make some window properties like position, size, + "always on top" or user defined rules for window behavior persistent, the + compositor needs some way to identify windows even after the application + has been restarted. + This protocol allows clients to make this possible by setting a tag for + toplevels. + + Warning! The protocol described in this file is currently in the testing + phase. Backward compatible changes may be added together with the + corresponding interface version bump. Backward incompatible changes can + only be done by creating a new major version of the extension. + + + + + Destroy this toplevel tag manager object. This request has no other + effects. + + + + + + Set a tag for a toplevel. The tag may be shown to the user in UI, so + it's preferable for it to be human readable, but it must be suitable + for configuration files and should not be translated. + Suitable tags would for example be "main window", "settings", + "e-mail composer" or similar. + + The tag does not need to be unique across applications, and the client + may set the same tag for multiple windows, for example if the user has + opened the same UI twice. How the potentially resulting conflicts are + handled is compositor policy. + + The client should set the tag as part of the initial commit on the + associated toplevel, but it may set it at any time afterwards as well, + for example if the purpose of the toplevel changes. + + + + + + + + Set a description for a toplevel. This description may be shown to the + user in UI or read by a screen reader for accessibility purposes, and + should be translated. + It is recommended to make the description the translation of the tag. + + The client should set the description as part of the initial commit on + the associated toplevel, but it may set it at any time afterwards as + well, for example if the purpose of the toplevel changes. + + + + + + + diff --git a/src/x11/atomnames.h b/src/x11/atomnames.h index 8b8f5e506..3f3bc7964 100644 --- a/src/x11/atomnames.h +++ b/src/x11/atomnames.h @@ -180,6 +180,7 @@ item(_NET_WM_OPAQUE_REGION) item(_NET_WM_FRAME_DRAWN) item(_NET_WM_FRAME_TIMINGS) item(_NET_WM_WINDOW_OPACITY) +item(_NET_WM_WINDOW_TAG) item(_NET_RESTACK_WINDOW) item(_NET_WM_XAPP_ICON_NAME) item(_NET_WM_XAPP_PROGRESS) diff --git a/src/x11/window-props.c b/src/x11/window-props.c index abc714973..6d06be225 100644 --- a/src/x11/window-props.c +++ b/src/x11/window-props.c @@ -418,6 +418,14 @@ reload_struts (MetaWindow *window, meta_window_update_struts (window); } +static void +reload_toplevel_tag (MetaWindow *window, + MetaPropValue *value, + gboolean initial) +{ + meta_window_set_tag (window, value->v.str); +} + static void reload_wm_window_role (MetaWindow *window, MetaPropValue *value, @@ -2055,6 +2063,7 @@ meta_x11_display_init_window_prop_hooks (MetaX11Display *x11_display) { x11_display->atom__NET_WM_STRUT_PARTIAL, META_PROP_VALUE_INVALID, reload_struts, NONE }, { x11_display->atom__NET_WM_BYPASS_COMPOSITOR, META_PROP_VALUE_CARDINAL, reload_bypass_compositor, LOAD_INIT | INCLUDE_OR }, { x11_display->atom__NET_WM_WINDOW_OPACITY, META_PROP_VALUE_CARDINAL, reload_window_opacity, LOAD_INIT | INCLUDE_OR }, + { x11_display->atom__NET_WM_WINDOW_TAG, META_PROP_VALUE_STRING, reload_toplevel_tag, LOAD_INIT }, { x11_display->atom__NET_WM_XAPP_ICON_NAME, META_PROP_VALUE_UTF8, reload_theme_icon_name, LOAD_INIT | INCLUDE_OR }, { x11_display->atom__NET_WM_XAPP_PROGRESS, META_PROP_VALUE_CARDINAL, reload_progress, LOAD_INIT | INCLUDE_OR }, { x11_display->atom__NET_WM_XAPP_PROGRESS_PULSE, META_PROP_VALUE_CARDINAL, reload_progress_pulse, LOAD_INIT | INCLUDE_OR },