Proper support for selection conversion with MULTIPLE target.

This commit is contained in:
David Reveman 2008-10-18 18:17:40 -04:00
parent 9d27235e93
commit 4c6c7db673
4 changed files with 201 additions and 87 deletions

View file

@ -204,7 +204,7 @@ typedef struct _DMXScreenInfo {
int beShmEventBase;
#endif
Display *beAttachedDisplay; /**< Disabld X server's display */
Display *beAttachedDisplay; /**< Disabled X server's display */
char *authType;
int authTypeLen;
@ -239,6 +239,8 @@ typedef struct _DMXScreenInfo {
Window getSelectionOwnerResult;
XID selectionProxyWid[DMX_N_SELECTION_PROXY];
WindowPtr pSelectionProxyWin[DMX_N_SELECTION_PROXY];
Atom multipleAtom;
Atom atomPairAtom;
Atom incrAtom;
/*---------- DnD information ----------*/

View file

@ -1113,11 +1113,14 @@ void OsVendorInit(void)
{
if (!dmxPropTrans)
{
dmxPropTrans = xalloc (sizeof (DMXPropTrans));
dmxPropTrans->name = "_COMPIZ_WINDOW_DECOR";
dmxPropTrans->format = "xP";
dmxPropTrans->type = 0;
dmxPropTransNum = 1;
dmxPropTrans = xalloc (sizeof (DMXPropTrans) * 2);
dmxPropTrans[0].name = "ATOM_PAIR";
dmxPropTrans[0].format = "aa..";
dmxPropTrans[0].type = 0;
dmxPropTrans[1].name = "_COMPIZ_WINDOW_DECOR";
dmxPropTrans[1].format = "xP";
dmxPropTrans[1].type = 0;
dmxPropTransNum = 2;
}
if (!dmxSelectionMap)

View file

@ -1036,6 +1036,8 @@ Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[])
dmxScreen->rootEventMask = ExposureMask | StructureNotifyMask |
SubstructureRedirectMask;
dmxScreen->multipleAtom = MakeAtom ("MULTIPLE", strlen ("MULTIPLE"), TRUE);
dmxScreen->atomPairAtom = MakeAtom ("ATOM_PAIR", strlen ("ATOM_PAIR"), TRUE);
dmxScreen->incrAtom = MakeAtom ("INCR", strlen ("INCR"), TRUE);
if (!dmxInitGC(pScreen)) return FALSE;

View file

@ -493,6 +493,9 @@ dmxSelectionPropertyReply (ScreenPtr pScreen,
*/
type = 0;
default:
if (type == dmxScreen->atomPairAtom)
for (i = 0; i < length; i++)
data[i] = dmxAtom (dmxScreen, data[i]);
break;
}
}
@ -710,21 +713,16 @@ dmxSelectionPropertyNotify (ScreenPtr pScreen,
return TRUE;
}
void
dmxSelectionRequest (ScreenPtr pScreen,
Window owner,
Window requestor,
Atom xSelection,
Atom xTarget,
Atom xProperty,
Time xTime)
static Bool
dmxConvertSelection (ScreenPtr pScreen,
DMXSelection *s,
Window owner,
int multipleLength,
uint32_t *multipleData)
{
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
WindowPtr pChild0, pChildN;
xcb_selection_notify_event_t xevent;
Selection *pSel = NULL;
Atom selection = dmxSelectionAtom (dmxScreen,
xSelection);
DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
WindowPtr pChild0, pChildN;
Selection *pSel = NULL;
pChild0 = WindowTable[0];
pChildN = WindowTable[pScreen->myNum];
@ -735,11 +733,10 @@ dmxSelectionRequest (ScreenPtr pScreen,
if (pWinPriv->window == owner)
{
if (ValidAtom (selection))
dixLookupSelection (&pSel,
selection,
serverClient,
DixReadAccess);
dixLookupSelection (&pSel,
s->selection,
serverClient,
DixReadAccess);
break;
}
@ -764,88 +761,198 @@ dmxSelectionRequest (ScreenPtr pScreen,
}
if (pSel)
{
WindowPtr pProxy = NullWindow;
int i;
for (i = 1; i < DMX_N_SELECTION_PROXY; i++)
{
DMXSelection *r;
pProxy = dmxScreens[0].pSelectionProxyWin[i];
for (r = reqHead; pProxy && r; r = r->next)
if (r->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 = s->selection;
event.u.selectionRequest.target = s->target;
event.u.selectionRequest.property = s->property;
if (TryClientEvents (pSel->client, NULL, &event, 1,
NoEventMask,
NoEventMask /* CantBeFiltered */,
NullGrab))
{
int j;
s->wid = pProxy->drawable.id;
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 (multipleLength)
ChangeWindowProperty (pProxy,
s->property,
dmxScreen->atomPairAtom,
32,
PropModeReplace,
multipleLength,
multipleData,
TRUE);
dmxAppendSelection (&reqHead, s);
return TRUE;
}
}
else
{
/* TODO: wait for proxy window to become available */
dmxLog (dmxWarning,
"dmxSelectionRequest: no proxy window available "
"for conversion of %s selection\n",
NameForAtom (s->selection));
}
}
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 (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->requestor;
xevent.selection = dmxBESelectionAtom (dmxScreen, s->selection);
xevent.target = dmxBEAtom (dmxScreen, s->target);
xevent.property = 0;
xcb_send_event (dmxScreen->connection,
FALSE,
s->requestor,
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)))
{
WindowPtr pProxy = NullWindow;
DMXSelection *s;
int i;
for (i = 1; i < DMX_N_SELECTION_PROXY; i++)
s = xalloc (sizeof (DMXSelection));
if (s)
{
pProxy = dmxScreens[0].pSelectionProxyWin[i];
s->wid = 0;
s->requestor = requestor;
s->selection = selection;
s->target = target;
s->property = property;
s->time = xTime;
s->next = 0;
s->timer = 0;
for (s = reqHead; pProxy && s; s = s->next)
if (s->wid == pProxy->drawable.id)
pProxy = NullWindow;
memset (s->value, 0, sizeof (s->value));
if (pProxy)
break;
}
s->value[pScreen->myNum].out = requestor;
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 (target == dmxScreen->multipleAtom)
{
if (TryClientEvents (pSel->client, NULL, &event, 1,
NoEventMask,
NoEventMask /* CantBeFiltered */,
NullGrab))
if (ValidAtom (property))
{
int j;
xcb_get_property_cookie_t prop;
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;
prop = xcb_get_property (dmxScreen->connection,
xFalse,
requestor,
xProperty,
XCB_GET_PROPERTY_TYPE_ANY,
0,
0xffffffff);
memset (s->value, 0, sizeof (s->value));
s->wid = owner;
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 (&reqHead, s);
return;
dmxAddRequest (&dmxScreen->request,
dmxMultipleTargetPropertyReply,
prop.sequence,
(void *) s);
}
xfree (s);
}
else
{
if (dmxConvertSelection (pScreen, s, owner, 0, 0))
return;
}
}
else
{
/* TODO: wait for proxy window to become available */
dmxLog (dmxWarning,
"dmxSelectionRequest: no proxy window available "
"for conversion of %s selection\n",
NameForAtom (selection));
}
xfree (s);
}
}