selection.c revision 1b5d61b8
1/************************************************************ 2 3Copyright 1987, 1989, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Digital not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 44 45********************************************************/ 46 47#ifdef HAVE_DIX_CONFIG_H 48#include <dix-config.h> 49#endif 50 51#include "windowstr.h" 52#include "dixstruct.h" 53#include "dispatch.h" 54#include "selection.h" 55#include "xace.h" 56 57/***************************************************************** 58 * Selection Stuff 59 * 60 * dixLookupSelection 61 * 62 * Selections are global to the server. The list of selections should 63 * not be traversed directly. Instead, use the functions listed above. 64 * 65 *****************************************************************/ 66 67Selection *CurrentSelections; 68CallbackListPtr SelectionCallback; 69 70int 71dixLookupSelection(Selection ** result, Atom selectionName, 72 ClientPtr client, Mask access_mode) 73{ 74 Selection *pSel; 75 int rc = BadMatch; 76 77 client->errorValue = selectionName; 78 79 for (pSel = CurrentSelections; pSel; pSel = pSel->next) 80 if (pSel->selection == selectionName) 81 break; 82 83 if (pSel) 84 rc = XaceHookSelectionAccess(client, &pSel, access_mode); 85 *result = pSel; 86 return rc; 87} 88 89void 90InitSelections(void) 91{ 92 Selection *pSel, *pNextSel; 93 94 pSel = CurrentSelections; 95 while (pSel) { 96 pNextSel = pSel->next; 97 dixFreeObjectWithPrivates(pSel, PRIVATE_SELECTION); 98 pSel = pNextSel; 99 } 100 101 CurrentSelections = NULL; 102} 103 104static _X_INLINE void 105CallSelectionCallback(Selection * pSel, ClientPtr client, 106 SelectionCallbackKind kind) 107{ 108 SelectionInfoRec info = { pSel, client, kind }; 109 CallCallbacks(&SelectionCallback, &info); 110} 111 112void 113DeleteWindowFromAnySelections(WindowPtr pWin) 114{ 115 Selection *pSel; 116 117 for (pSel = CurrentSelections; pSel; pSel = pSel->next) 118 if (pSel->pWin == pWin) { 119 CallSelectionCallback(pSel, NULL, SelectionWindowDestroy); 120 121 pSel->pWin = (WindowPtr) NULL; 122 pSel->window = None; 123 pSel->client = NullClient; 124 } 125} 126 127void 128DeleteClientFromAnySelections(ClientPtr client) 129{ 130 Selection *pSel; 131 132 for (pSel = CurrentSelections; pSel; pSel = pSel->next) 133 if (pSel->client == client) { 134 CallSelectionCallback(pSel, NULL, SelectionClientClose); 135 136 pSel->pWin = (WindowPtr) NULL; 137 pSel->window = None; 138 pSel->client = NullClient; 139 } 140} 141 142int 143ProcSetSelectionOwner(ClientPtr client) 144{ 145 WindowPtr pWin = NULL; 146 TimeStamp time; 147 Selection *pSel; 148 int rc; 149 150 REQUEST(xSetSelectionOwnerReq); 151 REQUEST_SIZE_MATCH(xSetSelectionOwnerReq); 152 153 UpdateCurrentTime(); 154 time = ClientTimeToServerTime(stuff->time); 155 156 /* If the client's time stamp is in the future relative to the server's 157 time stamp, do not set the selection, just return success. */ 158 if (CompareTimeStamps(time, currentTime) == LATER) 159 return Success; 160 161 if (stuff->window != None) { 162 rc = dixLookupWindow(&pWin, stuff->window, client, DixSetAttrAccess); 163 if (rc != Success) 164 return rc; 165 } 166 if (!ValidAtom(stuff->selection)) { 167 client->errorValue = stuff->selection; 168 return BadAtom; 169 } 170 171 /* 172 * First, see if the selection is already set... 173 */ 174 rc = dixLookupSelection(&pSel, stuff->selection, client, DixSetAttrAccess); 175 176 if (rc == Success) { 177 /* If the timestamp in client's request is in the past relative 178 to the time stamp indicating the last time the owner of the 179 selection was set, do not set the selection, just return 180 success. */ 181 if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER) 182 return Success; 183 if (pSel->client && (!pWin || (pSel->client != client))) { 184 xEvent event = { 185 .u.selectionClear.time = time.milliseconds, 186 .u.selectionClear.window = pSel->window, 187 .u.selectionClear.atom = pSel->selection 188 }; 189 event.u.u.type = SelectionClear; 190 WriteEventsToClient(pSel->client, 1, &event); 191 } 192 } 193 else if (rc == BadMatch) { 194 /* 195 * It doesn't exist, so add it... 196 */ 197 pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION); 198 if (!pSel) 199 return BadAlloc; 200 201 pSel->selection = stuff->selection; 202 203 /* security creation/labeling check */ 204 rc = XaceHookSelectionAccess(client, &pSel, 205 DixCreateAccess | DixSetAttrAccess); 206 if (rc != Success) { 207 free(pSel); 208 return rc; 209 } 210 211 pSel->next = CurrentSelections; 212 CurrentSelections = pSel; 213 } 214 else 215 return rc; 216 217 pSel->lastTimeChanged = time; 218 pSel->window = stuff->window; 219 pSel->pWin = pWin; 220 pSel->client = (pWin ? client : NullClient); 221 222 CallSelectionCallback(pSel, client, SelectionSetOwner); 223 return Success; 224} 225 226int 227ProcGetSelectionOwner(ClientPtr client) 228{ 229 int rc; 230 Selection *pSel; 231 xGetSelectionOwnerReply reply; 232 233 REQUEST(xResourceReq); 234 REQUEST_SIZE_MATCH(xResourceReq); 235 236 if (!ValidAtom(stuff->id)) { 237 client->errorValue = stuff->id; 238 return BadAtom; 239 } 240 241 reply = (xGetSelectionOwnerReply) { 242 .type = X_Reply, 243 .sequenceNumber = client->sequence, 244 .length = 0, 245 }; 246 247 rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess); 248 if (rc == Success) 249 reply.owner = pSel->window; 250 else if (rc == BadMatch) 251 reply.owner = None; 252 else 253 return rc; 254 255 WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply); 256 return Success; 257} 258 259int 260ProcConvertSelection(ClientPtr client) 261{ 262 Bool paramsOkay; 263 xEvent event; 264 WindowPtr pWin; 265 Selection *pSel; 266 int rc; 267 268 REQUEST(xConvertSelectionReq); 269 REQUEST_SIZE_MATCH(xConvertSelectionReq); 270 271 rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess); 272 if (rc != Success) 273 return rc; 274 275 paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target); 276 paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property); 277 if (!paramsOkay) { 278 client->errorValue = stuff->property; 279 return BadAtom; 280 } 281 282 if (stuff->time == CurrentTime) 283 UpdateCurrentTime(); 284 285 rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess); 286 287 memset(&event, 0, sizeof(xEvent)); 288 if (rc != Success && rc != BadMatch) 289 return rc; 290 else if (rc == Success && pSel->window != None) { 291 event.u.u.type = SelectionRequest; 292 event.u.selectionRequest.owner = pSel->window; 293 event.u.selectionRequest.time = stuff->time; 294 event.u.selectionRequest.requestor = stuff->requestor; 295 event.u.selectionRequest.selection = stuff->selection; 296 event.u.selectionRequest.target = stuff->target; 297 event.u.selectionRequest.property = stuff->property; 298 if (pSel->client && pSel->client != serverClient && 299 !pSel->client->clientGone) { 300 WriteEventsToClient(pSel->client, 1, &event); 301 return Success; 302 } 303 } 304 305 event.u.u.type = SelectionNotify; 306 event.u.selectionNotify.time = stuff->time; 307 event.u.selectionNotify.requestor = stuff->requestor; 308 event.u.selectionNotify.selection = stuff->selection; 309 event.u.selectionNotify.target = stuff->target; 310 event.u.selectionNotify.property = None; 311 WriteEventsToClient(client, 1, &event); 312 return Success; 313} 314