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