2017-08-26 12:24:46 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2001 Havoc Pennington
|
|
|
|
* Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
|
|
|
|
* Copyright (C) 2003, 2004 Rob Adams
|
|
|
|
* Copyright (C) 2004-2006 Elijah Newren
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2018-07-16 10:25:20 -04:00
|
|
|
* SECTION:x11-display
|
2017-08-26 12:24:46 -04:00
|
|
|
* @title: MetaX11Display
|
|
|
|
* @short_description: Mutter X display handler
|
|
|
|
*
|
|
|
|
* The X11 display is represented as a #MetaX11Display struct.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
#include "core/display-private.h"
|
2017-08-26 12:24:46 -04:00
|
|
|
#include "x11/meta-x11-display-private.h"
|
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
#include <gdk/gdk.h>
|
x11: Integrate frames client into Mutter
Replace the in-process implementation of frames with the external
frames client.
When a client window is created and managed by Mutter, Mutter will
determine whether it is a window that requires decorations and
hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
property on the client window.
After the frames client created a window that has the _MUTTER_FRAME_FOR
property, Mutter will proceed to reparent the client window on the
frame window, and show them as a single unit.
Rendering and event handling on the frame window will be performed by
the external client, Mutter is still responsible for everything else,
namely resizing client and frame window in synchronization, and
managing updates on the MetaWindowActor.
In order to let the frame be managed by the external client, Mutter
needs to change the way some properties are forwarded to the client
and/or frame windows. Some properties are necessary to keep propagating
to the client window only, some others need to happen on the frame
window now, and some others needs to be propagated on both so they
are synchronized about the behavior.
Also, some events that were previously totally unexpected in frame
windows are now susceptible to happen, so must be allowed now.
MetaFrame in src/core/frame.c now acts as the wrapper of foreign
windows created by the frames client, from the Mutter side. Location,
size, and lifetime are still largely in control of Mutter, some
details like visible/invisible borders are obtained from the client
instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
properties, respectively).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
2022-09-08 04:35:47 -04:00
|
|
|
#include <gdk/gdkx.h>
|
2017-08-26 12:26:30 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xatom.h>
|
2017-08-26 16:35:18 -04:00
|
|
|
#include <X11/XKBlib.h>
|
2017-08-26 12:28:53 -04:00
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
#include <X11/Xcursor/Xcursor.h>
|
|
|
|
#include <X11/extensions/Xcomposite.h>
|
|
|
|
#include <X11/extensions/Xdamage.h>
|
|
|
|
#include <X11/extensions/Xfixes.h>
|
2017-08-26 15:28:04 -04:00
|
|
|
#include <X11/extensions/Xinerama.h>
|
2018-07-10 04:36:24 -04:00
|
|
|
#include <X11/extensions/Xrandr.h>
|
|
|
|
|
2017-08-26 12:37:29 -04:00
|
|
|
#include "backends/meta-backend-private.h"
|
2019-07-03 10:23:45 -04:00
|
|
|
#include "backends/meta-dnd-private.h"
|
2018-08-17 07:56:47 -04:00
|
|
|
#include "backends/meta-cursor-sprite-xcursor.h"
|
2017-08-26 15:28:04 -04:00
|
|
|
#include "backends/meta-logical-monitor.h"
|
2018-07-06 13:22:26 -04:00
|
|
|
#include "backends/meta-settings-private.h"
|
2017-08-26 12:37:29 -04:00
|
|
|
#include "backends/x11/meta-backend-x11.h"
|
2019-03-22 08:53:00 -04:00
|
|
|
#include "backends/x11/meta-stage-x11.h"
|
2017-08-26 14:51:28 -04:00
|
|
|
#include "core/frame.h"
|
2017-08-27 15:02:40 -04:00
|
|
|
#include "core/meta-workspace-manager-private.h"
|
2017-08-26 12:26:30 -04:00
|
|
|
#include "core/util-private.h"
|
2017-08-26 15:39:46 -04:00
|
|
|
#include "core/workspace-private.h"
|
2017-08-26 14:51:28 -04:00
|
|
|
#include "meta/main.h"
|
2017-08-27 14:48:55 -04:00
|
|
|
#include "meta/meta-x11-errors.h"
|
2017-08-26 12:26:30 -04:00
|
|
|
|
2017-08-26 14:54:39 -04:00
|
|
|
#include "x11/events.h"
|
2017-08-26 12:58:29 -04:00
|
|
|
#include "x11/group-props.h"
|
2018-11-19 12:17:25 -05:00
|
|
|
#include "x11/meta-x11-selection-private.h"
|
2017-08-26 12:58:29 -04:00
|
|
|
#include "x11/window-props.h"
|
2017-08-26 14:51:28 -04:00
|
|
|
#include "x11/xprops.h"
|
2017-08-26 12:58:29 -04:00
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
#ifdef HAVE_WAYLAND
|
|
|
|
#include "wayland/meta-xwayland-private.h"
|
|
|
|
#endif
|
|
|
|
|
2017-08-26 12:24:46 -04:00
|
|
|
G_DEFINE_TYPE (MetaX11Display, meta_x11_display, G_TYPE_OBJECT)
|
|
|
|
|
2017-08-26 15:28:04 -04:00
|
|
|
static GQuark quark_x11_display_logical_monitor_data = 0;
|
|
|
|
|
|
|
|
typedef struct _MetaX11DisplayLogicalMonitorData
|
|
|
|
{
|
|
|
|
int xinerama_index;
|
|
|
|
} MetaX11DisplayLogicalMonitorData;
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
static char *get_screen_name (Display *xdisplay,
|
|
|
|
int number);
|
|
|
|
|
2017-08-27 14:44:38 -04:00
|
|
|
static void on_monitors_changed_internal (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaX11Display *x11_display);
|
2017-08-26 13:03:51 -04:00
|
|
|
|
2017-08-26 12:37:29 -04:00
|
|
|
static void update_cursor_theme (MetaX11Display *x11_display);
|
2017-08-26 14:54:39 -04:00
|
|
|
static void unset_wm_check_hint (MetaX11Display *x11_display);
|
2017-08-26 12:37:29 -04:00
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
static void prefs_changed_callback (MetaPreference pref,
|
|
|
|
void *data);
|
|
|
|
|
x11: Integrate frames client into Mutter
Replace the in-process implementation of frames with the external
frames client.
When a client window is created and managed by Mutter, Mutter will
determine whether it is a window that requires decorations and
hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
property on the client window.
After the frames client created a window that has the _MUTTER_FRAME_FOR
property, Mutter will proceed to reparent the client window on the
frame window, and show them as a single unit.
Rendering and event handling on the frame window will be performed by
the external client, Mutter is still responsible for everything else,
namely resizing client and frame window in synchronization, and
managing updates on the MetaWindowActor.
In order to let the frame be managed by the external client, Mutter
needs to change the way some properties are forwarded to the client
and/or frame windows. Some properties are necessary to keep propagating
to the client window only, some others need to happen on the frame
window now, and some others needs to be propagated on both so they
are synchronized about the behavior.
Also, some events that were previously totally unexpected in frame
windows are now susceptible to happen, so must be allowed now.
MetaFrame in src/core/frame.c now acts as the wrapper of foreign
windows created by the frames client, from the Mutter side. Location,
size, and lifetime are still largely in control of Mutter, some
details like visible/invisible borders are obtained from the client
instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
properties, respectively).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
2022-09-08 04:35:47 -04:00
|
|
|
static void meta_x11_display_init_frames_client (MetaX11Display *x11_display);
|
|
|
|
|
2022-09-07 05:34:35 -04:00
|
|
|
static MetaBackend *
|
|
|
|
backend_from_x11_display (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_x11_display_get_display (x11_display);
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
|
|
|
|
return meta_context_get_backend (context);
|
|
|
|
}
|
|
|
|
|
2018-12-10 07:42:53 -05:00
|
|
|
static void
|
|
|
|
meta_x11_display_unmanage_windows (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
GList *windows, *l;
|
|
|
|
|
|
|
|
if (!x11_display->xids)
|
|
|
|
return;
|
|
|
|
|
|
|
|
windows = g_hash_table_get_values (x11_display->xids);
|
|
|
|
g_list_foreach (windows, (GFunc) g_object_ref, NULL);
|
|
|
|
|
|
|
|
for (l = windows; l; l = l->next)
|
|
|
|
{
|
2022-03-15 18:13:44 -04:00
|
|
|
MetaWindow *window = META_WINDOW (l->data);
|
|
|
|
|
|
|
|
if (!window->unmanaging)
|
|
|
|
meta_window_unmanage (window, META_CURRENT_TIME);
|
2018-12-10 07:42:53 -05:00
|
|
|
}
|
|
|
|
g_list_free_full (windows, g_object_unref);
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:24:46 -04:00
|
|
|
static void
|
|
|
|
meta_x11_display_dispose (GObject *object)
|
|
|
|
{
|
2017-08-26 12:26:30 -04:00
|
|
|
MetaX11Display *x11_display = META_X11_DISPLAY (object);
|
|
|
|
|
2019-06-14 11:25:10 -04:00
|
|
|
x11_display->closing = TRUE;
|
|
|
|
|
2022-11-20 14:15:34 -05:00
|
|
|
g_clear_pointer (&x11_display->alarm_filters, g_ptr_array_unref);
|
|
|
|
|
x11: Integrate frames client into Mutter
Replace the in-process implementation of frames with the external
frames client.
When a client window is created and managed by Mutter, Mutter will
determine whether it is a window that requires decorations and
hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
property on the client window.
After the frames client created a window that has the _MUTTER_FRAME_FOR
property, Mutter will proceed to reparent the client window on the
frame window, and show them as a single unit.
Rendering and event handling on the frame window will be performed by
the external client, Mutter is still responsible for everything else,
namely resizing client and frame window in synchronization, and
managing updates on the MetaWindowActor.
In order to let the frame be managed by the external client, Mutter
needs to change the way some properties are forwarded to the client
and/or frame windows. Some properties are necessary to keep propagating
to the client window only, some others need to happen on the frame
window now, and some others needs to be propagated on both so they
are synchronized about the behavior.
Also, some events that were previously totally unexpected in frame
windows are now susceptible to happen, so must be allowed now.
MetaFrame in src/core/frame.c now acts as the wrapper of foreign
windows created by the frames client, from the Mutter side. Location,
size, and lifetime are still largely in control of Mutter, some
details like visible/invisible borders are obtained from the client
instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
properties, respectively).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
2022-09-08 04:35:47 -04:00
|
|
|
if (x11_display->frames_client_cancellable)
|
|
|
|
{
|
|
|
|
g_cancellable_cancel (x11_display->frames_client_cancellable);
|
|
|
|
g_clear_object (&x11_display->frames_client_cancellable);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x11_display->frames_client)
|
|
|
|
{
|
|
|
|
g_subprocess_send_signal (x11_display->frames_client, SIGTERM);
|
|
|
|
g_clear_object (&x11_display->frames_client);
|
|
|
|
}
|
|
|
|
|
2019-08-16 10:23:08 -04:00
|
|
|
if (x11_display->empty_region != None)
|
|
|
|
{
|
|
|
|
XFixesDestroyRegion (x11_display->xdisplay,
|
|
|
|
x11_display->empty_region);
|
|
|
|
x11_display->empty_region = None;
|
|
|
|
}
|
|
|
|
|
2018-08-22 14:57:04 -04:00
|
|
|
meta_x11_startup_notification_release (x11_display);
|
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
meta_prefs_remove_listener (prefs_changed_callback, x11_display);
|
|
|
|
|
2017-08-26 15:38:59 -04:00
|
|
|
meta_x11_display_ungrab_keys (x11_display);
|
|
|
|
|
2019-06-14 10:49:04 -04:00
|
|
|
g_clear_object (&x11_display->x11_stack);
|
|
|
|
|
2018-11-19 12:17:25 -05:00
|
|
|
meta_x11_selection_shutdown (x11_display);
|
2018-12-10 07:42:53 -05:00
|
|
|
meta_x11_display_unmanage_windows (x11_display);
|
2018-11-19 12:17:25 -05:00
|
|
|
|
2017-08-26 14:51:28 -04:00
|
|
|
if (x11_display->no_focus_window != None)
|
|
|
|
{
|
|
|
|
XUnmapWindow (x11_display->xdisplay, x11_display->no_focus_window);
|
|
|
|
XDestroyWindow (x11_display->xdisplay, x11_display->no_focus_window);
|
|
|
|
|
|
|
|
x11_display->no_focus_window = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x11_display->composite_overlay_window != None)
|
|
|
|
{
|
|
|
|
XCompositeReleaseOverlayWindow (x11_display->xdisplay,
|
|
|
|
x11_display->composite_overlay_window);
|
|
|
|
|
|
|
|
x11_display->composite_overlay_window = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x11_display->wm_sn_selection_window != None)
|
|
|
|
{
|
|
|
|
XDestroyWindow (x11_display->xdisplay, x11_display->wm_sn_selection_window);
|
|
|
|
x11_display->wm_sn_selection_window = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x11_display->timestamp_pinging_window != None)
|
|
|
|
{
|
|
|
|
XDestroyWindow (x11_display->xdisplay, x11_display->timestamp_pinging_window);
|
|
|
|
x11_display->timestamp_pinging_window = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x11_display->leader_window != None)
|
|
|
|
{
|
|
|
|
XDestroyWindow (x11_display->xdisplay, x11_display->leader_window);
|
|
|
|
x11_display->leader_window = None;
|
|
|
|
}
|
|
|
|
|
2017-08-26 13:03:51 -04:00
|
|
|
if (x11_display->guard_window != None)
|
|
|
|
{
|
|
|
|
XUnmapWindow (x11_display->xdisplay, x11_display->guard_window);
|
|
|
|
XDestroyWindow (x11_display->xdisplay, x11_display->guard_window);
|
|
|
|
x11_display->guard_window = None;
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:58:29 -04:00
|
|
|
if (x11_display->prop_hooks)
|
|
|
|
{
|
|
|
|
meta_x11_display_free_window_prop_hooks (x11_display);
|
|
|
|
x11_display->prop_hooks = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x11_display->group_prop_hooks)
|
|
|
|
{
|
|
|
|
meta_x11_display_free_group_prop_hooks (x11_display);
|
|
|
|
x11_display->group_prop_hooks = NULL;
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:56:44 -04:00
|
|
|
if (x11_display->xids)
|
|
|
|
{
|
|
|
|
/* Must be after all calls to meta_window_unmanage() since they
|
|
|
|
* unregister windows
|
|
|
|
*/
|
|
|
|
g_hash_table_destroy (x11_display->xids);
|
|
|
|
x11_display->xids = NULL;
|
|
|
|
}
|
|
|
|
|
2022-09-09 06:45:52 -04:00
|
|
|
g_clear_pointer (&x11_display->alarms, g_hash_table_unref);
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
if (x11_display->xroot != None)
|
|
|
|
{
|
2017-08-26 14:54:39 -04:00
|
|
|
unset_wm_check_hint (x11_display);
|
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 12:26:30 -04:00
|
|
|
XSelectInput (x11_display->xdisplay, x11_display->xroot, 0);
|
2017-08-27 14:48:55 -04:00
|
|
|
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning ("Could not release screen %d on display \"%s\"",
|
2017-08-26 16:52:02 -04:00
|
|
|
DefaultScreen (x11_display->xdisplay),
|
|
|
|
x11_display->name);
|
2017-08-26 12:26:30 -04:00
|
|
|
|
|
|
|
x11_display->xroot = None;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (x11_display->xdisplay)
|
|
|
|
{
|
2017-08-26 14:54:39 -04:00
|
|
|
meta_x11_display_free_events (x11_display);
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
x11_display->xdisplay = NULL;
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
if (x11_display->gdk_display)
|
|
|
|
{
|
|
|
|
gdk_display_close (x11_display->gdk_display);
|
|
|
|
x11_display->gdk_display = NULL;
|
|
|
|
}
|
|
|
|
|
2019-11-21 18:25:30 -05:00
|
|
|
g_clear_handle_id (&x11_display->display_close_idle, g_source_remove);
|
2018-10-31 10:21:40 -04:00
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
g_free (x11_display->name);
|
|
|
|
x11_display->name = NULL;
|
|
|
|
|
|
|
|
g_free (x11_display->screen_name);
|
|
|
|
x11_display->screen_name = NULL;
|
|
|
|
|
2017-08-26 12:24:46 -04:00
|
|
|
G_OBJECT_CLASS (meta_x11_display_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_x11_display_class_init (MetaX11DisplayClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->dispose = meta_x11_display_dispose;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_x11_display_init (MetaX11Display *x11_display)
|
|
|
|
{
|
2017-08-26 15:28:04 -04:00
|
|
|
quark_x11_display_logical_monitor_data =
|
|
|
|
g_quark_from_static_string ("-meta-x11-display-logical-monitor-data");
|
2017-08-26 12:24:46 -04:00
|
|
|
}
|
|
|
|
|
2017-08-26 12:28:53 -04:00
|
|
|
static void
|
|
|
|
query_xsync_extension (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
int major, minor;
|
|
|
|
|
|
|
|
x11_display->have_xsync = FALSE;
|
|
|
|
|
|
|
|
x11_display->xsync_error_base = 0;
|
|
|
|
x11_display->xsync_event_base = 0;
|
|
|
|
|
|
|
|
/* I don't think we really have to fill these in */
|
|
|
|
major = SYNC_MAJOR_VERSION;
|
|
|
|
minor = SYNC_MINOR_VERSION;
|
|
|
|
|
|
|
|
if (!XSyncQueryExtension (x11_display->xdisplay,
|
|
|
|
&x11_display->xsync_event_base,
|
|
|
|
&x11_display->xsync_error_base) ||
|
|
|
|
!XSyncInitialize (x11_display->xdisplay,
|
|
|
|
&major, &minor))
|
|
|
|
{
|
|
|
|
x11_display->xsync_error_base = 0;
|
|
|
|
x11_display->xsync_event_base = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x11_display->have_xsync = TRUE;
|
|
|
|
XSyncSetPriority (x11_display->xdisplay, None, 10);
|
|
|
|
}
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Attempted to init Xsync, found version %d.%d error base %d event base %d",
|
2017-08-26 12:28:53 -04:00
|
|
|
major, minor,
|
|
|
|
x11_display->xsync_error_base,
|
|
|
|
x11_display->xsync_event_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
query_xshape_extension (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
x11_display->have_shape = FALSE;
|
|
|
|
|
|
|
|
x11_display->shape_error_base = 0;
|
|
|
|
x11_display->shape_event_base = 0;
|
|
|
|
|
|
|
|
if (!XShapeQueryExtension (x11_display->xdisplay,
|
|
|
|
&x11_display->shape_event_base,
|
|
|
|
&x11_display->shape_error_base))
|
|
|
|
{
|
|
|
|
x11_display->shape_error_base = 0;
|
|
|
|
x11_display->shape_event_base = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
x11_display->have_shape = TRUE;
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Attempted to init Shape, found error base %d event base %d",
|
2017-08-26 12:28:53 -04:00
|
|
|
x11_display->shape_error_base,
|
|
|
|
x11_display->shape_event_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
query_xcomposite_extension (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
x11_display->have_composite = FALSE;
|
|
|
|
|
|
|
|
x11_display->composite_error_base = 0;
|
|
|
|
x11_display->composite_event_base = 0;
|
|
|
|
|
|
|
|
if (!XCompositeQueryExtension (x11_display->xdisplay,
|
|
|
|
&x11_display->composite_event_base,
|
|
|
|
&x11_display->composite_error_base))
|
|
|
|
{
|
|
|
|
x11_display->composite_error_base = 0;
|
|
|
|
x11_display->composite_event_base = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x11_display->composite_major_version = 0;
|
|
|
|
x11_display->composite_minor_version = 0;
|
|
|
|
if (XCompositeQueryVersion (x11_display->xdisplay,
|
|
|
|
&x11_display->composite_major_version,
|
|
|
|
&x11_display->composite_minor_version))
|
|
|
|
{
|
|
|
|
x11_display->have_composite = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x11_display->composite_major_version = 0;
|
|
|
|
x11_display->composite_minor_version = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_verbose ("Attempted to init Composite, found error base %d event base %d "
|
2020-10-02 11:47:22 -04:00
|
|
|
"extn ver %d %d",
|
2017-08-26 12:28:53 -04:00
|
|
|
x11_display->composite_error_base,
|
|
|
|
x11_display->composite_event_base,
|
|
|
|
x11_display->composite_major_version,
|
|
|
|
x11_display->composite_minor_version);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
query_xdamage_extension (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
x11_display->have_damage = FALSE;
|
|
|
|
|
|
|
|
x11_display->damage_error_base = 0;
|
|
|
|
x11_display->damage_event_base = 0;
|
|
|
|
|
|
|
|
if (!XDamageQueryExtension (x11_display->xdisplay,
|
|
|
|
&x11_display->damage_event_base,
|
|
|
|
&x11_display->damage_error_base))
|
|
|
|
{
|
|
|
|
x11_display->damage_error_base = 0;
|
|
|
|
x11_display->damage_event_base = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
x11_display->have_damage = TRUE;
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Attempted to init Damage, found error base %d event base %d",
|
2017-08-26 12:28:53 -04:00
|
|
|
x11_display->damage_error_base,
|
|
|
|
x11_display->damage_event_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
query_xfixes_extension (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
x11_display->xfixes_error_base = 0;
|
|
|
|
x11_display->xfixes_event_base = 0;
|
|
|
|
|
|
|
|
if (XFixesQueryExtension (x11_display->xdisplay,
|
|
|
|
&x11_display->xfixes_event_base,
|
|
|
|
&x11_display->xfixes_error_base))
|
|
|
|
{
|
|
|
|
int xfixes_major, xfixes_minor;
|
|
|
|
|
|
|
|
XFixesQueryVersion (x11_display->xdisplay, &xfixes_major, &xfixes_minor);
|
|
|
|
|
|
|
|
if (xfixes_major * 100 + xfixes_minor < 500)
|
|
|
|
meta_fatal ("Mutter requires XFixes 5.0");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
meta_fatal ("Mutter requires XFixes 5.0");
|
|
|
|
}
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Attempted to init XFixes, found error base %d event base %d",
|
2017-08-26 12:28:53 -04:00
|
|
|
x11_display->xfixes_error_base,
|
|
|
|
x11_display->xfixes_event_base);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
query_xi_extension (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
int major = 2, minor = 3;
|
|
|
|
gboolean has_xi = FALSE;
|
|
|
|
|
|
|
|
if (XQueryExtension (x11_display->xdisplay,
|
|
|
|
"XInputExtension",
|
|
|
|
&x11_display->xinput_opcode,
|
|
|
|
&x11_display->xinput_error_base,
|
|
|
|
&x11_display->xinput_event_base))
|
|
|
|
{
|
2022-03-14 17:45:34 -04:00
|
|
|
if (XIQueryVersion (x11_display->xdisplay, &major, &minor) == Success)
|
|
|
|
has_xi = TRUE;
|
2017-08-26 12:28:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_xi)
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_fatal ("X server doesn't have the XInput extension, version 2.2 or newer");
|
2017-08-26 12:28:53 -04:00
|
|
|
}
|
|
|
|
|
2017-08-26 16:35:18 -04:00
|
|
|
/*
|
2020-08-26 05:49:50 -04:00
|
|
|
* Initialises the bell subsystem. This involves initialising
|
2017-08-26 16:35:18 -04:00
|
|
|
* XKB (which, despite being a keyboard extension, is the
|
|
|
|
* place to look for bell notifications), then asking it
|
|
|
|
* to send us bell notifications, and then also switching
|
|
|
|
* off the audible bell if we're using a visual one ourselves.
|
|
|
|
*
|
|
|
|
* \bug There is a line of code that's never run that tells
|
|
|
|
* XKB to reset the bell status after we quit. Bill H said
|
|
|
|
* (<http://bugzilla.gnome.org/show_bug.cgi?id=99886#c12>)
|
|
|
|
* that XFree86's implementation is broken so we shouldn't
|
|
|
|
* call it, but that was in 2002. Is it working now?
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_x11_bell (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
int xkb_base_error_type, xkb_opcode;
|
|
|
|
|
|
|
|
if (!XkbQueryExtension (x11_display->xdisplay, &xkb_opcode,
|
|
|
|
&x11_display->xkb_base_event_type,
|
|
|
|
&xkb_base_error_type,
|
|
|
|
NULL, NULL))
|
|
|
|
{
|
|
|
|
x11_display->xkb_base_event_type = -1;
|
|
|
|
meta_warning ("could not find XKB extension.");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned int mask = XkbBellNotifyMask;
|
|
|
|
gboolean visual_bell_auto_reset = FALSE;
|
|
|
|
/* TRUE if and when non-broken version is available */
|
|
|
|
XkbSelectEvents (x11_display->xdisplay,
|
|
|
|
XkbUseCoreKbd,
|
|
|
|
XkbBellNotifyMask,
|
|
|
|
XkbBellNotifyMask);
|
|
|
|
|
|
|
|
if (visual_bell_auto_reset)
|
|
|
|
{
|
|
|
|
XkbSetAutoResetControls (x11_display->xdisplay,
|
|
|
|
XkbAudibleBellMask,
|
|
|
|
&mask,
|
|
|
|
&mask);
|
|
|
|
}
|
|
|
|
}
|
2019-05-27 16:43:21 -04:00
|
|
|
|
|
|
|
/* We are playing sounds using libcanberra support, we handle the
|
|
|
|
* bell whether its an audible bell or a visible bell */
|
|
|
|
XkbChangeEnabledControls (x11_display->xdisplay,
|
|
|
|
XkbUseCoreKbd,
|
|
|
|
XkbAudibleBellMask,
|
|
|
|
0);
|
2017-08-26 16:35:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* \bug This is never called! If we had XkbSetAutoResetControls
|
|
|
|
* enabled in meta_x11_bell_init(), this wouldn't be a problem,
|
|
|
|
* but we don't.
|
|
|
|
*/
|
|
|
|
G_GNUC_UNUSED static void
|
|
|
|
shutdown_x11_bell (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
/* TODO: persist initial bell state in display, reset here */
|
|
|
|
XkbChangeEnabledControls (x11_display->xdisplay,
|
|
|
|
XkbUseCoreKbd,
|
|
|
|
XkbAudibleBellMask,
|
|
|
|
XkbAudibleBellMask);
|
|
|
|
}
|
|
|
|
|
2017-08-26 14:54:39 -04:00
|
|
|
static void
|
|
|
|
set_desktop_geometry_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
unsigned long data[2];
|
2017-08-27 14:44:38 -04:00
|
|
|
int monitor_width, monitor_height;
|
2017-08-26 14:54:39 -04:00
|
|
|
|
|
|
|
if (x11_display->display->closing > 0)
|
|
|
|
return;
|
|
|
|
|
2017-08-27 14:44:38 -04:00
|
|
|
meta_display_get_size (x11_display->display, &monitor_width, &monitor_height);
|
|
|
|
|
|
|
|
data[0] = monitor_width;
|
|
|
|
data[1] = monitor_height;
|
2017-08-26 14:54:39 -04:00
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu", data[0], data[1]);
|
2017-08-26 14:54:39 -04:00
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 14:54:39 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_DESKTOP_GEOMETRY,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 2);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 14:54:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_desktop_viewport_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
unsigned long data[2];
|
|
|
|
|
|
|
|
if (x11_display->display->closing > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mutter does not implement viewports, so this is a fixed 0,0
|
|
|
|
*/
|
|
|
|
data[0] = 0;
|
|
|
|
data[1] = 0;
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0");
|
2017-08-26 14:54:39 -04:00
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 14:54:39 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_DESKTOP_VIEWPORT,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 2);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 14:54:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
set_wm_check_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
unsigned long data[1];
|
|
|
|
|
|
|
|
g_return_val_if_fail (x11_display->leader_window != None, 0);
|
|
|
|
|
|
|
|
data[0] = x11_display->leader_window;
|
|
|
|
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_SUPPORTING_WM_CHECK,
|
|
|
|
XA_WINDOW,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
|
|
|
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
unset_wm_check_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
XDeleteProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_SUPPORTING_WM_CHECK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
set_supported_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
Atom atoms[] = {
|
|
|
|
#define EWMH_ATOMS_ONLY
|
|
|
|
#define item(x) x11_display->atom_##x,
|
|
|
|
#include "x11/atomnames.h"
|
|
|
|
#undef item
|
|
|
|
#undef EWMH_ATOMS_ONLY
|
|
|
|
|
|
|
|
x11_display->atom__GTK_FRAME_EXTENTS,
|
|
|
|
x11_display->atom__GTK_SHOW_WINDOW_MENU,
|
2019-01-03 11:57:06 -05:00
|
|
|
x11_display->atom__GTK_EDGE_CONSTRAINTS,
|
2018-12-31 09:29:11 -05:00
|
|
|
x11_display->atom__GTK_WORKAREAS,
|
2017-08-26 14:54:39 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_SUPPORTED,
|
|
|
|
XA_ATOM,
|
|
|
|
32, PropModeReplace,
|
|
|
|
(guchar*) atoms, G_N_ELEMENTS(atoms));
|
|
|
|
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
set_wm_icon_size_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
#define N_VALS 6
|
|
|
|
gulong vals[N_VALS];
|
|
|
|
|
|
|
|
/* We've bumped the real icon size up to 96x96, but
|
|
|
|
* we really should not add these sorts of constraints
|
|
|
|
* on clients still using the legacy WM_HINTS interface.
|
|
|
|
*/
|
|
|
|
#define LEGACY_ICON_SIZE 32
|
|
|
|
|
|
|
|
/* min width, min height, max w, max h, width inc, height inc */
|
|
|
|
vals[0] = LEGACY_ICON_SIZE;
|
|
|
|
vals[1] = LEGACY_ICON_SIZE;
|
|
|
|
vals[2] = LEGACY_ICON_SIZE;
|
|
|
|
vals[3] = LEGACY_ICON_SIZE;
|
|
|
|
vals[4] = 0;
|
|
|
|
vals[5] = 0;
|
|
|
|
#undef LEGACY_ICON_SIZE
|
|
|
|
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom_WM_ICON_SIZE,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) vals, N_VALS);
|
|
|
|
|
|
|
|
return Success;
|
|
|
|
#undef N_VALS
|
|
|
|
}
|
|
|
|
|
2017-08-26 14:51:28 -04:00
|
|
|
static Window
|
|
|
|
take_manager_selection (MetaX11Display *x11_display,
|
|
|
|
Window xroot,
|
|
|
|
Atom manager_atom,
|
|
|
|
int timestamp,
|
|
|
|
gboolean should_replace)
|
|
|
|
{
|
|
|
|
Window current_owner, new_owner;
|
|
|
|
|
|
|
|
current_owner = XGetSelectionOwner (x11_display->xdisplay, manager_atom);
|
|
|
|
if (current_owner != None)
|
|
|
|
{
|
|
|
|
XSetWindowAttributes attrs;
|
|
|
|
|
|
|
|
if (should_replace)
|
|
|
|
{
|
|
|
|
/* We want to find out when the current selection owner dies */
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 14:51:28 -04:00
|
|
|
attrs.event_mask = StructureNotifyMask;
|
|
|
|
XChangeWindowAttributes (x11_display->xdisplay, current_owner, CWEventMask, &attrs);
|
2017-08-27 14:48:55 -04:00
|
|
|
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
|
2017-08-26 14:51:28 -04:00
|
|
|
current_owner = None; /* don't wait for it to die later on */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
meta_warning (_("Display “%s” already has a window manager; try using the --replace option to replace the current window manager."),
|
|
|
|
x11_display->name);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We need SelectionClear and SelectionRequest events on the new owner,
|
|
|
|
* but those cannot be masked, so we only need NoEventMask.
|
|
|
|
*/
|
|
|
|
new_owner = meta_x11_display_create_offscreen_window (x11_display, xroot, NoEventMask);
|
|
|
|
|
|
|
|
XSetSelectionOwner (x11_display->xdisplay, manager_atom, new_owner, timestamp);
|
|
|
|
|
|
|
|
if (XGetSelectionOwner (x11_display->xdisplay, manager_atom) != new_owner)
|
|
|
|
{
|
|
|
|
meta_warning ("Could not acquire selection: %s", XGetAtomName (x11_display->xdisplay, manager_atom));
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
/* Send client message indicating that we are now the selection owner */
|
2022-11-29 13:00:33 -05:00
|
|
|
XClientMessageEvent ev = { 0, };
|
2017-08-26 14:51:28 -04:00
|
|
|
|
|
|
|
ev.type = ClientMessage;
|
|
|
|
ev.window = xroot;
|
|
|
|
ev.message_type = x11_display->atom_MANAGER;
|
|
|
|
ev.format = 32;
|
|
|
|
ev.data.l[0] = timestamp;
|
|
|
|
ev.data.l[1] = manager_atom;
|
|
|
|
|
|
|
|
XSendEvent (x11_display->xdisplay, xroot, False, StructureNotifyMask, (XEvent *) &ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wait for old window manager to go away */
|
|
|
|
if (current_owner != None)
|
|
|
|
{
|
|
|
|
XEvent event;
|
|
|
|
|
|
|
|
/* We sort of block infinitely here which is probably lame. */
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Waiting for old window manager to exit");
|
2017-08-26 14:51:28 -04:00
|
|
|
do
|
|
|
|
XWindowEvent (x11_display->xdisplay, current_owner, StructureNotifyMask, &event);
|
|
|
|
while (event.type != DestroyNotify);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_owner;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create the leader window here. Set its properties and
|
|
|
|
* use the timestamp from one of the PropertyNotify events
|
|
|
|
* that will follow.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
init_leader_window (MetaX11Display *x11_display,
|
|
|
|
guint32 *timestamp)
|
|
|
|
{
|
2021-03-03 16:12:01 -05:00
|
|
|
MetaContext *context = meta_display_get_context (x11_display->display);
|
2021-03-03 17:02:02 -05:00
|
|
|
const char *gnome_wm_keybindings;
|
2017-08-26 14:51:28 -04:00
|
|
|
gulong data[1];
|
|
|
|
XEvent event;
|
|
|
|
|
|
|
|
/* We only care about the PropertyChangeMask in the next 30 or so lines of
|
|
|
|
* code. Note that gdk will at some point unset the PropertyChangeMask for
|
|
|
|
* this window, so we can't rely on it still being set later. See bug
|
|
|
|
* 354213 for details.
|
|
|
|
*/
|
|
|
|
x11_display->leader_window =
|
|
|
|
meta_x11_display_create_offscreen_window (x11_display,
|
|
|
|
x11_display->xroot,
|
|
|
|
PropertyChangeMask);
|
|
|
|
|
|
|
|
meta_prop_set_utf8_string_hint (x11_display,
|
|
|
|
x11_display->leader_window,
|
|
|
|
x11_display->atom__NET_WM_NAME,
|
2021-03-03 16:12:01 -05:00
|
|
|
meta_context_get_name (context));
|
2017-08-26 14:51:28 -04:00
|
|
|
|
2021-03-03 17:02:02 -05:00
|
|
|
gnome_wm_keybindings = meta_context_get_gnome_wm_keybindings (context);
|
2017-08-26 14:51:28 -04:00
|
|
|
meta_prop_set_utf8_string_hint (x11_display,
|
|
|
|
x11_display->leader_window,
|
|
|
|
x11_display->atom__GNOME_WM_KEYBINDINGS,
|
|
|
|
gnome_wm_keybindings);
|
|
|
|
|
|
|
|
meta_prop_set_utf8_string_hint (x11_display,
|
|
|
|
x11_display->leader_window,
|
|
|
|
x11_display->atom__MUTTER_VERSION,
|
|
|
|
VERSION);
|
|
|
|
|
|
|
|
data[0] = x11_display->leader_window;
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->leader_window,
|
|
|
|
x11_display->atom__NET_SUPPORTING_WM_CHECK,
|
|
|
|
XA_WINDOW,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
|
|
|
|
|
|
|
XWindowEvent (x11_display->xdisplay,
|
|
|
|
x11_display->leader_window,
|
|
|
|
PropertyChangeMask,
|
|
|
|
&event);
|
|
|
|
|
|
|
|
if (timestamp)
|
|
|
|
*timestamp = event.xproperty.time;
|
|
|
|
|
|
|
|
/* Make it painfully clear that we can't rely on PropertyNotify events on
|
|
|
|
* this window, as per bug 354213.
|
|
|
|
*/
|
|
|
|
XSelectInput (x11_display->xdisplay,
|
|
|
|
x11_display->leader_window,
|
|
|
|
NoEventMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_event_masks (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
long event_mask;
|
|
|
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
|
|
|
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
|
|
|
|
|
|
|
XISetMask (mask.mask, XI_Enter);
|
|
|
|
XISetMask (mask.mask, XI_Leave);
|
|
|
|
XISetMask (mask.mask, XI_FocusIn);
|
|
|
|
XISetMask (mask.mask, XI_FocusOut);
|
|
|
|
XISelectEvents (x11_display->xdisplay, x11_display->xroot, &mask, 1);
|
|
|
|
|
|
|
|
event_mask = (SubstructureRedirectMask | SubstructureNotifyMask |
|
|
|
|
StructureNotifyMask | ColormapChangeMask | PropertyChangeMask);
|
|
|
|
XSelectInput (x11_display->xdisplay, x11_display->xroot, event_mask);
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
static void
|
2017-08-27 15:02:40 -04:00
|
|
|
set_active_workspace_hint (MetaWorkspaceManager *workspace_manager,
|
|
|
|
MetaX11Display *x11_display)
|
2017-08-26 16:29:10 -04:00
|
|
|
{
|
|
|
|
unsigned long data[1];
|
|
|
|
|
|
|
|
/* this is because we destroy the spaces in order,
|
|
|
|
* so we always end up setting a current desktop of
|
|
|
|
* 0 when closing a screen, so lose the current desktop
|
|
|
|
* on restart. By doing this we keep the current
|
|
|
|
* desktop on restart.
|
|
|
|
*/
|
2017-08-27 15:02:40 -04:00
|
|
|
if (x11_display->display->closing > 0)
|
2017-08-26 16:29:10 -04:00
|
|
|
return;
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
data[0] = meta_workspace_index (workspace_manager->active_workspace);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Setting _NET_CURRENT_DESKTOP to %lu", data[0]);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_CURRENT_DESKTOP,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-08-27 15:02:40 -04:00
|
|
|
set_number_of_spaces_hint (MetaWorkspaceManager *workspace_manager,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
gpointer user_data)
|
2017-08-26 16:29:10 -04:00
|
|
|
{
|
|
|
|
MetaX11Display *x11_display = user_data;
|
|
|
|
unsigned long data[1];
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
if (x11_display->display->closing > 0)
|
2017-08-26 16:29:10 -04:00
|
|
|
return;
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
data[0] = meta_workspace_manager_get_n_workspaces (workspace_manager);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu", data[0]);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_NUMBER_OF_DESKTOPS,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-08-27 15:02:40 -04:00
|
|
|
set_showing_desktop_hint (MetaWorkspaceManager *workspace_manager,
|
|
|
|
MetaX11Display *x11_display)
|
2017-08-26 16:29:10 -04:00
|
|
|
{
|
|
|
|
unsigned long data[1];
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
data[0] = workspace_manager->active_workspace->showing_desktop ? 1 : 0;
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_SHOWING_DESKTOP,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_workspace_names (MetaX11Display *x11_display)
|
|
|
|
{
|
2017-08-27 15:02:40 -04:00
|
|
|
MetaWorkspaceManager *workspace_manager;
|
2017-08-26 16:29:10 -04:00
|
|
|
GString *flattened;
|
|
|
|
int i;
|
|
|
|
int n_spaces;
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
workspace_manager = x11_display->display->workspace_manager;
|
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
/* flatten to nul-separated list */
|
2017-08-27 15:02:40 -04:00
|
|
|
n_spaces = meta_workspace_manager_get_n_workspaces (workspace_manager);
|
2017-08-26 16:29:10 -04:00
|
|
|
flattened = g_string_new ("");
|
|
|
|
i = 0;
|
|
|
|
while (i < n_spaces)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = meta_prefs_get_workspace_name (i);
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
g_string_append_len (flattened, name,
|
|
|
|
strlen (name) + 1);
|
|
|
|
else
|
|
|
|
g_string_append_len (flattened, "", 1);
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_DESKTOP_NAMES,
|
|
|
|
x11_display->atom_UTF8_STRING,
|
|
|
|
8, PropModeReplace,
|
|
|
|
(unsigned char *)flattened->str, flattened->len);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
|
|
|
g_string_free (flattened, TRUE);
|
|
|
|
}
|
|
|
|
|
2018-12-31 09:29:11 -05:00
|
|
|
static void
|
|
|
|
set_workspace_work_area_hint (MetaWorkspace *workspace,
|
|
|
|
MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
MetaMonitorManager *monitor_manager;
|
|
|
|
GList *logical_monitors;
|
|
|
|
GList *l;
|
|
|
|
int num_monitors;
|
|
|
|
unsigned long *data;
|
|
|
|
unsigned long *tmp;
|
2021-09-04 15:53:37 -04:00
|
|
|
g_autofree char *workarea_name = NULL;
|
2018-12-31 09:29:11 -05:00
|
|
|
Atom workarea_atom;
|
|
|
|
|
2022-09-07 05:34:35 -04:00
|
|
|
monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend_from_x11_display (x11_display));
|
2018-12-31 09:29:11 -05:00
|
|
|
logical_monitors = meta_monitor_manager_get_logical_monitors (monitor_manager);
|
|
|
|
num_monitors = meta_monitor_manager_get_num_logical_monitors (monitor_manager);
|
|
|
|
|
|
|
|
data = g_new (unsigned long, num_monitors * 4);
|
|
|
|
tmp = data;
|
|
|
|
|
|
|
|
for (l = logical_monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaRectangle area;
|
|
|
|
|
|
|
|
meta_workspace_get_work_area_for_logical_monitor (workspace, l->data, &area);
|
|
|
|
|
|
|
|
tmp[0] = area.x;
|
|
|
|
tmp[1] = area.y;
|
|
|
|
tmp[2] = area.width;
|
|
|
|
tmp[3] = area.height;
|
|
|
|
|
|
|
|
tmp += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
workarea_name = g_strdup_printf ("_GTK_WORKAREAS_D%d",
|
|
|
|
meta_workspace_index (workspace));
|
|
|
|
|
|
|
|
workarea_atom = XInternAtom (x11_display->xdisplay, workarea_name, False);
|
|
|
|
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
workarea_atom,
|
|
|
|
XA_CARDINAL, 32, PropModeReplace,
|
|
|
|
(guchar*) data, num_monitors * 4);
|
|
|
|
meta_x11_error_trap_pop (x11_display);
|
|
|
|
|
|
|
|
g_free (data);
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:41:16 -04:00
|
|
|
static void
|
|
|
|
set_work_area_hint (MetaDisplay *display,
|
|
|
|
MetaX11Display *x11_display)
|
|
|
|
{
|
2017-08-27 15:02:40 -04:00
|
|
|
MetaWorkspaceManager *workspace_manager = display->workspace_manager;
|
2017-08-26 16:41:16 -04:00
|
|
|
int num_workspaces;
|
|
|
|
GList *l;
|
|
|
|
unsigned long *data, *tmp;
|
|
|
|
MetaRectangle area;
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
num_workspaces = meta_workspace_manager_get_n_workspaces (workspace_manager);
|
2017-08-26 16:41:16 -04:00
|
|
|
data = g_new (unsigned long, num_workspaces * 4);
|
|
|
|
tmp = data;
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
for (l = workspace_manager->workspaces; l; l = l->next)
|
2017-08-26 16:41:16 -04:00
|
|
|
{
|
|
|
|
MetaWorkspace *workspace = l->data;
|
|
|
|
|
|
|
|
meta_workspace_get_work_area_all_monitors (workspace, &area);
|
2018-12-31 09:29:11 -05:00
|
|
|
set_workspace_work_area_hint (workspace, x11_display);
|
|
|
|
|
2017-08-26 16:41:16 -04:00
|
|
|
tmp[0] = area.x;
|
|
|
|
tmp[1] = area.y;
|
|
|
|
tmp[2] = area.width;
|
|
|
|
tmp[3] = area.height;
|
|
|
|
|
|
|
|
tmp += 4;
|
|
|
|
}
|
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:41:16 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_WORKAREA,
|
|
|
|
XA_CARDINAL, 32, PropModeReplace,
|
|
|
|
(guchar*) data, num_workspaces*4);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 16:41:16 -04:00
|
|
|
|
|
|
|
g_free (data);
|
|
|
|
}
|
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
static const char *
|
|
|
|
get_display_name (MetaDisplay *display)
|
2019-05-24 13:51:00 -04:00
|
|
|
{
|
|
|
|
#ifdef HAVE_WAYLAND
|
2022-05-28 17:39:30 -04:00
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaWaylandCompositor *compositor =
|
|
|
|
meta_context_get_wayland_compositor (context);
|
2019-05-24 13:51:00 -04:00
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
if (compositor)
|
|
|
|
return meta_wayland_get_private_xwayland_display_name (compositor);
|
2019-05-24 13:51:00 -04:00
|
|
|
else
|
|
|
|
#endif
|
2022-05-28 17:39:30 -04:00
|
|
|
return g_getenv ("DISPLAY");
|
2019-05-24 13:51:00 -04:00
|
|
|
}
|
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
static GdkDisplay *
|
|
|
|
open_gdk_display (MetaDisplay *display,
|
|
|
|
GError **error)
|
2017-08-26 12:24:46 -04:00
|
|
|
{
|
2017-12-26 02:58:54 -05:00
|
|
|
const char *xdisplay_name;
|
2017-08-26 16:52:02 -04:00
|
|
|
GdkDisplay *gdk_display;
|
2022-07-06 11:38:55 -04:00
|
|
|
const char *gdk_backend_env = NULL;
|
2017-08-26 16:52:02 -04:00
|
|
|
const char *gdk_gl_env = NULL;
|
x11-display: Set NO_AT_BRIDGE to 1 while opening the GDK display
gnome-shell has this hack where it sets the environment variable
"NO_AT_BRIDGE" to "1" before calling meta_init() and then unsets it
after meta_init() returns.
This variable being set to "1" will then cause the ATK bridge in
at-spi2-gtk to fail to load, which GTK then ignores. This is on purpose,
since accessibility is supposed to be done done by GNOME Shell via
Clutter, not via GTK.
The problem is that, now, by default, setting "NO_AT_BRIDGE" to
"1" during meta_init() only has the desired effect on an X11 session,
where we always connect to the X11 server on startup (i.e. during
meta_init()). With Xwayland on-demand, we do not attempt to create the
GDK display during meta_init(), thus this hack falls apart.
Since there are no real altenatives to this hack, just move it to
mutter, which have a better idea when GDK displays are created or not.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1744>
2021-02-23 12:14:17 -05:00
|
|
|
const char *old_no_at_bridge;
|
2017-12-26 02:58:54 -05:00
|
|
|
Display *xdisplay;
|
2017-08-26 16:52:02 -04:00
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
xdisplay_name = get_display_name (display);
|
2017-08-26 16:52:02 -04:00
|
|
|
if (!xdisplay_name)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Unable to open display, DISPLAY not set");
|
2022-05-28 17:39:30 -04:00
|
|
|
return NULL;
|
2017-08-26 16:52:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
gdk_set_allowed_backends ("x11");
|
|
|
|
|
2022-07-06 11:38:55 -04:00
|
|
|
gdk_backend_env = g_getenv ("GDK_BACKEND");
|
|
|
|
/* GDK would fail to initialize with e.g. GDK_BACKEND=wayland */
|
|
|
|
g_unsetenv ("GDK_BACKEND");
|
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
gdk_gl_env = g_getenv ("GDK_GL");
|
2017-12-26 02:58:54 -05:00
|
|
|
g_setenv ("GDK_GL", "disable", TRUE);
|
|
|
|
|
|
|
|
gdk_parse_args (NULL, NULL);
|
|
|
|
if (!gtk_parse_args (NULL, NULL))
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to initialize gtk");
|
2022-05-28 17:39:30 -04:00
|
|
|
return NULL;
|
2017-12-26 02:58:54 -05:00
|
|
|
}
|
2017-08-26 16:52:02 -04:00
|
|
|
|
x11-display: Set NO_AT_BRIDGE to 1 while opening the GDK display
gnome-shell has this hack where it sets the environment variable
"NO_AT_BRIDGE" to "1" before calling meta_init() and then unsets it
after meta_init() returns.
This variable being set to "1" will then cause the ATK bridge in
at-spi2-gtk to fail to load, which GTK then ignores. This is on purpose,
since accessibility is supposed to be done done by GNOME Shell via
Clutter, not via GTK.
The problem is that, now, by default, setting "NO_AT_BRIDGE" to
"1" during meta_init() only has the desired effect on an X11 session,
where we always connect to the X11 server on startup (i.e. during
meta_init()). With Xwayland on-demand, we do not attempt to create the
GDK display during meta_init(), thus this hack falls apart.
Since there are no real altenatives to this hack, just move it to
mutter, which have a better idea when GDK displays are created or not.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1744>
2021-02-23 12:14:17 -05:00
|
|
|
old_no_at_bridge = g_getenv ("NO_AT_BRIDGE");
|
|
|
|
g_setenv ("NO_AT_BRIDGE", "1", TRUE);
|
2017-08-26 16:52:02 -04:00
|
|
|
gdk_display = gdk_display_open (xdisplay_name);
|
2021-02-27 02:27:36 -05:00
|
|
|
|
|
|
|
if (old_no_at_bridge)
|
|
|
|
g_setenv ("NO_AT_BRIDGE", old_no_at_bridge, TRUE);
|
|
|
|
else
|
|
|
|
g_unsetenv ("NO_AT_BRIDGE");
|
2017-08-26 16:52:02 -04:00
|
|
|
|
|
|
|
if (!gdk_display)
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning (_("Failed to initialize GDK"));
|
2017-08-26 16:52:02 -04:00
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to initialize GDK");
|
2022-05-28 17:39:30 -04:00
|
|
|
return NULL;
|
2017-08-26 16:52:02 -04:00
|
|
|
}
|
|
|
|
|
2022-07-06 11:38:55 -04:00
|
|
|
if (gdk_backend_env)
|
|
|
|
g_setenv("GDK_BACKEND", gdk_backend_env, TRUE);
|
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
if (gdk_gl_env)
|
|
|
|
g_setenv("GDK_GL", gdk_gl_env, TRUE);
|
|
|
|
else
|
|
|
|
unsetenv("GDK_GL");
|
|
|
|
|
|
|
|
/* We need to be able to fully trust that the window and monitor sizes
|
|
|
|
that Gdk reports corresponds to the X ones, so we disable the automatic
|
|
|
|
scale handling */
|
|
|
|
gdk_x11_display_set_window_scale (gdk_display, 1);
|
2017-08-26 12:26:30 -04:00
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Opening display '%s'", XDisplayName (NULL));
|
2017-08-26 12:26:30 -04:00
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display);
|
2017-08-26 12:26:30 -04:00
|
|
|
|
|
|
|
if (xdisplay == NULL)
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning (_("Failed to open X Window System display “%s”"),
|
2017-08-26 12:26:30 -04:00
|
|
|
XDisplayName (NULL));
|
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to open X11 display");
|
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
gdk_display_close (gdk_display);
|
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
return NULL;
|
2017-08-26 12:26:30 -04:00
|
|
|
}
|
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
return gdk_display;
|
|
|
|
}
|
2017-12-26 02:58:54 -05:00
|
|
|
|
2022-01-28 18:49:50 -05:00
|
|
|
static void
|
|
|
|
on_window_visibility_updated (MetaDisplay *display,
|
|
|
|
GList *placed_windows,
|
|
|
|
GList *shown_windows,
|
|
|
|
GList *hidden_windows,
|
|
|
|
MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
GList *l;
|
|
|
|
|
|
|
|
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (display->mouse_mode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (l = shown_windows; l; l = l->next)
|
|
|
|
meta_x11_display_increment_focus_sentinel (x11_display);
|
|
|
|
}
|
|
|
|
|
x11: Integrate frames client into Mutter
Replace the in-process implementation of frames with the external
frames client.
When a client window is created and managed by Mutter, Mutter will
determine whether it is a window that requires decorations and
hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
property on the client window.
After the frames client created a window that has the _MUTTER_FRAME_FOR
property, Mutter will proceed to reparent the client window on the
frame window, and show them as a single unit.
Rendering and event handling on the frame window will be performed by
the external client, Mutter is still responsible for everything else,
namely resizing client and frame window in synchronization, and
managing updates on the MetaWindowActor.
In order to let the frame be managed by the external client, Mutter
needs to change the way some properties are forwarded to the client
and/or frame windows. Some properties are necessary to keep propagating
to the client window only, some others need to happen on the frame
window now, and some others needs to be propagated on both so they
are synchronized about the behavior.
Also, some events that were previously totally unexpected in frame
windows are now susceptible to happen, so must be allowed now.
MetaFrame in src/core/frame.c now acts as the wrapper of foreign
windows created by the frames client, from the Mutter side. Location,
size, and lifetime are still largely in control of Mutter, some
details like visible/invisible borders are obtained from the client
instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
properties, respectively).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
2022-09-08 04:35:47 -04:00
|
|
|
static void
|
|
|
|
on_frames_client_died (GObject *source,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaX11Display *x11_display = user_data;
|
|
|
|
GSubprocess *proc = G_SUBPROCESS (source);
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
if (!g_subprocess_wait_finish (proc, result, &error))
|
|
|
|
{
|
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_warning ("Error obtaining frames client exit status: %s\n", error->message);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_object (&x11_display->frames_client_cancellable);
|
|
|
|
g_clear_object (&x11_display->frames_client);
|
|
|
|
|
|
|
|
if (g_subprocess_get_if_signaled (proc))
|
|
|
|
{
|
|
|
|
int signum;
|
|
|
|
|
|
|
|
signum = g_subprocess_get_term_sig (proc);
|
|
|
|
|
|
|
|
/* Bring it up again, unless it was forcibly closed */
|
|
|
|
if (signum != SIGTERM && signum != SIGKILL)
|
|
|
|
meta_x11_display_init_frames_client (x11_display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_x11_display_init_frames_client (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
const char *display_name;
|
|
|
|
|
|
|
|
display_name = get_display_name (x11_display->display);
|
|
|
|
x11_display->frames_client_cancellable = g_cancellable_new ();
|
|
|
|
x11_display->frames_client = meta_frame_launch_client (x11_display,
|
|
|
|
display_name);
|
|
|
|
g_subprocess_wait_async (x11_display->frames_client,
|
|
|
|
x11_display->frames_client_cancellable,
|
|
|
|
on_frames_client_died, x11_display);
|
|
|
|
}
|
|
|
|
|
2017-12-26 02:58:54 -05:00
|
|
|
/**
|
|
|
|
* meta_x11_display_new:
|
|
|
|
*
|
|
|
|
* Opens a new X11 display, sets it up, initialises all the X extensions
|
|
|
|
* we will need.
|
|
|
|
*
|
|
|
|
* Returns: #MetaX11Display if the display was opened successfully,
|
|
|
|
* and %NULL otherwise-- that is, if the display doesn't exist or
|
|
|
|
* it already has a window manager, and sets the error appropriately.
|
|
|
|
*/
|
|
|
|
MetaX11Display *
|
2022-05-28 17:48:36 -04:00
|
|
|
meta_x11_display_new (MetaDisplay *display,
|
|
|
|
GError **error)
|
2017-12-26 02:58:54 -05:00
|
|
|
{
|
2022-05-30 14:27:02 -04:00
|
|
|
MetaContext *context = meta_display_get_context (display);
|
2022-09-07 05:34:35 -04:00
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend);
|
2022-04-06 05:32:51 -04:00
|
|
|
g_autoptr (MetaX11Display) x11_display = NULL;
|
2017-12-26 02:58:54 -05:00
|
|
|
Display *xdisplay;
|
|
|
|
Screen *xscreen;
|
|
|
|
Window xroot;
|
|
|
|
int i, number;
|
|
|
|
Window new_wm_sn_owner;
|
|
|
|
gboolean replace_current_wm;
|
|
|
|
Atom wm_sn_atom;
|
|
|
|
char buf[128];
|
|
|
|
guint32 timestamp;
|
|
|
|
Atom atom_restart_helper;
|
|
|
|
Window restart_helper_window = None;
|
2022-05-30 17:20:37 -04:00
|
|
|
gboolean is_restart = FALSE;
|
2017-12-26 02:58:54 -05:00
|
|
|
GdkDisplay *gdk_display;
|
|
|
|
|
|
|
|
/* A list of all atom names, so that we can intern them in one go. */
|
|
|
|
const char *atom_names[] = {
|
|
|
|
#define item(x) #x,
|
|
|
|
#include "x11/atomnames.h"
|
|
|
|
#undef item
|
|
|
|
};
|
|
|
|
Atom atoms[G_N_ELEMENTS(atom_names)];
|
|
|
|
|
2022-05-28 17:39:30 -04:00
|
|
|
gdk_display = open_gdk_display (display, error);
|
|
|
|
if (!gdk_display)
|
2018-12-10 07:59:27 -05:00
|
|
|
return NULL;
|
|
|
|
|
2019-08-19 09:36:32 -04:00
|
|
|
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display);
|
2017-12-26 02:58:54 -05:00
|
|
|
|
2022-05-30 14:27:02 -04:00
|
|
|
XSynchronize (xdisplay, meta_context_is_x11_sync (context));
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
#ifdef HAVE_WAYLAND
|
|
|
|
if (meta_is_wayland_compositor ())
|
2021-03-23 11:47:45 -04:00
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor =
|
|
|
|
meta_context_get_wayland_compositor (context);
|
|
|
|
|
|
|
|
meta_xwayland_setup_xdisplay (&compositor->xwayland_manager, xdisplay);
|
|
|
|
}
|
2017-08-26 12:26:30 -04:00
|
|
|
#endif
|
|
|
|
|
2021-04-19 10:13:47 -04:00
|
|
|
replace_current_wm =
|
|
|
|
meta_context_is_replacing (meta_backend_get_context (backend));
|
2017-08-26 14:51:28 -04:00
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
/* According to _gdk_x11_display_open (), this will be returned
|
|
|
|
* by gdk_display_get_default_screen ()
|
|
|
|
*/
|
|
|
|
number = DefaultScreen (xdisplay);
|
2017-08-26 12:26:30 -04:00
|
|
|
|
|
|
|
xroot = RootWindow (xdisplay, number);
|
|
|
|
|
|
|
|
/* FVWM checks for None here, I don't know if this
|
|
|
|
* ever actually happens
|
|
|
|
*/
|
|
|
|
if (xroot == None)
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning (_("Screen %d on display “%s” is invalid"),
|
2017-08-26 12:26:30 -04:00
|
|
|
number, XDisplayName (NULL));
|
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to open default X11 screen");
|
|
|
|
|
|
|
|
XFlush (xdisplay);
|
|
|
|
XCloseDisplay (xdisplay);
|
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
gdk_display_close (gdk_display);
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
xscreen = ScreenOfDisplay (xdisplay, number);
|
2017-08-26 12:24:46 -04:00
|
|
|
|
2017-08-26 16:52:02 -04:00
|
|
|
atom_restart_helper = XInternAtom (xdisplay, "_MUTTER_RESTART_HELPER", False);
|
|
|
|
restart_helper_window = XGetSelectionOwner (xdisplay, atom_restart_helper);
|
|
|
|
if (restart_helper_window)
|
2022-05-30 17:20:37 -04:00
|
|
|
{
|
|
|
|
is_restart = TRUE;
|
|
|
|
meta_set_is_restart (TRUE);
|
|
|
|
}
|
2017-08-26 16:52:02 -04:00
|
|
|
|
2017-08-26 12:24:46 -04:00
|
|
|
x11_display = g_object_new (META_TYPE_X11_DISPLAY, NULL);
|
2017-08-26 16:52:02 -04:00
|
|
|
x11_display->gdk_display = gdk_display;
|
2017-08-26 12:24:46 -04:00
|
|
|
x11_display->display = display;
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
/* here we use XDisplayName which is what the user
|
|
|
|
* probably put in, vs. DisplayString(display) which is
|
|
|
|
* canonicalized by XOpenDisplay()
|
|
|
|
*/
|
|
|
|
x11_display->xdisplay = xdisplay;
|
|
|
|
x11_display->xroot = xroot;
|
|
|
|
|
|
|
|
x11_display->name = g_strdup (XDisplayName (NULL));
|
|
|
|
x11_display->screen_name = get_screen_name (xdisplay, number);
|
|
|
|
x11_display->default_xvisual = DefaultVisualOfScreen (xscreen);
|
|
|
|
x11_display->default_depth = DefaultDepthOfScreen (xscreen);
|
|
|
|
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Creating %d atoms", (int) G_N_ELEMENTS (atom_names));
|
2017-08-26 12:26:30 -04:00
|
|
|
XInternAtoms (xdisplay, (char **)atom_names, G_N_ELEMENTS (atom_names),
|
|
|
|
False, atoms);
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
#define item(x) x11_display->atom_##x = atoms[i++];
|
|
|
|
#include "x11/atomnames.h"
|
|
|
|
#undef item
|
|
|
|
|
2017-08-26 12:28:53 -04:00
|
|
|
query_xsync_extension (x11_display);
|
|
|
|
query_xshape_extension (x11_display);
|
|
|
|
query_xcomposite_extension (x11_display);
|
|
|
|
query_xdamage_extension (x11_display);
|
|
|
|
query_xfixes_extension (x11_display);
|
|
|
|
query_xi_extension (x11_display);
|
|
|
|
|
2017-08-26 12:37:29 -04:00
|
|
|
g_signal_connect_object (display,
|
|
|
|
"cursor-updated",
|
|
|
|
G_CALLBACK (update_cursor_theme),
|
|
|
|
x11_display,
|
|
|
|
G_CONNECT_SWAPPED);
|
2022-01-28 18:49:50 -05:00
|
|
|
g_signal_connect_object (display,
|
|
|
|
"window-visibility-updated",
|
|
|
|
G_CALLBACK (on_window_visibility_updated),
|
|
|
|
x11_display, 0);
|
2017-08-26 12:37:29 -04:00
|
|
|
|
|
|
|
update_cursor_theme (x11_display);
|
|
|
|
|
2017-08-26 12:56:44 -04:00
|
|
|
x11_display->xids = g_hash_table_new (meta_unsigned_long_hash,
|
|
|
|
meta_unsigned_long_equal);
|
2022-09-09 06:45:52 -04:00
|
|
|
x11_display->alarms = g_hash_table_new (meta_unsigned_long_hash,
|
|
|
|
meta_unsigned_long_equal);
|
2017-08-26 12:56:44 -04:00
|
|
|
|
2017-08-26 12:58:29 -04:00
|
|
|
x11_display->groups_by_leader = NULL;
|
2017-08-26 14:51:28 -04:00
|
|
|
x11_display->composite_overlay_window = None;
|
2017-08-26 13:03:51 -04:00
|
|
|
x11_display->guard_window = None;
|
2017-08-26 14:51:28 -04:00
|
|
|
x11_display->leader_window = None;
|
|
|
|
x11_display->timestamp_pinging_window = None;
|
|
|
|
x11_display->wm_sn_selection_window = None;
|
|
|
|
|
2018-10-31 10:21:40 -04:00
|
|
|
x11_display->display_close_idle = 0;
|
|
|
|
x11_display->xselectionclear_timestamp = 0;
|
|
|
|
|
2017-08-26 16:35:18 -04:00
|
|
|
x11_display->last_bell_time = 0;
|
2017-08-26 14:51:28 -04:00
|
|
|
x11_display->focus_serial = 0;
|
|
|
|
x11_display->server_focus_window = None;
|
|
|
|
x11_display->server_focus_serial = 0;
|
2017-08-26 12:58:29 -04:00
|
|
|
|
|
|
|
x11_display->prop_hooks = NULL;
|
|
|
|
meta_x11_display_init_window_prop_hooks (x11_display);
|
|
|
|
x11_display->group_prop_hooks = NULL;
|
|
|
|
meta_x11_display_init_group_prop_hooks (x11_display);
|
|
|
|
|
2017-08-27 14:44:38 -04:00
|
|
|
g_signal_connect_object (monitor_manager,
|
|
|
|
"monitors-changed-internal",
|
|
|
|
G_CALLBACK (on_monitors_changed_internal),
|
2017-08-26 13:03:51 -04:00
|
|
|
x11_display,
|
|
|
|
0);
|
|
|
|
|
2017-08-26 14:51:28 -04:00
|
|
|
init_leader_window (x11_display, ×tamp);
|
|
|
|
x11_display->timestamp = timestamp;
|
|
|
|
|
|
|
|
/* Make a little window used only for pinging the server for timestamps; note
|
|
|
|
* that meta_create_offscreen_window already selects for PropertyChangeMask.
|
|
|
|
*/
|
|
|
|
x11_display->timestamp_pinging_window =
|
|
|
|
meta_x11_display_create_offscreen_window (x11_display,
|
|
|
|
xroot,
|
|
|
|
PropertyChangeMask);
|
|
|
|
|
|
|
|
/* Select for cursor changes so the cursor tracker is up to date. */
|
|
|
|
XFixesSelectCursorInput (xdisplay, xroot, XFixesDisplayCursorNotifyMask);
|
|
|
|
|
|
|
|
/* If we're a Wayland compositor, then we don't grab the COW, since it
|
|
|
|
* will map it. */
|
|
|
|
if (!meta_is_wayland_compositor ())
|
|
|
|
x11_display->composite_overlay_window = XCompositeGetOverlayWindow (xdisplay, xroot);
|
|
|
|
|
|
|
|
/* Now that we've gotten taken a reference count on the COW, we
|
|
|
|
* can close the helper that is holding on to it */
|
2022-05-30 17:20:37 -04:00
|
|
|
if (is_restart)
|
2017-08-26 16:52:02 -04:00
|
|
|
XSetSelectionOwner (xdisplay, atom_restart_helper, None, META_CURRENT_TIME);
|
2017-08-26 14:51:28 -04:00
|
|
|
|
|
|
|
/* Handle creating a no_focus_window for this screen */
|
|
|
|
x11_display->no_focus_window =
|
|
|
|
meta_x11_display_create_offscreen_window (x11_display,
|
|
|
|
xroot,
|
|
|
|
FocusChangeMask|KeyPressMask|KeyReleaseMask);
|
|
|
|
XMapWindow (xdisplay, x11_display->no_focus_window);
|
|
|
|
/* Done with no_focus_window stuff */
|
|
|
|
|
2017-08-26 14:54:39 -04:00
|
|
|
meta_x11_display_init_events (x11_display);
|
|
|
|
|
|
|
|
set_wm_icon_size_hint (x11_display);
|
|
|
|
set_supported_hint (x11_display);
|
|
|
|
set_wm_check_hint (x11_display);
|
|
|
|
set_desktop_viewport_hint (x11_display);
|
|
|
|
set_desktop_geometry_hint (x11_display);
|
|
|
|
|
2019-05-07 06:59:50 -04:00
|
|
|
x11_display->x11_stack = meta_x11_stack_new (x11_display);
|
2017-08-26 15:38:59 -04:00
|
|
|
|
|
|
|
x11_display->keys_grabbed = FALSE;
|
|
|
|
meta_x11_display_grab_keys (x11_display);
|
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
meta_x11_display_update_workspace_layout (x11_display);
|
|
|
|
|
|
|
|
if (meta_prefs_get_dynamic_workspaces ())
|
|
|
|
{
|
|
|
|
int num = 0;
|
|
|
|
int n_items = 0;
|
|
|
|
uint32_t *list = NULL;
|
|
|
|
|
|
|
|
if (meta_prop_get_cardinal_list (x11_display,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_NUMBER_OF_DESKTOPS,
|
|
|
|
&list, &n_items))
|
|
|
|
{
|
|
|
|
num = list[0];
|
2019-09-09 12:36:48 -04:00
|
|
|
g_free (list);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
if (num > meta_workspace_manager_get_n_workspaces (display->workspace_manager))
|
|
|
|
meta_workspace_manager_update_num_workspaces (display->workspace_manager, timestamp, num);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
g_signal_connect_object (display->workspace_manager, "active-workspace-changed",
|
2017-08-26 16:29:10 -04:00
|
|
|
G_CALLBACK (set_active_workspace_hint),
|
|
|
|
x11_display, 0);
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
set_number_of_spaces_hint (display->workspace_manager, NULL, x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
g_signal_connect_object (display->workspace_manager, "notify::n-workspaces",
|
2017-08-26 16:29:10 -04:00
|
|
|
G_CALLBACK (set_number_of_spaces_hint),
|
|
|
|
x11_display, 0);
|
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
set_showing_desktop_hint (display->workspace_manager, x11_display);
|
2017-08-26 16:29:10 -04:00
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
g_signal_connect_object (display->workspace_manager, "showing-desktop-changed",
|
2017-08-26 16:29:10 -04:00
|
|
|
G_CALLBACK (set_showing_desktop_hint),
|
|
|
|
x11_display, 0);
|
|
|
|
|
|
|
|
set_workspace_names (x11_display);
|
|
|
|
|
|
|
|
meta_prefs_add_listener (prefs_changed_callback, x11_display);
|
|
|
|
|
2017-08-26 16:41:16 -04:00
|
|
|
set_work_area_hint (display, x11_display);
|
|
|
|
|
|
|
|
g_signal_connect_object (display, "workareas-changed",
|
|
|
|
G_CALLBACK (set_work_area_hint),
|
|
|
|
x11_display, 0);
|
|
|
|
|
2017-08-26 16:35:18 -04:00
|
|
|
init_x11_bell (x11_display);
|
|
|
|
|
2018-08-22 14:57:04 -04:00
|
|
|
meta_x11_startup_notification_init (x11_display);
|
2018-11-19 12:17:25 -05:00
|
|
|
meta_x11_selection_init (x11_display);
|
2018-08-22 14:57:04 -04:00
|
|
|
|
2019-07-03 10:23:45 -04:00
|
|
|
if (!meta_is_wayland_compositor ())
|
|
|
|
meta_dnd_init_xdnd (x11_display);
|
|
|
|
|
2022-03-09 08:41:13 -05:00
|
|
|
sprintf (buf, "WM_S%d", number);
|
|
|
|
|
|
|
|
wm_sn_atom = XInternAtom (xdisplay, buf, False);
|
|
|
|
new_wm_sn_owner = take_manager_selection (x11_display,
|
|
|
|
xroot,
|
|
|
|
wm_sn_atom,
|
|
|
|
timestamp,
|
|
|
|
replace_current_wm);
|
|
|
|
if (new_wm_sn_owner == None)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to acquire window manager ownership");
|
|
|
|
|
|
|
|
g_object_run_dispose (G_OBJECT (x11_display));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
x11_display->wm_sn_selection_window = new_wm_sn_owner;
|
|
|
|
x11_display->wm_sn_atom = wm_sn_atom;
|
|
|
|
x11_display->wm_sn_timestamp = timestamp;
|
|
|
|
|
2022-05-27 04:51:24 -04:00
|
|
|
init_event_masks (x11_display);
|
|
|
|
|
x11: Integrate frames client into Mutter
Replace the in-process implementation of frames with the external
frames client.
When a client window is created and managed by Mutter, Mutter will
determine whether it is a window that requires decorations and
hint the creation of a frame for it by setting the _MUTTER_NEEDS_FRAME
property on the client window.
After the frames client created a window that has the _MUTTER_FRAME_FOR
property, Mutter will proceed to reparent the client window on the
frame window, and show them as a single unit.
Rendering and event handling on the frame window will be performed by
the external client, Mutter is still responsible for everything else,
namely resizing client and frame window in synchronization, and
managing updates on the MetaWindowActor.
In order to let the frame be managed by the external client, Mutter
needs to change the way some properties are forwarded to the client
and/or frame windows. Some properties are necessary to keep propagating
to the client window only, some others need to happen on the frame
window now, and some others needs to be propagated on both so they
are synchronized about the behavior.
Also, some events that were previously totally unexpected in frame
windows are now susceptible to happen, so must be allowed now.
MetaFrame in src/core/frame.c now acts as the wrapper of foreign
windows created by the frames client, from the Mutter side. Location,
size, and lifetime are still largely in control of Mutter, some
details like visible/invisible borders are obtained from the client
instead (through the _MUTTER_FRAME_EXTENTS and _GTK_FRAME_EXTENTS
properties, respectively).
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2175>
2022-09-08 04:35:47 -04:00
|
|
|
meta_x11_display_init_frames_client (x11_display);
|
|
|
|
|
2022-04-06 05:32:51 -04:00
|
|
|
return g_steal_pointer (&x11_display);
|
2017-08-26 12:24:46 -04:00
|
|
|
}
|
2017-08-26 12:26:30 -04:00
|
|
|
|
2019-03-01 06:03:46 -05:00
|
|
|
void
|
|
|
|
meta_x11_display_restore_active_workspace (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
MetaDisplay *display;
|
|
|
|
MetaWorkspace *current_workspace;
|
|
|
|
uint32_t current_workspace_index = 0;
|
|
|
|
guint32 timestamp;
|
|
|
|
|
|
|
|
g_return_if_fail (META_IS_X11_DISPLAY (x11_display));
|
|
|
|
|
|
|
|
display = x11_display->display;
|
|
|
|
timestamp = x11_display->timestamp;
|
|
|
|
|
|
|
|
/* Get current workspace */
|
|
|
|
if (meta_prop_get_cardinal (x11_display,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_CURRENT_DESKTOP,
|
|
|
|
¤t_workspace_index))
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Read existing _NET_CURRENT_DESKTOP = %d",
|
2019-03-01 06:03:46 -05:00
|
|
|
(int) current_workspace_index);
|
|
|
|
|
|
|
|
/* Switch to the _NET_CURRENT_DESKTOP workspace */
|
|
|
|
current_workspace = meta_workspace_manager_get_workspace_by_index (display->workspace_manager,
|
|
|
|
current_workspace_index);
|
|
|
|
|
|
|
|
if (current_workspace != NULL)
|
|
|
|
meta_workspace_activate (current_workspace, timestamp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("No _NET_CURRENT_DESKTOP present");
|
2019-03-01 06:03:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
set_active_workspace_hint (display->workspace_manager, x11_display);
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
int
|
|
|
|
meta_x11_display_get_screen_number (MetaX11Display *x11_display)
|
|
|
|
{
|
2017-08-26 16:52:02 -04:00
|
|
|
return DefaultScreen (x11_display->xdisplay);
|
2017-08-26 12:26:30 -04:00
|
|
|
}
|
|
|
|
|
2019-10-14 05:32:54 -04:00
|
|
|
MetaDisplay *
|
|
|
|
meta_x11_display_get_display (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return x11_display->display;
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
/**
|
|
|
|
* meta_x11_display_get_xdisplay: (skip)
|
|
|
|
* @x11_display: a #MetaX11Display
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
Display *
|
|
|
|
meta_x11_display_get_xdisplay (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return x11_display->xdisplay;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_x11_display_get_xroot: (skip)
|
|
|
|
* @x11_display: A #MetaX11Display
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
Window
|
|
|
|
meta_x11_display_get_xroot (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return x11_display->xroot;
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:28:53 -04:00
|
|
|
/**
|
|
|
|
* meta_x11_display_get_xinput_opcode: (skip)
|
|
|
|
* @x11_display: a #MetaX11Display
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
meta_x11_display_get_xinput_opcode (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return x11_display->xinput_opcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_x11_display_get_damage_event_base (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return x11_display->damage_event_base;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_x11_display_get_shape_event_base (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return x11_display->shape_event_base;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_x11_display_has_shape (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return META_X11_DISPLAY_HAS_SHAPE (x11_display);
|
|
|
|
}
|
|
|
|
|
2017-08-26 12:26:30 -04:00
|
|
|
Window
|
|
|
|
meta_x11_display_create_offscreen_window (MetaX11Display *x11_display,
|
|
|
|
Window parent,
|
|
|
|
long valuemask)
|
|
|
|
{
|
|
|
|
XSetWindowAttributes attrs;
|
|
|
|
|
|
|
|
/* we want to be override redirect because sometimes we
|
|
|
|
* create a window on a screen we aren't managing.
|
|
|
|
* (but on a display we are managing at least one screen for)
|
|
|
|
*/
|
|
|
|
attrs.override_redirect = True;
|
|
|
|
attrs.event_mask = valuemask;
|
|
|
|
|
|
|
|
return XCreateWindow (x11_display->xdisplay,
|
|
|
|
parent,
|
|
|
|
-100, -100, 1, 1,
|
|
|
|
0,
|
|
|
|
CopyFromParent,
|
|
|
|
CopyFromParent,
|
|
|
|
(Visual *)CopyFromParent,
|
|
|
|
CWOverrideRedirect | CWEventMask,
|
|
|
|
&attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
Cursor
|
|
|
|
meta_x11_display_create_x_cursor (MetaX11Display *x11_display,
|
|
|
|
MetaCursor cursor)
|
|
|
|
{
|
|
|
|
return meta_create_x_cursor (x11_display->xdisplay, cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
get_screen_name (Display *xdisplay,
|
|
|
|
int number)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
char *dname;
|
|
|
|
char *scr;
|
|
|
|
|
|
|
|
/* DisplayString gives us a sort of canonical display,
|
|
|
|
* vs. the user-entered name from XDisplayName()
|
|
|
|
*/
|
|
|
|
dname = g_strdup (DisplayString (xdisplay));
|
|
|
|
|
|
|
|
/* Change display name to specify this screen.
|
|
|
|
*/
|
|
|
|
p = strrchr (dname, ':');
|
|
|
|
if (p)
|
|
|
|
{
|
|
|
|
p = strchr (p, '.');
|
|
|
|
if (p)
|
|
|
|
*p = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
scr = g_strdup_printf ("%s.%d", dname, number);
|
|
|
|
|
|
|
|
g_free (dname);
|
|
|
|
|
|
|
|
return scr;
|
|
|
|
}
|
2017-08-26 12:37:29 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_reload_cursor (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
Cursor xcursor;
|
|
|
|
MetaCursor cursor = x11_display->display->current_cursor;
|
|
|
|
|
|
|
|
/* Set a cursor for X11 applications that don't specify their own */
|
|
|
|
xcursor = meta_x11_display_create_x_cursor (x11_display, cursor);
|
|
|
|
|
|
|
|
XDefineCursor (x11_display->xdisplay, x11_display->xroot, xcursor);
|
|
|
|
XFlush (x11_display->xdisplay);
|
2018-08-01 18:58:56 -04:00
|
|
|
|
|
|
|
if (xcursor)
|
|
|
|
XFreeCursor (x11_display->xdisplay, xcursor);
|
2017-08-26 12:37:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-09-07 05:34:35 -04:00
|
|
|
set_cursor_theme (Display *xdisplay,
|
|
|
|
MetaBackend *backend)
|
2017-08-26 12:37:29 -04:00
|
|
|
{
|
2018-07-06 13:22:26 -04:00
|
|
|
MetaSettings *settings = meta_backend_get_settings (backend);
|
|
|
|
int scale;
|
|
|
|
|
|
|
|
scale = meta_settings_get_ui_scaling_factor (settings);
|
2017-08-26 12:37:29 -04:00
|
|
|
XcursorSetTheme (xdisplay, meta_prefs_get_cursor_theme ());
|
2022-09-07 05:34:35 -04:00
|
|
|
XcursorSetDefaultSize (xdisplay,
|
|
|
|
meta_prefs_get_cursor_size () * scale);
|
2017-08-26 12:37:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_cursor_theme (MetaX11Display *x11_display)
|
|
|
|
{
|
2022-09-07 05:34:35 -04:00
|
|
|
MetaBackend *backend = backend_from_x11_display (x11_display);
|
2017-08-26 12:37:29 -04:00
|
|
|
|
2022-09-07 05:34:35 -04:00
|
|
|
set_cursor_theme (x11_display->xdisplay, backend);
|
2017-08-26 12:37:29 -04:00
|
|
|
meta_x11_display_reload_cursor (x11_display);
|
|
|
|
|
|
|
|
if (META_IS_BACKEND_X11 (backend))
|
|
|
|
{
|
|
|
|
MetaBackendX11 *backend_x11 = META_BACKEND_X11 (backend);
|
|
|
|
Display *xdisplay = meta_backend_x11_get_xdisplay (backend_x11);
|
|
|
|
|
2022-09-07 05:34:35 -04:00
|
|
|
set_cursor_theme (xdisplay, backend);
|
2018-06-27 15:30:55 -04:00
|
|
|
meta_backend_x11_reload_cursor (backend_x11);
|
2017-08-26 12:37:29 -04:00
|
|
|
}
|
|
|
|
}
|
2017-08-26 12:56:44 -04:00
|
|
|
|
|
|
|
MetaWindow *
|
|
|
|
meta_x11_display_lookup_x_window (MetaX11Display *x11_display,
|
|
|
|
Window xwindow)
|
|
|
|
{
|
|
|
|
return g_hash_table_lookup (x11_display->xids, &xwindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_register_x_window (MetaX11Display *x11_display,
|
|
|
|
Window *xwindowp,
|
|
|
|
MetaWindow *window)
|
|
|
|
{
|
|
|
|
g_return_if_fail (g_hash_table_lookup (x11_display->xids, xwindowp) == NULL);
|
|
|
|
|
|
|
|
g_hash_table_insert (x11_display->xids, xwindowp, window);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_unregister_x_window (MetaX11Display *x11_display,
|
|
|
|
Window xwindow)
|
|
|
|
{
|
|
|
|
g_return_if_fail (g_hash_table_lookup (x11_display->xids, &xwindow) != NULL);
|
|
|
|
|
|
|
|
g_hash_table_remove (x11_display->xids, &xwindow);
|
|
|
|
}
|
|
|
|
|
2022-09-09 06:45:52 -04:00
|
|
|
MetaSyncCounter *
|
2017-08-26 12:56:44 -04:00
|
|
|
meta_x11_display_lookup_sync_alarm (MetaX11Display *x11_display,
|
|
|
|
XSyncAlarm alarm)
|
|
|
|
{
|
2022-09-09 06:45:52 -04:00
|
|
|
return g_hash_table_lookup (x11_display->alarms, &alarm);
|
2017-08-26 12:56:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-09-09 06:45:52 -04:00
|
|
|
meta_x11_display_register_sync_alarm (MetaX11Display *x11_display,
|
|
|
|
XSyncAlarm *alarmp,
|
|
|
|
MetaSyncCounter *sync_counter)
|
2017-08-26 12:56:44 -04:00
|
|
|
{
|
2022-09-09 06:45:52 -04:00
|
|
|
g_return_if_fail (g_hash_table_lookup (x11_display->alarms, alarmp) == NULL);
|
2017-08-26 12:56:44 -04:00
|
|
|
|
2022-09-09 06:45:52 -04:00
|
|
|
g_hash_table_insert (x11_display->alarms, alarmp, sync_counter);
|
2017-08-26 12:56:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_unregister_sync_alarm (MetaX11Display *x11_display,
|
|
|
|
XSyncAlarm alarm)
|
|
|
|
{
|
2022-09-09 06:45:52 -04:00
|
|
|
g_return_if_fail (g_hash_table_lookup (x11_display->alarms, &alarm) != NULL);
|
2017-08-26 12:56:44 -04:00
|
|
|
|
2022-09-09 06:45:52 -04:00
|
|
|
g_hash_table_remove (x11_display->alarms, &alarm);
|
2017-08-26 12:56:44 -04:00
|
|
|
}
|
|
|
|
|
2022-11-20 14:15:34 -05:00
|
|
|
MetaX11AlarmFilter *
|
|
|
|
meta_x11_display_add_alarm_filter (MetaX11Display *x11_display,
|
|
|
|
MetaAlarmFilter filter,
|
|
|
|
gpointer user_data)
|
2017-08-26 12:56:44 -04:00
|
|
|
{
|
2022-11-20 14:15:34 -05:00
|
|
|
MetaX11AlarmFilter *alarm_filter;
|
|
|
|
|
|
|
|
if (!x11_display->alarm_filters)
|
|
|
|
x11_display->alarm_filters = g_ptr_array_new_with_free_func (g_free);
|
|
|
|
|
|
|
|
alarm_filter = g_new0 (MetaX11AlarmFilter, 1);
|
|
|
|
alarm_filter->filter = filter;
|
|
|
|
alarm_filter->user_data = user_data;
|
|
|
|
g_ptr_array_add (x11_display->alarm_filters, alarm_filter);
|
2017-08-26 12:56:44 -04:00
|
|
|
|
2022-11-20 14:15:34 -05:00
|
|
|
return alarm_filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_remove_alarm_filter (MetaX11Display *x11_display,
|
|
|
|
MetaX11AlarmFilter *alarm_filter)
|
|
|
|
{
|
|
|
|
g_ptr_array_remove (x11_display->alarm_filters, alarm_filter);
|
2017-08-26 12:56:44 -04:00
|
|
|
}
|
2017-08-26 13:03:51 -04:00
|
|
|
|
|
|
|
/* The guard window allows us to leave minimized windows mapped so
|
|
|
|
* that compositor code may provide live previews of them.
|
|
|
|
* Instead of being unmapped/withdrawn, they get pushed underneath
|
|
|
|
* the guard window. We also select events on the guard window, which
|
|
|
|
* should effectively be forwarded to events on the background actor,
|
|
|
|
* providing that the scene graph is set up correctly.
|
|
|
|
*/
|
|
|
|
static Window
|
|
|
|
create_guard_window (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
XSetWindowAttributes attributes;
|
|
|
|
Window guard_window;
|
|
|
|
gulong create_serial;
|
2017-08-27 14:44:38 -04:00
|
|
|
int display_width, display_height;
|
|
|
|
|
|
|
|
meta_display_get_size (x11_display->display,
|
|
|
|
&display_width,
|
|
|
|
&display_height);
|
2017-08-26 13:03:51 -04:00
|
|
|
|
|
|
|
attributes.event_mask = NoEventMask;
|
|
|
|
attributes.override_redirect = True;
|
|
|
|
|
|
|
|
/* We have to call record_add() after we have the new window ID,
|
|
|
|
* so save the serial for the CreateWindow request until then */
|
|
|
|
create_serial = XNextRequest (x11_display->xdisplay);
|
|
|
|
guard_window =
|
|
|
|
XCreateWindow (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
0, /* x */
|
|
|
|
0, /* y */
|
2017-08-27 14:44:38 -04:00
|
|
|
display_width,
|
|
|
|
display_height,
|
2017-08-26 13:03:51 -04:00
|
|
|
0, /* border width */
|
|
|
|
0, /* depth */
|
|
|
|
InputOnly, /* class */
|
|
|
|
CopyFromParent, /* visual */
|
|
|
|
CWEventMask | CWOverrideRedirect,
|
|
|
|
&attributes);
|
|
|
|
|
|
|
|
/* https://bugzilla.gnome.org/show_bug.cgi?id=710346 */
|
|
|
|
XStoreName (x11_display->xdisplay, guard_window, "mutter guard window");
|
|
|
|
|
|
|
|
{
|
|
|
|
if (!meta_is_wayland_compositor ())
|
|
|
|
{
|
2022-09-07 05:34:35 -04:00
|
|
|
MetaBackendX11 *backend =
|
|
|
|
META_BACKEND_X11 (backend_from_x11_display (x11_display));
|
2017-08-26 13:03:51 -04:00
|
|
|
Display *backend_xdisplay = meta_backend_x11_get_xdisplay (backend);
|
|
|
|
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
|
|
|
|
XIEventMask mask = { XIAllMasterDevices, sizeof (mask_bits), mask_bits };
|
|
|
|
|
|
|
|
XISetMask (mask.mask, XI_ButtonPress);
|
|
|
|
XISetMask (mask.mask, XI_ButtonRelease);
|
|
|
|
XISetMask (mask.mask, XI_Motion);
|
|
|
|
|
|
|
|
/* Sync on the connection we created the window on to
|
|
|
|
* make sure it's created before we select on it on the
|
|
|
|
* backend connection. */
|
|
|
|
XSync (x11_display->xdisplay, False);
|
|
|
|
|
|
|
|
XISelectEvents (backend_xdisplay, guard_window, &mask, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_stack_tracker_record_add (x11_display->display->stack_tracker,
|
|
|
|
guard_window,
|
|
|
|
create_serial);
|
|
|
|
|
|
|
|
meta_stack_tracker_lower (x11_display->display->stack_tracker,
|
|
|
|
guard_window);
|
|
|
|
|
|
|
|
XMapWindow (x11_display->xdisplay, guard_window);
|
|
|
|
return guard_window;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_create_guard_window (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
if (x11_display->guard_window == None)
|
|
|
|
x11_display->guard_window = create_guard_window (x11_display);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-08-27 14:44:38 -04:00
|
|
|
on_monitors_changed_internal (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaX11Display *x11_display)
|
2017-08-26 13:03:51 -04:00
|
|
|
{
|
2017-08-27 14:44:38 -04:00
|
|
|
int display_width, display_height;
|
|
|
|
|
|
|
|
meta_monitor_manager_get_screen_size (monitor_manager,
|
|
|
|
&display_width,
|
|
|
|
&display_height);
|
|
|
|
|
2017-08-26 14:54:39 -04:00
|
|
|
set_desktop_geometry_hint (x11_display);
|
|
|
|
|
2017-08-26 13:03:51 -04:00
|
|
|
/* Resize the guard window to fill the screen again. */
|
|
|
|
if (x11_display->guard_window != None)
|
|
|
|
{
|
|
|
|
XWindowChanges changes;
|
|
|
|
|
|
|
|
changes.x = 0;
|
|
|
|
changes.y = 0;
|
2017-08-27 14:44:38 -04:00
|
|
|
changes.width = display_width;
|
|
|
|
changes.height = display_height;
|
2017-08-26 13:03:51 -04:00
|
|
|
|
|
|
|
XConfigureWindow (x11_display->xdisplay,
|
|
|
|
x11_display->guard_window,
|
|
|
|
CWX | CWY | CWWidth | CWHeight,
|
|
|
|
&changes);
|
|
|
|
}
|
2017-08-26 15:28:04 -04:00
|
|
|
|
|
|
|
x11_display->has_xinerama_indices = FALSE;
|
2017-08-26 13:03:51 -04:00
|
|
|
}
|
2017-08-26 14:51:28 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_set_cm_selection (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
char selection[32];
|
|
|
|
Atom a;
|
|
|
|
guint32 timestamp;
|
|
|
|
|
|
|
|
timestamp = meta_x11_display_get_current_time_roundtrip (x11_display);
|
|
|
|
g_snprintf (selection, sizeof (selection), "_NET_WM_CM_S%d",
|
2017-08-26 16:52:02 -04:00
|
|
|
DefaultScreen (x11_display->xdisplay));
|
2017-08-26 14:51:28 -04:00
|
|
|
a = XInternAtom (x11_display->xdisplay, selection, False);
|
|
|
|
|
|
|
|
x11_display->wm_cm_selection_window = take_manager_selection (x11_display, x11_display->xroot, a, timestamp, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Bool
|
|
|
|
find_timestamp_predicate (Display *xdisplay,
|
|
|
|
XEvent *ev,
|
|
|
|
XPointer arg)
|
|
|
|
{
|
|
|
|
MetaX11Display *x11_display = (MetaX11Display *) arg;
|
|
|
|
|
|
|
|
return (ev->type == PropertyNotify &&
|
|
|
|
ev->xproperty.atom == x11_display->atom__MUTTER_TIMESTAMP_PING);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get a timestamp, even if it means a roundtrip */
|
|
|
|
guint32
|
|
|
|
meta_x11_display_get_current_time_roundtrip (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
guint32 timestamp;
|
|
|
|
|
|
|
|
timestamp = meta_display_get_current_time (x11_display->display);
|
2017-08-26 16:24:21 -04:00
|
|
|
if (timestamp == META_CURRENT_TIME)
|
2017-08-26 14:51:28 -04:00
|
|
|
{
|
|
|
|
XEvent property_event;
|
|
|
|
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->timestamp_pinging_window,
|
|
|
|
x11_display->atom__MUTTER_TIMESTAMP_PING,
|
|
|
|
XA_STRING, 8, PropModeAppend, NULL, 0);
|
|
|
|
XIfEvent (x11_display->xdisplay,
|
|
|
|
&property_event,
|
|
|
|
find_timestamp_predicate,
|
|
|
|
(XPointer) x11_display);
|
|
|
|
timestamp = property_event.xproperty.time;
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_display_sanity_check_timestamps (x11_display->display, timestamp);
|
|
|
|
|
|
|
|
return timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_x11_display_xwindow_is_a_no_focus_window:
|
|
|
|
* @x11_display: A #MetaX11Display
|
|
|
|
* @xwindow: An X11 window
|
|
|
|
*
|
|
|
|
* Returns: %TRUE iff window is one of mutter's internal "no focus" windows
|
|
|
|
* which will have the focus when there is no actual client window focused.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
meta_x11_display_xwindow_is_a_no_focus_window (MetaX11Display *x11_display,
|
|
|
|
Window xwindow)
|
|
|
|
{
|
|
|
|
return xwindow == x11_display->no_focus_window;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_increment_event_serial (MetaX11Display *x11_display)
|
|
|
|
|
|
|
|
{
|
|
|
|
/* We just make some random X request */
|
|
|
|
XDeleteProperty (x11_display->xdisplay,
|
|
|
|
x11_display->leader_window,
|
|
|
|
x11_display->atom__MOTIF_WM_HINTS);
|
|
|
|
}
|
|
|
|
|
2019-09-05 07:17:21 -04:00
|
|
|
static void
|
2017-08-26 14:51:28 -04:00
|
|
|
meta_x11_display_update_active_window_hint (MetaX11Display *x11_display)
|
|
|
|
{
|
2019-09-05 06:59:08 -04:00
|
|
|
MetaWindow *focus_window;
|
2017-08-26 14:51:28 -04:00
|
|
|
gulong data[1];
|
|
|
|
|
|
|
|
if (x11_display->display->closing)
|
|
|
|
return; /* Leave old value for a replacement */
|
|
|
|
|
2019-09-05 06:59:08 -04:00
|
|
|
focus_window = meta_x11_display_lookup_x_window (x11_display,
|
|
|
|
x11_display->focus_xwindow);
|
|
|
|
|
2017-08-26 14:51:28 -04:00
|
|
|
if (focus_window)
|
|
|
|
data[0] = focus_window->xwindow;
|
|
|
|
else
|
|
|
|
data[0] = None;
|
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 14:51:28 -04:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_ACTIVE_WINDOW,
|
|
|
|
XA_WINDOW,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 14:51:28 -04:00
|
|
|
}
|
|
|
|
|
2018-12-30 12:25:08 -05:00
|
|
|
void
|
|
|
|
meta_x11_display_update_focus_window (MetaX11Display *x11_display,
|
|
|
|
Window xwindow,
|
|
|
|
gulong serial,
|
|
|
|
gboolean focused_by_us)
|
|
|
|
{
|
|
|
|
x11_display->focus_serial = serial;
|
|
|
|
x11_display->focused_by_us = !!focused_by_us;
|
|
|
|
|
|
|
|
if (x11_display->focus_xwindow == xwindow)
|
|
|
|
return;
|
|
|
|
|
|
|
|
x11_display->focus_xwindow = xwindow;
|
|
|
|
meta_x11_display_update_active_window_hint (x11_display);
|
|
|
|
}
|
|
|
|
|
2019-09-05 07:17:21 -04:00
|
|
|
static void
|
|
|
|
meta_x11_display_set_input_focus_internal (MetaX11Display *x11_display,
|
|
|
|
Window xwindow,
|
|
|
|
uint32_t timestamp)
|
2017-08-26 14:51:28 -04:00
|
|
|
{
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 14:51:28 -04:00
|
|
|
|
|
|
|
/* In order for mutter to know that the focus request succeeded, we track
|
|
|
|
* the serial of the "focus request" we made, but if we take the serial
|
|
|
|
* of the XSetInputFocus request, then there's no way to determine the
|
|
|
|
* difference between focus events as a result of the SetInputFocus and
|
|
|
|
* focus events that other clients send around the same time. Ensure that
|
|
|
|
* we know which is which by making two requests that the server will
|
|
|
|
* process at the same time.
|
|
|
|
*/
|
|
|
|
XGrabServer (x11_display->xdisplay);
|
|
|
|
|
|
|
|
XSetInputFocus (x11_display->xdisplay,
|
|
|
|
xwindow,
|
|
|
|
RevertToPointerRoot,
|
|
|
|
timestamp);
|
|
|
|
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->timestamp_pinging_window,
|
|
|
|
x11_display->atom__MUTTER_FOCUS_SET,
|
|
|
|
XA_STRING, 8, PropModeAppend, NULL, 0);
|
|
|
|
|
|
|
|
XUngrabServer (x11_display->xdisplay);
|
|
|
|
XFlush (x11_display->xdisplay);
|
|
|
|
|
2017-08-27 14:48:55 -04:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2017-08-26 14:51:28 -04:00
|
|
|
}
|
|
|
|
|
2019-09-05 07:17:21 -04:00
|
|
|
void
|
|
|
|
meta_x11_display_set_input_focus (MetaX11Display *x11_display,
|
|
|
|
MetaWindow *window,
|
|
|
|
gboolean focus_frame,
|
|
|
|
uint32_t timestamp)
|
|
|
|
{
|
|
|
|
Window xwindow;
|
|
|
|
gulong serial;
|
|
|
|
|
|
|
|
if (window)
|
|
|
|
xwindow = focus_frame ? window->frame->xwindow : window->xwindow;
|
|
|
|
else
|
|
|
|
xwindow = x11_display->no_focus_window;
|
|
|
|
|
|
|
|
meta_x11_error_trap_push (x11_display);
|
|
|
|
meta_x11_display_set_input_focus_internal (x11_display, xwindow, timestamp);
|
|
|
|
serial = XNextRequest (x11_display->xdisplay);
|
|
|
|
meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE);
|
|
|
|
meta_x11_error_trap_pop (x11_display);
|
|
|
|
}
|
|
|
|
|
2017-08-26 14:51:28 -04:00
|
|
|
void
|
|
|
|
meta_x11_display_set_input_focus_xwindow (MetaX11Display *x11_display,
|
|
|
|
Window window,
|
|
|
|
guint32 timestamp)
|
|
|
|
{
|
2018-12-30 15:23:07 -05:00
|
|
|
gulong serial;
|
2017-08-26 14:51:28 -04:00
|
|
|
|
2019-10-31 02:36:52 -04:00
|
|
|
if (meta_display_timestamp_too_old (x11_display->display, ×tamp))
|
|
|
|
return;
|
|
|
|
|
2019-09-05 07:17:21 -04:00
|
|
|
meta_x11_display_set_input_focus_internal (x11_display, window, timestamp);
|
2019-11-04 06:36:36 -05:00
|
|
|
serial = XNextRequest (x11_display->xdisplay);
|
2018-12-30 15:23:07 -05:00
|
|
|
meta_x11_display_update_focus_window (x11_display, window, serial, TRUE);
|
2019-10-31 02:36:52 -04:00
|
|
|
meta_display_update_focus_window (x11_display->display, NULL);
|
|
|
|
meta_display_remove_autoraise_callback (x11_display->display);
|
|
|
|
x11_display->display->last_focus_time = timestamp;
|
2017-08-26 14:51:28 -04:00
|
|
|
}
|
2017-08-26 15:28:04 -04:00
|
|
|
|
|
|
|
static MetaX11DisplayLogicalMonitorData *
|
|
|
|
get_x11_display_logical_monitor_data (MetaLogicalMonitor *logical_monitor)
|
|
|
|
{
|
|
|
|
return g_object_get_qdata (G_OBJECT (logical_monitor),
|
|
|
|
quark_x11_display_logical_monitor_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MetaX11DisplayLogicalMonitorData *
|
|
|
|
ensure_x11_display_logical_monitor_data (MetaLogicalMonitor *logical_monitor)
|
|
|
|
{
|
|
|
|
MetaX11DisplayLogicalMonitorData *data;
|
|
|
|
|
|
|
|
data = get_x11_display_logical_monitor_data (logical_monitor);
|
|
|
|
if (data)
|
|
|
|
return data;
|
|
|
|
|
|
|
|
data = g_new0 (MetaX11DisplayLogicalMonitorData, 1);
|
|
|
|
g_object_set_qdata_full (G_OBJECT (logical_monitor),
|
|
|
|
quark_x11_display_logical_monitor_data,
|
|
|
|
data,
|
|
|
|
g_free);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_x11_display_ensure_xinerama_indices (MetaX11Display *x11_display)
|
|
|
|
{
|
2022-09-07 05:34:35 -04:00
|
|
|
MetaBackend *backend = backend_from_x11_display (x11_display);
|
2017-08-26 15:28:04 -04:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend);
|
|
|
|
GList *logical_monitors, *l;
|
|
|
|
XineramaScreenInfo *infos;
|
|
|
|
int n_infos, j;
|
|
|
|
|
|
|
|
if (x11_display->has_xinerama_indices)
|
|
|
|
return;
|
|
|
|
|
|
|
|
x11_display->has_xinerama_indices = TRUE;
|
|
|
|
|
|
|
|
if (!XineramaIsActive (x11_display->xdisplay))
|
|
|
|
return;
|
|
|
|
|
|
|
|
infos = XineramaQueryScreens (x11_display->xdisplay,
|
|
|
|
&n_infos);
|
|
|
|
if (n_infos <= 0 || infos == NULL)
|
|
|
|
{
|
|
|
|
meta_XFree (infos);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
logical_monitors =
|
|
|
|
meta_monitor_manager_get_logical_monitors (monitor_manager);
|
|
|
|
|
|
|
|
for (l = logical_monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
|
|
|
|
for (j = 0; j < n_infos; ++j)
|
|
|
|
{
|
|
|
|
if (logical_monitor->rect.x == infos[j].x_org &&
|
|
|
|
logical_monitor->rect.y == infos[j].y_org &&
|
|
|
|
logical_monitor->rect.width == infos[j].width &&
|
|
|
|
logical_monitor->rect.height == infos[j].height)
|
|
|
|
{
|
|
|
|
MetaX11DisplayLogicalMonitorData *logical_monitor_data;
|
|
|
|
|
|
|
|
logical_monitor_data =
|
|
|
|
ensure_x11_display_logical_monitor_data (logical_monitor);
|
|
|
|
logical_monitor_data->xinerama_index = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_XFree (infos);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_x11_display_logical_monitor_to_xinerama_index (MetaX11Display *x11_display,
|
|
|
|
MetaLogicalMonitor *logical_monitor)
|
|
|
|
{
|
|
|
|
MetaX11DisplayLogicalMonitorData *logical_monitor_data;
|
|
|
|
|
|
|
|
g_return_val_if_fail (logical_monitor, -1);
|
|
|
|
|
|
|
|
meta_x11_display_ensure_xinerama_indices (x11_display);
|
|
|
|
|
|
|
|
logical_monitor_data = get_x11_display_logical_monitor_data (logical_monitor);
|
|
|
|
|
|
|
|
return logical_monitor_data->xinerama_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_x11_display_xinerama_index_to_logical_monitor (MetaX11Display *x11_display,
|
|
|
|
int xinerama_index)
|
|
|
|
{
|
2022-09-07 05:34:35 -04:00
|
|
|
MetaBackend *backend = backend_from_x11_display (x11_display);
|
2017-08-26 15:28:04 -04:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
meta_backend_get_monitor_manager (backend);
|
|
|
|
GList *logical_monitors, *l;
|
|
|
|
|
|
|
|
meta_x11_display_ensure_xinerama_indices (x11_display);
|
|
|
|
|
|
|
|
logical_monitors =
|
|
|
|
meta_monitor_manager_get_logical_monitors (monitor_manager);
|
|
|
|
|
|
|
|
for (l = logical_monitors; l; l = l->next)
|
|
|
|
{
|
|
|
|
MetaLogicalMonitor *logical_monitor = l->data;
|
|
|
|
MetaX11DisplayLogicalMonitorData *logical_monitor_data;
|
|
|
|
|
|
|
|
logical_monitor_data =
|
|
|
|
ensure_x11_display_logical_monitor_data (logical_monitor);
|
|
|
|
|
|
|
|
if (logical_monitor_data->xinerama_index == xinerama_index)
|
|
|
|
return logical_monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-08-26 15:39:46 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_update_workspace_names (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
char **names;
|
|
|
|
int n_names;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* this updates names in prefs when the root window property changes,
|
|
|
|
* iff the new property contents don't match what's already in prefs
|
|
|
|
*/
|
|
|
|
|
|
|
|
names = NULL;
|
|
|
|
n_names = 0;
|
|
|
|
if (!meta_prop_get_utf8_list (x11_display,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_DESKTOP_NAMES,
|
|
|
|
&names, &n_names))
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_verbose ("Failed to get workspace names from root window");
|
2017-08-26 15:39:46 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (i < n_names)
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_PREFS,
|
2020-10-02 11:47:22 -04:00
|
|
|
"Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change",
|
2017-08-26 15:39:46 -04:00
|
|
|
i, names[i] ? names[i] : "null");
|
|
|
|
meta_prefs_change_workspace_name (i, names[i]);
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev (names);
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
#define _NET_WM_ORIENTATION_HORZ 0
|
|
|
|
#define _NET_WM_ORIENTATION_VERT 1
|
|
|
|
|
|
|
|
#define _NET_WM_TOPLEFT 0
|
|
|
|
#define _NET_WM_TOPRIGHT 1
|
|
|
|
#define _NET_WM_BOTTOMRIGHT 2
|
|
|
|
#define _NET_WM_BOTTOMLEFT 3
|
2017-08-26 15:39:46 -04:00
|
|
|
|
|
|
|
void
|
2017-08-26 16:29:10 -04:00
|
|
|
meta_x11_display_update_workspace_layout (MetaX11Display *x11_display)
|
2017-08-26 15:39:46 -04:00
|
|
|
{
|
2017-08-27 15:02:40 -04:00
|
|
|
MetaWorkspaceManager *workspace_manager = x11_display->display->workspace_manager;
|
2017-08-26 16:29:10 -04:00
|
|
|
gboolean vertical_layout = FALSE;
|
2021-01-27 09:28:49 -05:00
|
|
|
int n_rows = 1;
|
|
|
|
int n_columns = -1;
|
2017-08-26 16:29:10 -04:00
|
|
|
MetaDisplayCorner starting_corner = META_DISPLAY_TOPLEFT;
|
|
|
|
uint32_t *list;
|
|
|
|
int n_items;
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
if (workspace_manager->workspace_layout_overridden)
|
2017-08-26 15:39:46 -04:00
|
|
|
return;
|
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
list = NULL;
|
|
|
|
n_items = 0;
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
if (meta_prop_get_cardinal_list (x11_display,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__NET_DESKTOP_LAYOUT,
|
|
|
|
&list, &n_items))
|
|
|
|
{
|
|
|
|
if (n_items == 3 || n_items == 4)
|
|
|
|
{
|
|
|
|
int cols, rows;
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
switch (list[0])
|
|
|
|
{
|
|
|
|
case _NET_WM_ORIENTATION_HORZ:
|
|
|
|
vertical_layout = FALSE;
|
|
|
|
break;
|
|
|
|
case _NET_WM_ORIENTATION_VERT:
|
|
|
|
vertical_layout = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT");
|
2017-08-26 16:29:10 -04:00
|
|
|
break;
|
|
|
|
}
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
cols = list[1];
|
|
|
|
rows = list[2];
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
if (rows <= 0 && cols <= 0)
|
|
|
|
{
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense", rows, cols);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rows > 0)
|
|
|
|
n_rows = rows;
|
|
|
|
else
|
|
|
|
n_rows = -1;
|
|
|
|
|
|
|
|
if (cols > 0)
|
|
|
|
n_columns = cols;
|
|
|
|
else
|
|
|
|
n_columns = -1;
|
|
|
|
}
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-26 16:29:10 -04:00
|
|
|
if (n_items == 4)
|
|
|
|
{
|
|
|
|
switch (list[3])
|
|
|
|
{
|
|
|
|
case _NET_WM_TOPLEFT:
|
|
|
|
starting_corner = META_DISPLAY_TOPLEFT;
|
|
|
|
break;
|
|
|
|
case _NET_WM_TOPRIGHT:
|
|
|
|
starting_corner = META_DISPLAY_TOPRIGHT;
|
|
|
|
break;
|
|
|
|
case _NET_WM_BOTTOMRIGHT:
|
|
|
|
starting_corner = META_DISPLAY_BOTTOMRIGHT;
|
|
|
|
break;
|
|
|
|
case _NET_WM_BOTTOMLEFT:
|
|
|
|
starting_corner = META_DISPLAY_BOTTOMLEFT;
|
|
|
|
break;
|
|
|
|
default:
|
2020-10-02 11:47:22 -04:00
|
|
|
meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT");
|
2017-08-26 16:29:10 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
|
2020-10-02 11:47:22 -04:00
|
|
|
"(3 is accepted for backwards compat)", n_items);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2019-09-09 12:36:48 -04:00
|
|
|
g_free (list);
|
2017-08-26 15:39:46 -04:00
|
|
|
|
2017-08-27 15:02:40 -04:00
|
|
|
meta_workspace_manager_update_workspace_layout (workspace_manager,
|
|
|
|
starting_corner,
|
|
|
|
vertical_layout,
|
|
|
|
n_rows,
|
|
|
|
n_columns);
|
2017-08-26 16:29:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
prefs_changed_callback (MetaPreference pref,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
MetaX11Display *x11_display = data;
|
|
|
|
|
|
|
|
if (pref == META_PREF_WORKSPACE_NAMES)
|
|
|
|
{
|
|
|
|
set_workspace_names (x11_display);
|
|
|
|
}
|
2017-08-26 15:39:46 -04:00
|
|
|
}
|
2018-12-30 06:58:31 -05:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_increment_focus_sentinel (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
unsigned long data[1];
|
|
|
|
|
|
|
|
data[0] = meta_display_get_current_time (x11_display->display);
|
|
|
|
|
|
|
|
XChangeProperty (x11_display->xdisplay,
|
|
|
|
x11_display->xroot,
|
|
|
|
x11_display->atom__MUTTER_SENTINEL,
|
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 1);
|
|
|
|
|
|
|
|
x11_display->sentinel_counter += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_decrement_focus_sentinel (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
x11_display->sentinel_counter -= 1;
|
|
|
|
|
|
|
|
if (x11_display->sentinel_counter < 0)
|
|
|
|
x11_display->sentinel_counter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_x11_display_focus_sentinel_clear (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
return (x11_display->sentinel_counter == 0);
|
|
|
|
}
|
2019-08-16 10:23:08 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_set_stage_input_region (MetaX11Display *x11_display,
|
|
|
|
XserverRegion region)
|
|
|
|
{
|
|
|
|
Display *xdisplay = x11_display->xdisplay;
|
2022-09-07 05:34:35 -04:00
|
|
|
MetaBackend *backend = backend_from_x11_display (x11_display);
|
2019-08-16 10:23:08 -04:00
|
|
|
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
|
|
|
|
Window stage_xwindow;
|
|
|
|
|
|
|
|
g_return_if_fail (!meta_is_wayland_compositor ());
|
|
|
|
|
2019-03-22 08:53:00 -04:00
|
|
|
stage_xwindow = meta_x11_get_stage_window (stage);
|
2019-08-16 10:23:08 -04:00
|
|
|
XFixesSetWindowShapeRegion (xdisplay, stage_xwindow,
|
|
|
|
ShapeInput, 0, 0, region);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's generally a good heuristic that when a crossing event is generated
|
|
|
|
* because we reshape the overlay, we don't want it to affect
|
|
|
|
* focus-follows-mouse focus - it's not the user doing something, it's the
|
|
|
|
* environment changing under the user.
|
|
|
|
*/
|
|
|
|
meta_display_add_ignored_crossing_serial (x11_display->display,
|
|
|
|
XNextRequest (xdisplay));
|
|
|
|
XFixesSetWindowShapeRegion (xdisplay,
|
|
|
|
x11_display->composite_overlay_window,
|
|
|
|
ShapeInput, 0, 0, region);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_x11_display_clear_stage_input_region (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
if (x11_display->empty_region == None)
|
|
|
|
{
|
|
|
|
x11_display->empty_region = XFixesCreateRegion (x11_display->xdisplay,
|
|
|
|
NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_x11_display_set_stage_input_region (x11_display,
|
|
|
|
x11_display->empty_region);
|
|
|
|
}
|