Implement keyboard shortcut inhibition

* 12to11.c (XLMain): Initialize keyboard shortcut inhibition.
* Imakefile (SRCS): Add keyboard_shortcuts_inhibit.c.
(OBJS): Add keyboard_shortcuts_inhibit.o.
* compositor.h (enum _ClientDataType): Add ShortcutInhibitData.
(struct _ClientData): New structure.
(struct _Surface): Make client data a linked list.
* pointer_constraints.c (Reconfine, XLPointerBarrierLeft)
(XLPointerBarrierCheck, XLPointerConstraintsSurfaceMovedTo):
Adjust to new client data storage approach.
* seat.c (struct _Seat): New fields `last_focus_time' and
`external_grab_time'.
(HandleBind, SelectDeviceEvents, SetFocusSurface): Use size_t to
represent mask length.
(DispatchFocusIn): Set last focus time.
(FakePointerEdge, XLSelectStandardEvents): Likewise; use size_t.
(XLSeatExplicitlyGrabSurface): Clear active grab.
(XLSeatBeginDrag): Use size_t to represent XI mask length.
(XLSeatApplyExternalGrab, XLSeatCancelExternalGrab): New
functions.
* subsurface.c (Teardown, XLSubsurfaceHandleParentCommit):
Adjust client data storage.
* surface.c (HandleSurfaceDestroy, XLSurfaceGetClientData):
Adjust client data storage to use a linked list.
(XLSurfaceFindClientData): New function.
* text_input.c (FilterInputCallback): Pacify cppcheck.
This commit is contained in:
oldosfan 2022-10-18 05:35:52 +00:00
parent f683d8c30f
commit 17571b6f97
8 changed files with 196 additions and 57 deletions

View file

@ -236,6 +236,7 @@ XLMain (int argc, char **argv)
XLInitDrmLease ();
XLInitPointerConstraints ();
XLInitRelativePointer ();
XLInitKeyboardShortcutsInhibit ();
/* This has to come after the rest of the initialization. */
DetermineServerTime ();

View file

@ -24,7 +24,7 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
picture_renderer.c explicit_synchronization.c transform.c \
wp_viewporter.c decoration.c text_input.c \
single_pixel_buffer.c drm_lease.c pointer_constraints.c \
time.c relative_pointer.c
time.c relative_pointer.c keyboard_shortcuts_inhibit.c
OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
surface.o region.o shm.o atoms.o subcompositor.o positioner.o \
@ -35,7 +35,7 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
picture_renderer.o explicit_synchronization.o transform.o \
wp_viewporter.o decoration.o text_input.o \
single_pixel_buffer.o drm_lease.o pointer_constraints.o \
time.o relative_pointer.o
time.o relative_pointer.o keyboard_shortcuts_inhibit.o
GENHEADERS = transfer_atoms.h
@ -121,6 +121,7 @@ ScannerTarget(single-pixel-buffer-v1)
ScannerTarget(drm-lease-v1)
ScannerTarget(pointer-constraints-unstable-v1)
ScannerTarget(relative-pointer-unstable-v1)
ScannerTarget(keyboard-shortcuts-inhibit-unstable-v1)
/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */
$(OBJS): $(GENHEADERS)

View file

@ -892,11 +892,13 @@ typedef struct _RoleFuncs RoleFuncs;
typedef struct _CommitCallback CommitCallback;
typedef struct _UnmapCallback UnmapCallback;
typedef struct _DestroyCallback DestroyCallback;
typedef struct _ClientData ClientData;
enum _ClientDataType
{
SubsurfaceData,
PointerConfinementData,
ShortcutInhibitData,
MaxClientData,
};
@ -937,6 +939,21 @@ struct _CommitCallback
CommitCallback *next, *last;
};
struct _ClientData
{
/* The next piece of client data attached to this surface. */
ClientData *next;
/* The client data itself. */
void *data;
/* The free function. */
void (*free_function) (void *);
/* The type of the client data. */
ClientDataType type;
};
struct _Surface
{
/* The view associated with this surface. */
@ -968,11 +985,8 @@ struct _Surface
/* List of subsurfaces. */
XLList *subsurfaces;
/* Array of "client data". */
void *client_data[MaxClientData];
/* List of functions for freeing "client data". */
void (*free_client_data[MaxClientData]) (void *);
/* List of client data. */
ClientData *client_data;
/* List of commit callbacks. */
CommitCallback commit_callbacks;
@ -1087,6 +1101,7 @@ extern DestroyCallback *XLSurfaceRunOnFree (Surface *, void (*) (void *),
extern void XLSurfaceCancelRunOnFree (DestroyCallback *);
extern void *XLSurfaceGetClientData (Surface *, ClientDataType,
size_t, void (*) (void *));
extern void *XLSurfaceFindClientData (Surface *, ClientDataType);
extern Bool XLSurfaceGetResizeDimensions (Surface *, int *, int *);
extern void XLSurfacePostResize (Surface *, int, int, int, int);
extern void XLSurfaceMoveBy (Surface *, int, int);
@ -1450,6 +1465,8 @@ extern void XLSeatLockPointer (Seat *);
extern void XLSeatUnlockPointer (Seat *);
extern RelativePointer *XLSeatGetRelativePointer (Seat *, struct wl_resource *);
extern void XLSeatDestroyRelativePointer (RelativePointer *);
extern Bool XLSeatApplyExternalGrab (Seat *, Surface *);
extern void XLSeatCancelExternalGrab (Seat *);
extern Cursor InitDefaultCursor (void);
@ -1623,6 +1640,12 @@ extern void XLInitRelativePointer (void);
extern void XLRelativePointerSendRelativeMotion (struct wl_resource *,
uint64_t, double, double);
/* Defined in keyboard_shortcuts_inhibit.c. */
extern void XLInitKeyboardShortcutsInhibit (void);
extern void XLCheckShortcutInhibition (Seat *, Surface *);
extern void XLReleaseShortcutInhibition (Seat *, Surface *);
/* Utility functions that don't belong in a specific file. */
#define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0])

View file

@ -1776,7 +1776,7 @@ Reconfine (Surface *surface, int *root_x, int *root_y,
if (!XLWindowFromSurface (surface))
return;
record = surface->client_data[PointerConfinementData];
record = XLSurfaceFindClientData (surface, PointerConfinementData);
if (!record)
return;
@ -1813,7 +1813,7 @@ XLPointerBarrierLeft (Seat *seat, Surface *surface)
/* The pointer has now left the given surface. If there is an
active confinement for that surface and seat, disable it. */
record = surface->client_data[PointerConfinementData];
record = XLSurfaceFindClientData (surface, PointerConfinementData);
if (!record)
return;
@ -1834,7 +1834,7 @@ XLPointerBarrierCheck (Seat *seat, Surface *dispatch, double x, double y,
pixman_box32_t box;
int offset_x, offset_y;
record = dispatch->client_data[PointerConfinementData];
record = XLSurfaceFindClientData (dispatch, PointerConfinementData);
if (!record)
return;
@ -1959,7 +1959,7 @@ XLPointerConstraintsSurfaceMovedTo (Surface *surface, int root_x,
query for the position manually. Simply move the lines for the
surface's window and each of its subsurfaces. */
record = surface->client_data[PointerConfinementData];
record = XLSurfaceFindClientData (surface, PointerConfinementData);
if (!record)
return;

94
seat.c
View file

@ -89,6 +89,7 @@ enum
IsTextInputSeat = (1 << 5),
IsPointerLocked = (1 << 6),
IsSurfaceCoordSet = (1 << 7),
IsExternalGrabApplied = (1 << 8),
};
enum
@ -362,6 +363,12 @@ struct _Seat
/* The last user time. */
Timestamp last_user_time;
/* The last time the focus changed into a surface. */
Timestamp last_focus_time;
/* When the last external grab was applied. */
Time external_grab_time;
/* wl_global associated with this seat. */
struct wl_global *global;
@ -1749,7 +1756,7 @@ HandleBind (struct wl_client *client, void *data,
{
struct wl_resource *resource;
char *name;
ptrdiff_t length;
size_t length;
Seat *seat;
seat = data;
@ -2665,7 +2672,7 @@ static void
SelectDeviceEvents (void)
{
XIEventMask mask;
ptrdiff_t length;
size_t length;
length = XIMaskLen (XI_LASTEVENT);
mask.mask = alloca (length);
@ -2864,6 +2871,10 @@ SetFocusSurface (Seat *seat, Surface *focus)
{
SendKeyboardLeave (seat, seat->focus_surface);
/* Cancel any grab that may be associated with shortcut
inhibition. */
XLReleaseShortcutInhibition (seat, seat->focus_surface);
XLSurfaceCancelRunOnFree (seat->focus_destroy_callback);
seat->focus_destroy_callback = NULL;
seat->focus_surface = NULL;
@ -2881,6 +2892,9 @@ SetFocusSurface (Seat *seat, Surface *focus)
return;
}
/* Apply any shortcut inhibition. */
XLCheckShortcutInhibition (seat, focus);
if (input_funcs)
/* Tell any input method about the change. */
input_funcs->focus_in (seat, focus);
@ -2907,6 +2921,9 @@ DispatchFocusIn (Surface *surface, XIFocusInEvent *event)
if (!seat)
return;
/* Record the time the focus changed for the external grab. */
seat->last_focus_time = TimestampFromServerTime (event->time);
SetFocusSurface (seat, surface);
}
@ -4553,7 +4570,7 @@ FakePointerEdge (Seat *seat, Surface *target, uint32_t serial,
Status state;
Window window;
XIEventMask mask;
ptrdiff_t length;
size_t length;
if (edge == NoneEdge)
return False;
@ -4751,7 +4768,7 @@ void
XLSelectStandardEvents (Window window)
{
XIEventMask mask;
ptrdiff_t length;
size_t length;
length = XIMaskLen (XI_LASTEVENT);
mask.mask = alloca (length);
@ -4965,7 +4982,7 @@ XLSeatExplicitlyGrabSurface (Seat *seat, Surface *surface, uint32_t serial)
WhatEdge edge;
Time time;
XIEventMask mask;
ptrdiff_t length;
size_t length;
Cursor cursor;
if (seat->flags & IsInert
@ -5017,6 +5034,8 @@ XLSeatExplicitlyGrabSurface (Seat *seat, Surface *surface, uint32_t serial)
XISetMask (mask.mask, XI_Motion);
XISetMask (mask.mask, XI_ButtonPress);
XISetMask (mask.mask, XI_ButtonRelease);
XISetMask (mask.mask, XI_KeyPress);
XISetMask (mask.mask, XI_KeyRelease);
cursor = (seat->cursor ? seat->cursor->cursor : None);
@ -5036,10 +5055,15 @@ XLSeatExplicitlyGrabSurface (Seat *seat, Surface *surface, uint32_t serial)
that keyboard focus cannot be changed, which is not very crucial,
so it is allowed to fail. */
XIGrabDevice (compositor.display, seat->master_keyboard,
state = XIGrabDevice (compositor.display, seat->master_keyboard,
window, time, None, XIGrabModeAsync,
XIGrabModeAsync, True, &mask);
/* Cancel any external grab that might be applied if the keyboard
grab succeeded. */
if (state == Success)
seat->flags &= ~IsExternalGrabApplied;
/* And record the grab surface, so that owner_events can be
implemented correctly. */
SwapGrabSurface (seat, surface);
@ -5332,7 +5356,7 @@ XLSeatBeginDrag (Seat *seat, DataSource *data_source, Surface *start_surface,
Window window;
Time time;
XIEventMask mask;
ptrdiff_t length;
size_t length;
WhatEdge edge;
Status state;
@ -5737,3 +5761,59 @@ XLSeatDestroyRelativePointer (RelativePointer *relative_pointer)
XLFree (relative_pointer);
}
Bool
XLSeatApplyExternalGrab (Seat *seat, Surface *surface)
{
Window window;
Status state;
XIEventMask mask;
size_t length;
/* Grab the toplevel SURFACE on SEAT. */
window = XLWindowFromSurface (surface);
if (!window)
return None;
length = XIMaskLen (XI_LASTEVENT);
mask.mask = alloca (length);
mask.mask_len = length;
mask.deviceid = XIAllMasterDevices;
memset (mask.mask, 0, length);
/* Grab focus and key events. */
XISetMask (mask.mask, XI_FocusIn);
XISetMask (mask.mask, XI_FocusOut);
XISetMask (mask.mask, XI_KeyPress);
XISetMask (mask.mask, XI_KeyRelease);
state = XIGrabDevice (compositor.display, seat->master_keyboard,
window, seat->last_focus_time.milliseconds, None,
XIGrabModeAsync, XIGrabModeAsync, True, &mask);
if (state == Success)
{
/* Mark an external grab as having been applied. */
seat->flags |= IsExternalGrabApplied;
/* Record the time when it was applied. */
seat->external_grab_time = seat->last_focus_time.milliseconds;
return True;
}
return False;
}
void
XLSeatCancelExternalGrab (Seat *seat)
{
if (!(seat->flags & IsExternalGrabApplied))
return;
/* Cancel the external grab. */
XIUngrabDevice (compositor.display, seat->master_keyboard,
seat->external_grab_time);
}

View file

@ -792,7 +792,8 @@ Teardown (Surface *surface, Role *role)
ViewUnparent (surface->under);
ViewSetSubcompositor (surface->under, NULL);
client = subsurface->parent->client_data[SubsurfaceData];
client = XLSurfaceFindClientData (subsurface->parent,
SubsurfaceData);
if (client)
{
@ -986,7 +987,7 @@ XLSubsurfaceHandleParentCommit (Surface *parent)
{
SurfaceActionClientData *client;
client = parent->client_data[SubsurfaceData];
client = XLSurfaceFindClientData (parent, SubsurfaceData);
if (client)
RunSurfaceActions (&client->actions);

View file

@ -1305,7 +1305,7 @@ static void
HandleSurfaceDestroy (struct wl_resource *resource)
{
Surface *surface;
int i;
ClientData *data, *last;
surface = wl_resource_get_user_data (resource);
@ -1322,13 +1322,18 @@ HandleSurfaceDestroy (struct wl_resource *resource)
NotifySubsurfaceDestroyed);
/* Then release all client data. */
for (i = 0; i < MaxClientData; ++i)
{
if (surface->client_data[i])
surface->free_client_data[i] (surface->client_data[i]);
XLFree (surface->client_data[i]);
data = surface->client_data;
surface->client_data[i] = NULL;
while (data)
{
/* Free the client data. */
data->free_function (data->data);
XLFree (data->data);
/* And its record. */
last = data;
data = data->next;
XLFree (last);
}
/* Release the output region. */
@ -1641,13 +1646,38 @@ void *
XLSurfaceGetClientData (Surface *surface, ClientDataType type,
size_t size, void (*free_func) (void *))
{
if (surface->client_data[type])
return surface->client_data[type];
ClientData *data;
surface->client_data[type] = XLCalloc (1, size);
surface->free_client_data[type] = free_func;
/* First, look for existing client data. */
for (data = surface->client_data; data; data = data->next)
{
if (data->type == type)
return data->data;
}
return surface->client_data[type];
/* Next, allocate some new client data. */
data = XLMalloc (sizeof *data);
data->next = surface->client_data;
surface->client_data = data;
data->data = XLCalloc (1, size);
data->free_function = free_func;
data->type = type;
return data->data;
}
void *
XLSurfaceFindClientData (Surface *surface, ClientDataType type)
{
ClientData *data;
for (data = surface->client_data; data; data = data->next)
{
if (data->type == type)
return data->data;
}
return NULL;
}
Window

View file

@ -3217,27 +3217,30 @@ FilterInputCallback (Seat *seat, Surface *surface, void *event,
/* Find the enabled text input. */
if (info)
{
input = FindEnabledTextInput (info);
/* If there is an enabled text input, start filtering the event. */
if (info && input && input->xic)
/* If there is an enabled text input, start filtering the
event. */
if (input && input->xic)
{
DebugPrint ("found enabled text input %p on client-seat info %p",
input, info);
/* Convert the extension event into a fake core event that the
input method can understand. */
/* Convert the extension event into a fake core event that
the input method can understand. */
ConvertKeyEvent (xev, &xkey);
/* And return the result of filtering the event. */
if (XFilterEvent (&xkey, XLWindowFromSurface (surface)))
return True;
/* Otherwise, call XmbLookupString. If a keysym is returned,
return False. Otherwise, commit the string looked up and
return True. */
/* Otherwise, call XmbLookupString. If a keysym is
returned, return False. Otherwise, commit the string
looked up and return True. */
return LookupString (input, &xkey, keysym);
}
}
/* Otherwise, do nothing. */
return False;