1 /*
2 * Minimal implementation of PanoramiX/Xinerama
3 *
4 * This is used in rootless mode where the underlying window server
5 * already provides an abstracted view of multiple screens as one
6 * large screen area.
7 *
8 * This code is largely based on panoramiX.c, which contains the
9 * following copyright notice:
10 */
11 /*****************************************************************
12 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software.
18
19 The above copyright notice and this permission notice shall be included in
20 all copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
26 BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
28 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 Except as contained in this notice, the name of Digital Equipment Corporation
31 shall not be used in advertising or otherwise to promote the sale, use or other
32 dealings in this Software without prior written authorization from Digital
33 Equipment Corporation.
34 ******************************************************************/
35
36 #ifdef HAVE_DIX_CONFIG_H
37 #include <dix-config.h>
38 #endif
39
40 #include "pseudoramiX.h"
41 #include "extnsionst.h"
42 #include "nonsdk_extinit.h"
43 #include "dixstruct.h"
44 #include "window.h"
45 #include <X11/extensions/panoramiXproto.h>
46 #include "globals.h"
47
48 #define TRACE PseudoramiXTrace("TRACE " __FILE__ ":%s",__FUNCTION__)
49 #define DEBUG_LOG PseudoramiXDebug
50
51 Bool noPseudoramiXExtension = FALSE;
52 extern Bool noRRXineramaExtension;
53
54 extern int
55 ProcPanoramiXQueryVersion(ClientPtr client);
56
57 static void
58 PseudoramiXResetProc(ExtensionEntry *extEntry);
59
60 static int
61 ProcPseudoramiXQueryVersion(ClientPtr client);
62 static int
63 ProcPseudoramiXGetState(ClientPtr client);
64 static int
65 ProcPseudoramiXGetScreenCount(ClientPtr client);
66 static int
67 ProcPseudoramiXGetScreenSize(ClientPtr client);
68 static int
69 ProcPseudoramiXIsActive(ClientPtr client);
70 static int
71 ProcPseudoramiXQueryScreens(ClientPtr client);
72 static int
73 ProcPseudoramiXDispatch(ClientPtr client);
74
75 static int
76 SProcPseudoramiXQueryVersion(ClientPtr client);
77 static int
78 SProcPseudoramiXGetState(ClientPtr client);
79 static int
80 SProcPseudoramiXGetScreenCount(ClientPtr client);
81 static int
82 SProcPseudoramiXGetScreenSize(ClientPtr client);
83 static int
84 SProcPseudoramiXIsActive(ClientPtr client);
85 static int
86 SProcPseudoramiXQueryScreens(ClientPtr client);
87 static int
88 SProcPseudoramiXDispatch(ClientPtr client);
89
90 typedef struct {
91 int x;
92 int y;
93 int w;
94 int h;
95 } PseudoramiXScreenRec;
96
97 static PseudoramiXScreenRec *pseudoramiXScreens = NULL;
98 static int pseudoramiXScreensAllocated = 0;
99 static int pseudoramiXNumScreens = 0;
100 static unsigned long pseudoramiXGeneration = 0;
101
102 static void
103 PseudoramiXTrace(const char *format, ...)
104 _X_ATTRIBUTE_PRINTF(1, 2);
105
106 static void
PseudoramiXTrace(const char * format,...)107 PseudoramiXTrace(const char *format, ...)
108 {
109 va_list ap;
110
111 va_start(ap, format);
112 LogVMessageVerb(X_NONE, 10, format, ap);
113 va_end(ap);
114 }
115
116 static void
117 PseudoramiXDebug(const char *format, ...)
118 _X_ATTRIBUTE_PRINTF(1, 2);
119
120 static void
PseudoramiXDebug(const char * format,...)121 PseudoramiXDebug(const char *format, ...)
122 {
123 va_list ap;
124
125 va_start(ap, format);
126 LogVMessageVerb(X_NONE, 3, format, ap);
127 va_end(ap);
128 }
129
130 // Add a PseudoramiX screen.
131 // The rest of the X server will know nothing about this screen.
132 // Can be called before or after extension init.
133 // Screens must be re-added once per generation.
134 void
PseudoramiXAddScreen(int x,int y,int w,int h)135 PseudoramiXAddScreen(int x, int y, int w, int h)
136 {
137 PseudoramiXScreenRec *s;
138
139 if (noPseudoramiXExtension) return;
140
141 if (pseudoramiXNumScreens == pseudoramiXScreensAllocated) {
142 pseudoramiXScreensAllocated += pseudoramiXScreensAllocated + 1;
143 pseudoramiXScreens = reallocarray(pseudoramiXScreens,
144 pseudoramiXScreensAllocated,
145 sizeof(PseudoramiXScreenRec));
146 }
147
148 DEBUG_LOG("x: %d, y: %d, w: %d, h: %d\n", x, y, w, h);
149
150 s = &pseudoramiXScreens[pseudoramiXNumScreens++];
151 s->x = x;
152 s->y = y;
153 s->w = w;
154 s->h = h;
155 }
156
157 // Initialize PseudoramiX.
158 // Copied from PanoramiXExtensionInit
159 void
PseudoramiXExtensionInit(void)160 PseudoramiXExtensionInit(void)
161 {
162 Bool success = FALSE;
163 ExtensionEntry *extEntry;
164
165 if (noPseudoramiXExtension) return;
166
167 TRACE;
168
169 /* Even with only one screen we need to enable PseudoramiX to allow
170 dynamic screen configuration changes. */
171 #if 0
172 if (pseudoramiXNumScreens == 1) {
173 // Only one screen - disable Xinerama extension.
174 noPseudoramiXExtension = TRUE;
175 return;
176 }
177 #endif
178
179 if (pseudoramiXGeneration != serverGeneration) {
180 extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0,
181 ProcPseudoramiXDispatch,
182 SProcPseudoramiXDispatch,
183 PseudoramiXResetProc,
184 StandardMinorOpcode);
185 if (!extEntry) {
186 ErrorF("PseudoramiXExtensionInit(): AddExtension failed\n");
187 }
188 else {
189 pseudoramiXGeneration = serverGeneration;
190 success = TRUE;
191 }
192 }
193
194 /* Do not allow RRXinerama to initialize if we did */
195 noRRXineramaExtension = success;
196
197 if (!success) {
198 ErrorF("%s Extension (PseudoramiX) failed to initialize\n",
199 PANORAMIX_PROTOCOL_NAME);
200 return;
201 }
202 }
203
204 void
PseudoramiXResetScreens(void)205 PseudoramiXResetScreens(void)
206 {
207 TRACE;
208
209 pseudoramiXNumScreens = 0;
210 }
211
212 static void
PseudoramiXResetProc(ExtensionEntry * extEntry)213 PseudoramiXResetProc(ExtensionEntry *extEntry)
214 {
215 TRACE;
216
217 PseudoramiXResetScreens();
218 }
219
220 // was PanoramiX
221 static int
ProcPseudoramiXQueryVersion(ClientPtr client)222 ProcPseudoramiXQueryVersion(ClientPtr client)
223 {
224 TRACE;
225
226 return ProcPanoramiXQueryVersion(client);
227 }
228
229 // was PanoramiX
230 static int
ProcPseudoramiXGetState(ClientPtr client)231 ProcPseudoramiXGetState(ClientPtr client)
232 {
233 REQUEST(xPanoramiXGetStateReq);
234 WindowPtr pWin;
235 xPanoramiXGetStateReply rep;
236 register int rc;
237
238 TRACE;
239
240 REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
241 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
242 if (rc != Success)
243 return rc;
244
245 rep.type = X_Reply;
246 rep.length = 0;
247 rep.sequenceNumber = client->sequence;
248 rep.state = !noPseudoramiXExtension;
249 rep.window = stuff->window;
250 if (client->swapped) {
251 swaps(&rep.sequenceNumber);
252 swapl(&rep.length);
253 swapl(&rep.window);
254 }
255 WriteToClient(client, sizeof(xPanoramiXGetStateReply),&rep);
256 return Success;
257 }
258
259 // was PanoramiX
260 static int
ProcPseudoramiXGetScreenCount(ClientPtr client)261 ProcPseudoramiXGetScreenCount(ClientPtr client)
262 {
263 REQUEST(xPanoramiXGetScreenCountReq);
264 WindowPtr pWin;
265 xPanoramiXGetScreenCountReply rep;
266 register int rc;
267
268 TRACE;
269
270 REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
271 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
272 if (rc != Success)
273 return rc;
274
275 rep.type = X_Reply;
276 rep.length = 0;
277 rep.sequenceNumber = client->sequence;
278 rep.ScreenCount = pseudoramiXNumScreens;
279 rep.window = stuff->window;
280 if (client->swapped) {
281 swaps(&rep.sequenceNumber);
282 swapl(&rep.length);
283 swapl(&rep.window);
284 }
285 WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply),&rep);
286 return Success;
287 }
288
289 // was PanoramiX
290 static int
ProcPseudoramiXGetScreenSize(ClientPtr client)291 ProcPseudoramiXGetScreenSize(ClientPtr client)
292 {
293 REQUEST(xPanoramiXGetScreenSizeReq);
294 WindowPtr pWin;
295 xPanoramiXGetScreenSizeReply rep;
296 register int rc;
297
298 TRACE;
299
300 REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
301
302 if (stuff->screen >= pseudoramiXNumScreens)
303 return BadMatch;
304
305 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
306 if (rc != Success)
307 return rc;
308
309 rep.type = X_Reply;
310 rep.length = 0;
311 rep.sequenceNumber = client->sequence;
312 /* screen dimensions */
313 rep.width = pseudoramiXScreens[stuff->screen].w;
314 // was screenInfo.screens[stuff->screen]->width;
315 rep.height = pseudoramiXScreens[stuff->screen].h;
316 // was screenInfo.screens[stuff->screen]->height;
317 rep.window = stuff->window;
318 rep.screen = stuff->screen;
319 if (client->swapped) {
320 swaps(&rep.sequenceNumber);
321 swapl(&rep.length);
322 swapl(&rep.width);
323 swapl(&rep.height);
324 swapl(&rep.window);
325 swapl(&rep.screen);
326 }
327 WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply),&rep);
328 return Success;
329 }
330
331 // was Xinerama
332 static int
ProcPseudoramiXIsActive(ClientPtr client)333 ProcPseudoramiXIsActive(ClientPtr client)
334 {
335 /* REQUEST(xXineramaIsActiveReq); */
336 xXineramaIsActiveReply rep;
337
338 TRACE;
339
340 REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
341
342 rep.type = X_Reply;
343 rep.length = 0;
344 rep.sequenceNumber = client->sequence;
345 rep.state = !noPseudoramiXExtension;
346 if (client->swapped) {
347 swaps(&rep.sequenceNumber);
348 swapl(&rep.length);
349 swapl(&rep.state);
350 }
351 WriteToClient(client, sizeof(xXineramaIsActiveReply),&rep);
352 return Success;
353 }
354
355 // was Xinerama
356 static int
ProcPseudoramiXQueryScreens(ClientPtr client)357 ProcPseudoramiXQueryScreens(ClientPtr client)
358 {
359 /* REQUEST(xXineramaQueryScreensReq); */
360 xXineramaQueryScreensReply rep;
361
362 DEBUG_LOG("noPseudoramiXExtension=%d, pseudoramiXNumScreens=%d\n",
363 noPseudoramiXExtension,
364 pseudoramiXNumScreens);
365
366 REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
367
368 rep.type = X_Reply;
369 rep.sequenceNumber = client->sequence;
370 rep.number = noPseudoramiXExtension ? 0 : pseudoramiXNumScreens;
371 rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo);
372 if (client->swapped) {
373 swaps(&rep.sequenceNumber);
374 swapl(&rep.length);
375 swapl(&rep.number);
376 }
377 WriteToClient(client, sizeof(xXineramaQueryScreensReply),&rep);
378
379 if (!noPseudoramiXExtension) {
380 xXineramaScreenInfo scratch;
381 int i;
382
383 for (i = 0; i < pseudoramiXNumScreens; i++) {
384 scratch.x_org = pseudoramiXScreens[i].x;
385 scratch.y_org = pseudoramiXScreens[i].y;
386 scratch.width = pseudoramiXScreens[i].w;
387 scratch.height = pseudoramiXScreens[i].h;
388
389 if (client->swapped) {
390 swaps(&scratch.x_org);
391 swaps(&scratch.y_org);
392 swaps(&scratch.width);
393 swaps(&scratch.height);
394 }
395 WriteToClient(client, sz_XineramaScreenInfo,&scratch);
396 }
397 }
398
399 return Success;
400 }
401
402 // was PanoramiX
403 static int
ProcPseudoramiXDispatch(ClientPtr client)404 ProcPseudoramiXDispatch(ClientPtr client)
405 {
406 REQUEST(xReq);
407 TRACE;
408 switch (stuff->data) {
409 case X_PanoramiXQueryVersion:
410 return ProcPseudoramiXQueryVersion(client);
411
412 case X_PanoramiXGetState:
413 return ProcPseudoramiXGetState(client);
414
415 case X_PanoramiXGetScreenCount:
416 return ProcPseudoramiXGetScreenCount(client);
417
418 case X_PanoramiXGetScreenSize:
419 return ProcPseudoramiXGetScreenSize(client);
420
421 case X_XineramaIsActive:
422 return ProcPseudoramiXIsActive(client);
423
424 case X_XineramaQueryScreens:
425 return ProcPseudoramiXQueryScreens(client);
426 }
427 return BadRequest;
428 }
429
430 static int
SProcPseudoramiXQueryVersion(ClientPtr client)431 SProcPseudoramiXQueryVersion(ClientPtr client)
432 {
433 REQUEST(xPanoramiXQueryVersionReq);
434
435 TRACE;
436
437 swaps(&stuff->length);
438 REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
439 return ProcPseudoramiXQueryVersion(client);
440 }
441
442 static int
SProcPseudoramiXGetState(ClientPtr client)443 SProcPseudoramiXGetState(ClientPtr client)
444 {
445 REQUEST(xPanoramiXGetStateReq);
446
447 TRACE;
448
449 swaps(&stuff->length);
450 REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
451 return ProcPseudoramiXGetState(client);
452 }
453
454 static int
SProcPseudoramiXGetScreenCount(ClientPtr client)455 SProcPseudoramiXGetScreenCount(ClientPtr client)
456 {
457 REQUEST(xPanoramiXGetScreenCountReq);
458
459 TRACE;
460
461 swaps(&stuff->length);
462 REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
463 return ProcPseudoramiXGetScreenCount(client);
464 }
465
466 static int
SProcPseudoramiXGetScreenSize(ClientPtr client)467 SProcPseudoramiXGetScreenSize(ClientPtr client)
468 {
469 REQUEST(xPanoramiXGetScreenSizeReq);
470
471 TRACE;
472
473 swaps(&stuff->length);
474 REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
475 return ProcPseudoramiXGetScreenSize(client);
476 }
477
478 static int
SProcPseudoramiXIsActive(ClientPtr client)479 SProcPseudoramiXIsActive(ClientPtr client)
480 {
481 REQUEST(xXineramaIsActiveReq);
482
483 TRACE;
484
485 swaps(&stuff->length);
486 REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
487 return ProcPseudoramiXIsActive(client);
488 }
489
490 static int
SProcPseudoramiXQueryScreens(ClientPtr client)491 SProcPseudoramiXQueryScreens(ClientPtr client)
492 {
493 REQUEST(xXineramaQueryScreensReq);
494
495 TRACE;
496
497 swaps(&stuff->length);
498 REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
499 return ProcPseudoramiXQueryScreens(client);
500 }
501
502 static int
SProcPseudoramiXDispatch(ClientPtr client)503 SProcPseudoramiXDispatch(ClientPtr client)
504 {
505 REQUEST(xReq);
506
507 TRACE;
508
509 switch (stuff->data) {
510 case X_PanoramiXQueryVersion:
511 return SProcPseudoramiXQueryVersion(client);
512
513 case X_PanoramiXGetState:
514 return SProcPseudoramiXGetState(client);
515
516 case X_PanoramiXGetScreenCount:
517 return SProcPseudoramiXGetScreenCount(client);
518
519 case X_PanoramiXGetScreenSize:
520 return SProcPseudoramiXGetScreenSize(client);
521
522 case X_XineramaIsActive:
523 return SProcPseudoramiXIsActive(client);
524
525 case X_XineramaQueryScreens:
526 return SProcPseudoramiXQueryScreens(client);
527 }
528 return BadRequest;
529 }
530