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