Commit | Line | Data |
---|---|---|
a09e091a JB |
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 "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 | ||
53 | extern int | |
54 | ProcPanoramiXQueryVersion(ClientPtr client); | |
55 | ||
56 | static void | |
57 | PseudoramiXResetProc(ExtensionEntry *extEntry); | |
58 | ||
59 | static int | |
60 | ProcPseudoramiXQueryVersion(ClientPtr client); | |
61 | static int | |
62 | ProcPseudoramiXGetState(ClientPtr client); | |
63 | static int | |
64 | ProcPseudoramiXGetScreenCount(ClientPtr client); | |
65 | static int | |
66 | ProcPseudoramiXGetScreenSize(ClientPtr client); | |
67 | static int | |
68 | ProcPseudoramiXIsActive(ClientPtr client); | |
69 | static int | |
70 | ProcPseudoramiXQueryScreens(ClientPtr client); | |
71 | static int | |
72 | ProcPseudoramiXDispatch(ClientPtr client); | |
73 | ||
74 | static int | |
75 | SProcPseudoramiXQueryVersion(ClientPtr client); | |
76 | static int | |
77 | SProcPseudoramiXGetState(ClientPtr client); | |
78 | static int | |
79 | SProcPseudoramiXGetScreenCount(ClientPtr client); | |
80 | static int | |
81 | SProcPseudoramiXGetScreenSize(ClientPtr client); | |
82 | static int | |
83 | SProcPseudoramiXIsActive(ClientPtr client); | |
84 | static int | |
85 | SProcPseudoramiXQueryScreens(ClientPtr client); | |
86 | static int | |
87 | SProcPseudoramiXDispatch(ClientPtr client); | |
88 | ||
89 | typedef struct { | |
90 | int x; | |
91 | int y; | |
92 | int w; | |
93 | int h; | |
94 | } PseudoramiXScreenRec; | |
95 | ||
96 | static PseudoramiXScreenRec *pseudoramiXScreens = NULL; | |
97 | static int pseudoramiXScreensAllocated = 0; | |
98 | static int pseudoramiXNumScreens = 0; | |
99 | static unsigned long pseudoramiXGeneration = 0; | |
100 | ||
101 | static void | |
102 | PseudoramiXTrace(const char *format, ...) | |
103 | { | |
104 | va_list ap; | |
105 | ||
106 | va_start(ap, format); | |
107 | LogVMessageVerb(X_NONE, 10, format, ap); | |
108 | va_end(ap); | |
109 | } | |
110 | ||
111 | static void | |
112 | PseudoramiXDebug(const char *format, ...) | |
113 | { | |
114 | va_list ap; | |
115 | ||
116 | va_start(ap, format); | |
117 | LogVMessageVerb(X_NONE, 3, format, ap); | |
118 | va_end(ap); | |
119 | } | |
120 | ||
121 | // Add a PseudoramiX screen. | |
122 | // The rest of the X server will know nothing about this screen. | |
123 | // Can be called before or after extension init. | |
124 | // Screens must be re-added once per generation. | |
125 | void | |
126 | PseudoramiXAddScreen(int x, int y, int w, int h) | |
127 | { | |
128 | PseudoramiXScreenRec *s; | |
129 | ||
130 | if (noPseudoramiXExtension) return; | |
131 | ||
132 | if (pseudoramiXNumScreens == pseudoramiXScreensAllocated) { | |
133 | pseudoramiXScreensAllocated += pseudoramiXScreensAllocated + 1; | |
134 | pseudoramiXScreens = realloc(pseudoramiXScreens, | |
135 | pseudoramiXScreensAllocated * | |
136 | sizeof(PseudoramiXScreenRec)); | |
137 | } | |
138 | ||
139 | DEBUG_LOG("x: %d, y: %d, w: %d, h: %d\n", x, y, w, h); | |
140 | ||
141 | s = &pseudoramiXScreens[pseudoramiXNumScreens++]; | |
142 | s->x = x; | |
143 | s->y = y; | |
144 | s->w = w; | |
145 | s->h = h; | |
146 | } | |
147 | ||
148 | // Initialize PseudoramiX. | |
149 | // Copied from PanoramiXExtensionInit | |
150 | void | |
151 | PseudoramiXExtensionInit(void) | |
152 | { | |
153 | Bool success = FALSE; | |
154 | ExtensionEntry *extEntry; | |
155 | ||
156 | if (noPseudoramiXExtension) return; | |
157 | ||
158 | TRACE; | |
159 | ||
160 | /* Even with only one screen we need to enable PseudoramiX to allow | |
161 | dynamic screen configuration changes. */ | |
162 | #if 0 | |
163 | if (pseudoramiXNumScreens == 1) { | |
164 | // Only one screen - disable Xinerama extension. | |
165 | noPseudoramiXExtension = TRUE; | |
166 | return; | |
167 | } | |
168 | #endif | |
169 | ||
170 | if (pseudoramiXGeneration != serverGeneration) { | |
171 | extEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0, 0, | |
172 | ProcPseudoramiXDispatch, | |
173 | SProcPseudoramiXDispatch, | |
174 | PseudoramiXResetProc, | |
175 | StandardMinorOpcode); | |
176 | if (!extEntry) { | |
177 | ErrorF("PseudoramiXExtensionInit(): AddExtension failed\n"); | |
178 | } | |
179 | else { | |
180 | pseudoramiXGeneration = serverGeneration; | |
181 | success = TRUE; | |
182 | } | |
183 | } | |
184 | ||
185 | if (!success) { | |
186 | ErrorF("%s Extension (PseudoramiX) failed to initialize\n", | |
187 | PANORAMIX_PROTOCOL_NAME); | |
188 | return; | |
189 | } | |
190 | } | |
191 | ||
192 | void | |
193 | PseudoramiXResetScreens(void) | |
194 | { | |
195 | TRACE; | |
196 | ||
197 | pseudoramiXNumScreens = 0; | |
198 | } | |
199 | ||
200 | static void | |
201 | PseudoramiXResetProc(ExtensionEntry *extEntry) | |
202 | { | |
203 | TRACE; | |
204 | ||
205 | PseudoramiXResetScreens(); | |
206 | } | |
207 | ||
208 | // was PanoramiX | |
209 | static int | |
210 | ProcPseudoramiXQueryVersion(ClientPtr client) | |
211 | { | |
212 | TRACE; | |
213 | ||
214 | return ProcPanoramiXQueryVersion(client); | |
215 | } | |
216 | ||
217 | // was PanoramiX | |
218 | static int | |
219 | ProcPseudoramiXGetState(ClientPtr client) | |
220 | { | |
221 | REQUEST(xPanoramiXGetStateReq); | |
222 | WindowPtr pWin; | |
223 | xPanoramiXGetStateReply rep; | |
224 | register int rc; | |
225 | ||
226 | TRACE; | |
227 | ||
228 | REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); | |
229 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
230 | if (rc != Success) | |
231 | return rc; | |
232 | ||
233 | rep.type = X_Reply; | |
234 | rep.length = 0; | |
235 | rep.sequenceNumber = client->sequence; | |
236 | rep.state = !noPseudoramiXExtension; | |
237 | rep.window = stuff->window; | |
238 | if (client->swapped) { | |
239 | swaps(&rep.sequenceNumber); | |
240 | swapl(&rep.length); | |
241 | swapl(&rep.window); | |
242 | } | |
243 | WriteToClient(client, sizeof(xPanoramiXGetStateReply),&rep); | |
244 | return Success; | |
245 | } | |
246 | ||
247 | // was PanoramiX | |
248 | static int | |
249 | ProcPseudoramiXGetScreenCount(ClientPtr client) | |
250 | { | |
251 | REQUEST(xPanoramiXGetScreenCountReq); | |
252 | WindowPtr pWin; | |
253 | xPanoramiXGetScreenCountReply rep; | |
254 | register int rc; | |
255 | ||
256 | TRACE; | |
257 | ||
258 | REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); | |
259 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
260 | if (rc != Success) | |
261 | return rc; | |
262 | ||
263 | rep.type = X_Reply; | |
264 | rep.length = 0; | |
265 | rep.sequenceNumber = client->sequence; | |
266 | rep.ScreenCount = pseudoramiXNumScreens; | |
267 | rep.window = stuff->window; | |
268 | if (client->swapped) { | |
269 | swaps(&rep.sequenceNumber); | |
270 | swapl(&rep.length); | |
271 | swapl(&rep.window); | |
272 | } | |
273 | WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply),&rep); | |
274 | return Success; | |
275 | } | |
276 | ||
277 | // was PanoramiX | |
278 | static int | |
279 | ProcPseudoramiXGetScreenSize(ClientPtr client) | |
280 | { | |
281 | REQUEST(xPanoramiXGetScreenSizeReq); | |
282 | WindowPtr pWin; | |
283 | xPanoramiXGetScreenSizeReply rep; | |
284 | register int rc; | |
285 | ||
286 | TRACE; | |
287 | ||
288 | if (stuff->screen >= pseudoramiXNumScreens) | |
289 | return BadMatch; | |
290 | ||
291 | REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); | |
292 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
293 | if (rc != Success) | |
294 | return rc; | |
295 | ||
296 | rep.type = X_Reply; | |
297 | rep.length = 0; | |
298 | rep.sequenceNumber = client->sequence; | |
299 | /* screen dimensions */ | |
300 | rep.width = pseudoramiXScreens[stuff->screen].w; | |
301 | // was screenInfo.screens[stuff->screen]->width; | |
302 | rep.height = pseudoramiXScreens[stuff->screen].h; | |
303 | // was screenInfo.screens[stuff->screen]->height; | |
304 | rep.window = stuff->window; | |
305 | rep.screen = stuff->screen; | |
306 | if (client->swapped) { | |
307 | swaps(&rep.sequenceNumber); | |
308 | swapl(&rep.length); | |
309 | swapl(&rep.width); | |
310 | swapl(&rep.height); | |
311 | swapl(&rep.window); | |
312 | swapl(&rep.screen); | |
313 | } | |
314 | WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply),&rep); | |
315 | return Success; | |
316 | } | |
317 | ||
318 | // was Xinerama | |
319 | static int | |
320 | ProcPseudoramiXIsActive(ClientPtr client) | |
321 | { | |
322 | /* REQUEST(xXineramaIsActiveReq); */ | |
323 | xXineramaIsActiveReply rep; | |
324 | ||
325 | TRACE; | |
326 | ||
327 | REQUEST_SIZE_MATCH(xXineramaIsActiveReq); | |
328 | ||
329 | rep.type = X_Reply; | |
330 | rep.length = 0; | |
331 | rep.sequenceNumber = client->sequence; | |
332 | rep.state = !noPseudoramiXExtension; | |
333 | if (client->swapped) { | |
334 | swaps(&rep.sequenceNumber); | |
335 | swapl(&rep.length); | |
336 | swapl(&rep.state); | |
337 | } | |
338 | WriteToClient(client, sizeof(xXineramaIsActiveReply),&rep); | |
339 | return Success; | |
340 | } | |
341 | ||
342 | // was Xinerama | |
343 | static int | |
344 | ProcPseudoramiXQueryScreens(ClientPtr client) | |
345 | { | |
346 | /* REQUEST(xXineramaQueryScreensReq); */ | |
347 | xXineramaQueryScreensReply rep; | |
348 | ||
349 | DEBUG_LOG("noPseudoramiXExtension=%d, pseudoramiXNumScreens=%d\n", | |
350 | noPseudoramiXExtension, | |
351 | pseudoramiXNumScreens); | |
352 | ||
353 | REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); | |
354 | ||
355 | rep.type = X_Reply; | |
356 | rep.sequenceNumber = client->sequence; | |
357 | rep.number = noPseudoramiXExtension ? 0 : pseudoramiXNumScreens; | |
358 | rep.length = bytes_to_int32(rep.number * sz_XineramaScreenInfo); | |
359 | if (client->swapped) { | |
360 | swaps(&rep.sequenceNumber); | |
361 | swapl(&rep.length); | |
362 | swapl(&rep.number); | |
363 | } | |
364 | WriteToClient(client, sizeof(xXineramaQueryScreensReply),&rep); | |
365 | ||
366 | if (!noPseudoramiXExtension) { | |
367 | xXineramaScreenInfo scratch; | |
368 | int i; | |
369 | ||
370 | for (i = 0; i < pseudoramiXNumScreens; i++) { | |
371 | scratch.x_org = pseudoramiXScreens[i].x; | |
372 | scratch.y_org = pseudoramiXScreens[i].y; | |
373 | scratch.width = pseudoramiXScreens[i].w; | |
374 | scratch.height = pseudoramiXScreens[i].h; | |
375 | ||
376 | if (client->swapped) { | |
377 | swaps(&scratch.x_org); | |
378 | swaps(&scratch.y_org); | |
379 | swaps(&scratch.width); | |
380 | swaps(&scratch.height); | |
381 | } | |
382 | WriteToClient(client, sz_XineramaScreenInfo,&scratch); | |
383 | } | |
384 | } | |
385 | ||
386 | return Success; | |
387 | } | |
388 | ||
389 | // was PanoramiX | |
390 | static int | |
391 | ProcPseudoramiXDispatch(ClientPtr client) | |
392 | { | |
393 | REQUEST(xReq); | |
394 | TRACE; | |
395 | switch (stuff->data) { | |
396 | case X_PanoramiXQueryVersion: | |
397 | return ProcPseudoramiXQueryVersion(client); | |
398 | ||
399 | case X_PanoramiXGetState: | |
400 | return ProcPseudoramiXGetState(client); | |
401 | ||
402 | case X_PanoramiXGetScreenCount: | |
403 | return ProcPseudoramiXGetScreenCount(client); | |
404 | ||
405 | case X_PanoramiXGetScreenSize: | |
406 | return ProcPseudoramiXGetScreenSize(client); | |
407 | ||
408 | case X_XineramaIsActive: | |
409 | return ProcPseudoramiXIsActive(client); | |
410 | ||
411 | case X_XineramaQueryScreens: | |
412 | return ProcPseudoramiXQueryScreens(client); | |
413 | } | |
414 | return BadRequest; | |
415 | } | |
416 | ||
417 | static int | |
418 | SProcPseudoramiXQueryVersion(ClientPtr client) | |
419 | { | |
420 | REQUEST(xPanoramiXQueryVersionReq); | |
421 | ||
422 | TRACE; | |
423 | ||
424 | swaps(&stuff->length); | |
425 | REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); | |
426 | return ProcPseudoramiXQueryVersion(client); | |
427 | } | |
428 | ||
429 | static int | |
430 | SProcPseudoramiXGetState(ClientPtr client) | |
431 | { | |
432 | REQUEST(xPanoramiXGetStateReq); | |
433 | ||
434 | TRACE; | |
435 | ||
436 | swaps(&stuff->length); | |
437 | REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); | |
438 | return ProcPseudoramiXGetState(client); | |
439 | } | |
440 | ||
441 | static int | |
442 | SProcPseudoramiXGetScreenCount(ClientPtr client) | |
443 | { | |
444 | REQUEST(xPanoramiXGetScreenCountReq); | |
445 | ||
446 | TRACE; | |
447 | ||
448 | swaps(&stuff->length); | |
449 | REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); | |
450 | return ProcPseudoramiXGetScreenCount(client); | |
451 | } | |
452 | ||
453 | static int | |
454 | SProcPseudoramiXGetScreenSize(ClientPtr client) | |
455 | { | |
456 | REQUEST(xPanoramiXGetScreenSizeReq); | |
457 | ||
458 | TRACE; | |
459 | ||
460 | swaps(&stuff->length); | |
461 | REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); | |
462 | return ProcPseudoramiXGetScreenSize(client); | |
463 | } | |
464 | ||
465 | static int | |
466 | SProcPseudoramiXIsActive(ClientPtr client) | |
467 | { | |
468 | REQUEST(xXineramaIsActiveReq); | |
469 | ||
470 | TRACE; | |
471 | ||
472 | swaps(&stuff->length); | |
473 | REQUEST_SIZE_MATCH(xXineramaIsActiveReq); | |
474 | return ProcPseudoramiXIsActive(client); | |
475 | } | |
476 | ||
477 | static int | |
478 | SProcPseudoramiXQueryScreens(ClientPtr client) | |
479 | { | |
480 | REQUEST(xXineramaQueryScreensReq); | |
481 | ||
482 | TRACE; | |
483 | ||
484 | swaps(&stuff->length); | |
485 | REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); | |
486 | return ProcPseudoramiXQueryScreens(client); | |
487 | } | |
488 | ||
489 | static int | |
490 | SProcPseudoramiXDispatch(ClientPtr client) | |
491 | { | |
492 | REQUEST(xReq); | |
493 | ||
494 | TRACE; | |
495 | ||
496 | switch (stuff->data) { | |
497 | case X_PanoramiXQueryVersion: | |
498 | return SProcPseudoramiXQueryVersion(client); | |
499 | ||
500 | case X_PanoramiXGetState: | |
501 | return SProcPseudoramiXGetState(client); | |
502 | ||
503 | case X_PanoramiXGetScreenCount: | |
504 | return SProcPseudoramiXGetScreenCount(client); | |
505 | ||
506 | case X_PanoramiXGetScreenSize: | |
507 | return SProcPseudoramiXGetScreenSize(client); | |
508 | ||
509 | case X_XineramaIsActive: | |
510 | return SProcPseudoramiXIsActive(client); | |
511 | ||
512 | case X_XineramaQueryScreens: | |
513 | return SProcPseudoramiXQueryScreens(client); | |
514 | } | |
515 | return BadRequest; | |
516 | } |