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