rrxinerama.c revision 05b261ec
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
75#define RR_XINERAMA_MAJOR_VERSION   1
76#define RR_XINERAMA_MINOR_VERSION   1
77
78/* Xinerama is not multi-screen capable; just report about screen 0 */
79#define RR_XINERAMA_SCREEN  0
80
81static int ProcRRXineramaQueryVersion(ClientPtr client);
82static int ProcRRXineramaGetState(ClientPtr client);
83static int ProcRRXineramaGetScreenCount(ClientPtr client);
84static int ProcRRXineramaGetScreenSize(ClientPtr client);
85static int ProcRRXineramaIsActive(ClientPtr client);
86static int ProcRRXineramaQueryScreens(ClientPtr client);
87static int SProcRRXineramaDispatch(ClientPtr client);
88
89/* Proc */
90
91int
92ProcRRXineramaQueryVersion(ClientPtr client)
93{
94    xPanoramiXQueryVersionReply	  rep;
95    register int		  n;
96
97    REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq);
98    rep.type = X_Reply;
99    rep.length = 0;
100    rep.sequenceNumber = client->sequence;
101    rep.majorVersion = RR_XINERAMA_MAJOR_VERSION;
102    rep.minorVersion = RR_XINERAMA_MINOR_VERSION;
103    if(client->swapped) {
104        swaps(&rep.sequenceNumber, n);
105        swapl(&rep.length, n);
106        swaps(&rep.majorVersion, n);
107        swaps(&rep.minorVersion, n);
108    }
109    WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep);
110    return (client->noClientException);
111}
112
113int
114ProcRRXineramaGetState(ClientPtr client)
115{
116    REQUEST(xPanoramiXGetStateReq);
117    WindowPtr			pWin;
118    xPanoramiXGetStateReply	rep;
119    register int		n, rc;
120    ScreenPtr			pScreen;
121    rrScrPrivPtr		pScrPriv;
122    Bool			active = FALSE;
123
124    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
125    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
126    if(rc != Success)
127	return rc;
128
129    pScreen = pWin->drawable.pScreen;
130    pScrPriv = rrGetScrPriv(pScreen);
131    if (pScrPriv)
132    {
133	/* XXX do we need more than this? */
134	active = TRUE;
135    }
136
137    rep.type = X_Reply;
138    rep.length = 0;
139    rep.sequenceNumber = client->sequence;
140    rep.state = active;
141    if(client->swapped) {
142       swaps (&rep.sequenceNumber, n);
143       swapl (&rep.length, n);
144       swaps (&rep.state, n);
145    }
146    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
147    return client->noClientException;
148}
149
150static Bool
151RRXineramaCrtcActive (RRCrtcPtr crtc)
152{
153    return crtc->mode != NULL && crtc->numOutputs > 0;
154}
155
156static int
157RRXineramaScreenCount (ScreenPtr pScreen)
158{
159    int	i, n;
160
161    n = 0;
162    if (rrGetScrPriv (pScreen))
163    {
164	rrScrPriv(pScreen);
165	for (i = 0; i < pScrPriv->numCrtcs; i++)
166	    if (RRXineramaCrtcActive (pScrPriv->crtcs[i]))
167		n++;
168    }
169    return n;
170}
171
172static Bool
173RRXineramaScreenActive (ScreenPtr pScreen)
174{
175    return RRXineramaScreenCount (pScreen) > 0;
176}
177
178int
179ProcRRXineramaGetScreenCount(ClientPtr client)
180{
181    REQUEST(xPanoramiXGetScreenCountReq);
182    WindowPtr				pWin;
183    xPanoramiXGetScreenCountReply	rep;
184    register int			n, rc;
185
186    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
187    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
188    if (rc != Success)
189	return rc;
190
191    rep.type = X_Reply;
192    rep.length = 0;
193    rep.sequenceNumber = client->sequence;
194    rep.ScreenCount = RRXineramaScreenCount (pWin->drawable.pScreen);
195    if(client->swapped) {
196       swaps(&rep.sequenceNumber, n);
197       swapl(&rep.length, n);
198       swaps(&rep.ScreenCount, n);
199    }
200    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
201    return client->noClientException;
202}
203
204int
205ProcRRXineramaGetScreenSize(ClientPtr client)
206{
207    REQUEST(xPanoramiXGetScreenSizeReq);
208    WindowPtr				pWin, pRoot;
209    ScreenPtr				pScreen;
210    xPanoramiXGetScreenSizeReply	rep;
211    register int			n, rc;
212
213    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
214    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
215    if (rc != Success)
216	return rc;
217
218    pScreen = pWin->drawable.pScreen;
219    pRoot = WindowTable[pScreen->myNum];
220
221    rep.type = X_Reply;
222    rep.length = 0;
223    rep.sequenceNumber = client->sequence;
224    rep.width  = pRoot->drawable.width;
225    rep.height = pRoot->drawable.height;
226    if(client->swapped) {
227       swaps(&rep.sequenceNumber, n);
228       swapl(&rep.length, n);
229       swaps(&rep.width, n);
230       swaps(&rep.height, n);
231    }
232    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
233    return client->noClientException;
234}
235
236int
237ProcRRXineramaIsActive(ClientPtr client)
238{
239    xXineramaIsActiveReply	rep;
240
241    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
242
243    rep.type = X_Reply;
244    rep.length = 0;
245    rep.sequenceNumber = client->sequence;
246    rep.state = RRXineramaScreenActive (screenInfo.screens[RR_XINERAMA_SCREEN]);
247    if(client->swapped) {
248	register int n;
249	swaps(&rep.sequenceNumber, n);
250	swapl(&rep.length, n);
251	swapl(&rep.state, n);
252    }
253    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
254    return client->noClientException;
255}
256
257int
258ProcRRXineramaQueryScreens(ClientPtr client)
259{
260    xXineramaQueryScreensReply	rep;
261    ScreenPtr	pScreen = screenInfo.screens[RR_XINERAMA_SCREEN];
262
263    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
264
265    if (RRXineramaScreenActive (pScreen))
266    {
267	rrScrPriv(pScreen);
268	if (pScrPriv->numCrtcs == 0 || pScrPriv->numOutputs == 0)
269	    RRGetInfo (pScreen);
270    }
271
272    rep.type = X_Reply;
273    rep.sequenceNumber = client->sequence;
274    rep.number = RRXineramaScreenCount (pScreen);
275    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
276    if(client->swapped) {
277	register int n;
278	swaps(&rep.sequenceNumber, n);
279	swapl(&rep.length, n);
280	swapl(&rep.number, n);
281    }
282    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
283
284    if(rep.number) {
285	rrScrPriv(pScreen);
286	xXineramaScreenInfo scratch;
287	int i;
288
289	for(i = 0; i < pScrPriv->numCrtcs; i++) {
290	    RRCrtcPtr	crtc = pScrPriv->crtcs[i];
291	    if (RRXineramaCrtcActive (crtc))
292	    {
293	        int width, height;
294		RRCrtcGetScanoutSize (crtc, &width, &height);
295		scratch.x_org  = crtc->x;
296		scratch.y_org  = crtc->y;
297		scratch.width  = width;
298		scratch.height = height;
299		if(client->swapped) {
300		    register int n;
301		    swaps(&scratch.x_org, n);
302		    swaps(&scratch.y_org, n);
303		    swaps(&scratch.width, n);
304		    swaps(&scratch.height, n);
305		}
306		WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch);
307	    }
308	}
309    }
310
311    return client->noClientException;
312}
313
314static int
315ProcRRXineramaDispatch(ClientPtr client)
316{
317    REQUEST(xReq);
318    switch (stuff->data) {
319	case X_PanoramiXQueryVersion:
320	     return ProcRRXineramaQueryVersion(client);
321	case X_PanoramiXGetState:
322	     return ProcRRXineramaGetState(client);
323	case X_PanoramiXGetScreenCount:
324	     return ProcRRXineramaGetScreenCount(client);
325	case X_PanoramiXGetScreenSize:
326	     return ProcRRXineramaGetScreenSize(client);
327	case X_XineramaIsActive:
328	     return ProcRRXineramaIsActive(client);
329	case X_XineramaQueryScreens:
330	     return ProcRRXineramaQueryScreens(client);
331    }
332    return BadRequest;
333}
334
335/* SProc */
336
337static int
338SProcRRXineramaQueryVersion (ClientPtr client)
339{
340    REQUEST(xPanoramiXQueryVersionReq);
341    register int n;
342    swaps(&stuff->length,n);
343    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
344    return ProcRRXineramaQueryVersion(client);
345}
346
347static int
348SProcRRXineramaGetState(ClientPtr client)
349{
350    REQUEST(xPanoramiXGetStateReq);
351    register int n;
352    swaps (&stuff->length, n);
353    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
354    return ProcRRXineramaGetState(client);
355}
356
357static int
358SProcRRXineramaGetScreenCount(ClientPtr client)
359{
360    REQUEST(xPanoramiXGetScreenCountReq);
361    register int n;
362    swaps (&stuff->length, n);
363    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
364    return ProcRRXineramaGetScreenCount(client);
365}
366
367static int
368SProcRRXineramaGetScreenSize(ClientPtr client)
369{
370    REQUEST(xPanoramiXGetScreenSizeReq);
371    register int n;
372    swaps (&stuff->length, n);
373    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
374    return ProcRRXineramaGetScreenSize(client);
375}
376
377static int
378SProcRRXineramaIsActive(ClientPtr client)
379{
380    REQUEST(xXineramaIsActiveReq);
381    register int n;
382    swaps (&stuff->length, n);
383    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
384    return ProcRRXineramaIsActive(client);
385}
386
387static int
388SProcRRXineramaQueryScreens(ClientPtr client)
389{
390    REQUEST(xXineramaQueryScreensReq);
391    register int n;
392    swaps (&stuff->length, n);
393    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
394    return ProcRRXineramaQueryScreens(client);
395}
396
397int
398SProcRRXineramaDispatch(ClientPtr client)
399{
400    REQUEST(xReq);
401    switch (stuff->data) {
402	case X_PanoramiXQueryVersion:
403	     return SProcRRXineramaQueryVersion(client);
404	case X_PanoramiXGetState:
405	     return SProcRRXineramaGetState(client);
406	case X_PanoramiXGetScreenCount:
407	     return SProcRRXineramaGetScreenCount(client);
408	case X_PanoramiXGetScreenSize:
409	     return SProcRRXineramaGetScreenSize(client);
410	case X_XineramaIsActive:
411	     return SProcRRXineramaIsActive(client);
412	case X_XineramaQueryScreens:
413	     return SProcRRXineramaQueryScreens(client);
414    }
415    return BadRequest;
416}
417
418static void
419RRXineramaResetProc(ExtensionEntry* extEntry)
420{
421}
422
423void
424RRXineramaExtensionInit(void)
425{
426#ifdef PANORAMIX
427    if(!noPanoramiXExtension)
428	return;
429#endif
430
431    /*
432     * Xinerama isn't capable enough to have multiple protocol screens each
433     * with their own output geometry.  So if there's more than one protocol
434     * screen, just don't even try.
435     */
436    if (screenInfo.numScreens > 1)
437	return;
438
439    (void) AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
440			ProcRRXineramaDispatch,
441			SProcRRXineramaDispatch,
442			RRXineramaResetProc,
443			StandardMinorOpcode);
444}
445