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