[User] Fix clip cursor handling on resolution change
Lionel Ulmer
lionel.ulmer at free.fr
Tue Nov 1 15:03:51 CST 2005
This is the patch which fixes the mouse on DungeonKeeper (resent after 1.5
years :-) ). But this time I added some tests so I hope it will get in :-)
Lionel
Changelog:
- fix ClipCursor handling on resolution change
- add tests for other corner cases
--
Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
Index: dlls/x11drv/settings.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/settings.c,v
retrieving revision 1.3
diff -u -r1.3 settings.c
--- dlls/x11drv/settings.c 18 Jul 2005 13:20:18 -0000 1.3
+++ dlls/x11drv/settings.c 1 Nov 2005 21:01:53 -0000
@@ -239,6 +239,7 @@
{
DWORD i;
DEVMODEW dm;
+ int cur_mode;
TRACE("(%s,%p,%p,0x%08lx,%p)\n",debugstr_w(devname),devmode,hwnd,flags,lpvoid);
TRACE("flags=%s\n",_CDS_flags(flags));
@@ -260,6 +261,8 @@
devmode = &dm;
}
+ cur_mode = pGetCurrentMode();
+
for (i = 0; i < dd_mode_count; i++)
{
if (devmode->dmFields & DM_BITSPERPEL)
@@ -284,11 +287,33 @@
}
/* we have a valid mode */
TRACE("Requested display settings match mode %ld (%s)\n", i, handler_name);
- if (!(flags & CDS_TEST))
+ if (!(flags & CDS_TEST)) {
pSetCurrentMode(i);
+
+ if (i != cur_mode) {
+ /* This means that we choose another resolution .. Update the clip cursor accordingly.
+ *
+ * Note: at this point, as 'pSetCurrentMode' has been called, we suppose that the System
+ * metrics have been updated properly and that the sanity checks in ClipCursor
+ * won't give us any problems.
+ */
+ RECT rect;
+
+ TRACE("New mode (%ld) different from current mode (%d) - updating clip cursor.\n", i, cur_mode);
+
+ rect.top = 0;
+ rect.bottom = dd_modes[i].dwHeight;
+
+ rect.left = 0;
+ rect.right = dd_modes[i].dwWidth;
+
+ ClipCursor(&rect);
+ }
+ }
+
return DISP_CHANGE_SUCCESSFUL;
}
-
+
/* no valid modes found */
ERR("No matching mode found! (%s)\n", handler_name);
return DISP_CHANGE_BADMODE;
Index: dlls/user/cursoricon.c
===================================================================
RCS file: /home/wine/wine/dlls/user/cursoricon.c,v
retrieving revision 1.17
diff -u -r1.17 cursoricon.c
--- dlls/user/cursoricon.c 12 Sep 2005 10:30:06 -0000 1.17
+++ dlls/user/cursoricon.c 1 Nov 2005 21:01:54 -0000
@@ -1553,7 +1553,29 @@
BOOL WINAPI ClipCursor( const RECT *rect )
{
if (!rect) SetRectEmpty( &CURSOR_ClipRect );
- else CopyRect( &CURSOR_ClipRect, rect );
+ else {
+ /* Some sanity checks (verified on Win2K) */
+ RECT screen_rect;
+
+ screen_rect.top = screen_rect.left = 0;
+ screen_rect.right = GetSystemMetrics(SM_CXSCREEN);
+ screen_rect.bottom = GetSystemMetrics(SM_CYSCREEN);
+
+ /* If the rectangle is bad or out of the screen rectangle, the clip cursor is set
+ * to the whole screen.
+ */
+ if ((rect->top > rect->bottom) || (rect->left > rect->right) ||
+ (rect->top >= screen_rect.bottom) ||
+ (rect->bottom < screen_rect.top) ||
+ (rect->left >= screen_rect.right) ||
+ (rect->right < screen_rect.left))
+ rect = &screen_rect;
+
+ /* If the rectangle is empty, keep the same rectangle */
+ if (IsRectEmpty(rect)) CopyRect(&CURSOR_ClipRect, rect);
+ /* Otherwise, it's the intersection of the given rectangle with the screen */
+ else IntersectRect(&CURSOR_ClipRect, rect, &screen_rect);
+ }
return TRUE;
}
Index: dlls/user/user_main.c
===================================================================
RCS file: /home/wine/wine/dlls/user/user_main.c,v
retrieving revision 1.97
diff -u -r1.97 user_main.c
--- dlls/user/user_main.c 17 Sep 2005 14:28:44 -0000 1.97
+++ dlls/user/user_main.c 1 Nov 2005 21:01:54 -0000
@@ -158,6 +158,7 @@
static BOOL process_attach(void)
{
HINSTANCE16 instance;
+ RECT rect;
/* Create USER heap */
if ((instance = LoadLibrary16( "USER.EXE" )) >= 32) USER_HeapSel = instance | 7;
@@ -173,6 +174,13 @@
/* Initialize system colors and metrics */
SYSPARAMS_Init();
+ /* Now that system metrics are set-up, we can initialize the clip rectangle */
+ rect.left = 0;
+ rect.right = GetSystemMetrics(SM_CXSCREEN);
+ rect.top = 0;
+ rect.bottom = GetSystemMetrics(SM_CYSCREEN);
+ ClipCursor(&rect);
+
/* Setup palette function pointers */
palette_init();
Index: dlls/user/tests/monitor.c
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/monitor.c,v
retrieving revision 1.2
diff -u -r1.2 monitor.c
--- dlls/user/tests/monitor.c 11 Oct 2005 20:27:27 -0000 1.2
+++ dlls/user/tests/monitor.c 1 Nov 2005 21:01:54 -0000
@@ -86,9 +86,104 @@
}
}
+static void test_changedisplaysettings(void)
+{
+ RECT rect;
+ DEVMODE mode;
+
+ EnumDisplaySettingsEx(NULL, ENUM_CURRENT_SETTINGS, &mode, 0);
+
+ /* Basic test */
+ rect.left = 0; rect.top = 0;
+ rect.right = 400; rect.bottom = 400;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 0) && (rect.top == 0) && (rect.right == 400) && (rect.bottom == 400), "ClipCursor not properly set\n");
+
+ /* Test various 'broken' clipping cursors */
+ rect.left = 50; rect.top = 50;
+ rect.right = 3000; rect.bottom = 3000;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 50) && (rect.top == 50) && (rect.right == mode.dmPelsWidth) && (rect.bottom == mode.dmPelsHeight), "ClipCursor not properly set (clip 1)\n");
+
+ rect.left = -50; rect.top = -50;
+ rect.right = 400; rect.bottom = 400;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 0) && (rect.top == 0) && (rect.right == 400) && (rect.bottom == 400), "ClipCursor not properly set (clip 2)\n");
+
+ rect.left = 3000; rect.top = 3000;
+ rect.right = 4000; rect.bottom = 4000;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 0) && (rect.top == 0) && (rect.right == mode.dmPelsWidth) && (rect.bottom == mode.dmPelsHeight), "ClipCursor not properly set (out of screen)\n");
+
+ rect.left = 50; rect.top = 50;
+ rect.right = 50; rect.bottom = 50;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 50) && (rect.top == 50) && (rect.right == 50) && (rect.bottom == 50), "ClipCursor not properly set (point in screen)\n");
+
+ rect.left = 3000; rect.top = 3000;
+ rect.right = 3000; rect.bottom = 3000;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 0) && (rect.top == 0) && (rect.right == mode.dmPelsWidth) && (rect.bottom == mode.dmPelsHeight), "ClipCursor not properly set (point out of screen)\n");
+
+ /* Tests with resolution / depth change */
+ if ((mode.dmPelsWidth != 640) || (mode.dmPelsHeight != 480)) {
+ /* I am lazy here... Instead of searching for a given mode in the list, I use 640x480 if not already the current
+ * mode and just exit the test if it cannot be set.
+ */
+ rect.left = 0; rect.top = 0;
+ rect.right = 400; rect.bottom = 400;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+
+ mode.dmSize = sizeof(mode);
+ mode.dmDriverExtra = 0;
+ mode.dmPelsWidth = 640;
+ mode.dmPelsHeight = 480;
+ mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ if (ChangeDisplaySettingsEx(NULL, &mode, NULL, 0, NULL) != DISP_CHANGE_SUCCESSFUL) {
+ return;
+ }
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 0) && (rect.top == 0) && (rect.right == 640) && (rect.bottom == 480), "ClipCursor not properly set (after resolution change)\n");
+
+ rect.left = 0; rect.top = 0;
+ rect.right = 400; rect.bottom = 400;
+ ClipCursor(&rect);
+ memset(&rect, 0, sizeof(rect));
+
+ mode.dmSize = sizeof(mode);
+ mode.dmDriverExtra = 0;
+ mode.dmPelsWidth = 640;
+ mode.dmPelsHeight = 480;
+ mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+ if (ChangeDisplaySettingsEx(NULL, &mode, NULL, 0, NULL) != DISP_CHANGE_SUCCESSFUL) {
+ return;
+ }
+ memset(&rect, 0, sizeof(rect));
+ ok(GetClipCursor(&rect), "GetClipCursor failed\n");
+ ok((rect.left == 0) && (rect.top == 0) && (rect.right == 400) && (rect.bottom == 400), "ClipCursor not properly set (after dummy resolution change)\n");
+
+ /* Go back to original mode */
+ ChangeDisplaySettingsEx(NULL, NULL, NULL, 0, NULL);
+ }
+}
START_TEST(monitor)
{
init_function_pointers();
test_enumdisplaydevices();
+ test_changedisplaysettings();
}
More information about the wine-patches
mailing list