1/*
2 * Copyright 2006 by VMware, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the copyright holder(s)
23 * and author(s) shall not be used in advertising or otherwise to promote
24 * the sale, use or other dealings in this Software without prior written
25 * authorization from the copyright holder(s) and author(s).
26 */
27
28/*
29 * vmwarexinerama.c --
30 *
31 *      The implementation of the Xinerama protocol extension.
32 */
33
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include "dixstruct.h"
40#include "extnsionst.h"
41#include <X11/X.h>
42#include <X11/extensions/panoramiXproto.h>
43
44#include "vmware.h"
45
46#ifndef HAVE_XORG_SERVER_1_5_0
47#include <xf86_ansic.h>
48#include <xf86_libc.h>
49#endif
50
51/*
52 * LookupWindow was removed with video abi 11.
53 */
54#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 4)
55#ifndef DixGetAttrAccess
56#define DixGetAttrAccess   (1<<4)
57#endif
58#endif
59
60#if (GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 2)
61static inline int
62dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
63{
64    *pWin = LookupWindow(id, client);
65    if (!*pWin)
66	return BadWindow;
67    return Success;
68}
69#endif
70
71
72/*
73 *----------------------------------------------------------------------------
74 *
75 * VMwareXineramaQueryVersion --
76 *
77 *      Implementation of QueryVersion command handler. Initialises and
78 *      sends a reply.
79 *
80 * Results:
81 *      Standard response codes.
82 *
83 * Side effects:
84 *      Writes reply to client.
85 *
86 *----------------------------------------------------------------------------
87 */
88
89static int
90VMwareXineramaQueryVersion(ClientPtr client)
91{
92    xPanoramiXQueryVersionReply	  rep;
93    register int		  n;
94
95    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
96    rep.type = X_Reply;
97    rep.length = 0;
98    rep.sequenceNumber = client->sequence;
99    rep.majorVersion = 1;
100    rep.minorVersion = 0;
101    if(client->swapped) {
102        _swaps(&rep.sequenceNumber, n);
103        _swapl(&rep.length, n);
104        _swaps(&rep.majorVersion, n);
105        _swaps(&rep.minorVersion, n);
106    }
107    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
108    return (client->noClientException);
109}
110
111
112/*
113 *----------------------------------------------------------------------------
114 *
115 * VMwareXineramaGetState --
116 *
117 *      Implementation of GetState command handler. Initialises and
118 *      sends a reply.
119 *
120 * Results:
121 *      Standard response codes.
122 *
123 * Side effects:
124 *      Writes reply to client.
125 *
126 *----------------------------------------------------------------------------
127 */
128
129static int
130VMwareXineramaGetState(ClientPtr client)
131{
132    REQUEST(xPanoramiXGetStateReq);
133    WindowPtr			pWin;
134    xPanoramiXGetStateReply	rep;
135    register int		n;
136    ExtensionEntry *ext;
137    ScrnInfoPtr pScrn;
138    VMWAREPtr pVMWARE;
139    int rc;
140
141    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
142    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
143    if (rc != Success)
144	return rc;
145
146    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
147       return BadMatch;
148    }
149    pScrn = ext->extPrivate;
150    pVMWARE = VMWAREPTR(pScrn);
151
152    rep.type = X_Reply;
153    rep.length = 0;
154    rep.sequenceNumber = client->sequence;
155    rep.state = pVMWARE->xinerama;
156    rep.window = stuff->window;
157    if(client->swapped) {
158       _swaps (&rep.sequenceNumber, n);
159       _swapl (&rep.length, n);
160       _swapl (&rep.window, n);
161    }
162    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
163    return client->noClientException;
164}
165
166
167/*
168 *----------------------------------------------------------------------------
169 *
170 * VMwareXineramaGetScreenCount --
171 *
172 *      Implementation of GetScreenCount command handler. Initialises and
173 *      sends a reply.
174 *
175 * Results:
176 *      Standard response codes.
177 *
178 * Side effects:
179 *      Writes reply to client.
180 *
181 *----------------------------------------------------------------------------
182 */
183
184static int
185VMwareXineramaGetScreenCount(ClientPtr client)
186{
187    REQUEST(xPanoramiXGetScreenCountReq);
188    WindowPtr				pWin;
189    xPanoramiXGetScreenCountReply	rep;
190    register int			n;
191    ExtensionEntry *ext;
192    ScrnInfoPtr pScrn;
193    VMWAREPtr pVMWARE;
194    int rc;
195
196    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
197    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
198    if (rc != Success)
199	return rc;
200
201    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
202       return BadMatch;
203    }
204    pScrn = ext->extPrivate;
205    pVMWARE = VMWAREPTR(pScrn);
206
207    rep.type = X_Reply;
208    rep.length = 0;
209    rep.sequenceNumber = client->sequence;
210    rep.ScreenCount = pVMWARE->xineramaNumOutputs;
211    rep.window = stuff->window;
212
213    if(client->swapped) {
214       _swaps(&rep.sequenceNumber, n);
215       _swapl(&rep.length, n);
216       _swapl(&rep.window, n);
217    }
218    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
219    return client->noClientException;
220}
221
222
223/*
224 *----------------------------------------------------------------------------
225 *
226 * VMwareXineramaGetScreenSize --
227 *
228 *      Implementation of GetScreenSize command handler. Initialises and
229 *      sends a reply.
230 *
231 * Results:
232 *      Standard response codes.
233 *
234 * Side effects:
235 *      Writes reply to client.
236 *
237 *----------------------------------------------------------------------------
238 */
239
240static int
241VMwareXineramaGetScreenSize(ClientPtr client)
242{
243    REQUEST(xPanoramiXGetScreenSizeReq);
244    WindowPtr				pWin;
245    xPanoramiXGetScreenSizeReply	rep;
246    register int			n;
247    ExtensionEntry *ext;
248    ScrnInfoPtr pScrn;
249    VMWAREPtr pVMWARE;
250    int rc;
251
252
253    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
254    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
255    if (rc != Success)
256	return rc;
257
258    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
259       return BadMatch;
260    }
261    pScrn = ext->extPrivate;
262    pVMWARE = VMWAREPTR(pScrn);
263
264    rep.type = X_Reply;
265    rep.length = 0;
266    rep.sequenceNumber = client->sequence;
267    rep.width  = pVMWARE->xineramaState[stuff->screen].width;
268    rep.height  = pVMWARE->xineramaState[stuff->screen].height;
269    rep.window = stuff->window;
270    rep.screen = stuff->screen;
271    if(client->swapped) {
272       _swaps(&rep.sequenceNumber, n);
273       _swapl(&rep.length, n);
274       _swapl(&rep.width, n);
275       _swapl(&rep.height, n);
276       _swapl(&rep.window, n);
277       _swapl(&rep.screen, n);
278    }
279    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
280    return client->noClientException;
281}
282
283
284/*
285 *----------------------------------------------------------------------------
286 *
287 * VMwareXineramaIsActive --
288 *
289 *      Implementation of IsActive command handler. Initialises and
290 *      sends a reply.
291 *
292 * Results:
293 *      Standard response codes.
294 *
295 * Side effects:
296 *      Writes reply to client.
297 *
298 *----------------------------------------------------------------------------
299 */
300
301static int
302VMwareXineramaIsActive(ClientPtr client)
303{
304    xXineramaIsActiveReply	rep;
305    ExtensionEntry *ext;
306    ScrnInfoPtr pScrn;
307    VMWAREPtr pVMWARE;
308
309    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
310
311    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
312       return BadMatch;
313    }
314    pScrn = ext->extPrivate;
315    pVMWARE = VMWAREPTR(pScrn);
316
317    rep.type = X_Reply;
318    rep.length = 0;
319    rep.sequenceNumber = client->sequence;
320    rep.state = pVMWARE->xinerama;
321    if(client->swapped) {
322	register int n;
323	_swaps(&rep.sequenceNumber, n);
324	_swapl(&rep.length, n);
325	_swapl(&rep.state, n);
326    }
327    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
328    return client->noClientException;
329}
330
331
332/*
333 *----------------------------------------------------------------------------
334 *
335 * VMwareXineramaQueryScreens --
336 *
337 *      Implementation of QueryScreens command handler. Initialises and
338 *      sends a reply.
339 *
340 * Results:
341 *      Standard response codes.
342 *
343 * Side effects:
344 *      Writes reply to client.
345 *
346 *----------------------------------------------------------------------------
347 */
348
349static int
350VMwareXineramaQueryScreens(ClientPtr client)
351{
352    xXineramaQueryScreensReply	rep;
353    ExtensionEntry *ext;
354    ScrnInfoPtr pScrn;
355    VMWAREPtr pVMWARE;
356
357    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
358
359    if (!(ext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
360       return BadMatch;
361    }
362    pScrn = ext->extPrivate;
363    pVMWARE = VMWAREPTR(pScrn);
364
365    rep.type = X_Reply;
366    rep.sequenceNumber = client->sequence;
367    rep.number = pVMWARE->xinerama ? pVMWARE->xineramaNumOutputs : 0;
368    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
369    if(client->swapped) {
370       register int n;
371       _swaps(&rep.sequenceNumber, n);
372       _swapl(&rep.length, n);
373       _swapl(&rep.number, n);
374    }
375    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
376
377    if(pVMWARE->xinerama) {
378       xXineramaScreenInfo scratch;
379       int i;
380
381       for(i = 0; i < pVMWARE->xineramaNumOutputs; i++) {
382	  scratch.x_org  = pVMWARE->xineramaState[i].x_org;
383	  scratch.y_org  = pVMWARE->xineramaState[i].y_org;
384	  scratch.width  = pVMWARE->xineramaState[i].width;
385	  scratch.height = pVMWARE->xineramaState[i].height;
386	  if(client->swapped) {
387	     register int n;
388	     _swaps(&scratch.x_org, n);
389	     _swaps(&scratch.y_org, n);
390	     _swaps(&scratch.width, n);
391	     _swaps(&scratch.height, n);
392	  }
393	  WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
394       }
395    }
396
397    return client->noClientException;
398}
399
400
401/*
402 *----------------------------------------------------------------------------
403 *
404 * VMwareXineramaDispatch --
405 *
406 *      Dispatcher for Xinerama commands. Calls the correct handler for
407 *      each command type.
408 *
409 * Results:
410 *      Standard response codes.
411 *
412 * Side effects:
413 *      Side effects of individual command handlers.
414 *
415 *----------------------------------------------------------------------------
416 */
417
418static int
419VMwareXineramaDispatch(ClientPtr client)
420{
421    REQUEST(xReq);
422    switch (stuff->data) {
423	case X_PanoramiXQueryVersion:
424	     return VMwareXineramaQueryVersion(client);
425	case X_PanoramiXGetState:
426	     return VMwareXineramaGetState(client);
427	case X_PanoramiXGetScreenCount:
428	     return VMwareXineramaGetScreenCount(client);
429	case X_PanoramiXGetScreenSize:
430	     return VMwareXineramaGetScreenSize(client);
431	case X_XineramaIsActive:
432	     return VMwareXineramaIsActive(client);
433	case X_XineramaQueryScreens:
434	     return VMwareXineramaQueryScreens(client);
435    }
436    return BadRequest;
437}
438
439
440/*
441 *----------------------------------------------------------------------------
442 *
443 * SVMwareXineramaQueryVersion --
444 *
445 *      Wrapper for QueryVersion handler that handles input from other-endian
446 *      clients.
447 *
448 * Results:
449 *      Standard response codes.
450 *
451 * Side effects:
452 *      Side effects of unswapped implementation.
453 *
454 *----------------------------------------------------------------------------
455 */
456
457static int
458SVMwareXineramaQueryVersion (ClientPtr client)
459{
460    REQUEST(xPanoramiXQueryVersionReq);
461    register int n;
462    _swaps(&stuff->length,n);
463    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
464    return VMwareXineramaQueryVersion(client);
465}
466
467
468/*
469 *----------------------------------------------------------------------------
470 *
471 * SVMwareXineramaGetState --
472 *
473 *      Wrapper for GetState handler that handles input from other-endian
474 *      clients.
475 *
476 * Results:
477 *      Standard response codes.
478 *
479 * Side effects:
480 *      Side effects of unswapped implementation.
481 *
482 *----------------------------------------------------------------------------
483 */
484
485static int
486SVMwareXineramaGetState(ClientPtr client)
487{
488    REQUEST(xPanoramiXGetStateReq);
489    register int n;
490    _swaps (&stuff->length, n);
491    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
492    return VMwareXineramaGetState(client);
493}
494
495
496/*
497 *----------------------------------------------------------------------------
498 *
499 * SVMwareXineramaGetScreenCount --
500 *
501 *      Wrapper for GetScreenCount handler that handles input from other-endian
502 *      clients.
503 *
504 * Results:
505 *      Standard response codes.
506 *
507 * Side effects:
508 *      Side effects of unswapped implementation.
509 *
510 *----------------------------------------------------------------------------
511 */
512
513static int
514SVMwareXineramaGetScreenCount(ClientPtr client)
515{
516    REQUEST(xPanoramiXGetScreenCountReq);
517    register int n;
518    _swaps (&stuff->length, n);
519    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
520    return VMwareXineramaGetScreenCount(client);
521}
522
523
524/*
525 *----------------------------------------------------------------------------
526 *
527 * SVMwareXineramaGetScreenSize --
528 *
529 *      Wrapper for GetScreenSize handler that handles input from other-endian
530 *      clients.
531 *
532 * Results:
533 *      Standard response codes.
534 *
535 * Side effects:
536 *      Side effects of unswapped implementation.
537 *
538 *----------------------------------------------------------------------------
539 */
540
541static int
542SVMwareXineramaGetScreenSize(ClientPtr client)
543{
544    REQUEST(xPanoramiXGetScreenSizeReq);
545    register int n;
546    _swaps (&stuff->length, n);
547    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
548    return VMwareXineramaGetScreenSize(client);
549}
550
551
552/*
553 *----------------------------------------------------------------------------
554 *
555 * SVMwareXineramaIsActive --
556 *
557 *      Wrapper for IsActive handler that handles input from other-endian
558 *      clients.
559 *
560 * Results:
561 *      Standard response codes.
562 *
563 * Side effects:
564 *      Side effects of unswapped implementation.
565 *
566 *----------------------------------------------------------------------------
567 */
568
569static int
570SVMwareXineramaIsActive(ClientPtr client)
571{
572    REQUEST(xXineramaIsActiveReq);
573    register int n;
574    _swaps (&stuff->length, n);
575    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
576    return VMwareXineramaIsActive(client);
577}
578
579
580/*
581 *----------------------------------------------------------------------------
582 *
583 * SVMwareXineramaQueryScreens --
584 *
585 *      Wrapper for QueryScreens handler that handles input from other-endian
586 *      clients.
587 *
588 * Results:
589 *      Standard response codes.
590 *
591 * Side effects:
592 *      Side effects of unswapped implementation.
593 *
594 *----------------------------------------------------------------------------
595 */
596
597static int
598SVMwareXineramaQueryScreens(ClientPtr client)
599{
600    REQUEST(xXineramaQueryScreensReq);
601    register int n;
602    _swaps (&stuff->length, n);
603    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
604    return VMwareXineramaQueryScreens(client);
605}
606
607
608/*
609 *----------------------------------------------------------------------------
610 *
611 * SVMwareXineramaDispatch --
612 *
613 *      Wrapper for dispatcher that handles input from other-endian clients.
614 *
615 * Results:
616 *      Standard response codes.
617 *
618 * Side effects:
619 *      Side effects of individual command handlers.
620 *
621 *----------------------------------------------------------------------------
622 */
623
624static int
625SVMwareXineramaDispatch(ClientPtr client)
626{
627    REQUEST(xReq);
628    switch (stuff->data) {
629	case X_PanoramiXQueryVersion:
630	     return SVMwareXineramaQueryVersion(client);
631	case X_PanoramiXGetState:
632	     return SVMwareXineramaGetState(client);
633	case X_PanoramiXGetScreenCount:
634	     return SVMwareXineramaGetScreenCount(client);
635	case X_PanoramiXGetScreenSize:
636	     return SVMwareXineramaGetScreenSize(client);
637	case X_XineramaIsActive:
638	     return SVMwareXineramaIsActive(client);
639	case X_XineramaQueryScreens:
640	     return SVMwareXineramaQueryScreens(client);
641    }
642    return BadRequest;
643}
644
645
646/*
647 *----------------------------------------------------------------------------
648 *
649 * VMwareXineramaResetProc --
650 *
651 *      Cleanup handler called when the extension is removed.
652 *
653 * Results:
654 *      None
655 *
656 * Side effects:
657 *      None
658 *
659 *----------------------------------------------------------------------------
660 */
661
662static void
663VMwareXineramaResetProc(ExtensionEntry* extEntry)
664{
665    /* Called by CloseDownExtensions() */
666
667   ScrnInfoPtr pScrn = extEntry->extPrivate;
668   VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
669
670   if (pVMWARE->xineramaState) {
671      free(pVMWARE->xineramaState);
672      pVMWARE->xineramaState = NULL;
673      pVMWARE->xineramaNumOutputs = 0;
674      pVMWARE->xinerama = FALSE;
675   }
676}
677
678
679/*
680 *----------------------------------------------------------------------------
681 *
682 * VMwareCtrl_ExitInit --
683 *
684 *      Initialiser for the Xinerama protocol extension.
685 *
686 * Results:
687 *      None.
688 *
689 * Side effects:
690 *      Protocol extension will be registered if successful.
691 *
692 *----------------------------------------------------------------------------
693 */
694
695void
696VMwareXinerama_ExtInit(ScrnInfoPtr pScrn)
697{
698   ExtensionEntry *myext;
699   VMWAREPtr pVMWARE = VMWAREPTR(pScrn);
700
701#ifdef PANORAMIX
702   if(!noPanoramiXExtension) {
703      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
704                 "Built-in Xinerama active, not initializing VMware Xinerama\n");
705      pVMWARE->xinerama = FALSE;
706      return;
707   }
708#endif
709
710   if (!(myext = CheckExtension(PANORAMIX_PROTOCOL_NAME))) {
711      if (!(myext = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0,
712                                 VMwareXineramaDispatch,
713                                 SVMwareXineramaDispatch,
714                                 VMwareXineramaResetProc,
715                                 StandardMinorOpcode))) {
716         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
717                    "Failed to add VMware Xinerama extension.\n");
718         return;
719      }
720
721      pVMWARE->xinerama = TRUE;
722
723      myext->extPrivate = pScrn;
724
725      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
726                 "Initialized VMware Xinerama extension.\n");
727   }
728}
729