diff --git a/ChangeLog b/ChangeLog index e6b0efda75..1b4887eb59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2005-06-04 Tor Lillqvist + * gdk/win32/gdkcursor-win32.c + * gdk/win32/gdkwindow-win32.c + * gdk/win32/gdkprivate-win32.h: Support full-colour cursors. + Support cursors with alpha on XP. Use code in common with the + support for alpha icons that already was present. (#306101, Tim + Evans) + * modules/engines/ms-windows/msw_style.c: Render insensitive icons in a way that more closely matches Windows. (#305986, Tim Evans). diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index e6b0efda75..1b4887eb59 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,12 @@ 2005-06-04 Tor Lillqvist + * gdk/win32/gdkcursor-win32.c + * gdk/win32/gdkwindow-win32.c + * gdk/win32/gdkprivate-win32.h: Support full-colour cursors. + Support cursors with alpha on XP. Use code in common with the + support for alpha icons that already was present. (#306101, Tim + Evans) + * modules/engines/ms-windows/msw_style.c: Render insensitive icons in a way that more closely matches Windows. (#305986, Tim Evans). diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index e6b0efda75..1b4887eb59 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,5 +1,12 @@ 2005-06-04 Tor Lillqvist + * gdk/win32/gdkcursor-win32.c + * gdk/win32/gdkwindow-win32.c + * gdk/win32/gdkprivate-win32.h: Support full-colour cursors. + Support cursors with alpha on XP. Use code in common with the + support for alpha icons that already was present. (#306101, Tim + Evans) + * modules/engines/ms-windows/msw_style.c: Render insensitive icons in a way that more closely matches Windows. (#305986, Tim Evans). diff --git a/gdk/win32/gdkcursor-win32.c b/gdk/win32/gdkcursor-win32.c index c3b3fe4732..5aea417804 100644 --- a/gdk/win32/gdkcursor-win32.c +++ b/gdk/win32/gdkcursor-win32.c @@ -26,6 +26,35 @@ #include "xcursors.h" +#if defined(__MINGW32__) || (defined(_MSC_VER) && (WINVER < 0x0500)) +typedef struct { + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; +} BITMAPV5HEADER; +#endif + static HCURSOR _gdk_win32_data_to_wcursor (GdkCursorType cursor_type) { @@ -85,12 +114,25 @@ _gdk_win32_data_to_wcursor (GdkCursorType cursor_type) return rv; } +static GdkCursor* +_gdk_win32_cursor_new_from_hcursor (HCURSOR hcursor, GdkCursorType cursor_type) +{ + GdkCursorPrivate *private; + GdkCursor *cursor; + + private = g_new (GdkCursorPrivate, 1); + private->hcursor = hcursor; + cursor = (GdkCursor*) private; + cursor->type = cursor_type; + cursor->ref_count = 1; + + return cursor; +} + GdkCursor* gdk_cursor_new_for_display (GdkDisplay *display, GdkCursorType cursor_type) { - GdkCursorPrivate *private; - GdkCursor *cursor; HCURSOR hcursor; g_return_val_if_fail (display == gdk_display_get_default (), NULL); @@ -103,13 +145,7 @@ gdk_cursor_new_for_display (GdkDisplay *display, GDK_NOTE (MISC, g_print ("gdk_cursor_new_for_display: %d: %p\n", cursor_type, hcursor)); - private = g_new (GdkCursorPrivate, 1); - private->hcursor = hcursor; - cursor = (GdkCursor*) private; - cursor->type = cursor_type; - cursor->ref_count = 1; - - return cursor; + return _gdk_win32_cursor_new_from_hcursor (hcursor, cursor_type); } static gboolean @@ -128,8 +164,6 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source, gint x, gint y) { - GdkCursorPrivate *private; - GdkCursor *cursor; GdkPixmapImplWin32 *source_impl, *mask_impl; guchar *source_bits, *mask_bits; gint source_bpl, mask_bpl; @@ -285,13 +319,7 @@ gdk_cursor_new_from_pixmap (GdkPixmap *source, g_free (xor_mask); g_free (and_mask); - private = g_new (GdkCursorPrivate, 1); - private->hcursor = hcursor; - cursor = (GdkCursor*) private; - cursor->type = GDK_CURSOR_IS_PIXMAP; - cursor->ref_count = 1; - - return cursor; + return _gdk_win32_cursor_new_from_hcursor (hcursor, GDK_CURSOR_IS_PIXMAP); } void @@ -326,71 +354,17 @@ gdk_cursor_new_from_pixbuf (GdkDisplay *display, gint x, gint y) { - /* FIXME: Use alpha if supported */ - - GdkCursor *cursor; - GdkPixmap *pixmap, *mask; - guint width, height, n_channels, rowstride, i, j; - guint8 *data, *mask_data, *pixels; - GdkColor fg = { 0, 0, 0, 0 }; - GdkColor bg = { 0, 0xffff, 0xffff, 0xffff }; - GdkScreen *screen; + HCURSOR hcursor; g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); + g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL); + g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL); - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - - g_return_val_if_fail (0 <= x && x < width, NULL); - g_return_val_if_fail (0 <= y && y < height, NULL); - - n_channels = gdk_pixbuf_get_n_channels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - pixels = gdk_pixbuf_get_pixels (pixbuf); - - data = g_new0 (guint8, (width + 7) / 8 * height); - mask_data = g_new0 (guint8, (width + 7) / 8 * height); - - for (j = 0; j < height; j++) - { - guint8 *src = pixels + j * rowstride; - guint8 *d = data + (width + 7) / 8 * j; - guint8 *md = mask_data + (width + 7) / 8 * j; - - for (i = 0; i < width; i++) - { - if (src[1] < 0x80) - *d |= 1 << (i % 8); - - if (n_channels == 3 || src[3] >= 0x80) - *md |= 1 << (i % 8); - - src += n_channels; - if (i % 8 == 7) - { - d++; - md++; - } - } - } - - screen = gdk_display_get_default_screen (display); - pixmap = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen), - data, width, height); - - mask = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen), - mask_data, width, height); - - cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, x, y); - - g_object_unref (pixmap); - g_object_unref (mask); - - g_free (data); - g_free (mask_data); - - return cursor; + hcursor = _gdk_win32_pixbuf_to_hcursor (pixbuf, x, y); + if (!hcursor) + return NULL; + return _gdk_win32_cursor_new_from_hcursor (hcursor, GDK_CURSOR_IS_PIXMAP); } gboolean @@ -398,8 +372,7 @@ gdk_display_supports_cursor_alpha (GdkDisplay *display) { g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); - /* FIXME */ - return FALSE; + return _gdk_win32_pixbuf_to_hicon_supports_alpha (); } gboolean @@ -407,8 +380,7 @@ gdk_display_supports_cursor_color (GdkDisplay *display) { g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); - /* FIXME */ - return FALSE; + return TRUE; } guint @@ -431,3 +403,254 @@ gdk_display_get_maximal_cursor_size (GdkDisplay *display, if (height) *height = GetSystemMetrics (SM_CYCURSOR); } + + +/* Convert a pixbuf to an HICON (or HCURSOR). Supports alpha under + * Windows XP, thresholds alpha otherwise. Also used from + * gdkwindow-win32.c for creating application icons. + */ + +static HBITMAP +create_alpha_bitmap (gint width, gint height, guchar **outdata) +{ + BITMAPV5HEADER bi; + HDC hdc; + HBITMAP hBitmap; + + ZeroMemory (&bi, sizeof (BITMAPV5HEADER)); + bi.bV5Size = sizeof (BITMAPV5HEADER); + bi.bV5Width = width; + bi.bV5Height = height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + /* The following mask specification specifies a supported 32 BPP + * alpha format for Windows XP (BGRA format). + */ + bi.bV5RedMask = 0x00FF0000; + bi.bV5GreenMask = 0x0000FF00; + bi.bV5BlueMask = 0x000000FF; + bi.bV5AlphaMask = 0xFF000000; + + /* Create the DIB section with an alpha channel. */ + hdc = GetDC (NULL); + if (!hdc) + { + WIN32_GDI_FAILED ("GetDC"); + return NULL; + } + hBitmap = CreateDIBSection (hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, + (PVOID *) outdata, NULL, (DWORD)0); + if (hBitmap == NULL) + WIN32_GDI_FAILED ("CreateDIBSection"); + ReleaseDC (NULL, hdc); + + return hBitmap; +} + +static HBITMAP +create_color_bitmap (gint width, gint height, guchar **outdata) +{ + BITMAPV4HEADER bi; + HDC hdc; + HBITMAP hBitmap; + + ZeroMemory (&bi, sizeof (BITMAPV4HEADER)); + bi.bV4Size = sizeof (BITMAPV4HEADER); + bi.bV4Width = width; + bi.bV4Height = height; + bi.bV4Planes = 1; + bi.bV4BitCount = 24; + bi.bV4V4Compression = BI_RGB; + + hdc = GetDC (NULL); + if (!hdc) + { + WIN32_GDI_FAILED ("GetDC"); + return NULL; + } + hBitmap = CreateDIBSection (hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, + (PVOID *) outdata, NULL, (DWORD)0); + if (hBitmap == NULL) + WIN32_GDI_FAILED ("CreateDIBSection"); + ReleaseDC (NULL, hdc); + + return hBitmap; +} + +static gboolean +pixbuf_to_hbitmaps_alpha_winxp (GdkPixbuf *pixbuf, + HBITMAP *color, + HBITMAP *mask) +{ + /* Based on code from + * http://www.dotnet247.com/247reference/msgs/13/66301.aspx + */ + HBITMAP hColorBitmap, hMaskBitmap; + guchar *indata, *inrow; + guchar *outdata, *outrow; + gint width, height, i, j, rowstride; + + width = gdk_pixbuf_get_width (pixbuf); /* width of icon */ + height = gdk_pixbuf_get_height (pixbuf); /* height of icon */ + + hColorBitmap = create_alpha_bitmap (width, height, &outdata); + if (!hColorBitmap) + return FALSE; + hMaskBitmap = CreateBitmap (width, height, 1, 1, NULL); + if (!hMaskBitmap) + { + DeleteObject (hColorBitmap); + return FALSE; + } + + /* rows are always aligned on 4-byte boundarys, but here our pixels are always 4 bytes */ + indata = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + for (j=0; j 5 + || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1)); + } + return is_win_xp; +} diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 6c5a9112f2..a2764a2b9f 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -510,6 +510,15 @@ extern HGLOBAL _delayed_rendering_data; HGLOBAL _gdk_win32_selection_convert_to_dib (HGLOBAL hdata, GdkAtom target); +/* Convert a pixbuf to an HICON (or HCURSOR). Supports alpha under + * Windows XP, thresholds alpha otherwise. + */ +HICON _gdk_win32_pixbuf_to_hicon (GdkPixbuf *pixbuf); +HICON _gdk_win32_pixbuf_to_hcursor (GdkPixbuf *pixbuf, + gint x_hotspot, + gint y_hotspot); +gboolean _gdk_win32_pixbuf_to_hicon_supports_alpha (void); + /* Initialization */ void _gdk_windowing_window_init (void); void _gdk_root_window_size_init (void); diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 53b4d63a05..150f7beed3 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -37,34 +37,7 @@ #include "gdkprivate-win32.h" #include "gdkinput-win32.h" -#if defined __MINGW32__ || (WINVER < 0x0500) -typedef struct { - DWORD bV5Size; - LONG bV5Width; - LONG bV5Height; - WORD bV5Planes; - WORD bV5BitCount; - DWORD bV5Compression; - DWORD bV5SizeImage; - LONG bV5XPelsPerMeter; - LONG bV5YPelsPerMeter; - DWORD bV5ClrUsed; - DWORD bV5ClrImportant; - DWORD bV5RedMask; - DWORD bV5GreenMask; - DWORD bV5BlueMask; - DWORD bV5AlphaMask; - DWORD bV5CSType; - CIEXYZTRIPLE bV5Endpoints; - DWORD bV5GammaRed; - DWORD bV5GammaGreen; - DWORD bV5GammaBlue; - DWORD bV5Intent; - DWORD bV5ProfileData; - DWORD bV5ProfileSize; - DWORD bV5Reserved; -} BITMAPV5HEADER; - +#if defined(_MSC_VER) && (WINVER < 0x0500) #define GetAncestor(hwnd,what) _gdk_win32_get_ancestor_parent(hwnd) static HWND @@ -2406,193 +2379,6 @@ gdk_window_set_focus_on_map (GdkWindow *window, private->focus_on_map = focus_on_map; } -static HICON -pixbuf_to_hicon_alpha_winxp (GdkWindow *window, - GdkPixbuf *pixbuf) -{ - /* Based on code from - * http://www.dotnet247.com/247reference/msgs/13/66301.aspx - */ - HDC hdc; - BITMAPV5HEADER bi; - HBITMAP hBitmap, hMonoBitmap; - guchar *indata, *inrow; - guchar *outdata, *outrow; - HICON hAlphaIcon = NULL; - ICONINFO ii; - gint width, height, i, j, rowstride; - - if (pixbuf == NULL) - return NULL; - - width = gdk_pixbuf_get_width (pixbuf); /* width of icon */ - height = gdk_pixbuf_get_height (pixbuf); /* height of icon */ - - ZeroMemory (&bi, sizeof (BITMAPV5HEADER)); - bi.bV5Size = sizeof (BITMAPV5HEADER); - bi.bV5Width = width; - bi.bV5Height = height; - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; - /* The following mask specification specifies a supported 32 BPP - * alpha format for Windows XP (BGRA format). - */ - bi.bV5RedMask = 0x00FF0000; - bi.bV5GreenMask = 0x0000FF00; - bi.bV5BlueMask = 0x000000FF; - bi.bV5AlphaMask = 0xFF000000; - - /* Create the DIB section with an alpha channel. */ - hdc = GetDC (NULL); - hBitmap = CreateDIBSection (hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, - (void **)&outdata, NULL, (DWORD)0); - ReleaseDC (NULL, hdc); - - /* Draw something on the DIB section */ - indata = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - for (j=0; j 5 - || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1)); - } - - if (pixbuf == NULL) - return NULL; - - if (is_win_xp && gdk_pixbuf_get_has_alpha (pixbuf)) - return pixbuf_to_hicon_alpha_winxp (window, pixbuf); - else - return pixbuf_to_hicon_normal (window, pixbuf); -} - void gdk_window_set_icon_list (GdkWindow *window, GList *pixbufs) @@ -2656,8 +2442,8 @@ gdk_window_set_icon_list (GdkWindow *window, } /* Create the icons */ - big_hicon = pixbuf_to_hicon (window, big_pixbuf); - small_hicon = pixbuf_to_hicon (window, small_pixbuf); + big_hicon = _gdk_win32_pixbuf_to_hicon (big_pixbuf); + small_hicon = _gdk_win32_pixbuf_to_hicon (small_pixbuf); /* Set the icons */ SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG,