2014-06-11 20:08:33 +00: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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
#include "x11/events.h"
|
|
|
|
|
|
|
|
#include <X11/Xatom.h>
|
2017-08-26 20:35:18 +00:00
|
|
|
#include <X11/XKBlib.h>
|
2014-06-11 20:08:33 +00:00
|
|
|
#include <X11/extensions/Xdamage.h>
|
|
|
|
#include <X11/extensions/shape.h>
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
#include "backends/meta-cursor-tracker-private.h"
|
2016-12-01 04:59:47 +00:00
|
|
|
#include "backends/x11/meta-backend-x11.h"
|
2020-07-31 19:08:15 +00:00
|
|
|
#include "backends/x11/meta-cursor-tracker-x11.h"
|
2019-08-14 21:25:54 +00:00
|
|
|
#include "compositor/meta-compositor-x11.h"
|
2020-02-17 17:32:35 +00:00
|
|
|
#include "cogl/cogl.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "core/bell.h"
|
|
|
|
#include "core/display-private.h"
|
|
|
|
#include "core/meta-workspace-manager-private.h"
|
|
|
|
#include "core/window-private.h"
|
|
|
|
#include "core/workspace-private.h"
|
|
|
|
#include "meta/meta-backend.h"
|
2021-03-03 16:21:59 +00:00
|
|
|
#include "meta/meta-context.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "meta/meta-x11-errors.h"
|
2018-08-22 18:57:04 +00:00
|
|
|
#include "x11/meta-startup-notification-x11.h"
|
2018-11-18 09:49:36 +00:00
|
|
|
#include "x11/meta-x11-display-private.h"
|
2018-11-19 17:17:25 +00:00
|
|
|
#include "x11/meta-x11-selection-private.h"
|
2018-11-18 09:49:36 +00:00
|
|
|
#include "x11/meta-x11-selection-input-stream-private.h"
|
|
|
|
#include "x11/meta-x11-selection-output-stream-private.h"
|
2014-06-11 20:08:33 +00:00
|
|
|
#include "x11/window-x11.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 08:35:47 +00:00
|
|
|
#include "x11/window-x11-private.h"
|
2014-06-11 20:08:33 +00:00
|
|
|
#include "x11/xprops.h"
|
2014-09-04 02:51:02 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_WAYLAND
|
2014-06-11 20:08:33 +00:00
|
|
|
#include "wayland/meta-wayland-private.h"
|
2014-10-10 16:55:00 +00:00
|
|
|
#include "wayland/meta-xwayland-private.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "wayland/meta-xwayland.h"
|
2014-09-04 02:51:02 +00:00
|
|
|
#endif
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
static XIEvent *
|
2017-08-26 18:54:39 +00:00
|
|
|
get_input_event (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
if (event->type == GenericEvent &&
|
2017-08-26 18:54:39 +00:00
|
|
|
event->xcookie.extension == x11_display->xinput_opcode)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XIEvent *input_event;
|
|
|
|
|
|
|
|
/* NB: GDK event filters already have generic events
|
|
|
|
* allocated, so no need to do XGetEventData() on our own
|
|
|
|
*/
|
|
|
|
input_event = (XIEvent *) event->xcookie.data;
|
|
|
|
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_Motion:
|
|
|
|
case XI_ButtonPress:
|
|
|
|
case XI_ButtonRelease:
|
|
|
|
if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
|
|
|
|
return input_event;
|
|
|
|
break;
|
|
|
|
case XI_KeyPress:
|
|
|
|
case XI_KeyRelease:
|
|
|
|
if (((XIDeviceEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID)
|
|
|
|
return input_event;
|
|
|
|
break;
|
|
|
|
case XI_FocusIn:
|
|
|
|
case XI_FocusOut:
|
|
|
|
if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_KEYBOARD_ID)
|
|
|
|
return input_event;
|
|
|
|
break;
|
|
|
|
case XI_Enter:
|
|
|
|
case XI_Leave:
|
|
|
|
if (((XIEnterEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
|
|
|
|
return input_event;
|
|
|
|
break;
|
|
|
|
case XI_BarrierHit:
|
|
|
|
case XI_BarrierLeave:
|
|
|
|
if (((XIBarrierEvent *) input_event)->deviceid == META_VIRTUAL_CORE_POINTER_ID)
|
|
|
|
return input_event;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Window
|
2017-08-26 18:54:39 +00:00
|
|
|
xievent_get_modified_window (MetaX11Display *x11_display,
|
|
|
|
XIEvent *input_event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_Motion:
|
|
|
|
case XI_ButtonPress:
|
|
|
|
case XI_ButtonRelease:
|
|
|
|
case XI_KeyPress:
|
|
|
|
case XI_KeyRelease:
|
|
|
|
return ((XIDeviceEvent *) input_event)->event;
|
|
|
|
case XI_FocusIn:
|
|
|
|
case XI_FocusOut:
|
|
|
|
case XI_Enter:
|
|
|
|
case XI_Leave:
|
|
|
|
return ((XIEnterEvent *) input_event)->event;
|
|
|
|
case XI_BarrierHit:
|
|
|
|
case XI_BarrierLeave:
|
|
|
|
return ((XIBarrierEvent *) input_event)->event;
|
|
|
|
}
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the window this has to do with, if any, rather
|
|
|
|
* than the frame or root window that was selecting
|
|
|
|
* for substructure
|
|
|
|
*/
|
|
|
|
static Window
|
2017-08-26 18:54:39 +00:00
|
|
|
event_get_modified_window (MetaX11Display *x11_display,
|
2014-06-11 20:08:33 +00:00
|
|
|
XEvent *event)
|
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
XIEvent *input_event = get_input_event (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (input_event)
|
2017-08-26 18:54:39 +00:00
|
|
|
return xievent_get_modified_window (x11_display, input_event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case KeymapNotify:
|
|
|
|
case Expose:
|
|
|
|
case GraphicsExpose:
|
|
|
|
case NoExpose:
|
|
|
|
case VisibilityNotify:
|
|
|
|
case ResizeRequest:
|
|
|
|
case PropertyNotify:
|
|
|
|
case SelectionClear:
|
|
|
|
case SelectionRequest:
|
|
|
|
case SelectionNotify:
|
|
|
|
case ColormapNotify:
|
|
|
|
case ClientMessage:
|
|
|
|
return event->xany.window;
|
|
|
|
|
|
|
|
case CreateNotify:
|
|
|
|
return event->xcreatewindow.window;
|
|
|
|
|
|
|
|
case DestroyNotify:
|
|
|
|
return event->xdestroywindow.window;
|
|
|
|
|
|
|
|
case UnmapNotify:
|
|
|
|
return event->xunmap.window;
|
|
|
|
|
|
|
|
case MapNotify:
|
|
|
|
return event->xmap.window;
|
|
|
|
|
|
|
|
case MapRequest:
|
|
|
|
return event->xmaprequest.window;
|
|
|
|
|
|
|
|
case ReparentNotify:
|
|
|
|
return event->xreparent.window;
|
|
|
|
|
|
|
|
case ConfigureNotify:
|
|
|
|
return event->xconfigure.window;
|
|
|
|
|
|
|
|
case ConfigureRequest:
|
|
|
|
return event->xconfigurerequest.window;
|
|
|
|
|
|
|
|
case GravityNotify:
|
|
|
|
return event->xgravity.window;
|
|
|
|
|
|
|
|
case CirculateNotify:
|
|
|
|
return event->xcirculate.window;
|
|
|
|
|
|
|
|
case CirculateRequest:
|
|
|
|
return event->xcirculaterequest.window;
|
|
|
|
|
|
|
|
case MappingNotify:
|
|
|
|
return None;
|
|
|
|
|
|
|
|
default:
|
2017-08-26 18:54:39 +00:00
|
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XShapeEvent *sev = (XShapeEvent*) event;
|
|
|
|
return sev->window;
|
|
|
|
}
|
|
|
|
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static guint32
|
2017-08-26 18:54:39 +00:00
|
|
|
event_get_time (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
XIEvent *input_event = get_input_event (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (input_event)
|
|
|
|
return input_event->time;
|
|
|
|
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case PropertyNotify:
|
|
|
|
return event->xproperty.time;
|
|
|
|
|
|
|
|
case SelectionClear:
|
|
|
|
case SelectionRequest:
|
|
|
|
case SelectionNotify:
|
|
|
|
return event->xselection.time;
|
|
|
|
|
|
|
|
case KeymapNotify:
|
|
|
|
case Expose:
|
|
|
|
case GraphicsExpose:
|
|
|
|
case NoExpose:
|
|
|
|
case MapNotify:
|
|
|
|
case UnmapNotify:
|
|
|
|
case VisibilityNotify:
|
|
|
|
case ResizeRequest:
|
|
|
|
case ColormapNotify:
|
|
|
|
case ClientMessage:
|
|
|
|
case CreateNotify:
|
|
|
|
case DestroyNotify:
|
|
|
|
case MapRequest:
|
|
|
|
case ReparentNotify:
|
|
|
|
case ConfigureNotify:
|
|
|
|
case ConfigureRequest:
|
|
|
|
case GravityNotify:
|
|
|
|
case CirculateNotify:
|
|
|
|
case CirculateRequest:
|
|
|
|
case MappingNotify:
|
|
|
|
default:
|
2017-08-26 20:24:21 +00:00
|
|
|
return META_CURRENT_TIME;
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:43:11 +00:00
|
|
|
const char*
|
2014-06-11 20:08:33 +00:00
|
|
|
meta_event_detail_to_string (int d)
|
|
|
|
{
|
|
|
|
const char *detail = "???";
|
|
|
|
switch (d)
|
|
|
|
{
|
|
|
|
/* We are an ancestor in the A<->B focus change relationship */
|
|
|
|
case XINotifyAncestor:
|
|
|
|
detail = "NotifyAncestor";
|
|
|
|
break;
|
|
|
|
case XINotifyDetailNone:
|
|
|
|
detail = "NotifyDetailNone";
|
|
|
|
break;
|
|
|
|
/* We are a descendant in the A<->B focus change relationship */
|
|
|
|
case XINotifyInferior:
|
|
|
|
detail = "NotifyInferior";
|
|
|
|
break;
|
|
|
|
case XINotifyNonlinear:
|
|
|
|
detail = "NotifyNonlinear";
|
|
|
|
break;
|
|
|
|
case XINotifyNonlinearVirtual:
|
|
|
|
detail = "NotifyNonlinearVirtual";
|
|
|
|
break;
|
|
|
|
case XINotifyPointer:
|
|
|
|
detail = "NotifyPointer";
|
|
|
|
break;
|
|
|
|
case XINotifyPointerRoot:
|
|
|
|
detail = "NotifyPointerRoot";
|
|
|
|
break;
|
|
|
|
case XINotifyVirtual:
|
|
|
|
detail = "NotifyVirtual";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return detail;
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:43:11 +00:00
|
|
|
const char*
|
2014-06-11 20:08:33 +00:00
|
|
|
meta_event_mode_to_string (int m)
|
|
|
|
{
|
|
|
|
const char *mode = "???";
|
|
|
|
switch (m)
|
|
|
|
{
|
|
|
|
case XINotifyNormal:
|
|
|
|
mode = "NotifyNormal";
|
|
|
|
break;
|
|
|
|
case XINotifyGrab:
|
|
|
|
mode = "NotifyGrab";
|
|
|
|
break;
|
|
|
|
case XINotifyUngrab:
|
|
|
|
mode = "NotifyUngrab";
|
|
|
|
break;
|
|
|
|
case XINotifyWhileGrabbed:
|
|
|
|
mode = "NotifyWhileGrabbed";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_GNUC_UNUSED static const char*
|
|
|
|
stack_mode_to_string (int mode)
|
|
|
|
{
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case Above:
|
|
|
|
return "Above";
|
|
|
|
case Below:
|
|
|
|
return "Below";
|
|
|
|
case TopIf:
|
|
|
|
return "TopIf";
|
|
|
|
case BottomIf:
|
|
|
|
return "BottomIf";
|
|
|
|
case Opposite:
|
|
|
|
return "Opposite";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown";
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:43:11 +00:00
|
|
|
static gint64
|
2014-06-11 20:08:33 +00:00
|
|
|
sync_value_to_64 (const XSyncValue *value)
|
|
|
|
{
|
|
|
|
gint64 v;
|
|
|
|
|
|
|
|
v = XSyncValueLow32 (*value);
|
|
|
|
v |= (((gint64)XSyncValueHigh32 (*value)) << 32);
|
|
|
|
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:43:11 +00:00
|
|
|
static const char*
|
2014-06-11 20:08:33 +00:00
|
|
|
alarm_state_to_string (XSyncAlarmState state)
|
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case XSyncAlarmActive:
|
|
|
|
return "Active";
|
|
|
|
case XSyncAlarmInactive:
|
|
|
|
return "Inactive";
|
|
|
|
case XSyncAlarmDestroyed:
|
|
|
|
return "Destroyed";
|
|
|
|
default:
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 22:39:41 +00:00
|
|
|
static const char *
|
|
|
|
get_xi2_event_name (XIEvent *input_event)
|
|
|
|
{
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_FocusIn:
|
|
|
|
return "XI_FocusIn";
|
|
|
|
case XI_FocusOut:
|
|
|
|
return "XI_FocusOut";
|
|
|
|
case XI_Enter:
|
|
|
|
return "XI_Enter";
|
|
|
|
case XI_Leave:
|
|
|
|
return "XI_Leave";
|
|
|
|
case XI_BarrierHit:
|
|
|
|
return "XI_BarrierHit";
|
|
|
|
case XI_BarrierLeave:
|
|
|
|
return "XI_BarrierLeave";
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:43:11 +00:00
|
|
|
static void
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_xi2_event (MetaX11Display *x11_display,
|
|
|
|
XIEvent *input_event,
|
|
|
|
const char **name_p,
|
|
|
|
char **extra_p)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
const char *name = NULL;
|
|
|
|
char *extra = NULL;
|
|
|
|
|
|
|
|
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
|
|
|
|
2021-02-02 22:39:41 +00:00
|
|
|
name = get_xi2_event_name (input_event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_FocusIn:
|
|
|
|
case XI_FocusOut:
|
|
|
|
extra = g_strdup_printf ("detail: %s mode: %s\n",
|
|
|
|
meta_event_detail_to_string (enter_event->detail),
|
|
|
|
meta_event_mode_to_string (enter_event->mode));
|
|
|
|
break;
|
|
|
|
case XI_Enter:
|
|
|
|
case XI_Leave:
|
|
|
|
extra = g_strdup_printf ("win: 0x%lx root: 0x%lx mode: %s detail: %s focus: %d x: %g y: %g",
|
|
|
|
enter_event->event,
|
|
|
|
enter_event->root,
|
|
|
|
meta_event_mode_to_string (enter_event->mode),
|
|
|
|
meta_event_detail_to_string (enter_event->detail),
|
|
|
|
enter_event->focus,
|
|
|
|
enter_event->root_x,
|
|
|
|
enter_event->root_y);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*name_p = name;
|
|
|
|
*extra_p = extra;
|
|
|
|
}
|
|
|
|
|
2021-02-02 22:39:41 +00:00
|
|
|
static const char *
|
|
|
|
get_core_event_name (XEvent *event)
|
|
|
|
{
|
|
|
|
/* GenericEvent is omitted here, as it's handled separately. */
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case KeyPress:
|
|
|
|
return "KeyPress";
|
|
|
|
case KeyRelease:
|
|
|
|
return "KeyRelease";
|
|
|
|
case ButtonPress:
|
|
|
|
return "ButtonPress";
|
|
|
|
case ButtonRelease:
|
|
|
|
return "ButtonRelease";
|
|
|
|
case MotionNotify:
|
|
|
|
return "MotionNotify";
|
|
|
|
case EnterNotify:
|
|
|
|
return "EnterNotify";
|
|
|
|
case LeaveNotify:
|
|
|
|
return "LeaveNotify";
|
|
|
|
case FocusIn:
|
|
|
|
return "FocusIn";
|
|
|
|
case FocusOut:
|
|
|
|
return "FocusOut";
|
|
|
|
case KeymapNotify:
|
|
|
|
return "KeymapNotify";
|
|
|
|
case Expose:
|
|
|
|
return "Expose";
|
|
|
|
case GraphicsExpose:
|
|
|
|
return "GraphicsExpose";
|
|
|
|
case NoExpose:
|
|
|
|
return "NoExpose";
|
|
|
|
case VisibilityNotify:
|
|
|
|
return "VisibilityNotify";
|
|
|
|
case CreateNotify:
|
|
|
|
return "CreateNotify";
|
|
|
|
case DestroyNotify:
|
|
|
|
return "DestroyNotify";
|
|
|
|
case UnmapNotify:
|
|
|
|
return "UnmapNotify";
|
|
|
|
case MapNotify:
|
|
|
|
return "MapNotify";
|
|
|
|
case MapRequest:
|
|
|
|
return "MapRequest";
|
|
|
|
case ReparentNotify:
|
|
|
|
return "ReparentNotify";
|
|
|
|
case ConfigureNotify:
|
|
|
|
return "ConfigureNotify";
|
|
|
|
case ConfigureRequest:
|
|
|
|
return "ConfigureRequest";
|
|
|
|
case GravityNotify:
|
|
|
|
return "GravityNotify";
|
|
|
|
case ResizeRequest:
|
|
|
|
return "ResizeRequest";
|
|
|
|
case CirculateNotify:
|
|
|
|
return "CirculateNotify";
|
|
|
|
case CirculateRequest:
|
|
|
|
return "CirculateRequest";
|
|
|
|
case PropertyNotify:
|
|
|
|
return "PropertyNotify";
|
|
|
|
case SelectionClear:
|
|
|
|
return "SelectionClear";
|
|
|
|
case SelectionRequest:
|
|
|
|
return "SelectionRequest";
|
|
|
|
case SelectionNotify:
|
|
|
|
return "SelectionNotify";
|
|
|
|
case ColormapNotify:
|
|
|
|
return "ColormapNotify";
|
|
|
|
case ClientMessage:
|
|
|
|
return "ClientMessage";
|
|
|
|
case MappingNotify:
|
|
|
|
return "MappingNotify";
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
get_extension_event_name (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
|
|
|
{
|
|
|
|
if (META_X11_DISPLAY_HAS_XSYNC (x11_display) &&
|
|
|
|
event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
|
|
|
return "XSyncAlarmNotify";
|
|
|
|
|
|
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
|
|
|
return "ShapeNotify";
|
|
|
|
|
|
|
|
if (META_X11_DISPLAY_HAS_DAMAGE (x11_display) &&
|
|
|
|
event->type == (x11_display->damage_event_base + XDamageNotify))
|
|
|
|
return "XDamageNotify";
|
|
|
|
|
|
|
|
if (event->type == (x11_display->xfixes_event_base + XFixesSelectionNotify))
|
|
|
|
return "XFixesSelectionNotify";
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-02-02 22:44:08 +00:00
|
|
|
static const char *
|
|
|
|
get_event_name (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
XIEvent *input_event;
|
|
|
|
|
|
|
|
if (event->type < GenericEvent)
|
|
|
|
return get_core_event_name (event);
|
|
|
|
|
|
|
|
name = get_extension_event_name (x11_display, event);
|
|
|
|
if (name)
|
|
|
|
return name;
|
|
|
|
|
|
|
|
input_event = get_input_event (x11_display, event);
|
|
|
|
if (input_event)
|
|
|
|
{
|
|
|
|
name = get_xi2_event_name (input_event);
|
|
|
|
if (name)
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "Unknown event";
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:43:11 +00:00
|
|
|
static void
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_core_event (MetaX11Display *x11_display,
|
|
|
|
XEvent *event,
|
|
|
|
const char **name_p,
|
|
|
|
char **extra_p)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
const char *name = NULL;
|
|
|
|
char *extra = NULL;
|
|
|
|
|
2021-02-02 22:39:41 +00:00
|
|
|
name = get_core_event_name (event);
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
name = get_extension_event_name (x11_display, event);
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case KeymapNotify:
|
|
|
|
case Expose:
|
|
|
|
case GraphicsExpose:
|
|
|
|
case NoExpose:
|
|
|
|
case VisibilityNotify:
|
2021-02-02 22:39:41 +00:00
|
|
|
case GravityNotify:
|
|
|
|
case CirculateNotify:
|
|
|
|
case CirculateRequest:
|
|
|
|
case SelectionClear:
|
|
|
|
case SelectionRequest:
|
|
|
|
case SelectionNotify:
|
|
|
|
case ColormapNotify:
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
case CreateNotify:
|
|
|
|
extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx",
|
|
|
|
event->xcreatewindow.parent,
|
|
|
|
event->xcreatewindow.window);
|
|
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
|
|
extra = g_strdup_printf ("event: 0x%lx window: 0x%lx",
|
|
|
|
event->xdestroywindow.event,
|
|
|
|
event->xdestroywindow.window);
|
|
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
|
|
extra = g_strdup_printf ("event: 0x%lx window: 0x%lx from_configure: %d",
|
|
|
|
event->xunmap.event,
|
|
|
|
event->xunmap.window,
|
|
|
|
event->xunmap.from_configure);
|
|
|
|
break;
|
|
|
|
case MapNotify:
|
|
|
|
extra = g_strdup_printf ("event: 0x%lx window: 0x%lx override_redirect: %d",
|
|
|
|
event->xmap.event,
|
|
|
|
event->xmap.window,
|
|
|
|
event->xmap.override_redirect);
|
|
|
|
break;
|
|
|
|
case MapRequest:
|
|
|
|
extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx\n",
|
|
|
|
event->xmaprequest.window,
|
|
|
|
event->xmaprequest.parent);
|
|
|
|
break;
|
|
|
|
case ReparentNotify:
|
|
|
|
extra = g_strdup_printf ("window: 0x%lx parent: 0x%lx event: 0x%lx\n",
|
|
|
|
event->xreparent.window,
|
|
|
|
event->xreparent.parent,
|
|
|
|
event->xreparent.event);
|
|
|
|
break;
|
|
|
|
case ConfigureNotify:
|
|
|
|
extra = g_strdup_printf ("x: %d y: %d w: %d h: %d above: 0x%lx override_redirect: %d",
|
|
|
|
event->xconfigure.x,
|
|
|
|
event->xconfigure.y,
|
|
|
|
event->xconfigure.width,
|
|
|
|
event->xconfigure.height,
|
|
|
|
event->xconfigure.above,
|
|
|
|
event->xconfigure.override_redirect);
|
|
|
|
break;
|
|
|
|
case ConfigureRequest:
|
|
|
|
extra = g_strdup_printf ("parent: 0x%lx window: 0x%lx x: %d %sy: %d %sw: %d %sh: %d %sborder: %d %sabove: %lx %sstackmode: %s %s",
|
|
|
|
event->xconfigurerequest.parent,
|
|
|
|
event->xconfigurerequest.window,
|
|
|
|
event->xconfigurerequest.x,
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWX ? "" : "(unset) ",
|
|
|
|
event->xconfigurerequest.y,
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWY ? "" : "(unset) ",
|
|
|
|
event->xconfigurerequest.width,
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWWidth ? "" : "(unset) ",
|
|
|
|
event->xconfigurerequest.height,
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWHeight ? "" : "(unset) ",
|
|
|
|
event->xconfigurerequest.border_width,
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWBorderWidth ? "" : "(unset)",
|
|
|
|
event->xconfigurerequest.above,
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWSibling ? "" : "(unset)",
|
|
|
|
stack_mode_to_string (event->xconfigurerequest.detail),
|
|
|
|
event->xconfigurerequest.value_mask &
|
|
|
|
CWStackMode ? "" : "(unset)");
|
|
|
|
break;
|
|
|
|
case ResizeRequest:
|
|
|
|
extra = g_strdup_printf ("width = %d height = %d",
|
|
|
|
event->xresizerequest.width,
|
|
|
|
event->xresizerequest.height);
|
|
|
|
break;
|
|
|
|
case PropertyNotify:
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
const char *state;
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 18:54:39 +00:00
|
|
|
str = XGetAtomName (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xproperty.atom);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (event->xproperty.state == PropertyNewValue)
|
|
|
|
state = "PropertyNewValue";
|
|
|
|
else if (event->xproperty.state == PropertyDelete)
|
|
|
|
state = "PropertyDelete";
|
|
|
|
else
|
|
|
|
state = "???";
|
|
|
|
|
|
|
|
extra = g_strdup_printf ("atom: %s state: %s",
|
|
|
|
str ? str : "(unknown atom)",
|
|
|
|
state);
|
|
|
|
meta_XFree (str);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ClientMessage:
|
|
|
|
{
|
|
|
|
char *str;
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 18:54:39 +00:00
|
|
|
str = XGetAtomName (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xclient.message_type);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
extra = g_strdup_printf ("type: %s format: %d\n",
|
|
|
|
str ? str : "(unknown atom)",
|
|
|
|
event->xclient.format);
|
|
|
|
meta_XFree (str);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MappingNotify:
|
|
|
|
break;
|
|
|
|
default:
|
2017-08-26 18:54:39 +00:00
|
|
|
if (META_X11_DISPLAY_HAS_XSYNC (x11_display) &&
|
|
|
|
event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XSyncAlarmNotifyEvent *aevent = (XSyncAlarmNotifyEvent*) event;
|
|
|
|
|
|
|
|
extra =
|
|
|
|
g_strdup_printf ("alarm: 0x%lx"
|
|
|
|
" counter_value: %" G_GINT64_FORMAT
|
|
|
|
" alarm_value: %" G_GINT64_FORMAT
|
|
|
|
" time: %u alarm state: %s",
|
|
|
|
aevent->alarm,
|
|
|
|
(gint64) sync_value_to_64 (&aevent->counter_value),
|
|
|
|
(gint64) sync_value_to_64 (&aevent->alarm_value),
|
|
|
|
(unsigned int)aevent->time,
|
|
|
|
alarm_state_to_string (aevent->state));
|
|
|
|
}
|
|
|
|
else
|
2021-02-02 22:42:53 +00:00
|
|
|
{
|
|
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
|
|
|
{
|
|
|
|
XShapeEvent *sev = (XShapeEvent*) event;
|
|
|
|
|
|
|
|
extra =
|
|
|
|
g_strdup_printf ("kind: %s "
|
|
|
|
"x: %d y: %d w: %u h: %u "
|
|
|
|
"shaped: %d",
|
|
|
|
sev->kind == ShapeBounding ?
|
|
|
|
"ShapeBounding" :
|
|
|
|
(sev->kind == ShapeClip ?
|
|
|
|
"ShapeClip" : "(unknown)"),
|
|
|
|
sev->x, sev->y, sev->width, sev->height,
|
|
|
|
sev->shaped);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
extra = g_strdup_printf ("type: %d", event->xany.type);
|
|
|
|
}
|
|
|
|
}
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*name_p = name;
|
|
|
|
*extra_p = extra;
|
|
|
|
}
|
|
|
|
|
2014-12-29 03:45:59 +00:00
|
|
|
static char *
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_event (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
const char *name = NULL;
|
|
|
|
char *extra = NULL;
|
|
|
|
char *winname;
|
2014-12-29 03:45:59 +00:00
|
|
|
char *ret;
|
2014-06-11 20:08:33 +00:00
|
|
|
XIEvent *input_event;
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
input_event = get_input_event (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (input_event)
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_xi2_event (x11_display, input_event, &name, &extra);
|
2014-06-11 20:08:33 +00:00
|
|
|
else
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_core_event (x11_display, event, &name, &extra);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (event->xany.window == x11_display->xroot)
|
2016-07-21 13:03:56 +00:00
|
|
|
winname = g_strdup_printf ("root");
|
2014-06-11 20:08:33 +00:00
|
|
|
else
|
|
|
|
winname = g_strdup_printf ("0x%lx", event->xany.window);
|
|
|
|
|
2014-12-29 03:45:59 +00:00
|
|
|
ret = g_strdup_printf ("%s on %s%s %s %sserial %lu", name, winname,
|
|
|
|
extra ? ":" : "", extra ? extra : "",
|
|
|
|
event->xany.send_event ? "SEND " : "",
|
|
|
|
event->xany.serial);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
g_free (winname);
|
2014-12-29 03:46:25 +00:00
|
|
|
g_free (extra);
|
2014-12-29 03:45:59 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_GNUC_UNUSED static void
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_event_print (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-12-29 03:45:59 +00:00
|
|
|
{
|
|
|
|
char *event_str;
|
|
|
|
|
|
|
|
/* filter overnumerous events */
|
|
|
|
if (event->type == Expose || event->type == MotionNotify ||
|
|
|
|
event->type == NoExpose)
|
|
|
|
return;
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (event->type == (x11_display->damage_event_base + XDamageNotify))
|
2014-12-29 03:45:59 +00:00
|
|
|
return;
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
2014-12-29 03:45:59 +00:00
|
|
|
return;
|
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->type == PropertyNotify &&
|
2017-08-26 18:54:39 +00:00
|
|
|
event->xproperty.atom == x11_display->atom__NET_WM_USER_TIME)
|
2014-12-29 03:45:59 +00:00
|
|
|
return;
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
event_str = meta_spew_event (x11_display, event);
|
2014-12-29 03:45:59 +00:00
|
|
|
g_print ("%s\n", event_str);
|
|
|
|
g_free (event_str);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.
Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.
But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.
meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.
Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.
This stops the:
Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170). This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW. Trying to work around...
warning spam when closing a CSD window.
2014-09-17 02:16:23 +00:00
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
handle_window_focus_event (MetaX11Display *x11_display,
|
|
|
|
MetaWindow *window,
|
|
|
|
XIEnterEvent *event,
|
|
|
|
unsigned long serial)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
MetaDisplay *display = x11_display->display;
|
2014-06-11 20:08:33 +00:00
|
|
|
MetaWindow *focus_window;
|
|
|
|
#ifdef WITH_VERBOSE_MODE
|
|
|
|
const char *window_type;
|
|
|
|
|
|
|
|
/* Note the event can be on either the window or the frame,
|
|
|
|
* we focus the frame for shaded windows
|
|
|
|
*/
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
if (event->event == window->xwindow)
|
|
|
|
window_type = "client window";
|
|
|
|
else if (window->frame && event->event == window->frame->xwindow)
|
|
|
|
window_type = "frame window";
|
|
|
|
else
|
|
|
|
window_type = "unknown client window";
|
|
|
|
}
|
2017-08-26 18:54:39 +00:00
|
|
|
else if (meta_x11_display_xwindow_is_a_no_focus_window (x11_display,
|
2017-08-26 18:51:28 +00:00
|
|
|
event->event))
|
2014-06-11 20:08:33 +00:00
|
|
|
window_type = "no_focus_window";
|
2017-08-26 18:54:39 +00:00
|
|
|
else if (event->event == x11_display->xroot)
|
2014-06-11 20:08:33 +00:00
|
|
|
window_type = "root window";
|
|
|
|
else
|
|
|
|
window_type = "unknown window";
|
|
|
|
|
|
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
|
|
"Focus %s event received on %s 0x%lx (%s) "
|
2020-10-02 15:47:22 +00:00
|
|
|
"mode %s detail %s serial %lu",
|
2014-06-11 20:08:33 +00:00
|
|
|
event->evtype == XI_FocusIn ? "in" :
|
|
|
|
event->evtype == XI_FocusOut ? "out" :
|
|
|
|
"???",
|
|
|
|
window ? window->desc : "",
|
|
|
|
event->event, window_type,
|
|
|
|
meta_event_mode_to_string (event->mode),
|
|
|
|
meta_event_detail_to_string (event->mode),
|
2015-07-09 15:39:05 +00:00
|
|
|
serial);
|
2014-06-11 20:08:33 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* FIXME our pointer tracking is broken; see how
|
|
|
|
* gtk+/gdk/x11/gdkevents-x11.c or XFree86/xc/programs/xterm/misc.c
|
|
|
|
* for how to handle it the correct way. In brief you need to track
|
|
|
|
* pointer focus and regular focus, and handle EnterNotify in
|
|
|
|
* PointerRoot mode with no window manager. However as noted above,
|
|
|
|
* accurate focus tracking will break things because we want to keep
|
|
|
|
* windows "focused" when using keybindings on them, and also we
|
|
|
|
* sometimes "focus" a window by focusing its frame or
|
|
|
|
* no_focus_window; so this all needs rethinking massively.
|
|
|
|
*
|
|
|
|
* My suggestion is to change it so that we clearly separate
|
|
|
|
* actual keyboard focus tracking using the xterm algorithm,
|
|
|
|
* and mutter's "pretend" focus window, and go through all
|
|
|
|
* the code and decide which one should be used in each place;
|
|
|
|
* a hard bit is deciding on a policy for that.
|
|
|
|
*
|
|
|
|
* http://bugzilla.gnome.org/show_bug.cgi?id=90382
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* We ignore grabs, though this is questionable. It may be better to
|
|
|
|
* increase the intelligence of the focus window tracking.
|
|
|
|
*
|
|
|
|
* The problem is that keybindings for windows are done with
|
|
|
|
* XGrabKey, which means focus_window disappears and the front of
|
|
|
|
* the MRU list gets confused from what the user expects once a
|
|
|
|
* keybinding is used.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (event->mode == XINotifyGrab ||
|
|
|
|
event->mode == XINotifyUngrab ||
|
|
|
|
/* From WindowMaker, ignore all funky pointer root events */
|
|
|
|
event->detail > XINotifyNonlinearVirtual)
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_FOCUS,
|
2020-10-02 15:47:22 +00:00
|
|
|
"Ignoring focus event generated by a grab or other weirdness");
|
events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.
Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.
But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.
meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.
Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.
This stops the:
Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170). This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW. Trying to work around...
warning spam when closing a CSD window.
2014-09-17 02:16:23 +00:00
|
|
|
return FALSE;
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (event->evtype == XI_FocusIn)
|
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
x11_display->server_focus_window = event->event;
|
|
|
|
x11_display->server_focus_serial = serial;
|
2014-06-11 20:08:33 +00:00
|
|
|
focus_window = window;
|
|
|
|
}
|
|
|
|
else if (event->evtype == XI_FocusOut)
|
|
|
|
{
|
|
|
|
if (event->detail == XINotifyInferior)
|
|
|
|
{
|
|
|
|
/* This event means the client moved focus to a subwindow */
|
|
|
|
meta_topic (META_DEBUG_FOCUS,
|
2020-10-02 15:47:22 +00:00
|
|
|
"Ignoring focus out with NotifyInferior");
|
events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.
Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.
But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.
meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.
Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.
This stops the:
Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170). This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW. Trying to work around...
warning spam when closing a CSD window.
2014-09-17 02:16:23 +00:00
|
|
|
return FALSE;
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
x11_display->server_focus_window = None;
|
|
|
|
x11_display->server_focus_serial = serial;
|
2014-06-11 20:08:33 +00:00
|
|
|
focus_window = NULL;
|
|
|
|
}
|
|
|
|
else
|
events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.
Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.
But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.
meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.
Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.
This stops the:
Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170). This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW. Trying to work around...
warning spam when closing a CSD window.
2014-09-17 02:16:23 +00:00
|
|
|
g_assert_not_reached ();
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
/* If display->focused_by_us, then the focus_serial will be used only
|
|
|
|
* for a focus change we made and have already accounted for.
|
|
|
|
* (See request_xserver_input_focus_change().) Otherwise, we can get
|
|
|
|
* multiple focus events with the same serial.
|
|
|
|
*/
|
2017-08-26 18:54:39 +00:00
|
|
|
if (x11_display->server_focus_serial > x11_display->focus_serial ||
|
2018-12-30 17:25:08 +00:00
|
|
|
(!x11_display->focused_by_us &&
|
2017-08-26 18:54:39 +00:00
|
|
|
x11_display->server_focus_serial == x11_display->focus_serial))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2018-12-30 17:25:08 +00:00
|
|
|
meta_x11_display_update_focus_window (x11_display,
|
|
|
|
focus_window ?
|
|
|
|
focus_window->xwindow : None,
|
|
|
|
x11_display->server_focus_serial,
|
|
|
|
FALSE);
|
2019-09-27 11:06:34 +00:00
|
|
|
meta_display_update_focus_window (display, focus_window);
|
events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.
Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.
But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.
meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.
Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.
This stops the:
Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170). This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW. Trying to work around...
warning spam when closing a CSD window.
2014-09-17 02:16:23 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FALSE;
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
crossing_serial_is_ignored (MetaX11Display *x11_display,
|
|
|
|
unsigned long serial)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (i < N_IGNORED_CROSSING_SERIALS)
|
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
if (x11_display->display->ignored_crossing_serials[i] == serial)
|
2014-06-11 20:08:33 +00:00
|
|
|
return TRUE;
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
handle_input_xevent (MetaX11Display *x11_display,
|
|
|
|
XIEvent *input_event,
|
|
|
|
unsigned long serial)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
|
|
|
Window modified;
|
|
|
|
MetaWindow *window;
|
2017-08-26 18:54:39 +00:00
|
|
|
MetaDisplay *display = x11_display->display;
|
2017-08-27 19:02:40 +00:00
|
|
|
MetaWorkspaceManager *workspace_manager = display->workspace_manager;
|
2022-05-28 10:09:49 +00:00
|
|
|
MetaBackend *backend = meta_get_backend ();
|
|
|
|
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (input_event == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_Enter:
|
|
|
|
case XI_Leave:
|
|
|
|
case XI_FocusIn:
|
|
|
|
case XI_FocusOut:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
modified = xievent_get_modified_window (x11_display, input_event);
|
2017-08-26 16:56:44 +00:00
|
|
|
window = modified != None ?
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_x11_display_lookup_x_window (x11_display, modified) :
|
2017-08-26 16:56:44 +00:00
|
|
|
NULL;
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
switch (input_event->evtype)
|
|
|
|
{
|
|
|
|
case XI_Enter:
|
2014-09-17 02:28:13 +00:00
|
|
|
if (display->event_route != META_EVENT_ROUTE_NORMAL)
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
|
2022-05-28 10:09:49 +00:00
|
|
|
if (clutter_stage_get_grab_actor (stage) != NULL)
|
|
|
|
break;
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
/* Check if we've entered a window; do this even if window->has_focus to
|
|
|
|
* avoid races.
|
|
|
|
*/
|
2017-08-26 18:54:39 +00:00
|
|
|
if (window && !crossing_serial_is_ignored (x11_display, serial) &&
|
2014-06-11 20:08:33 +00:00
|
|
|
enter_event->mode != XINotifyGrab &&
|
|
|
|
enter_event->mode != XINotifyUngrab &&
|
|
|
|
enter_event->detail != XINotifyInferior &&
|
2018-12-30 11:58:31 +00:00
|
|
|
meta_x11_display_focus_sentinel_clear (x11_display))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
meta_window_handle_enter (window,
|
|
|
|
enter_event->time,
|
|
|
|
enter_event->root_x,
|
|
|
|
enter_event->root_y);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XI_Leave:
|
2014-09-17 02:28:13 +00:00
|
|
|
if (display->event_route != META_EVENT_ROUTE_NORMAL)
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
|
2022-05-28 10:09:49 +00:00
|
|
|
if (clutter_stage_get_grab_actor (stage) != NULL)
|
|
|
|
break;
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
if (window != NULL &&
|
|
|
|
enter_event->mode != XINotifyGrab &&
|
|
|
|
enter_event->mode != XINotifyUngrab)
|
|
|
|
{
|
|
|
|
meta_window_handle_leave (window);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XI_FocusIn:
|
|
|
|
case XI_FocusOut:
|
2017-08-26 18:54:39 +00:00
|
|
|
if (handle_window_focus_event (x11_display, window, enter_event, serial) &&
|
events: Ignore normal FocusIn events on the root window
GTK+ focuses its own windows with RevertToParent, which means that when
a GTK+ CSD window is destroyed, the X server will set the focus back to
the root window. The event stream that we is an UnmapNotify followed by
a FocusOut event. Our own UnmapNotify-handling code unmanages the window
and forcibly changes the focus to the next default window in the stack.
Since UnmapNotify events don't come with timestamps, we query for one,
and set the window focus using that.
But there's *still* a FocusOut event in the stack, with an older
timestamp and serial than our own focusing. We see this, throw it out
since it's older than the most recent focus, but then our own code that
notices the root has been focused kicks in and tries to focus the
default window... using a timestamp older than our most recent focusing.
meta_display_sanity_check_timestamps notices this, and (rightly so)
puts a warning in our face, telling something is awry.
Only let our workarounds kick in when the event is new enough, otherwise
our code will get confused over old events.
This stops the:
Window manager warning: last_focus_time (367917173) is greater than comparison timestamp (367917170). This most likely represents a buggy client sending inaccurate timestamps in messages such as _NET_ACTIVE_WINDOW. Trying to work around...
warning spam when closing a CSD window.
2014-09-17 02:16:23 +00:00
|
|
|
enter_event->event == enter_event->root)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
if (enter_event->evtype == XI_FocusIn &&
|
2014-09-17 01:53:05 +00:00
|
|
|
enter_event->detail == XINotifyDetailNone)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
|
|
"Focus got set to None, probably due to "
|
|
|
|
"brain-damage in the X protocol (see bug "
|
2020-10-02 15:47:22 +00:00
|
|
|
"125492). Setting the default focus window.");
|
2017-08-27 19:02:40 +00:00
|
|
|
meta_workspace_focus_default_window (workspace_manager->active_workspace,
|
2014-06-11 20:08:33 +00:00
|
|
|
NULL,
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_x11_display_get_current_time_roundtrip (x11_display));
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
else if (enter_event->evtype == XI_FocusIn &&
|
|
|
|
enter_event->mode == XINotifyNormal &&
|
|
|
|
enter_event->detail == XINotifyInferior)
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_FOCUS,
|
|
|
|
"Focus got set to root window, probably due to "
|
|
|
|
"gnome-session logout dialog usage (see bug "
|
2020-10-02 15:47:22 +00:00
|
|
|
"153220). Setting the default focus window.");
|
2017-08-27 19:02:40 +00:00
|
|
|
meta_workspace_focus_default_window (workspace_manager->active_workspace,
|
2014-06-11 20:08:33 +00:00
|
|
|
NULL,
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_x11_display_get_current_time_roundtrip (x11_display));
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't pass these events through to Clutter / GTK+ */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-08-26 18:54:39 +00:00
|
|
|
process_request_frame_extents (MetaX11Display *x11_display,
|
2014-06-11 20:08:33 +00:00
|
|
|
XEvent *event)
|
|
|
|
{
|
|
|
|
/* The X window whose frame extents will be set. */
|
|
|
|
Window xwindow = event->xclient.window;
|
|
|
|
unsigned long data[4] = { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
meta_topic (META_DEBUG_GEOMETRY,
|
2021-10-20 12:07:59 +00:00
|
|
|
"Setting _NET_FRAME_EXTENTS on unmanaged window 0x%lx",
|
|
|
|
xwindow);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 18:54:39 +00:00
|
|
|
XChangeProperty (x11_display->xdisplay, xwindow,
|
|
|
|
x11_display->atom__NET_FRAME_EXTENTS,
|
2014-06-11 20:08:33 +00:00
|
|
|
XA_CARDINAL,
|
|
|
|
32, PropModeReplace, (guchar*) data, 4);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
|
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
convert_property (MetaX11Display *x11_display,
|
|
|
|
Window w,
|
|
|
|
Atom target,
|
|
|
|
Atom property)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
#define N_TARGETS 4
|
|
|
|
Atom conversion_targets[N_TARGETS];
|
|
|
|
long icccm_version[] = { 2, 0 };
|
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
conversion_targets[0] = x11_display->atom_TARGETS;
|
|
|
|
conversion_targets[1] = x11_display->atom_MULTIPLE;
|
|
|
|
conversion_targets[2] = x11_display->atom_TIMESTAMP;
|
|
|
|
conversion_targets[3] = x11_display->atom_VERSION;
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:26:30 +00:00
|
|
|
if (target == x11_display->atom_TARGETS)
|
|
|
|
XChangeProperty (x11_display->xdisplay, w, property,
|
2014-06-11 20:08:33 +00:00
|
|
|
XA_ATOM, 32, PropModeReplace,
|
|
|
|
(unsigned char *)conversion_targets, N_TARGETS);
|
2017-08-26 16:26:30 +00:00
|
|
|
else if (target == x11_display->atom_TIMESTAMP)
|
|
|
|
XChangeProperty (x11_display->xdisplay, w, property,
|
2014-06-11 20:08:33 +00:00
|
|
|
XA_INTEGER, 32, PropModeReplace,
|
2017-08-26 18:51:28 +00:00
|
|
|
(unsigned char *)&x11_display->wm_sn_timestamp, 1);
|
2017-08-26 16:26:30 +00:00
|
|
|
else if (target == x11_display->atom_VERSION)
|
|
|
|
XChangeProperty (x11_display->xdisplay, w, property,
|
2014-06-11 20:08:33 +00:00
|
|
|
XA_INTEGER, 32, PropModeReplace,
|
|
|
|
(unsigned char *)icccm_version, 2);
|
|
|
|
else
|
|
|
|
{
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop_with_return (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
|
2014-06-11 20:08:33 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Be sure the PropertyNotify has arrived so we
|
|
|
|
* can send SelectionNotify
|
|
|
|
*/
|
|
|
|
/* FIXME the error trap pop synced anyway, right? */
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_topic (META_DEBUG_SYNC, "Syncing on %s", G_STRFUNC);
|
2017-08-26 16:26:30 +00:00
|
|
|
XSync (x11_display->xdisplay, False);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
|
|
|
|
static void
|
2017-08-26 18:54:39 +00:00
|
|
|
process_selection_request (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XSelectionEvent reply;
|
|
|
|
|
2017-08-26 18:51:28 +00:00
|
|
|
if (x11_display->wm_sn_selection_window != event->xselectionrequest.owner ||
|
|
|
|
x11_display->wm_sn_atom != event->xselectionrequest.selection)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:26:30 +00:00
|
|
|
str = XGetAtomName (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionrequest.selection);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Selection request with selection %s window 0x%lx not a WM_Sn selection we recognize",
|
2014-06-11 20:08:33 +00:00
|
|
|
str ? str : "(bad atom)", event->xselectionrequest.owner);
|
|
|
|
|
|
|
|
meta_XFree (str);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
reply.type = SelectionNotify;
|
2017-08-26 16:26:30 +00:00
|
|
|
reply.display = x11_display->xdisplay;
|
2014-06-11 20:08:33 +00:00
|
|
|
reply.requestor = event->xselectionrequest.requestor;
|
|
|
|
reply.selection = event->xselectionrequest.selection;
|
|
|
|
reply.target = event->xselectionrequest.target;
|
|
|
|
reply.property = None;
|
|
|
|
reply.time = event->xselectionrequest.time;
|
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xselectionrequest.target == x11_display->atom_MULTIPLE)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
if (event->xselectionrequest.property != None)
|
|
|
|
{
|
|
|
|
Atom type, *adata;
|
|
|
|
int i, format;
|
|
|
|
unsigned long num, rest;
|
|
|
|
unsigned char *data;
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:26:30 +00:00
|
|
|
if (XGetWindowProperty (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionrequest.requestor,
|
|
|
|
event->xselectionrequest.property, 0, 256, False,
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom_ATOM_PAIR,
|
2014-06-11 20:08:33 +00:00
|
|
|
&type, &format, &num, &rest, &data) != Success)
|
|
|
|
{
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop_with_return (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
if (meta_x11_error_trap_pop_with_return (x11_display) == Success)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
/* FIXME: to be 100% correct, should deal with rest > 0,
|
|
|
|
* but since we have 4 possible targets, we will hardly ever
|
|
|
|
* meet multiple requests with a length > 8
|
|
|
|
*/
|
|
|
|
adata = (Atom*)data;
|
|
|
|
i = 0;
|
|
|
|
while (i < (int) num)
|
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
if (!convert_property (x11_display,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionrequest.requestor,
|
|
|
|
adata[i], adata[i+1]))
|
|
|
|
adata[i+1] = None;
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:26:30 +00:00
|
|
|
XChangeProperty (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionrequest.requestor,
|
|
|
|
event->xselectionrequest.property,
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom_ATOM_PAIR,
|
2014-06-11 20:08:33 +00:00
|
|
|
32, PropModeReplace, data, num);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
meta_XFree (data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (event->xselectionrequest.property == None)
|
|
|
|
event->xselectionrequest.property = event->xselectionrequest.target;
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (convert_property (x11_display,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionrequest.requestor,
|
|
|
|
event->xselectionrequest.target,
|
|
|
|
event->xselectionrequest.property))
|
|
|
|
reply.property = event->xselectionrequest.property;
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
XSendEvent (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionrequest.requestor,
|
|
|
|
False, 0L, (XEvent*)&reply);
|
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Handled selection request");
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
2018-10-31 14:21:40 +00:00
|
|
|
static gboolean
|
|
|
|
close_display_idle_cb (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaX11Display *x11_display = META_X11_DISPLAY (user_data);
|
2021-03-03 16:21:59 +00:00
|
|
|
MetaDisplay *display = x11_display->display;
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
2018-10-31 14:21:40 +00:00
|
|
|
|
2021-03-03 16:21:59 +00:00
|
|
|
meta_display_close (display,
|
2018-10-31 14:21:40 +00:00
|
|
|
x11_display->xselectionclear_timestamp);
|
|
|
|
x11_display->display_close_idle = 0;
|
2021-03-03 16:21:59 +00:00
|
|
|
meta_context_terminate (context);
|
2018-10-31 14:21:40 +00:00
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2014-07-13 15:42:37 +00:00
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
process_selection_clear (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
if (x11_display->wm_sn_selection_window != event->xselectionclear.window ||
|
|
|
|
x11_display->wm_sn_atom != event->xselectionclear.selection)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 18:54:39 +00:00
|
|
|
str = XGetAtomName (x11_display->xdisplay,
|
2014-06-11 20:08:33 +00:00
|
|
|
event->xselectionclear.selection);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Selection clear with selection %s window 0x%lx not a WM_Sn selection we recognize",
|
2014-06-11 20:08:33 +00:00
|
|
|
str ? str : "(bad atom)", event->xselectionclear.window);
|
|
|
|
|
|
|
|
meta_XFree (str);
|
|
|
|
|
2014-07-13 15:42:37 +00:00
|
|
|
return FALSE;
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Got selection clear for on display %s",
|
2017-08-26 18:54:39 +00:00
|
|
|
x11_display->name);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2018-10-31 14:21:40 +00:00
|
|
|
/* We can't close a GdkDisplay in an even handler. */
|
|
|
|
if (!x11_display->display_close_idle)
|
|
|
|
{
|
|
|
|
x11_display->xselectionclear_timestamp = event->xselectionclear.time;
|
|
|
|
x11_display->display_close_idle = g_idle_add (close_display_idle_cb, x11_display);
|
|
|
|
}
|
|
|
|
|
2014-07-13 15:42:37 +00:00
|
|
|
return TRUE;
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
2016-03-07 04:46:18 +00:00
|
|
|
static void
|
2017-08-26 20:35:18 +00:00
|
|
|
notify_bell (MetaX11Display *x11_display,
|
|
|
|
XkbAnyEvent *xkb_ev)
|
2016-03-07 04:46:18 +00:00
|
|
|
{
|
2017-08-26 20:35:18 +00:00
|
|
|
MetaDisplay *display = x11_display->display;
|
2016-03-07 04:46:18 +00:00
|
|
|
XkbBellNotifyEvent *xkb_bell_event = (XkbBellNotifyEvent*) xkb_ev;
|
|
|
|
MetaWindow *window;
|
|
|
|
|
2017-08-26 20:35:18 +00:00
|
|
|
window = meta_x11_display_lookup_x_window (x11_display,
|
2017-08-26 16:56:44 +00:00
|
|
|
xkb_bell_event->window);
|
2016-03-07 04:46:18 +00:00
|
|
|
if (!window && display->focus_window && display->focus_window->frame)
|
|
|
|
window = display->focus_window;
|
|
|
|
|
2017-08-26 20:35:18 +00:00
|
|
|
x11_display->last_bell_time = xkb_ev->time;
|
2016-03-07 04:46:18 +00:00
|
|
|
if (!meta_bell_notify (display, window) &&
|
|
|
|
meta_prefs_bell_is_audible ())
|
|
|
|
{
|
|
|
|
/* Force a classic bell if the libcanberra bell failed. */
|
2017-08-26 20:35:18 +00:00
|
|
|
XkbForceDeviceBell (x11_display->xdisplay,
|
2016-03-07 04:46:18 +00:00
|
|
|
xkb_bell_event->device,
|
|
|
|
xkb_bell_event->bell_class,
|
|
|
|
xkb_bell_event->bell_id,
|
|
|
|
xkb_bell_event->percent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
handle_other_xevent (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
MetaDisplay *display = x11_display->display;
|
2017-08-27 19:02:40 +00:00
|
|
|
MetaWorkspaceManager *workspace_manager = display->workspace_manager;
|
2014-06-11 20:08:33 +00:00
|
|
|
Window modified;
|
|
|
|
MetaWindow *window;
|
|
|
|
MetaWindow *property_for_window;
|
|
|
|
gboolean frame_was_receiver;
|
|
|
|
gboolean bypass_gtk = FALSE;
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
modified = event_get_modified_window (x11_display, event);
|
2017-08-26 16:56:44 +00:00
|
|
|
window = modified != None ? meta_x11_display_lookup_x_window (x11_display, modified) : NULL;
|
2014-06-11 20:08:33 +00:00
|
|
|
frame_was_receiver = (window && window->frame && modified == window->frame->xwindow);
|
|
|
|
|
|
|
|
/* We only want to respond to _NET_WM_USER_TIME property notify
|
|
|
|
* events on _NET_WM_USER_TIME_WINDOW windows; in particular,
|
|
|
|
* responding to UnmapNotify events is kind of bad.
|
|
|
|
*/
|
|
|
|
property_for_window = NULL;
|
|
|
|
if (window && modified == window->user_time_window)
|
|
|
|
{
|
|
|
|
property_for_window = window;
|
|
|
|
window = NULL;
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:28:53 +00:00
|
|
|
if (META_X11_DISPLAY_HAS_XSYNC (x11_display) &&
|
|
|
|
event->type == (x11_display->xsync_event_base + XSyncAlarmNotify))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 16:56:44 +00:00
|
|
|
MetaWindow *alarm_window = meta_x11_display_lookup_sync_alarm (x11_display,
|
|
|
|
((XSyncAlarmNotifyEvent*)event)->alarm);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (alarm_window != NULL)
|
|
|
|
{
|
|
|
|
XSyncValue value = ((XSyncAlarmNotifyEvent*)event)->counter_value;
|
|
|
|
gint64 new_counter_value;
|
|
|
|
new_counter_value = XSyncValueLow32 (value) + ((gint64)XSyncValueHigh32 (value) << 32);
|
|
|
|
meta_window_x11_update_sync_request_counter (alarm_window, new_counter_value);
|
|
|
|
bypass_gtk = TRUE; /* GTK doesn't want to see this really */
|
|
|
|
}
|
2022-11-20 19:15:34 +00:00
|
|
|
else if (x11_display->alarm_filters)
|
2014-09-11 14:09:43 +00:00
|
|
|
{
|
2022-11-20 19:15:34 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < x11_display->alarm_filters->len; i++)
|
|
|
|
{
|
|
|
|
MetaX11AlarmFilter *alarm_filter =
|
|
|
|
x11_display->alarm_filters->pdata[i];
|
|
|
|
|
|
|
|
if (alarm_filter->filter (x11_display,
|
|
|
|
(XSyncAlarmNotifyEvent *) event,
|
|
|
|
alarm_filter->user_data))
|
|
|
|
{
|
|
|
|
bypass_gtk = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-09-11 14:09:43 +00:00
|
|
|
}
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-08-26 16:28:53 +00:00
|
|
|
if (META_X11_DISPLAY_HAS_SHAPE (x11_display) &&
|
|
|
|
event->type == (x11_display->shape_event_base + ShapeNotify))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
bypass_gtk = TRUE; /* GTK doesn't want to see this really */
|
|
|
|
|
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 08:35:47 +00:00
|
|
|
if (window)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XShapeEvent *sev = (XShapeEvent*) event;
|
|
|
|
|
|
|
|
if (sev->kind == ShapeBounding)
|
|
|
|
meta_window_x11_update_shape_region (window);
|
|
|
|
else if (sev->kind == ShapeInput)
|
|
|
|
meta_window_x11_update_input_region (window);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_SHAPES,
|
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 08:35:47 +00:00
|
|
|
"ShapeNotify not on a client window (window 0x%lx)",
|
|
|
|
modified);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case KeymapNotify:
|
|
|
|
break;
|
|
|
|
case Expose:
|
|
|
|
break;
|
|
|
|
case GraphicsExpose:
|
|
|
|
break;
|
|
|
|
case NoExpose:
|
|
|
|
break;
|
|
|
|
case VisibilityNotify:
|
|
|
|
break;
|
|
|
|
case CreateNotify:
|
|
|
|
{
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xcreatewindow.parent == x11_display->xroot)
|
2017-08-26 17:03:51 +00:00
|
|
|
meta_stack_tracker_create_event (display->stack_tracker,
|
2014-06-11 20:08:33 +00:00
|
|
|
&event->xcreatewindow);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DestroyNotify:
|
|
|
|
{
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xdestroywindow.event == x11_display->xroot)
|
2017-08-26 17:03:51 +00:00
|
|
|
meta_stack_tracker_destroy_event (display->stack_tracker,
|
2014-06-11 20:08:33 +00:00
|
|
|
&event->xdestroywindow);
|
|
|
|
}
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
/* FIXME: It sucks that DestroyNotify events don't come with
|
|
|
|
* a timestamp; could we do something better here? Maybe X
|
|
|
|
* will change one day?
|
|
|
|
*/
|
|
|
|
guint32 timestamp;
|
|
|
|
timestamp = meta_display_get_current_time_roundtrip (display);
|
|
|
|
|
|
|
|
if (display->grab_op != META_GRAB_OP_NONE &&
|
|
|
|
display->grab_window == window)
|
|
|
|
meta_display_end_grab_op (display, timestamp);
|
|
|
|
|
|
|
|
if (frame_was_receiver)
|
|
|
|
{
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
meta_window_destroy_frame (window->frame->window);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unmanage destroyed window */
|
|
|
|
meta_window_unmanage (window, timestamp);
|
|
|
|
window = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
/* FIXME: It sucks that UnmapNotify events don't come with
|
|
|
|
* a timestamp; could we do something better here? Maybe X
|
|
|
|
* will change one day?
|
|
|
|
*/
|
|
|
|
guint32 timestamp;
|
|
|
|
timestamp = meta_display_get_current_time_roundtrip (display);
|
|
|
|
|
|
|
|
if (display->grab_op != META_GRAB_OP_NONE &&
|
|
|
|
display->grab_window == window &&
|
|
|
|
window->frame == NULL)
|
|
|
|
meta_display_end_grab_op (display, timestamp);
|
|
|
|
|
|
|
|
if (!frame_was_receiver)
|
|
|
|
{
|
|
|
|
if (window->unmaps_pending == 0)
|
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_WINDOW_STATE,
|
2020-10-02 15:47:22 +00:00
|
|
|
"Window %s withdrawn",
|
2014-06-11 20:08:33 +00:00
|
|
|
window->desc);
|
|
|
|
|
|
|
|
/* Unmanage withdrawn window */
|
|
|
|
window->withdrawn = TRUE;
|
|
|
|
meta_window_unmanage (window, timestamp);
|
|
|
|
window = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
window->unmaps_pending -= 1;
|
|
|
|
meta_topic (META_DEBUG_WINDOW_STATE,
|
2020-10-02 15:47:22 +00:00
|
|
|
"Received pending unmap, %d now pending",
|
2014-06-11 20:08:33 +00:00
|
|
|
window->unmaps_pending);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MapNotify:
|
2020-08-26 09:49:50 +00:00
|
|
|
/* NB: override redirect windows won't cause a map request so we
|
2014-06-11 20:08:33 +00:00
|
|
|
* watch out for map notifies against any root windows too if a
|
|
|
|
* compositor is enabled: */
|
2017-08-26 16:26:30 +00:00
|
|
|
if (window == NULL && event->xmap.event == x11_display->xroot)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
window = meta_window_x11_new (display, event->xmap.window,
|
|
|
|
FALSE, META_COMP_EFFECT_CREATE);
|
|
|
|
}
|
2019-06-24 13:10:22 +00:00
|
|
|
else if (window && window->restore_focus_on_map &&
|
|
|
|
window->reparents_pending == 0)
|
2018-08-21 22:58:06 +00:00
|
|
|
{
|
|
|
|
meta_window_focus (window,
|
|
|
|
meta_display_get_current_time_roundtrip (display));
|
|
|
|
}
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
case MapRequest:
|
|
|
|
if (window == NULL)
|
|
|
|
{
|
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 08:35:47 +00:00
|
|
|
Atom type;
|
|
|
|
int format;
|
|
|
|
unsigned long nitems, bytes_after, *data;
|
|
|
|
|
|
|
|
/* Check whether the new window is a frame for another window */
|
|
|
|
if (XGetWindowProperty (x11_display->xdisplay,
|
|
|
|
event->xmaprequest.window,
|
|
|
|
x11_display->atom__MUTTER_FRAME_FOR,
|
|
|
|
0, 32, False, XA_WINDOW,
|
|
|
|
&type, &format, &nitems, &bytes_after,
|
|
|
|
(guchar **) &data) == Success &&
|
|
|
|
nitems == 1)
|
|
|
|
{
|
|
|
|
Window client_window;
|
|
|
|
|
|
|
|
client_window = data[0];
|
|
|
|
XFree (data);
|
|
|
|
|
|
|
|
window = meta_x11_display_lookup_x_window (x11_display,
|
|
|
|
client_window);
|
|
|
|
|
|
|
|
if (window != NULL && window->decorated && !window->frame)
|
|
|
|
{
|
|
|
|
meta_window_set_frame_xwindow (window,
|
|
|
|
event->xmaprequest.window);
|
|
|
|
meta_window_x11_initialize_state (window);
|
|
|
|
meta_window_update_visibility (window);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
window = meta_window_x11_new (display, event->xmaprequest.window,
|
|
|
|
FALSE, META_COMP_EFFECT_CREATE);
|
2014-09-18 10:03:53 +00:00
|
|
|
/* The window might have initial iconic state, but this is a
|
|
|
|
* MapRequest, fall through to ensure it is unminimized in
|
|
|
|
* that case.
|
|
|
|
*/
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
2014-09-18 10:03:53 +00:00
|
|
|
else if (frame_was_receiver)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2014-09-18 10:03:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Double check that creating the MetaWindow succeeded */
|
|
|
|
if (window == NULL)
|
|
|
|
break;
|
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("MapRequest on %s mapped = %d minimized = %d",
|
2014-09-18 10:03:53 +00:00
|
|
|
window->desc, window->mapped, window->minimized);
|
|
|
|
|
|
|
|
if (window->minimized)
|
|
|
|
{
|
|
|
|
meta_window_unminimize (window);
|
2017-08-27 19:02:40 +00:00
|
|
|
if (window->workspace != workspace_manager->active_workspace)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d",
|
2014-09-18 10:03:53 +00:00
|
|
|
window->mapped, window->minimized);
|
|
|
|
meta_window_change_workspace (window,
|
2017-08-27 19:02:40 +00:00
|
|
|
workspace_manager->active_workspace);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ReparentNotify:
|
|
|
|
{
|
2019-09-02 16:22:40 +00:00
|
|
|
if (window && window->reparents_pending > 0)
|
2019-06-24 13:10:22 +00:00
|
|
|
window->reparents_pending -= 1;
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xreparent.event == x11_display->xroot)
|
2017-08-26 17:03:51 +00:00
|
|
|
meta_stack_tracker_reparent_event (display->stack_tracker,
|
2014-06-11 20:08:33 +00:00
|
|
|
&event->xreparent);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ConfigureNotify:
|
|
|
|
if (event->xconfigure.event != event->xconfigure.window)
|
|
|
|
{
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xconfigure.event == x11_display->xroot &&
|
2017-08-26 18:51:28 +00:00
|
|
|
event->xconfigure.window != x11_display->composite_overlay_window)
|
2017-08-26 17:03:51 +00:00
|
|
|
meta_stack_tracker_configure_event (display->stack_tracker,
|
2014-06-11 20:08:33 +00:00
|
|
|
&event->xconfigure);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (window && window->override_redirect)
|
|
|
|
meta_window_x11_configure_notify (window, &event->xconfigure);
|
|
|
|
|
|
|
|
break;
|
|
|
|
case ConfigureRequest:
|
|
|
|
/* This comment and code is found in both twm and fvwm */
|
|
|
|
/*
|
|
|
|
* According to the July 27, 1988 ICCCM draft, we should ignore size and
|
|
|
|
* position fields in the WM_NORMAL_HINTS property when we map a window.
|
|
|
|
* Instead, we'll read the current geometry. Therefore, we should respond
|
|
|
|
* to configuration requests for windows which have never been mapped.
|
|
|
|
*/
|
|
|
|
if (window == NULL)
|
|
|
|
{
|
|
|
|
unsigned int xwcm;
|
|
|
|
XWindowChanges xwc;
|
|
|
|
|
|
|
|
xwcm = event->xconfigurerequest.value_mask &
|
|
|
|
(CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
|
|
|
|
|
|
|
|
xwc.x = event->xconfigurerequest.x;
|
|
|
|
xwc.y = event->xconfigurerequest.y;
|
|
|
|
xwc.width = event->xconfigurerequest.width;
|
|
|
|
xwc.height = event->xconfigurerequest.height;
|
|
|
|
xwc.border_width = event->xconfigurerequest.border_width;
|
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Configuring withdrawn window to %d,%d %dx%d border %d (some values may not be in mask)",
|
2014-06-11 20:08:33 +00:00
|
|
|
xwc.x, xwc.y, xwc.width, xwc.height, xwc.border_width);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_push (x11_display);
|
2017-08-26 16:26:30 +00:00
|
|
|
XConfigureWindow (x11_display->xdisplay, event->xconfigurerequest.window,
|
2014-06-11 20:08:33 +00:00
|
|
|
xwcm, &xwc);
|
2017-08-27 18:48:55 +00:00
|
|
|
meta_x11_error_trap_pop (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
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 08:35:47 +00:00
|
|
|
else if (!frame_was_receiver)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
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 08:35:47 +00:00
|
|
|
meta_window_x11_configure_request (window, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GravityNotify:
|
|
|
|
break;
|
|
|
|
case ResizeRequest:
|
|
|
|
break;
|
|
|
|
case CirculateNotify:
|
|
|
|
break;
|
|
|
|
case CirculateRequest:
|
|
|
|
break;
|
|
|
|
case PropertyNotify:
|
|
|
|
{
|
|
|
|
MetaGroup *group;
|
|
|
|
|
|
|
|
if (window && !frame_was_receiver)
|
|
|
|
meta_window_x11_property_notify (window, event);
|
|
|
|
else if (property_for_window && !frame_was_receiver)
|
|
|
|
meta_window_x11_property_notify (property_for_window, event);
|
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 08:35:47 +00:00
|
|
|
else if (frame_was_receiver)
|
|
|
|
meta_frame_handle_xevent (window->frame, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-26 16:58:29 +00:00
|
|
|
group = meta_x11_display_lookup_group (x11_display,
|
|
|
|
event->xproperty.window);
|
2014-06-11 20:08:33 +00:00
|
|
|
if (group != NULL)
|
|
|
|
meta_group_property_notify (group, event);
|
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xproperty.window == x11_display->xroot)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
if (event->xproperty.atom ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__NET_DESKTOP_LAYOUT)
|
2017-08-26 20:29:10 +00:00
|
|
|
meta_x11_display_update_workspace_layout (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
else if (event->xproperty.atom ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__NET_DESKTOP_NAMES)
|
2017-08-26 19:39:46 +00:00
|
|
|
meta_x11_display_update_workspace_names (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
/* we just use this property as a sentinel to avoid
|
|
|
|
* certain race conditions. See the comment for the
|
|
|
|
* sentinel_counter variable declaration in display.h
|
|
|
|
*/
|
|
|
|
if (event->xproperty.atom ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__MUTTER_SENTINEL)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2018-12-30 11:58:31 +00:00
|
|
|
meta_x11_display_decrement_focus_sentinel (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SelectionRequest:
|
2017-08-26 18:54:39 +00:00
|
|
|
process_selection_request (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
case SelectionNotify:
|
|
|
|
break;
|
|
|
|
case ColormapNotify:
|
|
|
|
break;
|
|
|
|
case ClientMessage:
|
|
|
|
if (window)
|
|
|
|
{
|
2014-08-14 00:19:35 +00:00
|
|
|
#ifdef HAVE_WAYLAND
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xclient.message_type == x11_display->atom_WL_SURFACE_ID)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
guint32 surface_id = event->xclient.data.l[0];
|
|
|
|
meta_xwayland_handle_wl_surface_id (window, surface_id);
|
|
|
|
}
|
2017-08-26 16:26:30 +00:00
|
|
|
else if (event->xclient.message_type ==
|
|
|
|
x11_display->atom__XWAYLAND_MAY_GRAB_KEYBOARD)
|
2017-10-20 08:47:24 +00:00
|
|
|
{
|
|
|
|
if (meta_is_wayland_compositor ())
|
|
|
|
g_object_set (G_OBJECT (window),
|
|
|
|
"xwayland-may-grab-keyboard", (event->xclient.data.l[0] != 0),
|
|
|
|
NULL);
|
|
|
|
}
|
2014-08-14 00:19:35 +00:00
|
|
|
else
|
|
|
|
#endif
|
2014-06-11 20:08:33 +00:00
|
|
|
meta_window_x11_client_message (window, event);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-26 16:26:30 +00:00
|
|
|
if (event->xclient.window == x11_display->xroot)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
if (event->xclient.message_type ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__NET_CURRENT_DESKTOP)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
int space;
|
|
|
|
MetaWorkspace *workspace;
|
|
|
|
guint32 time;
|
|
|
|
|
|
|
|
space = event->xclient.data.l[0];
|
|
|
|
time = event->xclient.data.l[1];
|
|
|
|
|
|
|
|
meta_verbose ("Request to change current workspace to %d with "
|
2020-10-02 15:47:22 +00:00
|
|
|
"specified timestamp of %u",
|
2014-06-11 20:08:33 +00:00
|
|
|
space, time);
|
|
|
|
|
2017-08-27 19:02:40 +00:00
|
|
|
workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, space);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2019-07-04 00:50:44 +00:00
|
|
|
if (workspace)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2019-07-04 00:50:44 +00:00
|
|
|
/* Handle clients using the older version of the spec... */
|
|
|
|
if (time == 0)
|
|
|
|
time = meta_x11_display_get_current_time_roundtrip (x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2019-07-04 00:50:44 +00:00
|
|
|
meta_workspace_activate (workspace, time);
|
|
|
|
}
|
2014-06-11 20:08:33 +00:00
|
|
|
else
|
2019-07-04 00:50:44 +00:00
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Don't know about workspace %d", space);
|
2019-07-04 00:50:44 +00:00
|
|
|
}
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
else if (event->xclient.message_type ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__NET_NUMBER_OF_DESKTOPS)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
int num_spaces;
|
|
|
|
|
|
|
|
num_spaces = event->xclient.data.l[0];
|
|
|
|
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Request to set number of workspaces to %d",
|
2014-06-11 20:08:33 +00:00
|
|
|
num_spaces);
|
|
|
|
|
|
|
|
meta_prefs_set_num_workspaces (num_spaces);
|
|
|
|
}
|
|
|
|
else if (event->xclient.message_type ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__NET_SHOWING_DESKTOP)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
gboolean showing_desktop;
|
|
|
|
guint32 timestamp;
|
|
|
|
|
|
|
|
showing_desktop = event->xclient.data.l[0] != 0;
|
|
|
|
/* FIXME: Braindead protocol doesn't have a timestamp */
|
2017-08-26 18:54:39 +00:00
|
|
|
timestamp = meta_x11_display_get_current_time_roundtrip (x11_display);
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Request to %s desktop",
|
2014-06-11 20:08:33 +00:00
|
|
|
showing_desktop ? "show" : "hide");
|
|
|
|
|
|
|
|
if (showing_desktop)
|
2017-08-27 19:02:40 +00:00
|
|
|
meta_workspace_manager_show_desktop (workspace_manager, timestamp);
|
2014-06-11 20:08:33 +00:00
|
|
|
else
|
|
|
|
{
|
2017-08-27 19:02:40 +00:00
|
|
|
meta_workspace_manager_unshow_desktop (workspace_manager);
|
|
|
|
meta_workspace_focus_default_window (workspace_manager->active_workspace, NULL, timestamp);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (event->xclient.message_type ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom_WM_PROTOCOLS)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Received WM_PROTOCOLS message");
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
if ((Atom)event->xclient.data.l[0] == x11_display->atom__NET_WM_PING)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
guint32 timestamp = event->xclient.data.l[1];
|
|
|
|
|
|
|
|
meta_display_pong_for_serial (display, timestamp);
|
|
|
|
|
|
|
|
/* We don't want ping reply events going into
|
|
|
|
* the GTK+ event loop because gtk+ will treat
|
|
|
|
* them as ping requests and send more replies.
|
|
|
|
*/
|
|
|
|
bypass_gtk = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->xclient.message_type ==
|
2017-08-26 16:26:30 +00:00
|
|
|
x11_display->atom__NET_REQUEST_FRAME_EXTENTS)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_verbose ("Received _NET_REQUEST_FRAME_EXTENTS message");
|
2017-08-26 18:54:39 +00:00
|
|
|
process_request_frame_extents (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MappingNotify:
|
|
|
|
{
|
|
|
|
gboolean ignore_current;
|
|
|
|
|
|
|
|
ignore_current = FALSE;
|
|
|
|
|
|
|
|
/* Check whether the next event is an identical MappingNotify
|
|
|
|
* event. If it is, ignore the current event, we'll update
|
|
|
|
* when we get the next one.
|
|
|
|
*/
|
2017-08-26 16:26:30 +00:00
|
|
|
if (XPending (x11_display->xdisplay))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XEvent next_event;
|
|
|
|
|
2017-08-26 16:26:30 +00:00
|
|
|
XPeekEvent (x11_display->xdisplay, &next_event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
|
|
|
if (next_event.type == MappingNotify &&
|
|
|
|
next_event.xmapping.request == event->xmapping.request)
|
|
|
|
ignore_current = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ignore_current)
|
|
|
|
{
|
|
|
|
/* Let XLib know that there is a new keyboard mapping.
|
|
|
|
*/
|
|
|
|
XRefreshKeyboardMapping (&event->xmapping);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2017-08-26 20:35:18 +00:00
|
|
|
if (event->type == x11_display->xkb_base_event_type)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
XkbAnyEvent *xkb_ev = (XkbAnyEvent *) event;
|
|
|
|
|
|
|
|
switch (xkb_ev->xkb_type)
|
|
|
|
{
|
|
|
|
case XkbBellNotify:
|
2017-08-26 20:35:18 +00:00
|
|
|
if (XSERVER_TIME_IS_BEFORE(x11_display->last_bell_time,
|
2014-06-11 20:08:33 +00:00
|
|
|
xkb_ev->time - 100))
|
|
|
|
{
|
2017-08-26 20:35:18 +00:00
|
|
|
notify_bell (x11_display, xkb_ev);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
break;
|
2014-08-14 21:32:41 +00:00
|
|
|
default:
|
2014-06-11 20:08:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return bypass_gtk;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
window_has_xwindow (MetaWindow *window,
|
|
|
|
Window xwindow)
|
|
|
|
{
|
|
|
|
if (window->xwindow == xwindow)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (window->frame && window->frame->xwindow == xwindow)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-11-18 09:49:36 +00:00
|
|
|
static gboolean
|
|
|
|
process_selection_event (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
|
|
|
{
|
|
|
|
gboolean handled = FALSE;
|
|
|
|
GList *l;
|
|
|
|
|
2018-11-19 17:17:25 +00:00
|
|
|
handled |= meta_x11_selection_handle_event (x11_display, event);
|
|
|
|
|
2019-10-21 10:58:35 +00:00
|
|
|
for (l = x11_display->selection.input_streams; l && !handled;)
|
|
|
|
{
|
|
|
|
GList *next = l->next;
|
|
|
|
|
|
|
|
handled |= meta_x11_selection_input_stream_xevent (l->data, event);
|
|
|
|
l = next;
|
|
|
|
}
|
2018-11-18 09:49:36 +00:00
|
|
|
|
2019-10-21 10:58:35 +00:00
|
|
|
for (l = x11_display->selection.output_streams; l && !handled;)
|
|
|
|
{
|
|
|
|
GList *next = l->next;
|
|
|
|
|
|
|
|
handled |= meta_x11_selection_output_stream_xevent (l->data, event);
|
|
|
|
l = next;
|
|
|
|
}
|
2018-11-18 09:49:36 +00:00
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
/**
|
|
|
|
* meta_display_handle_xevent:
|
|
|
|
* @display: The MetaDisplay that events are coming from
|
|
|
|
* @event: The event that just happened
|
|
|
|
*
|
|
|
|
* This is the most important function in the whole program. It is the heart,
|
|
|
|
* it is the nexus, it is the Grand Central Station of Mutter's world.
|
|
|
|
* When we create a #MetaDisplay, we ask GDK to pass *all* events for *all*
|
|
|
|
* windows to this function. So every time anything happens that we might
|
|
|
|
* want to know about, this function gets called. You see why it gets a bit
|
|
|
|
* busy around here. Most of this function is a ginormous switch statement
|
|
|
|
* dealing with all the kinds of events that might turn up.
|
|
|
|
*/
|
|
|
|
static gboolean
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_x11_display_handle_xevent (MetaX11Display *x11_display,
|
|
|
|
XEvent *event)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
MetaDisplay *display = x11_display->display;
|
2016-12-01 04:59:47 +00:00
|
|
|
MetaBackend *backend = meta_get_backend ();
|
2014-06-11 20:08:33 +00:00
|
|
|
Window modified;
|
|
|
|
gboolean bypass_compositor = FALSE, bypass_gtk = FALSE;
|
|
|
|
XIEvent *input_event;
|
2017-08-26 18:54:39 +00:00
|
|
|
MetaCursorTracker *cursor_tracker;
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2021-02-02 22:44:08 +00:00
|
|
|
COGL_TRACE_BEGIN (MetaX11DisplayHandleXevent,
|
|
|
|
"X11Display (handle X11 event)");
|
2019-08-29 17:35:01 +00:00
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
#if 0
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_spew_event_print (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
#endif
|
|
|
|
|
2018-08-22 18:57:04 +00:00
|
|
|
if (meta_x11_startup_notification_handle_xevent (x11_display, event))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-10-10 16:55:00 +00:00
|
|
|
#ifdef HAVE_WAYLAND
|
|
|
|
if (meta_is_wayland_compositor () &&
|
2020-11-11 12:17:14 +00:00
|
|
|
meta_xwayland_handle_xevent (event))
|
2014-10-10 16:55:00 +00:00
|
|
|
{
|
|
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-11-18 09:49:36 +00:00
|
|
|
if (process_selection_event (x11_display, event))
|
|
|
|
{
|
|
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
display->current_time = event_get_time (x11_display, event);
|
2016-12-01 04:59:47 +00:00
|
|
|
|
|
|
|
if (META_IS_BACKEND_X11 (backend))
|
|
|
|
meta_backend_x11_handle_event (META_BACKEND_X11 (backend), event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2018-12-30 17:25:08 +00:00
|
|
|
if (x11_display->focused_by_us &&
|
2017-08-26 18:54:39 +00:00
|
|
|
event->xany.serial > x11_display->focus_serial &&
|
2014-06-11 20:08:33 +00:00
|
|
|
display->focus_window &&
|
2017-08-26 18:54:39 +00:00
|
|
|
!window_has_xwindow (display->focus_window, x11_display->server_focus_window))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2020-10-02 15:47:22 +00:00
|
|
|
meta_topic (META_DEBUG_FOCUS, "Earlier attempt to focus %s failed",
|
2014-06-11 20:08:33 +00:00
|
|
|
display->focus_window->desc);
|
2018-12-30 17:25:08 +00:00
|
|
|
meta_x11_display_update_focus_window (x11_display,
|
|
|
|
x11_display->server_focus_window,
|
|
|
|
x11_display->server_focus_serial,
|
|
|
|
FALSE);
|
2019-09-27 11:06:34 +00:00
|
|
|
meta_display_update_focus_window (display,
|
|
|
|
meta_x11_display_lookup_x_window (x11_display,
|
|
|
|
x11_display->server_focus_window));
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (event->xany.window == x11_display->xroot)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
cursor_tracker = meta_backend_get_cursor_tracker (backend);
|
2020-07-31 19:08:15 +00:00
|
|
|
if (META_IS_CURSOR_TRACKER_X11 (cursor_tracker))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2020-07-31 19:08:15 +00:00
|
|
|
MetaCursorTrackerX11 *cursor_tracker_x11 =
|
|
|
|
META_CURSOR_TRACKER_X11 (cursor_tracker);
|
|
|
|
|
|
|
|
if (meta_cursor_tracker_x11_handle_xevent (cursor_tracker_x11, event))
|
|
|
|
{
|
|
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
modified = event_get_modified_window (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
input_event = get_input_event (x11_display, event);
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (handle_input_xevent (x11_display, input_event, event->xany.serial))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
bypass_gtk = bypass_compositor = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (handle_other_xevent (x11_display, event))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
|
|
|
bypass_gtk = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->type == SelectionClear)
|
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
if (process_selection_clear (x11_display, event))
|
2014-07-13 15:42:37 +00:00
|
|
|
{
|
2018-10-31 14:21:40 +00:00
|
|
|
bypass_gtk = TRUE;
|
|
|
|
goto out;
|
2014-07-13 15:42:37 +00:00
|
|
|
}
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2019-08-14 21:25:54 +00:00
|
|
|
if (!bypass_compositor && META_IS_COMPOSITOR_X11 (display->compositor))
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2019-08-14 21:25:54 +00:00
|
|
|
MetaCompositorX11 *compositor_x11 =
|
|
|
|
META_COMPOSITOR_X11 (display->compositor);
|
|
|
|
MetaWindow *window;
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2019-08-14 21:25:54 +00:00
|
|
|
if (modified != None)
|
|
|
|
window = meta_x11_display_lookup_x_window (x11_display, modified);
|
|
|
|
else
|
|
|
|
window = NULL;
|
|
|
|
|
|
|
|
meta_compositor_x11_process_xevent (compositor_x11, event, window);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
2017-08-26 20:24:21 +00:00
|
|
|
display->current_time = META_CURRENT_TIME;
|
2021-02-02 22:44:08 +00:00
|
|
|
|
|
|
|
COGL_TRACE_DESCRIBE (MetaX11DisplayHandleXevent,
|
|
|
|
get_event_name (x11_display, event));
|
|
|
|
COGL_TRACE_END (MetaX11DisplayHandleXevent);
|
|
|
|
|
2014-06-11 20:08:33 +00:00
|
|
|
return bypass_gtk;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GdkFilterReturn
|
|
|
|
xevent_filter (GdkXEvent *xevent,
|
|
|
|
GdkEvent *event,
|
|
|
|
gpointer data)
|
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
MetaX11Display *x11_display = data;
|
2014-06-11 20:08:33 +00:00
|
|
|
|
2017-08-26 18:54:39 +00:00
|
|
|
if (meta_x11_display_handle_xevent (x11_display, xevent))
|
2014-06-11 20:08:33 +00:00
|
|
|
return GDK_FILTER_REMOVE;
|
|
|
|
else
|
|
|
|
return GDK_FILTER_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_x11_display_init_events (MetaX11Display *x11_display)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
gdk_window_add_filter (NULL, xevent_filter, x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-08-26 18:54:39 +00:00
|
|
|
meta_x11_display_free_events (MetaX11Display *x11_display)
|
2014-06-11 20:08:33 +00:00
|
|
|
{
|
2017-08-26 18:54:39 +00:00
|
|
|
gdk_window_remove_filter (NULL, xevent_filter, x11_display);
|
2014-06-11 20:08:33 +00:00
|
|
|
}
|