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