diff --git a/hw/dmx/dmx.h b/hw/dmx/dmx.h index d254b13ad..9f3bcb86f 100644 --- a/hw/dmx/dmx.h +++ b/hw/dmx/dmx.h @@ -104,9 +104,18 @@ typedef struct _DMXPropTrans { Atom type; } DMXPropTrans; -/** Opcode for xcb_implementation. */ +typedef struct _DMXSelectionMap { + const char *name; + Atom atom; + Atom beAtom; +} DMXSelectionMap; + #define DMX_DETACHED 0xff +/** Number of backend selection conversion requests that can be + processed simultaneously . */ +#define DMX_N_SELECTION_PROXY 10 + /** Provide the typedef globally, but keep the contents opaque outside * of the XSync statistic routines. \see dmxstat.c */ typedef struct _DMXStatInfo DMXStatInfo; @@ -203,6 +212,15 @@ typedef struct _DMXScreenInfo { int rootY; /**< Y offset of "root" window WRT "screen"*/ int rootEventMask; + /*---------- Selection information ----------*/ + Atom selectionAtom; + Window selectionOwner; + xcb_get_selection_owner_cookie_t getSelectionOwner; + Window getSelectionOwnerResult; + XID selectionProxyWid[DMX_N_SELECTION_PROXY]; + WindowPtr pSelectionProxyWin[DMX_N_SELECTION_PROXY]; + Atom incrAtom; + /*---------- Other related information ----------*/ int dpmsCapable; /**< Non-zero if backend is DPMS capable */ @@ -364,11 +382,16 @@ extern int xRRCrtcsPerScreen; extern DMXPropTrans *dmxPropTrans; extern int dmxPropTransNum; +extern DMXSelectionMap *dmxSelectionMap; +extern int dmxSelectionMapNum; + #ifdef XV extern char **dmxXvImageFormats; extern int dmxXvImageFormatsNum; #endif +extern char dmxDigest[64]; + /** Wrap screen or GC function pointer */ #define DMX_WRAP(_entry, _newfunc, _saved, _actual) \ do { \ diff --git a/hw/dmx/dmxcb.c b/hw/dmx/dmxcb.c index 9cf9b9423..996eee755 100644 --- a/hw/dmx/dmxcb.c +++ b/hw/dmx/dmxcb.c @@ -42,6 +42,7 @@ #include "dmxcb.h" #include "dmxinput.h" #include "dmxlog.h" +#include "dmxselection.h" extern int connBlockScreenStart; @@ -194,4 +195,6 @@ void dmxConnectionBlockCallback(void) } #endif MAXSCREENSFREE(found); + + dmxCreateSelectionProxies (); } diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c index 3ec38f461..56af57574 100644 --- a/hw/dmx/dmxinit.c +++ b/hw/dmx/dmxinit.c @@ -141,6 +141,9 @@ int xRRCrtcsPerScreen = 1; DMXPropTrans *dmxPropTrans = NULL; int dmxPropTransNum = 0; +DMXSelectionMap *dmxSelectionMap = NULL; +int dmxSelectionMapNum = 0; + #ifdef XV char **dmxXvImageFormats = NULL; int dmxXvImageFormatsNum = 0; @@ -839,6 +842,26 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) strlen (dmxPropTrans[i].name), TRUE); + for (i = 0; i < dmxSelectionMapNum; i++) + { + char *beName; + + dmxSelectionMap[i].atom = MakeAtom ((char *) dmxSelectionMap[i].name, + strlen (dmxSelectionMap[i].name), + TRUE); + + beName = xalloc (strlen (dmxSelectionMap[i].name) + + strlen (dmxDigest) + 2); + if (!beName) + dmxLog (dmxFatal, "InitOutput: not enough memory\n"); + + sprintf (beName, "%s_%s", dmxSelectionMap[i].name, dmxDigest); + dmxSelectionMap[i].beAtom = MakeAtom ((char *) beName, + strlen (beName), + TRUE); + xfree (beName); + } + if (!dmxNumScreens) { dmxLaunchDisplay (argc, argv, dmxLaunchIndex, dmxLaunchVT); @@ -1093,6 +1116,39 @@ void OsVendorInit(void) dmxPropTransNum = 1; } + if (!dmxSelectionMap) + { + dmxSelectionMap = xalloc (sizeof (DMXSelectionMap) * 9); + dmxSelectionMap[0].name = "WM_S0"; + dmxSelectionMap[0].atom = 0; + dmxSelectionMap[0].beAtom = 0; + dmxSelectionMap[1].name = "_NET_WM_CM_S0"; + dmxSelectionMap[1].atom = 0; + dmxSelectionMap[1].beAtom = 0; + dmxSelectionMap[2].name = "_NET_SYSTEM_TRAY_S0"; + dmxSelectionMap[2].atom = 0; + dmxSelectionMap[2].beAtom = 0; + dmxSelectionMap[3].name = "_NET_DESKTOP_LAYOUT_S0"; + dmxSelectionMap[3].atom = 0; + dmxSelectionMap[3].beAtom = 0; + dmxSelectionMap[4].name = "_NET_DESKTOP_MANAGER_S0"; + dmxSelectionMap[4].atom = 0; + dmxSelectionMap[4].beAtom = 0; + dmxSelectionMap[5].name = "_XSETTINGS_S0"; + dmxSelectionMap[5].atom = 0; + dmxSelectionMap[5].beAtom = 0; + dmxSelectionMap[6].name = "CLIPBOARD_MANAGER"; + dmxSelectionMap[6].atom = 0; + dmxSelectionMap[6].beAtom = 0; + dmxSelectionMap[7].name = "GVM_SELECTION"; + dmxSelectionMap[7].atom = 0; + dmxSelectionMap[7].beAtom = 0; + dmxSelectionMap[8].name = "_COMPIZ_DM_S0"; + dmxSelectionMap[8].atom = 0; + dmxSelectionMap[8].beAtom = 0; + dmxSelectionMapNum = 9; + } + #ifdef PANORAMIX noPanoramiXExtension = dmxNoPanoramiXExtension; PanoramiXExtensionDisabledHack = TRUE; @@ -1211,6 +1267,26 @@ int ddxProcessArgument(int argc, char *argv[], int i) } retval = 3; } + else if (!strcmp (argv[i], "-selection")) + { + if (++i < argc) + { + DMXSelectionMap *selection; + + selection = xrealloc (dmxSelectionMap, sizeof (DMXSelectionMap) * + (dmxSelectionMapNum + 1)); + if (selection) + { + selection[dmxSelectionMapNum].name = argv[i]; + selection[dmxSelectionMapNum].atom = 0; + selection[dmxSelectionMapNum].beAtom = 0; + + dmxSelectionMapNum++; + dmxSelectionMap = selection; + } + } + retval = 2; + } #ifdef XV else if (!strcmp (argv[i], "-xvimage")) { @@ -1277,6 +1353,7 @@ void ddxUseMsg(void) ErrorF("-crtcs num RANDR crtcs for each back-end display\n"); #endif ErrorF("-prop name format Specify property translation\n"); + ErrorF("-selection name Specify selection that needs unique prefix\n"); #ifdef XV ErrorF("-xvimage fourcc Enable XVideo image format\n"); #endif diff --git a/hw/dmx/dmxprop.c b/hw/dmx/dmxprop.c index ed1776179..e37631e62 100644 --- a/hw/dmx/dmxprop.c +++ b/hw/dmx/dmxprop.c @@ -64,6 +64,7 @@ #include "dmxwindow.h" #include "dmxlog.h" #include "dmxatom.h" +#include "dmxselection.h" #ifdef PANORAMIX #include "panoramiX.h" @@ -146,14 +147,20 @@ dmxProcChangeProperty (ClientPtr client) XRT_WINDOW, DixReadAccess))) { - FOR_NSCREENS_FORWARD(j) { - if (dixLookupWindow (&pWin, + FOR_NSCREENS_BACKWARD(j) { + WindowPtr pScrWin; + + if (dixLookupWindow (&pScrWin, win->info[j].id, serverClient, DixReadAccess) == Success) - dmxBESetWindowProperty (pWin, pProp); + dmxBESetWindowProperty (pScrWin, pProp); } } + + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + stuff->nUnits); return Success; } @@ -161,6 +168,10 @@ dmxProcChangeProperty (ClientPtr client) dmxBESetWindowProperty (pWin, pProp); + dmxSelectionPropertyChangeCheck (pWin, + stuff->property, + stuff->nUnits); + return Success; } @@ -168,16 +179,17 @@ static void dmxDeleteProperty (WindowPtr pWin, Atom property) { - ScreenPtr pScreen = pWin->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + ScreenPtr pScreen = pWin->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Window window; - if (!pWinPriv->window) + window = dmxBEGetSelectionAdjustedPropertyWindow (pWin); + if (!window) return; XLIB_PROLOGUE (dmxScreen); XDeleteProperty (dmxScreen->beDisplay, - pWinPriv->window, + window, dmxBEAtom (dmxScreen, property)); XLIB_EPILOGUE (dmxScreen); } @@ -226,6 +238,60 @@ dmxProcDeleteProperty (ClientPtr client) return Success; } +static int +dmxProcGetProperty (ClientPtr client) +{ + WindowPtr pWin; + PropertyPtr pProp; + int err; + REQUEST(xGetPropertyReq); + + err = (*dmxSaveProcVector[X_GetProperty]) (client); + if (err != Success || !stuff->delete) + return err; + + if (dixLookupWindow (&pWin, + stuff->window, + serverClient, + DixReadAccess) != Success || + dixLookupProperty (&pProp, + pWin, + stuff->property, + serverClient, + DixReadAccess) != BadMatch) + return Success; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *win; + int j; + + if ((win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->window, + XRT_WINDOW, + DixReadAccess))) + { + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + { + dmxDeleteProperty (pWin, stuff->property); + } + } + } + + return Success; + } +#endif + + dmxDeleteProperty (pWin, stuff->property); + + return Success; +} + static void dmxRotateProperties (WindowPtr pWin, Atom *atoms, @@ -235,22 +301,22 @@ dmxRotateProperties (WindowPtr pWin, { ScreenPtr pScreen = pWin->drawable.pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + Window window; int i; - if (!pWinPriv->window) + window = dmxBEGetSelectionAdjustedPropertyWindow (pWin); + if (!window) return; - XLIB_PROLOGUE (dmxScreen); for (i = 0; i < nAtoms; i++) buf[i] = dmxBEAtom (dmxScreen, atoms[i]); + XLIB_PROLOGUE (dmxScreen); XRotateWindowProperties (dmxScreen->beDisplay, - pWinPriv->window, + window, buf, nAtoms, nPositions); - XLIB_EPILOGUE (dmxScreen); } @@ -323,6 +389,7 @@ void dmxInitProps (void) ProcVector[X_ChangeProperty] = dmxProcChangeProperty; ProcVector[X_DeleteProperty] = dmxProcDeleteProperty; + ProcVector[X_GetProperty] = dmxProcGetProperty; ProcVector[X_RotateProperties] = dmxProcRotateProperties; } diff --git a/hw/dmx/dmxscrinit.c b/hw/dmx/dmxscrinit.c index 23483adb9..3550e71e4 100644 --- a/hw/dmx/dmxscrinit.c +++ b/hw/dmx/dmxscrinit.c @@ -119,6 +119,7 @@ DevPrivateKey dmxGlyphPrivateKey = &dmxGlyphPrivateKeyIndex; /**< Private index void dmxBEScreenInit(int idx, ScreenPtr pScreen) { DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + char buf[256]; int i, j; /* FIXME: The dmxScreenInit() code currently assumes that it will @@ -138,6 +139,12 @@ void dmxBEScreenInit(int idx, ScreenPtr pScreen) pScreen->whitePixel = dmxScreen->beWhitePixel; pScreen->blackPixel = dmxScreen->beBlackPixel; + dmxScreen->selectionAtom = None; + dmxScreen->selectionOwner = None; + + sprintf(buf, "DMX_%s", dmxDigest); + dmxScreen->selectionAtom = XInternAtom (dmxScreen->beDisplay, buf, 0); + /* Handle screen savers and DPMS on the backend */ dmxDPMSInit(dmxScreen); @@ -208,6 +215,168 @@ dmxScreenReplyCheckInput (ScreenPtr pScreen, return dmxInputReplyCheck (&dmxScreen->input, sequence, reply); } +static void +dmxScreenGetSelectionOwner (ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + dmxScreen->selectionOwner = None; + while (dmxScreen->selectionOwner == None) + { + xcb_connection_t *c = dmxScreen->connection; + xcb_atom_t a = dmxScreen->selectionAtom; + xcb_get_selection_owner_reply_t *reply; + + reply = xcb_get_selection_owner_reply (c, + xcb_get_selection_owner (c, a), + NULL); + if (!reply) + break; + + if (reply->owner) + { + if (reply->owner != dmxScreen->rootWin) + { + const uint32_t value = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + xcb_void_cookie_t r; + xcb_generic_error_t *error; + + r = xcb_change_window_attributes_checked (c, + reply->owner, + XCB_CW_EVENT_MASK, + &value); + error = xcb_request_check (c, r); + if (error) + { + if (error->error_code != BadWindow) + dmxScreen->selectionOwner = reply->owner; + + free (error); + } + else + { + dmxScreen->selectionOwner = reply->owner; + } + } + else + { + dmxScreen->selectionOwner = dmxScreen->rootWin; + } + } + else + { + xcb_set_selection_owner (dmxScreen->connection, + dmxScreen->rootWin, + dmxScreen->selectionAtom, + 0); + } + + free (reply); + } +} + +static Bool +dmxScreenEventCheckSelection (ScreenPtr pScreen, + xcb_generic_event_t *event) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + switch (event->response_type & ~0x80) { + case XCB_DESTROY_NOTIFY: { + xcb_destroy_notify_event_t *xdestroy = + (xcb_destroy_notify_event_t *) event; + + if (xdestroy->window != dmxScreen->selectionOwner) + return FALSE; + + if (dmxScreen->selectionOwner == dmxScreen->rootWin) + return FALSE; + + dmxScreenGetSelectionOwner (pScreen); + } break; + case XCB_PROPERTY_NOTIFY: { + xcb_property_notify_event_t *xproperty = + (xcb_property_notify_event_t *) event; + + if (!dmxSelectionPropertyNotify (pScreen, + xproperty->window, + xproperty->state, + xproperty->atom, + xproperty->time)) + return FALSE; + } break; + case XCB_SELECTION_CLEAR: { + xcb_selection_clear_event_t *xclear = + (xcb_selection_clear_event_t *) event; + + if (xclear->selection == dmxScreen->selectionAtom) + { + dmxScreenGetSelectionOwner (pScreen); + } + else + { + dmxSelectionClear (pScreen, + xclear->owner, + xclear->selection); + } + } break; + case XCB_SELECTION_NOTIFY: { + xcb_selection_notify_event_t *xnotify = + (xcb_selection_notify_event_t *) event; + + dmxSelectionNotify (pScreen, + xnotify->requestor, + xnotify->selection, + xnotify->target, + xnotify->property, + xnotify->time); + } break; + case XCB_SELECTION_REQUEST: { + xcb_selection_request_event_t *xrequest = + (xcb_selection_request_event_t *) event; + + dmxSelectionRequest (pScreen, + xrequest->owner, + xrequest->requestor, + xrequest->selection, + xrequest->target, + xrequest->property, + xrequest->time); + } break; + default: + return FALSE; + } + + return TRUE; +} + +static Bool +dmxScreenReplyCheckSelection (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (sequence == dmxScreen->getSelectionOwner.sequence) + { + dmxScreen->getSelectionOwner.sequence = 0; + + if (reply->response_type) + { + xcb_get_selection_owner_reply_t *xselection = + (xcb_get_selection_owner_reply_t *) reply; + + dmxScreen->getSelectionOwnerResult = xselection->owner; + } + + return TRUE; + } + else + { + return dmxSelectionPropertyReplyCheck (pScreen, sequence, reply); + } +} + static void dmxDiscardIgnore (DMXScreenInfo *dmxScreen, unsigned long sequence) @@ -326,6 +495,7 @@ dmxScreenEventCheckOutputWindow (ScreenPtr pScreen, /* output window has been destroyed, detach screen when we reach the block handler */ dmxScreen->scrnWin = None; + return TRUE; } break; case XCB_MAP_NOTIFY: { xcb_map_notify_event_t *xmap = (xcb_map_notify_event_t *) event; @@ -334,10 +504,10 @@ dmxScreenEventCheckOutputWindow (ScreenPtr pScreen, return TRUE; } break; default: - return FALSE; + break; } - return TRUE; + return FALSE; } static Bool @@ -361,7 +531,7 @@ dmxScreenEventCheckManageRoot (ScreenPtr pScreen, (xcb_map_request_event_t *) event; xcb_client_message_event_t *xclient = (xcb_client_message_event_t *) event; - xcb_map_notify_event_t * xmap = + xcb_map_notify_event_t *xmap = (xcb_map_notify_event_t *) event; switch (event->response_type & ~0x80) { @@ -379,7 +549,10 @@ dmxScreenEventCheckManageRoot (ScreenPtr pScreen, break; case XCB_MAP_NOTIFY: if (xmap->window == dmxScreen->rootWin) + { + dmxScreenGetSelectionOwner (pScreen); return TRUE; + } /* fall-through */ default: @@ -680,6 +853,7 @@ dmxBEDispatch (ScreenPtr pScreen) while ((event = xcb_poll_for_event (dmxScreen->connection))) { if (!dmxScreenEventCheckInput (pScreen, event) && + !dmxScreenEventCheckSelection (pScreen, event) && !dmxScreenEventCheckOutputWindow (pScreen, event) && !dmxScreenEventCheckManageRoot (pScreen, event) && !dmxScreenEventCheckExpose (pScreen, event) && @@ -731,7 +905,8 @@ dmxBEDispatch (ScreenPtr pScreen) dmxScreen->request.tail = &dmxScreen->request.head; if (!dmxScreenReplyCheckSync (pScreen, head->sequence, rep) && - !dmxScreenReplyCheckInput (pScreen, head->sequence, rep)) + !dmxScreenReplyCheckInput (pScreen, head->sequence, rep) && + !dmxScreenReplyCheckSelection (pScreen, head->sequence, rep)) { /* error response */ if (rep->response_type == 0) @@ -751,36 +926,27 @@ dmxBEDispatch (ScreenPtr pScreen) if (!dmxScreen->scrnWin || xcb_connection_has_error (dmxScreen->connection)) { - if (!dmxScreen->broken) + while (dmxScreen->request.head) { + DMXSequence *head = dmxScreen->request.head; static xcb_generic_error_t detached_error = { 0, DMX_DETACHED }; - dmxScreenEventCheckInput (pScreen, (xcb_generic_event_t *) - &detached_error); - dmxScreenEventCheckOutputWindow (pScreen, (xcb_generic_event_t *) - &detached_error); - dmxScreenEventCheckManageRoot (pScreen, (xcb_generic_event_t *) - &detached_error); - dmxScreenEventCheckExpose (pScreen, (xcb_generic_event_t *) - &detached_error); + dmxScreen->request.head = head->next; + if (!dmxScreen->request.head) + dmxScreen->request.tail = &dmxScreen->request.head; -#ifdef MITSHM - dmxScreenEventCheckShm (pScreen, (xcb_generic_event_t *) - &detached_error); -#endif - -#ifdef RANDR - dmxScreenEventCheckRR (pScreen, (xcb_generic_event_t *) - &detached_error); -#endif - - dmxScreenReplyCheckSync (pScreen, 0, (xcb_generic_reply_t *) + dmxScreenReplyCheckSync (pScreen, head->sequence, + (xcb_generic_reply_t *) &detached_error); - dmxScreenReplyCheckInput (pScreen, 0, (xcb_generic_reply_t *) + dmxScreenReplyCheckInput (pScreen, head->sequence, + (xcb_generic_reply_t *) &detached_error); - - dmxScreen->broken = TRUE; + dmxScreenReplyCheckSelection (pScreen, head->sequence, + (xcb_generic_reply_t *) + &detached_error); } + + dmxScreen->broken = TRUE; } dmxScreen->inDispatch--; @@ -902,7 +1068,10 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) dmxScreen->request.head = NULL; dmxScreen->request.tail = &dmxScreen->request.head; - dmxScreen->rootEventMask = ExposureMask | SubstructureRedirectMask; + dmxScreen->rootEventMask = ExposureMask | StructureNotifyMask | + SubstructureRedirectMask; + + dmxScreen->incrAtom = MakeAtom ("INCR", strlen ("INCR"), TRUE); #ifdef MITSHM dmxScreen->beShm = FALSE; @@ -1207,6 +1376,10 @@ Bool dmxCloseScreen(int idx, ScreenPtr pScreen) { DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + /* Free selection proxy window tree */ + if (dmxScreen->selectionProxyWid[0]) + FreeResource (dmxScreen->selectionProxyWid[0], RT_NONE); + /* Reset the proc vectors */ if (idx == 0) { #ifdef COMPOSITE diff --git a/hw/dmx/dmxselection.c b/hw/dmx/dmxselection.c index 0280e93bf..964f84138 100644 --- a/hw/dmx/dmxselection.c +++ b/hw/dmx/dmxselection.c @@ -29,6 +29,10 @@ #include "dmx.h" #include "dmxlog.h" +#include "dmxatom.h" +#include "dmxwindow.h" +#include "dmxscrinit.h" +#include "dmxsync.h" #include "dmxselection.h" #include "selection.h" @@ -38,10 +42,893 @@ #include "panoramiXsrv.h" #endif -static void -dmxBESetSelectionOwner (WindowPtr pWin, - Selection *pSel) +#define DMX_SELECTION_TIMEOUT (60 * 1000) /* 60 seconds */ + +typedef struct _DMXSelection { + struct _DMXSelection *next; + + XID wid; + XID requestor; + Atom selection; + Atom target; + Atom property; + Time time; + + struct { + unsigned int in; + unsigned int out; + } value[MAXSCREENS]; + + OsTimerPtr timer; +} DMXSelection; + +static DMXSelection *convHead = NULL; +static DMXSelection **convTail = &convHead; + +static DMXSelection *propHead = NULL; +static DMXSelection **propTail = &propHead; + +static DMXSelection *reqHead = NULL; +static DMXSelection **reqTail = &reqHead; + +static DMXSelection * +dmxUnhookSelection (DMXSelection *s, + DMXSelection **head, + DMXSelection ***tail) { + DMXSelection *p, *prev = NULL; + + for (p = *head; p; p = p->next) + { + if (p == s) + break; + + prev = p; + } + + assert (p); + + if (prev) + { + prev->next = s->next; + if (!prev->next) + *tail = &prev->next; + } + else + { + *head = s->next; + if (!s->next) + *tail = head; + } + + s->next = NULL; + + TimerCancel (s->timer); + + return s; +} + +static int +dmxSelectionDeleteConv (DMXSelection *s) +{ + WindowPtr pWin; + xEvent event; + + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = s->time; + event.u.selectionNotify.requestor = s->wid; + event.u.selectionNotify.selection = s->selection; + event.u.selectionNotify.target = s->target; + event.u.selectionNotify.property = None; + + if (dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + DeliverEventsToWindow (inputInfo.pointer, pWin, &event, 1, + NoEventMask, NullGrab, 0); + + if (s->timer) + TimerFree (s->timer); + + xfree (s); + return 0; +} + +static int +dmxSelectionDeleteProp (DMXSelection *s) +{ + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (s->property == dmxScreen->incrAtom && s->value[i].out) + { + const uint32_t value = 0; + + xcb_change_window_attributes (dmxScreen->connection, + s->value[i].out, + XCB_CW_EVENT_MASK, + &value); + } + } + + if (s->timer) + TimerFree (s->timer); + + xfree (s); + return 0; +} + +static int +dmxSelectionDeleteReq (DMXSelection *s) +{ + WindowPtr pWin; + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + if (s->value[i].out) + { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + if (s->property == dmxScreen->incrAtom) + { + const uint32_t value = 0; + + xcb_change_window_attributes (dmxScreen->connection, + s->value[i].out, + XCB_CW_EVENT_MASK, + &value); + } + } + } + + if (s->wid && dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + DeleteProperty (serverClient, pWin, s->property); + + if (s->timer) + TimerFree (s->timer); + + xfree (s); + return 0; +} + +static CARD32 +dmxSelectionCallback (OsTimerPtr timer, + CARD32 time, + pointer arg) +{ + DMXSelection *r = (DMXSelection *) arg; + DMXSelection *s; + + dmxLog (dmxWarning, + "selection conversion for %s timed out\n", + NameForAtom (r->selection)); + + for (s = convHead; s; s = s->next) + if (s == r) + return dmxSelectionDeleteConv (dmxUnhookSelection (s, + &convHead, + &convTail)); + + for (s = propHead; s; s = s->next) + if (s == r) + return dmxSelectionDeleteProp (dmxUnhookSelection (s, + &propHead, + &propTail)); + + for (s = reqHead; s; s = s->next) + if (s == r) + return dmxSelectionDeleteReq (dmxUnhookSelection (s, + &reqHead, + &reqTail)); + + return 0; +} + +static void +dmxSelectionResetTimer (DMXSelection *s) +{ + s->timer = TimerSet (s->timer, + 0, + DMX_SELECTION_TIMEOUT, + dmxSelectionCallback, + s); +} + +static void +dmxAppendSelection (DMXSelection *s, + DMXSelection ***tail) +{ + dmxSelectionResetTimer (s); + + *(*tail) = s; + *tail = &s->next; +} + +static Atom +dmxBESelectionAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + int i; + + for (i = 0; i < dmxSelectionMapNum; i++) + if (atom == dmxSelectionMap[i].atom) + return dmxBEAtom (dmxScreen, dmxSelectionMap[i].beAtom); + + return dmxBEAtom (dmxScreen, atom); +} + +static Atom +dmxSelectionAtom (DMXScreenInfo *dmxScreen, + Atom atom) +{ + int i; + + for (i = 0; i < dmxSelectionMapNum; i++) + if (atom == dmxSelectionMap[i].beAtom) + return dmxAtom (dmxScreen, dmxSelectionMap[i].atom); + + return dmxAtom (dmxScreen, atom); +} + +static void +dmxBESetSelectionOwner (ScreenPtr pScreen, + WindowPtr pWin, + Atom selection) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Window window = None; + + if (!dmxScreen->beDisplay) + return; + + if (dmxScreen->selectionOwner != dmxScreen->rootWin) + return; + + if (pWin) + window = DMX_GET_WINDOW_PRIV(pWin)->window; + + xcb_set_selection_owner (dmxScreen->connection, + window, + dmxBESelectionAtom (dmxScreen, selection), + 0); +} + +static Bool +dmxBEGetSelectionOwner (ScreenPtr pScreen, + Atom selection) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + /* reset getSelectionOwner fields */ + dmxScreen->getSelectionOwner.sequence = 0; + dmxScreen->getSelectionOwnerResult = 0; + + if (!dmxScreen->beDisplay) + return FALSE; + + if (dmxScreen->selectionOwner != dmxScreen->rootWin) + return FALSE; + + dmxScreen->getSelectionOwner = + xcb_get_selection_owner (dmxScreen->connection, + dmxBESelectionAtom (dmxScreen, selection)); + + if (!dmxScreen->getSelectionOwner.sequence) + return FALSE; + + dmxAddSequence (&dmxScreen->request, + dmxScreen->getSelectionOwner.sequence); + + return TRUE; +} + +static Window +dmxBEConvertSelection (WindowPtr pWin, + Atom selection, + Atom target, + Atom property, + Time time) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + + if (!dmxScreen->beDisplay || !pWinPriv->window) + return 0; + + if (dmxScreen->selectionOwner != dmxScreen->rootWin) + return 0; + + xcb_convert_selection (dmxScreen->connection, + pWinPriv->window, + dmxBESelectionAtom (dmxScreen, selection), + dmxBEAtom (dmxScreen, target), + property ? dmxBEAtom (dmxScreen, property) : None, + 0); + + dmxSync (dmxScreen, FALSE); + + return pWinPriv->window; +} + +Window +dmxBEGetSelectionAdjustedPropertyWindow (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWin); + DMXSelection *s; + + if (!pWinPriv->window) + return None; + + for (s = reqHead; s; s = s->next) + if (s->value[pScreen->myNum].in == pWinPriv->window) + return s->value[pScreen->myNum].out; + + return pWinPriv->window; +} + +void +dmxSelectionClear (ScreenPtr pScreen, + Window owner, + Atom xSelection) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom selection = dmxSelectionAtom (dmxScreen, xSelection); + Selection *pSel; + + if (!ValidAtom (selection)) + return; + + if (dixLookupSelection (&pSel, + selection, + serverClient, + DixGetAttrAccess) == Success && + pSel->client != NullClient) + { + SelectionInfoRec info = { pSel, NullClient, SelectionSetOwner }; + xEvent event; + + event.u.u.type = SelectionClear; + event.u.selectionClear.time = currentTime.milliseconds; + event.u.selectionClear.window = pSel->window; + event.u.selectionClear.atom = pSel->selection; + + TryClientEvents (pSel->client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + + pSel->lastTimeChanged = currentTime; + pSel->window = dmxScreen->selectionProxyWid[0]; + pSel->pWin = NULL; + pSel->client = NullClient; + + CallCallbacks (&SelectionCallback, &info); + + pSel->window = None; + } +} + +void +dmxSelectionNotify (ScreenPtr pScreen, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom selection = dmxSelectionAtom (dmxScreen, xSelection); + Atom target = dmxAtom (dmxScreen, xTarget); + DMXSelection *s; + + for (s = convHead; s; s = s->next) + if (s->value[pScreen->myNum].out == requestor && + s->selection == selection && + s->target == target) + break; + + if (s) + { + xcb_get_property_cookie_t cookie = { 0 }; + Atom property = dmxAtom (dmxScreen, xProperty); + Atom target = dmxAtom (dmxScreen, xTarget); + + if (ValidAtom (property) && ValidAtom (target)) + cookie = xcb_get_property (dmxScreen->connection, + xFalse, + requestor, + xProperty, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + if (cookie.sequence) + { + const uint32_t value = XCB_EVENT_MASK_PROPERTY_CHANGE; + + dmxUnhookSelection (s, &convHead, &convTail); + + memset (s->value, 0, sizeof (s->value)); + + s->value[pScreen->myNum].out = requestor; + s->value[pScreen->myNum].in = cookie.sequence; + + s->property = property; + s->target = target; + + if (property == dmxScreen->incrAtom) + xcb_change_window_attributes (dmxScreen->connection, + requestor, + XCB_CW_EVENT_MASK, + &value); + + dmxAppendSelection (s, &propTail); + + dmxAddSequence (&dmxScreen->request, cookie.sequence); + } + else + { + int i; + + s->value[pScreen->myNum].out = 0; + + for (i = 0; i < dmxNumScreens; i++) + if (s->value[i].out) + break; + + if (i == dmxNumScreens) + dmxSelectionDeleteConv (dmxUnhookSelection (s, + &convHead, + &convTail)); + } + } +} + +Bool +dmxSelectionPropertyNotify (ScreenPtr pScreen, + Window window, + int state, + Atom xProperty, + Time xTime) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Atom property = dmxAtom (dmxScreen, xProperty); + DMXSelection *s; + + if (property != dmxScreen->incrAtom) + return FALSE; + + if (state == XCB_PROPERTY_NEW_VALUE) + { + for (s = propHead; s; s = s->next) + if (s->value[pScreen->myNum].out == window && + s->property == dmxScreen->incrAtom) + break; + + if (s) + { + xcb_get_property_cookie_t cookie = { 0 }; + + cookie = xcb_get_property (dmxScreen->connection, + xFalse, + window, + xProperty, + XCB_GET_PROPERTY_TYPE_ANY, + 0, + 0xffffffff); + + if (cookie.sequence) + { + s->value[pScreen->myNum].in = cookie.sequence; + dmxAddSequence (&dmxScreen->request, cookie.sequence); + dmxSelectionResetTimer (s); + } + else + { + dmxSelectionDeleteProp (dmxUnhookSelection (s, + &propHead, + &propTail)); + } + } + } + else + { + for (s = reqHead; s; s = s->next) + if (s->value[pScreen->myNum].out == window && + s->property == dmxScreen->incrAtom) + break; + + if (s) + { + WindowPtr pWin; + + if (dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + DeleteProperty (serverClient, pWin, s->property); + + dmxSelectionResetTimer (s); + } + } + + return TRUE; +} + +Bool +dmxSelectionPropertyReplyCheck (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply) +{ + DMXSelection *s; + + for (s = propHead; s; s = s->next) + if (s->value[pScreen->myNum].in == sequence) + break; + + if (s) + { + WindowPtr pWin = NullWindow; + xcb_get_property_reply_t *xproperty = + (xcb_get_property_reply_t *) reply; + + if (dixLookupWindow (&pWin, + s->wid, + serverClient, + DixReadAccess) == Success) + { + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + xEvent event; + + event.u.selectionNotify.property = None; + + if (reply->response_type) + { + Atom type = dmxAtom (dmxScreen, xproperty->type); + + /* only 32 bit data types can be translated */ + if (xproperty->format == 32) + { + uint32_t *data = (uint32_t *) (&xproperty[1]); + int i; + + switch (type) { + case XA_ATOM: + for (i = 0; i < xproperty->value_len; i++) + data[i] = dmxAtom (dmxScreen, data[i]); + break; + case XA_BITMAP: + case XA_PIXMAP: + case XA_COLORMAP: + case XA_CURSOR: + case XA_DRAWABLE: + case XA_FONT: + case XA_VISUALID: + case XA_WINDOW: + /* XXX: there's no guarantee that properties of these + types can be converted as all back-end resources + don't exist on this server. + */ + type = 0; + default: + break; + } + } + + if (ValidAtom (type) && + ChangeWindowProperty (pWin, + s->property, + type, + xproperty->format, + PropModeReplace, + xproperty->value_len, + &xproperty[1], + TRUE) == Success) + event.u.selectionNotify.property = s->property; + } + + if (s->selection) + { + event.u.u.type = SelectionNotify | 0x80; + event.u.selectionNotify.time = s->time; + event.u.selectionNotify.requestor = s->wid; + event.u.selectionNotify.selection = s->selection; + event.u.selectionNotify.target = s->target; + + TryClientEvents (wClient (pWin), NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + } + + if (event.u.selectionNotify.property == dmxScreen->incrAtom) + { + /* end of incremental selection transfer when size is 0 */ + if (xproperty->value_len != 0) + { + /* don't send another selection notify event */ + s->selection = None; + dmxSelectionResetTimer (s); + + return TRUE; + } + } + } + + dmxSelectionDeleteProp (dmxUnhookSelection (s, + &propHead, + &propTail)); + + return TRUE; + } + + return FALSE; +} + +void +dmxSelectionRequest (ScreenPtr pScreen, + Window owner, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pChild0, pChildN; + xcb_selection_notify_event_t xevent; + Selection *pSel = NULL; + Atom selection = dmxSelectionAtom (dmxScreen, + xSelection); + + pChild0 = WindowTable[0]; + pChildN = WindowTable[pScreen->myNum]; + + for (;;) + { + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pChildN); + + if (pWinPriv->window == owner) + { + if (ValidAtom (selection)) + dixLookupSelection (&pSel, + selection, + serverClient, + DixReadAccess); + break; + } + + if (pChild0->firstChild) + { + pChild0 = pChild0->firstChild; + pChildN = pChildN->firstChild; + continue; + } + + while (!pChild0->nextSib && (pChild0 != WindowTable[0])) + { + pChild0 = pChild0->parent; + pChildN = pChildN->parent; + } + + if (pChild0 == WindowTable[0]) + break; + + pChild0 = pChild0->nextSib; + pChildN = pChildN->nextSib; + } + + if (pSel) + { + Atom target = dmxAtom (dmxScreen, xTarget); + Atom property = (xProperty) ? dmxAtom (dmxScreen, xProperty) : None; + + if (ValidAtom (target) && ((property == None) || ValidAtom (property))) + { + WindowPtr pProxy = NullWindow; + DMXSelection *s; + int i; + + for (i = 1; i < DMX_N_SELECTION_PROXY; i++) + { + pProxy = dmxScreens[0].pSelectionProxyWin[i]; + + for (s = reqHead; pProxy && s; s = s->next) + if (s->wid == pProxy->drawable.id) + pProxy = NullWindow; + + if (pProxy) + break; + } + + if (pProxy) + { + xEvent event; + + event.u.u.type = SelectionRequest; + event.u.selectionRequest.owner = pSel->window; + event.u.selectionRequest.time = currentTime.milliseconds; + event.u.selectionRequest.requestor = pProxy->drawable.id; + event.u.selectionRequest.selection = selection; + event.u.selectionRequest.target = target; + event.u.selectionRequest.property = property; + + s = xalloc (sizeof (DMXSelection)); + if (s) + { + if (TryClientEvents (pSel->client, NULL, &event, 1, + NoEventMask, + NoEventMask /* CantBeFiltered */, + NullGrab)) + { + int j; + + s->wid = pProxy->drawable.id; + s->requestor = requestor; + s->selection = selection; + s->target = target; + s->property = property; + s->time = xTime; + s->next = 0; + s->timer = 0; + + memset (s->value, 0, sizeof (s->value)); + + for (j = 0; j < dmxNumScreens; j++) + { + WindowPtr pWin = + dmxScreens[j].pSelectionProxyWin[i]; + dmxWinPrivPtr pWinPriv = + DMX_GET_WINDOW_PRIV (pWin); + + s->value[j].in = pWinPriv->window; + if (j == pScreen->myNum) + s->value[j].out = requestor; + } + + dmxAppendSelection (s, &reqTail); + return; + } + + xfree (s); + } + } + else + { + /* TODO: wait for proxy window to become availble */ + dmxLog (dmxWarning, + "dmxSelectionRequest: no proxy window available " + "for conversion of %s selection\n", + NameForAtom (selection)); + } + } + } + + xevent.response_type = XCB_SELECTION_NOTIFY; + xevent.pad0 = 0; + xevent.sequence = 0; + xevent.time = xTime; + xevent.requestor = requestor; + xevent.selection = xSelection; + xevent.target = xTarget; + xevent.property = 0; + + xcb_send_event (dmxScreen->connection, + FALSE, + requestor, + 0, + (const char *) &xevent); + + dmxSync (dmxScreen, FALSE); +} + +void +dmxSelectionPropertyChangeCheck (WindowPtr pWin, + Atom property, + int nUnits) +{ + DMXSelection *s; + + /* check for end of incremental selection conversion */ + for (s = reqHead; s; s = s->next) + if (s->wid == pWin->drawable.id && + dmxScreens[0].incrAtom == property && + nUnits == 0) + break; + + if (s) + dmxSelectionDeleteReq (dmxUnhookSelection (s, + &reqHead, + &reqTail)); +} + +Bool +dmxCreateSelectionProxies (void) +{ + WindowPtr pWin; + WindowPtr pParent; + XID selectionProxyWid; + XID overrideRedirect = TRUE; + int result; + int i; + + for (i = 0; i < DMX_N_SELECTION_PROXY; i++) + { + if (dmxScreens[0].selectionProxyWid[i]) + continue; + + selectionProxyWid = FakeClientID (0); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + PanoramiXRes *newWin; + int j; + + if(!(newWin = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes)))) + return BadAlloc; + + newWin->type = XRT_WINDOW; + newWin->u.win.visibility = VisibilityNotViewable; + newWin->u.win.class = InputOnly; + newWin->u.win.root = FALSE; + newWin->info[0].id = selectionProxyWid; + for(j = 1; j < PanoramiXNumScreens; j++) + newWin->info[j].id = FakeClientID (0); + + FOR_NSCREENS_BACKWARD(j) { + if (i) + pParent = dmxScreens[j].pSelectionProxyWin[0]; + else + pParent = WindowTable[j]; + + pWin = CreateWindow (newWin->info[j].id, pParent, + 0, 0, 1, 1, 0, InputOnly, + CWOverrideRedirect, &overrideRedirect, + 0, serverClient, CopyFromParent, + &result); + if (result != Success) + return FALSE; + if (!AddResource (pWin->drawable.id, RT_WINDOW, pWin)) + return FALSE; + + dmxScreens[j].selectionProxyWid[i] = selectionProxyWid; + dmxScreens[j].pSelectionProxyWin[i] = pWin; + } + + AddResource(newWin->info[0].id, XRT_WINDOW, newWin); + } + else +#endif + + { + if (i) + pParent = dmxScreens[0].pSelectionProxyWin[0]; + else + pParent = WindowTable[0]; + + pWin = CreateWindow (selectionProxyWid, pParent, + 0, 0, 1, 1, 0, InputOnly, + CWOverrideRedirect, &overrideRedirect, + 0, serverClient, CopyFromParent, + &result); + if (result != Success) + return FALSE; + if (!AddResource (pWin->drawable.id, RT_WINDOW, pWin)) + return FALSE; + + dmxScreens[0].selectionProxyWid[i] = selectionProxyWid; + dmxScreens[0].pSelectionProxyWin[i] = pWin; + } + } + + return TRUE; } static int (*dmxSaveProcVector[256]) (ClientPtr); @@ -49,50 +936,78 @@ static int (*dmxSaveProcVector[256]) (ClientPtr); static int dmxProcSetSelectionOwner (ClientPtr client) { - WindowPtr pWin; - Selection *pSel; - int err; + WindowPtr pOld = NullWindow; + WindowPtr pWin; +#ifdef PANORAMIX + PanoramiXRes *win = NULL; +#endif + Selection *pSel; + int err; + int i; + REQUEST(xSetSelectionOwnerReq); + if (dixLookupSelection (&pSel, + stuff->selection, + serverClient, + DixReadAccess) == Success) + pOld = pSel->pWin; + err = (*dmxSaveProcVector[X_SetSelectionOwner]) (client); if (err != Success) return err; - if (dixLookupWindow (&pWin, - stuff->window, - serverClient, - DixReadAccess) != Success || - dixLookupSelection (&pSel, - stuff->selection, - serverClient, - DixReadAccess) != Success) + if (!pSel && dixLookupSelection (&pSel, + stuff->selection, + serverClient, + DixReadAccess) != Success) return Success; + if (pSel->pWin) + { + #ifdef PANORAMIX - if (!noPanoramiXExtension) + if (!noPanoramiXExtension) + win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + pSel->window, + XRT_WINDOW, + DixReadAccess); + else +#endif + dixLookupWindow (&pWin, pSel->window, serverClient, DixReadAccess); + } + else if (!pOld) { - PanoramiXRes *win; - int j; - - if ((win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, - stuff->window, - XRT_WINDOW, - DixReadAccess))) - { - FOR_NSCREENS_FORWARD(j) { - if (dixLookupWindow (&pWin, - win->info[j].id, - serverClient, - DixReadAccess) == Success) - dmxBESetSelectionOwner (pWin, pSel); - } - } - + /* avoid setting selection owner to none on back-end servers + when we're not the current owner */ return Success; } -#endif - dmxBESetSelectionOwner (pWin, pSel); + for (i = 0; i < dmxNumScreens; i++) + { + ScreenPtr pScreen = screenInfo.screens[i]; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + pWin = NullWindow; + if (win) + dixLookupWindow (&pWin, + win->info[i].id, + serverClient, + DixReadAccess); + + dmxBESetSelectionOwner (pScreen, pWin, pSel->selection); + } + else +#endif + { + if (pWin && pWin->drawable.pScreen != pScreen) + continue; + + dmxBESetSelectionOwner (pScreen, pWin, pSel->selection); + } + } return Success; } @@ -100,41 +1015,324 @@ dmxProcSetSelectionOwner (ClientPtr client) static int dmxProcGetSelectionOwner (ClientPtr client) { - int err; + xGetSelectionOwnerReply reply; + Selection *pSel; + int rc; - err = (*dmxSaveProcVector[X_GetSelectionOwner]) (client); - if (err != Success) - return err; + REQUEST(xResourceReq); + REQUEST_SIZE_MATCH(xResourceReq); - return Success; + if (!ValidAtom (stuff->id)) + { + client->errorValue = stuff->id; + return BadAtom; + } + + rc = dixLookupSelection (&pSel, stuff->id, client, DixGetAttrAccess); + if (rc == Success) + { + if (pSel->window != None) + return (*dmxSaveProcVector[X_GetSelectionOwner]) (client); + } + else if (rc != BadMatch) + { + return rc; + } + + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.owner = None; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + unsigned int sequence; + int j; + + FOR_NSCREENS(j) { + dmxBEGetSelectionOwner (screenInfo.screens[j], stuff->id); + } + + do { + dmxDispatch (); + + sequence = 0; + + FOR_NSCREENS_BACKWARD(j) { + DMXScreenInfo *dmxScreen = &dmxScreens[j]; + + if (dmxScreen->getSelectionOwnerResult) + break; + + sequence |= dmxScreen->getSelectionOwner.sequence; + } + } while (sequence && j < 0 && dmxWaitForResponse ()); + + /* at least one back-end server has an owner for this selection */ + if (j >= 0) + reply.owner = dmxScreens[0].selectionProxyWid[0]; + } +#endif + + WriteReplyToClient (client, sizeof (xGetSelectionOwnerReply), &reply); + return client->noClientException; } static int dmxProcConvertSelection (ClientPtr client) { - int err; + DMXSelection *s; + Bool paramsOkay; + xEvent event; + WindowPtr pWin; + Selection *pSel; + int rc; +#ifdef PANORAMIX + PanoramiXRes *win = NULL; + int j; +#endif - err = (*dmxSaveProcVector[X_ConvertSelection]) (client); - if (err != Success) - return err; + REQUEST(xConvertSelectionReq); + REQUEST_SIZE_MATCH(xConvertSelectionReq); - return Success; + rc = dixLookupWindow (&pWin, stuff->requestor, client, DixSetAttrAccess); + if (rc != Success) + return rc; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + if (!(win = (PanoramiXRes *) SecurityLookupIDByType (serverClient, + stuff->requestor, + XRT_WINDOW, + DixReadAccess))) + return BadImplementation; + } +#endif + + paramsOkay = ValidAtom (stuff->selection) && ValidAtom (stuff->target); + paramsOkay &= (stuff->property == None) || ValidAtom (stuff->property); + if (!paramsOkay) + { + client->errorValue = stuff->property; + return BadAtom; + } + + s = xalloc (sizeof (DMXSelection)); + if (!s) + return BadAlloc; + + s->wid = stuff->requestor; + s->requestor = 0; + s->selection = stuff->selection; + s->target = stuff->target; + s->property = stuff->property; + s->time = stuff->time; + s->next = 0; + s->timer = 0; + + memset (s->value, 0, sizeof (s->value)); + + rc = dixLookupSelection (&pSel, stuff->selection, client, DixReadAccess); + if (rc == Success) + { + if (pSel->window != None) + { + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + s->value[j].in = DMX_GET_WINDOW_PRIV (pWin)->window; + } + } + else +#endif + s->value[pWin->drawable.pScreen->myNum].in = + DMX_GET_WINDOW_PRIV (pWin)->window; + + dmxAppendSelection (s, &reqTail); + + return (*dmxSaveProcVector[X_ConvertSelection]) (client); + } + } + else if (rc != BadMatch) + { + xfree (s); + return rc; + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + { + FOR_NSCREENS_FORWARD(j) { + if (dixLookupWindow (&pWin, + win->info[j].id, + serverClient, + DixReadAccess) == Success) + s->value[j].out = dmxBEConvertSelection (pWin, + stuff->selection, + stuff->target, + stuff->property, + stuff->time); + } + } + else +#endif + s->value[pWin->drawable.pScreen->myNum].out = + dmxBEConvertSelection (pWin, + stuff->selection, + stuff->target, + stuff->property, + stuff->time); + + for (j = 0; j < dmxNumScreens; j++) + if (s->value[j].out) + break; + + if (j < dmxNumScreens) + { + dmxAppendSelection (s, &convTail); + + return client->noClientException; + } + + xfree (s); + + event.u.u.type = SelectionNotify; + event.u.selectionNotify.time = stuff->time; + event.u.selectionNotify.requestor = stuff->requestor; + event.u.selectionNotify.selection = stuff->selection; + event.u.selectionNotify.target = stuff->target; + event.u.selectionNotify.property = None; + + TryClientEvents (client, NULL, &event, 1, NoEventMask, + NoEventMask /* CantBeFiltered */, NullGrab); + return client->noClientException; } -void dmxInitSelections (void) +static int +dmxProcSendEvent (ClientPtr client) { - int i; + REQUEST(xSendEventReq); + REQUEST_SIZE_MATCH(xSendEventReq); + + if (stuff->event.u.u.type == SelectionNotify && + stuff->eventMask == NoEventMask && + stuff->destination != PointerWindow && + stuff->destination != InputFocus) + { + Atom property = stuff->event.u.selectionNotify.property; + Atom target = stuff->event.u.selectionNotify.target; + DMXSelection *s; + + if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue)) + { + client->errorValue = stuff->propagate; + return BadValue; + } + + for (s = reqHead; s; s = s->next) + if (s->wid == stuff->destination && + s->selection == stuff->event.u.selectionNotify.selection) + break; + + if (s) + { + int i; + + for (i = 0; i < dmxNumScreens; i++) + { + if (s->value[i].out) + { + xcb_selection_notify_event_t xevent; + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + + xevent.response_type = XCB_SELECTION_NOTIFY; + xevent.pad0 = 0; + xevent.sequence = 0; + xevent.time = s->time; + xevent.requestor = s->requestor; + xevent.selection = dmxBESelectionAtom (dmxScreen, + s->selection); + if (target) + xevent.target = dmxBEAtom (dmxScreen, target); + else + xevent.target = None; + + if (property) + xevent.property = dmxBEAtom (dmxScreen, property); + else + xevent.property = None; + + if (property == dmxScreen->incrAtom) + { + const uint32_t value = XCB_EVENT_MASK_PROPERTY_CHANGE; + + xcb_change_window_attributes (dmxScreen->connection, + s->requestor, + XCB_CW_EVENT_MASK, + &value); + + s->property = dmxScreen->incrAtom; + } + + xcb_send_event (dmxScreen->connection, + FALSE, + s->requestor, + 0, + (const char *) &xevent); + + dmxSync (dmxScreen, FALSE); + + if (property == dmxScreen->incrAtom) + dmxSelectionResetTimer (s); + else + dmxSelectionDeleteReq (dmxUnhookSelection (s, + &reqHead, + &reqTail)); + + return Success; + } + } + + s->property = property; + if (property == dmxScreens[0].incrAtom) + dmxSelectionResetTimer (s); + else + dmxSelectionDeleteReq (dmxUnhookSelection (s, + &reqHead, + &reqTail)); + } + } + + return (*dmxSaveProcVector[X_SendEvent]) (client); +} + +void +dmxInitSelections (void) +{ + int i; for (i = 0; i < 256; i++) dmxSaveProcVector[i] = ProcVector[i]; + ProcVector[X_GetSelectionOwner] = dmxProcGetSelectionOwner; ProcVector[X_SetSelectionOwner] = dmxProcSetSelectionOwner; ProcVector[X_ConvertSelection] = dmxProcConvertSelection; + ProcVector[X_SendEvent] = dmxProcSendEvent; } -void dmxResetSelections (void) +void +dmxResetSelections (void) { - int i; + int i; + for (i = 0; i < 256; i++) ProcVector[i] = dmxSaveProcVector[i]; diff --git a/hw/dmx/dmxselection.h b/hw/dmx/dmxselection.h index a75c575be..ac807adf0 100644 --- a/hw/dmx/dmxselection.h +++ b/hw/dmx/dmxselection.h @@ -27,8 +27,57 @@ #define DMXSELECTION_H #include "dmx.h" +#include "propertyst.h" -extern void dmxInitSelections (void); -extern void dmxResetSelections (void); +Window +dmxBEGetSelectionAdjustedPropertyWindow (WindowPtr pWin); + +void +dmxSelectionClear (ScreenPtr pScreen, + Window owner, + Atom xSelection); + +void +dmxSelectionNotify (ScreenPtr pScreen, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime); + +Bool +dmxSelectionPropertyNotify (ScreenPtr pScreen, + Window requestor, + int state, + Atom xProperty, + Time xTime); + +Bool +dmxSelectionPropertyReplyCheck (ScreenPtr pScreen, + unsigned int sequence, + xcb_generic_reply_t *reply); + +void +dmxSelectionRequest (ScreenPtr pScreen, + Window owner, + Window requestor, + Atom xSelection, + Atom xTarget, + Atom xProperty, + Time xTime); + +void +dmxSelectionPropertyChangeCheck (WindowPtr pWin, + Atom property, + int nUnits); + +Bool +dmxCreateSelectionProxies (void); + +void +dmxInitSelections (void); + +void +dmxResetSelections (void); #endif /* DMXSELECTION_H */ diff --git a/hw/dmx/dmxshm.c b/hw/dmx/dmxshm.c index 8a5969128..f16ec7f51 100644 --- a/hw/dmx/dmxshm.c +++ b/hw/dmx/dmxshm.c @@ -650,12 +650,13 @@ dmxShmInit (ScreenPtr pScreen) return FALSE; } - mask = (GCFunction | GCPlaneMask | GCClipMask); + mask = (GCFunction | GCPlaneMask | GCClipMask | GCGraphicsExposures); - gcvals.function = GXcopy; - gcvals.plane_mask = AllPlanes; - gcvals.clip_mask = None; - gcvals.foreground = 0; + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + gcvals.foreground = 0; + gcvals.graphics_exposures = FALSE; pixmap = xcb_generate_id (dmxScreen->connection); xcb_create_pixmap (dmxScreen->connection, diff --git a/hw/dmx/dmxsync.c b/hw/dmx/dmxsync.c index e2c94c8e3..230bc79ba 100644 --- a/hw/dmx/dmxsync.c +++ b/hw/dmx/dmxsync.c @@ -283,9 +283,8 @@ dmxScreenReplyCheckSync (ScreenPtr pScreen, { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - if (reply->response_type || reply->pad0 != DMX_DETACHED) - if (sequence != dmxScreen->sync.sequence) - return FALSE; + if (sequence != dmxScreen->sync.sequence) + return FALSE; if (dmxScreen->sync.sequence) { diff --git a/hw/dmx/dmxwindow.c b/hw/dmx/dmxwindow.c index a0853f53c..1dcbd4a30 100644 --- a/hw/dmx/dmxwindow.c +++ b/hw/dmx/dmxwindow.c @@ -51,6 +51,7 @@ #include "dmxfont.h" #include "dmxatom.h" #include "dmxprop.h" +#include "dmxselection.h" #ifdef RENDER #include "dmxpict.h" #endif @@ -152,7 +153,7 @@ Window dmxCreateRootWindow(WindowPtr pWindow) XLIB_EPILOGUE (dmxScreen); dmxPropertyWindow (dmxScreen, win); - + return win; } @@ -1347,12 +1348,13 @@ dmxBESetWindowProperty (WindowPtr pWindow, { ScreenPtr pScreen = pWindow->drawable.pScreen; DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pWindow); unsigned char *data = pProp->data; const char *format = NULL; + Window window; int i; - if (!pWinPriv->window) + window = dmxBEGetSelectionAdjustedPropertyWindow (pWindow); + if (!window) return; /* only 32 bit data types can be translated */ @@ -1429,7 +1431,7 @@ dmxBESetWindowProperty (WindowPtr pWindow, XLIB_PROLOGUE (dmxScreen); XChangeProperty (dmxScreen->beDisplay, - pWinPriv->window, + window, dmxBEAtom (dmxScreen, pProp->propertyName), dmxBEAtom (dmxScreen, pProp->type), pProp->format,