1/* WindowsWM extension is based on AppleWM extension */ 2/************************************************************************** 3 4Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. 5Copyright (c) 2003 Torrey T. Lyons. All Rights Reserved. 6 7Permission is hereby granted, free of charge, to any person obtaining a 8copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sub license, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice (including the 16next paragraph) shall be included in all copies or substantial portions 17of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 27**************************************************************************/ 28 29#ifdef HAVE_XWIN_CONFIG_H 30#include <xwin-config.h> 31#endif 32#include "win.h" 33 34#include "misc.h" 35#include "dixstruct.h" 36#include "extnsionst.h" 37#include "colormapst.h" 38#include "cursorstr.h" 39#include "scrnintstr.h" 40#include "servermd.h" 41#include "swaprep.h" 42#define _WINDOWSWM_SERVER_ 43#include <X11/extensions/windowswmstr.h> 44#include "protocol-versions.h" 45 46static int WMErrorBase; 47static unsigned char WMReqCode = 0; 48static int WMEventBase = 0; 49 50static RESTYPE ClientType, eventResourceType; /* resource types for event masks */ 51static XID eventResource; 52 53/* Currently selected events */ 54static unsigned int eventMask = 0; 55 56static int WMFreeClient (pointer data, XID id); 57static int WMFreeEvents (pointer data, XID id); 58static void SNotifyEvent(xWindowsWMNotifyEvent *from, xWindowsWMNotifyEvent *to); 59 60typedef struct _WMEvent *WMEventPtr; 61typedef struct _WMEvent { 62 WMEventPtr next; 63 ClientPtr client; 64 XID clientResource; 65 unsigned int mask; 66} WMEventRec; 67 68static inline BoxRec 69make_box (int x, int y, int w, int h) 70{ 71 BoxRec r; 72 r.x1 = x; 73 r.y1 = y; 74 r.x2 = x + w; 75 r.y2 = y + h; 76 return r; 77} 78 79static int 80ProcWindowsWMQueryVersion(ClientPtr client) 81{ 82 xWindowsWMQueryVersionReply rep; 83 int n; 84 85 REQUEST_SIZE_MATCH(xWindowsWMQueryVersionReq); 86 rep.type = X_Reply; 87 rep.length = 0; 88 rep.sequenceNumber = client->sequence; 89 rep.majorVersion = SERVER_WINDOWSWM_MAJOR_VERSION; 90 rep.minorVersion = SERVER_WINDOWSWM_MINOR_VERSION; 91 rep.patchVersion = SERVER_WINDOWSWM_PATCH_VERSION; 92 if (client->swapped) 93 { 94 swaps(&rep.sequenceNumber, n); 95 swapl(&rep.length, n); 96 } 97 WriteToClient(client, sizeof(xWindowsWMQueryVersionReply), (char *)&rep); 98 return Success; 99} 100 101 102/* events */ 103 104static inline void 105updateEventMask (WMEventPtr *pHead) 106{ 107 WMEventPtr pCur; 108 109 eventMask = 0; 110 for (pCur = *pHead; pCur != NULL; pCur = pCur->next) 111 eventMask |= pCur->mask; 112} 113 114/*ARGSUSED*/ 115static int 116WMFreeClient (pointer data, XID id) 117{ 118 WMEventPtr pEvent; 119 WMEventPtr *pHead, pCur, pPrev; 120 121 pEvent = (WMEventPtr) data; 122 dixLookupResourceByType((pointer) &pHead, eventResource, eventResourceType, 123 NullClient, DixUnknownAccess); 124 if (pHead) 125 { 126 pPrev = 0; 127 for (pCur = *pHead; pCur && pCur != pEvent; pCur=pCur->next) 128 pPrev = pCur; 129 if (pCur) 130 { 131 if (pPrev) 132 pPrev->next = pEvent->next; 133 else 134 *pHead = pEvent->next; 135 } 136 updateEventMask (pHead); 137 } 138 free((pointer) pEvent); 139 return 1; 140} 141 142/*ARGSUSED*/ 143static int 144WMFreeEvents (pointer data, XID id) 145{ 146 WMEventPtr *pHead, pCur, pNext; 147 148 pHead = (WMEventPtr *) data; 149 for (pCur = *pHead; pCur; pCur = pNext) 150 { 151 pNext = pCur->next; 152 FreeResource (pCur->clientResource, ClientType); 153 free((pointer) pCur); 154 } 155 free((pointer) pHead); 156 eventMask = 0; 157 return 1; 158} 159 160static int 161ProcWindowsWMSelectInput (ClientPtr client) 162{ 163 REQUEST(xWindowsWMSelectInputReq); 164 WMEventPtr pEvent, pNewEvent, *pHead; 165 XID clientResource; 166 167 REQUEST_SIZE_MATCH (xWindowsWMSelectInputReq); 168 dixLookupResourceByType((pointer) &pHead, eventResource, eventResourceType, client, DixWriteAccess); 169 if (stuff->mask != 0) 170 { 171 if (pHead) 172 { 173 /* check for existing entry. */ 174 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) 175 { 176 if (pEvent->client == client) 177 { 178 pEvent->mask = stuff->mask; 179 updateEventMask (pHead); 180 return Success; 181 } 182 } 183 } 184 185 /* build the entry */ 186 pNewEvent = (WMEventPtr) malloc(sizeof (WMEventRec)); 187 if (!pNewEvent) 188 return BadAlloc; 189 pNewEvent->next = 0; 190 pNewEvent->client = client; 191 pNewEvent->mask = stuff->mask; 192 /* 193 * add a resource that will be deleted when 194 * the client goes away 195 */ 196 clientResource = FakeClientID (client->index); 197 pNewEvent->clientResource = clientResource; 198 if (!AddResource (clientResource, ClientType, (pointer)pNewEvent)) 199 return BadAlloc; 200 /* 201 * create a resource to contain a pointer to the list 202 * of clients selecting input. This must be indirect as 203 * the list may be arbitrarily rearranged which cannot be 204 * done through the resource database. 205 */ 206 if (!pHead) 207 { 208 pHead = (WMEventPtr *) malloc(sizeof (WMEventPtr)); 209 if (!pHead || 210 !AddResource (eventResource, eventResourceType, (pointer)pHead)) 211 { 212 FreeResource (clientResource, RT_NONE); 213 return BadAlloc; 214 } 215 *pHead = 0; 216 } 217 pNewEvent->next = *pHead; 218 *pHead = pNewEvent; 219 updateEventMask (pHead); 220 } 221 else if (stuff->mask == 0) 222 { 223 /* delete the interest */ 224 if (pHead) 225 { 226 pNewEvent = 0; 227 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) 228 { 229 if (pEvent->client == client) 230 break; 231 pNewEvent = pEvent; 232 } 233 if (pEvent) 234 { 235 FreeResource (pEvent->clientResource, ClientType); 236 if (pNewEvent) 237 pNewEvent->next = pEvent->next; 238 else 239 *pHead = pEvent->next; 240 free(pEvent); 241 updateEventMask (pHead); 242 } 243 } 244 } 245 else 246 { 247 client->errorValue = stuff->mask; 248 return BadValue; 249 } 250 return Success; 251} 252 253/* 254 * deliver the event 255 */ 256 257void 258winWindowsWMSendEvent (int type, unsigned int mask, int which, int arg, 259 Window window, int x, int y, int w, int h) 260{ 261 WMEventPtr *pHead, pEvent; 262 ClientPtr client; 263 xWindowsWMNotifyEvent se; 264#if CYGMULTIWINDOW_DEBUG 265 ErrorF ("winWindowsWMSendEvent %d %d %d %d, %d %d - %d %d\n", 266 type, mask, which, arg, x, y, w, h); 267#endif 268 dixLookupResourceByType((pointer) &pHead, eventResource, eventResourceType, 269 NullClient, DixUnknownAccess); 270 if (!pHead) 271 return; 272 for (pEvent = *pHead; pEvent; pEvent = pEvent->next) 273 { 274 client = pEvent->client; 275#if CYGMULTIWINDOW_DEBUG 276 ErrorF ("winWindowsWMSendEvent - x%08x\n", (int) client); 277#endif 278 if ((pEvent->mask & mask) == 0) 279 { 280 continue; 281 } 282#if CYGMULTIWINDOW_DEBUG 283 ErrorF ("winWindowsWMSendEvent - send\n"); 284#endif 285 se.type = type + WMEventBase; 286 se.kind = which; 287 se.window = window; 288 se.arg = arg; 289 se.x = x; 290 se.y = y; 291 se.w = w; 292 se.h = h; 293 se.time = currentTime.milliseconds; 294 WriteEventsToClient (client, 1, (xEvent *) &se); 295 } 296} 297 298/* general utility functions */ 299 300static int 301ProcWindowsWMDisableUpdate (ClientPtr client) 302{ 303 REQUEST_SIZE_MATCH(xWindowsWMDisableUpdateReq); 304 305 //winDisableUpdate(); 306 307 return Success; 308} 309 310static int 311ProcWindowsWMReenableUpdate (ClientPtr client) 312{ 313 REQUEST_SIZE_MATCH(xWindowsWMReenableUpdateReq); 314 315 //winEnableUpdate(); 316 317 return Success; 318} 319 320 321/* window functions */ 322 323static int 324ProcWindowsWMSetFrontProcess (ClientPtr client) 325{ 326 REQUEST_SIZE_MATCH(xWindowsWMSetFrontProcessReq); 327 328 //QuartzMessageMainThread(kWindowsSetFrontProcess, NULL, 0); 329 330 return Success; 331} 332 333 334/* frame functions */ 335 336static int 337ProcWindowsWMFrameGetRect (ClientPtr client) 338{ 339 xWindowsWMFrameGetRectReply rep; 340 BoxRec ir; 341 RECT rcNew; 342 REQUEST(xWindowsWMFrameGetRectReq); 343 344#if CYGMULTIWINDOW_DEBUG 345 ErrorF ("ProcWindowsWMFrameGetRect %d %d\n", 346 (sizeof(xWindowsWMFrameGetRectReq) >> 2), (int) client->req_len); 347#endif 348 349 REQUEST_SIZE_MATCH(xWindowsWMFrameGetRectReq); 350 rep.type = X_Reply; 351 rep.length = 0; 352 rep.sequenceNumber = client->sequence; 353 354 ir = make_box (stuff->ix, stuff->iy, stuff->iw, stuff->ih); 355 356 if (stuff->frame_rect != 0) 357 { 358 ErrorF ("ProcWindowsWMFrameGetRect - stuff->frame_rect != 0\n"); 359 return BadValue; 360 } 361 362 /* Store the origin, height, and width in a rectangle structure */ 363 SetRect (&rcNew, stuff->ix, stuff->iy, 364 stuff->ix + stuff->iw, stuff->iy + stuff->ih); 365 366#if CYGMULTIWINDOW_DEBUG 367 ErrorF ("ProcWindowsWMFrameGetRect - %d %d %d %d\n", 368 stuff->ix, stuff->iy, stuff->ix + stuff->iw, stuff->iy + stuff->ih); 369#endif 370 371 /* 372 * Calculate the required size of the Windows window rectangle, 373 * given the size of the Windows window client area. 374 */ 375 AdjustWindowRectEx (&rcNew, stuff->frame_style, FALSE, stuff->frame_style_ex); 376 rep.x = rcNew.left; 377 rep.y = rcNew.top; 378 rep.w = rcNew.right - rcNew.left; 379 rep.h = rcNew.bottom - rcNew.top; 380#if CYGMULTIWINDOW_DEBUG 381 ErrorF ("ProcWindowsWMFrameGetRect - %d %d %d %d\n", 382 rep.x, rep.y, rep.w, rep.h); 383#endif 384 385 WriteToClient(client, sizeof(xWindowsWMFrameGetRectReply), (char *)&rep); 386 return Success; 387} 388 389 390static int 391ProcWindowsWMFrameDraw (ClientPtr client) 392{ 393 REQUEST(xWindowsWMFrameDrawReq); 394 WindowPtr pWin; 395 win32RootlessWindowPtr pRLWinPriv; 396 RECT rcNew; 397 int nCmdShow, rc; 398 RegionRec newShape; 399 400 REQUEST_SIZE_MATCH (xWindowsWMFrameDrawReq); 401 402#if CYGMULTIWINDOW_DEBUG 403 ErrorF ("ProcWindowsWMFrameDraw\n"); 404#endif 405 rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); 406 if (rc != Success) 407 return rc; 408#if CYGMULTIWINDOW_DEBUG 409 ErrorF ("ProcWindowsWMFrameDraw - Window found\n"); 410#endif 411 412 pRLWinPriv = (win32RootlessWindowPtr) RootlessFrameForWindow (pWin, TRUE); 413 if (pRLWinPriv == 0) return BadWindow; 414 415#if CYGMULTIWINDOW_DEBUG 416 ErrorF ("ProcWindowsWMFrameDraw - HWND 0x%08x 0x%08x 0x%08x\n", 417 (int) pRLWinPriv->hWnd, (int) stuff->frame_style, 418 (int) stuff->frame_style_ex); 419 ErrorF ("ProcWindowsWMFrameDraw - %d %d %d %d\n", 420 stuff->ix, stuff->iy, stuff->iw, stuff->ih); 421#endif 422 423 /* Store the origin, height, and width in a rectangle structure */ 424 SetRect (&rcNew, stuff->ix, stuff->iy, 425 stuff->ix + stuff->iw, stuff->iy + stuff->ih); 426 427 /* 428 * Calculate the required size of the Windows window rectangle, 429 * given the size of the Windows window client area. 430 */ 431 AdjustWindowRectEx (&rcNew, stuff->frame_style, FALSE, stuff->frame_style_ex); 432 433 /* Set the window extended style flags */ 434 if (!SetWindowLongPtr (pRLWinPriv->hWnd, GWL_EXSTYLE, stuff->frame_style_ex)) 435 { 436 return BadValue; 437 } 438 439 /* Set the window standard style flags */ 440 if (!SetWindowLongPtr (pRLWinPriv->hWnd, GWL_STYLE, stuff->frame_style)) 441 { 442 return BadValue; 443 } 444 445 /* Flush the window style */ 446 if (!SetWindowPos (pRLWinPriv->hWnd, NULL, 447 rcNew.left, rcNew.top, 448 rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, 449 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE)) 450 { 451 return BadValue; 452 } 453 if (!IsWindowVisible(pRLWinPriv->hWnd)) 454 nCmdShow = SW_HIDE; 455 else 456 nCmdShow = SW_SHOWNA; 457 458 ShowWindow (pRLWinPriv->hWnd, nCmdShow); 459 460 winMWExtWMUpdateIcon (pWin->drawable.id); 461 462 if (wBoundingShape(pWin) != NULL) 463 { 464 /* wBoundingShape is relative to *inner* origin of window. 465 Translate by borderWidth to get the outside-relative position. */ 466 467 RegionNull(&newShape); 468 RegionCopy(&newShape, wBoundingShape(pWin)); 469 RegionTranslate(&newShape, pWin->borderWidth, pWin->borderWidth); 470 winMWExtWMReshapeFrame (pRLWinPriv, &newShape); 471 RegionUninit(&newShape); 472 } 473#if CYGMULTIWINDOW_DEBUG 474 ErrorF ("ProcWindowsWMFrameDraw - done\n"); 475#endif 476 477 return Success; 478} 479 480static int 481ProcWindowsWMFrameSetTitle(ClientPtr client) 482{ 483 unsigned int title_length, title_max; 484 char *title_bytes; 485 REQUEST(xWindowsWMFrameSetTitleReq); 486 WindowPtr pWin; 487 win32RootlessWindowPtr pRLWinPriv; 488 int rc; 489 490#if CYGMULTIWINDOW_DEBUG 491 ErrorF ("ProcWindowsWMFrameSetTitle\n"); 492#endif 493 494 REQUEST_AT_LEAST_SIZE(xWindowsWMFrameSetTitleReq); 495 496 rc = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); 497 if (rc != Success) 498 return rc; 499#if CYGMULTIWINDOW_DEBUG 500 ErrorF ("ProcWindowsWMFrameSetTitle - Window found\n"); 501#endif 502 503 title_length = stuff->title_length; 504 title_max = (stuff->length << 2) - sizeof(xWindowsWMFrameSetTitleReq); 505 506 if (title_max < title_length) 507 return BadValue; 508 509#if CYGMULTIWINDOW_DEBUG 510 ErrorF ("ProcWindowsWMFrameSetTitle - length is valid\n"); 511#endif 512 513 title_bytes = malloc (title_length+1); 514 strncpy (title_bytes, (unsigned char *) &stuff[1], title_length); 515 title_bytes[title_length] = '\0'; 516 517 pRLWinPriv = (win32RootlessWindowPtr) RootlessFrameForWindow (pWin, FALSE); 518 519 if (pRLWinPriv == 0) 520 { 521 free (title_bytes); 522 return BadWindow; 523 } 524 525 /* Flush the window style */ 526 SetWindowText (pRLWinPriv->hWnd, title_bytes); 527 528 free (title_bytes); 529 530#if CYGMULTIWINDOW_DEBUG 531 ErrorF ("ProcWindowsWMFrameSetTitle - done\n"); 532#endif 533 534 return Success; 535} 536 537 538/* dispatch */ 539 540static int 541ProcWindowsWMDispatch (ClientPtr client) 542{ 543 REQUEST(xReq); 544 545 switch (stuff->data) 546 { 547 case X_WindowsWMQueryVersion: 548 return ProcWindowsWMQueryVersion(client); 549 } 550 551 if (!LocalClient(client)) 552 return WMErrorBase + WindowsWMClientNotLocal; 553 554 switch (stuff->data) 555 { 556 case X_WindowsWMSelectInput: 557 return ProcWindowsWMSelectInput(client); 558 case X_WindowsWMDisableUpdate: 559 return ProcWindowsWMDisableUpdate(client); 560 case X_WindowsWMReenableUpdate: 561 return ProcWindowsWMReenableUpdate(client); 562 case X_WindowsWMSetFrontProcess: 563 return ProcWindowsWMSetFrontProcess(client); 564 case X_WindowsWMFrameGetRect: 565 return ProcWindowsWMFrameGetRect(client); 566 case X_WindowsWMFrameDraw: 567 return ProcWindowsWMFrameDraw(client); 568 case X_WindowsWMFrameSetTitle: 569 return ProcWindowsWMFrameSetTitle(client); 570 default: 571 return BadRequest; 572 } 573} 574 575static void 576SNotifyEvent (xWindowsWMNotifyEvent *from, xWindowsWMNotifyEvent *to) 577{ 578 to->type = from->type; 579 to->kind = from->kind; 580 cpswaps (from->sequenceNumber, to->sequenceNumber); 581 cpswapl (from->window, to->window); 582 cpswapl (from->time, to->time); 583 cpswapl (from->arg, to->arg); 584} 585 586static int 587SProcWindowsWMQueryVersion (ClientPtr client) 588{ 589 int n; 590 REQUEST(xWindowsWMQueryVersionReq); 591 swaps(&stuff->length, n); 592 return ProcWindowsWMQueryVersion(client); 593} 594 595static int 596SProcWindowsWMDispatch (ClientPtr client) 597{ 598 REQUEST(xReq); 599 600 /* It is bound to be non-local when there is byte swapping */ 601 if (!LocalClient(client)) 602 return WMErrorBase + WindowsWMClientNotLocal; 603 604 /* only local clients are allowed WM access */ 605 switch (stuff->data) 606 { 607 case X_WindowsWMQueryVersion: 608 return SProcWindowsWMQueryVersion(client); 609 default: 610 return BadRequest; 611 } 612} 613 614void 615winWindowsWMExtensionInit (void) 616{ 617 ExtensionEntry* extEntry; 618 619 ClientType = CreateNewResourceType(WMFreeClient, "WMClient"); 620 eventResourceType = CreateNewResourceType(WMFreeEvents, "WMEvent"); 621 eventResource = FakeClientID(0); 622 623 if (ClientType && eventResourceType && 624 (extEntry = AddExtension(WINDOWSWMNAME, 625 WindowsWMNumberEvents, 626 WindowsWMNumberErrors, 627 ProcWindowsWMDispatch, 628 SProcWindowsWMDispatch, 629 NULL, 630 StandardMinorOpcode))) 631 { 632 size_t i; 633 WMReqCode = (unsigned char)extEntry->base; 634 WMErrorBase = extEntry->errorBase; 635 WMEventBase = extEntry->eventBase; 636 for (i=0; i < WindowsWMNumberEvents; i++) 637 EventSwapVector[WMEventBase + i] = (EventSwapPtr) SNotifyEvent; 638 } 639} 640