xref: /OK3568_Linux_fs/external/xserver/pseudoramiX/pseudoramiX.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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