win32: Use an invisible cursor when cursor-visible is FALSE

The win32 backend now handles the WM_SETCURSOR message and sets a
fully transparent cursor if the cursor-visible property has been
cleared on the stage. The icon is stored in the library via a resource
file. The instance handle for the DLL is needed to load the resource
so there is now a DllMain function to grab the handle.
This commit is contained in:
Neil Roberts 2010-01-15 22:56:37 +00:00
parent 4db89759a0
commit 14a28620ae
10 changed files with 112 additions and 6 deletions

View File

@ -20,6 +20,23 @@ DISTCLEANFILES =
EXTRA_DIST =
BUILT_SOURCES =
if WINSYS_WIN32
# Ideally this resources stuff would go in win32/ but libtool doesn't
# seem to pass on the -Wl argument when linking a convenience library
# so we need to do it here as part of linking the dll. libtool also
# won't let you link against the .o directly because it wants you to
# link against libtool objects for dynamic libraries.
.rc.o :
$(WINDRES) -I$(srcdir)/win32 $< $@
win32/resources.o : $(srcdir)/win32/invisible-cursor.cur
win32_resources = win32/resources.o
win32_resources_ldflag = -Wl,win32/resources.o
endif # WINSYS_WIN32
INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/clutter/cogl \
@ -205,7 +222,8 @@ libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_DEPENDENCIES = \
$(top_builddir)/clutter/cogl/pango/libcoglpango.la \
$(top_builddir)/clutter/$(CLUTTER_WINSYS)/libclutter-$(CLUTTER_WINSYS).la \
$(clutter_json_dep) \
$(CLUTTER_WINSYS_BASE_LIB)
$(CLUTTER_WINSYS_BASE_LIB) \
$(win32_resources)
libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_SOURCES = \
$(source_c) \
@ -219,6 +237,7 @@ libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_LDFLAGS = \
-export-dynamic \
-export-symbols-regex "^(clutter|cogl|json).*" \
-rpath $(libdir) \
$(win32_resources_ldflag) \
$(NULL)
lib_LTLIBRARIES = $(CLUTTER_WINSYS_LIB)

View File

@ -33,4 +33,4 @@ libclutter_win32_la_SOURCES = \
CLEANFILES = clutter-win32-$(CLUTTER_API_VERSION).pc
EXTRA_DIST = clutter-win32.pc.in
EXTRA_DIST = clutter-win32.pc.in resources.rc invisible-cursor.cur

View File

@ -47,6 +47,8 @@ static ClutterBackendWin32 *backend_singleton = NULL;
static gchar *clutter_vblank_name = NULL;
static HINSTANCE clutter_hinst = NULL;
gboolean
clutter_backend_win32_pre_parse (ClutterBackend *backend,
GError **error)
@ -67,6 +69,18 @@ clutter_backend_win32_init_events (ClutterBackend *backend)
_clutter_backend_win32_events_init (backend);
}
HCURSOR
_clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend)
{
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
if (backend_win32->invisible_cursor == NULL)
backend_win32->invisible_cursor =
LoadCursor (clutter_hinst, MAKEINTRESOURCE (42));
return backend_win32->invisible_cursor;
}
static const GOptionEntry entries[] =
{
{
@ -353,6 +367,7 @@ clutter_backend_win32_init (ClutterBackendWin32 *backend_win32)
backend_win32->gl_context = NULL;
backend_win32->no_event_retrieval = FALSE;
backend_win32->invisible_cursor = NULL;
/* FIXME: get from GetSystemMetric? */
clutter_backend_set_double_click_time (backend, 250);
@ -370,3 +385,13 @@ _clutter_backend_impl_get_type (void)
{
return clutter_backend_win32_get_type ();
}
BOOL WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
/* Store the module handle so that we can use it to load resources */
clutter_hinst = hinst;
return TRUE;
}

View File

@ -48,6 +48,8 @@ struct _ClutterBackendWin32
HGLRC gl_context;
gboolean no_event_retrieval;
HCURSOR invisible_cursor;
GSource *event_source;
};
@ -68,6 +70,8 @@ clutter_backend_win32_add_options (ClutterBackend *backend,
ClutterFeatureFlags
clutter_backend_win32_get_features (ClutterBackend *backend);
HCURSOR _clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_WIN32_H__ */

View File

@ -616,6 +616,20 @@ message_translate (ClutterBackend *backend,
}
break;
case WM_SETCURSOR:
/* If the cursor is in the window's client area and the stage's
cursor should be invisible then we'll set a blank cursor
instead */
if (LOWORD (msg->lParam) == HTCLIENT && !stage_win32->is_cursor_visible)
{
if (call_def_window_proc)
*call_def_window_proc = FALSE;
_clutter_stage_win32_update_cursor (stage_win32);
}
res = FALSE;
break;
default:
/* ignore every other message */
res = FALSE;

View File

@ -216,17 +216,51 @@ clutter_stage_win32_set_title (ClutterStageWindow *stage_window,
SetWindowTextW (stage_win32->hwnd, stage_win32->wtitle);
}
void
_clutter_stage_win32_update_cursor (ClutterStageWin32 *stage_win32)
{
HCURSOR cursor;
if (stage_win32->is_cursor_visible)
cursor = (HCURSOR) GetClassLongPtrW (stage_win32->hwnd, GCL_HCURSOR);
else
{
ClutterBackend *backend = clutter_get_default_backend ();
/* The documentation implies that we can just use
SetCursor(NULL) to get rid of the cursor but apparently this
doesn't work very well so instead we create an invisible
cursor */
cursor = _clutter_backend_win32_get_invisible_cursor (backend);
}
SetCursor (cursor);
}
static void
clutter_stage_win32_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible)
{
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
if (stage_win32->is_cursor_visible != cursor_visible &&
stage_win32->tracking_mouse)
ShowCursor (cursor_visible);
if (stage_win32->is_cursor_visible != cursor_visible)
{
POINT cursor_pos;
RECT client_rect;
stage_win32->is_cursor_visible = cursor_visible;
stage_win32->is_cursor_visible = cursor_visible;
/* If the cursor is already over the client area of the window
then we need to update it immediately */
GetCursorPos (&cursor_pos);
if (WindowFromPoint (cursor_pos) == stage_win32->hwnd &&
ScreenToClient (stage_win32->hwnd, &cursor_pos) &&
GetClientRect (stage_win32->hwnd, &client_rect) &&
cursor_pos.x >= client_rect.left &&
cursor_pos.y >= client_rect.top &&
cursor_pos.x < client_rect.right &&
cursor_pos.y < client_rect.bottom)
_clutter_stage_win32_update_cursor (stage_win32);
}
}
static LONG

View File

@ -80,6 +80,8 @@ LRESULT CALLBACK _clutter_stage_win32_window_proc (HWND hwnd,
void _clutter_stage_win32_get_min_max_info (ClutterStageWin32 *stage_win32,
MINMAXINFO *min_max_info);
void _clutter_stage_win32_update_cursor (ClutterStageWin32 *stage_win32);
G_END_DECLS
#endif /* __CLUTTER_STAGE_H__ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 B

View File

@ -0,0 +1 @@
42 CURSOR "invisible-cursor.cur"

View File

@ -364,11 +364,18 @@ AS_CASE([$CLUTTER_WINSYS],
WIN32_CFLAGS="-D_WIN32_WINNT=0x0500"
WIN32_LIBS="-lopengl32 -lgdi32 -lwinmm"
CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined"
AC_CHECK_TOOL(WINDRES, windres, no)
if test "$WINDRES" = no; then
AC_MSG_ERROR([*** windres is required])
fi
],
[AC_MSG_ERROR([Invalid backend for Clutter: use glx, sdl, osx, win32, eglx, eglnative or fruity])]
)
AM_CONDITIONAL(WINSYS_WIN32, [test "x$CLUTTER_WINSYS" = "xwin32"])
# at this point we must have a GL header to check
AS_IF([test "x$clutter_gl_header" = "x"], [AC_MSG_ERROR([Internal error: no GL header set])])
AC_CHECK_HEADERS([$clutter_gl_header],