Logo Search packages:      
Sourcecode: xserver-xorg-video-ati version File versions

xf86Cursors.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"
#define DPMS_SERVER
#include "X11/extensions/dpms.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;
    }
}

Generated by  Doxygen 1.6.0   Back to index