1999-11-11 22:01:55 +00:00
|
|
|
/* GDK - The GIMP Drawing Kit
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
Massive changes. Too many to list here, but I'll try a summary:
2002-02-17 Tor Lillqvist <tml@iki.fi>
* gdk/win32/*.c: Massive changes. Too many to list here, but I'll
try a summary:
1) Unify GdkPixmap and GdkImage implementation: For each
GdkPixmap, allocate a GdkImage, and vice versa.
GdkPixmapImplWin32Data has a pointer to the GdkImage.
GdkImage::windowing_data is a pointer to the GdkPixmap.
This simplifies many pixmap and image related functions a lot, and
reduces duplicated code snippets. For instance, there is only one
place in gdk/win32 where CreateDIBSection() is called, in the
function _gdk_win32_new_pixmap(). Converting a bitmap (GdkPixmap)
to a Windows region is almost trivial, with the bitmap bits being
readily accessible in the associated GdkImage.
All blitting between GdkPixmaps, GdkWindows and GdkImages goes
through handled the _gdk_win32_blit() function, which calls
different functions to handle the cases of blitting from pixmaps,
inside windows (scrolling), or from windows, which all require
somewhat different handling.
2) Support 256-color mode. This has long been very broken, now it
works more or less OK. Keep the logical palette for each colormap
as small as possible while allocating and freeing colors. Select
and realize the logical palette associated with a GdkColormap into
a DC before drawing or blitting.
When the display is in 256-color mode, make it possible for the
user to override the size of the palette(s) used with either the
GDK_WIN32_MAX_COLORS environment variable, or a -max-colors
command line option. It is possible to reduce the palette size all
the way down to using just the 16 static colors (which causes the
system visual to be of type GDK_VISUAL_STATIC_COLOR. This could
possibly be useful if one desperately wants to avoid color
flashing. (Note that in order for this to work properly, an as of
yet not commited fix to gdkrgb.c is needed.)
Handle the palette messages. On WM_PALETTECHANGED, call
UpdateColors() for the given window hierarchy. Do this only if a
window in some other top-level window hierarchy caused the palette
change (realized a palette). Do this max five times in a row (an
arbitrarily chosen limit), though, otherwise redraw by generating
expose events. On WM_QUERYNEWPALETTE, cause a redraw of the whole
window hierarchy by generating GDK_EXPOSE events.
3) Code cleanup in general. For instance, remove the "emulated"
X11 structs ColormapStruct, Visual and XStandardColormap. Use the
new GDK_DEBUG_* flags for debugging output in the relevant source
files. Remove the unused colormap hash table in gdkcolor-win32.c
4) Plug some resource leaks.
2002-02-14 Tor Lillqvist <tml@iki.fi>
* gdk/win32/gdkdnd-win32.c (gdk_dropfiles_filter): Use
g_filename_to_uri() to actually create legal URIs in the
text/uri-list data.
2002-02-17 00:25:05 +00:00
|
|
|
* Copyright (C) 1998-2002 Tor Lillqvist
|
1999-11-11 22:01:55 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
2000-07-26 11:33:08 +00:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
1999-11-11 22:01:55 +00:00
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2000-07-26 11:33:08 +00:00
|
|
|
* Lesser General Public License for more details.
|
1999-11-11 22:01:55 +00:00
|
|
|
*
|
2000-07-26 11:33:08 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-02-27 13:01:10 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
1999-11-11 22:01:55 +00:00
|
|
|
*/
|
|
|
|
|
2008-06-22 14:28:52 +00:00
|
|
|
#include "config.h"
|
2002-06-18 20:59:44 +00:00
|
|
|
#include "gdkdisplay.h"
|
1999-11-11 22:01:55 +00:00
|
|
|
#include "gdkcursor.h"
|
2013-05-28 06:59:46 +00:00
|
|
|
#include "gdkwin32.h"
|
2017-11-07 07:39:48 +00:00
|
|
|
#include "gdktextureprivate.h"
|
2024-03-21 01:33:18 +00:00
|
|
|
#include "gdkcursorprivate.h"
|
1999-11-11 22:01:55 +00:00
|
|
|
|
2015-05-13 07:45:40 +00:00
|
|
|
#include "gdkdisplay-win32.h"
|
|
|
|
|
2001-02-23 03:51:41 +00:00
|
|
|
#include "xcursors.h"
|
|
|
|
|
2022-10-06 08:57:12 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
static struct {
|
2015-05-13 07:45:40 +00:00
|
|
|
char *name;
|
|
|
|
char *id;
|
2022-10-06 08:57:12 +00:00
|
|
|
} default_cursors[] = {
|
|
|
|
/* -- Win32 cursor names: -- */
|
2015-05-13 07:45:40 +00:00
|
|
|
{ "appstarting", IDC_APPSTARTING },
|
|
|
|
{ "arrow", IDC_ARROW },
|
|
|
|
{ "cross", IDC_CROSS },
|
|
|
|
{ "hand", IDC_HAND },
|
|
|
|
{ "help", IDC_HELP },
|
|
|
|
{ "ibeam", IDC_IBEAM },
|
2022-10-06 08:57:12 +00:00
|
|
|
/* -- X11 cursor names: -- */
|
2015-05-13 07:45:40 +00:00
|
|
|
{ "left_ptr_watch", IDC_APPSTARTING },
|
|
|
|
{ "sizeall", IDC_SIZEALL },
|
|
|
|
{ "sizenesw", IDC_SIZENESW },
|
|
|
|
{ "sizens", IDC_SIZENS },
|
|
|
|
{ "sizenwse", IDC_SIZENWSE },
|
|
|
|
{ "sizewe", IDC_SIZEWE },
|
|
|
|
{ "uparrow", IDC_UPARROW },
|
|
|
|
{ "wait", IDC_WAIT },
|
2022-10-06 08:57:12 +00:00
|
|
|
/* -- CSS cursor names: -- */
|
2015-05-13 07:45:40 +00:00
|
|
|
{ "default", IDC_ARROW },
|
|
|
|
{ "pointer", IDC_HAND },
|
|
|
|
{ "progress", IDC_APPSTARTING },
|
|
|
|
{ "crosshair", IDC_CROSS },
|
|
|
|
{ "text", IDC_IBEAM },
|
|
|
|
{ "move", IDC_SIZEALL },
|
|
|
|
{ "not-allowed", IDC_NO },
|
2021-03-17 03:09:37 +00:00
|
|
|
{ "all-scroll", IDC_SIZEALL },
|
2015-05-13 07:45:40 +00:00
|
|
|
{ "ew-resize", IDC_SIZEWE },
|
2015-07-26 05:34:38 +00:00
|
|
|
{ "e-resize", IDC_SIZEWE },
|
|
|
|
{ "w-resize", IDC_SIZEWE },
|
|
|
|
{ "col-resize", IDC_SIZEWE },
|
2015-05-13 07:45:40 +00:00
|
|
|
{ "ns-resize", IDC_SIZENS },
|
2015-07-26 05:34:38 +00:00
|
|
|
{ "n-resize", IDC_SIZENS },
|
|
|
|
{ "s-resize", IDC_SIZENS },
|
|
|
|
{ "row-resize", IDC_SIZENS },
|
2015-05-13 07:45:40 +00:00
|
|
|
{ "nesw-resize", IDC_SIZENESW },
|
2015-07-26 05:34:38 +00:00
|
|
|
{ "ne-resize", IDC_SIZENESW },
|
|
|
|
{ "sw-resize", IDC_SIZENESW },
|
2015-08-14 12:12:01 +00:00
|
|
|
{ "nwse-resize", IDC_SIZENWSE },
|
|
|
|
{ "nw-resize", IDC_SIZENWSE },
|
2015-07-26 05:34:38 +00:00
|
|
|
{ "se-resize", IDC_SIZENWSE }
|
2015-05-13 07:45:40 +00:00
|
|
|
};
|
|
|
|
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
typedef struct _GdkWin32HCursorTableEntry GdkWin32HCursorTableEntry;
|
|
|
|
|
|
|
|
struct _GdkWin32HCursorTableEntry
|
|
|
|
{
|
|
|
|
HCURSOR handle;
|
|
|
|
guint64 refcount;
|
|
|
|
gboolean destroyable;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GdkWin32HCursor
|
|
|
|
{
|
|
|
|
GObject parent_instance;
|
|
|
|
|
|
|
|
/* Do not do any modifications to the handle
|
|
|
|
* (i.e. do not call DestroyCursor() on it).
|
2022-10-06 08:57:12 +00:00
|
|
|
* It's a "read-only" copy, the original is
|
|
|
|
* stored in the display instance */
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
HANDLE readonly_handle;
|
|
|
|
|
2022-10-06 08:57:12 +00:00
|
|
|
/* This is a way to access the real handle
|
|
|
|
* stored in the display.
|
|
|
|
* TODO: make it a weak reference */
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
GdkWin32Display *display;
|
|
|
|
|
2022-10-06 08:57:12 +00:00
|
|
|
/* A copy of the "destoyable" attribute of
|
|
|
|
* the handle */
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
gboolean readonly_destroyable;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GdkWin32HCursorClass
|
|
|
|
{
|
|
|
|
GObjectClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
PROP_DISPLAY,
|
|
|
|
PROP_HANDLE,
|
|
|
|
PROP_DESTROYABLE,
|
|
|
|
NUM_PROPERTIES
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GdkWin32HCursor, gdk_win32_hcursor, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_win32_hcursor_init (GdkWin32HCursor *win32_hcursor)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_win32_hcursor_finalize (GObject *gobject)
|
|
|
|
{
|
|
|
|
GdkWin32HCursor *win32_hcursor = GDK_WIN32_HCURSOR (gobject);
|
|
|
|
|
|
|
|
if (win32_hcursor->display)
|
|
|
|
_gdk_win32_display_hcursor_unref (win32_hcursor->display, win32_hcursor->readonly_handle);
|
|
|
|
|
|
|
|
g_clear_object (&win32_hcursor->display);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (gdk_win32_hcursor_parent_class)->finalize (G_OBJECT (win32_hcursor));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_win32_hcursor_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GdkWin32HCursor *win32_hcursor;
|
|
|
|
|
|
|
|
win32_hcursor = GDK_WIN32_HCURSOR (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_DISPLAY:
|
|
|
|
g_set_object (&win32_hcursor->display, g_value_get_object (value));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_DESTROYABLE:
|
|
|
|
win32_hcursor->readonly_destroyable = g_value_get_boolean (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_HANDLE:
|
|
|
|
win32_hcursor->readonly_handle = g_value_get_pointer (value);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_win32_hcursor_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GdkWin32HCursor *win32_hcursor;
|
|
|
|
|
|
|
|
win32_hcursor = GDK_WIN32_HCURSOR (object);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_DISPLAY:
|
|
|
|
g_value_set_object (value, win32_hcursor->display);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_DESTROYABLE:
|
|
|
|
g_value_set_boolean (value, win32_hcursor->readonly_destroyable);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_HANDLE:
|
|
|
|
g_value_set_pointer (value, win32_hcursor->readonly_handle);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_win32_hcursor_constructed (GObject *object)
|
|
|
|
{
|
|
|
|
GdkWin32HCursor *win32_hcursor;
|
|
|
|
|
|
|
|
win32_hcursor = GDK_WIN32_HCURSOR (object);
|
|
|
|
|
|
|
|
g_assert_nonnull (win32_hcursor->display);
|
|
|
|
g_assert_nonnull (win32_hcursor->readonly_handle);
|
|
|
|
|
|
|
|
_gdk_win32_display_hcursor_ref (win32_hcursor->display,
|
|
|
|
win32_hcursor->readonly_handle,
|
|
|
|
win32_hcursor->readonly_destroyable);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GParamSpec *hcursor_props[NUM_PROPERTIES] = { NULL, };
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_win32_hcursor_class_init (GdkWin32HCursorClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->finalize = gdk_win32_hcursor_finalize;
|
|
|
|
object_class->constructed = gdk_win32_hcursor_constructed;
|
|
|
|
object_class->get_property = gdk_win32_hcursor_get_property;
|
|
|
|
object_class->set_property = gdk_win32_hcursor_set_property;
|
|
|
|
|
|
|
|
hcursor_props[PROP_DISPLAY] =
|
2022-05-11 12:19:39 +00:00
|
|
|
g_param_spec_object ("display", NULL, NULL,
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
GDK_TYPE_DISPLAY,
|
|
|
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
hcursor_props[PROP_HANDLE] =
|
2022-05-11 12:19:39 +00:00
|
|
|
g_param_spec_pointer ("handle", NULL, NULL,
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
hcursor_props[PROP_DESTROYABLE] =
|
2022-05-11 12:19:39 +00:00
|
|
|
g_param_spec_boolean ("destroyable", NULL, NULL,
|
GDK W32: New cursor class
Instead of now-unused GdkWin32Cursor class (a subclass of GdkCursor),
add a stand-alone GdkWin32HCursor class that is a wrapper around
HCURSOR handle.
On creation it's given a display instance, a HCURSOR handle and a boolean
that indicates whether the HCURSOR handle can or cannot be destroyed
(this depends on how the handle was obtained).
That information is stored in a hash table inside the GdkWin32Display
singleton, each entry of that table has reference count.
When the GdkWin32HCursor object is finalized, it reduces the reference
count on the table entry in the GdkWin32Display. When it's created,
it either adds such an entry or refs an existing one.
This way two pieces of code (or the same piece of code called
multiple times) that independently obtain the same HCURSOR from the OS
will get to different GdkWin32HCursor instances, but GdkWin32Display
will know that both use the same handle.
Once the reference count reaches 0 on the table entry, it is freed
and the handle (if destroyable) is put on the destruction list,
and an idle destruction function is queued.
If the same handle is once again registered for use before the
idle destructior is invoked (this happens, for example, when
an old cursor is destroyed and then replaced with a new one),
the handle gets removed from the destruction list.
The destructor just calls DestroyCursor() on each handle, calling
SetCursor(NULL) before doing that when the handle is in use.
This ensures that SetCursor(NULL) (which will cause cursor to disappear,
which is bad by itself, and which will also cause flickering if the
cursor is set to a non-NULL again shortly afterward)
is almost never called, unless GTK messes up and keeps using a cursor
beyond its lifetime.
This scheme also ensures that non-destructable cursors are not destroyed.
It's also possible to call _gdk_win32_display_hcursor_ref()
and _gdk_win32_display_hcursor_unref() manually instead of creating
GdkWin32HCursor objects, but that is not recommended.
2018-03-29 23:38:05 +00:00
|
|
|
TRUE,
|
|
|
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
|
|
|
|
|
|
|
g_object_class_install_properties (object_class, NUM_PROPERTIES, hcursor_props);
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkWin32HCursor *
|
|
|
|
gdk_win32_hcursor_new (GdkWin32Display *display,
|
|
|
|
HCURSOR handle,
|
|
|
|
gboolean destroyable)
|
|
|
|
{
|
|
|
|
return g_object_new (GDK_TYPE_WIN32_HCURSOR,
|
|
|
|
"display", display,
|
|
|
|
"handle", handle,
|
|
|
|
"destroyable", destroyable,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_win32_display_hcursor_ref (GdkWin32Display *display,
|
|
|
|
HCURSOR handle,
|
|
|
|
gboolean destroyable)
|
|
|
|
{
|
|
|
|
GdkWin32HCursorTableEntry *entry;
|
|
|
|
|
|
|
|
entry = g_hash_table_lookup (display->cursor_reftable, handle);
|
|
|
|
|
|
|
|
if (entry)
|
|
|
|
{
|
|
|
|
if (entry->destroyable != destroyable)
|
|
|
|
g_warning ("Destroyability metadata for cursor handle 0x%p does not match", handle);
|
|
|
|
|
|
|
|
entry->refcount += 1;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry = g_new0 (GdkWin32HCursorTableEntry, 1);
|
|
|
|
entry->handle = handle;
|
|
|
|
entry->destroyable = destroyable;
|
|
|
|
entry->refcount = 1;
|
|
|
|
|
|
|
|
g_hash_table_insert (display->cursor_reftable, handle, entry);
|
|
|
|
display->cursors_for_destruction = g_list_remove_all (display->cursors_for_destruction, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
delayed_cursor_destruction (gpointer user_data)
|
|
|
|
{
|
|
|
|
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (user_data);
|
|
|
|
HANDLE current_hcursor = GetCursor ();
|
|
|
|
GList *p;
|
|
|
|
|
|
|
|
win32_display->idle_cursor_destructor_id = 0;
|
|
|
|
|
|
|
|
for (p = win32_display->cursors_for_destruction; p; p = p->next)
|
|
|
|
{
|
|
|
|
HCURSOR handle = (HCURSOR) p->data;
|
|
|
|
|
|
|
|
if (handle == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (current_hcursor == handle)
|
|
|
|
{
|
|
|
|
SetCursor (NULL);
|
|
|
|
current_hcursor = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DestroyCursor (handle))
|
|
|
|
g_warning (G_STRLOC ": DestroyCursor (%p) failed: %lu", handle, GetLastError ());
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (win32_display->cursors_for_destruction);
|
|
|
|
win32_display->cursors_for_destruction = NULL;
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_gdk_win32_display_hcursor_unref (GdkWin32Display *display,
|
|
|
|
HCURSOR handle)
|
|
|
|
{
|
|
|
|
GdkWin32HCursorTableEntry *entry;
|
|
|
|
gboolean destroyable;
|
|
|
|
|
|
|
|
entry = g_hash_table_lookup (display->cursor_reftable, handle);
|
|
|
|
|
|
|
|
if (!entry)
|
|
|
|
{
|
|
|
|
g_warning ("Trying to forget cursor handle 0x%p that is not in the table", handle);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->refcount -= 1;
|
|
|
|
|
|
|
|
if (entry->refcount > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
destroyable = entry->destroyable;
|
|
|
|
|
|
|
|
g_hash_table_remove (display->cursor_reftable, handle);
|
|
|
|
g_free (entry);
|
|
|
|
|
|
|
|
if (!destroyable)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* GDK tends to destroy a cursor first, then set a new one.
|
|
|
|
* This results in repeated oscillations between SetCursor(NULL)
|
|
|
|
* and SetCursor(hcursor). To avoid that, delay cursor destruction a bit
|
|
|
|
* to let GDK set a new one first. That way cursors are switched
|
|
|
|
* seamlessly, without a NULL cursor between them.
|
|
|
|
* If GDK sets the new cursor to the same handle the old cursor had,
|
|
|
|
* the cursor handle is taken off the destruction list.
|
|
|
|
*/
|
|
|
|
if (g_list_find (display->cursors_for_destruction, handle) == NULL)
|
|
|
|
{
|
|
|
|
display->cursors_for_destruction = g_list_prepend (display->cursors_for_destruction, handle);
|
|
|
|
|
|
|
|
if (display->idle_cursor_destructor_id == 0)
|
|
|
|
display->idle_cursor_destructor_id = g_idle_add (delayed_cursor_destruction, display);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef gdk_win32_hcursor_get_handle
|
|
|
|
#undef gdk_win32_hcursor_get_handle
|
|
|
|
#endif
|
|
|
|
|
|
|
|
HCURSOR
|
|
|
|
gdk_win32_hcursor_get_handle (GdkWin32HCursor *cursor)
|
|
|
|
{
|
|
|
|
return cursor->readonly_handle;
|
|
|
|
}
|
|
|
|
|
2001-02-23 03:51:41 +00:00
|
|
|
static HCURSOR
|
2020-07-24 13:54:49 +00:00
|
|
|
hcursor_from_x_cursor (int i,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2001-02-23 03:51:41 +00:00
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
int j, x, y, ofs;
|
2009-01-21 20:51:22 +00:00
|
|
|
HCURSOR rv;
|
2020-07-24 13:54:49 +00:00
|
|
|
int w, h;
|
2022-10-06 08:57:12 +00:00
|
|
|
uint8_t *and_plane;
|
|
|
|
uint8_t *xor_plane;
|
2001-02-23 03:51:41 +00:00
|
|
|
|
|
|
|
w = GetSystemMetrics (SM_CXCURSOR);
|
|
|
|
h = GetSystemMetrics (SM_CYCURSOR);
|
|
|
|
|
Massive changes. Too many to list here, but I'll try a summary:
2002-02-17 Tor Lillqvist <tml@iki.fi>
* gdk/win32/*.c: Massive changes. Too many to list here, but I'll
try a summary:
1) Unify GdkPixmap and GdkImage implementation: For each
GdkPixmap, allocate a GdkImage, and vice versa.
GdkPixmapImplWin32Data has a pointer to the GdkImage.
GdkImage::windowing_data is a pointer to the GdkPixmap.
This simplifies many pixmap and image related functions a lot, and
reduces duplicated code snippets. For instance, there is only one
place in gdk/win32 where CreateDIBSection() is called, in the
function _gdk_win32_new_pixmap(). Converting a bitmap (GdkPixmap)
to a Windows region is almost trivial, with the bitmap bits being
readily accessible in the associated GdkImage.
All blitting between GdkPixmaps, GdkWindows and GdkImages goes
through handled the _gdk_win32_blit() function, which calls
different functions to handle the cases of blitting from pixmaps,
inside windows (scrolling), or from windows, which all require
somewhat different handling.
2) Support 256-color mode. This has long been very broken, now it
works more or less OK. Keep the logical palette for each colormap
as small as possible while allocating and freeing colors. Select
and realize the logical palette associated with a GdkColormap into
a DC before drawing or blitting.
When the display is in 256-color mode, make it possible for the
user to override the size of the palette(s) used with either the
GDK_WIN32_MAX_COLORS environment variable, or a -max-colors
command line option. It is possible to reduce the palette size all
the way down to using just the 16 static colors (which causes the
system visual to be of type GDK_VISUAL_STATIC_COLOR. This could
possibly be useful if one desperately wants to avoid color
flashing. (Note that in order for this to work properly, an as of
yet not commited fix to gdkrgb.c is needed.)
Handle the palette messages. On WM_PALETTECHANGED, call
UpdateColors() for the given window hierarchy. Do this only if a
window in some other top-level window hierarchy caused the palette
change (realized a palette). Do this max five times in a row (an
arbitrarily chosen limit), though, otherwise redraw by generating
expose events. On WM_QUERYNEWPALETTE, cause a redraw of the whole
window hierarchy by generating GDK_EXPOSE events.
3) Code cleanup in general. For instance, remove the "emulated"
X11 structs ColormapStruct, Visual and XStandardColormap. Use the
new GDK_DEBUG_* flags for debugging output in the relevant source
files. Remove the unused colormap hash table in gdkcolor-win32.c
4) Plug some resource leaks.
2002-02-14 Tor Lillqvist <tml@iki.fi>
* gdk/win32/gdkdnd-win32.c (gdk_dropfiles_filter): Use
g_filename_to_uri() to actually create legal URIs in the
text/uri-list data.
2002-02-17 00:25:05 +00:00
|
|
|
and_plane = g_malloc ((w/8) * h);
|
|
|
|
memset (and_plane, 0xff, (w/8) * h);
|
|
|
|
xor_plane = g_malloc ((w/8) * h);
|
|
|
|
memset (xor_plane, 0, (w/8) * h);
|
2001-02-23 03:51:41 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
if (strcmp (name, "none") != 0)
|
2009-01-21 20:51:22 +00:00
|
|
|
{
|
|
|
|
|
2001-02-23 03:51:41 +00:00
|
|
|
#define SET_BIT(v,b) (v |= (1 << b))
|
|
|
|
#define RESET_BIT(v,b) (v &= ~(1 << b))
|
|
|
|
|
2009-01-21 20:51:22 +00:00
|
|
|
for (j = 0, y = 0; y < cursors[i].height && y < h ; y++)
|
|
|
|
{
|
|
|
|
ofs = (y * w) / 8;
|
|
|
|
j = y * cursors[i].width;
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2009-01-21 20:51:22 +00:00
|
|
|
for (x = 0; x < cursors[i].width && x < w ; x++, j++)
|
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
int pofs = ofs + x / 8;
|
2022-10-06 08:57:12 +00:00
|
|
|
uint8_t data = (cursors[i].data[j/4] & (0xc0 >> (2 * (j%4)))) >> (2 * (3 - (j%4)));
|
2020-07-24 13:54:49 +00:00
|
|
|
int bit = 7 - (j % cursors[i].width) % 8;
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2009-01-21 20:51:22 +00:00
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
RESET_BIT (and_plane[pofs], bit);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2009-01-21 20:51:22 +00:00
|
|
|
if (data == 1)
|
|
|
|
SET_BIT (xor_plane[pofs], bit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-02-23 03:51:41 +00:00
|
|
|
|
|
|
|
#undef SET_BIT
|
|
|
|
#undef RESET_BIT
|
|
|
|
|
2023-03-23 15:27:17 +00:00
|
|
|
rv = CreateCursor (NULL, cursors[i].hotx, cursors[i].hoty,
|
2009-01-21 20:51:22 +00:00
|
|
|
w, h, and_plane, xor_plane);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-03-23 15:27:17 +00:00
|
|
|
rv = CreateCursor (NULL, 0, 0, w, h, and_plane, xor_plane);
|
2009-01-21 20:51:22 +00:00
|
|
|
}
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2002-01-11 23:56:28 +00:00
|
|
|
if (rv == NULL)
|
|
|
|
WIN32_API_FAILED ("CreateCursor");
|
2015-05-13 07:45:40 +00:00
|
|
|
|
Massive changes. Too many to list here, but I'll try a summary:
2002-02-17 Tor Lillqvist <tml@iki.fi>
* gdk/win32/*.c: Massive changes. Too many to list here, but I'll
try a summary:
1) Unify GdkPixmap and GdkImage implementation: For each
GdkPixmap, allocate a GdkImage, and vice versa.
GdkPixmapImplWin32Data has a pointer to the GdkImage.
GdkImage::windowing_data is a pointer to the GdkPixmap.
This simplifies many pixmap and image related functions a lot, and
reduces duplicated code snippets. For instance, there is only one
place in gdk/win32 where CreateDIBSection() is called, in the
function _gdk_win32_new_pixmap(). Converting a bitmap (GdkPixmap)
to a Windows region is almost trivial, with the bitmap bits being
readily accessible in the associated GdkImage.
All blitting between GdkPixmaps, GdkWindows and GdkImages goes
through handled the _gdk_win32_blit() function, which calls
different functions to handle the cases of blitting from pixmaps,
inside windows (scrolling), or from windows, which all require
somewhat different handling.
2) Support 256-color mode. This has long been very broken, now it
works more or less OK. Keep the logical palette for each colormap
as small as possible while allocating and freeing colors. Select
and realize the logical palette associated with a GdkColormap into
a DC before drawing or blitting.
When the display is in 256-color mode, make it possible for the
user to override the size of the palette(s) used with either the
GDK_WIN32_MAX_COLORS environment variable, or a -max-colors
command line option. It is possible to reduce the palette size all
the way down to using just the 16 static colors (which causes the
system visual to be of type GDK_VISUAL_STATIC_COLOR. This could
possibly be useful if one desperately wants to avoid color
flashing. (Note that in order for this to work properly, an as of
yet not commited fix to gdkrgb.c is needed.)
Handle the palette messages. On WM_PALETTECHANGED, call
UpdateColors() for the given window hierarchy. Do this only if a
window in some other top-level window hierarchy caused the palette
change (realized a palette). Do this max five times in a row (an
arbitrarily chosen limit), though, otherwise redraw by generating
expose events. On WM_QUERYNEWPALETTE, cause a redraw of the whole
window hierarchy by generating GDK_EXPOSE events.
3) Code cleanup in general. For instance, remove the "emulated"
X11 structs ColormapStruct, Visual and XStandardColormap. Use the
new GDK_DEBUG_* flags for debugging output in the relevant source
files. Remove the unused colormap hash table in gdkcolor-win32.c
4) Plug some resource leaks.
2002-02-14 Tor Lillqvist <tml@iki.fi>
* gdk/win32/gdkdnd-win32.c (gdk_dropfiles_filter): Use
g_filename_to_uri() to actually create legal URIs in the
text/uri-list data.
2002-02-17 00:25:05 +00:00
|
|
|
g_free (and_plane);
|
|
|
|
g_free (xor_plane);
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2001-02-23 03:51:41 +00:00
|
|
|
return rv;
|
|
|
|
}
|
1999-11-11 22:01:55 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
static GdkWin32HCursor *
|
|
|
|
win32_cursor_create_win32hcursor (GdkWin32Display *display,
|
|
|
|
Win32Cursor *cursor,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *result;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
switch (cursor->load_type)
|
|
|
|
{
|
|
|
|
case GDK_WIN32_CURSOR_LOAD_FROM_FILE:
|
2018-03-29 23:40:32 +00:00
|
|
|
result = gdk_win32_hcursor_new (display,
|
|
|
|
LoadImageW (NULL,
|
|
|
|
cursor->resource_name,
|
|
|
|
IMAGE_CURSOR,
|
|
|
|
cursor->width,
|
|
|
|
cursor->height,
|
|
|
|
cursor->load_flags),
|
|
|
|
cursor->load_flags & LR_SHARED ? FALSE : TRUE);
|
2015-05-13 07:45:40 +00:00
|
|
|
break;
|
|
|
|
case GDK_WIN32_CURSOR_LOAD_FROM_RESOURCE_NULL:
|
2018-03-29 23:40:32 +00:00
|
|
|
result = gdk_win32_hcursor_new (display,
|
|
|
|
LoadImageA (NULL,
|
2020-07-24 18:40:36 +00:00
|
|
|
(const char *) cursor->resource_name,
|
2018-03-29 23:40:32 +00:00
|
|
|
IMAGE_CURSOR,
|
|
|
|
cursor->width,
|
|
|
|
cursor->height,
|
|
|
|
cursor->load_flags),
|
|
|
|
cursor->load_flags & LR_SHARED ? FALSE : TRUE);
|
2015-05-13 07:45:40 +00:00
|
|
|
break;
|
|
|
|
case GDK_WIN32_CURSOR_LOAD_FROM_RESOURCE_THIS:
|
2018-03-29 23:40:32 +00:00
|
|
|
result = gdk_win32_hcursor_new (display,
|
2023-03-23 15:27:17 +00:00
|
|
|
LoadImageA (GetModuleHandle (NULL),
|
2020-07-24 18:40:36 +00:00
|
|
|
(const char *) cursor->resource_name,
|
2018-03-29 23:40:32 +00:00
|
|
|
IMAGE_CURSOR,
|
|
|
|
cursor->width,
|
|
|
|
cursor->height,
|
|
|
|
cursor->load_flags),
|
|
|
|
cursor->load_flags & LR_SHARED ? FALSE : TRUE);
|
|
|
|
break;
|
|
|
|
case GDK_WIN32_CURSOR_LOAD_FROM_RESOURCE_GTK:
|
|
|
|
result = gdk_win32_hcursor_new (display,
|
2023-03-23 15:27:17 +00:00
|
|
|
LoadImageA (this_module (),
|
2020-07-24 18:40:36 +00:00
|
|
|
(const char *) cursor->resource_name,
|
2018-03-29 23:40:32 +00:00
|
|
|
IMAGE_CURSOR,
|
|
|
|
cursor->width,
|
|
|
|
cursor->height,
|
|
|
|
cursor->load_flags),
|
|
|
|
cursor->load_flags & LR_SHARED ? FALSE : TRUE);
|
2015-05-13 07:45:40 +00:00
|
|
|
break;
|
|
|
|
case GDK_WIN32_CURSOR_CREATE:
|
2018-03-29 23:40:32 +00:00
|
|
|
result = gdk_win32_hcursor_new (display,
|
|
|
|
hcursor_from_x_cursor (cursor->xcursor_number,
|
|
|
|
name),
|
|
|
|
TRUE);
|
2015-05-13 07:45:40 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Win32Cursor *
|
|
|
|
win32_cursor_new (GdkWin32CursorLoadType load_type,
|
|
|
|
gpointer resource_name,
|
2020-07-24 13:54:49 +00:00
|
|
|
int width,
|
|
|
|
int height,
|
2015-05-13 07:45:40 +00:00
|
|
|
guint load_flags,
|
2020-07-24 13:54:49 +00:00
|
|
|
int xcursor_number)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
|
|
|
Win32Cursor *result;
|
|
|
|
|
|
|
|
result = g_new (Win32Cursor, 1);
|
|
|
|
result->load_type = load_type;
|
|
|
|
result->resource_name = resource_name;
|
|
|
|
result->width = width;
|
|
|
|
result->height = height;
|
|
|
|
result->load_flags = load_flags;
|
|
|
|
result->xcursor_number = xcursor_number;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
win32_cursor_destroy (gpointer data)
|
|
|
|
{
|
|
|
|
Win32Cursor *cursor = data;
|
|
|
|
|
|
|
|
/* resource_name could be a resource ID (uint16_t stored as a pointer),
|
|
|
|
* which shouldn't be freed.
|
|
|
|
*/
|
|
|
|
if (cursor->load_type == GDK_WIN32_CURSOR_LOAD_FROM_FILE)
|
|
|
|
g_free (cursor->resource_name);
|
|
|
|
|
|
|
|
g_free (cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
win32_cursor_theme_load_from (Win32CursorTheme *theme,
|
2020-07-24 13:54:49 +00:00
|
|
|
int size,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *dir)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
|
|
|
GDir *gdir;
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *filename;
|
2015-05-13 07:45:40 +00:00
|
|
|
HCURSOR hcursor;
|
|
|
|
|
|
|
|
gdir = g_dir_open (dir, 0, NULL);
|
|
|
|
|
|
|
|
if (gdir == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while ((filename = g_dir_read_name (gdir)) != NULL)
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
char *fullname;
|
2015-05-13 07:45:40 +00:00
|
|
|
gunichar2 *filenamew;
|
2020-07-24 18:40:36 +00:00
|
|
|
char *cursor_name;
|
|
|
|
char *dot;
|
2015-05-13 07:45:40 +00:00
|
|
|
Win32Cursor *cursor;
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
fullname = g_build_filename (dir, filename, NULL);
|
2015-05-13 07:45:40 +00:00
|
|
|
filenamew = g_utf8_to_utf16 (fullname, -1, NULL, NULL, NULL);
|
|
|
|
g_free (fullname);
|
|
|
|
|
|
|
|
if (filenamew == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
hcursor = LoadImageW (NULL, filenamew, IMAGE_CURSOR, size, size,
|
|
|
|
LR_LOADFROMFILE | (size == 0 ? LR_DEFAULTSIZE : 0));
|
|
|
|
|
|
|
|
if (hcursor == NULL)
|
|
|
|
{
|
|
|
|
g_free (filenamew);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
DestroyCursor (hcursor);
|
|
|
|
dot = strchr (filename, '.');
|
|
|
|
|
|
|
|
cursor_name = dot ? g_strndup (filename, dot - filename) : g_strdup (filename);
|
|
|
|
|
|
|
|
cursor = win32_cursor_new (GDK_WIN32_CURSOR_LOAD_FROM_FILE,
|
|
|
|
filenamew,
|
|
|
|
size,
|
|
|
|
size,
|
|
|
|
LR_LOADFROMFILE | (size == 0 ? LR_DEFAULTSIZE : 0),
|
|
|
|
0);
|
2017-11-07 07:39:48 +00:00
|
|
|
|
2015-05-13 07:45:40 +00:00
|
|
|
g_hash_table_insert (theme->named_cursors, cursor_name, cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
win32_cursor_theme_load_from_dirs (Win32CursorTheme *theme,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name,
|
2020-07-24 13:54:49 +00:00
|
|
|
int size)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
char *theme_dir;
|
|
|
|
const char * const *dirs;
|
2020-07-24 13:54:49 +00:00
|
|
|
int i;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
dirs = g_get_system_data_dirs ();
|
|
|
|
|
|
|
|
/* <prefix>/share/icons */
|
|
|
|
for (i = 0; dirs[i]; i++)
|
|
|
|
{
|
2017-11-07 07:39:48 +00:00
|
|
|
theme_dir = g_build_filename (dirs[i], "icons", name, "cursors", NULL);
|
2015-05-13 07:45:40 +00:00
|
|
|
win32_cursor_theme_load_from (theme, size, theme_dir);
|
|
|
|
g_free (theme_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ~/.icons */
|
2017-11-07 07:39:48 +00:00
|
|
|
theme_dir = g_build_filename (g_get_home_dir (), "icons", name, "cursors", NULL);
|
2015-05-13 07:45:40 +00:00
|
|
|
win32_cursor_theme_load_from (theme, size, theme_dir);
|
|
|
|
g_free (theme_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
win32_cursor_theme_load_system (Win32CursorTheme *theme,
|
2020-07-24 13:54:49 +00:00
|
|
|
int size)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
int i;
|
2018-03-29 23:40:32 +00:00
|
|
|
HCURSOR shared_hcursor;
|
|
|
|
HCURSOR x_hcursor;
|
|
|
|
Win32Cursor *cursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (cursors); i++)
|
|
|
|
{
|
|
|
|
if (cursors[i].name == NULL)
|
|
|
|
break;
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
shared_hcursor = NULL;
|
|
|
|
x_hcursor = NULL;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
/* Prefer W32 cursors */
|
|
|
|
if (cursors[i].builtin)
|
2018-03-29 23:40:32 +00:00
|
|
|
shared_hcursor = LoadImageA (NULL, cursors[i].builtin, IMAGE_CURSOR,
|
|
|
|
size, size,
|
|
|
|
LR_SHARED | (size == 0 ? LR_DEFAULTSIZE : 0));
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
/* Fall back to X cursors, but only if we've got no theme cursor */
|
2018-03-29 23:40:32 +00:00
|
|
|
if (shared_hcursor == NULL && g_hash_table_lookup (theme->named_cursors, cursors[i].name) == NULL)
|
|
|
|
x_hcursor = hcursor_from_x_cursor (i, cursors[i].name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (shared_hcursor == NULL && x_hcursor == NULL)
|
2015-05-13 07:45:40 +00:00
|
|
|
continue;
|
2018-03-29 23:40:32 +00:00
|
|
|
else if (x_hcursor != NULL)
|
|
|
|
DestroyCursor (x_hcursor);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
cursor = win32_cursor_new (shared_hcursor ? GDK_WIN32_CURSOR_LOAD_FROM_RESOURCE_NULL : GDK_WIN32_CURSOR_CREATE,
|
2015-05-13 07:45:40 +00:00
|
|
|
(gpointer) cursors[i].builtin,
|
|
|
|
size,
|
|
|
|
size,
|
|
|
|
LR_SHARED | (size == 0 ? LR_DEFAULTSIZE : 0),
|
2018-03-29 23:40:32 +00:00
|
|
|
x_hcursor ? i : 0);
|
2015-05-13 07:45:40 +00:00
|
|
|
g_hash_table_insert (theme->named_cursors,
|
|
|
|
g_strdup (cursors[i].name),
|
|
|
|
cursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (default_cursors); i++)
|
|
|
|
{
|
|
|
|
if (default_cursors[i].name == NULL)
|
|
|
|
break;
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
shared_hcursor = LoadImageA (NULL, default_cursors[i].id, IMAGE_CURSOR, size, size,
|
|
|
|
LR_SHARED | (size == 0 ? LR_DEFAULTSIZE : 0));
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (shared_hcursor == NULL)
|
2015-05-13 07:45:40 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
cursor = win32_cursor_new (GDK_WIN32_CURSOR_LOAD_FROM_RESOURCE_NULL,
|
|
|
|
(gpointer) default_cursors[i].id,
|
|
|
|
size,
|
|
|
|
size,
|
|
|
|
LR_SHARED | (size == 0 ? LR_DEFAULTSIZE : 0),
|
|
|
|
0);
|
|
|
|
g_hash_table_insert (theme->named_cursors,
|
|
|
|
g_strdup (default_cursors[i].name),
|
|
|
|
cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Win32CursorTheme *
|
2020-07-24 18:40:36 +00:00
|
|
|
win32_cursor_theme_load (const char *name,
|
2020-07-24 13:54:49 +00:00
|
|
|
int size)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
|
|
|
Win32CursorTheme *result = g_new0 (Win32CursorTheme, 1);
|
|
|
|
|
|
|
|
result->named_cursors = g_hash_table_new_full (g_str_hash,
|
|
|
|
g_str_equal,
|
|
|
|
g_free,
|
|
|
|
win32_cursor_destroy);
|
|
|
|
|
|
|
|
if (strcmp (name, "system") == 0)
|
|
|
|
{
|
|
|
|
win32_cursor_theme_load_from_dirs (result, "Adwaita", size);
|
|
|
|
win32_cursor_theme_load_system (result, size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
win32_cursor_theme_load_from_dirs (result, name, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_hash_table_size (result->named_cursors) > 0)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
win32_cursor_theme_destroy (result);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
win32_cursor_theme_destroy (Win32CursorTheme *theme)
|
|
|
|
{
|
|
|
|
g_hash_table_destroy (theme->named_cursors);
|
|
|
|
g_free (theme);
|
|
|
|
}
|
|
|
|
|
|
|
|
Win32Cursor *
|
|
|
|
win32_cursor_theme_get_cursor (Win32CursorTheme *theme,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
|
|
|
return g_hash_table_lookup (theme->named_cursors, name);
|
|
|
|
}
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
static void
|
|
|
|
gdk_win32_cursor_remove_from_cache (gpointer data, GObject *cursor)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2017-11-07 07:39:48 +00:00
|
|
|
GdkDisplay *display = data;
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
/* Unrefs the GdkWin32HCursor value object automatically */
|
|
|
|
g_hash_table_remove (win32_display->cursors, cursor);
|
2015-05-13 07:45:40 +00:00
|
|
|
}
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
void
|
|
|
|
_gdk_win32_display_finalize_cursors (GdkWin32Display *display)
|
2011-01-02 10:51:25 +00:00
|
|
|
{
|
2017-11-07 07:39:48 +00:00
|
|
|
GHashTableIter iter;
|
|
|
|
gpointer cursor;
|
2011-01-02 10:51:25 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
if (display->cursors)
|
|
|
|
{
|
|
|
|
g_hash_table_iter_init (&iter, display->cursors);
|
|
|
|
while (g_hash_table_iter_next (&iter, &cursor, NULL))
|
|
|
|
g_object_weak_unref (G_OBJECT (cursor),
|
|
|
|
gdk_win32_cursor_remove_from_cache,
|
|
|
|
GDK_DISPLAY (display));
|
|
|
|
g_hash_table_unref (display->cursors);
|
|
|
|
}
|
2011-01-02 10:51:25 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
g_free (display->cursor_theme_name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
g_list_free (display->cursors_for_destruction);
|
|
|
|
display->cursors_for_destruction = NULL;
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
if (display->cursor_theme)
|
|
|
|
win32_cursor_theme_destroy (display->cursor_theme);
|
|
|
|
}
|
2011-01-02 10:51:25 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
void
|
|
|
|
_gdk_win32_display_init_cursors (GdkWin32Display *display)
|
|
|
|
{
|
2018-03-29 23:40:32 +00:00
|
|
|
display->cursors = g_hash_table_new_full (gdk_cursor_hash,
|
|
|
|
gdk_cursor_equal,
|
|
|
|
NULL,
|
|
|
|
g_object_unref);
|
|
|
|
display->cursor_reftable = g_hash_table_new (NULL, NULL);
|
2017-11-07 07:39:48 +00:00
|
|
|
display->cursor_theme_name = g_strdup ("system");
|
2011-01-02 10:51:25 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
/* This is where we use the names mapped to the equivalents that Windows defines by default */
|
|
|
|
static GdkWin32HCursor *
|
|
|
|
win32hcursor_idc_from_name (GdkWin32Display *display,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (default_cursors); i++)
|
|
|
|
{
|
|
|
|
if (strcmp (default_cursors[i].name, name) != 0)
|
|
|
|
continue;
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
return gdk_win32_hcursor_new (display,
|
|
|
|
LoadImageA (NULL, default_cursors[i].id, IMAGE_CURSOR, 0, 0,
|
|
|
|
LR_SHARED | LR_DEFAULTSIZE),
|
|
|
|
FALSE);
|
2015-05-13 07:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
static GdkWin32HCursor *
|
|
|
|
win32hcursor_x_from_name (GdkWin32Display *display,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
int i;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (cursors); i++)
|
|
|
|
if (cursors[i].name == NULL || strcmp (cursors[i].name, name) == 0)
|
2018-03-29 23:40:32 +00:00
|
|
|
return gdk_win32_hcursor_new (display, hcursor_from_x_cursor (i, name), TRUE);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
static GdkWin32HCursor *
|
|
|
|
win32hcursor_from_theme (GdkWin32Display *display,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
|
|
|
Win32CursorTheme *theme;
|
|
|
|
Win32Cursor *theme_cursor;
|
|
|
|
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
theme = _gdk_win32_display_get_cursor_theme (win32_display);
|
|
|
|
theme_cursor = win32_cursor_theme_get_cursor (theme, name);
|
|
|
|
|
|
|
|
if (theme_cursor == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
return win32_cursor_create_win32hcursor (win32_display, theme_cursor, name);
|
2015-05-13 07:45:40 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
static GdkWin32HCursor *
|
|
|
|
win32hcursor_from_name (GdkWin32Display *display,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *win32hcursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
|
|
|
/* Try current theme first */
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor = win32hcursor_from_theme (display, name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor != NULL)
|
|
|
|
return win32hcursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor = win32hcursor_idc_from_name (display, name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor != NULL)
|
|
|
|
return win32hcursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor = win32hcursor_x_from_name (display, name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
return win32hcursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
}
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
/* Create a blank cursor */
|
2018-03-29 23:40:32 +00:00
|
|
|
static GdkWin32HCursor *
|
|
|
|
create_blank_win32hcursor (GdkWin32Display *display)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
int w, h;
|
2022-10-06 08:57:12 +00:00
|
|
|
uint8_t *and_plane, *xor_plane;
|
2017-11-07 07:39:48 +00:00
|
|
|
HCURSOR rv;
|
2005-06-04 21:43:03 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
w = GetSystemMetrics (SM_CXCURSOR);
|
|
|
|
h = GetSystemMetrics (SM_CYCURSOR);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
and_plane = g_malloc ((w/8) * h);
|
|
|
|
memset (and_plane, 0xff, (w/8) * h);
|
|
|
|
xor_plane = g_malloc ((w/8) * h);
|
|
|
|
memset (xor_plane, 0, (w/8) * h);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2023-03-23 15:27:17 +00:00
|
|
|
rv = CreateCursor (NULL, 0, 0, w, h, and_plane, xor_plane);
|
2017-11-07 07:39:48 +00:00
|
|
|
if (rv == NULL)
|
|
|
|
WIN32_API_FAILED ("CreateCursor");
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
return gdk_win32_hcursor_new (display, rv, TRUE);
|
2005-06-04 21:43:03 +00:00
|
|
|
}
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
static GdkWin32HCursor *
|
|
|
|
gdk_win32hcursor_create_for_name (GdkWin32Display *display,
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2023-03-23 15:27:17 +00:00
|
|
|
const HINSTANCE hinstance = GetModuleHandle (NULL);
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *win32hcursor = NULL;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
/* Blank cursor case */
|
|
|
|
if (strcmp (name, "none") == 0)
|
2018-03-29 23:40:32 +00:00
|
|
|
return create_blank_win32hcursor (display);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor = win32hcursor_from_name (display, name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor)
|
|
|
|
return win32hcursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
/* Allow to load named cursor resources linked into the executable.
|
|
|
|
* Cursors obtained with LoadCursor() cannot be destroyed.
|
|
|
|
*/
|
2023-03-23 15:27:17 +00:00
|
|
|
return gdk_win32_hcursor_new (display, LoadCursor (hinstance, name), FALSE);
|
2017-11-07 07:39:48 +00:00
|
|
|
}
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
static HICON
|
|
|
|
pixbuf_to_hicon (GdkPixbuf *pixbuf,
|
|
|
|
gboolean is_icon,
|
2020-07-24 13:54:49 +00:00
|
|
|
int x,
|
|
|
|
int y);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2024-02-09 17:59:54 +00:00
|
|
|
HICON
|
|
|
|
_gdk_win32_create_hicon_for_texture (GdkTexture *texture,
|
|
|
|
gboolean is_icon,
|
|
|
|
int x,
|
|
|
|
int y)
|
2017-11-07 07:39:48 +00:00
|
|
|
{
|
|
|
|
cairo_surface_t *surface;
|
|
|
|
GdkPixbuf *pixbuf;
|
2020-07-24 13:54:49 +00:00
|
|
|
int width, height;
|
2017-11-07 07:39:48 +00:00
|
|
|
HICON icon;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
surface = gdk_texture_download_surface (texture);
|
|
|
|
width = cairo_image_surface_get_width (surface);
|
|
|
|
height = cairo_image_surface_get_height (surface);
|
2024-02-09 17:59:54 +00:00
|
|
|
|
2024-05-03 12:49:46 +00:00
|
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
2017-11-07 07:39:48 +00:00
|
|
|
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
|
2024-05-03 12:49:46 +00:00
|
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
2024-02-09 17:59:54 +00:00
|
|
|
|
|
|
|
icon = pixbuf_to_hicon (pixbuf, is_icon, x, y);
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
g_object_unref (pixbuf);
|
2024-02-09 17:59:54 +00:00
|
|
|
|
|
|
|
return icon;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GdkWin32HCursor *
|
|
|
|
gdk_win32hcursor_create_for_texture (GdkWin32Display *display,
|
|
|
|
GdkTexture *texture,
|
|
|
|
int x,
|
|
|
|
int y)
|
|
|
|
{
|
|
|
|
HICON icon = _gdk_win32_create_hicon_for_texture (texture, FALSE, x, y);
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
return gdk_win32_hcursor_new (display, (HCURSOR) icon, TRUE);
|
2015-05-13 07:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
static gboolean
|
2018-03-29 23:40:32 +00:00
|
|
|
_gdk_win32_cursor_update (GdkWin32Display *win32_display,
|
|
|
|
GdkCursor *cursor,
|
|
|
|
GdkWin32HCursor *win32_hcursor,
|
|
|
|
GList **update_cursors,
|
|
|
|
GList **update_win32hcursors)
|
2017-11-07 07:39:48 +00:00
|
|
|
{
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *win32hcursor_new = NULL;
|
2017-11-07 07:39:48 +00:00
|
|
|
Win32CursorTheme *theme;
|
2018-03-29 23:40:32 +00:00
|
|
|
Win32Cursor *theme_cursor;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name = gdk_cursor_get_name (cursor);
|
2001-02-23 03:51:41 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
/* Do nothing if this is not a named cursor. */
|
|
|
|
if (name == NULL)
|
|
|
|
return FALSE;
|
1999-11-11 22:01:55 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
theme = _gdk_win32_display_get_cursor_theme (win32_display);
|
|
|
|
theme_cursor = win32_cursor_theme_get_cursor (theme, name);
|
1999-11-11 22:01:55 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
if (theme_cursor != NULL)
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor_new = win32_cursor_create_win32hcursor (win32_display, theme_cursor, name);
|
2005-07-05 22:50:54 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor_new == NULL)
|
2015-05-13 07:45:40 +00:00
|
|
|
{
|
2017-11-07 07:39:48 +00:00
|
|
|
g_warning (G_STRLOC ": Unable to load %s from the cursor theme", name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor_new = win32hcursor_idc_from_name (win32_display, name);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor_new == NULL)
|
|
|
|
win32hcursor_new = win32hcursor_x_from_name (win32_display, name);
|
2005-07-03 15:47:42 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor_new == NULL)
|
2017-11-07 07:39:48 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2005-07-03 15:47:42 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (GetCursor () == win32_hcursor->readonly_handle)
|
|
|
|
SetCursor (win32hcursor_new->readonly_handle);
|
2005-07-05 22:50:54 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
/* Don't modify the hash table mid-iteration, put everything into a list
|
|
|
|
* and update the table later on.
|
|
|
|
*/
|
|
|
|
*update_cursors = g_list_prepend (*update_cursors, cursor);
|
|
|
|
*update_win32hcursors = g_list_prepend (*update_win32hcursors, win32hcursor_new);
|
2005-07-03 15:47:42 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
void
|
|
|
|
_gdk_win32_display_update_cursors (GdkWin32Display *display)
|
|
|
|
{
|
|
|
|
GHashTableIter iter;
|
|
|
|
GdkCursor *cursor;
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *win32hcursor;
|
|
|
|
GList *update_cursors = NULL;
|
|
|
|
GList *update_win32hcursors = NULL;
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
g_hash_table_iter_init (&iter, display->cursors);
|
2015-05-13 07:45:40 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &cursor, (gpointer *) &win32hcursor))
|
|
|
|
_gdk_win32_cursor_update (display, cursor, win32hcursor, &update_cursors, &update_win32hcursors);
|
|
|
|
|
|
|
|
while (update_cursors != NULL && update_win32hcursors != NULL)
|
|
|
|
{
|
|
|
|
g_hash_table_replace (display->cursors, update_cursors->data, update_win32hcursors->data);
|
|
|
|
update_cursors = g_list_delete_link (update_cursors, update_cursors);
|
|
|
|
update_win32hcursors = g_list_delete_link (update_win32hcursors, update_win32hcursors);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (update_cursors == NULL && update_win32hcursors == NULL);
|
2005-07-03 15:47:42 +00:00
|
|
|
}
|
|
|
|
|
2005-07-05 22:50:54 +00:00
|
|
|
GdkPixbuf *
|
2013-08-21 13:54:09 +00:00
|
|
|
gdk_win32_icon_to_pixbuf_libgtk_only (HICON hicon,
|
2020-07-24 20:32:16 +00:00
|
|
|
double *x_hot,
|
|
|
|
double *y_hot)
|
2005-07-05 22:50:54 +00:00
|
|
|
{
|
|
|
|
GdkPixbuf *pixbuf = NULL;
|
|
|
|
ICONINFO ii;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
BITMAPINFOHEADER bi;
|
|
|
|
RGBQUAD colors[2];
|
|
|
|
} bmi;
|
|
|
|
HDC hdc;
|
2022-10-06 08:57:12 +00:00
|
|
|
uint8_t *pixels, *bits;
|
2023-03-15 00:45:48 +00:00
|
|
|
int x, y, w, h;
|
|
|
|
gsize rowstride;
|
2005-07-05 22:50:54 +00:00
|
|
|
|
|
|
|
if (!GDI_CALL (GetIconInfo, (hicon, &ii)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!(hdc = CreateCompatibleDC (NULL)))
|
|
|
|
{
|
|
|
|
WIN32_GDI_FAILED ("CreateCompatibleDC");
|
|
|
|
goto out0;
|
|
|
|
}
|
|
|
|
|
2005-07-06 15:30:10 +00:00
|
|
|
memset (&bmi, 0, sizeof (bmi));
|
|
|
|
bmi.bi.biSize = sizeof (bmi.bi);
|
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
if (ii.hbmColor != NULL)
|
|
|
|
{
|
|
|
|
/* Colour cursor */
|
2005-07-05 22:50:54 +00:00
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
gboolean no_alpha;
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
if (!GDI_CALL (GetDIBits, (hdc, ii.hbmColor, 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS)))
|
|
|
|
goto out1;
|
|
|
|
|
|
|
|
w = bmi.bi.biWidth;
|
|
|
|
h = bmi.bi.biHeight;
|
|
|
|
|
|
|
|
bmi.bi.biBitCount = 32;
|
|
|
|
bmi.bi.biCompression = BI_RGB;
|
|
|
|
bmi.bi.biHeight = -h;
|
2005-07-06 15:30:10 +00:00
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
bits = g_malloc0 (4 * w * h);
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
/* color data */
|
|
|
|
if (!GDI_CALL (GetDIBits, (hdc, ii.hbmColor, 0, h, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS)))
|
|
|
|
goto out2;
|
|
|
|
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
|
|
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
|
|
no_alpha = TRUE;
|
|
|
|
for (y = 0; y < h; y++)
|
2005-07-05 22:50:54 +00:00
|
|
|
{
|
2006-10-29 00:17:11 +00:00
|
|
|
for (x = 0; x < w; x++)
|
|
|
|
{
|
|
|
|
pixels[2] = bits[(x+y*w) * 4];
|
|
|
|
pixels[1] = bits[(x+y*w) * 4 + 1];
|
|
|
|
pixels[0] = bits[(x+y*w) * 4 + 2];
|
|
|
|
pixels[3] = bits[(x+y*w) * 4 + 3];
|
|
|
|
if (no_alpha && pixels[3] > 0)
|
|
|
|
no_alpha = FALSE;
|
|
|
|
pixels += 4;
|
|
|
|
}
|
2023-03-15 00:45:48 +00:00
|
|
|
pixels += rowstride - w * 4;
|
2005-07-05 22:50:54 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
/* mask */
|
|
|
|
if (no_alpha &&
|
|
|
|
GDI_CALL (GetDIBits, (hdc, ii.hbmMask, 0, h, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS)))
|
|
|
|
{
|
|
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
|
|
|
for (y = 0; y < h; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < w; x++)
|
|
|
|
{
|
|
|
|
pixels[3] = 255 - bits[(x + y * w) * 4];
|
|
|
|
pixels += 4;
|
|
|
|
}
|
2023-03-15 00:45:48 +00:00
|
|
|
pixels += rowstride - w * 4;
|
2006-10-29 00:17:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2005-07-05 22:50:54 +00:00
|
|
|
{
|
2006-10-29 00:17:11 +00:00
|
|
|
/* B&W cursor */
|
|
|
|
|
|
|
|
int bpl;
|
|
|
|
|
|
|
|
if (!GDI_CALL (GetDIBits, (hdc, ii.hbmMask, 0, 0, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS)))
|
|
|
|
goto out1;
|
|
|
|
|
|
|
|
w = bmi.bi.biWidth;
|
|
|
|
h = ABS (bmi.bi.biHeight) / 2;
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
bits = g_malloc0 (4 * w * h);
|
2015-04-29 07:31:08 +00:00
|
|
|
|
2006-10-29 00:17:11 +00:00
|
|
|
/* masks */
|
|
|
|
if (!GDI_CALL (GetDIBits, (hdc, ii.hbmMask, 0, h*2, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS)))
|
|
|
|
goto out2;
|
|
|
|
|
|
|
|
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
|
2005-07-05 22:50:54 +00:00
|
|
|
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
2006-10-29 00:17:11 +00:00
|
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
|
|
bpl = ((w-1)/32 + 1)*4;
|
|
|
|
#if 0
|
|
|
|
for (y = 0; y < h*2; y++)
|
|
|
|
{
|
|
|
|
for (x = 0; x < w; x++)
|
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
const int bit = 7 - (x % 8);
|
2006-10-29 00:17:11 +00:00
|
|
|
printf ("%c ", ((bits[bpl*y+x/8])&(1<<bit)) ? ' ' : 'X');
|
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-07-05 22:50:54 +00:00
|
|
|
for (y = 0; y < h; y++)
|
|
|
|
{
|
2022-10-06 08:57:12 +00:00
|
|
|
const uint8_t *andp, *xorp;
|
2006-10-29 00:17:11 +00:00
|
|
|
if (bmi.bi.biHeight < 0)
|
|
|
|
{
|
|
|
|
andp = bits + bpl*y;
|
|
|
|
xorp = bits + bpl*(h+y);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
andp = bits + bpl*(h-y-1);
|
|
|
|
xorp = bits + bpl*(h+h-y-1);
|
|
|
|
}
|
2005-07-05 22:50:54 +00:00
|
|
|
for (x = 0; x < w; x++)
|
|
|
|
{
|
2020-07-24 13:54:49 +00:00
|
|
|
const int bit = 7 - (x % 8);
|
2006-10-29 00:17:11 +00:00
|
|
|
if ((*andp) & (1<<bit))
|
|
|
|
{
|
|
|
|
if ((*xorp) & (1<<bit))
|
|
|
|
pixels[2] = pixels[1] = pixels[0] = 0xFF;
|
|
|
|
else
|
|
|
|
pixels[2] = pixels[1] = pixels[0] = 0;
|
|
|
|
pixels[3] = 0xFF;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pixels[2] = pixels[1] = pixels[0] = 0;
|
|
|
|
pixels[3] = 0;
|
|
|
|
}
|
2005-07-05 22:50:54 +00:00
|
|
|
pixels += 4;
|
2006-10-29 00:17:11 +00:00
|
|
|
if (bit == 0)
|
|
|
|
{
|
|
|
|
andp++;
|
|
|
|
xorp++;
|
|
|
|
}
|
2005-07-05 22:50:54 +00:00
|
|
|
}
|
2023-03-15 00:45:48 +00:00
|
|
|
pixels += rowstride - w * 4;
|
2005-07-05 22:50:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-06 14:21:05 +00:00
|
|
|
if (x_hot)
|
|
|
|
*x_hot = ii.xHotspot;
|
|
|
|
if (y_hot)
|
|
|
|
*y_hot = ii.yHotspot;
|
2005-07-05 22:50:54 +00:00
|
|
|
|
|
|
|
/* release temporary resources */
|
|
|
|
out2:
|
|
|
|
g_free (bits);
|
|
|
|
out1:
|
|
|
|
DeleteDC (hdc);
|
|
|
|
out0:
|
|
|
|
DeleteObject (ii.hbmColor);
|
|
|
|
DeleteObject (ii.hbmMask);
|
|
|
|
|
|
|
|
return pixbuf;
|
|
|
|
}
|
|
|
|
|
2005-06-04 21:43:03 +00:00
|
|
|
/* Convert a pixbuf to an HICON (or HCURSOR). Supports alpha under
|
|
|
|
* Windows XP, thresholds alpha otherwise. Also used from
|
2018-03-20 10:46:11 +00:00
|
|
|
* gdksurface-win32.c for creating application icons.
|
2005-06-04 21:43:03 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static HBITMAP
|
2022-10-06 08:57:12 +00:00
|
|
|
create_alpha_bitmap (int size,
|
|
|
|
uint8_t **outdata)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
|
|
|
BITMAPV5HEADER bi;
|
|
|
|
HDC hdc;
|
|
|
|
HBITMAP hBitmap;
|
|
|
|
|
|
|
|
ZeroMemory (&bi, sizeof (BITMAPV5HEADER));
|
|
|
|
bi.bV5Size = sizeof (BITMAPV5HEADER);
|
2006-04-06 10:34:15 +00:00
|
|
|
bi.bV5Height = bi.bV5Width = size;
|
2005-06-04 21:43:03 +00:00
|
|
|
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
|
2022-10-06 08:57:12 +00:00
|
|
|
create_color_bitmap (int size,
|
|
|
|
uint8_t **outdata,
|
|
|
|
int bits)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
2005-11-06 05:36:49 +00:00
|
|
|
struct {
|
|
|
|
BITMAPV4HEADER bmiHeader;
|
|
|
|
RGBQUAD bmiColors[2];
|
|
|
|
} bmi;
|
2005-06-04 21:43:03 +00:00
|
|
|
HDC hdc;
|
|
|
|
HBITMAP hBitmap;
|
|
|
|
|
2005-11-06 05:36:49 +00:00
|
|
|
ZeroMemory (&bmi, sizeof (bmi));
|
|
|
|
bmi.bmiHeader.bV4Size = sizeof (BITMAPV4HEADER);
|
2006-04-06 10:34:15 +00:00
|
|
|
bmi.bmiHeader.bV4Height = bmi.bmiHeader.bV4Width = size;
|
2005-11-06 05:36:49 +00:00
|
|
|
bmi.bmiHeader.bV4Planes = 1;
|
|
|
|
bmi.bmiHeader.bV4BitCount = bits;
|
|
|
|
bmi.bmiHeader.bV4V4Compression = BI_RGB;
|
|
|
|
|
|
|
|
/* when bits is 1, these will be used.
|
|
|
|
* bmiColors[0] already zeroed from ZeroMemory()
|
|
|
|
*/
|
|
|
|
bmi.bmiColors[1].rgbBlue = 0xFF;
|
|
|
|
bmi.bmiColors[1].rgbGreen = 0xFF;
|
|
|
|
bmi.bmiColors[1].rgbRed = 0xFF;
|
2005-06-04 21:43:03 +00:00
|
|
|
|
|
|
|
hdc = GetDC (NULL);
|
|
|
|
if (!hdc)
|
|
|
|
{
|
|
|
|
WIN32_GDI_FAILED ("GetDC");
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-11-06 05:36:49 +00:00
|
|
|
hBitmap = CreateDIBSection (hdc, (BITMAPINFO *)&bmi, DIB_RGB_COLORS,
|
2005-06-04 21:43:03 +00:00
|
|
|
(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;
|
2022-10-06 08:57:12 +00:00
|
|
|
const uint8_t *indata;
|
|
|
|
const uint8_t *inrow;
|
|
|
|
uint8_t *colordata, *colorrow, *maskdata, *maskbyte;
|
2020-07-24 13:54:49 +00:00
|
|
|
int width, height, size, i, i_offset, j, j_offset, rowstride;
|
2005-11-06 05:36:49 +00:00
|
|
|
guint maskstride, mask_bit;
|
2005-06-04 21:43:03 +00:00
|
|
|
|
|
|
|
width = gdk_pixbuf_get_width (pixbuf); /* width of icon */
|
|
|
|
height = gdk_pixbuf_get_height (pixbuf); /* height of icon */
|
|
|
|
|
2006-04-06 10:34:15 +00:00
|
|
|
/* The bitmaps are created square */
|
|
|
|
size = MAX (width, height);
|
|
|
|
|
|
|
|
hColorBitmap = create_alpha_bitmap (size, &colordata);
|
2005-06-04 21:43:03 +00:00
|
|
|
if (!hColorBitmap)
|
|
|
|
return FALSE;
|
2006-04-06 10:34:15 +00:00
|
|
|
hMaskBitmap = create_color_bitmap (size, &maskdata, 1);
|
2005-06-04 21:43:03 +00:00
|
|
|
if (!hMaskBitmap)
|
|
|
|
{
|
|
|
|
DeleteObject (hColorBitmap);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2005-11-06 05:36:49 +00:00
|
|
|
/* MSDN says mask rows are aligned to "LONG" boundaries */
|
2006-04-06 10:34:15 +00:00
|
|
|
maskstride = (((size + 31) & ~31) >> 3);
|
2005-11-03 13:29:30 +00:00
|
|
|
|
2022-10-06 08:57:12 +00:00
|
|
|
indata = gdk_pixbuf_read_pixels (pixbuf);
|
2005-06-04 21:43:03 +00:00
|
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
2006-04-06 10:34:15 +00:00
|
|
|
|
|
|
|
if (width > height)
|
|
|
|
{
|
|
|
|
i_offset = 0;
|
|
|
|
j_offset = (width - height) / 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i_offset = (height - width) / 2;
|
|
|
|
j_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < height; j++)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
2006-04-06 10:34:15 +00:00
|
|
|
colorrow = colordata + 4*(j+j_offset)*size + 4*i_offset;
|
|
|
|
maskbyte = maskdata + (j+j_offset)*maskstride + i_offset/8;
|
|
|
|
mask_bit = (0x80 >> (i_offset % 8));
|
|
|
|
inrow = indata + (height-j-1)*rowstride;
|
|
|
|
for (i = 0; i < width; i++)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
2005-11-03 13:29:30 +00:00
|
|
|
colorrow[4*i+0] = inrow[4*i+2];
|
|
|
|
colorrow[4*i+1] = inrow[4*i+1];
|
|
|
|
colorrow[4*i+2] = inrow[4*i+0];
|
|
|
|
colorrow[4*i+3] = inrow[4*i+3];
|
|
|
|
if (inrow[4*i+3] == 0)
|
2005-11-06 05:36:49 +00:00
|
|
|
maskbyte[0] |= mask_bit; /* turn ON bit */
|
2005-11-03 13:29:30 +00:00
|
|
|
else
|
2005-11-06 05:36:49 +00:00
|
|
|
maskbyte[0] &= ~mask_bit; /* turn OFF bit */
|
|
|
|
mask_bit >>= 1;
|
|
|
|
if (mask_bit == 0)
|
|
|
|
{
|
|
|
|
mask_bit = 0x80;
|
|
|
|
maskbyte++;
|
|
|
|
}
|
2005-06-04 21:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-03 13:29:30 +00:00
|
|
|
*color = hColorBitmap;
|
|
|
|
*mask = hMaskBitmap;
|
2005-06-04 21:43:03 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
pixbuf_to_hbitmaps_normal (GdkPixbuf *pixbuf,
|
|
|
|
HBITMAP *color,
|
|
|
|
HBITMAP *mask)
|
|
|
|
{
|
|
|
|
/* Based on code from
|
|
|
|
* http://www.dotnet247.com/247reference/msgs/13/66301.aspx
|
|
|
|
*/
|
|
|
|
HBITMAP hColorBitmap, hMaskBitmap;
|
2022-10-06 08:57:12 +00:00
|
|
|
const uint8_t *indata;
|
|
|
|
const uint8_t *inrow;
|
|
|
|
uint8_t *colordata, *colorrow, *maskdata, *maskbyte;
|
2020-07-24 13:54:49 +00:00
|
|
|
int width, height, size, i, i_offset, j, j_offset, rowstride, nc, bmstride;
|
2005-06-04 21:43:03 +00:00
|
|
|
gboolean has_alpha;
|
2005-11-06 05:36:49 +00:00
|
|
|
guint maskstride, mask_bit;
|
2005-06-04 21:43:03 +00:00
|
|
|
|
|
|
|
width = gdk_pixbuf_get_width (pixbuf); /* width of icon */
|
|
|
|
height = gdk_pixbuf_get_height (pixbuf); /* height of icon */
|
|
|
|
|
2006-04-06 10:34:15 +00:00
|
|
|
/* The bitmaps are created square */
|
|
|
|
size = MAX (width, height);
|
|
|
|
|
|
|
|
hColorBitmap = create_color_bitmap (size, &colordata, 24);
|
2005-06-04 21:43:03 +00:00
|
|
|
if (!hColorBitmap)
|
|
|
|
return FALSE;
|
2006-04-06 10:34:15 +00:00
|
|
|
hMaskBitmap = create_color_bitmap (size, &maskdata, 1);
|
2005-06-04 21:43:03 +00:00
|
|
|
if (!hMaskBitmap)
|
|
|
|
{
|
|
|
|
DeleteObject (hColorBitmap);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-08-21 12:41:13 +00:00
|
|
|
/* rows are always aligned on 4-byte boundaries */
|
2006-04-06 10:34:15 +00:00
|
|
|
bmstride = size * 3;
|
2005-06-04 21:43:03 +00:00
|
|
|
if (bmstride % 4 != 0)
|
|
|
|
bmstride += 4 - (bmstride % 4);
|
|
|
|
|
2005-11-06 05:36:49 +00:00
|
|
|
/* MSDN says mask rows are aligned to "LONG" boundaries */
|
2006-04-06 10:34:15 +00:00
|
|
|
maskstride = (((size + 31) & ~31) >> 3);
|
2005-11-06 05:36:49 +00:00
|
|
|
|
2022-10-06 08:57:12 +00:00
|
|
|
indata = gdk_pixbuf_read_pixels (pixbuf);
|
2005-06-04 21:43:03 +00:00
|
|
|
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
|
|
|
|
nc = gdk_pixbuf_get_n_channels (pixbuf);
|
|
|
|
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
|
|
|
|
2006-04-06 10:34:15 +00:00
|
|
|
if (width > height)
|
|
|
|
{
|
|
|
|
i_offset = 0;
|
|
|
|
j_offset = (width - height) / 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
i_offset = (height - width) / 2;
|
|
|
|
j_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < height; j++)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
2006-04-06 10:34:15 +00:00
|
|
|
colorrow = colordata + (j+j_offset)*bmstride + 3*i_offset;
|
|
|
|
maskbyte = maskdata + (j+j_offset)*maskstride + i_offset/8;
|
|
|
|
mask_bit = (0x80 >> (i_offset % 8));
|
|
|
|
inrow = indata + (height-j-1)*rowstride;
|
|
|
|
for (i = 0; i < width; i++)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
|
|
|
if (has_alpha && inrow[nc*i+3] < 128)
|
|
|
|
{
|
|
|
|
colorrow[3*i+0] = colorrow[3*i+1] = colorrow[3*i+2] = 0;
|
2005-11-06 05:36:49 +00:00
|
|
|
maskbyte[0] |= mask_bit; /* turn ON bit */
|
2005-06-04 21:43:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
colorrow[3*i+0] = inrow[nc*i+2];
|
|
|
|
colorrow[3*i+1] = inrow[nc*i+1];
|
|
|
|
colorrow[3*i+2] = inrow[nc*i+0];
|
2005-11-06 05:36:49 +00:00
|
|
|
maskbyte[0] &= ~mask_bit; /* turn OFF bit */
|
|
|
|
}
|
|
|
|
mask_bit >>= 1;
|
|
|
|
if (mask_bit == 0)
|
|
|
|
{
|
|
|
|
mask_bit = 0x80;
|
|
|
|
maskbyte++;
|
2005-06-04 21:43:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-03 13:29:30 +00:00
|
|
|
*color = hColorBitmap;
|
|
|
|
*mask = hMaskBitmap;
|
2005-06-04 21:43:03 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HICON
|
|
|
|
pixbuf_to_hicon (GdkPixbuf *pixbuf,
|
|
|
|
gboolean is_icon,
|
2020-07-24 13:54:49 +00:00
|
|
|
int x,
|
|
|
|
int y)
|
2005-06-04 21:43:03 +00:00
|
|
|
{
|
|
|
|
ICONINFO ii;
|
|
|
|
HICON icon;
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
if (pixbuf == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2015-04-19 23:04:53 +00:00
|
|
|
if (gdk_pixbuf_get_has_alpha (pixbuf))
|
2005-06-04 21:43:03 +00:00
|
|
|
success = pixbuf_to_hbitmaps_alpha_winxp (pixbuf, &ii.hbmColor, &ii.hbmMask);
|
|
|
|
else
|
|
|
|
success = pixbuf_to_hbitmaps_normal (pixbuf, &ii.hbmColor, &ii.hbmMask);
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ii.fIcon = is_icon;
|
|
|
|
ii.xHotspot = x;
|
|
|
|
ii.yHotspot = y;
|
|
|
|
icon = CreateIconIndirect (&ii);
|
|
|
|
DeleteObject (ii.hbmColor);
|
|
|
|
DeleteObject (ii.hbmMask);
|
|
|
|
return icon;
|
|
|
|
}
|
|
|
|
|
2017-11-07 07:39:48 +00:00
|
|
|
/**
|
2018-03-29 23:40:32 +00:00
|
|
|
* gdk_win32_display_get_win32hcursor:
|
2021-05-20 03:39:18 +00:00
|
|
|
* @display: (type GdkWin32Display): a `GdkDisplay`
|
|
|
|
* @cursor: a `GdkCursor`
|
|
|
|
*
|
|
|
|
* Returns the Win32 HCURSOR wrapper object belonging to a `GdkCursor`,
|
2018-03-29 23:40:32 +00:00
|
|
|
* potentially creating the cursor object.
|
2017-11-07 07:39:48 +00:00
|
|
|
*
|
|
|
|
* Be aware that the returned cursor may not be unique to @cursor.
|
|
|
|
* It may for example be shared with its fallback cursor.
|
2021-05-20 03:39:18 +00:00
|
|
|
*
|
|
|
|
* Returns: a GdkWin32HCursor
|
|
|
|
*/
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *
|
|
|
|
gdk_win32_display_get_win32hcursor (GdkWin32Display *display,
|
|
|
|
GdkCursor *cursor)
|
2011-01-02 10:51:25 +00:00
|
|
|
{
|
2017-11-07 07:39:48 +00:00
|
|
|
GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkWin32HCursor *win32hcursor;
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *cursor_name;
|
2024-03-21 01:33:18 +00:00
|
|
|
GdkTexture *texture;
|
2018-03-29 23:40:32 +00:00
|
|
|
GdkCursor *fallback;
|
2017-11-07 07:39:48 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (cursor != NULL, NULL);
|
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (gdk_display_is_closed (GDK_DISPLAY (display)))
|
2017-11-07 07:39:48 +00:00
|
|
|
return NULL;
|
2011-01-02 10:51:25 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor = g_hash_table_lookup (win32_display->cursors, cursor);
|
|
|
|
|
|
|
|
if (win32hcursor != NULL)
|
|
|
|
return win32hcursor;
|
|
|
|
|
|
|
|
cursor_name = gdk_cursor_get_name (cursor);
|
2024-03-21 01:33:18 +00:00
|
|
|
texture = gdk_cursor_get_texture (cursor);
|
2018-03-29 23:40:32 +00:00
|
|
|
|
|
|
|
if (cursor_name)
|
|
|
|
win32hcursor = gdk_win32hcursor_create_for_name (display, cursor_name);
|
2024-03-21 01:33:18 +00:00
|
|
|
else if (texture)
|
2018-03-29 23:40:32 +00:00
|
|
|
win32hcursor = gdk_win32hcursor_create_for_texture (display,
|
2024-03-21 01:33:18 +00:00
|
|
|
texture,
|
2018-03-29 23:40:32 +00:00
|
|
|
gdk_cursor_get_hotspot_x (cursor),
|
|
|
|
gdk_cursor_get_hotspot_y (cursor));
|
2024-03-21 01:33:18 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int size = display->cursor_theme_size;
|
|
|
|
int width, height, hotspot_x, hotspot_y;
|
|
|
|
|
|
|
|
texture = gdk_cursor_get_texture_for_size (cursor, size, 1,
|
|
|
|
&width, &height,
|
|
|
|
&hotspot_x, &hotspot_y);
|
|
|
|
if (texture)
|
|
|
|
{
|
|
|
|
win32hcursor = gdk_win32hcursor_create_for_texture (display,
|
|
|
|
texture,
|
|
|
|
hotspot_x,
|
|
|
|
hotspot_y);
|
|
|
|
g_object_unref (texture);
|
|
|
|
}
|
|
|
|
}
|
2017-11-07 07:39:48 +00:00
|
|
|
|
2018-03-29 23:40:32 +00:00
|
|
|
if (win32hcursor != NULL)
|
2017-11-07 07:39:48 +00:00
|
|
|
{
|
2018-04-11 16:39:34 +00:00
|
|
|
g_object_weak_ref (G_OBJECT (cursor), gdk_win32_cursor_remove_from_cache, display);
|
2018-03-29 23:40:32 +00:00
|
|
|
g_hash_table_insert (win32_display->cursors, cursor, win32hcursor);
|
|
|
|
|
|
|
|
return win32hcursor;
|
2017-11-07 07:39:48 +00:00
|
|
|
}
|
2018-03-29 23:40:32 +00:00
|
|
|
|
|
|
|
fallback = gdk_cursor_get_fallback (cursor);
|
|
|
|
|
|
|
|
if (fallback)
|
|
|
|
return gdk_win32_display_get_win32hcursor (display, fallback);
|
2017-11-07 07:39:48 +00:00
|
|
|
|
|
|
|
return NULL;
|
2011-01-02 10:51:25 +00:00
|
|
|
}
|