parent
cd2b6bd350
commit
cc4f7560bf
@ -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
Loading…
Reference in new issue