xf86Cursors.c revision 05b261ec
1/* 2 * Copyright © 2007 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#ifdef HAVE_XORG_CONFIG_H 24#include <xorg-config.h> 25#else 26#ifdef HAVE_CONFIG_H 27#include <config.h> 28#endif 29#endif 30 31#include <stddef.h> 32#include <string.h> 33#include <stdio.h> 34 35#include "xf86.h" 36#include "xf86DDC.h" 37#include "xf86Crtc.h" 38#include "xf86Modes.h" 39#include "xf86RandR12.h" 40#include "X11/extensions/render.h" 41#define DPMS_SERVER 42#include "X11/extensions/dpms.h" 43#include "X11/Xatom.h" 44#ifdef RENDER 45#include "picturestr.h" 46#endif 47#include "cursorstr.h" 48 49/* 50 * Given a screen coordinate, rotate back to a cursor source coordinate 51 */ 52static void 53xf86_crtc_rotate_coord (Rotation rotation, 54 int width, 55 int height, 56 int x_dst, 57 int y_dst, 58 int *x_src, 59 int *y_src) 60{ 61 int t; 62 63 switch (rotation & 0xf) { 64 case RR_Rotate_0: 65 break; 66 case RR_Rotate_90: 67 t = x_dst; 68 x_dst = height - y_dst - 1; 69 y_dst = t; 70 break; 71 case RR_Rotate_180: 72 x_dst = width - x_dst - 1; 73 y_dst = height - y_dst - 1; 74 break; 75 case RR_Rotate_270: 76 t = x_dst; 77 x_dst = y_dst; 78 y_dst = width - t - 1; 79 break; 80 } 81 if (rotation & RR_Reflect_X) 82 x_dst = width - x_dst - 1; 83 if (rotation & RR_Reflect_Y) 84 y_dst = height - y_dst - 1; 85 *x_src = x_dst; 86 *y_src = y_dst; 87} 88 89/* 90 * Given a cursor source coordinate, rotate to a screen coordinate 91 */ 92static void 93xf86_crtc_rotate_coord_back (Rotation rotation, 94 int width, 95 int height, 96 int x_dst, 97 int y_dst, 98 int *x_src, 99 int *y_src) 100{ 101 int t; 102 103 if (rotation & RR_Reflect_X) 104 x_dst = width - x_dst - 1; 105 if (rotation & RR_Reflect_Y) 106 y_dst = height - y_dst - 1; 107 108 switch (rotation & 0xf) { 109 case RR_Rotate_0: 110 break; 111 case RR_Rotate_90: 112 t = x_dst; 113 x_dst = y_dst; 114 y_dst = width - t - 1; 115 break; 116 case RR_Rotate_180: 117 x_dst = width - x_dst - 1; 118 y_dst = height - y_dst - 1; 119 break; 120 case RR_Rotate_270: 121 t = x_dst; 122 x_dst = height - y_dst - 1; 123 y_dst = t; 124 break; 125 } 126 *x_src = x_dst; 127 *y_src = y_dst; 128} 129 130/* 131 * Convert an x coordinate to a position within the cursor bitmap 132 */ 133static int 134cursor_bitpos (int flags, int x, Bool mask) 135{ 136 if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) 137 mask = !mask; 138 if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) 139 x = (x & ~3) | (3 - (x & 3)); 140 if (((flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) == 0) == 141 (X_BYTE_ORDER == X_BIG_ENDIAN)) 142 x = (x & ~7) | (7 - (x & 7)); 143 if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1) 144 x = (x << 1) + mask; 145 else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8) 146 x = ((x & ~7) << 1) | (mask << 3) | (x & 7); 147 else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16) 148 x = ((x & ~15) << 1) | (mask << 4) | (x & 15); 149 else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32) 150 x = ((x & ~31) << 1) | (mask << 5) | (x & 31); 151 else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64) 152 x = ((x & ~63) << 1) | (mask << 6) | (x & 63); 153 return x; 154} 155 156/* 157 * Fetch one bit from a cursor bitmap 158 */ 159static CARD8 160get_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) 161{ 162 x = cursor_bitpos (flags, x, mask); 163 image += y * stride; 164 return (image[(x >> 3)] >> (x & 7)) & 1; 165} 166 167/* 168 * Set one bit in a cursor bitmap 169 */ 170static void 171set_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask) 172{ 173 x = cursor_bitpos (flags, x, mask); 174 image += y * stride; 175 image[(x >> 3)] |= 1 << (x & 7); 176} 177 178/* 179 * Load a two color cursor into a driver that supports only ARGB cursors 180 */ 181static void 182xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src) 183{ 184 ScrnInfoPtr scrn = crtc->scrn; 185 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 186 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 187 CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; 188 int x, y; 189 int xin, yin; 190 int stride = cursor_info->MaxWidth >> 2; 191 int flags = cursor_info->Flags; 192 CARD32 bits; 193 194#ifdef ARGB_CURSOR 195 crtc->cursor_argb = FALSE; 196#endif 197 198 for (y = 0; y < cursor_info->MaxHeight; y++) 199 for (x = 0; x < cursor_info->MaxWidth; x++) 200 { 201 xf86_crtc_rotate_coord (crtc->rotation, 202 cursor_info->MaxWidth, 203 cursor_info->MaxHeight, 204 x, y, &xin, &yin); 205 if (get_bit (src, stride, flags, xin, yin, TRUE) == 206 ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) 207 { 208 if (get_bit (src, stride, flags, xin, yin, FALSE)) 209 bits = xf86_config->cursor_fg; 210 else 211 bits = xf86_config->cursor_bg; 212 } 213 else 214 bits = 0; 215 cursor_image[y * cursor_info->MaxWidth + x] = bits; 216 } 217 crtc->funcs->load_cursor_argb (crtc, cursor_image); 218} 219 220/* 221 * Set the colors for a two-color cursor (ignore for ARGB cursors) 222 */ 223static void 224xf86_set_cursor_colors (ScrnInfoPtr scrn, int bg, int fg) 225{ 226 ScreenPtr screen = scrn->pScreen; 227 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 228 CursorPtr cursor = xf86_config->cursor; 229 int c; 230 CARD8 *bits = cursor ? cursor->devPriv[screen->myNum] : NULL; 231 232 /* Save ARGB versions of these colors */ 233 xf86_config->cursor_fg = (CARD32) fg | 0xff000000; 234 xf86_config->cursor_bg = (CARD32) bg | 0xff000000; 235 236 for (c = 0; c < xf86_config->num_crtc; c++) 237 { 238 xf86CrtcPtr crtc = xf86_config->crtc[c]; 239 240 if (crtc->enabled && !crtc->cursor_argb) 241 { 242 if (crtc->funcs->load_cursor_image) 243 crtc->funcs->set_cursor_colors (crtc, bg, fg); 244 else if (bits) 245 xf86_crtc_convert_cursor_to_argb (crtc, bits); 246 } 247 } 248} 249 250static void 251xf86_crtc_hide_cursor (xf86CrtcPtr crtc) 252{ 253 if (crtc->cursor_shown) 254 { 255 crtc->funcs->hide_cursor (crtc); 256 crtc->cursor_shown = FALSE; 257 } 258} 259 260_X_EXPORT void 261xf86_hide_cursors (ScrnInfoPtr scrn) 262{ 263 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 264 int c; 265 266 xf86_config->cursor_on = FALSE; 267 for (c = 0; c < xf86_config->num_crtc; c++) 268 { 269 xf86CrtcPtr crtc = xf86_config->crtc[c]; 270 271 if (crtc->enabled) 272 xf86_crtc_hide_cursor (crtc); 273 } 274} 275 276static void 277xf86_crtc_show_cursor (xf86CrtcPtr crtc) 278{ 279 if (!crtc->cursor_shown && crtc->cursor_in_range) 280 { 281 crtc->funcs->show_cursor (crtc); 282 crtc->cursor_shown = TRUE; 283 } 284} 285 286_X_EXPORT void 287xf86_show_cursors (ScrnInfoPtr scrn) 288{ 289 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 290 int c; 291 292 xf86_config->cursor_on = TRUE; 293 for (c = 0; c < xf86_config->num_crtc; c++) 294 { 295 xf86CrtcPtr crtc = xf86_config->crtc[c]; 296 297 if (crtc->enabled) 298 xf86_crtc_show_cursor (crtc); 299 } 300} 301 302static void 303xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 304{ 305 ScrnInfoPtr scrn = crtc->scrn; 306 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 307 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 308 DisplayModePtr mode = &crtc->mode; 309 Bool in_range; 310 int dx, dy; 311 312 /* 313 * Transform position of cursor on screen 314 */ 315 if (crtc->transform_in_use) 316 { 317 PictVector v; 318 v.vector[0] = IntToxFixed (x); v.vector[1] = IntToxFixed (y); v.vector[2] = IntToxFixed(1); 319 PictureTransformPoint (&crtc->framebuffer_to_crtc, &v); 320 x = xFixedToInt (v.vector[0]); y = xFixedToInt (v.vector[1]); 321 } 322 else 323 { 324 x -= crtc->x; 325 y -= crtc->y; 326 } 327 /* 328 * Transform position of cursor upper left corner 329 */ 330 xf86_crtc_rotate_coord_back (crtc->rotation, 331 cursor_info->MaxWidth, 332 cursor_info->MaxHeight, 333 0, 0, &dx, &dy); 334 x -= dx; 335 y -= dy; 336 337 /* 338 * Disable the cursor when it is outside the viewport 339 */ 340 in_range = TRUE; 341 if (x >= mode->HDisplay || y >= mode->VDisplay || 342 x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight) 343 { 344 in_range = FALSE; 345 x = 0; 346 y = 0; 347 } 348 349 crtc->cursor_in_range = in_range; 350 351 if (in_range) 352 { 353 crtc->funcs->set_cursor_position (crtc, x, y); 354 xf86_crtc_show_cursor (crtc); 355 } 356 else 357 xf86_crtc_hide_cursor (crtc); 358} 359 360static void 361xf86_set_cursor_position (ScrnInfoPtr scrn, int x, int y) 362{ 363 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 364 int c; 365 366 /* undo what xf86HWCurs did to the coordinates */ 367 x += scrn->frameX0; 368 y += scrn->frameY0; 369 for (c = 0; c < xf86_config->num_crtc; c++) 370 { 371 xf86CrtcPtr crtc = xf86_config->crtc[c]; 372 373 if (crtc->enabled) 374 xf86_crtc_set_cursor_position (crtc, x, y); 375 } 376} 377 378/* 379 * Load a two-color cursor into a crtc, performing rotation as needed 380 */ 381static void 382xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src) 383{ 384 ScrnInfoPtr scrn = crtc->scrn; 385 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 386 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 387 CARD8 *cursor_image; 388 389#ifdef ARGB_CURSOR 390 crtc->cursor_argb = FALSE; 391#endif 392 393 if (crtc->rotation == RR_Rotate_0) 394 cursor_image = src; 395 else 396 { 397 int x, y; 398 int xin, yin; 399 int stride = cursor_info->MaxWidth >> 2; 400 int flags = cursor_info->Flags; 401 402 cursor_image = xf86_config->cursor_image; 403 memset(cursor_image, 0, cursor_info->MaxWidth * stride); 404 405 for (y = 0; y < cursor_info->MaxHeight; y++) 406 for (x = 0; x < cursor_info->MaxWidth; x++) 407 { 408 xf86_crtc_rotate_coord (crtc->rotation, 409 cursor_info->MaxWidth, 410 cursor_info->MaxHeight, 411 x, y, &xin, &yin); 412 if (get_bit(src, stride, flags, xin, yin, FALSE)) 413 set_bit(cursor_image, stride, flags, x, y, FALSE); 414 if (get_bit(src, stride, flags, xin, yin, TRUE)) 415 set_bit(cursor_image, stride, flags, x, y, TRUE); 416 } 417 } 418 crtc->funcs->load_cursor_image (crtc, cursor_image); 419} 420 421/* 422 * Load a cursor image into all active CRTCs 423 */ 424static void 425xf86_load_cursor_image (ScrnInfoPtr scrn, unsigned char *src) 426{ 427 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 428 int c; 429 430 for (c = 0; c < xf86_config->num_crtc; c++) 431 { 432 xf86CrtcPtr crtc = xf86_config->crtc[c]; 433 434 if (crtc->enabled) 435 { 436 if (crtc->funcs->load_cursor_image) 437 xf86_crtc_load_cursor_image (crtc, src); 438 else if (crtc->funcs->load_cursor_argb) 439 xf86_crtc_convert_cursor_to_argb (crtc, src); 440 } 441 } 442} 443 444static Bool 445xf86_use_hw_cursor (ScreenPtr screen, CursorPtr cursor) 446{ 447 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 448 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 449 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 450 451 if (xf86_config->cursor) 452 FreeCursor (xf86_config->cursor, None); 453 xf86_config->cursor = cursor; 454 ++cursor->refcnt; 455 456 if (cursor->bits->width > cursor_info->MaxWidth || 457 cursor->bits->height> cursor_info->MaxHeight) 458 return FALSE; 459 460 return TRUE; 461} 462 463static Bool 464xf86_use_hw_cursor_argb (ScreenPtr screen, CursorPtr cursor) 465{ 466 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 467 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 468 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 469 470 if (xf86_config->cursor) 471 FreeCursor (xf86_config->cursor, None); 472 xf86_config->cursor = cursor; 473 ++cursor->refcnt; 474 475 /* Make sure ARGB support is available */ 476 if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0) 477 return FALSE; 478 479 if (cursor->bits->width > cursor_info->MaxWidth || 480 cursor->bits->height> cursor_info->MaxHeight) 481 return FALSE; 482 483 return TRUE; 484} 485 486static void 487xf86_crtc_load_cursor_argb (xf86CrtcPtr crtc, CursorPtr cursor) 488{ 489 ScrnInfoPtr scrn = crtc->scrn; 490 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 491 xf86CursorInfoPtr cursor_info = xf86_config->cursor_info; 492 CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image; 493 CARD32 *cursor_source = (CARD32 *) cursor->bits->argb; 494 int x, y; 495 int xin, yin; 496 CARD32 bits; 497 int source_width = cursor->bits->width; 498 int source_height = cursor->bits->height; 499 int image_width = cursor_info->MaxWidth; 500 int image_height = cursor_info->MaxHeight; 501 502 for (y = 0; y < image_height; y++) 503 for (x = 0; x < image_width; x++) 504 { 505 xf86_crtc_rotate_coord (crtc->rotation, image_width, image_height, 506 x, y, &xin, &yin); 507 if (xin < source_width && yin < source_height) 508 bits = cursor_source[yin * source_width + xin]; 509 else 510 bits = 0; 511 cursor_image[y * image_width + x] = bits; 512 } 513 514 crtc->funcs->load_cursor_argb (crtc, cursor_image); 515} 516 517static void 518xf86_load_cursor_argb (ScrnInfoPtr scrn, CursorPtr cursor) 519{ 520 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 521 int c; 522 523 for (c = 0; c < xf86_config->num_crtc; c++) 524 { 525 xf86CrtcPtr crtc = xf86_config->crtc[c]; 526 527 if (crtc->enabled) 528 xf86_crtc_load_cursor_argb (crtc, cursor); 529 } 530} 531 532_X_EXPORT Bool 533xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags) 534{ 535 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 536 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 537 xf86CursorInfoPtr cursor_info; 538 539 cursor_info = xf86CreateCursorInfoRec(); 540 if (!cursor_info) 541 return FALSE; 542 543 xf86_config->cursor_image = xalloc (max_width * max_height * 4); 544 545 if (!xf86_config->cursor_image) 546 { 547 xf86DestroyCursorInfoRec (cursor_info); 548 return FALSE; 549 } 550 551 xf86_config->cursor_info = cursor_info; 552 553 cursor_info->MaxWidth = max_width; 554 cursor_info->MaxHeight = max_height; 555 cursor_info->Flags = flags; 556 557 cursor_info->SetCursorColors = xf86_set_cursor_colors; 558 cursor_info->SetCursorPosition = xf86_set_cursor_position; 559 cursor_info->LoadCursorImage = xf86_load_cursor_image; 560 cursor_info->HideCursor = xf86_hide_cursors; 561 cursor_info->ShowCursor = xf86_show_cursors; 562 cursor_info->UseHWCursor = xf86_use_hw_cursor; 563#ifdef ARGB_CURSOR 564 if (flags & HARDWARE_CURSOR_ARGB) 565 { 566 cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb; 567 cursor_info->LoadCursorARGB = xf86_load_cursor_argb; 568 } 569#endif 570 571 xf86_config->cursor = NULL; 572 xf86_hide_cursors (scrn); 573 574 return xf86InitCursor (screen, cursor_info); 575} 576 577/** 578 * Called when anything on the screen is reconfigured. 579 * 580 * Reloads cursor images as needed, then adjusts cursor positions 581 */ 582 583_X_EXPORT void 584xf86_reload_cursors (ScreenPtr screen) 585{ 586 ScrnInfoPtr scrn; 587 xf86CrtcConfigPtr xf86_config; 588 xf86CursorInfoPtr cursor_info; 589 CursorPtr cursor; 590 int x, y; 591 592 /* initial mode setting will not have set a screen yet */ 593 if (!screen) 594 return; 595 scrn = xf86Screens[screen->myNum]; 596 xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 597 598 /* make sure the cursor code has been initialized */ 599 cursor_info = xf86_config->cursor_info; 600 if (!cursor_info) 601 return; 602 603 cursor = xf86_config->cursor; 604 GetSpritePosition (&x, &y); 605 if (!(cursor_info->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN)) 606 (*cursor_info->HideCursor)(scrn); 607 608 if (cursor) 609 { 610#ifdef ARGB_CURSOR 611 if (cursor->bits->argb && cursor_info->LoadCursorARGB) 612 (*cursor_info->LoadCursorARGB) (scrn, cursor); 613 else 614#endif 615 (*cursor_info->LoadCursorImage)(cursor_info->pScrn, 616 cursor->devPriv[screen->myNum]); 617 618 (*cursor_info->SetCursorPosition)(cursor_info->pScrn, x, y); 619 (*cursor_info->ShowCursor)(cursor_info->pScrn); 620 } 621} 622 623/** 624 * Clean up CRTC-based cursor code 625 */ 626_X_EXPORT void 627xf86_cursors_fini (ScreenPtr screen) 628{ 629 ScrnInfoPtr scrn = xf86Screens[screen->myNum]; 630 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 631 632 if (xf86_config->cursor_info) 633 { 634 xf86DestroyCursorInfoRec (xf86_config->cursor_info); 635 xf86_config->cursor_info = NULL; 636 } 637 if (xf86_config->cursor_image) 638 { 639 xfree (xf86_config->cursor_image); 640 xf86_config->cursor_image = NULL; 641 } 642 if (xf86_config->cursor) 643 { 644 FreeCursor (xf86_config->cursor, None); 645 xf86_config->cursor = NULL; 646 } 647} 648