xserver-multidpi/hw/xfree86/modes/xf86Cursors.c
Peter Hutterer d3f6b43a24 Update to xextproto 7.0.99.1.
xextproto had Xlib client headers moved into libXext.
Protocol header files are named fooproto.h, header files with constants
foo.h or fooconst.h where foo.h was already in use for client-side headers.
2009-07-15 17:00:05 +10:00

673 lines
17 KiB
C

/*
* Copyright © 2007 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#else
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#endif
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "xf86.h"
#include "xf86DDC.h"
#include "xf86Crtc.h"
#include "xf86Modes.h"
#include "xf86RandR12.h"
#include "xf86CursorPriv.h"
#include "X11/extensions/render.h"
#include "X11/extensions/dpmsconst.h"
#include "X11/Xatom.h"
#ifdef RENDER
#include "picturestr.h"
#endif
#include "cursorstr.h"
#include "inputstr.h"
/*
* Given a screen coordinate, rotate back to a cursor source coordinate
*/
static void
xf86_crtc_rotate_coord (Rotation rotation,
int width,
int height,
int x_dst,
int y_dst,
int *x_src,
int *y_src)
{
int t;
switch (rotation & 0xf) {
case RR_Rotate_0:
break;
case RR_Rotate_90:
t = x_dst;
x_dst = height - y_dst - 1;
y_dst = t;
break;
case RR_Rotate_180:
x_dst = width - x_dst - 1;
y_dst = height - y_dst - 1;
break;
case RR_Rotate_270:
t = x_dst;
x_dst = y_dst;
y_dst = width - t - 1;
break;
}
if (rotation & RR_Reflect_X)
x_dst = width - x_dst - 1;
if (rotation & RR_Reflect_Y)
y_dst = height - y_dst - 1;
*x_src = x_dst;
*y_src = y_dst;
}
/*
* Given a cursor source coordinate, rotate to a screen coordinate
*/
static void
xf86_crtc_rotate_coord_back (Rotation rotation,
int width,
int height,
int x_dst,
int y_dst,
int *x_src,
int *y_src)
{
int t;
if (rotation & RR_Reflect_X)
x_dst = width - x_dst - 1;
if (rotation & RR_Reflect_Y)
y_dst = height - y_dst - 1;
switch (rotation & 0xf) {
case RR_Rotate_0:
break;
case RR_Rotate_90:
t = x_dst;
x_dst = y_dst;
y_dst = width - t - 1;
break;
case RR_Rotate_180:
x_dst = width - x_dst - 1;
y_dst = height - y_dst - 1;
break;
case RR_Rotate_270:
t = x_dst;
x_dst = height - y_dst - 1;
y_dst = t;
break;
}
*x_src = x_dst;
*y_src = y_dst;
}
/*
* Convert an x coordinate to a position within the cursor bitmap
*/
static int
cursor_bitpos (int flags, int x, Bool mask)
{
if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)
mask = !mask;
if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED)
x = (x & ~3) | (3 - (x & 3));
if (((flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) == 0) ==
(X_BYTE_ORDER == X_BIG_ENDIAN))
x = (x & ~7) | (7 - (x & 7));
if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1)
x = (x << 1) + mask;
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8)
x = ((x & ~7) << 1) | (mask << 3) | (x & 7);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16)
x = ((x & ~15) << 1) | (mask << 4) | (x & 15);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32)
x = ((x & ~31) << 1) | (mask << 5) | (x & 31);
else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64)
x = ((x & ~63) << 1) | (mask << 6) | (x & 63);
return x;
}
/*
* Fetch one bit from a cursor bitmap
*/
static CARD8
get_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask)
{
x = cursor_bitpos (flags, x, mask);
image += y * stride;
return (image[(x >> 3)] >> (x & 7)) & 1;
}
/*
* Set one bit in a cursor bitmap
*/
static void
set_bit (CARD8 *image, int stride, int flags, int x, int y, Bool mask)
{
x = cursor_bitpos (flags, x, mask);
image += y * stride;
image[(x >> 3)] |= 1 << (x & 7);
}
/*
* Load a two color cursor into a driver that supports only ARGB cursors
*/
static void
xf86_crtc_convert_cursor_to_argb (xf86CrtcPtr crtc, unsigned char *src)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
int x, y;
int xin, yin;
int stride = cursor_info->MaxWidth >> 2;
int flags = cursor_info->Flags;
CARD32 bits;
#ifdef ARGB_CURSOR
crtc->cursor_argb = FALSE;
#endif
for (y = 0; y < cursor_info->MaxHeight; y++)
for (x = 0; x < cursor_info->MaxWidth; x++)
{
xf86_crtc_rotate_coord (crtc->rotation,
cursor_info->MaxWidth,
cursor_info->MaxHeight,
x, y, &xin, &yin);
if (get_bit (src, stride, flags, xin, yin, TRUE) ==
((flags & HARDWARE_CURSOR_INVERT_MASK) == 0))
{
if (get_bit (src, stride, flags, xin, yin, FALSE))
bits = xf86_config->cursor_fg;
else
bits = xf86_config->cursor_bg;
}
else
bits = 0;
cursor_image[y * cursor_info->MaxWidth + x] = bits;
}
crtc->funcs->load_cursor_argb (crtc, cursor_image);
}
/*
* Set the colors for a two-color cursor (ignore for ARGB cursors)
*/
static void
xf86_set_cursor_colors (ScrnInfoPtr scrn, int bg, int fg)
{
ScreenPtr screen = scrn->pScreen;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
CursorPtr cursor = xf86_config->cursor;
int c;
CARD8 *bits = cursor ?
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
dixLookupPrivate(&cursor->devPrivates, CursorScreenKey(screen))
#else
cursor->devPriv[screen->myNum]
#endif
: NULL;
/* Save ARGB versions of these colors */
xf86_config->cursor_fg = (CARD32) fg | 0xff000000;
xf86_config->cursor_bg = (CARD32) bg | 0xff000000;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled && !crtc->cursor_argb)
{
if (crtc->funcs->load_cursor_image)
crtc->funcs->set_cursor_colors (crtc, bg, fg);
else if (bits)
xf86_crtc_convert_cursor_to_argb (crtc, bits);
}
}
}
static void
xf86_crtc_hide_cursor (xf86CrtcPtr crtc)
{
if (crtc->cursor_shown)
{
crtc->funcs->hide_cursor (crtc);
crtc->cursor_shown = FALSE;
}
}
void
xf86_hide_cursors (ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
xf86_config->cursor_on = FALSE;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_hide_cursor (crtc);
}
}
static void
xf86_crtc_show_cursor (xf86CrtcPtr crtc)
{
if (!crtc->cursor_shown && crtc->cursor_in_range)
{
crtc->funcs->show_cursor (crtc);
crtc->cursor_shown = TRUE;
}
}
void
xf86_show_cursors (ScrnInfoPtr scrn)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
xf86_config->cursor_on = TRUE;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_show_cursor (crtc);
}
}
static void
xf86_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
DisplayModePtr mode = &crtc->mode;
Bool in_range;
int dx, dy;
/*
* Transform position of cursor on screen
*/
if (crtc->transform_in_use)
{
ScreenPtr screen = scrn->pScreen;
xf86CursorScreenPtr ScreenPriv =
(xf86CursorScreenPtr)dixLookupPrivate(&screen->devPrivates,
xf86CursorScreenKey);
struct pict_f_vector v;
v.v[0] = x + ScreenPriv->HotX; v.v[1] = y + ScreenPriv->HotY; v.v[2] = 1;
pixman_f_transform_point (&crtc->f_framebuffer_to_crtc, &v);
x = floor (v.v[0] + 0.5);
y = floor (v.v[1] + 0.5);
/*
* Transform position of cursor upper left corner
*/
xf86_crtc_rotate_coord_back (crtc->rotation,
cursor_info->MaxWidth,
cursor_info->MaxHeight,
ScreenPriv->HotX, ScreenPriv->HotY, &dx, &dy);
x -= dx;
y -= dy;
}
else
{
x -= crtc->x;
y -= crtc->y;
}
/*
* Disable the cursor when it is outside the viewport
*/
in_range = TRUE;
if (x >= mode->HDisplay || y >= mode->VDisplay ||
x <= -cursor_info->MaxWidth || y <= -cursor_info->MaxHeight)
{
in_range = FALSE;
x = 0;
y = 0;
}
crtc->cursor_in_range = in_range;
if (in_range)
{
crtc->funcs->set_cursor_position (crtc, x, y);
xf86_crtc_show_cursor (crtc);
}
else
xf86_crtc_hide_cursor (crtc);
}
static void
xf86_set_cursor_position (ScrnInfoPtr scrn, int x, int y)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
/* undo what xf86HWCurs did to the coordinates */
x += scrn->frameX0;
y += scrn->frameY0;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_set_cursor_position (crtc, x, y);
}
}
/*
* Load a two-color cursor into a crtc, performing rotation as needed
*/
static void
xf86_crtc_load_cursor_image (xf86CrtcPtr crtc, CARD8 *src)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
CARD8 *cursor_image;
#ifdef ARGB_CURSOR
crtc->cursor_argb = FALSE;
#endif
if (crtc->rotation == RR_Rotate_0)
cursor_image = src;
else
{
int x, y;
int xin, yin;
int stride = cursor_info->MaxWidth >> 2;
int flags = cursor_info->Flags;
cursor_image = xf86_config->cursor_image;
memset(cursor_image, 0, cursor_info->MaxHeight * stride);
for (y = 0; y < cursor_info->MaxHeight; y++)
for (x = 0; x < cursor_info->MaxWidth; x++)
{
xf86_crtc_rotate_coord (crtc->rotation,
cursor_info->MaxWidth,
cursor_info->MaxHeight,
x, y, &xin, &yin);
if (get_bit(src, stride, flags, xin, yin, FALSE))
set_bit(cursor_image, stride, flags, x, y, FALSE);
if (get_bit(src, stride, flags, xin, yin, TRUE))
set_bit(cursor_image, stride, flags, x, y, TRUE);
}
}
crtc->funcs->load_cursor_image (crtc, cursor_image);
}
/*
* Load a cursor image into all active CRTCs
*/
static void
xf86_load_cursor_image (ScrnInfoPtr scrn, unsigned char *src)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
{
if (crtc->funcs->load_cursor_image)
xf86_crtc_load_cursor_image (crtc, src);
else if (crtc->funcs->load_cursor_argb)
xf86_crtc_convert_cursor_to_argb (crtc, src);
}
}
}
static Bool
xf86_use_hw_cursor (ScreenPtr screen, CursorPtr cursor)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
if (xf86_config->cursor)
FreeCursor (xf86_config->cursor, None);
xf86_config->cursor = cursor;
++cursor->refcnt;
if (cursor->bits->width > cursor_info->MaxWidth ||
cursor->bits->height> cursor_info->MaxHeight)
return FALSE;
return TRUE;
}
static Bool
xf86_use_hw_cursor_argb (ScreenPtr screen, CursorPtr cursor)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
if (xf86_config->cursor)
FreeCursor (xf86_config->cursor, None);
xf86_config->cursor = cursor;
++cursor->refcnt;
/* Make sure ARGB support is available */
if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0)
return FALSE;
if (cursor->bits->width > cursor_info->MaxWidth ||
cursor->bits->height> cursor_info->MaxHeight)
return FALSE;
return TRUE;
}
static void
xf86_crtc_load_cursor_argb (xf86CrtcPtr crtc, CursorPtr cursor)
{
ScrnInfoPtr scrn = crtc->scrn;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
CARD32 *cursor_source = (CARD32 *) cursor->bits->argb;
int x, y;
int xin, yin;
CARD32 bits;
int source_width = cursor->bits->width;
int source_height = cursor->bits->height;
int image_width = cursor_info->MaxWidth;
int image_height = cursor_info->MaxHeight;
for (y = 0; y < image_height; y++)
for (x = 0; x < image_width; x++)
{
xf86_crtc_rotate_coord (crtc->rotation, image_width, image_height,
x, y, &xin, &yin);
if (xin < source_width && yin < source_height)
bits = cursor_source[yin * source_width + xin];
else
bits = 0;
cursor_image[y * image_width + x] = bits;
}
crtc->funcs->load_cursor_argb (crtc, cursor_image);
}
static void
xf86_load_cursor_argb (ScrnInfoPtr scrn, CursorPtr cursor)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
int c;
for (c = 0; c < xf86_config->num_crtc; c++)
{
xf86CrtcPtr crtc = xf86_config->crtc[c];
if (crtc->enabled)
xf86_crtc_load_cursor_argb (crtc, cursor);
}
}
Bool
xf86_cursors_init (ScreenPtr screen, int max_width, int max_height, int flags)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
xf86CursorInfoPtr cursor_info;
cursor_info = xf86CreateCursorInfoRec();
if (!cursor_info)
return FALSE;
xf86_config->cursor_image = xalloc (max_width * max_height * 4);
if (!xf86_config->cursor_image)
{
xf86DestroyCursorInfoRec (cursor_info);
return FALSE;
}
xf86_config->cursor_info = cursor_info;
cursor_info->MaxWidth = max_width;
cursor_info->MaxHeight = max_height;
cursor_info->Flags = flags;
cursor_info->SetCursorColors = xf86_set_cursor_colors;
cursor_info->SetCursorPosition = xf86_set_cursor_position;
cursor_info->LoadCursorImage = xf86_load_cursor_image;
cursor_info->HideCursor = xf86_hide_cursors;
cursor_info->ShowCursor = xf86_show_cursors;
cursor_info->UseHWCursor = xf86_use_hw_cursor;
#ifdef ARGB_CURSOR
if (flags & HARDWARE_CURSOR_ARGB)
{
cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb;
cursor_info->LoadCursorARGB = xf86_load_cursor_argb;
}
#endif
xf86_config->cursor = NULL;
xf86_hide_cursors (scrn);
return xf86InitCursor (screen, cursor_info);
}
/**
* Called when anything on the screen is reconfigured.
*
* Reloads cursor images as needed, then adjusts cursor positions
*/
void
xf86_reload_cursors (ScreenPtr screen)
{
ScrnInfoPtr scrn;
xf86CrtcConfigPtr xf86_config;
xf86CursorInfoPtr cursor_info;
CursorPtr cursor;
int x, y;
xf86CursorScreenPtr cursor_screen_priv;
/* initial mode setting will not have set a screen yet.
May be called before the devices are initialised.
*/
if (!screen || !inputInfo.pointer)
return;
cursor_screen_priv = dixLookupPrivate(&screen->devPrivates,
xf86CursorScreenKey);
/* return if HW cursor is inactive, to avoid displaying two cursors */
if (!cursor_screen_priv->isUp)
return;
scrn = xf86Screens[screen->myNum];
xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
/* make sure the cursor code has been initialized */
cursor_info = xf86_config->cursor_info;
if (!cursor_info)
return;
cursor = xf86_config->cursor;
GetSpritePosition (inputInfo.pointer, &x, &y);
if (!(cursor_info->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN))
(*cursor_info->HideCursor)(scrn);
if (cursor)
{
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
void *src = dixLookupPrivate(&cursor->devPrivates, CursorScreenKey(screen));
#else
void *src = cursor->devPriv[screen->myNum];
#endif
#ifdef ARGB_CURSOR
if (cursor->bits->argb && cursor_info->LoadCursorARGB)
(*cursor_info->LoadCursorARGB) (scrn, cursor);
else if (src)
#endif
(*cursor_info->LoadCursorImage)(cursor_info->pScrn, src);
(*cursor_info->SetCursorPosition)(cursor_info->pScrn, x, y);
}
}
/**
* Clean up CRTC-based cursor code
*/
void
xf86_cursors_fini (ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
if (xf86_config->cursor_info)
{
xf86DestroyCursorInfoRec (xf86_config->cursor_info);
xf86_config->cursor_info = NULL;
}
if (xf86_config->cursor_image)
{
xfree (xf86_config->cursor_image);
xf86_config->cursor_image = NULL;
}
if (xf86_config->cursor)
{
FreeCursor (xf86_config->cursor, None);
xf86_config->cursor = NULL;
}
}