mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2025-12-20 23:20:03 +01:00
Dynamically create proxy windows as needed. Handle multiple simultaneous selection conversions of the same selection properly.
1539 lines
34 KiB
C
1539 lines
34 KiB
C
/*
|
|
* Copyright © 2008 Novell, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software
|
|
* and its documentation for any purpose is hereby granted without
|
|
* fee, provided that the above copyright notice appear in all copies
|
|
* and that both that copyright notice and this permission notice
|
|
* appear in supporting documentation, and that the name of
|
|
* Novell, Inc. not be used in advertising or publicity pertaining to
|
|
* distribution of the software without specific, written prior permission.
|
|
* Novell, Inc. makes no representations about the suitability of this
|
|
* software for any purpose. It is provided "as is" without express or
|
|
* implied warranty.
|
|
*
|
|
* NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
|
|
* NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Author: David Reveman <davidr@novell.com>
|
|
*/
|
|
|
|
#ifdef HAVE_DMX_CONFIG_H
|
|
#include <dmx-config.h>
|
|
#endif
|
|
|
|
#include "dmx.h"
|
|
#include "dmxlog.h"
|
|
#include "dmxatom.h"
|
|
#include "dmxwindow.h"
|
|
#include "dmxscrinit.h"
|
|
#include "dmxsync.h"
|
|
#include "dmxdnd.h"
|
|
#include "dmxselection.h"
|
|
|
|
#include "selection.h"
|
|
|
|
#ifdef PANORAMIX
|
|
#include "panoramiX.h"
|
|
#include "panoramiXsrv.h"
|
|
#endif
|
|
|
|
#define DMX_SELECTION_TIMEOUT (30 * 1000) /* 30 seconds */
|
|
|
|
typedef struct _DMXSelection {
|
|
struct _DMXSelection *next;
|
|
|
|
XID wid;
|
|
XID requestor;
|
|
Atom selection;
|
|
Atom target;
|
|
Atom property;
|
|
Time time;
|
|
Bool incr;
|
|
|
|
struct {
|
|
unsigned int in;
|
|
unsigned int out;
|
|
} value[MAXSCREENS];
|
|
|
|
OsTimerPtr timer;
|
|
} DMXSelection;
|
|
|
|
static DMXSelection *convHead = NULL;
|
|
static DMXSelection *propHead = NULL;
|
|
static DMXSelection *reqHead = NULL;
|
|
|
|
static DMXSelection *
|
|
dmxUnhookSelection (DMXSelection **head,
|
|
DMXSelection *s)
|
|
{
|
|
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;
|
|
else
|
|
*head = s->next;
|
|
|
|
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->incr && 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)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dmxNumScreens; i++)
|
|
{
|
|
if (s->value[i].out)
|
|
{
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[i];
|
|
const uint32_t value = 0;
|
|
|
|
xcb_change_window_attributes (dmxScreen->connection,
|
|
s->value[i].out,
|
|
XCB_CW_EVENT_MASK,
|
|
&value);
|
|
}
|
|
}
|
|
|
|
if (s->wid)
|
|
{
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
{
|
|
PanoramiXRes *win;
|
|
|
|
win = (PanoramiXRes *) SecurityLookupIDByType (serverClient,
|
|
s->wid,
|
|
XRT_WINDOW,
|
|
DixDestroyAccess);
|
|
|
|
if (win)
|
|
{
|
|
int j;
|
|
|
|
FOR_NSCREENS_BACKWARD(j) {
|
|
FreeResource (win->info[j].id, RT_NONE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
|
|
FreeResource (s->wid, RT_NONE);
|
|
}
|
|
|
|
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;
|
|
|
|
if (time)
|
|
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 (&convHead, s));
|
|
|
|
for (s = propHead; s; s = s->next)
|
|
if (s == r)
|
|
return dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s));
|
|
|
|
for (s = reqHead; s; s = s->next)
|
|
if (s == r)
|
|
return dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
dmxSelectionResetTimer (DMXSelection *s)
|
|
{
|
|
s->timer = TimerSet (s->timer,
|
|
0,
|
|
DMX_SELECTION_TIMEOUT,
|
|
dmxSelectionCallback,
|
|
s);
|
|
}
|
|
|
|
static void
|
|
dmxAppendSelection (DMXSelection **head,
|
|
DMXSelection *s)
|
|
{
|
|
DMXSelection *p, *last;
|
|
|
|
do {
|
|
for (last = NULL, p = *head; p; p = p->next)
|
|
{
|
|
/* avoid duplicates */
|
|
if (p->selection == s->selection &&
|
|
p->requestor == s->requestor)
|
|
{
|
|
if (p->timer)
|
|
TimerCancel (p->timer);
|
|
|
|
dmxSelectionCallback (s->timer, 0, p);
|
|
break;
|
|
}
|
|
|
|
last = p;
|
|
}
|
|
} while (p);
|
|
|
|
dmxSelectionResetTimer (s);
|
|
|
|
if (last)
|
|
last->next = s;
|
|
else
|
|
*head = s;
|
|
}
|
|
|
|
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 void
|
|
dmxSelectionOwnerReply (ScreenPtr pScreen,
|
|
unsigned int sequence,
|
|
xcb_generic_reply_t *reply,
|
|
xcb_generic_error_t *error,
|
|
void *data)
|
|
{
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
|
|
|
|
if (reply)
|
|
{
|
|
xcb_get_selection_owner_reply_t *xselection =
|
|
(xcb_get_selection_owner_reply_t *) reply;
|
|
|
|
dmxScreen->getSelectionOwnerResult = xselection->owner;
|
|
}
|
|
|
|
dmxScreen->getSelectionOwner.sequence = 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));
|
|
|
|
dmxAddRequest (&dmxScreen->request,
|
|
dmxSelectionOwnerReply,
|
|
dmxScreen->getSelectionOwner.sequence,
|
|
0);
|
|
|
|
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->inputOverlayWid;
|
|
pSel->pWin = NULL;
|
|
pSel->client = NullClient;
|
|
|
|
CallCallbacks (&SelectionCallback, &info);
|
|
|
|
pSel->window = None;
|
|
}
|
|
}
|
|
|
|
static void
|
|
dmxSelectionPropertyReply (ScreenPtr pScreen,
|
|
unsigned int sequence,
|
|
xcb_generic_reply_t *reply,
|
|
xcb_generic_error_t *error,
|
|
void *data)
|
|
{
|
|
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)
|
|
{
|
|
Atom type = dmxAtom (dmxScreen, xproperty->type);
|
|
uint32_t *data = xcb_get_property_value (xproperty);
|
|
int length = xcb_get_property_value_length (xproperty);
|
|
|
|
/* only 32 bit data types can be translated */
|
|
if (xproperty->format == 32)
|
|
{
|
|
int i;
|
|
|
|
switch (type) {
|
|
case XA_ATOM:
|
|
for (i = 0; i < length; 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:
|
|
if (type == dmxScreen->atomPairAtom)
|
|
for (i = 0; i < length; i++)
|
|
data[i] = dmxAtom (dmxScreen, data[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ValidAtom (type) &&
|
|
ChangeWindowProperty (pWin,
|
|
s->property,
|
|
type,
|
|
xproperty->format,
|
|
PropModeReplace,
|
|
length,
|
|
data,
|
|
TRUE) == Success)
|
|
event.u.selectionNotify.property = s->property;
|
|
}
|
|
|
|
if (s->target)
|
|
{
|
|
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 (s->incr)
|
|
{
|
|
/* end of incremental selection transfer when size is 0 */
|
|
if (xproperty->value_len != 0)
|
|
{
|
|
/* don't send another selection notify event */
|
|
s->target = None;
|
|
dmxSelectionResetTimer (s);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s));
|
|
}
|
|
}
|
|
|
|
void
|
|
dmxSelectionNotify (ScreenPtr pScreen,
|
|
Window requestor,
|
|
Atom xSelection,
|
|
Atom xTarget,
|
|
Atom xProperty,
|
|
Time xTime)
|
|
{
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
|
|
Atom selection = dmxSelectionAtom (dmxScreen, xSelection);
|
|
DMXSelection *s;
|
|
|
|
for (s = convHead; s; s = s->next)
|
|
if (s->value[pScreen->myNum].out == requestor &&
|
|
s->selection == selection)
|
|
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_STRUCTURE_NOTIFY |
|
|
XCB_EVENT_MASK_PROPERTY_CHANGE;
|
|
|
|
dmxUnhookSelection (&convHead, s);
|
|
|
|
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 (target == dmxScreen->incrAtom)
|
|
s->incr = TRUE;
|
|
|
|
if (s->incr)
|
|
xcb_change_window_attributes (dmxScreen->connection,
|
|
requestor,
|
|
XCB_CW_EVENT_MASK,
|
|
&value);
|
|
|
|
dmxAppendSelection (&propHead, s);
|
|
|
|
dmxAddRequest (&dmxScreen->request,
|
|
dmxSelectionPropertyReply,
|
|
cookie.sequence,
|
|
0);
|
|
}
|
|
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 (&convHead, s));
|
|
}
|
|
}
|
|
}
|
|
|
|
Bool
|
|
dmxSelectionDestroyNotify (ScreenPtr pScreen,
|
|
Window window)
|
|
{
|
|
DMXSelection *s;
|
|
|
|
for (s = reqHead; s; s = s->next)
|
|
if (s->value[pScreen->myNum].out == window)
|
|
break;
|
|
|
|
if (s)
|
|
{
|
|
dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s));
|
|
return TRUE;
|
|
}
|
|
|
|
for (s = propHead; s; s = s->next)
|
|
if (s->value[pScreen->myNum].out == window)
|
|
break;
|
|
|
|
if (s)
|
|
{
|
|
s->value[pScreen->myNum].out = None;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Bool
|
|
dmxSelectionPropertyNotify (ScreenPtr pScreen,
|
|
Window window,
|
|
int state,
|
|
Atom xProperty,
|
|
Time xTime)
|
|
{
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
|
|
DMXSelection *s;
|
|
|
|
if (state == XCB_PROPERTY_NEW_VALUE)
|
|
{
|
|
for (s = propHead; s; s = s->next)
|
|
if (s->value[pScreen->myNum].out == window)
|
|
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;
|
|
dmxAddRequest (&dmxScreen->request,
|
|
dmxSelectionPropertyReply,
|
|
cookie.sequence,
|
|
0);
|
|
dmxSelectionResetTimer (s);
|
|
}
|
|
else
|
|
{
|
|
dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (s = reqHead; s; s = s->next)
|
|
if (s->value[pScreen->myNum].out == window &&
|
|
s->property == dmxAtom (dmxScreen, xProperty))
|
|
break;
|
|
|
|
if (s)
|
|
{
|
|
WindowPtr pWin;
|
|
|
|
if (dixLookupWindow (&pWin,
|
|
s->wid,
|
|
serverClient,
|
|
DixReadAccess) == Success)
|
|
DeleteProperty (serverClient, pWin, s->property);
|
|
|
|
if (s->incr)
|
|
TimerCancel (s->timer);
|
|
else
|
|
dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s));
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
dmxConvertSelection (ScreenPtr pScreen,
|
|
DMXSelection *s,
|
|
Window owner,
|
|
int multipleLength,
|
|
uint32_t *multipleData)
|
|
{
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
|
|
WindowPtr pChild0, pChildN;
|
|
Selection *pSel = NULL;
|
|
|
|
pChild0 = WindowTable[0];
|
|
pChildN = WindowTable[pScreen->myNum];
|
|
|
|
for (;;)
|
|
{
|
|
dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV (pChildN);
|
|
|
|
if (pWinPriv->window == owner)
|
|
{
|
|
dixLookupSelection (&pSel,
|
|
s->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)
|
|
{
|
|
XID overrideRedirect = TRUE;
|
|
WindowPtr pProxy = NullWindow;
|
|
int result;
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
{
|
|
PanoramiXRes *newWin;
|
|
int j;
|
|
|
|
if (!(newWin = (PanoramiXRes *) xalloc (sizeof (PanoramiXRes))))
|
|
return FALSE;
|
|
|
|
newWin->type = XRT_WINDOW;
|
|
newWin->u.win.visibility = VisibilityNotViewable;
|
|
newWin->u.win.class = InputOnly;
|
|
newWin->u.win.root = FALSE;
|
|
for (j = 0; j < PanoramiXNumScreens; j++)
|
|
newWin->info[j].id = FakeClientID (0);
|
|
|
|
FOR_NSCREENS_BACKWARD(j) {
|
|
pProxy = CreateWindow (newWin->info[j].id,
|
|
dmxScreens[j].pInputOverlayWin,
|
|
0, 0, 1, 1, 0, InputOnly,
|
|
CWOverrideRedirect, &overrideRedirect,
|
|
0, serverClient, CopyFromParent,
|
|
&result);
|
|
if (result != Success)
|
|
return FALSE;
|
|
if (!AddResource (pProxy->drawable.id, RT_WINDOW, pProxy))
|
|
return FALSE;
|
|
|
|
s->value[j].in = DMX_GET_WINDOW_PRIV (pProxy)->window;
|
|
}
|
|
|
|
AddResource (newWin->info[0].id, XRT_WINDOW, newWin);
|
|
}
|
|
else
|
|
#endif
|
|
|
|
{
|
|
pProxy = CreateWindow (FakeClientID (0),
|
|
dmxScreens[0].pInputOverlayWin,
|
|
0, 0, 1, 1, 0, InputOnly,
|
|
CWOverrideRedirect, &overrideRedirect,
|
|
0, serverClient, CopyFromParent,
|
|
&result);
|
|
if (result != Success)
|
|
return FALSE;
|
|
if (!AddResource (pProxy->drawable.id, RT_WINDOW, pProxy))
|
|
return FALSE;
|
|
|
|
s->value[0].in = DMX_GET_WINDOW_PRIV (pProxy)->window;
|
|
}
|
|
|
|
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 = s->selection;
|
|
event.u.selectionRequest.target = s->target;
|
|
event.u.selectionRequest.property = s->property;
|
|
|
|
s->wid = pProxy->drawable.id;
|
|
s->requestor = pProxy->drawable.id;
|
|
|
|
if (TryClientEvents (pSel->client, NULL, &event, 1,
|
|
NoEventMask,
|
|
NoEventMask /* CantBeFiltered */,
|
|
NullGrab))
|
|
{
|
|
if (multipleLength)
|
|
ChangeWindowProperty (pProxy,
|
|
s->property,
|
|
dmxScreen->atomPairAtom,
|
|
32,
|
|
PropModeReplace,
|
|
multipleLength,
|
|
multipleData,
|
|
TRUE);
|
|
|
|
dmxAppendSelection (&reqHead, s);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
dmxSelectionDeleteReq (s);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
dmxMultipleTargetPropertyReply (ScreenPtr pScreen,
|
|
unsigned int sequence,
|
|
xcb_generic_reply_t *reply,
|
|
xcb_generic_error_t *error,
|
|
void *data)
|
|
{
|
|
xcb_selection_notify_event_t xevent;
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
|
|
DMXSelection *s = (DMXSelection *) data;
|
|
|
|
if (reply)
|
|
{
|
|
xcb_get_property_reply_t *xproperty =
|
|
(xcb_get_property_reply_t *) reply;
|
|
|
|
if (xproperty->format == 32)
|
|
{
|
|
uint32_t *data = xcb_get_property_value (xproperty);
|
|
int length = xcb_get_property_value_length (xproperty);
|
|
int i;
|
|
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
data[i] = dmxAtom (dmxScreen, data[i]);
|
|
if ((i & 1) == 0 && data[i] == dmxScreen->incrAtom)
|
|
s->incr = TRUE;
|
|
}
|
|
|
|
if (dmxConvertSelection (pScreen, s, s->wid, length, data))
|
|
return;
|
|
}
|
|
}
|
|
|
|
xevent.response_type = XCB_SELECTION_NOTIFY;
|
|
xevent.pad0 = 0;
|
|
xevent.sequence = 0;
|
|
xevent.time = s->time;
|
|
xevent.requestor = s->value[pScreen->myNum].out;
|
|
xevent.selection = dmxBESelectionAtom (dmxScreen, s->selection);
|
|
xevent.target = dmxBEAtom (dmxScreen, s->target);
|
|
xevent.property = 0;
|
|
|
|
xcb_send_event (dmxScreen->connection,
|
|
FALSE,
|
|
s->value[pScreen->myNum].out,
|
|
0,
|
|
(const char *) &xevent);
|
|
|
|
dmxSync (dmxScreen, FALSE);
|
|
|
|
free (s);
|
|
}
|
|
|
|
void
|
|
dmxSelectionRequest (ScreenPtr pScreen,
|
|
Window owner,
|
|
Window requestor,
|
|
Atom xSelection,
|
|
Atom xTarget,
|
|
Atom xProperty,
|
|
Time xTime)
|
|
{
|
|
xcb_selection_notify_event_t xevent;
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
|
|
Atom selection =
|
|
dmxSelectionAtom (dmxScreen, xSelection);
|
|
|
|
if (ValidAtom (selection))
|
|
{
|
|
Atom target = dmxAtom (dmxScreen, xTarget);
|
|
Atom property = (xProperty) ? dmxAtom (dmxScreen, xProperty) : None;
|
|
|
|
if (ValidAtom (target) && ((property == None) || ValidAtom (property)))
|
|
{
|
|
DMXSelection *s;
|
|
|
|
s = xalloc (sizeof (DMXSelection));
|
|
if (s)
|
|
{
|
|
s->wid = 0;
|
|
s->requestor = 0;
|
|
s->selection = selection;
|
|
s->target = target;
|
|
s->property = property;
|
|
s->time = xTime;
|
|
s->incr = FALSE;
|
|
s->next = 0;
|
|
s->timer = 0;
|
|
|
|
memset (s->value, 0, sizeof (s->value));
|
|
|
|
s->value[pScreen->myNum].out = requestor;
|
|
|
|
if (target == dmxScreen->multipleAtom)
|
|
{
|
|
if (ValidAtom (property))
|
|
{
|
|
xcb_get_property_cookie_t prop;
|
|
|
|
prop = xcb_get_property (dmxScreen->connection,
|
|
xFalse,
|
|
requestor,
|
|
xProperty,
|
|
XCB_GET_PROPERTY_TYPE_ANY,
|
|
0,
|
|
0xffffffff);
|
|
|
|
s->wid = owner;
|
|
|
|
dmxAddRequest (&dmxScreen->request,
|
|
dmxMultipleTargetPropertyReply,
|
|
prop.sequence,
|
|
(void *) s);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dmxConvertSelection (pScreen, s, owner, 0, 0))
|
|
return;
|
|
}
|
|
}
|
|
|
|
xfree (s);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
if (nUnits == -1)
|
|
{
|
|
for (s = reqHead; s; s = s->next)
|
|
if (s->requestor == pWin->drawable.id &&
|
|
s->property == property)
|
|
break;
|
|
|
|
if (s)
|
|
{
|
|
if (s->incr)
|
|
TimerCancel (s->timer);
|
|
else
|
|
dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s));
|
|
|
|
return;
|
|
}
|
|
|
|
for (s = propHead; s; s = s->next)
|
|
if (s->requestor == pWin->drawable.id &&
|
|
s->property == property)
|
|
break;
|
|
|
|
if (s && s->incr)
|
|
{
|
|
int i;
|
|
|
|
TimerCancel (s->timer);
|
|
|
|
for (i = 0; i < dmxNumScreens; i++)
|
|
if (s->value[i].out)
|
|
break;
|
|
|
|
/* owner doesn't exist anymore */
|
|
if (i == dmxNumScreens)
|
|
{
|
|
ChangeWindowProperty (pWin,
|
|
s->property,
|
|
XA_ATOM,
|
|
32,
|
|
PropModeReplace,
|
|
0,
|
|
NULL,
|
|
TRUE);
|
|
|
|
dmxSelectionDeleteProp (dmxUnhookSelection (&propHead, s));
|
|
}
|
|
}
|
|
}
|
|
else if (nUnits == 0)
|
|
{
|
|
for (s = reqHead; s; s = s->next)
|
|
if (s->requestor == pWin->drawable.id &&
|
|
s->property == property)
|
|
break;
|
|
|
|
/* end of incremental selection conversion */
|
|
if (s && s->incr)
|
|
dmxSelectionDeleteReq (dmxUnhookSelection (&reqHead, s));
|
|
}
|
|
}
|
|
|
|
static int (*dmxSaveProcVector[256]) (ClientPtr);
|
|
|
|
static int
|
|
dmxProcSetSelectionOwner (ClientPtr client)
|
|
{
|
|
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 (!pSel && dixLookupSelection (&pSel,
|
|
stuff->selection,
|
|
serverClient,
|
|
DixReadAccess) != Success)
|
|
return Success;
|
|
|
|
if (pSel->pWin)
|
|
{
|
|
|
|
#ifdef PANORAMIX
|
|
if (!noPanoramiXExtension)
|
|
win = (PanoramiXRes *) SecurityLookupIDByType (serverClient,
|
|
pSel->window,
|
|
XRT_WINDOW,
|
|
DixReadAccess);
|
|
else
|
|
#endif
|
|
dixLookupWindow (&pWin, pSel->window, serverClient, DixReadAccess);
|
|
}
|
|
else if (!pOld)
|
|
{
|
|
/* avoid setting selection owner to none on back-end servers
|
|
when we're not the current owner */
|
|
return Success;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static int
|
|
dmxProcGetSelectionOwner (ClientPtr client)
|
|
{
|
|
xGetSelectionOwnerReply reply;
|
|
Selection *pSel;
|
|
int rc;
|
|
|
|
REQUEST(xResourceReq);
|
|
REQUEST_SIZE_MATCH(xResourceReq);
|
|
|
|
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].inputOverlayWid;
|
|
}
|
|
#endif
|
|
|
|
WriteReplyToClient (client, sizeof (xGetSelectionOwnerReply), &reply);
|
|
return client->noClientException;
|
|
}
|
|
|
|
static int
|
|
dmxProcConvertSelection (ClientPtr client)
|
|
{
|
|
DMXSelection *s;
|
|
Bool paramsOkay;
|
|
xEvent event;
|
|
WindowPtr pWin;
|
|
Selection *pSel;
|
|
int rc;
|
|
#ifdef PANORAMIX
|
|
PanoramiXRes *win = NULL;
|
|
int j;
|
|
#endif
|
|
|
|
REQUEST(xConvertSelectionReq);
|
|
REQUEST_SIZE_MATCH(xConvertSelectionReq);
|
|
|
|
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 = 0;
|
|
s->requestor = stuff->requestor;
|
|
s->selection = stuff->selection;
|
|
s->target = stuff->target;
|
|
s->property = stuff->property;
|
|
s->time = stuff->time;
|
|
s->incr = FALSE;
|
|
s->next = 0;
|
|
s->timer = 0;
|
|
|
|
memset (s->value, 0, sizeof (s->value));
|
|
|
|
if (stuff->target == dmxScreens[0].multipleAtom)
|
|
{
|
|
PropertyPtr pProp;
|
|
|
|
if (dixLookupProperty (&pProp,
|
|
pWin,
|
|
stuff->property,
|
|
serverClient,
|
|
DixReadAccess) == Success &&
|
|
pProp->format == 32)
|
|
{
|
|
Atom *data = (Atom *) pProp->data;
|
|
int i;
|
|
|
|
for (i = 0; i < pProp->size; i++)
|
|
if ((i & 1) == 0 && data[i] == dmxScreens[0].incrAtom)
|
|
s->incr = TRUE;
|
|
}
|
|
}
|
|
|
|
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 (&reqHead, s);
|
|
|
|
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)
|
|
{
|
|
s->wid = stuff->requestor;
|
|
|
|
dmxAppendSelection (&convHead, s);
|
|
|
|
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;
|
|
}
|
|
|
|
static int
|
|
dmxProcSendEvent (ClientPtr client)
|
|
{
|
|
REQUEST(xSendEventReq);
|
|
REQUEST_SIZE_MATCH(xSendEventReq);
|
|
|
|
if ((stuff->propagate != xFalse) && (stuff->propagate != xTrue))
|
|
{
|
|
client->errorValue = stuff->propagate;
|
|
return BadValue;
|
|
}
|
|
|
|
switch (stuff->event.u.u.type) {
|
|
case SelectionNotify:
|
|
if (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;
|
|
|
|
for (s = reqHead; s; s = s->next)
|
|
if (s->requestor == stuff->destination &&
|
|
s->selection == stuff->event.u.selectionNotify.selection)
|
|
break;
|
|
|
|
if (s)
|
|
{
|
|
int i;
|
|
|
|
if (target == dmxScreens[0].incrAtom)
|
|
s->incr = TRUE;
|
|
|
|
s->property = property;
|
|
|
|
for (i = 0; i < dmxNumScreens; i++)
|
|
{
|
|
xcb_selection_notify_event_t xevent;
|
|
DMXScreenInfo *dmxScreen = &dmxScreens[i];
|
|
const uint32_t value =
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
|
XCB_EVENT_MASK_PROPERTY_CHANGE;
|
|
|
|
if (!s->value[i].out)
|
|
continue;
|
|
|
|
xevent.response_type = XCB_SELECTION_NOTIFY;
|
|
xevent.pad0 = 0;
|
|
xevent.sequence = 0;
|
|
xevent.time = s->time;
|
|
xevent.requestor = s->value[i].out;
|
|
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;
|
|
|
|
xcb_change_window_attributes (dmxScreen->connection,
|
|
s->value[i].out,
|
|
XCB_CW_EVENT_MASK,
|
|
&value);
|
|
|
|
xcb_send_event (dmxScreen->connection,
|
|
FALSE,
|
|
s->value[i].out,
|
|
0,
|
|
(const char *) &xevent);
|
|
|
|
dmxSync (dmxScreen, FALSE);
|
|
|
|
dmxSelectionResetTimer (s);
|
|
return client->noClientException;
|
|
}
|
|
|
|
dmxSelectionResetTimer (s);
|
|
}
|
|
}
|
|
break;
|
|
case ClientMessage:
|
|
if (stuff->event.u.u.detail != 8 &&
|
|
stuff->event.u.u.detail != 16 &&
|
|
stuff->event.u.u.detail != 32)
|
|
{
|
|
client->errorValue = stuff->event.u.u.detail;
|
|
return BadValue;
|
|
}
|
|
|
|
if (stuff->destination == dmxScreens[0].inputOverlayWid)
|
|
dmxDnDClientMessageEvent (&stuff->event);
|
|
|
|
break;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < 256; i++)
|
|
ProcVector[i] = dmxSaveProcVector[i];
|
|
}
|