]> Pileus Git - ~andy/gtk/blobdiff - gdk/win32/gdkcursor-win32.c
Fixes contributed by Archaeopteryx Software: This is a first small part of
[~andy/gtk] / gdk / win32 / gdkcursor-win32.c
index 763bdb38871f31601e97d7350abbf001adc02da4..6fceb2a5d1f99ea910ad4f9ffbc669dbb0f16dce 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-#include "config.h"
-
-#include "gdkwin32.h"
 #include "gdkcursor.h"
-#include "gdkinternals.h"
-#include "gdkpixmap-win32.h"
 #include "gdkprivate-win32.h"
 
-static const struct { const char *name; int type; } cursors[] = {
-  { "x_cursor", 0 },
-  { "arrow", 2 },
-  { "based_arrow_down", 4 },
-  { "based_arrow_up", 6 },
-  { "boat", 8 },
-  { "bogosity", 10 },
-  { "bottom_left_corner", 12 },
-  { "bottom_right_corner", 14 },
-  { "bottom_side", 16 },
-  { "bottom_tee", 18 },
-  { "box_spiral", 20 },
-  { "center_ptr", 22 },
-  { "circle", 24 },
-  { "clock", 26 },
-  { "coffee_mug", 28 },
-  { "cross", 30 },
-  { "cross_reverse", 32 },
-  { "crosshair", 34 },
-  { "diamond_cross", 36 },
-  { "dot", 38 },
-  { "dotbox", 40 },
-  { "double_arrow", 42 },
-  { "draft_large", 44 },
-  { "draft_small", 46 },
-  { "draped_box", 48 },
-  { "exchange", 50 },
-  { "fleur", 52 },
-  { "gobbler", 54 },
-  { "gumby", 56 },
-  { "hand1", 58 },
-  { "hand2", 60 },
-  { "heart", 62 },
-  { "icon", 64 },
-  { "iron_cross", 66 },
-  { "left_ptr", 68 },
-  { "left_side", 70 },
-  { "left_tee", 72 },
-  { "leftbutton", 74 },
-  { "ll_angle", 76 },
-  { "lr_angle", 78 },
-  { "man", 80 },
-  { "middlebutton", 82 },
-  { "mouse", 84 },
-  { "pencil", 86 },
-  { "pirate", 88 },
-  { "plus", 90 },
-  { "question_arrow", 92 },
-  { "right_ptr", 94 },
-  { "right_side", 96 },
-  { "right_tee", 98 },
-  { "rightbutton", 100 },
-  { "rtl_logo", 102 },
-  { "sailboat", 104 },
-  { "sb_down_arrow", 106 },
-  { "sb_h_double_arrow", 108 },
-  { "sb_left_arrow", 110 },
-  { "sb_right_arrow", 112 },
-  { "sb_up_arrow", 114 },
-  { "sb_v_double_arrow", 116 },
-  { "shuttle", 118 },
-  { "sizing", 120 },
-  { "spider", 122 },
-  { "spraycan", 124 },
-  { "star", 126 },
-  { "target", 128 },
-  { "tcross", 130 },
-  { "top_left_arrow", 132 },
-  { "top_left_corner", 134 },
-  { "top_right_corner", 136 },
-  { "top_side", 138 },
-  { "top_tee", 140 },
-  { "trek", 142 },
-  { "ul_angle", 144 },
-  { "umbrella", 146 },
-  { "ur_angle", 148 },
-  { "watch", 150 },
-  { "xterm", 152 },
-  { NULL, 0 }
-};  
+#include "xcursors.h"
+
+static HCURSOR
+_gdk_win32_data_to_wcursor (GdkCursorType cursor_type)
+{
+  gint i, j, x, y, ofs;
+  HCURSOR rv = NULL;
+  gint w, h;
+  guchar *ANDplane, *XORplane;
+
+  for (i = 0; i < G_N_ELEMENTS (cursors); i++)
+    if (cursors[i].type == cursor_type)
+      break;
+
+  if (i >= G_N_ELEMENTS (cursors) || !cursors[i].name)
+    return NULL;
+
+  w = GetSystemMetrics (SM_CXCURSOR);
+  h = GetSystemMetrics (SM_CYCURSOR);
+
+  ANDplane = g_malloc ((w/8) * h);
+  memset (ANDplane, 0xff, (w/8) * h);
+  XORplane = g_malloc ((w/8) * h);
+  memset (XORplane, 0, (w/8) * h);
+
+#define SET_BIT(v,b)  (v |= (1 << b))
+#define RESET_BIT(v,b)  (v &= ~(1 << b))
+
+  for (j = 0, y = 0; y < cursors[i].height && y < h ; y++)
+    {
+      ofs = (y * w) / 8;
+      j = y * cursors[i].width;
+
+      for (x = 0; x < cursors[i].width && x < w ; x++, j++)
+      {
+        gint pofs = ofs + x / 8;
+        guchar data = (cursors[i].data[j/4] & (0xc0 >> (2 * (j%4)))) >> (2 * (3 - (j%4)));
+        gint bit = 7 - (j % cursors[i].width) % 8;
+
+        if (data)
+          {
+            RESET_BIT (ANDplane[pofs], bit);
+            if (data == 1)
+              SET_BIT (XORplane[pofs], bit);
+          }
+      }
+    }
+
+#undef SET_BIT
+#undef RESET_BIT
+
+  rv = CreateCursor (gdk_app_hmodule, cursors[i].hotx, cursors[i].hoty,
+                    w, h, ANDplane, XORplane);
+  if (rv == NULL)
+    WIN32_API_FAILED ("CreateCursor");
+  g_free (ANDplane);
+  g_free (XORplane);
+  
+  return rv;
+}
 
 GdkCursor*
 gdk_cursor_new (GdkCursorType cursor_type)
@@ -112,24 +87,14 @@ gdk_cursor_new (GdkCursorType cursor_type)
   GdkCursorPrivate *private;
   GdkCursor *cursor;
   HCURSOR hcursor;
-  int i;
 
-  for (i = 0; cursors[i].name != NULL && cursors[i].type != cursor_type; i++)
-    ;
-  if (cursors[i].name != NULL)
-    {
-      hcursor = LoadCursor (gdk_dll_hinstance, cursors[i].name);
-      if (hcursor == NULL)
-       WIN32_API_FAILED ("LoadCursor");
-      GDK_NOTE (MISC, g_print ("gdk_cursor_new: %#x %d\n",
-                              hcursor, cursor_type));
-    }
+  hcursor = _gdk_win32_data_to_wcursor (cursor_type);
+
+  if (hcursor == NULL)
+    g_warning ("gdk_cursor_new: no cursor %d found", cursor_type);
   else
-    {
-      g_warning ("gdk_cursor_new: no cursor %d found",
-                cursor_type);
-      hcursor = NULL;
-    }
+    GDK_NOTE (MISC, g_print ("gdk_cursor_new: %d: %#x\n",
+                            cursor_type, (guint) hcursor));
 
   private = g_new (GdkCursorPrivate, 1);
   private->hcursor = hcursor;
@@ -140,6 +105,14 @@ gdk_cursor_new (GdkCursorType cursor_type)
   return cursor;
 }
 
+static gboolean
+color_is_white (GdkColor *color)
+{
+  return (color->red == 0xFFFF
+         && color->green == 0xFFFF
+         && color->blue == 0xFFFF);
+}
+
 GdkCursor*
 gdk_cursor_new_from_pixmap (GdkPixmap *source,
                            GdkPixmap *mask,
@@ -157,14 +130,15 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source,
   gint width, height, cursor_width, cursor_height;
   guchar residue;
   gint ix, iy;
+  const gboolean bg_is_white = color_is_white (bg);
   
   g_return_val_if_fail (GDK_IS_PIXMAP (source), NULL);
   g_return_val_if_fail (GDK_IS_PIXMAP (mask), NULL);
   g_return_val_if_fail (fg != NULL, NULL);
   g_return_val_if_fail (bg != NULL, NULL);
 
-  source_impl = GDK_PIXMAP_IMPL_WIN32 (source);
-  mask_impl   = GDK_PIXMAP_IMPL_WIN32 (mask);
+  source_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (source)->impl);
+  mask_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (mask)->impl);
 
   g_return_val_if_fail (source_impl->width == mask_impl->width
                        && source_impl->height == mask_impl->height,
@@ -193,7 +167,13 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source,
   /* Such complex bit manipulation for this simple task, sigh.
    * The X cursor and Windows cursor concepts are quite different.
    * We assume here that we are always called with fg == black and
-   * bg == white.
+   * bg == white, *or* the other way around. Random colours won't work.
+   * (Well, you will get a cursor, but not in those colours.)
+   */
+
+  /* Note: The comments below refer to the case fg==black and
+   * bg==white, as that was what was implemented first. The fg==white
+   * (the "if (fg->pixel)" branches) case was added later.
    */
 
   /* First set masked-out source bits, as all source bits matter on Windoze.
@@ -205,7 +185,10 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source,
       q = (guchar *) mask_image->mem + iy*mask_image->bpl;
       
       for (ix = 0; ix < ((width-1)/8+1); ix++)
-       *p++ |= ~(*q++);
+       if (bg_is_white)
+         *p++ |= ~(*q++);
+       else
+         *p++ &= *q++;
     }
 
   /* XOR mask is initialized to zero */
@@ -217,7 +200,11 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source,
       q = xor_mask + iy*cursor_width/8;
 
       for (ix = 0; ix < ((width-1)/8+1); ix++)
-       *q++ = ~(*p++);
+       if (bg_is_white)
+         *q++ = ~(*p++);
+       else
+         *q++ = *p++;
+
       q[-1] &= ~residue;       /* Clear left-over bits */
     }
       
@@ -232,6 +219,7 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source,
 
       for (ix = 0; ix < ((width-1)/8+1); ix++)
        *q++ = ~(*p++);
+
       q[-1] |= residue;        /* Set left-over bits */
     }
       
@@ -240,11 +228,11 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source,
 
   GDK_NOTE (MISC, g_print ("gdk_cursor_new_from_pixmap: "
                           "%#x (%dx%d) %#x (%dx%d) = %#x (%dx%d)\n",
-                          GDK_PIXMAP_HBITMAP (source),
+                          (guint) GDK_PIXMAP_HBITMAP (source),
                           source_impl->width, source_impl->height,
-                          GDK_PIXMAP_HBITMAP (mask),
+                          (guint) GDK_PIXMAP_HBITMAP (mask),
                           mask_impl->width, mask_impl->height,
-                          hcursor, cursor_width, cursor_height));
+                          (guint) hcursor, cursor_width, cursor_height));
 
   g_free (xor_mask);
   g_free (and_mask);
@@ -270,11 +258,13 @@ _gdk_cursor_destroy (GdkCursor *cursor)
   private = (GdkCursorPrivate *) cursor;
 
   GDK_NOTE (MISC, g_print ("_gdk_cursor_destroy: %#x\n",
-                          (cursor->type == GDK_CURSOR_IS_PIXMAP) ? private->hcursor : 0));
+                          (cursor->type == GDK_CURSOR_IS_PIXMAP) ? (guint) private->hcursor : 0));
+
+  if (GetCursor() == private->hcursor)
+    SetCursor(NULL);
 
-  if (cursor->type == GDK_CURSOR_IS_PIXMAP)
-    if (!DestroyCursor (private->hcursor))
-      WIN32_API_FAILED ("DestroyCursor");
+  if (!DestroyCursor (private->hcursor))
+    WIN32_API_FAILED ("DestroyCursor");
 
   g_free (private);
 }