import mutter-40.9-20.el9

i9-beta changed/i9-beta/mutter-40.9-20.el9.inferit
MSVSphere Packaging Team 3 months ago committed by tigro
parent cd2b6bd350
commit cc4f7560bf
Signed by: tigro
GPG Key ID: 1EC08A25C9DB2503

@ -0,0 +1,106 @@
From 8d340beb368b3b59637c91e2e6e4adbc81ce7caf Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Wed, 7 Feb 2024 21:27:32 +0100
Subject: [PATCH] backends: Disambiguate output mapped to tablet with connector
name
In some circumstances, we may end up with outputs with the same
vendor/product/serial, in which case we have a hard time finding the
right one to map tablets to, since configuration only has these 3
pieces of data.
Add the handling of a 4th argument containing the output name
based on the connector (e.g. HDMI-1), so that it can be used to
disambiguate the output if necessary.
This only kicks in if there actually are multiple outputs with the
same EDID data. A goal of the configuration as it was stored was to
remain useful if the user changed how the device is physically
connected to the computer, this remains true for the vast majority
of users having a single thing of each.
---
src/backends/meta-input-mapper.c | 43 +++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 4 deletions(-)
diff --git a/src/backends/meta-input-mapper.c b/src/backends/meta-input-mapper.c
index ae4cd05..a0a4b8a 100644
--- a/src/backends/meta-input-mapper.c
+++ b/src/backends/meta-input-mapper.c
@@ -395,9 +395,33 @@ match_builtin (MetaInputMapper *mapper,
return monitor == meta_monitor_manager_get_laptop_panel (mapper->monitor_manager);
}
+static gboolean
+monitor_has_twin (MetaMonitor *monitor,
+ GList *monitors)
+{
+ GList *l;
+
+ for (l = monitors; l; l = l->next)
+ {
+ if (l->data == monitor)
+ continue;
+
+ if (g_strcmp0 (meta_monitor_get_vendor (monitor),
+ meta_monitor_get_vendor (l->data)) == 0 &&
+ g_strcmp0 (meta_monitor_get_product (monitor),
+ meta_monitor_get_product (l->data)) == 0 &&
+ g_strcmp0 (meta_monitor_get_serial (monitor),
+ meta_monitor_get_serial (l->data)) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static gboolean
match_config (MetaMapperInputInfo *info,
- MetaMonitor *monitor)
+ MetaMonitor *monitor,
+ GList *monitors)
{
gboolean match = FALSE;
char **edid;
@@ -406,10 +430,10 @@ match_config (MetaMapperInputInfo *info,
edid = g_settings_get_strv (info->settings, "output");
n_values = g_strv_length (edid);
- if (n_values != 3)
+ if (n_values < 3)
{
g_warning ("EDID configuration for device '%s' "
- "is incorrect, must have 3 values",
+ "is incorrect, must have at least 3 values",
clutter_input_device_get_device_name (info->device));
goto out;
}
@@ -421,6 +445,17 @@ match_config (MetaMapperInputInfo *info,
g_strcmp0 (meta_monitor_get_product (monitor), edid[1]) == 0 &&
g_strcmp0 (meta_monitor_get_serial (monitor), edid[2]) == 0);
+ if (match && n_values >= 4 && monitor_has_twin (monitor, monitors))
+ {
+ /* The 4th value if set contains the ID (e.g. HDMI-1), use it
+ * for disambiguation if multiple monitors with the same
+ * EDID data are found.
+ */
+ MetaOutput *output;
+ output = meta_monitor_get_main_output (monitor);
+ match = g_strcmp0 (meta_output_get_name (output), edid[3]) == 0;
+ }
+
out:
g_strfreev (edid);
@@ -481,7 +516,7 @@ guess_candidates (MetaInputMapper *mapper,
if (builtin && match_builtin (mapper, l->data))
match.score |= 1 << META_MATCH_IS_BUILTIN;
- if (match_config (input, l->data))
+ if (match_config (input, l->data, monitors))
match.score |= 1 << META_MATCH_CONFIG;
if (match.score > 0)
--
2.43.0

@ -0,0 +1,69 @@
From 4618af58cc9046142f348d16ab1150bfde8f49c4 Mon Sep 17 00:00:00 2001
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
Date: Wed, 20 Jul 2022 10:10:21 +0000
Subject: [PATCH] cursor-renderer-native: Don't retry forever after GBM cursor
functions fail
This avoids flooding the log with every cursor change:
```
(gnome-shell:19923): libmutter-WARNING **: 10:15:23.404: Realizing HW cursor failed: Failed to allocate gbm_bo: Invalid argument
(gnome-shell:19923): libmutter-WARNING **: 10:15:23.450: Realizing HW cursor failed: Failed to allocate gbm_bo: Invalid argument
(gnome-shell:19923): libmutter-WARNING **: 10:15:23.451: Realizing HW cursor failed: Failed to allocate gbm_bo: Invalid argument
```
Related: https://gitlab.gnome.org/GNOME/mutter/-/issues/2354
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2520>
---
.../native/meta-cursor-renderer-native.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c
index 3c63a15d68..08c9819a12 100644
--- a/src/backends/native/meta-cursor-renderer-native.c
+++ b/src/backends/native/meta-cursor-renderer-native.c
@@ -506,12 +506,9 @@ unset_crtc_cursor (MetaCursorRendererNative *native,
}
static void
-disable_hw_cursor_for_crtc (MetaKmsCrtc *kms_crtc,
- const GError *error)
+disable_hw_cursor_for_gpu (MetaGpuKms *gpu_kms,
+ const GError *error)
{
- MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (kms_crtc);
- MetaCrtc *crtc = META_CRTC (crtc_kms);
- MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data =
meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms);
@@ -521,6 +518,17 @@ disable_hw_cursor_for_crtc (MetaKmsCrtc *kms_crtc,
cursor_renderer_gpu_data->hw_cursor_broken = TRUE;
}
+static void
+disable_hw_cursor_for_crtc (MetaKmsCrtc *kms_crtc,
+ const GError *error)
+{
+ MetaCrtcKms *crtc_kms = meta_crtc_kms_from_kms_crtc (kms_crtc);
+ MetaCrtc *crtc = META_CRTC (crtc_kms);
+ MetaGpuKms *gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
+
+ disable_hw_cursor_for_gpu (gpu_kms, error);
+}
+
void
meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_renderer_native,
MetaRendererView *view)
@@ -1375,6 +1383,7 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native,
if (!buffer)
{
g_warning ("Realizing HW cursor failed: %s", error->message);
+ disable_hw_cursor_for_gpu (gpu_kms, error);
return;
}
--
2.44.0.501.g19981daefd.dirty

@ -0,0 +1,51 @@
From 11e6100226006b5371de30310357582db64c9309 Mon Sep 17 00:00:00 2001
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
Date: Tue, 5 Apr 2022 17:05:17 +0800
Subject: [PATCH 1/2] kms/impl-device: Add addfb2_modifiers to
MetaKmsDeviceCaps
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2359>
---
src/backends/native/meta-kms-impl-device.c | 6 ++++++
src/backends/native/meta-kms-impl-device.h | 1 +
2 files changed, 7 insertions(+)
diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index 75920fe6b..d2e821338 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -288,6 +288,7 @@ init_caps (MetaKmsImplDevice *impl_device)
meta_kms_impl_device_get_instance_private (impl_device);
int fd = priv->fd;
uint64_t cursor_width, cursor_height;
+ uint64_t addfb2_modifiers;
if (drmGetCap (fd, DRM_CAP_CURSOR_WIDTH, &cursor_width) == 0 &&
drmGetCap (fd, DRM_CAP_CURSOR_HEIGHT, &cursor_height) == 0)
@@ -296,6 +297,11 @@ init_caps (MetaKmsImplDevice *impl_device)
priv->caps.cursor_width = cursor_width;
priv->caps.cursor_height = cursor_height;
}
+
+ if (drmGetCap (fd, DRM_CAP_ADDFB2_MODIFIERS, &addfb2_modifiers) == 0)
+ {
+ priv->caps.addfb2_modifiers = (addfb2_modifiers != 0);
+ }
}
static void
diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h
index 913ba992f..a82ad4155 100644
--- a/src/backends/native/meta-kms-impl-device.h
+++ b/src/backends/native/meta-kms-impl-device.h
@@ -36,6 +36,7 @@ typedef struct _MetaKmsDeviceCaps
gboolean has_cursor_size;
uint64_t cursor_width;
uint64_t cursor_height;
+ gboolean addfb2_modifiers;
} MetaKmsDeviceCaps;
typedef struct _MetaKmsProp MetaKmsProp;
--
2.45.2

@ -0,0 +1,101 @@
From f1da6553e13e3c9a9ed91370dcf435fa4a19fb2b Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 6 Jun 2024 13:01:41 -0400
Subject: [PATCH 1/6] window: Don't switch workspaces if users from forged
activation messages
---
src/core/window.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/core/window.c b/src/core/window.c
index 7d86adece..e787dbce0 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -3687,74 +3687,81 @@ meta_window_unshade (MetaWindow *window,
"Focusing window %s after unshading it",
window->desc);
meta_window_focus (window, timestamp);
set_net_wm_state (window);
}
}
static gboolean
unminimize_func (MetaWindow *window,
void *data)
{
meta_window_unminimize (window);
return TRUE;
}
static void
unminimize_window_and_all_transient_parents (MetaWindow *window)
{
meta_window_unminimize (window);
meta_window_foreach_ancestor (window, unminimize_func, NULL);
}
void
meta_window_activate_full (MetaWindow *window,
guint32 timestamp,
MetaClientType source_indication,
MetaWorkspace *workspace)
{
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
- gboolean allow_workspace_switch;
+ gboolean allow_workspace_switch = FALSE;
if (window->unmanaging)
{
g_warning ("Trying to activate unmanaged window '%s'", window->desc);
return;
}
meta_topic (META_DEBUG_FOCUS,
"_NET_ACTIVE_WINDOW message sent for %s at time %u "
"by client type %u.",
window->desc, timestamp, source_indication);
- allow_workspace_switch = (timestamp != 0);
+ if (window->display->last_user_time == timestamp)
+ {
+ /* Only allow workspace switches if this activation message uses the same
+ * timestamp as the last user interaction
+ */
+ allow_workspace_switch = TRUE;
+ }
+
if (timestamp != 0 &&
XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time))
{
meta_topic (META_DEBUG_FOCUS,
"last_user_time (%u) is more recent; ignoring "
" _NET_ACTIVE_WINDOW message.",
window->display->last_user_time);
meta_window_set_demands_attention(window);
return;
}
if (timestamp == 0)
timestamp = meta_display_get_current_time_roundtrip (window->display);
meta_window_set_user_time (window, timestamp);
/* disable show desktop mode unless we're a desktop component */
maybe_leave_show_desktop_mode (window);
/* Get window on current or given workspace */
if (workspace == NULL)
workspace = workspace_manager->active_workspace;
/* For non-transient windows, we just set up a pulsing indicator,
rather than move windows or workspaces.
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
if (window->transient_for == NULL &&
!allow_workspace_switch &&
!meta_window_located_on_workspace (window, workspace))
{
--
2.44.0

@ -0,0 +1,133 @@
From b2cf9836373a446d674ecce251e3e42bb863dc75 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 6 Jun 2024 13:32:03 -0400
Subject: [PATCH 2/6] core/events: Count shell interactions has user
interactions too
mutter keeps track of the last time the user used the system to
decide whether or not to prevent focus stealing.
Right now, it only considers user interactions with application
windows, not interactions with the compositor chrome.
That means a user could start loading an application,
switch workspaces, and get forcefully pulled back when the
application finishes loading.
This commit fixes that problem by updating the user time on shell
interactions as well.
---
src/core/events.c | 38 ++++++++++++++++++++++++--------------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/src/core/events.c b/src/core/events.c
index 775104229..4d25b6dc0 100644
--- a/src/core/events.c
+++ b/src/core/events.c
@@ -288,79 +288,89 @@ meta_display_handle_event (MetaDisplay *display,
if (source)
meta_backend_update_last_device (backend, source);
}
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
{
MetaCursorRenderer *cursor_renderer;
ClutterInputDevice *device;
device = clutter_event_get_device (event);
cursor_renderer = meta_backend_get_cursor_renderer_for_device (backend,
device);
if (cursor_renderer)
meta_cursor_renderer_update_position (cursor_renderer);
if (device == clutter_seat_get_pointer (clutter_input_device_get_seat (device)))
{
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
meta_cursor_tracker_invalidate_position (cursor_tracker);
}
}
#endif
window = get_window_for_event (display, event);
display->current_time = event->any.time;
- if (window && !window->override_redirect &&
- (event->type == CLUTTER_KEY_PRESS ||
- event->type == CLUTTER_BUTTON_PRESS ||
- event->type == CLUTTER_TOUCH_BEGIN))
+ if (event->type == CLUTTER_KEY_PRESS ||
+ event->type == CLUTTER_BUTTON_PRESS ||
+ event->type == CLUTTER_TOUCH_BEGIN)
{
- if (META_CURRENT_TIME == display->current_time)
+ if (window && !window->override_redirect)
{
- /* We can't use missing (i.e. invalid) timestamps to set user time,
- * nor do we want to use them to sanity check other timestamps.
- * See bug 313490 for more details.
- */
- meta_warning ("Event has no timestamp! You may be using a broken "
- "program such as xse. Please ask the authors of that "
- "program to fix it.");
+ if (META_CURRENT_TIME == display->current_time)
+ {
+ /* We can't use missing (i.e. invalid) timestamps to set user time,
+ * nor do we want to use them to sanity check other timestamps.
+ * See bug 313490 for more details.
+ */
+ meta_warning ("Event has no timestamp! You may be using a broken "
+ "program such as xse. Please ask the authors of that "
+ "program to fix it.");
+ }
+ else
+ {
+ meta_window_set_user_time (window, display->current_time);
+ meta_display_sanity_check_timestamps (display, display->current_time);
+ }
}
else
{
- meta_window_set_user_time (window, display->current_time);
- meta_display_sanity_check_timestamps (display, display->current_time);
+ /* Always update user time to the last time the user did an event, even
+ * if it was to shell chrome or a notification or something.
+ */
+ if (XSERVER_TIME_IS_BEFORE (display->last_user_time, display->current_time))
+ display->last_user_time = display->current_time;
}
}
gesture_tracker = meta_display_get_gesture_tracker (display);
if (meta_gesture_tracker_handle_event (gesture_tracker, event))
{
bypass_wayland = bypass_clutter = TRUE;
goto out;
}
if (display->event_route == META_EVENT_ROUTE_WINDOW_OP)
{
if (meta_window_handle_mouse_grab_op_event (window, event))
{
bypass_clutter = TRUE;
bypass_wayland = TRUE;
goto out;
}
}
/* For key events, it's important to enforce single-handling, or
* we can get into a confused state. So if a keybinding is
* handled (because it's one of our hot-keys, or because we are
* in a keyboard-grabbed mode like moving a window, we don't
* want to pass the key event to the compositor or Wayland at all.
*/
if (meta_keybindings_process_event (display, window, event))
{
bypass_clutter = TRUE;
--
2.44.0

@ -0,0 +1,29 @@
From dd94c448e94b1033b90749d77c5dc587c3b8f9f4 Mon Sep 17 00:00:00 2001
From: Daniel van Vugt <daniel.van.vugt@canonical.com>
Date: Tue, 5 Apr 2022 17:06:21 +0800
Subject: [PATCH 2/2] kms/device: Disable modifiers when
!DRM_CAP_ADDFB2_MODIFIERS
Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2210
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2359>
---
src/backends/native/meta-kms-device.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c
index bef1e2065..7c84f14f5 100644
--- a/src/backends/native/meta-kms-device.c
+++ b/src/backends/native/meta-kms-device.c
@@ -490,6 +490,9 @@ meta_kms_device_new (MetaKms *kms,
free (device->path);
device->path = data.out_path;
+ if (!device->caps.addfb2_modifiers)
+ device->flags |= META_KMS_DEVICE_FLAG_DISABLE_MODIFIERS;
+
return device;
}
--
2.45.2

@ -0,0 +1,816 @@
From 0c104d85654318978d10d0fadf33ceea92e29c0a Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 13 Jun 2024 12:58:21 -0400
Subject: [PATCH 3/6] core/window: Split cgroup out to separate struct
We're going to need to attach other information to the cgroup,
aside from the cgroup path, so this commit separates it out
to its own struct, shared with other windows using the same
cgroup.
---
src/core/display-private.h | 17 +++++++++
src/core/display.c | 70 ++++++++++++++++++++++++++++++++++++++
src/core/window-private.h | 2 ++
src/core/window.c | 44 ++++++++++++++++++++++++
4 files changed, 133 insertions(+)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 3d690fcb6..fb17d20a6 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -78,98 +78,106 @@ typedef enum
META_TILE_LEFT,
META_TILE_RIGHT,
META_TILE_MAXIMIZED
} MetaTileMode;
typedef enum
{
/* Normal interaction where you're interacting with windows.
* Events go to windows normally. */
META_EVENT_ROUTE_NORMAL,
/* In a window operation like moving or resizing. All events
* goes to MetaWindow, but not to the actual client window. */
META_EVENT_ROUTE_WINDOW_OP,
/* In a compositor grab operation. All events go to the
* compositor plugin. */
META_EVENT_ROUTE_COMPOSITOR_GRAB,
/* A Wayland application has a popup open. All events go to
* the Wayland application. */
META_EVENT_ROUTE_WAYLAND_POPUP,
/* The user is clicking on a window button. */
META_EVENT_ROUTE_FRAME_BUTTON,
} MetaEventRoute;
typedef void (* MetaDisplayWindowFunc) (MetaWindow *window,
gpointer user_data);
+typedef struct _MetaCGroup MetaCGroup;
+struct _MetaCGroup {
+ GFile *path;
+
+ grefcount ref_count;
+};
+
struct _MetaDisplay
{
GObject parent_instance;
MetaX11Display *x11_display;
int clutter_event_filter;
/* Our best guess as to the "currently" focused window (that is, the
* window that we expect will be focused at the point when the X
* server processes our next request), and the serial of the request
* or event that caused this.
*/
MetaWindow *focus_window;
/* last timestamp passed to XSetInputFocus */
guint32 last_focus_time;
/* last user interaction time in any app */
guint32 last_user_time;
/* whether we're using mousenav (only relevant for sloppy&mouse focus modes;
* !mouse_mode means "keynav mode")
*/
guint mouse_mode : 1;
/* Helper var used when focus_new_windows setting is 'strict'; only
* relevant in 'strict' mode and if the focus window is a terminal.
* In that case, we don't allow new windows to take focus away from
* a terminal, but if the user explicitly did something that should
* allow a different window to gain focus (e.g. global keybinding or
* clicking on a dock), then we will allow the transfer.
*/
guint allow_terminal_deactivation : 1;
/*< private-ish >*/
GHashTable *stamps;
GHashTable *wayland_windows;
+ GHashTable *cgroups;
/* serials of leave/unmap events that may
* correspond to an enter event we should
* ignore
*/
unsigned long ignored_crossing_serials[N_IGNORED_CROSSING_SERIALS];
guint32 current_time;
/* We maintain a sequence counter, incremented for each #MetaWindow
* created. This is exposed by meta_window_get_stable_sequence()
* but is otherwise not used inside mutter.
*
* It can be useful to plugins which want to sort windows in a
* stable fashion.
*/
guint32 window_sequence_counter;
/* Pings which we're waiting for a reply from */
GSList *pending_pings;
/* Pending focus change */
guint focus_timeout_id;
/* Pending autoraise */
guint autoraise_timeout_id;
MetaWindow* autoraise_window;
/* Event routing */
MetaEventRoute event_route;
@@ -254,60 +262,69 @@ struct _MetaDisplayClass
*
* See the docs for meta_display_xserver_time_is_before().
*/
#define XSERVER_TIME_IS_BEFORE(time1, time2) \
( (time1) == 0 || \
(XSERVER_TIME_IS_BEFORE_ASSUMING_REAL_TIMESTAMPS(time1, time2) && \
(time2) != 0) \
)
gboolean meta_display_open (void);
void meta_display_manage_all_xwindows (MetaDisplay *display);
void meta_display_unmanage_windows (MetaDisplay *display,
guint32 timestamp);
/* Utility function to compare the stacking of two windows */
int meta_display_stack_cmp (const void *a,
const void *b);
/* Each MetaWindow is uniquely identified by a 64-bit "stamp"; unlike a
* a MetaWindow *, a stamp will never be recycled
*/
MetaWindow* meta_display_lookup_stamp (MetaDisplay *display,
guint64 stamp);
void meta_display_register_stamp (MetaDisplay *display,
guint64 *stampp,
MetaWindow *window);
void meta_display_unregister_stamp (MetaDisplay *display,
guint64 stamp);
+void meta_display_register_cgroup (MetaDisplay *display,
+ MetaWindow *window,
+ const char *path);
+void meta_display_unregister_cgroup (MetaDisplay *display,
+ MetaWindow *window);
+
+MetaCGroup* meta_cgroup_ref (MetaCGroup *cgroup);
+gboolean meta_cgroup_unref (MetaCGroup *cgroup);
+
/* A "stack id" is a XID or a stamp */
#define META_STACK_ID_IS_X11(id) ((id) < G_GUINT64_CONSTANT(0x100000000))
META_EXPORT_TEST
MetaWindow* meta_display_lookup_stack_id (MetaDisplay *display,
guint64 stack_id);
/* for debug logging only; returns a human-description of the stack
* ID - a small number of buffers are recycled, so the result must
* be used immediately or copied */
const char *meta_display_describe_stack_id (MetaDisplay *display,
guint64 stack_id);
void meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_unregister_wayland_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_notify_window_created (MetaDisplay *display,
MetaWindow *window);
META_EXPORT_TEST
GSList* meta_display_list_windows (MetaDisplay *display,
MetaListWindowsFlags flags);
MetaDisplay* meta_display_for_x_display (Display *xdisplay);
META_EXPORT_TEST
MetaDisplay* meta_get_display (void);
diff --git a/src/core/display.c b/src/core/display.c
index 4b58a5d2f..937defd2c 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -833,60 +833,61 @@ meta_display_open (void)
i = 0;
while (i < N_IGNORED_CROSSING_SERIALS)
{
display->ignored_crossing_serials[i] = 0;
++i;
}
display->current_time = META_CURRENT_TIME;
display->grab_resize_timeout_id = 0;
display->grab_have_keyboard = FALSE;
display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL;
display->grab_tile_mode = META_TILE_NONE;
display->grab_tile_monitor_number = -1;
meta_display_cleanup_edges (display);
meta_display_init_keys (display);
meta_prefs_add_listener (prefs_changed_callback, display);
/* Get events */
meta_display_init_events (display);
display->stamps = g_hash_table_new (g_int64_hash,
g_int64_equal);
display->wayland_windows = g_hash_table_new (NULL, NULL);
+ display->cgroups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
monitor_manager = meta_backend_get_monitor_manager (backend);
g_signal_connect (monitor_manager, "monitors-changed-internal",
G_CALLBACK (on_monitors_changed_internal), display);
display->pad_action_mapper = meta_pad_action_mapper_new (monitor_manager);
settings = meta_backend_get_settings (backend);
g_signal_connect (settings, "ui-scaling-factor-changed",
G_CALLBACK (on_ui_scaling_factor_changed), display);
display->compositor = create_compositor (display);
meta_display_set_cursor (display, META_CURSOR_DEFAULT);
display->stack = meta_stack_new (display);
display->stack_tracker = meta_stack_tracker_new (display);
display->workspace_manager = meta_workspace_manager_new (display);
display->startup_notification = meta_startup_notification_new (display);
display->bell = meta_bell_new (display);
display->selection = meta_selection_new (display);
meta_clipboard_manager_init (display);
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
@@ -1095,60 +1096,61 @@ meta_display_close (MetaDisplay *display,
meta_prefs_remove_listener (prefs_changed_callback, display);
meta_display_remove_autoraise_callback (display);
g_clear_object (&display->gesture_tracker);
g_clear_handle_id (&display->focus_timeout_id, g_source_remove);
g_clear_handle_id (&display->tile_preview_timeout_id, g_source_remove);
if (display->work_area_later != 0)
meta_later_remove (display->work_area_later);
if (display->check_fullscreen_later != 0)
meta_later_remove (display->check_fullscreen_later);
/* Stop caring about events */
meta_display_free_events (display);
g_clear_pointer (&display->compositor, meta_compositor_destroy);
meta_display_shutdown_x11 (display);
g_clear_object (&display->stack);
g_clear_pointer (&display->stack_tracker,
meta_stack_tracker_free);
/* Must be after all calls to meta_window_unmanage() since they
* unregister windows
*/
g_hash_table_destroy (display->wayland_windows);
g_hash_table_destroy (display->stamps);
+ g_hash_table_destroy (display->cgroups);
meta_display_shutdown_keys (display);
g_clear_object (&display->bell);
g_clear_object (&display->startup_notification);
g_clear_object (&display->workspace_manager);
g_clear_object (&display->sound_player);
meta_clipboard_manager_shutdown (display);
g_clear_object (&display->selection);
g_clear_object (&display->pad_action_mapper);
g_object_unref (display);
the_display = NULL;
meta_quit (META_EXIT_SUCCESS);
}
/**
* meta_display_for_x_display:
* @xdisplay: An X display
*
* Returns the singleton MetaDisplay if @xdisplay matches the X display it's
* managing; otherwise gives a warning and returns %NULL. When we were claiming
* to be able to manage multiple displays, this was supposed to find the
* display out of the list which matched that display. Now it's merely an
* extra sanity check.
*
* Returns: The singleton X display, or %NULL if @xdisplay isn't the one
* we're managing.
@@ -1491,60 +1493,128 @@ meta_display_set_input_focus (MetaDisplay *display,
meta_display_update_focus_window (display, window);
display->last_focus_time = timestamp;
if (window == NULL || window != display->autoraise_window)
meta_display_remove_autoraise_callback (display);
}
void
meta_display_unset_input_focus (MetaDisplay *display,
guint32 timestamp)
{
meta_display_set_input_focus (display, NULL, FALSE, timestamp);
}
void
meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window)
{
g_hash_table_add (display->wayland_windows, window);
}
void
meta_display_unregister_wayland_window (MetaDisplay *display,
MetaWindow *window)
{
g_hash_table_remove (display->wayland_windows, window);
}
+MetaCGroup*
+meta_cgroup_new (const char *path)
+{
+ MetaCGroup *cgroup;
+
+ cgroup = g_new0 (MetaCGroup, 1);
+ cgroup->path = g_file_new_for_path (path);
+ g_ref_count_init (&cgroup->ref_count);
+
+ return cgroup;
+}
+
+MetaCGroup*
+meta_cgroup_ref (MetaCGroup *cgroup)
+{
+ g_ref_count_inc (&cgroup->ref_count);
+ return cgroup;
+}
+
+gboolean
+meta_cgroup_unref (MetaCGroup *cgroup)
+{
+ if (!g_ref_count_dec (&cgroup->ref_count))
+ return FALSE;
+
+ g_clear_object (&cgroup->path);
+ g_free (cgroup);
+
+ return TRUE;
+}
+
+void
+meta_display_register_cgroup (MetaDisplay *display,
+ MetaWindow *window,
+ const char *path)
+{
+ MetaCGroup *cgroup;
+
+ cgroup = g_hash_table_lookup (display->cgroups, path);
+
+ if (cgroup)
+ {
+ window->cgroup = meta_cgroup_ref (cgroup);
+ return;
+ }
+
+ cgroup = meta_cgroup_new (path);
+ g_hash_table_insert (display->cgroups, g_file_get_path (cgroup->path), cgroup);
+}
+
+void
+meta_display_unregister_cgroup (MetaDisplay *display,
+ MetaWindow *window)
+{
+ g_autofree const char *path = NULL;
+ MetaCGroup *cgroup = g_steal_pointer (&window->cgroup);
+
+ if (!cgroup)
+ return;
+
+ path = g_file_get_path (cgroup->path);
+
+ if (!meta_cgroup_unref (cgroup))
+ return;
+
+ g_hash_table_remove (display->cgroups, path);
+}
+
MetaWindow*
meta_display_lookup_stamp (MetaDisplay *display,
guint64 stamp)
{
return g_hash_table_lookup (display->stamps, &stamp);
}
void
meta_display_register_stamp (MetaDisplay *display,
guint64 *stampp,
MetaWindow *window)
{
g_return_if_fail (g_hash_table_lookup (display->stamps, stampp) == NULL);
g_hash_table_insert (display->stamps, stampp, window);
}
void
meta_display_unregister_stamp (MetaDisplay *display,
guint64 stamp)
{
g_return_if_fail (g_hash_table_lookup (display->stamps, &stamp) != NULL);
g_hash_table_remove (display->stamps, &stamp);
}
MetaWindow*
meta_display_lookup_stack_id (MetaDisplay *display,
guint64 stack_id)
{
diff --git a/src/core/window-private.h b/src/core/window-private.h
index d1730c988..8a0aebb38 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -193,60 +193,62 @@ struct _MetaWindow
* binary data
*/
char *res_class;
char *res_name;
char *role;
char *sm_client_id;
char *wm_client_machine;
char *startup_id;
char *mutter_hints;
char *sandboxed_app_id;
char *gtk_theme_variant;
char *gtk_application_id;
char *gtk_unique_bus_name;
char *gtk_application_object_path;
char *gtk_window_object_path;
char *gtk_app_menu_object_path;
char *gtk_menubar_object_path;
Window xtransient_for;
Window xgroup_leader;
Window xclient_leader;
MetaWindow *transient_for;
/* Initial workspace property */
int initial_workspace;
/* Initial timestamp property */
guint32 initial_timestamp;
+ MetaCGroup *cgroup;
+
/* Whether this is an override redirect window or not */
guint override_redirect : 1;
/* Whether we're maximized */
guint maximized_horizontally : 1;
guint maximized_vertically : 1;
/* Whether we have to maximize/minimize after placement */
guint maximize_horizontally_after_placement : 1;
guint maximize_vertically_after_placement : 1;
guint minimize_after_placement : 1;
/* The current tile mode */
MetaTileMode tile_mode;
/* The last "full" maximized/unmaximized state. We need to keep track of
* that to toggle between normal/tiled or maximized/tiled states. */
guint saved_maximize : 1;
int tile_monitor_number;
struct {
MetaEdgeConstraint top;
MetaEdgeConstraint right;
MetaEdgeConstraint bottom;
MetaEdgeConstraint left;
} edge_constraints;
double tile_hfraction;
uint64_t preferred_output_winsys_id;
diff --git a/src/core/window.c b/src/core/window.c
index e787dbce0..f5ecd6438 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -70,60 +70,65 @@
#include "cogl/cogl.h"
#include "core/boxes-private.h"
#include "core/constraints.h"
#include "core/edge-resistance.h"
#include "core/frame.h"
#include "core/keybindings-private.h"
#include "core/meta-workspace-manager-private.h"
#include "core/place.h"
#include "core/stack.h"
#include "core/util-private.h"
#include "core/workspace-private.h"
#include "meta/compositor-mutter.h"
#include "meta/group.h"
#include "meta/meta-cursor-tracker.h"
#include "meta/meta-enum-types.h"
#include "meta/meta-x11-errors.h"
#include "meta/prefs.h"
#include "ui/ui.h"
#include "x11/meta-x11-display-private.h"
#include "x11/window-props.h"
#include "x11/window-x11.h"
#include "x11/xprops.h"
#ifdef HAVE_WAYLAND
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface.h"
#include "wayland/meta-window-wayland.h"
#include "wayland/meta-window-xwayland.h"
#endif
+#ifdef HAVE_LIBSYSTEMD
+#include <systemd/sd-login.h>
+#endif
+
+
/* Windows that unmaximize to a size bigger than that fraction of the workarea
* will be scaled down to that size (while maintaining aspect ratio).
* Windows that cover an area greater then this size are automaximized on map.
*/
#define MAX_UNMAXIMIZED_WINDOW_AREA .8
#define SNAP_SECURITY_LABEL_PREFIX "snap."
static int destroying_windows_disallowed = 0;
/* Each window has a "stamp" which is a non-recycled 64-bit ID. They
* start after the end of the XID space so that, for stacking
* we can keep a guint64 that represents one or the other
*/
static guint64 next_window_stamp = G_GUINT64_CONSTANT(0x100000000);
static void invalidate_work_areas (MetaWindow *window);
static void set_wm_state (MetaWindow *window);
static void set_net_wm_state (MetaWindow *window);
static void meta_window_set_above (MetaWindow *window,
gboolean new_value);
static void meta_window_show (MetaWindow *window);
static void meta_window_hide (MetaWindow *window);
static void meta_window_save_rect (MetaWindow *window);
static void ensure_mru_position_after (MetaWindow *window,
MetaWindow *after_this_one);
@@ -303,60 +308,63 @@ meta_window_real_get_client_pid (MetaWindow *window)
}
static void
meta_window_finalize (GObject *object)
{
MetaWindow *window = META_WINDOW (object);
if (window->icon)
cairo_surface_destroy (window->icon);
if (window->mini_icon)
cairo_surface_destroy (window->mini_icon);
if (window->frame_bounds)
cairo_region_destroy (window->frame_bounds);
if (window->shape_region)
cairo_region_destroy (window->shape_region);
if (window->opaque_region)
cairo_region_destroy (window->opaque_region);
if (window->input_region)
cairo_region_destroy (window->input_region);
if (window->transient_for)
g_object_unref (window->transient_for);
g_free (window->sm_client_id);
g_free (window->wm_client_machine);
+
+ meta_display_unregister_cgroup (window->display, window);
+
g_free (window->startup_id);
g_free (window->role);
g_free (window->res_class);
g_free (window->res_name);
g_free (window->title);
g_free (window->desc);
g_free (window->sandboxed_app_id);
g_free (window->gtk_theme_variant);
g_free (window->gtk_application_id);
g_free (window->gtk_unique_bus_name);
g_free (window->gtk_application_object_path);
g_free (window->gtk_window_object_path);
g_free (window->gtk_app_menu_object_path);
g_free (window->gtk_menubar_object_path);
g_free (window->placement.rule);
G_OBJECT_CLASS (meta_window_parent_class)->finalize (object);
}
static void
meta_window_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaWindow *win = META_WINDOW (object);
switch (prop_id)
{
case PROP_TITLE:
@@ -1129,60 +1137,61 @@ _meta_window_shared_new (MetaDisplay *display,
window->has_minimize_func = TRUE;
window->has_maximize_func = TRUE;
window->has_move_func = TRUE;
window->has_resize_func = TRUE;
window->has_shade_func = TRUE;
window->has_fullscreen_func = TRUE;
window->always_sticky = FALSE;
window->skip_taskbar = FALSE;
window->skip_pager = FALSE;
window->skip_from_window_list = FALSE;
window->wm_state_above = FALSE;
window->wm_state_below = FALSE;
window->wm_state_demands_attention = FALSE;
window->res_class = NULL;
window->res_name = NULL;
window->role = NULL;
window->sm_client_id = NULL;
window->wm_client_machine = NULL;
window->is_remote = FALSE;
window->startup_id = NULL;
window->client_pid = 0;
window->xtransient_for = None;
window->xclient_leader = None;
+ window->cgroup = NULL;
window->type = META_WINDOW_NORMAL;
window->struts = NULL;
window->layer = META_LAYER_LAST; /* invalid value */
window->stack_position = -1;
window->initial_workspace = 0; /* not used */
window->initial_timestamp = 0; /* not used */
window->compositor_private = NULL;
window->monitor = meta_window_calculate_main_logical_monitor (window);
if (window->monitor)
window->preferred_output_winsys_id = window->monitor->winsys_id;
else
window->preferred_output_winsys_id = UINT_MAX;
window->tile_match = NULL;
/* Assign this #MetaWindow a sequence number which can be used
* for sorting.
*/
window->stable_sequence = ++display->window_sequence_counter;
window->opacity = 0xFF;
if (window->override_redirect)
{
window->decorated = FALSE;
@@ -7640,60 +7649,95 @@ meta_window_get_transient_for (MetaWindow *window)
else if (window->xtransient_for)
return meta_x11_display_lookup_x_window (window->display->x11_display,
window->xtransient_for);
else
return NULL;
}
/**
* meta_window_get_pid:
* @window: a #MetaWindow
*
* Returns the pid of the process that created this window, if available
* to the windowing system.
*
* Note that the value returned by this is vulnerable to spoofing attacks
* by the client.
*
* Return value: the pid, or 0 if not known.
*/
pid_t
meta_window_get_pid (MetaWindow *window)
{
g_return_val_if_fail (META_IS_WINDOW (window), 0);
if (window->client_pid == 0)
window->client_pid = META_WINDOW_GET_CLASS (window)->get_client_pid (window);
return window->client_pid;
}
+static void
+meta_window_read_cgroup (MetaWindow *window)
+{
+#ifdef HAVE_LIBSYSTEMD
+ g_autofree char *contents = NULL;
+ g_autofree char *complete_path = NULL;
+ g_autofree char *unit_name = NULL;
+ g_autofree char *unit_path = NULL;
+ char *unit_end;
+ pid_t pid;
+
+ if (window->cgroup)
+ return;
+
+ pid = meta_window_get_pid (window);
+ if (pid < 1)
+ return;
+
+ if (sd_pid_get_cgroup (pid, &contents) < 0)
+ return;
+ g_strstrip (contents);
+
+ complete_path = g_strdup_printf ("%s%s", "/sys/fs/cgroup", contents);
+
+ if (sd_pid_get_user_unit (pid, &unit_name) < 0)
+ return;
+ g_strstrip (unit_name);
+
+ unit_end = strstr (complete_path, unit_name) + strlen (unit_name);
+ *unit_end = '\0';
+
+ meta_display_register_cgroup (window->display, window, complete_path);
+#endif
+}
+
/**
* meta_window_get_client_machine:
* @window: a #MetaWindow
*
* Returns name of the client machine from which this windows was created,
* if known (obtained from the WM_CLIENT_MACHINE property).
*
* Return value: (transfer none): the machine name, or NULL; the string is
* owned by the window manager and should not be freed or modified by the
* caller.
*/
const char *
meta_window_get_client_machine (MetaWindow *window)
{
g_return_val_if_fail (META_IS_WINDOW (window), NULL);
return window->wm_client_machine;
}
/**
* meta_window_is_remote:
* @window: a #MetaWindow
*
* Returns: %TRUE if this window originates from a host
* different from the one running mutter.
*/
gboolean
meta_window_is_remote (MetaWindow *window)
{
return window->is_remote;
--
2.44.0

@ -0,0 +1,685 @@
From 9befece38b28581958d87d9393ff9c788213d2fb Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Thu, 13 Jun 2024 13:47:01 -0400
Subject: [PATCH 4/6] window: Track workspace per-cgroup
If an application doesn't tell us what workspace to start on we
need to guess. Currently our guess is "currently active workspace",
but that's not really always the best choice.
This commit adds code to track the workspace other windows in the
same cgroup (~application) are running on and uses that to decide
which workspace to start on instead.
---
src/core/display-private.h | 6 ++++++
src/core/display.c | 31 +++++++++++++++++++++++++++++++
src/core/window-private.h | 1 +
src/core/window.c | 36 ++++++++++++++++++++++++++++++++----
4 files changed, 70 insertions(+), 4 deletions(-)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index fb17d20a6..2b8d9e0d0 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -81,60 +81,63 @@ typedef enum
} MetaTileMode;
typedef enum
{
/* Normal interaction where you're interacting with windows.
* Events go to windows normally. */
META_EVENT_ROUTE_NORMAL,
/* In a window operation like moving or resizing. All events
* goes to MetaWindow, but not to the actual client window. */
META_EVENT_ROUTE_WINDOW_OP,
/* In a compositor grab operation. All events go to the
* compositor plugin. */
META_EVENT_ROUTE_COMPOSITOR_GRAB,
/* A Wayland application has a popup open. All events go to
* the Wayland application. */
META_EVENT_ROUTE_WAYLAND_POPUP,
/* The user is clicking on a window button. */
META_EVENT_ROUTE_FRAME_BUTTON,
} MetaEventRoute;
typedef void (* MetaDisplayWindowFunc) (MetaWindow *window,
gpointer user_data);
typedef struct _MetaCGroup MetaCGroup;
struct _MetaCGroup {
GFile *path;
+ guint32 user_time;
+ MetaWorkspace *last_active_workspace;
+ gboolean has_startup_sequence;
grefcount ref_count;
};
struct _MetaDisplay
{
GObject parent_instance;
MetaX11Display *x11_display;
int clutter_event_filter;
/* Our best guess as to the "currently" focused window (that is, the
* window that we expect will be focused at the point when the X
* server processes our next request), and the serial of the request
* or event that caused this.
*/
MetaWindow *focus_window;
/* last timestamp passed to XSetInputFocus */
guint32 last_focus_time;
/* last user interaction time in any app */
guint32 last_user_time;
/* whether we're using mousenav (only relevant for sloppy&mouse focus modes;
* !mouse_mode means "keynav mode")
*/
guint mouse_mode : 1;
@@ -270,60 +273,63 @@ struct _MetaDisplayClass
gboolean meta_display_open (void);
void meta_display_manage_all_xwindows (MetaDisplay *display);
void meta_display_unmanage_windows (MetaDisplay *display,
guint32 timestamp);
/* Utility function to compare the stacking of two windows */
int meta_display_stack_cmp (const void *a,
const void *b);
/* Each MetaWindow is uniquely identified by a 64-bit "stamp"; unlike a
* a MetaWindow *, a stamp will never be recycled
*/
MetaWindow* meta_display_lookup_stamp (MetaDisplay *display,
guint64 stamp);
void meta_display_register_stamp (MetaDisplay *display,
guint64 *stampp,
MetaWindow *window);
void meta_display_unregister_stamp (MetaDisplay *display,
guint64 stamp);
void meta_display_register_cgroup (MetaDisplay *display,
MetaWindow *window,
const char *path);
void meta_display_unregister_cgroup (MetaDisplay *display,
MetaWindow *window);
MetaCGroup* meta_cgroup_ref (MetaCGroup *cgroup);
gboolean meta_cgroup_unref (MetaCGroup *cgroup);
+void meta_cgroup_update_workspace (MetaCGroup *cgroup,
+ MetaWorkspace *workspace,
+ guint32 timestamp);
/* A "stack id" is a XID or a stamp */
#define META_STACK_ID_IS_X11(id) ((id) < G_GUINT64_CONSTANT(0x100000000))
META_EXPORT_TEST
MetaWindow* meta_display_lookup_stack_id (MetaDisplay *display,
guint64 stack_id);
/* for debug logging only; returns a human-description of the stack
* ID - a small number of buffers are recycled, so the result must
* be used immediately or copied */
const char *meta_display_describe_stack_id (MetaDisplay *display,
guint64 stack_id);
void meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_unregister_wayland_window (MetaDisplay *display,
MetaWindow *window);
void meta_display_notify_window_created (MetaDisplay *display,
MetaWindow *window);
META_EXPORT_TEST
GSList* meta_display_list_windows (MetaDisplay *display,
MetaListWindowsFlags flags);
MetaDisplay* meta_display_for_x_display (Display *xdisplay);
META_EXPORT_TEST
MetaDisplay* meta_get_display (void);
diff --git a/src/core/display.c b/src/core/display.c
index 937defd2c..f30f9a268 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1524,94 +1524,121 @@ MetaCGroup*
meta_cgroup_new (const char *path)
{
MetaCGroup *cgroup;
cgroup = g_new0 (MetaCGroup, 1);
cgroup->path = g_file_new_for_path (path);
g_ref_count_init (&cgroup->ref_count);
return cgroup;
}
MetaCGroup*
meta_cgroup_ref (MetaCGroup *cgroup)
{
g_ref_count_inc (&cgroup->ref_count);
return cgroup;
}
gboolean
meta_cgroup_unref (MetaCGroup *cgroup)
{
if (!g_ref_count_dec (&cgroup->ref_count))
return FALSE;
g_clear_object (&cgroup->path);
g_free (cgroup);
return TRUE;
}
+void
+meta_cgroup_update_workspace (MetaCGroup *cgroup,
+ MetaWorkspace *workspace,
+ guint32 timestamp)
+{
+ if (!cgroup)
+ return;
+
+ if (!XSERVER_TIME_IS_BEFORE (cgroup->user_time, timestamp))
+ return;
+
+ cgroup->user_time = timestamp;
+
+ if (cgroup->last_active_workspace)
+ g_object_remove_weak_pointer (G_OBJECT (cgroup->last_active_workspace),
+ (gpointer *) &cgroup->last_active_workspace);
+
+ cgroup->last_active_workspace = workspace;
+
+ g_object_add_weak_pointer (G_OBJECT (workspace),
+ (gpointer *) &cgroup->last_active_workspace);
+}
+
void
meta_display_register_cgroup (MetaDisplay *display,
MetaWindow *window,
const char *path)
{
MetaCGroup *cgroup;
cgroup = g_hash_table_lookup (display->cgroups, path);
if (cgroup)
{
window->cgroup = meta_cgroup_ref (cgroup);
return;
}
cgroup = meta_cgroup_new (path);
g_hash_table_insert (display->cgroups, g_file_get_path (cgroup->path), cgroup);
}
void
meta_display_unregister_cgroup (MetaDisplay *display,
MetaWindow *window)
{
g_autofree const char *path = NULL;
MetaCGroup *cgroup = g_steal_pointer (&window->cgroup);
if (!cgroup)
return;
path = g_file_get_path (cgroup->path);
if (!meta_cgroup_unref (cgroup))
return;
+ if (cgroup->last_active_workspace)
+ g_object_remove_weak_pointer (G_OBJECT (cgroup->last_active_workspace),
+ (gpointer *) &cgroup->last_active_workspace);
+
g_hash_table_remove (display->cgroups, path);
}
MetaWindow*
meta_display_lookup_stamp (MetaDisplay *display,
guint64 stamp)
{
return g_hash_table_lookup (display->stamps, &stamp);
}
void
meta_display_register_stamp (MetaDisplay *display,
guint64 *stampp,
MetaWindow *window)
{
g_return_if_fail (g_hash_table_lookup (display->stamps, stampp) == NULL);
g_hash_table_insert (display->stamps, stampp, window);
}
void
meta_display_unregister_stamp (MetaDisplay *display,
guint64 stamp)
{
g_return_if_fail (g_hash_table_lookup (display->stamps, &stamp) != NULL);
g_hash_table_remove (display->stamps, &stamp);
}
MetaWindow*
@@ -3374,60 +3401,64 @@ meta_display_apply_startup_properties (MetaDisplay *display,
meta_startup_sequence_get_id (sequence),
window->desc);
meta_startup_sequence_complete (sequence);
}
}
/* Still no startup ID? Bail. */
if (!startup_id)
return FALSE;
/* We might get this far and not know the sequence ID (if the window
* already had a startup ID stored), so let's look for one if we don't
* already know it.
*/
if (sequence == NULL)
{
sequence =
meta_startup_notification_lookup_sequence (display->startup_notification,
startup_id);
}
if (sequence != NULL)
{
gboolean changed_something = FALSE;
meta_topic (META_DEBUG_STARTUP,
"Found startup sequence for window %s ID \"%s\"",
window->desc, startup_id);
+ meta_window_read_cgroup (window);
+ if (window->cgroup)
+ window->cgroup->has_startup_sequence = TRUE;
+
if (!window->initial_workspace_set)
{
int space = meta_startup_sequence_get_workspace (sequence);
if (space >= 0)
{
meta_topic (META_DEBUG_STARTUP,
"Setting initial window workspace to %d based on startup info",
space);
window->initial_workspace_set = TRUE;
window->initial_workspace = space;
changed_something = TRUE;
}
}
if (!window->initial_timestamp_set)
{
guint32 timestamp = meta_startup_sequence_get_timestamp (sequence);
meta_topic (META_DEBUG_STARTUP,
"Setting initial window timestamp to %u based on startup info",
timestamp);
window->initial_timestamp_set = TRUE;
window->initial_timestamp = timestamp;
changed_something = TRUE;
}
return changed_something;
}
else
diff --git a/src/core/window-private.h b/src/core/window-private.h
index 8a0aebb38..41782aa99 100644
--- a/src/core/window-private.h
+++ b/src/core/window-private.h
@@ -860,31 +860,32 @@ void meta_window_update_resize (MetaWindow *window,
MetaEdgeResistanceFlags flags,
int x, int y,
gboolean force);
void meta_window_move_resize_internal (MetaWindow *window,
MetaMoveResizeFlags flags,
MetaGravity gravity,
MetaRectangle frame_rect);
void meta_window_grab_op_began (MetaWindow *window, MetaGrabOp op);
void meta_window_grab_op_ended (MetaWindow *window, MetaGrabOp op);
void meta_window_set_alive (MetaWindow *window, gboolean is_alive);
gboolean meta_window_has_pointer (MetaWindow *window);
void meta_window_emit_size_changed (MetaWindow *window);
MetaPlacementRule *meta_window_get_placement_rule (MetaWindow *window);
void meta_window_force_placement (MetaWindow *window,
gboolean force_move);
void meta_window_force_restore_shortcuts (MetaWindow *window,
ClutterInputDevice *source);
gboolean meta_window_shortcuts_inhibited (MetaWindow *window,
ClutterInputDevice *source);
gboolean meta_window_is_stackable (MetaWindow *window);
gboolean meta_window_is_focus_async (MetaWindow *window);
+void meta_window_read_cgroup (MetaWindow *window);
#endif
diff --git a/src/core/window.c b/src/core/window.c
index f5ecd6438..5c7b2e8cf 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1296,79 +1296,88 @@ _meta_window_shared_new (MetaDisplay *display,
* added to all the MRU lists
*/
window->on_all_workspaces_requested = TRUE;
on_all_workspaces = TRUE;
}
else if (!on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Window %s is initially on space %d",
window->desc, window->initial_workspace);
workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager,
window->initial_workspace);
}
/* Ignore when a window requests to be placed on a non-existent workspace
*/
if (on_all_workspaces || workspace != NULL)
set_workspace_state (window, on_all_workspaces, workspace);
}
/* override-redirect windows are subtly different from other windows
* with window->on_all_workspaces == TRUE. Other windows are part of
* some workspace (so they can return to that if the flag is turned off),
* but appear on other workspaces. override-redirect windows are part
* of no workspace.
*/
if (!window->override_redirect && window->workspace == NULL)
{
+ meta_window_read_cgroup (window);
if (window->transient_for != NULL)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on same workspace as parent %s",
window->desc, window->transient_for->desc);
g_warn_if_fail (!window->transient_for->override_redirect);
set_workspace_state (window,
window->transient_for->on_all_workspaces,
window->transient_for->workspace);
}
else if (window->on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on all workspaces",
window->desc);
set_workspace_state (window, TRUE, NULL);
}
+ else if (window->cgroup && window->cgroup->last_active_workspace != NULL &&
+ !window->cgroup->has_startup_sequence)
+ {
+ meta_topic (META_DEBUG_PLACEMENT,
+ "Putting window %s on active workspace",
+ window->desc);
+ set_workspace_state (window, FALSE, window->cgroup->last_active_workspace);
+ }
else
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on active workspace",
window->desc);
set_workspace_state (window, FALSE, workspace_manager->active_workspace);
}
meta_window_update_struts (window);
}
meta_window_main_monitor_changed (window, NULL);
/* Must add window to stack before doing move/resize, since the
* window might have fullscreen size (i.e. should have been
* fullscreen'd; acrobat is one such braindead case; it withdraws
* and remaps its window whenever trying to become fullscreen...)
* and thus constraints may try to auto-fullscreen it which also
* means restacking it.
*/
if (meta_window_is_stackable (window))
meta_stack_add (window->display->stack,
window);
else if (window->override_redirect)
window->layer = META_LAYER_OVERRIDE_REDIRECT; /* otherwise set by MetaStack */
if (!window->override_redirect)
{
/* FIXME we have a tendency to set this then immediately
@@ -3736,63 +3745,71 @@ meta_window_activate_full (MetaWindow *window,
"by client type %u.",
window->desc, timestamp, source_indication);
if (window->display->last_user_time == timestamp)
{
/* Only allow workspace switches if this activation message uses the same
* timestamp as the last user interaction
*/
allow_workspace_switch = TRUE;
}
if (timestamp != 0 &&
XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time))
{
meta_topic (META_DEBUG_FOCUS,
"last_user_time (%u) is more recent; ignoring "
" _NET_ACTIVE_WINDOW message.",
window->display->last_user_time);
meta_window_set_demands_attention(window);
return;
}
if (timestamp == 0)
timestamp = meta_display_get_current_time_roundtrip (window->display);
meta_window_set_user_time (window, timestamp);
/* disable show desktop mode unless we're a desktop component */
maybe_leave_show_desktop_mode (window);
- /* Get window on current or given workspace */
- if (workspace == NULL)
- workspace = workspace_manager->active_workspace;
+ /* Get window on last active, current, or given workspace */
+ if (workspace == NULL)
+ {
+ meta_window_read_cgroup (window);
+ if (window->cgroup &&
+ window->cgroup->last_active_workspace != NULL &&
+ !window->cgroup->has_startup_sequence)
+ workspace = window->cgroup->last_active_workspace;
+ else
+ workspace = workspace_manager->active_workspace;
+ }
/* For non-transient windows, we just set up a pulsing indicator,
rather than move windows or workspaces.
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
if (window->transient_for == NULL &&
!allow_workspace_switch &&
!meta_window_located_on_workspace (window, workspace))
{
meta_window_set_demands_attention (window);
/* We've marked it as demanding, don't need to do anything else. */
return;
}
else if (window->transient_for != NULL)
{
/* Move transients to current workspace - preference dialogs should appear over
the source window. */
meta_window_change_workspace (window, workspace);
}
if (window->shaded)
meta_window_unshade (window, timestamp);
unminimize_window_and_all_transient_parents (window);
if (meta_prefs_get_raise_on_click () ||
source_indication == META_CLIENT_TYPE_PAGER)
meta_window_raise (window);
meta_topic (META_DEBUG_FOCUS,
"Focusing window %s due to activation",
@@ -7165,60 +7182,71 @@ meta_window_set_user_time (MetaWindow *window,
g_return_if_fail (!window->override_redirect);
/* Only update the time if this timestamp is newer... */
if (window->net_wm_user_time_set &&
XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time))
{
meta_topic (META_DEBUG_STARTUP,
"Window %s _NET_WM_USER_TIME not updated to %u, because it "
"is less than %u",
window->desc, timestamp, window->net_wm_user_time);
}
else
{
meta_topic (META_DEBUG_STARTUP,
"Window %s has _NET_WM_USER_TIME of %u",
window->desc, timestamp);
window->net_wm_user_time_set = TRUE;
window->net_wm_user_time = timestamp;
if (XSERVER_TIME_IS_BEFORE (window->display->last_user_time, timestamp))
window->display->last_user_time = timestamp;
/* If this is a terminal, user interaction with it means the user likely
* doesn't want to have focus transferred for now due to new windows.
*/
if (meta_prefs_get_focus_new_windows () == G_DESKTOP_FOCUS_NEW_WINDOWS_STRICT &&
window_is_terminal (window))
window->display->allow_terminal_deactivation = FALSE;
g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_USER_TIME]);
}
+
+ if (!window->cgroup)
+ meta_window_read_cgroup (window);
+
+ if (window->cgroup)
+ {
+ MetaWorkspace *workspace = meta_window_get_workspace (window);
+
+ if (workspace)
+ meta_cgroup_update_workspace (window->cgroup, workspace, timestamp);
+ }
}
/**
* meta_window_get_stable_sequence:
* @window: A #MetaWindow
*
* The stable sequence number is a monotonicially increasing
* unique integer assigned to each #MetaWindow upon creation.
*
* This number can be useful for sorting windows in a stable
* fashion.
*
* Returns: Internal sequence number for this window
*/
guint32
meta_window_get_stable_sequence (MetaWindow *window)
{
g_return_val_if_fail (META_IS_WINDOW (window), 0);
return window->stable_sequence;
}
/* Sets the demands_attention hint on a window, but only
* if it's at least partially obscured (see #305882).
*/
void
meta_window_set_demands_attention (MetaWindow *window)
{
MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
MetaRectangle candidate_rect, other_rect;
@@ -7649,61 +7677,61 @@ meta_window_get_transient_for (MetaWindow *window)
else if (window->xtransient_for)
return meta_x11_display_lookup_x_window (window->display->x11_display,
window->xtransient_for);
else
return NULL;
}
/**
* meta_window_get_pid:
* @window: a #MetaWindow
*
* Returns the pid of the process that created this window, if available
* to the windowing system.
*
* Note that the value returned by this is vulnerable to spoofing attacks
* by the client.
*
* Return value: the pid, or 0 if not known.
*/
pid_t
meta_window_get_pid (MetaWindow *window)
{
g_return_val_if_fail (META_IS_WINDOW (window), 0);
if (window->client_pid == 0)
window->client_pid = META_WINDOW_GET_CLASS (window)->get_client_pid (window);
return window->client_pid;
}
-static void
+void
meta_window_read_cgroup (MetaWindow *window)
{
#ifdef HAVE_LIBSYSTEMD
g_autofree char *contents = NULL;
g_autofree char *complete_path = NULL;
g_autofree char *unit_name = NULL;
g_autofree char *unit_path = NULL;
char *unit_end;
pid_t pid;
if (window->cgroup)
return;
pid = meta_window_get_pid (window);
if (pid < 1)
return;
if (sd_pid_get_cgroup (pid, &contents) < 0)
return;
g_strstrip (contents);
complete_path = g_strdup_printf ("%s%s", "/sys/fs/cgroup", contents);
if (sd_pid_get_user_unit (pid, &unit_name) < 0)
return;
g_strstrip (unit_name);
unit_end = strstr (complete_path, unit_name) + strlen (unit_name);
*unit_end = '\0';
--
2.44.0

@ -0,0 +1,556 @@
From 62e4f7153738b404b05b1ee59d088bc52fd86bc0 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 8 Jul 2024 09:54:01 -0400
Subject: [PATCH 5/6] core/display: Avoid placement heuristcs for apps that can
do startup notification
We recently introduced heuristics to decide which workspace to put an an
application window on. Those heuristics are only used if an application
doesn't support startup notification (since startup notification
provides a means to give that information without heuristics).
Unfortunately, sometimes applications that support startup notification
aren't started with it. In those cases, it's wrong to fall back to
heuristics, because those heuristics are a big change in behavior, and
cause applications to break (like terminals launched from the desktop
starting on the wrong workspace)
This commit adds code to try to deduce the application from its cgroup,
and then check if it supports startup notification, even if it's not
started with it in any given instance.
---
src/core/display-private.h | 1 +
src/core/display.c | 113 +++++++++++++++++++++++++++++++++++++
src/core/window.c | 10 +++-
3 files changed, 122 insertions(+), 2 deletions(-)
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 2b8d9e0d0..3c7e0898b 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -81,60 +81,61 @@ typedef enum
} MetaTileMode;
typedef enum
{
/* Normal interaction where you're interacting with windows.
* Events go to windows normally. */
META_EVENT_ROUTE_NORMAL,
/* In a window operation like moving or resizing. All events
* goes to MetaWindow, but not to the actual client window. */
META_EVENT_ROUTE_WINDOW_OP,
/* In a compositor grab operation. All events go to the
* compositor plugin. */
META_EVENT_ROUTE_COMPOSITOR_GRAB,
/* A Wayland application has a popup open. All events go to
* the Wayland application. */
META_EVENT_ROUTE_WAYLAND_POPUP,
/* The user is clicking on a window button. */
META_EVENT_ROUTE_FRAME_BUTTON,
} MetaEventRoute;
typedef void (* MetaDisplayWindowFunc) (MetaWindow *window,
gpointer user_data);
typedef struct _MetaCGroup MetaCGroup;
struct _MetaCGroup {
GFile *path;
+ GAppInfo *app_info;
guint32 user_time;
MetaWorkspace *last_active_workspace;
gboolean has_startup_sequence;
grefcount ref_count;
};
struct _MetaDisplay
{
GObject parent_instance;
MetaX11Display *x11_display;
int clutter_event_filter;
/* Our best guess as to the "currently" focused window (that is, the
* window that we expect will be focused at the point when the X
* server processes our next request), and the serial of the request
* or event that caused this.
*/
MetaWindow *focus_window;
/* last timestamp passed to XSetInputFocus */
guint32 last_focus_time;
/* last user interaction time in any app */
guint32 last_user_time;
/* whether we're using mousenav (only relevant for sloppy&mouse focus modes;
* !mouse_mode means "keynav mode")
diff --git a/src/core/display.c b/src/core/display.c
index f30f9a268..4c9038e62 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -65,60 +65,62 @@
#include "core/meta-clipboard-manager.h"
#include "core/meta-workspace-manager-private.h"
#include "core/util-private.h"
#include "core/window-private.h"
#include "core/workspace-private.h"
#include "meta/compositor-mutter.h"
#include "meta/compositor.h"
#include "meta/main.h"
#include "meta/meta-backend.h"
#include "meta/meta-enum-types.h"
#include "meta/meta-sound-player.h"
#include "meta/meta-x11-errors.h"
#include "meta/prefs.h"
#include "x11/meta-startup-notification-x11.h"
#include "x11/meta-x11-display-private.h"
#include "x11/window-x11.h"
#include "x11/xprops.h"
#ifdef HAVE_WAYLAND
#include "compositor/meta-compositor-native.h"
#include "compositor/meta-compositor-server.h"
#include "wayland/meta-xwayland-private.h"
#include "wayland/meta-wayland-tablet-seat.h"
#include "wayland/meta-wayland-tablet-pad.h"
#endif
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
#endif
+#include <gio/gdesktopappinfo.h>
+
/*
* SECTION:pings
*
* Sometimes we want to see whether a window is responding,
* so we send it a "ping" message and see whether it sends us back a "pong"
* message within a reasonable time. Here we have a system which lets us
* nominate one function to be called if we get the pong in time and another
* function if we don't. The system is rather more complicated than it needs
* to be, since we only ever use it to destroy windows which are asked to
* close themselves and don't do so within a reasonable amount of time, and
* therefore we always use the same callbacks. It's possible that we might
* use it for other things in future, or on the other hand we might decide
* that we're never going to do so and simplify it a bit.
*/
/**
* MetaPingData:
*
* Describes a ping on a window. When we send a ping to a window, we build
* one of these structs, and it eventually gets passed to the timeout function
* or to the function which handles the response from the window. If the window
* does or doesn't respond to the ping, we use this information to deal with
* these facts; we have a handler function for each.
*/
typedef struct
{
MetaWindow *window;
guint32 serial;
guint ping_timeout_id;
} MetaPingData;
@@ -1493,85 +1495,196 @@ meta_display_set_input_focus (MetaDisplay *display,
meta_display_update_focus_window (display, window);
display->last_focus_time = timestamp;
if (window == NULL || window != display->autoraise_window)
meta_display_remove_autoraise_callback (display);
}
void
meta_display_unset_input_focus (MetaDisplay *display,
guint32 timestamp)
{
meta_display_set_input_focus (display, NULL, FALSE, timestamp);
}
void
meta_display_register_wayland_window (MetaDisplay *display,
MetaWindow *window)
{
g_hash_table_add (display->wayland_windows, window);
}
void
meta_display_unregister_wayland_window (MetaDisplay *display,
MetaWindow *window)
{
g_hash_table_remove (display->wayland_windows, window);
}
+static void
+unescape_app_id (char **app_id)
+{
+ char *p = *app_id;
+ char *q = *app_id;
+
+ while (*p != '\0')
+ {
+ if (*p == '\\' &&
+ p[1] == 'x' &&
+ g_ascii_isxdigit (p[2]) &&
+ g_ascii_isxdigit (p[3]))
+ {
+ char escape_code[3] = { p[2], p[3], '\0' };
+ *q = (char) g_ascii_strtoll (escape_code, NULL, 16);
+ p += strlen ("\\xAA");
+ }
+ else
+ {
+ *q = *p;
+ p++;
+ }
+ q++;
+ }
+ *q = '\0';
+}
+
+/* The possible formats are:
+ *
+ * /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/app-dbus\x2d:1.2\x2dorg.gnome.Totem.slice/dbus-:1.2-org.gnome.Totem@0.service
+ * /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/app-org.gnome.Terminal.slice/gnome-terminal-server.service
+ * /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/app.slice/app-gnome-org.gnome.Evince-12345.scope
+ */
+static char *
+extract_app_id_from_cgroup (const char *cgroup)
+{
+ g_auto (GStrv) path_components = NULL;
+ const char *unit_name = NULL;
+ size_t i;
+ g_autofree char *app_id = NULL;
+ char *start_delimiter = NULL;
+ char *end_delimiter = NULL;
+ int app_id_length;
+
+ path_components = g_strsplit (cgroup, G_DIR_SEPARATOR_S, -1);
+
+ for (i = 0; path_components[i]; i++)
+ {
+ if (!g_str_equal (path_components[i], "app.slice"))
+ continue;
+
+ unit_name = path_components[i + 1];
+ break;
+ }
+
+ if (!unit_name)
+ return NULL;
+
+ if (!g_str_has_prefix (unit_name, "app-"))
+ return NULL;
+
+ end_delimiter = g_strrstr (unit_name, ".slice");
+
+ if (!end_delimiter)
+ end_delimiter = strrchr (unit_name, '-');
+
+ if (end_delimiter == NULL || end_delimiter == unit_name)
+ return NULL;
+
+ start_delimiter = end_delimiter - 1;
+ while (start_delimiter > cgroup && *start_delimiter != '-')
+ start_delimiter--;
+
+ if (start_delimiter == NULL || start_delimiter == unit_name)
+ return NULL;
+
+ app_id_length = end_delimiter - (start_delimiter + 1);
+ app_id = g_strdup_printf ("%.*s.desktop", app_id_length, start_delimiter + 1);
+
+ unescape_app_id (&app_id);
+
+ if (g_str_has_prefix (app_id, "dbus-"))
+ {
+ const char *dbus_prefix;
+ dbus_prefix = strchr (app_id + strlen ("dbus-") + 1, '-');
+
+ if (dbus_prefix)
+ {
+ char *stripped_app_id = strdup (dbus_prefix + 1);
+ g_clear_pointer (&app_id, g_free);
+ app_id = g_steal_pointer (&stripped_app_id);
+ }
+ }
+
+ return g_steal_pointer (&app_id);
+}
+
MetaCGroup*
meta_cgroup_new (const char *path)
{
MetaCGroup *cgroup;
+ g_autofree char *app_id = NULL;
cgroup = g_new0 (MetaCGroup, 1);
cgroup->path = g_file_new_for_path (path);
g_ref_count_init (&cgroup->ref_count);
+ app_id = extract_app_id_from_cgroup (path);
+
+ if (app_id)
+ {
+ g_autoptr (GDesktopAppInfo) app_info = NULL;
+
+ app_info = g_desktop_app_info_new (app_id);
+
+ if (app_info)
+ cgroup->app_info = G_APP_INFO (g_steal_pointer (&app_info));
+ }
+
return cgroup;
}
MetaCGroup*
meta_cgroup_ref (MetaCGroup *cgroup)
{
g_ref_count_inc (&cgroup->ref_count);
return cgroup;
}
gboolean
meta_cgroup_unref (MetaCGroup *cgroup)
{
if (!g_ref_count_dec (&cgroup->ref_count))
return FALSE;
+ g_clear_object (&cgroup->app_info);
g_clear_object (&cgroup->path);
g_free (cgroup);
return TRUE;
}
void
meta_cgroup_update_workspace (MetaCGroup *cgroup,
MetaWorkspace *workspace,
guint32 timestamp)
{
if (!cgroup)
return;
if (!XSERVER_TIME_IS_BEFORE (cgroup->user_time, timestamp))
return;
cgroup->user_time = timestamp;
if (cgroup->last_active_workspace)
g_object_remove_weak_pointer (G_OBJECT (cgroup->last_active_workspace),
(gpointer *) &cgroup->last_active_workspace);
cgroup->last_active_workspace = workspace;
g_object_add_weak_pointer (G_OBJECT (workspace),
(gpointer *) &cgroup->last_active_workspace);
}
void
diff --git a/src/core/window.c b/src/core/window.c
index 5c7b2e8cf..d36e45992 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -74,60 +74,62 @@
#include "core/frame.h"
#include "core/keybindings-private.h"
#include "core/meta-workspace-manager-private.h"
#include "core/place.h"
#include "core/stack.h"
#include "core/util-private.h"
#include "core/workspace-private.h"
#include "meta/compositor-mutter.h"
#include "meta/group.h"
#include "meta/meta-cursor-tracker.h"
#include "meta/meta-enum-types.h"
#include "meta/meta-x11-errors.h"
#include "meta/prefs.h"
#include "ui/ui.h"
#include "x11/meta-x11-display-private.h"
#include "x11/window-props.h"
#include "x11/window-x11.h"
#include "x11/xprops.h"
#ifdef HAVE_WAYLAND
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface.h"
#include "wayland/meta-window-wayland.h"
#include "wayland/meta-window-xwayland.h"
#endif
#ifdef HAVE_LIBSYSTEMD
#include <systemd/sd-login.h>
#endif
+#include <gio/gdesktopappinfo.h>
+
/* Windows that unmaximize to a size bigger than that fraction of the workarea
* will be scaled down to that size (while maintaining aspect ratio).
* Windows that cover an area greater then this size are automaximized on map.
*/
#define MAX_UNMAXIMIZED_WINDOW_AREA .8
#define SNAP_SECURITY_LABEL_PREFIX "snap."
static int destroying_windows_disallowed = 0;
/* Each window has a "stamp" which is a non-recycled 64-bit ID. They
* start after the end of the XID space so that, for stacking
* we can keep a guint64 that represents one or the other
*/
static guint64 next_window_stamp = G_GUINT64_CONSTANT(0x100000000);
static void invalidate_work_areas (MetaWindow *window);
static void set_wm_state (MetaWindow *window);
static void set_net_wm_state (MetaWindow *window);
static void meta_window_set_above (MetaWindow *window,
gboolean new_value);
static void meta_window_show (MetaWindow *window);
static void meta_window_hide (MetaWindow *window);
static void meta_window_save_rect (MetaWindow *window);
static void ensure_mru_position_after (MetaWindow *window,
MetaWindow *after_this_one);
@@ -1317,61 +1319,63 @@ _meta_window_shared_new (MetaDisplay *display,
/* override-redirect windows are subtly different from other windows
* with window->on_all_workspaces == TRUE. Other windows are part of
* some workspace (so they can return to that if the flag is turned off),
* but appear on other workspaces. override-redirect windows are part
* of no workspace.
*/
if (!window->override_redirect && window->workspace == NULL)
{
meta_window_read_cgroup (window);
if (window->transient_for != NULL)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on same workspace as parent %s",
window->desc, window->transient_for->desc);
g_warn_if_fail (!window->transient_for->override_redirect);
set_workspace_state (window,
window->transient_for->on_all_workspaces,
window->transient_for->workspace);
}
else if (window->on_all_workspaces)
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on all workspaces",
window->desc);
set_workspace_state (window, TRUE, NULL);
}
else if (window->cgroup && window->cgroup->last_active_workspace != NULL &&
- !window->cgroup->has_startup_sequence)
+ !window->cgroup->has_startup_sequence &&
+ (!window->cgroup->app_info ||
+ !g_desktop_app_info_get_boolean (G_DESKTOP_APP_INFO (window->cgroup->app_info), "StartupNotify")))
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on active workspace",
window->desc);
set_workspace_state (window, FALSE, window->cgroup->last_active_workspace);
}
else
{
meta_topic (META_DEBUG_PLACEMENT,
"Putting window %s on active workspace",
window->desc);
set_workspace_state (window, FALSE, workspace_manager->active_workspace);
}
meta_window_update_struts (window);
}
meta_window_main_monitor_changed (window, NULL);
/* Must add window to stack before doing move/resize, since the
* window might have fullscreen size (i.e. should have been
* fullscreen'd; acrobat is one such braindead case; it withdraws
* and remaps its window whenever trying to become fullscreen...)
* and thus constraints may try to auto-fullscreen it which also
* means restacking it.
*/
if (meta_window_is_stackable (window))
meta_stack_add (window->display->stack,
window);
@@ -3751,61 +3755,63 @@ meta_window_activate_full (MetaWindow *window,
* timestamp as the last user interaction
*/
allow_workspace_switch = TRUE;
}
if (timestamp != 0 &&
XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time))
{
meta_topic (META_DEBUG_FOCUS,
"last_user_time (%u) is more recent; ignoring "
" _NET_ACTIVE_WINDOW message.",
window->display->last_user_time);
meta_window_set_demands_attention(window);
return;
}
if (timestamp == 0)
timestamp = meta_display_get_current_time_roundtrip (window->display);
meta_window_set_user_time (window, timestamp);
/* disable show desktop mode unless we're a desktop component */
maybe_leave_show_desktop_mode (window);
/* Get window on last active, current, or given workspace */
if (workspace == NULL)
{
meta_window_read_cgroup (window);
if (window->cgroup &&
window->cgroup->last_active_workspace != NULL &&
- !window->cgroup->has_startup_sequence)
+ !window->cgroup->has_startup_sequence &&
+ (!window->cgroup->app_info ||
+ !g_desktop_app_info_get_boolean (G_DESKTOP_APP_INFO (window->cgroup->app_info), "StartupNotify")))
workspace = window->cgroup->last_active_workspace;
else
workspace = workspace_manager->active_workspace;
}
/* For non-transient windows, we just set up a pulsing indicator,
rather than move windows or workspaces.
See http://bugzilla.gnome.org/show_bug.cgi?id=482354 */
if (window->transient_for == NULL &&
!allow_workspace_switch &&
!meta_window_located_on_workspace (window, workspace))
{
meta_window_set_demands_attention (window);
/* We've marked it as demanding, don't need to do anything else. */
return;
}
else if (window->transient_for != NULL)
{
/* Move transients to current workspace - preference dialogs should appear over
the source window. */
meta_window_change_workspace (window, workspace);
}
if (window->shaded)
meta_window_unshade (window, timestamp);
unminimize_window_and_all_transient_parents (window);
if (meta_prefs_get_raise_on_click () ||
source_indication == META_CLIENT_TYPE_PAGER)
--
2.44.0

@ -0,0 +1,370 @@
From 63c529fc5a8db1a82fd6b988aa44e3e6a1e417bf Mon Sep 17 00:00:00 2001
From: Nishal Kulkarni <nishalkulkarni@gmail.com>
Date: Thu, 5 Aug 2021 19:37:28 +0530
Subject: [PATCH 6/6] meson: Add optional libsystemd dependency
To utilize the API provided by libsystemd it would be better to
create a separate HAVE_LIBSYSTEMD configuration option instead of
having to rely on HAVE_NATIVE_BACKEND.
For now this will be utilized for getting the control group of a
MetaWindow.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1960>
---
config.h.meson | 3 +++
meson.build | 5 ++++-
meson_options.txt | 6 ++++++
src/meson.build | 6 ++++++
4 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/config.h.meson b/config.h.meson
index 26e13b9ca..b7ca736df 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -7,60 +7,63 @@
/* Version number of package */
#mesondefine PACKAGE_VERSION
/* Search path for plugins */
#mesondefine MUTTER_PLUGIN_DIR
/* */
#mesondefine MUTTER_LOCALEDIR
/* */
#mesondefine MUTTER_LIBEXECDIR
/* */
#mesondefine MUTTER_PKGDATADIR
/* Defined if EGL support is enabled */
#mesondefine HAVE_EGL
/* Defined if EGLDevice support is enabled */
#mesondefine HAVE_EGL_DEVICE
/* Defined if EGLStream support is enabled */
#mesondefine HAVE_WAYLAND_EGLSTREAM
/* Building with gudev for device type detection */
#mesondefine HAVE_LIBGUDEV
/* Building with libwacom for advanced tablet management */
#mesondefine HAVE_LIBWACOM
+/* Building with libsystemd */
+#mesondefine HAVE_LIBSYSTEMD
+
/* Define if you want to enable the native (KMS) backend based on systemd */
#mesondefine HAVE_NATIVE_BACKEND
/* Define if you want to enable Wayland support */
#mesondefine HAVE_WAYLAND
/* Defined if screen cast and remote desktop support is enabled */
#mesondefine HAVE_REMOTE_DESKTOP
/* Building with SM support */
#mesondefine HAVE_SM
/* Building with startup notification support */
#mesondefine HAVE_STARTUP_NOTIFICATION
/* Building with Sysprof profiling support */
#mesondefine HAVE_PROFILER
/* Path to Xwayland executable */
#mesondefine XWAYLAND_PATH
/* Xwayland applications allowed to issue keyboard grabs */
#mesondefine XWAYLAND_GRAB_DEFAULT_ACCESS_RULES
/* XKB base prefix */
#mesondefine XKB_BASE
/* Whether <sys/prctl.h> exists and it defines prctl() */
#mesondefine HAVE_SYS_PRCTL
diff --git a/meson.build b/meson.build
index 39ad5bcd1..613aa6779 100644
--- a/meson.build
+++ b/meson.build
@@ -161,67 +161,69 @@ if have_gles2
if not have_egl
error('GLESv2 support requires EGL to be enabled')
endif
endif
have_wayland = get_option('wayland')
if have_wayland
wayland_server_dep = dependency('wayland-server', version: wayland_server_req)
wayland_client_dep = dependency('wayland-client', version: wayland_server_req)
wayland_protocols_dep = dependency('wayland-protocols',
version: wayland_protocols_req)
wayland_egl_dep = dependency('wayland-egl')
if not have_egl
error('Wayland support requires EGL to be enabled')
endif
endif
have_libgudev = get_option('udev')
if have_libgudev
libudev_dep = dependency('libudev', version: udev_req)
gudev_dep = dependency('gudev-1.0', version: gudev_req)
udev_dep = dependency('udev')
udev_dir = get_option('udev_dir')
if udev_dir == ''
udev_dir = udev_dep.get_pkgconfig_variable('udevdir')
endif
endif
+have_libsystemd = get_option('systemd')
+libsystemd_dep = dependency('libsystemd', required: have_libsystemd)
+
have_native_backend = get_option('native_backend')
if have_native_backend
libdrm_dep = dependency('libdrm')
libgbm_dep = dependency('gbm', version: gbm_req)
libinput_dep = dependency('libinput', version: libinput_req)
- libsystemd_dep = dependency('libsystemd', required: false)
if libsystemd_dep.found()
logind_provider_dep = libsystemd_dep
else
logind_provider_dep = dependency('libelogind')
endif
if not have_egl
error('The native backend requires EGL to be enabled')
endif
if not have_gles2
error('The native backend requires GLESv2 to be enabled')
endif
if not have_libgudev
error('The native backend requires udev to be enabled')
endif
endif
have_egl_device = get_option('egl_device')
have_wayland_eglstream = get_option('wayland_eglstream')
if have_wayland_eglstream
wayland_eglstream_protocols_dep = dependency('wayland-eglstream-protocols')
dl_dep = cc.find_library('dl', required: true)
if not have_wayland
error('Wayland EGLStream support requires Wayland to be enabled')
endif
endif
@@ -359,60 +361,61 @@ if buildtype != 'plain'
'-Werror=array-bounds',
'-Werror=write-strings',
'-Werror=address',
'-Werror=int-to-pointer-cast',
'-Werror=pointer-to-int-cast',
'-Werror=empty-body',
'-Werror=write-strings',
]
supported_warnings = cc.get_supported_arguments(all_warnings)
add_project_arguments(supported_warnings, language: 'c')
endif
if get_option('debug')
debug_c_args = [
'-DG_ENABLE_DEBUG',
'-fno-omit-frame-pointer'
]
supported_debug_c_args = cc.get_supported_arguments(debug_c_args)
add_project_arguments(supported_debug_c_args, language: 'c')
endif
cc.compiles('void main (void) { __builtin_ffsl (0); __builtin_popcountl (0); }')
cdata = configuration_data()
cdata.set_quoted('GETTEXT_PACKAGE', gettext_package)
cdata.set_quoted('VERSION', meson.project_version())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set('HAVE_EGL', have_egl)
cdata.set('HAVE_WAYLAND', have_wayland)
+cdata.set('HAVE_LIBSYSTEMD', have_libsystemd)
cdata.set('HAVE_NATIVE_BACKEND', have_native_backend)
cdata.set('HAVE_REMOTE_DESKTOP', have_remote_desktop)
cdata.set('HAVE_EGL_DEVICE', have_egl_device)
cdata.set('HAVE_WAYLAND_EGLSTREAM', have_wayland_eglstream)
cdata.set('HAVE_LIBGUDEV', have_libgudev)
cdata.set('HAVE_LIBWACOM', have_libwacom)
cdata.set('HAVE_SM', have_sm)
cdata.set('HAVE_STARTUP_NOTIFICATION', have_startup_notification)
cdata.set('HAVE_INTROSPECTION', have_introspection)
cdata.set('HAVE_PROFILER', have_profiler)
xkb_base = xkeyboard_config_dep.get_pkgconfig_variable('xkb_base')
cdata.set_quoted('XKB_BASE', xkb_base)
if cc.has_header_symbol('sys/prctl.h', 'prctl')
cdata.set('HAVE_SYS_PRCTL', 1)
endif
have_xwayland_initfd = false
have_xwayland_listenfd = false
if have_wayland
xwayland_dep = dependency('xwayland', required: false)
xwayland_path = get_option('xwayland_path')
if xwayland_path == ''
if xwayland_dep.found()
xwayland_path = xwayland_dep.get_pkgconfig_variable('xwayland')
else
xwayland_path = find_program('Xwayland').path()
endif
diff --git a/meson_options.txt b/meson_options.txt
index 61d9cb48d..6609e4332 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -12,60 +12,66 @@ option('opengl_libname',
option('gles2_libname',
type: 'string',
value: 'libGLESv2.so.2',
description: 'GLESv2 library file name'
)
option('gles2',
type: 'boolean',
value: true,
description: 'Enable GLES2 support'
)
option('egl',
type: 'boolean',
value: true,
description: 'Enable EGL support'
)
option('glx',
type: 'boolean',
value: true,
description: 'Enable GLX support'
)
option('wayland',
type: 'boolean',
value: true,
description: 'Enable Wayland support'
)
+option('systemd',
+ type: 'boolean',
+ value: true,
+ description: 'Enable systemd support'
+)
+
option('native_backend',
type: 'boolean',
value: true,
description: 'Enable the native backend'
)
option('remote_desktop',
type: 'boolean',
value: true,
description: 'Enable remote desktop and screen cast support'
)
option('egl_device',
type: 'boolean',
value: false,
description: 'Enable EGLDevice and EGLStream renderer support'
)
option('wayland_eglstream',
type: 'boolean',
value: false,
description: 'Enable Wayland EGLStream support client support'
)
option('udev',
type: 'boolean',
value: true,
description: 'Enable udev support when using the X11 backend'
)
diff --git a/src/meson.build b/src/meson.build
index 47633498e..9ac6afa1a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -91,60 +91,66 @@ if have_x11
xinerama_dep,
xext_dep,
ice_dep,
xcomposite_dep,
xcursor_dep,
xdamage_dep,
xkbfile_dep,
xkeyboard_config_dep,
xkbcommon_x11_dep,
xrender_dep,
x11_xcb_dep,
xcb_randr_dep,
xcb_res_dep,
xau_dep,
xtst_dep,
]
if have_sm
mutter_pkg_private_deps += [
sm_dep,
]
endif
endif
if have_wayland
mutter_pkg_deps += [
wayland_server_dep,
]
endif
+if have_libsystemd
+ mutter_pkg_private_deps += [
+ libsystemd_dep,
+ ]
+endif
+
if have_native_backend
mutter_pkg_private_deps += [
libdrm_dep,
libinput_dep,
gudev_dep,
libgbm_dep,
logind_provider_dep,
libudev_dep,
xkbcommon_dep,
]
endif
if have_wayland_eglstream
mutter_lib_deps += [
dl_dep,
]
mutter_pkg_private_deps += [
wayland_eglstream_protocols_dep,
]
endif
mutter_deps = [
mutter_pkg_deps,
mutter_pkg_private_deps,
mutter_lib_deps,
]
mutter_c_args = [
'-DCLUTTER_ENABLE_COMPOSITOR_API',
'-DCOGL_ENABLE_EXPERIMENTAL_API',
--
2.44.0

File diff suppressed because it is too large Load Diff

@ -10,7 +10,7 @@
Name: mutter
Version: 40.9
Release: 15%{?dist}.inferit.1
Release: 20%{?dist}.inferit
Summary: Window and compositing manager based on Clutter
License: GPLv2+
@ -113,6 +113,28 @@ Patch46: 0001-clutter-text-Don-t-query-preferred-size-without-allo.patch
Patch47: 0001-core-Change-MetaWaylandTextInput-event-forwarding-to.patch
Patch48: 0001-backends-Disambiguate-output-mapped-to-tablet-with-c.patch
# Backport https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2359
# Resolves https://issues.redhat.com/browse/RHEL-45198
Patch49: 0001-kms-impl-device-Add-addfb2_modifiers-to-MetaKmsDevic.patch
Patch50: 0002-kms-device-Disable-modifiers-when-DRM_CAP_ADDFB2_MOD.patch
# Focus stealing prevention fixes
# Resolves https://issues.redhat.com/browse/RHEL-29537
Patch51: 0001-window-Don-t-switch-workspaces-if-users-from-forged-.patch
Patch52: 0002-core-events-Count-shell-interactions-has-user-intera.patch
Patch53: 0003-core-window-Split-cgroup-out-to-separate-struct.patch
Patch54: 0004-window-Track-workspace-per-cgroup.patch
Patch55: 0005-core-display-Avoid-placement-heuristcs-for-apps-that.patch
Patch56: 0006-meson-Add-optional-libsystemd-dependency.patch
# Don't retry cursor plane if failed (RHEL-33720)
Patch57: 0001-cursor-renderer-native-Don-t-retry-forever-after-GBM.patch
# RHEL-45998 & RHEL-45366
Patch58: sticky-or-on-top-dialog-fixes.patch
# MSVSphere
Patch100: 0001-Update-Russian-translation.patch
@ -272,17 +294,33 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop
https://gitlab.gnome.org/3v1n0/mutter/commits/xrandr-scaling
Scaling appears in the user interface ( 100%, 125%, 150%, 175%, 200% )
* Tue Oct 10 2023 Sergey Cherevko <s.cherevko@msvsphere-os.ru> - 40.9-15.inferit
- Rebuilt for MSVSphere 9.3
* Mon Aug 05 2024 Jonas Ådahl <jadahl@redhat.com>) - 40.9-20
- Fix positioning when using always-on-top windows
Resolves: RHEL-45998
- Improve handling of always-on-visible-workspace windows
Resolves: RHEL-45366
* Mon Aug 05 2024 Jonas Ådahl <jadahl@redhat.com>) - 40.9-19
- Don't retry using cursor plane if it failed
Resolves: RHEL-32622
* Mon Jul 29 2024 Ray Strode <rstrode@redhat.com> - 40.9-18
- Don't allow applications on other workspaces to steal
focus, unless their timestamps are pristine
Resolves: RHEL-29537
* Thu Jul 04 2024 José Expósito <jexposit@redhat.com> - 40.9-17
- Fix Wayland session with Virtio driver
Resolves: RHEL-45198
* Tue Feb 06 2024 Carlos Garnacho <cgarnach@redhat.com> - 40.9-16
- Disambiguate output mapped to tablet with connector name
Resolves: RHEL-28535
* Mon Jul 10 2023 Carlos Garnacho <cgarnach@redhat.com> - 40.9-15
- Fix ordering of keyboard modifiers relative to other keyboard events
Resolves: #2218146
* Fri May 12 2023 Sergey Cherevko <s.cherevko@msvsphere-os.ru> - 40.9-14.inferit
- Update Russian translation
- Rebuilt for MSVSphere 9.2 beta
* Fri Apr 14 2023 MSVSphere Packaging Team <packager@msvsphere.ru> - 40.9-14
- Rebuilt for MSVSphere 9.2 beta

Loading…
Cancel
Save