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:
parent
f683d8c30f
commit
17571b6f97
8 changed files with 196 additions and 57 deletions
1
12to11.c
1
12to11.c
|
@ -236,6 +236,7 @@ XLMain (int argc, char **argv)
|
|||
XLInitDrmLease ();
|
||||
XLInitPointerConstraints ();
|
||||
XLInitRelativePointer ();
|
||||
XLInitKeyboardShortcutsInhibit ();
|
||||
|
||||
/* This has to come after the rest of the initialization. */
|
||||
DetermineServerTime ();
|
||||
|
|
|
@ -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)
|
||||
|
|
33
compositor.h
33
compositor.h
|
@ -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])
|
||||
|
|
|
@ -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;
|
||||
|
|
112
seat.c
112
seat.c
|
@ -82,13 +82,14 @@ XLList *live_seats;
|
|||
|
||||
enum
|
||||
{
|
||||
IsInert = 1,
|
||||
IsWindowMenuShown = (1 << 2),
|
||||
IsDragging = (1 << 3),
|
||||
IsDropped = (1 << 4),
|
||||
IsTextInputSeat = (1 << 5),
|
||||
IsPointerLocked = (1 << 6),
|
||||
IsSurfaceCoordSet = (1 << 7),
|
||||
IsInert = 1,
|
||||
IsWindowMenuShown = (1 << 2),
|
||||
IsDragging = (1 << 3),
|
||||
IsDropped = (1 << 4),
|
||||
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,9 +5055,14 @@ 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,
|
||||
window, time, None, XIGrabModeAsync,
|
||||
XIGrabModeAsync, True, &mask);
|
||||
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. */
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
54
surface.c
54
surface.c
|
@ -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
|
||||
|
|
35
text_input.c
35
text_input.c
|
@ -3217,26 +3217,29 @@ 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)
|
||||
{
|
||||
DebugPrint ("found enabled text input %p on client-seat info %p",
|
||||
input, info);
|
||||
input = FindEnabledTextInput (info);
|
||||
|
||||
/* Convert the extension event into a fake core event that the
|
||||
input method can understand. */
|
||||
ConvertKeyEvent (xev, &xkey);
|
||||
/* 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);
|
||||
|
||||
/* And return the result of filtering the event. */
|
||||
if (XFilterEvent (&xkey, XLWindowFromSurface (surface)))
|
||||
return True;
|
||||
/* Convert the extension event into a fake core event that
|
||||
the input method can understand. */
|
||||
ConvertKeyEvent (xev, &xkey);
|
||||
|
||||
/* Otherwise, call XmbLookupString. If a keysym is returned,
|
||||
return False. Otherwise, commit the string looked up and
|
||||
return True. */
|
||||
return LookupString (input, &xkey, keysym);
|
||||
/* 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. */
|
||||
return LookupString (input, &xkey, keysym);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, do nothing. */
|
||||
|
|
Loading…
Add table
Reference in a new issue