Implement support for zwp_text_input_manager_v3

* 12to11.c (HandleCmdline): New function.
(XLMain): Handle locale, initialize text input and and set up
the resource database.
* 12to11.man: Document resources and command-line arguments.
* Imakefile (SRCS, OBJS): Add text_input.c and text_input.o.
(text-input-unstable-v3): New scanner target.
* README: Document support for zwp_text_input_manager_v3.
* alloc.c (XLMalloc, XLCalloc, XLRealloc): Allow alloc of size 0
to return NULL.
* atoms.c (resource_quark, app_quark, QString): New quarks.
(XLInitAtoms): Initialize some quarks.
* compositor.h (struct _Compositor): Add resource and app names.
(struct _RoleFuncs): Add `select_extra_events'.
(struct _TextInputFuncs): New structure.
* run.c (HandleOneXEvent): Filter events if necessary.
* seat.c (AllKeyMask): New define.
(input_funcs): New variable.
(MakeSeatForDevicePair, NoticeDeviceDisabled): Always assign a
single seat the role of "text input seat".
(ClearFocusSurface, SetFocusSurface): Call input method hooks.
(HackKeyboardModifiers): New function.
(DispatchKey): Ignore repeated key events.
(XLSeatGetFocus): New function.
(XLSeatSetTextInputFuncs, XLSeatGetKeyboardDevice)
(XLSeatGetInputMethodSeat, XLSeatDispatchCoreKeyEvent): New
function.
* surface.c (XLSurfaceSelectExtraEvents): New function.
* xdg_surface.c (DefaultEventMask): Add core event mask here.
(XLHandleXEventForXdgSurfaces): Handle core key events.
(Commit, NoteBounds): Improve debug code.
(SelectExtraEvents): New function.
(XLGetXdgSurface, XLXdgRoleSetBoundsSize): Improve debug code.
(XLInitXdgSurfaces): Reduce size of assoc table.
* xdg_toplevel.c (SendConfigure, SendDecorationConfigure, Map)
(HandleConfigureEvent, SetMode, UnsetMode): Avoid sending
decoration configure before initial commit.
This commit is contained in:
oldosfan 2022-10-06 02:09:36 +00:00
parent 46aa84e4e5
commit c190ead122
12 changed files with 526 additions and 49 deletions

View file

@ -19,8 +19,10 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <locale.h>
#include "compositor.h"
@ -62,6 +64,71 @@ DetermineServerTime (void)
}
}
static void
HandleCmdline (int argc, char **argv)
{
int i;
/* Set the default resource and class names. */
compositor.resource_name = "12to11";
compositor.app_name = "12to11";
if (argc < 2)
/* There are no arguments to handle. */
return;
/* Determine the instance name based on the executable. First,
remove any leading directory separator from argv[0]. */
compositor.app_name = strrchr (argv[0], '/');
/* If no directory separator was present, just use it. */
if (!compositor.app_name)
compositor.app_name = argv[0];
else
/* Otherwise, strip the trailing '/'. */
compositor.app_name = compositor.app_name + 1;
for (i = 1; i < argc; ++i)
{
if (!strcmp (argv[i], "-help"))
{
print_usage:
fprintf (stderr,
"usage: %s [-name name] [-class class]\n",
argv[0]);
exit (!strcmp (argv[i], "-help") ? 0 : 1);
}
else if (!strcmp (argv[i], "-class"))
{
if (i + 1 >= argc)
{
fprintf (stderr, "%s: option -class requires a value\n",
argv[0]);
exit (1);
}
compositor.resource_name = argv[++i];
}
else if (!strcmp (argv[i], "-name"))
{
if (i + 1 >= argc)
{
fprintf (stderr, "%s: option -name requires a value\n",
argv[0]);
exit (1);
}
compositor.app_name = argv[++i];
}
else
{
fprintf (stderr, "%s: bad command line option \"%s\"\n",
argv[0], argv[1]);
goto print_usage;
}
}
}
static void
XLMain (int argc, char **argv)
{
@ -69,6 +136,9 @@ XLMain (int argc, char **argv)
struct wl_display *wl_display;
const char *socket;
/* Set the locale. */
setlocale (LC_ALL, "");
dpy = XOpenDisplay (NULL);
wl_display = wl_display_create ();
@ -86,6 +156,14 @@ XLMain (int argc, char **argv)
exit (1);
}
/* Call XGetDefault with some dummy values to have the resource
database set up. */
XrmInitialize ();
XGetDefault (dpy, "dummmy", "value");
/* Parse command-line arguments. */
HandleCmdline (argc, argv);
compositor.display = dpy;
compositor.conn = XGetXCBConnection (dpy);
compositor.wl_display = wl_display;
@ -124,6 +202,7 @@ XLMain (int argc, char **argv)
XLInitExplicitSynchronization ();
XLInitWpViewporter ();
XLInitDecoration ();
XLInitTextInput ();
/* This has to come after the rest of the initialization. */
DetermineServerTime ();
XLRunCompositor ();

View file

@ -3,12 +3,102 @@
12to11 - Wayland to X protocol translator
.SH SYNOPSIS
.B 12to11
[\-\fIclass\fP class] [\-\fIname\fP name]
.SH DESCRIPTION
.I 12to11
starts a Wayland compositor on the next available socket;
Wayland programs will then be displayed through the X server.
.SH OPTIONS
None.
Some X Toolkit library-style command-line arguments are also accepted,
despite the protocol translator being implemented without using a
toolkit. These options are:
.TP 8
.B \-class \fIclass\fP
This option specifies the resource class under which resources are to
be obtained. When not set, it defaults to the string ``12to11''. The
resource class and name used by the protocol translator are \fInot\fP
set as the
.B WM_CLASS
property on windows created by the protocol translator; instead, those
windows get the classes and names assigned to them by their individual
Wayland clients.
.TP 8
.B \-name \fIname\fP
This option specifies the instance name under which resources are to
be obtained. When not set, it defaults to the executable file name.
.TP 8
.B \-help\fP
This option causes the protocol translator to print a message
describing options it accepts. The protocol translator will then exit
after printing the message.
.SH RESOURCES
\fI12to11\fP understands some resource names and classes that can be
used to specify various settings that affect its behavior. Those
resources are listed below:
.TP 8
.B ximFont\fP (class \fBXimFont\fP)
Specifies the font to be used for displaying the preedit or status
areas of an input method.
.IP
In many input methods, the preedit (a.k.a composition or
preconversion) string and/or a status window is displayed on screen
while typing by the input method server. The client is supposed to
determine the font used by the input method server to display --
however, the Wayland protocol does not allow Wayland clients to
specify that themselves, so the protocol translator has to do that by
itself.
.TP
.B ximStyles\fP (class \fBXimStyles\fP)
Specifies the default input method styles used by the protocol
translator.
.IP
X input methods can support different editing styles, which affect how
preconversion and status text is displayed while typing. These styles
are named:
.TP
.I overTheSpot
In ``over the spot'', the preedit string is displayed in a window
created by the input method at a location specified by the Wayland
client, typically the text insertion point.
.TP
.I offTheSpot
In ``off the spot'', the preedit string is displayed in a window
created by the input method at some location away from the text
insertion point. Often, this type of window is placed at the bottom
of the preedit window.
.TP
.I rootWindow
In the ``root window'' editing style, the preedit string is displayed
in a popup window created by the input method.
.TP
.I onTheSpot
In the ``on the spot'' editing style, the preedit string is displayed
inside the text itself by the Wayland client.
.PP
Not all input methods support all editing styles. In the real world,
most only support one or two of the styles listed above. The protocol
translator will search for a style supported by the input method when
initializing input method support. The \fBximStyles\fP resource is
used to control the order in which the protocol translator searches
for input styles, and should be a comma separated list of input names,
which are searched in left-to-right order. For example,
.PP
.in +4
.EX
\fBoverTheSpot,rootWindow\fP
.EE
.in
.PP
will result in the protocol translator searching for the ``over the
spot'' input style, and if that is not present, the ``root window''
style. Whitespace must not be present inside the comma-separated
list. When \fBximStyles\fP is not specified, it defaults to:
.PP
.in +4
.EX
\fBoverTheSpot,offTheSpot,rootWindow,onTheSpot\fP
.EE
.in
.SH ENVIRONMENT
Several environment variables exist that modify the behavior of the
protocol translator in one way or another. Most of these are used for
@ -99,6 +189,6 @@ and
window manager hints will result in Wayland programs running
incorrectly.
.SH "SEE ALSO"
X(1), Xorg(1)
X(7), Xorg(1)
.SH AUTHOR
Various contributors.

View file

@ -21,7 +21,7 @@ SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c \
dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c \
icon_surface.c primary_selection.c renderer.c \
picture_renderer.c explicit_synchronization.c transform.c \
wp_viewporter.c decoration.c
wp_viewporter.c decoration.c text_input.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 \
@ -30,7 +30,7 @@ OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o \
dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o \
icon_surface.o primary_selection.o renderer.o \
picture_renderer.o explicit_synchronization.o transform.o \
wp_viewporter.o decoration.o
wp_viewporter.o decoration.o text_input.o
GENHEADERS = transfer_atoms.h
@ -111,6 +111,7 @@ ScannerTarget(primary-selection-unstable-v1)
ScannerTarget(linux-explicit-synchronization-unstable-v1)
ScannerTarget(viewporter)
ScannerTarget(xdg-decoration-unstable-v1)
ScannerTarget(text-input-unstable-v3)
/* Make OBJS depend on scanner headers, and depend on both them and SRCS. */
$(OBJS): $(GENHEADERS)

1
README
View file

@ -66,6 +66,7 @@ complete degree:
'zwp_primary_selection_device_manager_v1', version: 1
'wp_viewporter', version: 1
'zxdg_decoration_manager_v1', version: 1
'zwp_text_input_manager_v3', version: 1
When built with EGL, the following Wayland protocol is also supported:

View file

@ -31,7 +31,7 @@ XLMalloc (size_t size)
ptr = malloc (size);
if (!ptr)
if (!ptr && size)
{
fprintf (stderr, "Allocation of %zu bytes failed\n",
size);
@ -54,7 +54,7 @@ XLCalloc (size_t nmemb, size_t size)
ptr = calloc (nmemb, size);
if (!ptr)
if (!ptr && nmemb && size)
{
fprintf (stderr, "Allocation of %zu * %zu failed\n",
nmemb, size);
@ -96,11 +96,13 @@ XLRealloc (void *ptr, size_t size)
ptr = realloc (ptr, size);
if (!ptr)
if (size && !ptr)
{
fprintf (stderr, "Reallocation of %zu bytes failed\n", size);
abort ();
}
/* Allow realloc to return NULL if size is also NULL. */
return ptr;
}

View file

@ -131,6 +131,8 @@ Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE, _NET_WM_SYNC_REQUEST_COUNTER,
_NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND;
XrmQuark resource_quark, app_quark, QString;
/* Hash table containing atoms. */
static AtomTable atom_table;
@ -284,4 +286,9 @@ XLInitAtoms (void)
/* This is automatically generated. */
DirectTransferAtomInit (atoms, 61);
/* Now, initialize quarks. */
resource_quark = XrmPermStringToQuark (compositor.resource_name);
app_quark = XrmPermStringToQuark (compositor.app_name);
QString = XrmPermStringToQuark ("String");
}

View file

@ -26,6 +26,7 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#include <X11/Xlib-xcb.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xrender.h>
@ -80,6 +81,9 @@ struct _Compositor
/* Whether the server time is monotonic. */
Bool server_time_monotonic;
/* The resource and app names. */
const char *resource_name, *app_name;
};
/* Forward declarations from seat.c. */
@ -920,6 +924,7 @@ struct _RoleFuncs
void (*parent_rescale) (Surface *, Role *);
void (*note_desync_child) (Surface *, Role *);
void (*note_child_synced) (Surface *, Role *);
void (*select_extra_events) (Surface *, Role *, unsigned long);
};
struct _Role
@ -966,6 +971,7 @@ extern void XLSurfacePostResize (Surface *, int, int, int, int);
extern void XLSurfaceMoveBy (Surface *, int, int);
extern Window XLWindowFromSurface (Surface *);
extern void XLUpdateSurfaceOutputs (Surface *, int, int, int, int);
extern void XLSurfaceSelectExtraEvents (Surface *, unsigned long);
extern void SurfaceToWindow (Surface *, double, double, double *, double *);
extern void ScaleToWindow (Surface *, double, double, double *, double *);
@ -1008,6 +1014,8 @@ extern Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE,
XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE,
_NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND;
extern XrmQuark resource_quark, app_quark, QString;
/* This is automatically generated by mime4.awk. */
extern Atom DirectTransferAtoms;
@ -1247,6 +1255,22 @@ extern void XLDataDeviceSendMotion (Seat *, Surface *, double, double, Time);
extern void XLDataDeviceSendLeave (Seat *, Surface *, DataSource *);
extern void XLDataDeviceSendDrop (Seat *, Surface *);
/* Defined in text_input.h. */
typedef struct _TextInputFuncs TextInputFuncs;
struct _TextInputFuncs
{
void (*focus_in) (Seat *, Surface *);
void (*focus_out) (Seat *);
/* The last argument is actually an XIDeviceEvent *. */
Bool (*filter_input) (Seat *, Surface *, void *);
};
extern void XLTextInputDispatchCoreEvent (Surface *, XEvent *);
extern void XLInitTextInput (void);
/* Defined in seat.c. */
extern int xi2_opcode;
@ -1274,6 +1298,7 @@ extern DataDevice *XLSeatGetDataDevice (Seat *);
extern void XLSeatSetDataDevice (Seat *, DataDevice *);
extern Bool XLSeatIsInert (Seat *);
extern Bool XLSeatIsClientFocused (Seat *, struct wl_client *);
extern Surface *XLSeatGetFocus (Seat *);
extern void XLSeatShowWindowMenu (Seat *, Surface *, int, int);
extern Time XLSeatGetLastUserTime (Seat *);
extern void XLSeatBeginDrag (Seat *, DataSource *, Surface *,
@ -1284,6 +1309,11 @@ extern void *XLSeatAddModifierCallback (Seat *, void (*) (unsigned int, void *),
extern void XLSeatRemoveModifierCallback (void *);
extern unsigned int XLSeatGetEffectiveModifiers (Seat *);
extern Bool XLSeatResizeInProgress (Seat *);
extern void XLSeatSetTextInputFuncs (TextInputFuncs *);
extern int XLSeatGetKeyboardDevice (Seat *);
extern Seat *XLSeatGetInputMethodSeat (void);
extern void XLSeatDispatchCoreKeyEvent (Seat *, Surface *, XEvent *,
KeySym);
extern Cursor InitDefaultCursor (void);

6
run.c
View file

@ -130,6 +130,12 @@ HandleOneXEvent (XEvent *event)
{
XLHandleOneXEventForDnd (event);
/* Filter all non-GenericEvents through the input method
infrastructure. */
if (event->type != GenericEvent
&& XFilterEvent (event, event->xany.window))
return;
if (XLHandleXEventForXdgSurfaces (event))
return;

181
seat.c
View file

@ -75,12 +75,18 @@ static XLAssocTable *devices;
XLList *live_seats;
/* This is a mask of all keyboard state. */
#define AllKeyMask \
(ShiftMask | LockMask | ControlMask | Mod1Mask | Mod2Mask | Mod3Mask \
| Mod4Mask)
enum
{
IsInert = 1,
IsWindowMenuShown = (1 << 2),
IsDragging = (1 << 3),
IsDropped = (1 << 4),
IsTextInputSeat = (1 << 5),
};
enum
@ -533,6 +539,9 @@ struct _DeviceInfo
#define MaskLen(event) \
(((event) >> 3) + 1)
/* Text input functions. */
static TextInputFuncs *input_funcs;
#define CursorFromRole(role) ((SeatCursor *) (role))
/* Subcompositor targets used inside cursor subframes. */
@ -1786,6 +1795,10 @@ MakeSeatForDevicePair (int master_keyboard, int master_pointer,
XLMakeAssoc (seats, master_keyboard, seat);
XLMakeAssoc (seats, master_pointer, seat);
if (!live_seats)
/* This is the first seat; make it the input seat. */
seat->flags |= IsTextInputSeat;
live_seats = XLListPrepend (live_seats, seat);
/* Now update the seat state from the X server. */
@ -2076,7 +2089,7 @@ RunDestroyListeners (Seat *seat)
static void
NoticeDeviceDisabled (int deviceid)
{
Seat *seat;
Seat *seat, *new;
DeviceInfo *info;
/* First, see if there is any deviceinfo related to the disabled
@ -2124,6 +2137,18 @@ NoticeDeviceDisabled (int deviceid)
wl_global_destroy (seat->global);
/* If it was the input seat, then find a new seat to take its
place. */
if (seat->flags & IsTextInputSeat
&& live_seats)
{
new = live_seats->data;
/* This results in nondeterministic selection of input
seats, and as such can be confusing to the user. */
new->flags |= IsTextInputSeat;
}
/* And release the seat. */
ReleaseSeat (seat);
@ -2624,6 +2649,12 @@ ClearFocusSurface (void *data)
seat->focus_surface = NULL;
seat->focus_destroy_callback = NULL;
XLPrimarySelectionHandleFocusChange (seat);
/* Tell any input method about the focus change. */
if (input_funcs)
input_funcs->focus_out (seat);
}
static void
@ -2697,6 +2728,29 @@ SendKeyboardModifiers (Seat *seat, Surface *focus)
UpdateSingleModifiers (seat, keyboard, serial);
}
static void
HackKeyboardModifiers (Seat *seat, Surface *focus, int effective,
int group)
{
Keyboard *keyboard;
uint32_t serial;
SeatClientInfo *info;
serial = wl_display_next_serial (compositor.wl_display);
info = ClientInfoForResource (seat, focus->resource);
if (!info)
return;
keyboard = info->keyboards.next;
for (; keyboard != &info->keyboards; keyboard = keyboard->next)
/* It is wrong to send the new modifiers in seat->based, but I
don't know anything better. */
wl_keyboard_send_modifiers (keyboard->resource, serial,
effective, 0, 0, group);
}
static void
SendUpdatedModifiers (Seat *seat)
{
@ -2758,6 +2812,10 @@ SetFocusSurface (Seat *seat, Surface *focus)
XLSurfaceCancelRunOnFree (seat->focus_destroy_callback);
seat->focus_destroy_callback = NULL;
seat->focus_surface = NULL;
if (input_funcs)
/* Tell any input method about the change. */
input_funcs->focus_out (seat);
}
if (!focus)
@ -2768,6 +2826,10 @@ SetFocusSurface (Seat *seat, Surface *focus)
return;
}
if (input_funcs)
/* Tell any input method about the change. */
input_funcs->focus_in (seat, focus);
seat->focus_surface = focus;
seat->focus_destroy_callback
= XLSurfaceRunOnFree (focus, ClearFocusSurface, seat);
@ -3971,6 +4033,17 @@ DispatchKey (XIDeviceEvent *xev)
if (seat->focus_surface)
{
if (input_funcs
&& seat->flags & IsTextInputSeat
&& input_funcs->filter_input (seat, seat->focus_surface,
xev))
/* The input method decided to filter the key. */
return;
/* Ignore repeated keys. */
if (xev->flags & XIKeyRepeat)
return;
if (xev->evtype == XI_KeyPress)
SendKeyboardKey (seat, seat->focus_surface,
xev->time, WaylandKeycode (xev->detail),
@ -4799,6 +4872,12 @@ XLSeatIsClientFocused (Seat *seat, struct wl_client *client)
return client == surface_client;
}
Surface *
XLSeatGetFocus (Seat *seat)
{
return seat->focus_surface;
}
void
XLSeatShowWindowMenu (Seat *seat, Surface *surface, int root_x,
int root_y)
@ -5272,3 +5351,103 @@ XLSeatResizeInProgress (Seat *seat)
{
return seat->resize_in_progress;
}
void
XLSeatSetTextInputFuncs (TextInputFuncs *funcs)
{
input_funcs = funcs;
}
int
XLSeatGetKeyboardDevice (Seat *seat)
{
return seat->master_keyboard;
}
Seat *
XLSeatGetInputMethodSeat (void)
{
XLList *list;
Seat *seat;
for (list = live_seats; list; list = list->next)
{
seat = list->data;
if (seat->flags & IsTextInputSeat)
return seat;
}
return NULL;
}
void
XLSeatDispatchCoreKeyEvent (Seat *seat, Surface *surface, XEvent *event,
KeySym keysym)
{
unsigned int effective;
unsigned int state, group;
unsigned int mods_return;
KeyCode keycode;
KeySym sym_return;
/* Dispatch a core event generated by an input method to SEAT. If
SURFACE is no longer the focus surface, refrain from doing
anything. If a keycode can be found for KEYSYM, use that
keycode. */
if (surface != seat->focus_surface)
return;
/* Get the group and state of the key event. */
group = event->xkey.state >> 13;
state = event->xkey.state & AllKeyMask;
/* Get the effective state of the seat. */
effective = seat->base | seat->latched | seat->locked;
/* Determine what keycode to use. If a keysym was provided, try to
find a corresponding keycode. */
if (keysym)
{
/* If looking up the event keycode also results in the keysym,
then just use the keycode specified in the event. */
if (XkbLookupKeySym (compositor.display, event->xkey.keycode,
event->xkey.state, &mods_return, &sym_return)
&& keysym == sym_return)
{
keycode = event->xkey.keycode;
}
else
keycode = XKeysymToKeycode (compositor.display, keysym);
/* But if no corresponding keycode could be found, use the
keycode provided in the event. */
if (!keycode)
keycode = event->xkey.keycode;
}
else
keycode = event->xkey.keycode;
if (group != seat->effective_group || state != effective)
/* The modifiers in the provided core event are different from
what the focus surface was previously sent. Send a new
modifier event with the effective state provided in the give
core event. */
HackKeyboardModifiers (seat, surface, effective, group);
/* Then send the event. */
if (event->xkey.type == KeyPress)
SendKeyboardKey (seat, seat->focus_surface, event->xkey.time,
WaylandKeycode (keycode),
WL_KEYBOARD_KEY_STATE_PRESSED);
else
SendKeyboardKey (seat, seat->focus_surface, event->xkey.time,
WaylandKeycode (keycode),
WL_KEYBOARD_KEY_STATE_RELEASED);
/* Restore the modifiers. */
if (group != seat->effective_group || state != effective)
SendKeyboardModifiers (seat, surface);
}

View file

@ -1734,6 +1734,21 @@ XLSurfaceMoveBy (Surface *surface, int west, int north)
west, north);
}
void
XLSurfaceSelectExtraEvents (Surface *surface, unsigned long event_mask)
{
if (!surface->role
|| !surface->role->funcs.select_extra_events)
return;
/* Note that this need only be implemented for surfaces that can get
the input focus. */
surface->role->funcs.select_extra_events (surface, surface->role,
event_mask);
}
/* The following functions convert from window to surface
coordinates and vice versa:

View file

@ -29,6 +29,10 @@ along with 12to11. If not, see <https://www.gnu.org/licenses/>. */
#define XdgRoleFromRole(role) ((XdgRole *) (role))
/* This is the default core event mask used by our windows. */
#define DefaultEventMask \
(ExposureMask | StructureNotifyMask | PropertyChangeMask)
enum
{
StatePendingFrameCallback = 1,
@ -472,6 +476,22 @@ XLHandleXEventForXdgSurfaces (XEvent *event)
return False;
}
if (event->type == KeyPress || event->type == KeyRelease)
{
/* These events are actually sent by the input method library
upon receiving XIM_COMMIT messages. */
role = XLLookUpAssoc (surfaces, event->xkey.window);
if (role && role->role.surface)
{
XLTextInputDispatchCoreEvent (role->role.surface, event);
return True;
}
return False;
}
window = XLGetGEWindowForSeats (event);
if (window != None)
@ -685,7 +705,8 @@ Commit (Surface *surface, Role *role)
/* This flag means no commit has happened after an
ack_configure. */
if (!(xdg_role->state & StateWaitingForAckConfigure))
if (!(xdg_role->state & StateWaitingForAckConfigure)
&& xdg_role->state & StateWaitingForAckCommit)
{
#ifdef DEBUG_GEOMETRY_CALCULATION
fprintf (stderr, "Client aknowledged commit\n");
@ -1131,15 +1152,13 @@ NoteBounds (void *data, int min_x, int min_y,
bounds_width = max_x - min_x + 1;
bounds_height = max_y - min_y + 1;
#ifdef DEBUG_GEOMETRY_CALCULATION
fprintf (stderr, "Noticed bounds: %d %d\n", bounds_width, bounds_height);
#endif
if (role->bounds_width != bounds_width
|| role->bounds_height != bounds_height)
{
#ifdef DEBUG_GEOMETRY_CALCULATION
fprintf (stderr, "Resizing to: %d %d\n", bounds_width, bounds_height);
fprintf (stderr, "Resizing to: %d %d (from: %d %d)\n",
bounds_width, bounds_height, role->bounds_width,
role->bounds_height);
#endif
if (role->impl->funcs.note_window_pre_resize)
@ -1357,6 +1376,19 @@ HandleFreeze (void *data)
role->state |= StateMaybeConfigure;
}
static void
SelectExtraEvents (Surface *surface, Role *role,
unsigned long event_mask)
{
XdgRole *xdg_role;
xdg_role = XdgRoleFromRole (role);
/* Select extra events for the input method. */
XSelectInput (compositor.display, xdg_role->window,
DefaultEventMask | event_mask);
}
void
XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
uint32_t id, struct wl_resource *surface_resource)
@ -1431,11 +1463,11 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource,
role->role.funcs.rescale = Rescale;
role->role.funcs.note_desync_child = NoteDesyncChild;
role->role.funcs.note_child_synced = NoteChildSynced;
role->role.funcs.select_extra_events = SelectExtraEvents;
attrs.colormap = compositor.colormap;
attrs.border_pixel = border_pixel;
attrs.event_mask = (ExposureMask | StructureNotifyMask
| PropertyChangeMask);
attrs.event_mask = DefaultEventMask;
attrs.cursor = InitDefaultCursor ();
flags = (CWColormap | CWBorderPixel | CWEventMask
| CWCursor);
@ -1647,6 +1679,11 @@ XLXdgRoleSetBoundsSize (Role *role, int bounds_width, int bounds_height)
xdg_role->bounds_width = bounds_width;
xdg_role->bounds_height = bounds_height;
#ifdef DEBUG_GEOMETRY_CALCULATION
fprintf (stderr, "Set new bounds size: %d %d\n", bounds_width,
bounds_height);
#endif
/* Now, a temporary bounds_width and bounds_height has been
recorded. This means that if a configure event has not yet been
delivered, then any subsequent SubcompositorUpdate will cause
@ -1857,7 +1894,7 @@ XLInitXdgSurfaces (void)
XColor alloc;
int shape_minor, shape_major, shape_error;
surfaces = XLCreateAssocTable (2048);
surfaces = XLCreateAssocTable (1024);
alloc.red = 0;
alloc.green = 65535;

View file

@ -40,15 +40,17 @@ typedef enum _DecorationMode DecorationMode;
enum
{
StateIsMapped = 1,
StateMissingState = (1 << 1),
StatePendingMaxSize = (1 << 2),
StatePendingMinSize = (1 << 3),
StatePendingAckMovement = (1 << 4),
StatePendingResize = (1 << 5),
StatePendingConfigureSize = (1 << 6),
StatePendingConfigureStates = (1 << 7),
StateDecorationModeDirty = (1 << 8),
StateIsMapped = 1,
StateMissingState = (1 << 1),
StatePendingMaxSize = (1 << 2),
StatePendingMinSize = (1 << 3),
StatePendingAckMovement = (1 << 4),
StatePendingResize = (1 << 5),
StatePendingConfigureSize = (1 << 6),
StatePendingConfigureStates = (1 << 7),
StateDecorationModeDirty = (1 << 8),
StateEverMapped = (1 << 9),
StateNeedDecorationConfigure = (1 << 10),
};
enum
@ -370,6 +372,27 @@ AddState (XdgToplevel *toplevel, uint32_t state)
*data = state;
}
static void
SendDecorationConfigure1 (XdgToplevel *toplevel)
{
#define ServerSide ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
#define ClientSide ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
if (toplevel->decor == DecorationModeClient)
zxdg_toplevel_decoration_v1_send_configure (toplevel->decoration->resource,
ClientSide);
else
zxdg_toplevel_decoration_v1_send_configure (toplevel->decoration->resource,
ServerSide);
#undef ServerSide
#undef ClientSide
/* This means that the decoration should be reapplied upon the next
commit. */
toplevel->state |= StateDecorationModeDirty;
}
static void
SendConfigure (XdgToplevel *toplevel, unsigned int width,
unsigned int height)
@ -380,6 +403,15 @@ SendConfigure (XdgToplevel *toplevel, unsigned int width,
xdg_toplevel_send_configure (toplevel->resource, width, height,
&toplevel->states);
/* If a toplevel decoration resource is created and
SetMode/UnsetMode is called before the initial toplevel commit,
then the toplevel decoration mode must be sent here instead. */
if (toplevel->state & StateNeedDecorationConfigure
&& toplevel->decoration)
SendDecorationConfigure1 (toplevel);
toplevel->state &= ~StateNeedDecorationConfigure;
XLXdgRoleSendConfigure (toplevel->role, serial);
toplevel->conf_reply = True;
@ -396,27 +428,11 @@ SendDecorationConfigure (XdgToplevel *toplevel)
serial = wl_display_next_serial (compositor.wl_display);
#define ServerSide ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
#define ClientSide ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE
if (toplevel->decor == DecorationModeClient)
zxdg_toplevel_decoration_v1_send_configure (toplevel->decoration->resource,
ClientSide);
else
zxdg_toplevel_decoration_v1_send_configure (toplevel->decoration->resource,
ServerSide);
#undef ServerSide
#undef ClientSide
SendDecorationConfigure1 (toplevel);
XLXdgRoleSendConfigure (toplevel->role, serial);
toplevel->conf_reply = True;
toplevel->conf_serial = serial;
/* This means that the decoration should be reapplied upon the next
commit. */
toplevel->state |= StateDecorationModeDirty;
}
/* Forward declaration. */
@ -1081,7 +1097,7 @@ Map (XdgToplevel *toplevel)
at this point. */
SubcompositorGarbage (XLSubcompositorFromXdgRole (toplevel->role));
toplevel->state |= StateIsMapped | StateMissingState;
toplevel->state |= StateIsMapped | StateMissingState | StateEverMapped;
/* Update the width and height from the xdg_surface bounds. */
toplevel->width = XLXdgRoleGetWidth (toplevel->role);
@ -1329,6 +1345,10 @@ HandleConfigureEvent (XdgToplevel *toplevel, XEvent *event)
event->xconfigure.height))
WriteStates (toplevel);
/* Set toplevel->width and toplevel->height correctly. */
toplevel->width = event->xconfigure.width;
toplevel->height = event->xconfigure.height;
/* Also set the bounds width and height to avoid resizing the
window. */
XLXdgRoleSetBoundsSize (toplevel->role,
@ -1345,9 +1365,8 @@ HandleConfigureEvent (XdgToplevel *toplevel, XEvent *event)
SendConfigure (toplevel, width, height);
}
/* Set toplevel->width and toplevel->height correctly. */
toplevel->width = event->xconfigure.width;
toplevel->height = event->xconfigure.height;
/* Now set toplevel->configure_width and
toplevel->configure_height. */
toplevel->configure_width = toplevel->width;
toplevel->configure_height = toplevel->height;
@ -2248,7 +2267,12 @@ SetMode (struct wl_client *client, struct wl_resource *resource,
return;
}
SendDecorationConfigure (decoration->toplevel);
/* According to #wayland the configure event shouldn't be sent for
partially initialized surfaces. */
if (decoration->toplevel->state & StateEverMapped)
SendDecorationConfigure (decoration->toplevel);
else
decoration->toplevel->state |= StateNeedDecorationConfigure;
}
static void
@ -2263,7 +2287,13 @@ UnsetMode (struct wl_client *client, struct wl_resource *resource)
/* Default to using window manager decorations. */
decoration->toplevel->decor = DecorationModeWindowManager;
SendDecorationConfigure (decoration->toplevel);
/* According to #wayland the configure event shouldn't be sent for
partially initialized surfaces. */
if (decoration->toplevel->state & StateEverMapped)
SendDecorationConfigure (decoration->toplevel);
else
decoration->toplevel->state |= StateNeedDecorationConfigure;
}
static struct zxdg_toplevel_decoration_v1_interface decoration_impl =