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