Recently, I've found that in order to obey _NET_WM_SYNC_REQUEST events use presentation at the same time in a reasonable fashion, one must be able to determine whether or not the compositing manager has actually redirected the window. Polling with an error trap and XCompositeRedirectWindow is horribly inefficient, and there is no other way for a client to be notified when redirection has changed.
These additions to the Composite extension constitute a minor revision of that extension, and provide a mechanism for clients to listen to redirection changes on a given window. The patches consist of additions to xorgproto defining the new version of the extension, an implementation in the X.Org server, and stubs in libXcomposite. Since I've totally lost track of how X server development works today, I've copied in the maintainer of libXcomposite, as this list does not seem to get much attention. I hope that isn't a problem. If these changes look good, I'd like for them to be installed. If they're not, please tell me why, and I will try my best to fix them. Thanks in advance.
>From 8c72d0297c1993cb2f8f121cd5bc2f5d7702bfd9 Mon Sep 17 00:00:00 2001 From: Po Lu <luang...@yahoo.com> Date: Wed, 19 Oct 2022 15:43:38 +0800 Subject: [PATCH xorgproto] Add composite redirection notification events Applications may want to monitor whether or not their windows are redirected, in order to decide whether or not to wait for protocols such as _NET_WM_FRAME_DRAWN when the compositor can choose to unredirect them. This update to the Composite protocol allows applications to select for events that are emitted upon changes to the redirection state of arbitrary windows, and to query their state. --- compositeproto.pc.in | 2 +- compositeproto.txt | 145 ++++++++++++++++++++++++ configure.ac | 2 +- include/X11/extensions/composite.h | 25 +++- include/X11/extensions/compositeproto.h | 77 +++++++++++++ meson.build | 2 +- 6 files changed, 247 insertions(+), 6 deletions(-) diff --git a/compositeproto.pc.in b/compositeproto.pc.in index 91f2422..f053a3a 100644 --- a/compositeproto.pc.in +++ b/compositeproto.pc.in @@ -3,5 +3,5 @@ includedir=@includedir@ Name: CompositeExt Description: Composite extension headers -Version: 0.4.2 +Version: 0.5.0 Cflags: -I${includedir} diff --git a/compositeproto.txt b/compositeproto.txt index c1a7878..febdde3 100644 --- a/compositeproto.txt +++ b/compositeproto.txt @@ -303,3 +303,148 @@ operations other than QueryVersion. Composite Overlay Window on the screen specified by the argument 'window'. A screen's Composite Overlay Window is unmapped when there are no longer any clients using it. + +12. Composite Input (0.5) + +Applications may wish to monitor whether or not their windows are redirected. +The CompositeSelectInput request paried with the RedirectNotify event allows +monitoring whether or not a window is redirected, and why it was redirected or +unredirected. + +12.1 Types + + COMPOSITEEVENT { RedirectNotify, + RedirectStateNotify, } + REDIRECTREASON { WindowRedirected, + ParentRedirected, + ChildCreated, + ChildReparented, } + +12.2 Events + +RedirectNotify + + reason: REDIRECTREASON + update: SETofUPDATETYPE or Unredirected + window: Window + timestamp: Timestamp + + This event is emitted when a client has selected for RedirectNotify + events on a window through the CompositeSelectInput request, and the + storage for its contents may have changed. + + If 'type' is Unredirected, then the window contents are no longer + directed to off-screen storage. + + Otherwise, 'type' is a mask containing the update modes given to all + RedirectWindow or RedirectSubwindows requests that are currently causing + the window contents to be redirected. 'reason' specifies why the event + was sent, and has the following meanings: + + WindowRedirected + + The window may have been redirected or unredirected as + the result of being specified as the 'window' argument + to a RedirectWindow, UnredirectWindow, + UnredirectSubwindows, or RedirectSubwindows request, or + its equivalent, such as client destruction. + + ParentRedirected + + The window may have been redirected or unredirected as + the result of being a child of the 'window' argument to + a RedirectSubwindows or UnredirectSubwindows request at + the time the request was made, or its equivalent, such + as client destruction. + + ChildCreated + + The window was redirected as the result of being created + as a child of the 'window' argument to a + RedirectSubwindows request, after that request was made. + + ChildReparented + + The window was redirected or unredirected as a result of + being reparented to or away from the 'window' argument + of a RedirectSubwindows request, either by a + ReparentWindow request or save-set processing. + + No event is emitted if the window was unredirected as a result of being + destroyed. If 'reason' is ChildCreated or ChildReparented, this event + is emitted after any CreateNotify or ReparentNotify events generated as + a result of the window creation or reparenting that caused the window to + be redirected. + + If a window is reparented from one window that has been passed to a + CompositeRedirectSubwindows request to another, then two events will be + generated: one event will be generated as if the window may have been + unredirected as a result of the reparent, and another as if the window + may have been redirected as a result of the reparent. Both events will + be emitted after any ReparentNotify event generated as a result of the + reparenting. + + 'timestamp' is the server time at which the event was generated. + +RedirectStateNotify + + update: SETofUPDATETYPE or Unredirected + window: Window + timestamp: Timestamp + + This event is emitted in response to a CompositeGetRedirectedEvent + request. 'window' is the window argument to the request, 'timestamp' is + the current server time, and 'update' is a mask of all update modes that + have been specified in prior RedirectWindow and RedirectSubwindows + request that are currently causing the 'window' to be redirected, or + Unredirected if the window is not currently redirected. + +12.3 Requests + + CompositeSelectInput + + window: Window + events: SETofCOMPOSITEEVENT + + errors: Window, Value, Match + + Select for events to be delivered to the window when the window is + redirected or un-redirected. + + If the given window is not valid, a Window error is generated. If + 'events' contains events that are not listed in the definition of + COMPOSITEEVENT, a Value error is generated. If 'window' is the root + window of a screen, a Match error is generated. + + CompositeQueryRedirected + + id: Window + + -> + + redirected: SETofUPDATETYPE or Unredirected + + errors: Window, Match + + Obtain whether or not the given window is redirected. The reply is a + mask of all update modes that have been specified in prior + RedirectWindow and RedirectSubwindows request that are currently causing + the 'window' to be redirected, or Unredirected if the window is not + currently redirected. + + If the given window is not valid, a Window error is generated. If it is + the root window of a screen, a Match error is generated. + + CompositeGetRedirectedEvent + + id: Window + + errors: Window, Match + + Request the delivery of a RedirectStateNotify event to the current + client for the given window. The client need not select for the + generated event with the CompositeSelectInput request, but if it does, + it will receive events requested by other clients as well. + + If the given window is not valid, a Window error is generated. If it is + the root window of a screen, a Match error is generated. diff --git a/configure.ac b/configure.ac index 87334ad..aba9ba9 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ dnl Process this file with autoconf to create configure. AC_PREREQ([2.60]) # keep version in sync with meson.build -AC_INIT([xorgproto], [2022.2], +AC_INIT([xorgproto], [2022.10], [https://gitlab.freedesktop.org/xorg/proto/xorgproto/issues]) AM_INIT_AUTOMAKE([foreign dist-xz]) diff --git a/include/X11/extensions/composite.h b/include/X11/extensions/composite.h index e460118..39121a3 100644 --- a/include/X11/extensions/composite.h +++ b/include/X11/extensions/composite.h @@ -49,11 +49,17 @@ #define COMPOSITE_NAME "Composite" #define COMPOSITE_MAJOR 0 -#define COMPOSITE_MINOR 4 +#define COMPOSITE_MINOR 5 #define CompositeRedirectAutomatic 0 #define CompositeRedirectManual 1 +#define CompositeRedirectAutomaticMask 1 +#define CompositeRedirectManualMask 2 +#define CompositeUnredirected 0 + +#define CompositeUpdateTypeToMask(update_type) (1 << (update_type)) + #define X_CompositeQueryVersion 0 #define X_CompositeRedirectWindow 1 #define X_CompositeRedirectSubwindows 2 @@ -63,9 +69,22 @@ #define X_CompositeNameWindowPixmap 6 #define X_CompositeGetOverlayWindow 7 #define X_CompositeReleaseOverlayWindow 8 +#define X_CompositeSelectInput 9 +#define X_CompositeQueryRedirected 10 +#define X_CompositeGetRedirectedEvent 11 + +#define CompositeNumberRequests (X_CompositeGetRedirectedEvent + 1) + +#define CompositeRedirectNotify 0 +#define CompositeRedirectStateNotify 1 +#define CompositeRedirectNotifyMask 1 +#define CompositeRedirectStateNotifyMask 2 -#define CompositeNumberRequests (X_CompositeReleaseOverlayWindow + 1) +#define CompositeNumberEvents (CompositeRedirectStateNotify + 1) -#define CompositeNumberEvents 0 +#define CompositeWindowRedirected 0 +#define CompositeParentRedirected 1 +#define CompositeChildCreated 2 +#define CompositeChildReparented 3 #endif /* _COMPOSITE_H_ */ diff --git a/include/X11/extensions/compositeproto.h b/include/X11/extensions/compositeproto.h index b63f9cc..3435ead 100644 --- a/include/X11/extensions/compositeproto.h +++ b/include/X11/extensions/compositeproto.h @@ -51,6 +51,7 @@ #define Window CARD32 #define Region CARD32 #define Pixmap CARD32 +#define Time CARD32 /* * requests and replies @@ -185,8 +186,84 @@ typedef struct { #define sz_xCompositeReleaseOverlayWindowReq sizeof(xCompositeReleaseOverlayWindowReq) +/* Version 0.5 additions. */ + +typedef struct { + CARD8 type; + BYTE pad; + CARD16 sequenceNumber; + CARD32 reason; + CARD32 update; + Window window; + Time timestamp; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; +} xCompositeRedirectNotifyEvent; + +#define sz_xCompositeRedirectNotifyEvent sizeof(xCompositeRedirectNotifyEvent) + +typedef struct { + CARD8 type; + BYTE pad; + CARD16 sequenceNumber; + Window window; + Time timestamp; + CARD32 update; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; +} xCompositeRedirectStateNotifyEvent; + +#define sz_xCompositeRedirectStateNotifyEvent sizeof(xCompositeRedirectStateNotifyEvent) + +typedef struct { + CARD8 reqType; + CARD8 compositeReqType; + CARD16 length; + Window window; + CARD32 events; +} xCompositeSelectInputReq; + +#define sz_xCompositeSelectInputReq sizeof(xCompositeSelectInputReq) + +typedef struct { + CARD8 reqType; + CARD8 compositeReqType; + CARD16 length; + Window id; +} xCompositeQueryRedirectedReq; + +#define sz_xCompositeQueryRedirectedReq sizeof(xCompositeQueryRedirectedReq) + +typedef struct { + BYTE type; /* X_Reply */ + BYTE pad; + CARD16 sequenceNumber; + CARD32 length; + CARD32 update; + CARD32 pad1; + CARD32 pad2; + CARD32 pad3; + CARD32 pad4; + CARD32 pad5; +} xCompositeQueryRedirectedReply; + +#define sz_xCompsiteQueryRedirectedReply sizeof(xCompositeQueryRedirectedReply) + +typedef struct { + CARD8 reqType; + CARD8 compositeReqType; + CARD16 length; + Window id; +} xCompositeGetRedirectedEventReq; + +#define sz_xCompositeGetRedirectedEventReq sizeof(xCompositeGetRedirectedEventReq) + #undef Window #undef Region #undef Pixmap +#undef Time #endif /* _COMPOSITEPROTO_H_ */ diff --git a/meson.build b/meson.build index 6bd7110..09dbeda 100644 --- a/meson.build +++ b/meson.build @@ -19,7 +19,7 @@ # SOFTWARE. # keep version in sync with configure.ac -project('xorgproto', 'c', license : 'MIT', version : '2022.2') +project('xorgproto', 'c', license : 'MIT', version : '2022.10') cc = meson.get_compiler('c') pcs = [ -- 2.37.3
>From 5c2c8ada35ed843d527f492d1bba64f3af1c0e0d Mon Sep 17 00:00:00 2001 From: Po Lu <luang...@yahoo.com> Date: Wed, 19 Oct 2022 15:46:05 +0800 Subject: [PATCH libXcomposite] Implement wrappers for version 0.5 of the Composite extension --- configure.ac | 2 +- include/X11/extensions/Xcomposite.h | 32 ++++- man/Makefile.am | 5 +- man/XCompositeGetRedirectedEvent.man | 1 + man/XCompositeQueryRedirected.man | 1 + man/XCompositeSelectInput.man | 1 + man/Xcomposite.xml | 29 +++++ src/Xcomposite.c | 175 +++++++++++++++++++++++++++ 8 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 man/XCompositeGetRedirectedEvent.man create mode 100644 man/XCompositeQueryRedirected.man create mode 100644 man/XCompositeSelectInput.man diff --git a/configure.ac b/configure.ac index d62be07..99f3e40 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ AC_PREREQ([2.60]) # that 'revision' number appears in Xcomposite.h and has to be manually # synchronized. # -AC_INIT(libXcomposite, [0.4.5], +AC_INIT(libXcomposite, [0.5.0], [https://gitlab.freedesktop.org/xorg/lib/libXcomposite/issues], [libXcomposite]) AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_HEADERS([config.h]) diff --git a/include/X11/extensions/Xcomposite.h b/include/X11/extensions/Xcomposite.h index 9e4fcb1..53447fb 100644 --- a/include/X11/extensions/Xcomposite.h +++ b/include/X11/extensions/Xcomposite.h @@ -55,9 +55,30 @@ */ #define XCOMPOSITE_MAJOR COMPOSITE_MAJOR #define XCOMPOSITE_MINOR COMPOSITE_MINOR -#define XCOMPOSITE_REVISION 2 +#define XCOMPOSITE_REVISION 0 #define XCOMPOSITE_VERSION ((XCOMPOSITE_MAJOR * 10000) + (XCOMPOSITE_MINOR * 100) + (XCOMPOSITE_REVISION)) +typedef struct { + int type; + unsigned long serial; + Bool send_event; + Display *display; + Window window; + Time timestamp; + int reason; + int update; +} XCompositeRedirectNotifyEvent; + +typedef struct { + int type; + unsigned long serial; + Bool send_event; + Display *display; + Window window; + Time timestamp; + int update; +} XCompositeRedirectStateNotifyEvent; + _XFUNCPROTOBEGIN Bool XCompositeQueryExtension (Display *dpy, @@ -94,6 +115,15 @@ XCompositeGetOverlayWindow (Display *dpy, Window window); void XCompositeReleaseOverlayWindow (Display *dpy, Window window); +void +XCompositeSelectInput (Display *dpy, Window window, long events); + +Status +XCompositeQueryRedirected (Display *display, Window window, long *); + +void +XCompositeGetRedirectedEvent (Display *display, Window window); + _XFUNCPROTOEND #endif /* _XCOMPOSITE_H_ */ diff --git a/man/Makefile.am b/man/Makefile.am index cbed2eb..942b09d 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -16,7 +16,10 @@ Xcomposite_shadows = \ XCompositeCreateRegionFromBorderClip \ XCompositeNameWindowPixmap \ XCompositeGetOverlayWindow \ - XCompositeReleaseOverlayWindow + XCompositeReleaseOverlayWindow \ + XCompositeSelectInput \ + XCompositeQueryRedirected \ + XCompositeGetRedirectedEvent if INSTALL_MANPAGES libman_DATA = $(libman_PRE:man=@LIB_MAN_SUFFIX@) diff --git a/man/XCompositeGetRedirectedEvent.man b/man/XCompositeGetRedirectedEvent.man new file mode 100644 index 0000000..3d50287 --- /dev/null +++ b/man/XCompositeGetRedirectedEvent.man @@ -0,0 +1 @@ +.so man3/Xcomposite.3 diff --git a/man/XCompositeQueryRedirected.man b/man/XCompositeQueryRedirected.man new file mode 100644 index 0000000..3d50287 --- /dev/null +++ b/man/XCompositeQueryRedirected.man @@ -0,0 +1 @@ +.so man3/Xcomposite.3 diff --git a/man/XCompositeSelectInput.man b/man/XCompositeSelectInput.man new file mode 100644 index 0000000..3d50287 --- /dev/null +++ b/man/XCompositeSelectInput.man @@ -0,0 +1 @@ +.so man3/Xcomposite.3 diff --git a/man/Xcomposite.xml b/man/Xcomposite.xml index 9ba9ec5..cc46a00 100644 --- a/man/Xcomposite.xml +++ b/man/Xcomposite.xml @@ -117,6 +117,23 @@ <paramdef>Display *<parameter>dpy</parameter></paramdef> <paramdef>Window <parameter>window</parameter></paramdef> </funcprototype> + <funcprototype> + <funcdef>void <function>XCompositeSelectInput</function></funcdef> + <paramdef>Display *<parameter>dpy</parameter></paramdef> + <paramdef>Window <parameter>window</parameter></paramdef> + <paramdef>long <parameter>events</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>Status <function>XCompositeQueryRedirected</function></funcdef> + <paramdef>Display *<parameter>dpy</parameter></paramdef> + <paramdef>Window <parameter>window</parameter></paramdef> + <paramdef>long *<parameter>update</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>void <function>XCompositeGetRedirectEvent</function></funcdef> + <paramdef>Display *<parameter>dpy</parameter></paramdef> + <paramdef>Window <parameter>window</parameter></paramdef> + </funcprototype> </funcsynopsis></refsynopsisdiv> <refsect1><title>Description</title> @@ -394,6 +411,18 @@ contents of all descendants. Extension for <function>XCompositeReleaseOverlayWindow</function>. </para></listitem> </varlistentry> + <varlistentry> + <term><function>XCompositeSelectInput</function></term> + <listitem><para> + This request selects for some kinds of events to be delivered to + the window specified in the <parameter>window</parameter> + window when it is redirected or un-redirected. + </para> + <para> + The X server must support at least version 0.5 of the Composite + Extension for <function>XCompositeSelectInput</function>. + </para></listitem> + </varlistentry> </variablelist> </para> </refsect1> diff --git a/src/Xcomposite.c b/src/Xcomposite.c index b107475..48c0220 100644 --- a/src/Xcomposite.c +++ b/src/Xcomposite.c @@ -93,6 +93,105 @@ XCompositeCloseDisplay (Display *dpy, XExtCodes *codes) return XCompositeExtRemoveDisplay (&XCompositeExtensionInfo, dpy); } + +static Bool +XCompositeWireToEvent (Display *dpy, XEvent *event, xEvent *wire) +{ + XCompositeExtDisplayInfo *info; + XCompositeRedirectNotifyEvent *event_out; + xCompositeRedirectNotifyEvent *wire_in; + XCompositeRedirectStateNotifyEvent *event_out_1; + xCompositeRedirectStateNotifyEvent *wire_in_1; + + info = XCompositeFindDisplay (dpy); + XCompositeCheckExtension (dpy, info, False); + + switch ((wire->u.u.type & 0x7F) - info->codes->first_event) + { + case CompositeRedirectNotify: + event_out = (XCompositeRedirectNotifyEvent *) event; + wire_in = (xCompositeRedirectNotifyEvent *) wire; + + event_out->type = wire_in->type & 0x7F; + event_out->serial = _XSetLastRequestRead (dpy, + (xGenericReply *) wire); + event_out->send_event = (wire_in->type & 0x80) != 0; + event_out->display = dpy; + event_out->window = wire_in->window; + event_out->timestamp = wire_in->timestamp; + event_out->reason = wire_in->reason; + event_out->update = wire_in->update; + + return True; + + case CompositeRedirectStateNotify: + event_out_1 = (XCompositeRedirectStateNotifyEvent *) event; + wire_in_1 = (xCompositeRedirectStateNotifyEvent *) wire; + + event_out_1->type = wire_in_1->type & 0x7F; + event_out_1->serial = _XSetLastRequestRead (dpy, + (xGenericReply *) wire); + event_out_1->send_event = (wire_in_1->type & 0x80) != 0; + event_out_1->display = dpy; + event_out_1->window = wire_in_1->window; + event_out_1->timestamp = wire_in_1->timestamp; + event_out_1->update = wire_in_1->update; + + return True; + } + + return False; +} + +static Status +XCompositeEventToWire (Display *dpy, XEvent *event, xEvent *wire) +{ + XCompositeExtDisplayInfo *info; + XCompositeRedirectNotifyEvent *event_in; + xCompositeRedirectNotifyEvent *wire_out; + XCompositeRedirectStateNotifyEvent *event_in_1; + xCompositeRedirectStateNotifyEvent *wire_out_1; + + info = XCompositeFindDisplay (dpy); + XCompositeCheckExtension (dpyinfo, info, 0); + + switch ((wire->u.u.type & 0x7F) - info->codes->first_event) + { + case CompositeRedirectNotify: + event_in = (XCompositeRedirectNotifyEvent *) event; + wire_out = (xCompositeRedirectNotifyEvent *) wire; + + wire_out->type = event_in->type; + + if (event_in->send_event) + wire_out->type |= 0x80; + + wire_out->window = event_in->window; + wire_out->timestamp = event_in->timestamp; + wire_out->reason = event_in->reason; + wire_out->update = event_in->update; + + return 1; + + case CompositeRedirectStateNotify: + event_in_1 = (XCompositeRedirectStateNotifyEvent *) event; + wire_out_1 = (xCompositeRedirectStateNotifyEvent *) wire; + + wire_out_1->type = event_in_1->type; + + if (event_in_1->send_event) + wire_out_1->type |= 0x80; + + wire_out_1->window = event_in_1->window; + wire_out_1->timestamp = event_in_1->timestamp; + wire_out_1->update = event_in_1->update; + + return 1; + } + + return 0; +} + /* * XCompositeExtAddDisplay - add a display to this extension. (Replaces * XextAddDisplay) @@ -103,6 +202,7 @@ XCompositeExtAddDisplay (XCompositeExtInfo *extinfo, const char *ext_name) { XCompositeExtDisplayInfo *info; + int event_number; info = (XCompositeExtDisplayInfo *) Xmalloc (sizeof (XCompositeExtDisplayInfo)); if (!info) return NULL; @@ -119,6 +219,16 @@ XCompositeExtAddDisplay (XCompositeExtInfo *extinfo, xCompositeQueryVersionReq *req; XESetCloseDisplay (dpy, info->codes->extension, XCompositeCloseDisplay); + /* + * Install event conversion functions. + */ + for (event_number = info->codes->first_event; + event_number < info->codes->first_event + CompositeNumberEvents; + event_number++) + { + XESetWireToEvent (dpy, event_number, XCompositeWireToEvent); + XESetEventToWire (dpy, event_number, XCompositeEventToWire); + } /* * Get the version info */ @@ -394,3 +504,68 @@ XCompositeReleaseOverlayWindow (Display *dpy, Window window) UnlockDisplay (dpy); SyncHandle (); } + +void +XCompositeSelectInput (Display *dpy, Window window, long events) +{ + XCompositeExtDisplayInfo *info; + xCompositeSelectInputReq *req; + + info = XCompositeFindDisplay (dpy); + XCompositeSimpleCheckExtension (dpy, info); + LockDisplay (dpy); + GetReq (CompositeSelectInput, req); + req->reqType = info->codes->major_opcode; + req->compositeReqType = X_CompositeSelectInput; + req->window = window; + req->events = events; + UnlockDisplay (dpy); + SyncHandle (); +} + +Status +XCompositeQueryRedirected (Display *dpy, Window window, long *update) +{ + XCompositeExtDisplayInfo *info; + xCompositeQueryRedirectedReq *req; + xCompositeQueryRedirectedReply reply; + + *update = CompositeUnredirected; + + info = XCompositeFindDisplay (dpy); + XCompositeCheckExtension (dpy, info, 0); + LockDisplay (dpy); + GetReq (CompositeQueryRedirected, req); + req->reqType = info->codes->major_opcode; + req->compositeReqType = X_CompositeQueryRedirected; + req->id = window; + if (!_XReply (dpy, (xReply *) &reply, 0, xFalse)) + { + UnlockDisplay (dpy); + SyncHandle (); + return 0; + } + UnlockDisplay (dpy); + SyncHandle (); + + *update = reply.update; + return 1; +} + +void +XCompositeGetRedirectedEvent (Display *dpy, Window window) +{ + XCompositeExtDisplayInfo *info; + xCompositeGetRedirectedEventReq *req; + + info = XCompositeFindDisplay (dpy); + XCompositeSimpleCheckExtension (dpy, info); + LockDisplay (dpy); + GetReq (CompositeGetRedirectedEvent, req); + req->reqType = info->codes->major_opcode; + req->compositeReqType = X_CompositeGetRedirectedEvent; + req->id = window; + UnlockDisplay (dpy); + SyncHandle (); +} + -- 2.37.3
>From 3631d5158e67d557d0602966e296105fa489df1d Mon Sep 17 00:00:00 2001 From: Po Lu <luang...@yahoo.com> Date: Wed, 19 Oct 2022 15:44:23 +0800 Subject: [PATCH] Implement version 0.5 of the Composite extension --- composite/compalloc.c | 49 ++++- composite/compext.c | 399 +++++++++++++++++++++++++++++++++++- composite/compint.h | 10 + composite/compwindow.c | 10 +- include/protocol-versions.h | 2 +- meson.build | 2 +- 6 files changed, 459 insertions(+), 13 deletions(-) diff --git a/composite/compalloc.c b/composite/compalloc.c index eaabf0d91..f960ee72b 100644 --- a/composite/compalloc.c +++ b/composite/compalloc.c @@ -47,6 +47,29 @@ #include "compint.h" +int +compGetUpdateMask(WindowPtr pWindow) +{ + CompWindowPtr pCompWindow; + CompClientWindowPtr pCompClientWindow; + int mask; + + pCompWindow = GetCompWindow(pWindow); + + if (!pCompWindow) + return CompositeUnredirected; + + mask = CompositeUnredirected; + for (pCompClientWindow = pCompWindow->clients; + pCompClientWindow; + pCompClientWindow = pCompClientWindow->next) { + if (CLIENT_ID (pCompClientWindow->id) != serverClient->index) + mask |= CompositeUpdateTypeToMask(pCompClientWindow->update); + } + + return mask; +} + static Bool compScreenUpdate(ClientPtr pClient, void *closure) { @@ -409,6 +432,9 @@ compRedirectSubwindows(ClientPtr pClient, WindowPtr pWin, int update) DamageExtSetCritical(pClient, TRUE); pWin->inhibitBGPaint = TRUE; } + for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) + CompositeSendRedirectNotify(pChild, CompositeParentRedirected, + compGetUpdateMask(pChild)); return Success; } @@ -446,8 +472,11 @@ compFreeClientSubwindows(WindowPtr pWin, XID id) /* * Unredirect all existing subwindows */ - for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) + for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) { (void) compUnredirectWindow(pClient, pChild, ccw->update); + CompositeSendRedirectNotify(pChild, CompositeParentRedirected, + compGetUpdateMask(pChild)); + } free(ccw); break; @@ -499,9 +528,16 @@ compRedirectOneSubwindow(WindowPtr pParent, WindowPtr pWin) int ret = compRedirectWindow(clients[CLIENT_ID(ccw->id)], pWin, ccw->update); - if (ret != Success) + if (ret != Success) { + /* Some windows may still have been redirected, so send + the event anyway. */ + CompositeSendRedirectNotify(pWin, CompositeChildReparented, + compGetUpdateMask(pWin)); return ret; + } } + CompositeSendRedirectNotify(pWin, CompositeChildReparented, + compGetUpdateMask(pWin)); return Success; } @@ -521,9 +557,16 @@ compUnredirectOneSubwindow(WindowPtr pParent, WindowPtr pWin) int ret = compUnredirectWindow(clients[CLIENT_ID(ccw->id)], pWin, ccw->update); - if (ret != Success) + if (ret != Success) { + /* Some windows may still have been unredirected, so send + the event anyway. */ + CompositeSendRedirectNotify(pWin, CompositeChildReparented, + compGetUpdateMask(pWin)); return ret; + } } + CompositeSendRedirectNotify(pWin, CompositeChildReparented, + compGetUpdateMask(pWin)); return Success; } diff --git a/composite/compext.c b/composite/compext.c index 34a2a5363..af53328d9 100644 --- a/composite/compext.c +++ b/composite/compext.c @@ -51,6 +51,7 @@ #include "extinit.h" static CARD8 CompositeReqCode; +static int CompositeEventBase; static DevPrivateKeyRec CompositeClientPrivateKeyRec; #define CompositeClientPrivateKey (&CompositeClientPrivateKeyRec) @@ -63,6 +64,88 @@ typedef struct _CompositeClient { int minor_version; } CompositeClientRec, *CompositeClientPtr; +static RESTYPE CompositeEventType; +static RESTYPE CompositeClientType; + +typedef struct _CompositeEvent *CompositeEventPtr; + +typedef struct _CompositeEvent { + CompositeEventPtr next, last; + CARD32 eventMask; + ClientPtr pClient; + WindowPtr pWindow; + XID clientResource; +} CompositeEventRec; + +#define ALLCOMPOSITEEVENT \ + (CompositeRedirectNotifyMask | CompositeRedirectStateNotifyMask) + +void +CompositeSendRedirectNotify(WindowPtr pWin, int reason, int update) +{ + CompositeEventPtr *pHead, pEvent; + int rc; + xCompositeRedirectNotifyEvent wire; + + rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id, + CompositeEventType, serverClient, + DixReadAccess); + if (rc != Success) + return; + + UpdateCurrentTimeIf(); + + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (!(pEvent->eventMask & CompositeRedirectNotifyMask)) + continue; + + memset(&wire, 0, sizeof (xCompositeRedirectNotifyEvent)); + wire.type = CompositeRedirectNotify + CompositeEventBase; + wire.reason = reason; + wire.update = update; + wire.window = pWin->drawable.id; + wire.timestamp = currentTime.milliseconds; + WriteEventsToClient(pEvent->pClient, 1, (xEvent *) &wire); + } +} + +static void +CompositeSendRedirectStateNotify(ClientPtr pClient, WindowPtr pWin, + int update) +{ + CompositeEventPtr *pHead, pEvent; + int rc; + xCompositeRedirectStateNotifyEvent wire; + + UpdateCurrentTimeIf(); + + memset(&wire, 0, sizeof (wire)); + wire.type = CompositeRedirectStateNotify + CompositeEventBase; + wire.window = pWin->drawable.id; + wire.update = update; + wire.timestamp = currentTime.milliseconds; + WriteEventsToClient(pClient, 1, (xEvent *) &wire); + + rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id, + CompositeEventType, serverClient, + DixReadAccess); + if (rc != Success) + return; + + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (!(pEvent->eventMask & CompositeRedirectStateNotifyMask) + || pEvent->pClient == pClient) + continue; + + memset(&wire, 0, sizeof (wire)); + wire.type = CompositeRedirectStateNotify + CompositeEventBase; + wire.window = pWin->drawable.id; + wire.update = update; + wire.timestamp = currentTime.milliseconds; + WriteEventsToClient(pEvent->pClient, 1, (xEvent *) &wire); + } +} + #define GetCompositeClient(pClient) ((CompositeClientPtr) \ dixLookupPrivate(&(pClient)->devPrivates, CompositeClientPrivateKey)) @@ -141,6 +224,7 @@ static int ProcCompositeRedirectWindow(ClientPtr client) { WindowPtr pWin; + int rc; REQUEST(xCompositeRedirectWindowReq); @@ -148,7 +232,13 @@ ProcCompositeRedirectWindow(ClientPtr client) VERIFY_WINDOW(pWin, stuff->window, client, DixSetAttrAccess | DixManageAccess | DixBlendAccess); - return compRedirectWindow(client, pWin, stuff->update); + rc = compRedirectWindow(client, pWin, stuff->update); + + if (rc == Success) + CompositeSendRedirectNotify(pWin, CompositeWindowRedirected, + compGetUpdateMask(pWin)); + + return rc; } static int @@ -169,6 +259,7 @@ static int ProcCompositeUnredirectWindow(ClientPtr client) { WindowPtr pWin; + int rc; REQUEST(xCompositeUnredirectWindowReq); @@ -176,7 +267,13 @@ ProcCompositeUnredirectWindow(ClientPtr client) VERIFY_WINDOW(pWin, stuff->window, client, DixSetAttrAccess | DixManageAccess | DixBlendAccess); - return compUnredirectWindow(client, pWin, stuff->update); + rc = compUnredirectWindow(client, pWin, stuff->update); + + if (rc == Success) + CompositeSendRedirectNotify(pWin, CompositeWindowRedirected, + compGetUpdateMask(pWin)); + + return rc; } static int @@ -354,15 +451,131 @@ ProcCompositeReleaseOverlayWindow(ClientPtr client) return Success; } +static int +ProcCompositeSelectInput(ClientPtr client) +{ + REQUEST(xCompositeSelectInputReq); + WindowPtr pWin; + CompositeEventPtr pEvent, pNewEvent, *pHead; + XID clientResource; + int rc; + + REQUEST_SIZE_MATCH(xCompositeSelectInputReq); + VERIFY_WINDOW(pWin, stuff->window, client, DixReceiveAccess); + + rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id, + CompositeEventType, client, DixWriteAccess); + if (rc != Success && rc != BadValue) + return rc; + + if (!stuff->events) { + /* Delete the existing entry. */ + if (pHead) { + pNewEvent = NULL; + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (pEvent->pClient == client) + break; + pNewEvent = pEvent; + } + if (pEvent) { + FreeResource(pEvent->clientResource, CompositeClientType); + if (pNewEvent) + pNewEvent->next = pEvent->next; + else + *pHead = pEvent->next; + free(pEvent); + } + } + } + else { + if (stuff->events & ~ALLCOMPOSITEEVENT) { + client->errorValue = stuff->events; + return BadValue; + } + if (pHead) { + /* Check for existing entry. */ + for (pEvent = *pHead; pEvent; pEvent = pEvent->next) { + if (pEvent->pClient == client) { + pEvent->eventMask = stuff->events; + return Success; + } + } + } + pNewEvent = malloc(sizeof (CompositeEventRec)); + if (!pNewEvent) + return BadAlloc; + pNewEvent->next = NULL; + pNewEvent->pClient = client; + pNewEvent->pWindow = pWin; + clientResource = FakeClientID(client->index); + pNewEvent->clientResource = clientResource; + if (!AddResource(clientResource, CompositeClientType, + (void *) pNewEvent)) + return BadAlloc; + pNewEvent->eventMask = stuff->events; + if (!pHead) { + pHead = calloc(1, sizeof(CompositeEventPtr)); + if (!pHead || + !AddResource (pWin->drawable.id, CompositeEventType, + (void *) pHead)) { + FreeResource (clientResource, RT_NONE); + return BadAlloc; + } + } + pNewEvent->next = *pHead; + *pHead = pNewEvent; + } + + return Success; +} + +static int +ProcCompositeQueryRedirected(ClientPtr client) +{ + REQUEST(xCompositeQueryRedirectedReq); + WindowPtr pWin; + xCompositeQueryRedirectedReply rep; + + REQUEST_SIZE_MATCH(xCompositeQueryRedirectedReq); + VERIFY_WINDOW(pWin, stuff->id, client, DixGetAttrAccess); + + memset(&rep, 0, sizeof(rep)); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.update = compGetUpdateMask(pWin); + WriteToClient(client, sizeof(rep), &rep); + return Success; +} + +static int +ProcCompositeGetRedirectedEvent(ClientPtr client) +{ + REQUEST(xCompositeGetRedirectedEventReq); + WindowPtr pWin; + + REQUEST_SIZE_MATCH(xCompositeGetRedirectedEventReq); + VERIFY_WINDOW(pWin, stuff->id, client, DixGetAttrAccess); + + CompositeSendRedirectStateNotify(client, pWin, + compGetUpdateMask(pWin)); + return Success; +} + static int (*ProcCompositeVector[CompositeNumberRequests]) (ClientPtr) = { -ProcCompositeQueryVersion, + ProcCompositeQueryVersion, ProcCompositeRedirectWindow, ProcCompositeRedirectSubwindows, ProcCompositeUnredirectWindow, ProcCompositeUnredirectSubwindows, ProcCompositeCreateRegionFromBorderClip, ProcCompositeNameWindowPixmap, - ProcCompositeGetOverlayWindow, ProcCompositeReleaseOverlayWindow,}; + ProcCompositeGetOverlayWindow, + ProcCompositeReleaseOverlayWindow, + ProcCompositeSelectInput, + ProcCompositeQueryRedirected, + ProcCompositeGetRedirectedEvent, +}; static int ProcCompositeDispatch(ClientPtr client) @@ -477,6 +690,39 @@ SProcCompositeReleaseOverlayWindow(ClientPtr client) return (*ProcCompositeVector[stuff->compositeReqType]) (client); } +static int _X_COLD +SProcCompositeSelectInput(ClientPtr client) +{ + REQUEST(xCompositeSelectInputReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xCompositeSelectInputReq); + swapl(&stuff->window); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int _X_COLD +SProcCompositeQueryRedirected(ClientPtr client) +{ + REQUEST(xCompositeQueryRedirectedReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xCompositeSelectInputReq); + swapl(&stuff->id); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + +static int _X_COLD +SProcCompositeGetRedirectedEvent(ClientPtr client) +{ + REQUEST(xCompositeGetRedirectedEventReq); + + swaps(&stuff->length); + REQUEST_SIZE_MATCH(xCompositeGetRedirectedEventReq); + swapl(&stuff->id); + return (*ProcCompositeVector[stuff->compositeReqType]) (client); +} + static int (*SProcCompositeVector[CompositeNumberRequests]) (ClientPtr) = { SProcCompositeQueryVersion, @@ -488,6 +734,9 @@ static int SProcCompositeNameWindowPixmap, SProcCompositeGetOverlayWindow, SProcCompositeReleaseOverlayWindow, + SProcCompositeSelectInput, + SProcCompositeQueryRedirected, + SProcCompositeGetRedirectedEvent, }; static int _X_COLD @@ -524,6 +773,51 @@ GetCompositeWindowBytes(void *value, XID id, ResourceSizePtr size) } } +static int +CompositeFreeClient(void *data, XID id) +{ + CompositeEventPtr pEvent; + WindowPtr pWin; + CompositeEventPtr *pHead, pCur, pPrev; + int rc; + + pEvent = (CompositeEventPtr) data; + pWin = pEvent->pWindow; + rc = dixLookupResourceByType((void **) &pHead, pWin->drawable.id, + CompositeEventType, serverClient, + DixReadAccess); + if (rc == Success) { + pPrev = NULL; + + for (pCur = *pHead; pCur && pCur != pEvent; pCur = pCur->next) + pPrev = pCur; + if (pCur) { + if (pPrev) + pPrev->next = pEvent->next; + else + *pHead = pEvent->next; + } + } + + free(pEvent); + return 1; +} + +static int +CompositeFreeEvents(void *data, XID id) +{ + CompositeEventPtr *pHead, pCur, pNext; + + pHead = (CompositeEventPtr *) data; + for (pCur = *pHead; pCur; pCur = pNext) { + pNext = pCur->next; + FreeResource(pCur->clientResource, CompositeClientType); + free(pCur); + } + free(pHead); + return 1; +} + void CompositeExtensionInit(void) { @@ -569,6 +863,16 @@ CompositeExtensionInit(void) if (!CompositeClientOverlayType) return; + CompositeClientType = CreateNewResourceType + (CompositeFreeClient, "CompositeClient"); + if (!CompositeClientType) + return; + + CompositeEventType = CreateNewResourceType + (CompositeFreeEvents, "CompositeEvent"); + if (!CompositeEventType) + return; + if (!dixRegisterPrivateKey(&CompositeClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(CompositeClientRec))) return; @@ -577,12 +881,13 @@ CompositeExtensionInit(void) if (!compScreenInit(screenInfo.screens[s])) return; - extEntry = AddExtension(COMPOSITE_NAME, 0, 0, + extEntry = AddExtension(COMPOSITE_NAME, CompositeNumberEvents, 0, ProcCompositeDispatch, SProcCompositeDispatch, NULL, StandardMinorOpcode); if (!extEntry) return; CompositeReqCode = (CARD8) extEntry->base; + CompositeEventBase = extEntry->eventBase; /* Initialization succeeded */ noCompositeExtension = FALSE; @@ -904,6 +1209,84 @@ PanoramiXCompositeReleaseOverlayWindow(ClientPtr client) return Success; } +static int +PanoramiXCompositeSelectInput (ClientPtr client) +{ + PanoramiXRes *win; + int rc, j; + + REQUEST(xCompositeSelectInputReq); + REQUEST_SIZE_MATCH(xCompositeSelectInputReq); + + if ((rc = dixLookupResourceByType((void **) &win, stuff->window, + XRT_WINDOW, client, + DixUnknownAccess))) { + client->errorValue = stuff->window; + return rc; + } + + FOR_NSCREENS_FORWARD(j) { + stuff->window = win->info[j].id; + rc = (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + if (rc != Success) + break; + } + + return rc; +} + +static int +PanoramiXCompositeQueryRedirected (ClientPtr client) +{ + PanoramiXRes *win; + int rc, j; + + REQUEST(xCompositeQueryRedirectedReq); + REQUEST_SIZE_MATCH(xCompositeQueryRedirectedReq); + + if ((rc = dixLookupResourceByType((void **) &win, stuff->id, + XRT_WINDOW, client, + DixUnknownAccess))) { + client->errorValue = stuff->id; + return rc; + } + + FOR_NSCREENS_FORWARD(j) { + /* Just do the first screen. */ + stuff->id = win->info[j].id; + return (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + } + + /* Xinerama with 0 screens! */ + return BadImplementation; +} + +static int +PanoramiXCompositeGetRedirectedEvent (ClientPtr client) +{ + PanoramiXRes *win; + int rc, j; + + REQUEST(xCompositeQueryRedirectedReq); + REQUEST_SIZE_MATCH(xCompositeQueryRedirectedReq); + + if ((rc = dixLookupResourceByType((void **) &win, stuff->id, + XRT_WINDOW, client, + DixUnknownAccess))) { + client->errorValue = stuff->id; + return rc; + } + + FOR_NSCREENS_FORWARD(j) { + /* Just do the first screen. */ + stuff->id = win->info[j].id; + return (*PanoramiXSaveCompositeVector[stuff->compositeReqType]) (client); + } + + /* Xinerama with 0 screens! */ + return BadImplementation; +} + void PanoramiXCompositeInit(void) { @@ -928,6 +1311,12 @@ PanoramiXCompositeInit(void) PanoramiXCompositeGetOverlayWindow; ProcCompositeVector[X_CompositeReleaseOverlayWindow] = PanoramiXCompositeReleaseOverlayWindow; + ProcCompositeVector[X_CompositeSelectInput] = + PanoramiXCompositeSelectInput; + ProcCompositeVector[X_CompositeQueryRedirected] = + PanoramiXCompositeQueryRedirected; + ProcCompositeVector[X_CompositeGetRedirectedEvent] = + PanoramiXCompositeGetRedirectedEvent; } void diff --git a/composite/compint.h b/composite/compint.h index 423b641ff..df6ca8198 100644 --- a/composite/compint.h +++ b/composite/compint.h @@ -197,6 +197,9 @@ extern RESTYPE CompositeClientOverlayType; * compalloc.c */ +int + compGetUpdateMask(WindowPtr pWin); + Bool compRedirectWindow(ClientPtr pClient, WindowPtr pWin, int update); @@ -335,6 +338,13 @@ int compConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw, WindowPtr pSib); +/* + * compext.c + */ + +void + CompositeSendRedirectNotify(WindowPtr pWin, int reason, int update); + void PanoramiXCompositeInit(void); void PanoramiXCompositeReset(void); diff --git a/composite/compwindow.c b/composite/compwindow.c index 73a1871a0..6e8142912 100644 --- a/composite/compwindow.c +++ b/composite/compwindow.c @@ -584,9 +584,13 @@ compCreateWindow(WindowPtr pWin) if (window_pixmap != parent_pixmap) (*pScreen->SetWindowPixmap) (pWin, parent_pixmap); if (csw) - for (ccw = csw->clients; ccw; ccw = ccw->next) - compRedirectWindow(clients[CLIENT_ID(ccw->id)], - pWin, ccw->update); + { + for (ccw = csw->clients; ccw; ccw = ccw->next) + compRedirectWindow(clients[CLIENT_ID(ccw->id)], + pWin, ccw->update); + CompositeSendRedirectNotify(pWin, CompositeChildCreated, + compGetUpdateMask(pWin)); + } if (compImplicitRedirect(pWin, pWin->parent)) compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic); } diff --git a/include/protocol-versions.h b/include/protocol-versions.h index d7bfc6dca..6da5eb6b5 100644 --- a/include/protocol-versions.h +++ b/include/protocol-versions.h @@ -40,7 +40,7 @@ /* Composite */ #define SERVER_COMPOSITE_MAJOR_VERSION 0 -#define SERVER_COMPOSITE_MINOR_VERSION 4 +#define SERVER_COMPOSITE_MINOR_VERSION 5 /* Damage */ #define SERVER_DAMAGE_MAJOR_VERSION 1 diff --git a/meson.build b/meson.build index 47ecb06c9..7b70b50fb 100644 --- a/meson.build +++ b/meson.build @@ -82,7 +82,7 @@ bigreqsproto_dep = dependency('bigreqsproto', version: '>= 1.1.0', fallback: ['x xtrans_dep = dependency('xtrans', version: '>= 1.3.5') videoproto_dep = dependency('videoproto', fallback: ['xorgproto', 'ext_xorgproto']) -compositeproto_dep = dependency('compositeproto', version: '>= 0.4', fallback: ['xorgproto', 'ext_xorgproto']) +compositeproto_dep = dependency('compositeproto', version: '>= 0.5', fallback: ['xorgproto', 'ext_xorgproto']) recordproto_dep = dependency('recordproto', version: '>= 1.13.99.1', fallback: ['xorgproto', 'ext_xorgproto']) scrnsaverproto_dep = dependency('scrnsaverproto', version: '>= 1.1', fallback: ['xorgproto', 'ext_xorgproto']) resourceproto_dep = dependency('resourceproto', version: '>= 1.2.0', fallback: ['xorgproto', 'ext_xorgproto']) -- 2.37.3