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 25 26Copyright 1987, 1989 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46********************************************************/ 47 48#ifdef HAVE_DIX_CONFIG_H 49#include <dix-config.h> 50#endif 51 52#include "windowstr.h" 53#include "dixstruct.h" 54#include "dispatch.h" 55#include "selection.h" 56#include "xace.h" 57 58/***************************************************************** 59 * Selection Stuff 60 * 61 * dixLookupSelection 62 * 63 * Selections are global to the server. The list of selections should 64 * not be traversed directly. Instead, use the functions listed above. 65 * 66 *****************************************************************/ 67 68Selection *CurrentSelections; 69CallbackListPtr SelectionCallback; 70 71int 72dixLookupSelection(Selection **result, Atom selectionName, 73 ClientPtr client, Mask access_mode) 74{ 75 Selection *pSel; 76 int rc = BadMatch; 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 xEvent event; 178 179 /* If the timestamp in client's request is in the past relative 180 to the time stamp indicating the last time the owner of the 181 selection was set, do not set the selection, just return 182 success. */ 183 if (CompareTimeStamps(time, pSel->lastTimeChanged) == EARLIER) 184 return Success; 185 if (pSel->client && (!pWin || (pSel->client != client))) 186 { 187 event.u.u.type = SelectionClear; 188 event.u.selectionClear.time = time.milliseconds; 189 event.u.selectionClear.window = pSel->window; 190 event.u.selectionClear.atom = pSel->selection; 191 WriteEventsToClient(pSel->client, 1, &event); 192 } 193 } 194 else if (rc == BadMatch) 195 { 196 /* 197 * It doesn't exist, so add it... 198 */ 199 pSel = dixAllocateObjectWithPrivates(Selection, PRIVATE_SELECTION); 200 if (!pSel) 201 return BadAlloc; 202 203 pSel->selection = stuff->selection; 204 205 /* security creation/labeling check */ 206 rc = XaceHookSelectionAccess(client, &pSel, 207 DixCreateAccess|DixSetAttrAccess); 208 if (rc != Success) { 209 free(pSel); 210 return rc; 211 } 212 213 pSel->next = CurrentSelections; 214 CurrentSelections = pSel; 215 } 216 else 217 return rc; 218 219 pSel->lastTimeChanged = time; 220 pSel->window = stuff->window; 221 pSel->pWin = pWin; 222 pSel->client = (pWin ? client : NullClient); 223 224 CallSelectionCallback(pSel, client, SelectionSetOwner); 225 return Success; 226} 227 228int 229ProcGetSelectionOwner(ClientPtr client) 230{ 231 int rc; 232 Selection *pSel; 233 xGetSelectionOwnerReply reply; 234 235 REQUEST(xResourceReq); 236 REQUEST_SIZE_MATCH(xResourceReq); 237 238 if (!ValidAtom(stuff->id)) { 239 client->errorValue = stuff->id; 240 return BadAtom; 241 } 242 243 memset(&reply, 0, sizeof(xGetSelectionOwnerReply)); 244 reply.type = X_Reply; 245 reply.length = 0; 246 reply.sequenceNumber = client->sequence; 247 248 rc = dixLookupSelection(&pSel, stuff->id, client, DixGetAttrAccess); 249 if (rc == Success) 250 reply.owner = pSel->window; 251 else if (rc == BadMatch) 252 reply.owner = None; 253 else 254 return rc; 255 256 WriteReplyToClient(client, sizeof(xGetSelectionOwnerReply), &reply); 257 return Success; 258} 259 260int 261ProcConvertSelection(ClientPtr client) 262{ 263 Bool paramsOkay; 264 xEvent event; 265 WindowPtr pWin; 266 Selection *pSel; 267 int rc; 268 269 REQUEST(xConvertSelectionReq); 270 REQUEST_SIZE_MATCH(xConvertSelectionReq); 271 272 rc = dixLookupWindow(&pWin, stuff->requestor, client, DixSetAttrAccess); 273 if (rc != Success) 274 return rc; 275 276 paramsOkay = ValidAtom(stuff->selection) && ValidAtom(stuff->target); 277 paramsOkay &= (stuff->property == None) || ValidAtom(stuff->property); 278 if (!paramsOkay) { 279 client->errorValue = stuff->property; 280 return BadAtom; 281 } 282 283 rc = dixLookupSelection(&pSel, stuff->selection, client, DixReadAccess); 284 285 memset(&event, 0, sizeof(xEvent)); 286 if (rc != Success && rc != BadMatch) 287 return rc; 288 else if (rc == Success && pSel->window != None) { 289 event.u.u.type = SelectionRequest; 290 event.u.selectionRequest.owner = pSel->window; 291 event.u.selectionRequest.time = stuff->time; 292 event.u.selectionRequest.requestor = stuff->requestor; 293 event.u.selectionRequest.selection = stuff->selection; 294 event.u.selectionRequest.target = stuff->target; 295 event.u.selectionRequest.property = stuff->property; 296 if (pSel->client && pSel->client != serverClient && !pSel->client->clientGone) 297 { 298 WriteEventsToClient(pSel->client, 1, &event); 299 return Success; 300 } 301 } 302 303 event.u.u.type = SelectionNotify; 304 event.u.selectionNotify.time = stuff->time; 305 event.u.selectionNotify.requestor = stuff->requestor; 306 event.u.selectionNotify.selection = stuff->selection; 307 event.u.selectionNotify.target = stuff->target; 308 event.u.selectionNotify.property = None; 309 WriteEventsToClient(client, 1, &event); 310 return Success; 311} 312