rrxinerama.c revision 4642e01f
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, DixGetAttrAccess);
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    rep.window = stuff->window;
142    if(client->swapped) {
143       swaps (&rep.sequenceNumber, n);
144       swapl (&rep.length, n);
145       swapl (&rep.window, n);
146    }
147    WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep);
148    return client->noClientException;
149}
150
151static Bool
152RRXineramaCrtcActive (RRCrtcPtr crtc)
153{
154    return crtc->mode != NULL && crtc->numOutputs > 0;
155}
156
157static int
158RRXineramaScreenCount (ScreenPtr pScreen)
159{
160    int	i, n;
161
162    n = 0;
163    if (rrGetScrPriv (pScreen))
164    {
165	rrScrPriv(pScreen);
166	for (i = 0; i < pScrPriv->numCrtcs; i++)
167	    if (RRXineramaCrtcActive (pScrPriv->crtcs[i]))
168		n++;
169    }
170    return n;
171}
172
173static Bool
174RRXineramaScreenActive (ScreenPtr pScreen)
175{
176    return RRXineramaScreenCount (pScreen) > 0;
177}
178
179int
180ProcRRXineramaGetScreenCount(ClientPtr client)
181{
182    REQUEST(xPanoramiXGetScreenCountReq);
183    WindowPtr				pWin;
184    xPanoramiXGetScreenCountReply	rep;
185    register int			n, rc;
186
187    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
188    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
189    if (rc != Success)
190	return rc;
191
192    rep.type = X_Reply;
193    rep.length = 0;
194    rep.sequenceNumber = client->sequence;
195    rep.ScreenCount = RRXineramaScreenCount (pWin->drawable.pScreen);
196    rep.window = stuff->window;
197    if(client->swapped) {
198       swaps(&rep.sequenceNumber, n);
199       swapl(&rep.length, n);
200       swapl(&rep.window, n);
201    }
202    WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep);
203    return client->noClientException;
204}
205
206int
207ProcRRXineramaGetScreenSize(ClientPtr client)
208{
209    REQUEST(xPanoramiXGetScreenSizeReq);
210    WindowPtr				pWin, pRoot;
211    ScreenPtr				pScreen;
212    xPanoramiXGetScreenSizeReply	rep;
213    register int			n, rc;
214
215    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
216    rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
217    if (rc != Success)
218	return rc;
219
220    pScreen = pWin->drawable.pScreen;
221    pRoot = WindowTable[pScreen->myNum];
222
223    rep.type = X_Reply;
224    rep.length = 0;
225    rep.sequenceNumber = client->sequence;
226    rep.width  = pRoot->drawable.width;
227    rep.height = pRoot->drawable.height;
228    rep.window = stuff->window;
229    rep.screen = stuff->screen;
230    if(client->swapped) {
231       swaps(&rep.sequenceNumber, n);
232       swapl(&rep.length, n);
233       swapl(&rep.width, n);
234       swapl(&rep.height, n);
235       swapl(&rep.window, n);
236       swapl(&rep.screen, n);
237    }
238    WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep);
239    return client->noClientException;
240}
241
242int
243ProcRRXineramaIsActive(ClientPtr client)
244{
245    xXineramaIsActiveReply	rep;
246
247    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
248
249    rep.type = X_Reply;
250    rep.length = 0;
251    rep.sequenceNumber = client->sequence;
252    rep.state = RRXineramaScreenActive (screenInfo.screens[RR_XINERAMA_SCREEN]);
253    if(client->swapped) {
254	register int n;
255	swaps(&rep.sequenceNumber, n);
256	swapl(&rep.length, n);
257	swapl(&rep.state, n);
258    }
259    WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep);
260    return client->noClientException;
261}
262
263static void
264RRXineramaWriteCrtc(ClientPtr client, RRCrtcPtr crtc)
265{
266    xXineramaScreenInfo scratch;
267
268    if (RRXineramaCrtcActive (crtc))
269    {
270	ScreenPtr pScreen = crtc->pScreen;
271	rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
272	BoxRec panned_area;
273
274	/* Check to see if crtc is panned and return the full area when applicable. */
275	if (pScrPriv && pScrPriv->rrGetPanning &&
276	    pScrPriv->rrGetPanning (pScreen, crtc, &panned_area, NULL, NULL) &&
277	    (panned_area.x2 > panned_area.x1) && (panned_area.y2 > panned_area.y1)) {
278	    scratch.x_org  = panned_area.x1;
279	    scratch.y_org  = panned_area.y1;
280	    scratch.width  = panned_area.x2  - panned_area.x1;
281	    scratch.height = panned_area.y2  - panned_area.y1;
282	} else {
283	    int width, height;
284	    RRCrtcGetScanoutSize (crtc, &width, &height);
285	    scratch.x_org  = crtc->x;
286	    scratch.y_org  = crtc->y;
287	    scratch.width  = width;
288	    scratch.height = height;
289	}
290	if(client->swapped) {
291	    register int n;
292	    swaps(&scratch.x_org, n);
293	    swaps(&scratch.y_org, n);
294	    swaps(&scratch.width, n);
295	    swaps(&scratch.height, n);
296	}
297	WriteToClient(client, sz_XineramaScreenInfo, &scratch);
298    }
299}
300
301int
302ProcRRXineramaQueryScreens(ClientPtr client)
303{
304    xXineramaQueryScreensReply	rep;
305    ScreenPtr	pScreen = screenInfo.screens[RR_XINERAMA_SCREEN];
306
307    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
308
309    if (RRXineramaScreenActive (pScreen))
310	RRGetInfo (pScreen, FALSE);
311
312    rep.type = X_Reply;
313    rep.sequenceNumber = client->sequence;
314    rep.number = RRXineramaScreenCount (pScreen);
315    rep.length = rep.number * sz_XineramaScreenInfo >> 2;
316    if(client->swapped) {
317	register int n;
318	swaps(&rep.sequenceNumber, n);
319	swapl(&rep.length, n);
320	swapl(&rep.number, n);
321    }
322    WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep);
323
324    if(rep.number) {
325	rrScrPriv(pScreen);
326	int i;
327	int has_primary = 0;
328
329	if (pScrPriv->primaryOutput && pScrPriv->primaryOutput->crtc) {
330	    has_primary = 1;
331	    RRXineramaWriteCrtc(client, pScrPriv->primaryOutput->crtc);
332	}
333
334	for(i = 0; i < pScrPriv->numCrtcs; i++) {
335	    if (has_primary &&
336		pScrPriv->primaryOutput->crtc == pScrPriv->crtcs[i])
337	    {
338		has_primary = 0;
339		continue;
340	    }
341	    RRXineramaWriteCrtc(client, pScrPriv->crtcs[i]);
342	}
343    }
344
345    return client->noClientException;
346}
347
348static int
349ProcRRXineramaDispatch(ClientPtr client)
350{
351    REQUEST(xReq);
352    switch (stuff->data) {
353	case X_PanoramiXQueryVersion:
354	     return ProcRRXineramaQueryVersion(client);
355	case X_PanoramiXGetState:
356	     return ProcRRXineramaGetState(client);
357	case X_PanoramiXGetScreenCount:
358	     return ProcRRXineramaGetScreenCount(client);
359	case X_PanoramiXGetScreenSize:
360	     return ProcRRXineramaGetScreenSize(client);
361	case X_XineramaIsActive:
362	     return ProcRRXineramaIsActive(client);
363	case X_XineramaQueryScreens:
364	     return ProcRRXineramaQueryScreens(client);
365    }
366    return BadRequest;
367}
368
369/* SProc */
370
371static int
372SProcRRXineramaQueryVersion (ClientPtr client)
373{
374    REQUEST(xPanoramiXQueryVersionReq);
375    register int n;
376    swaps(&stuff->length,n);
377    REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq);
378    return ProcRRXineramaQueryVersion(client);
379}
380
381static int
382SProcRRXineramaGetState(ClientPtr client)
383{
384    REQUEST(xPanoramiXGetStateReq);
385    register int n;
386    swaps (&stuff->length, n);
387    REQUEST_SIZE_MATCH(xPanoramiXGetStateReq);
388    swapl (&stuff->window, n);
389    return ProcRRXineramaGetState(client);
390}
391
392static int
393SProcRRXineramaGetScreenCount(ClientPtr client)
394{
395    REQUEST(xPanoramiXGetScreenCountReq);
396    register int n;
397    swaps (&stuff->length, n);
398    REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq);
399    swapl (&stuff->window, n);
400    return ProcRRXineramaGetScreenCount(client);
401}
402
403static int
404SProcRRXineramaGetScreenSize(ClientPtr client)
405{
406    REQUEST(xPanoramiXGetScreenSizeReq);
407    register int n;
408    swaps (&stuff->length, n);
409    REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq);
410    swapl (&stuff->window, n);
411    swapl (&stuff->screen, n);
412    return ProcRRXineramaGetScreenSize(client);
413}
414
415static int
416SProcRRXineramaIsActive(ClientPtr client)
417{
418    REQUEST(xXineramaIsActiveReq);
419    register int n;
420    swaps (&stuff->length, n);
421    REQUEST_SIZE_MATCH(xXineramaIsActiveReq);
422    return ProcRRXineramaIsActive(client);
423}
424
425static int
426SProcRRXineramaQueryScreens(ClientPtr client)
427{
428    REQUEST(xXineramaQueryScreensReq);
429    register int n;
430    swaps (&stuff->length, n);
431    REQUEST_SIZE_MATCH(xXineramaQueryScreensReq);
432    return ProcRRXineramaQueryScreens(client);
433}
434
435int
436SProcRRXineramaDispatch(ClientPtr client)
437{
438    REQUEST(xReq);
439    switch (stuff->data) {
440	case X_PanoramiXQueryVersion:
441	     return SProcRRXineramaQueryVersion(client);
442	case X_PanoramiXGetState:
443	     return SProcRRXineramaGetState(client);
444	case X_PanoramiXGetScreenCount:
445	     return SProcRRXineramaGetScreenCount(client);
446	case X_PanoramiXGetScreenSize:
447	     return SProcRRXineramaGetScreenSize(client);
448	case X_XineramaIsActive:
449	     return SProcRRXineramaIsActive(client);
450	case X_XineramaQueryScreens:
451	     return SProcRRXineramaQueryScreens(client);
452    }
453    return BadRequest;
454}
455
456void
457RRXineramaExtensionInit(void)
458{
459#ifdef PANORAMIX
460    if(!noPanoramiXExtension)
461	return;
462#endif
463
464    /*
465     * Xinerama isn't capable enough to have multiple protocol screens each
466     * with their own output geometry.  So if there's more than one protocol
467     * screen, just don't even try.
468     */
469    if (screenInfo.numScreens > 1)
470	return;
471
472    (void) AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0,
473			ProcRRXineramaDispatch,
474			SProcRRXineramaDispatch,
475			NULL,
476			StandardMinorOpcode);
477}
478