1 /*
2  * Copyright © 2006 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 /*
23  * This Xinerama implementation comes from the SiS driver which has
24  * the following notice:
25  */
26 /*
27  * SiS driver main code
28  *
29  * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1) Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2) Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3) The name of the author may not be used to endorse or promote products
40  *    derived from this software without specific prior written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52  *
53  * Author: Thomas Winischhofer <thomas@winischhofer.net>
54  *	- driver entirely rewritten since 2001, only basic structure taken from
55  *	  old code (except sis_dri.c, sis_shadow.c, sis_accel.c and parts of
56  *	  sis_dga.c; these were mostly taken over; sis_dri.c was changed for
57  *	  new versions of the DRI layer)
58  *
59  * This notice covers the entire driver code unless indicated otherwise.
60  *
61  * Formerly based on code which was
62  * 	     Copyright (C) 1998, 1999 by Alan Hourihane, Wigan, England.
63  * 	     Written by:
64  *           Alan Hourihane <alanh@fairlite.demon.co.uk>,
65  *           Mike Chapman <mike@paranoia.com>,
66  *           Juanjo Santamarta <santamarta@ctv.es>,
67  *           Mitani Hiroshi <hmitani@drl.mei.co.jp>,
68  *           David Thomas <davtom@dream.org.uk>.
69  */
70 
71 #include "randrstr.h"
72 #include "swaprep.h"
73 #include <X11/extensions/panoramiXproto.h>
74 #include "protocol-versions.h"
75 
76 /* Xinerama is not multi-screen capable; just report about screen 0 */
77 #define RR_XINERAMA_SCREEN  0
78 
79 static int ProcRRXineramaQueryVersion(ClientPtr client);
80 static int ProcRRXineramaGetState(ClientPtr client);
81 static int ProcRRXineramaGetScreenCount(ClientPtr client);
82 static int ProcRRXineramaGetScreenSize(ClientPtr client);
83 static int ProcRRXineramaIsActive(ClientPtr client);
84 static int ProcRRXineramaQueryScreens(ClientPtr client);
85 static int _X_COLD SProcRRXineramaDispatch(ClientPtr client);
86 
87 Bool noRRXineramaExtension = FALSE;
88 
89 /* Proc */
90 
91 int
ProcRRXineramaQueryVersion(ClientPtr client)92 ProcRRXineramaQueryVersion(ClientPtr client)
93 {
94     xPanoramiXQueryVersionReply rep = {
95         .type = X_Reply,
96         .sequenceNumber = client->sequence,
97         .length = 0,
98         .majorVersion = SERVER_RRXINERAMA_MAJOR_VERSION,
99         .minorVersion = SERVER_RRXINERAMA_MINOR_VERSION
100     };
101 
102     REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
103     if (client->swapped) {
104         swaps(&rep.sequenceNumber);
105         swapl(&rep.length);
106         swaps(&rep.majorVersion);
107         swaps(&rep.minorVersion);
108     }
109     WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), &rep);
110     return Success;
111 }
112 
113 int
ProcRRXineramaGetState(ClientPtr client)114 ProcRRXineramaGetState(ClientPtr client)
115 {
116     REQUEST(xPanoramiXGetStateReq);
117     WindowPtr pWin;
118     xPanoramiXGetStateReply rep;
119     register int rc;
120     ScreenPtr pScreen;
121     rrScrPrivPtr pScrPriv;
122     Bool active = FALSE;
123 
124     REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
125     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
126     if (rc != Success)
127         return rc;
128 
129     pScreen = pWin->drawable.pScreen;
130     pScrPriv = rrGetScrPriv(pScreen);
131     if (pScrPriv) {
132         /* XXX do we need more than this? */
133         active = TRUE;
134     }
135 
136     rep = (xPanoramiXGetStateReply) {
137         .type = X_Reply,
138         .state = active,
139         .sequenceNumber = client->sequence,
140         .length = 0,
141         .window = stuff->window
142     };
143     if (client->swapped) {
144         swaps(&rep.sequenceNumber);
145         swapl(&rep.length);
146         swapl(&rep.window);
147     }
148     WriteToClient(client, sizeof(xPanoramiXGetStateReply), &rep);
149     return Success;
150 }
151 
152 static int
RRXineramaScreenCount(ScreenPtr pScreen)153 RRXineramaScreenCount(ScreenPtr pScreen)
154 {
155     return RRMonitorCountList(pScreen);
156 }
157 
158 static Bool
RRXineramaScreenActive(ScreenPtr pScreen)159 RRXineramaScreenActive(ScreenPtr pScreen)
160 {
161     return RRXineramaScreenCount(pScreen) > 0;
162 }
163 
164 int
ProcRRXineramaGetScreenCount(ClientPtr client)165 ProcRRXineramaGetScreenCount(ClientPtr client)
166 {
167     REQUEST(xPanoramiXGetScreenCountReq);
168     WindowPtr pWin;
169     xPanoramiXGetScreenCountReply rep;
170     register int rc;
171 
172     REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
173     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
174     if (rc != Success)
175         return rc;
176 
177     rep = (xPanoramiXGetScreenCountReply)  {
178         .type = X_Reply,
179         .ScreenCount = RRXineramaScreenCount(pWin->drawable.pScreen),
180         .sequenceNumber = client->sequence,
181         .length = 0,
182         .window = stuff->window
183     };
184     if (client->swapped) {
185         swaps(&rep.sequenceNumber);
186         swapl(&rep.length);
187         swapl(&rep.window);
188     }
189     WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), &rep);
190     return Success;
191 }
192 
193 int
ProcRRXineramaGetScreenSize(ClientPtr client)194 ProcRRXineramaGetScreenSize(ClientPtr client)
195 {
196     REQUEST(xPanoramiXGetScreenSizeReq);
197     WindowPtr pWin, pRoot;
198     ScreenPtr pScreen;
199     xPanoramiXGetScreenSizeReply rep;
200     register int rc;
201 
202     REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
203     rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
204     if (rc != Success)
205         return rc;
206 
207     pScreen = pWin->drawable.pScreen;
208     pRoot = pScreen->root;
209 
210     rep = (xPanoramiXGetScreenSizeReply) {
211         .type = X_Reply,
212         .sequenceNumber = client->sequence,
213         .length = 0,
214         .width = pRoot->drawable.width,
215         .height = pRoot->drawable.height,
216         .window = stuff->window,
217         .screen = stuff->screen
218     };
219     if (client->swapped) {
220         swaps(&rep.sequenceNumber);
221         swapl(&rep.length);
222         swapl(&rep.width);
223         swapl(&rep.height);
224         swapl(&rep.window);
225         swapl(&rep.screen);
226     }
227     WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), &rep);
228     return Success;
229 }
230 
231 int
ProcRRXineramaIsActive(ClientPtr client)232 ProcRRXineramaIsActive(ClientPtr client)
233 {
234     xXineramaIsActiveReply rep;
235 
236     REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
237 
238     rep = (xXineramaIsActiveReply) {
239         .type = X_Reply,
240         .length = 0,
241         .sequenceNumber = client->sequence,
242         .state = RRXineramaScreenActive(screenInfo.screens[RR_XINERAMA_SCREEN])
243     };
244     if (client->swapped) {
245         swaps(&rep.sequenceNumber);
246         swapl(&rep.length);
247         swapl(&rep.state);
248     }
249     WriteToClient(client, sizeof(xXineramaIsActiveReply), &rep);
250     return Success;
251 }
252 
253 static void
RRXineramaWriteMonitor(ClientPtr client,RRMonitorPtr monitor)254 RRXineramaWriteMonitor(ClientPtr client, RRMonitorPtr monitor)
255 {
256     xXineramaScreenInfo scratch;
257 
258     scratch.x_org = monitor->geometry.box.x1;
259     scratch.y_org = monitor->geometry.box.y1;
260     scratch.width = monitor->geometry.box.x2 - monitor->geometry.box.x1;
261     scratch.height = monitor->geometry.box.y2 - monitor->geometry.box.y1;
262 
263     if (client->swapped) {
264         swaps(&scratch.x_org);
265         swaps(&scratch.y_org);
266         swaps(&scratch.width);
267         swaps(&scratch.height);
268     }
269 
270     WriteToClient(client, sz_XineramaScreenInfo, &scratch);
271 }
272 
273 int
ProcRRXineramaQueryScreens(ClientPtr client)274 ProcRRXineramaQueryScreens(ClientPtr client)
275 {
276     xXineramaQueryScreensReply rep;
277     ScreenPtr pScreen = screenInfo.screens[RR_XINERAMA_SCREEN];
278     int m;
279     RRMonitorPtr monitors = NULL;
280     int nmonitors = 0;
281 
282     REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
283 
284     if (RRXineramaScreenActive(pScreen)) {
285         RRGetInfo(pScreen, FALSE);
286         if (!RRMonitorMakeList(pScreen, TRUE, &monitors, &nmonitors))
287             return BadAlloc;
288     }
289 
290     rep = (xXineramaQueryScreensReply) {
291         .type = X_Reply,
292         .sequenceNumber = client->sequence,
293         .length = bytes_to_int32(nmonitors * sz_XineramaScreenInfo),
294         .number = nmonitors
295     };
296     if (client->swapped) {
297         swaps(&rep.sequenceNumber);
298         swapl(&rep.length);
299         swapl(&rep.number);
300     }
301     WriteToClient(client, sizeof(xXineramaQueryScreensReply), &rep);
302 
303     for (m = 0; m < nmonitors; m++)
304         RRXineramaWriteMonitor(client, &monitors[m]);
305 
306     if (monitors)
307         RRMonitorFreeList(monitors, nmonitors);
308 
309     return Success;
310 }
311 
312 static int
ProcRRXineramaDispatch(ClientPtr client)313 ProcRRXineramaDispatch(ClientPtr client)
314 {
315     REQUEST(xReq);
316     switch (stuff->data) {
317     case X_PanoramiXQueryVersion:
318         return ProcRRXineramaQueryVersion(client);
319     case X_PanoramiXGetState:
320         return ProcRRXineramaGetState(client);
321     case X_PanoramiXGetScreenCount:
322         return ProcRRXineramaGetScreenCount(client);
323     case X_PanoramiXGetScreenSize:
324         return ProcRRXineramaGetScreenSize(client);
325     case X_XineramaIsActive:
326         return ProcRRXineramaIsActive(client);
327     case X_XineramaQueryScreens:
328         return ProcRRXineramaQueryScreens(client);
329     }
330     return BadRequest;
331 }
332 
333 /* SProc */
334 
335 static int _X_COLD
SProcRRXineramaQueryVersion(ClientPtr client)336 SProcRRXineramaQueryVersion(ClientPtr client)
337 {
338     REQUEST(xPanoramiXQueryVersionReq);
339     swaps(&stuff->length);
340     REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
341     return ProcRRXineramaQueryVersion(client);
342 }
343 
344 static int _X_COLD
SProcRRXineramaGetState(ClientPtr client)345 SProcRRXineramaGetState(ClientPtr client)
346 {
347     REQUEST(xPanoramiXGetStateReq);
348     swaps(&stuff->length);
349     REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
350     swapl(&stuff->window);
351     return ProcRRXineramaGetState(client);
352 }
353 
354 static int _X_COLD
SProcRRXineramaGetScreenCount(ClientPtr client)355 SProcRRXineramaGetScreenCount(ClientPtr client)
356 {
357     REQUEST(xPanoramiXGetScreenCountReq);
358     swaps(&stuff->length);
359     REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
360     swapl(&stuff->window);
361     return ProcRRXineramaGetScreenCount(client);
362 }
363 
364 static int _X_COLD
SProcRRXineramaGetScreenSize(ClientPtr client)365 SProcRRXineramaGetScreenSize(ClientPtr client)
366 {
367     REQUEST(xPanoramiXGetScreenSizeReq);
368     swaps(&stuff->length);
369     REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
370     swapl(&stuff->window);
371     swapl(&stuff->screen);
372     return ProcRRXineramaGetScreenSize(client);
373 }
374 
375 static int _X_COLD
SProcRRXineramaIsActive(ClientPtr client)376 SProcRRXineramaIsActive(ClientPtr client)
377 {
378     REQUEST(xXineramaIsActiveReq);
379     swaps(&stuff->length);
380     REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
381     return ProcRRXineramaIsActive(client);
382 }
383 
384 static int _X_COLD
SProcRRXineramaQueryScreens(ClientPtr client)385 SProcRRXineramaQueryScreens(ClientPtr client)
386 {
387     REQUEST(xXineramaQueryScreensReq);
388     swaps(&stuff->length);
389     REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
390     return ProcRRXineramaQueryScreens(client);
391 }
392 
393 int
SProcRRXineramaDispatch(ClientPtr client)394 SProcRRXineramaDispatch(ClientPtr client)
395 {
396     REQUEST(xReq);
397     switch (stuff->data) {
398     case X_PanoramiXQueryVersion:
399         return SProcRRXineramaQueryVersion(client);
400     case X_PanoramiXGetState:
401         return SProcRRXineramaGetState(client);
402     case X_PanoramiXGetScreenCount:
403         return SProcRRXineramaGetScreenCount(client);
404     case X_PanoramiXGetScreenSize:
405         return SProcRRXineramaGetScreenSize(client);
406     case X_XineramaIsActive:
407         return SProcRRXineramaIsActive(client);
408     case X_XineramaQueryScreens:
409         return SProcRRXineramaQueryScreens(client);
410     }
411     return BadRequest;
412 }
413 
414 void
RRXineramaExtensionInit(void)415 RRXineramaExtensionInit(void)
416 {
417 #ifdef PANORAMIX
418     if (!noPanoramiXExtension)
419         return;
420 #endif
421 
422     if (noRRXineramaExtension)
423       return;
424 
425     /*
426      * Xinerama isn't capable enough to have multiple protocol screens each
427      * with their own output geometry.  So if there's more than one protocol
428      * screen, just don't even try.
429      */
430     if (screenInfo.numScreens > 1)
431         return;
432 
433     (void) AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0,
434                         ProcRRXineramaDispatch,
435                         SProcRRXineramaDispatch, NULL, StandardMinorOpcode);
436 }
437