Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
April 2021
- 70 participants
- 697 discussions
[PATCH 5/5] comctl32/theme_dialog: Pass the WM_SYSCOLORCHANGE message to the original dialog procedure.
by Zhiyi Zhang 26 Apr '21
by Zhiyi Zhang 26 Apr '21
26 Apr '21
Even though themed dialog itself doesn't need to repaint after WM_SYSCOLORCHANGE is received,
WM_SYSCOLORCHANGE should be passed to the original dialog procedure DefDlgProcW(), which can then
forward WM_SYSCOLORCHANGE to its common controls and call COMCTL32_RefreshSysColors().
Fix wrong property sheet tab background color after winecfg disables theming.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44511
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/tests/misc.c | 12 ++----------
dlls/comctl32/theme_dialog.c | 8 +-------
2 files changed, 3 insertions(+), 17 deletions(-)
diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
index e2a1dc00bc4..9d3ca76e8d5 100644
--- a/dlls/comctl32/tests/misc.c
+++ b/dlls/comctl32/tests/misc.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
-#include <uxtheme.h>
#include "wine/test.h"
#include "v6util.h"
@@ -40,9 +39,8 @@ static BOOL (WINAPI * pStr_SetPtrW)(LPWSTR, LPCWSTR);
static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
-static BOOL (WINAPI *pIsThemeActive)(void);
-static HMODULE hComctl32, hUxtheme;
+static HMODULE hComctl32;
/* For message tests */
enum seq_index
@@ -108,9 +106,6 @@ static BOOL init_functions_v6(void)
COMCTL32_GET_PROC(412, RemoveWindowSubclass)
COMCTL32_GET_PROC(413, DefSubclassProc)
- hUxtheme = LoadLibraryA("uxtheme.dll");
- pIsThemeActive = (void *)GetProcAddress(hUxtheme, "IsThemeActive");
-
return TRUE;
}
@@ -630,7 +625,6 @@ static INT_PTR CALLBACK wm_syscolorchange_dlg_proc(HWND hwnd, UINT message, WPAR
static void test_WM_SYSCOLORCHANGE(void)
{
HWND parent, dialog;
- BOOL todo;
struct
{
DLGTEMPLATE tmplate;
@@ -652,8 +646,7 @@ static void test_WM_SYSCOLORCHANGE(void)
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SendMessageW(dialog, WM_SYSCOLORCHANGE, 0, 0);
- todo = pIsThemeActive && pIsThemeActive();
- ok_sequence(sequences, CHILD_SEQ_INDEX, wm_syscolorchange_seq, "test dialog WM_SYSCOLORCHANGE", todo);
+ ok_sequence(sequences, CHILD_SEQ_INDEX, wm_syscolorchange_seq, "test dialog WM_SYSCOLORCHANGE", FALSE);
EndDialog(dialog, 0);
DestroyWindow(parent);
@@ -687,5 +680,4 @@ START_TEST(misc)
unload_v6_module(ctx_cookie, hCtx);
FreeLibrary(hComctl32);
- FreeLibrary(hUxtheme);
}
diff --git a/dlls/comctl32/theme_dialog.c b/dlls/comctl32/theme_dialog.c
index 29007ba5c60..0f7835ae32f 100644
--- a/dlls/comctl32/theme_dialog.c
+++ b/dlls/comctl32/theme_dialog.c
@@ -63,13 +63,7 @@ LRESULT CALLBACK THEMING_DialogSubclassProc (HWND hWnd, UINT msg,
OpenThemeData( hWnd, themeClass );
InvalidateRect( hWnd, NULL, TRUE );
return 0;
-
- case WM_SYSCOLORCHANGE:
- if (!doTheming) return THEMING_CallOriginalClass (hWnd, msg, wParam, lParam);
- /* Do nothing. When themed, a WM_THEMECHANGED will be received, too,
- * which will do the repaint. */
- break;
-
+
case WM_ERASEBKGND:
if (!doTheming) return THEMING_CallOriginalClass (hWnd, msg, wParam, lParam);
{
--
2.30.2
1
0
[PATCH 4/5] comctl32/test: Test that WM_SYSCOLORCHANGE should always be passed to the dialog procedure.
by Zhiyi Zhang 26 Apr '21
by Zhiyi Zhang 26 Apr '21
26 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/tests/misc.c | 59 +++++++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
index 15ff3b2d099..e2a1dc00bc4 100644
--- a/dlls/comctl32/tests/misc.c
+++ b/dlls/comctl32/tests/misc.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
+#include <uxtheme.h>
#include "wine/test.h"
#include "v6util.h"
@@ -39,8 +40,9 @@ static BOOL (WINAPI * pStr_SetPtrW)(LPWSTR, LPCWSTR);
static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
+static BOOL (WINAPI *pIsThemeActive)(void);
-static HMODULE hComctl32 = 0;
+static HMODULE hComctl32, hUxtheme;
/* For message tests */
enum seq_index
@@ -106,6 +108,9 @@ static BOOL init_functions_v6(void)
COMCTL32_GET_PROC(412, RemoveWindowSubclass)
COMCTL32_GET_PROC(413, DefSubclassProc)
+ hUxtheme = LoadLibraryA("uxtheme.dll");
+ pIsThemeActive = (void *)GetProcAddress(hUxtheme, "IsThemeActive");
+
return TRUE;
}
@@ -604,6 +609,56 @@ static void test_WM_THEMECHANGED(void)
DestroyWindow(parent);
}
+static const struct message wm_syscolorchange_seq[] =
+{
+ {WM_SYSCOLORCHANGE, sent | wparam | lparam},
+ {0},
+};
+
+static INT_PTR CALLBACK wm_syscolorchange_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ struct message msg = {0};
+
+ msg.message = message;
+ msg.flags = sent | wparam | lparam;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(sequences, CHILD_SEQ_INDEX, &msg);
+ return FALSE;
+}
+
+static void test_WM_SYSCOLORCHANGE(void)
+{
+ HWND parent, dialog;
+ BOOL todo;
+ struct
+ {
+ DLGTEMPLATE tmplate;
+ WORD menu;
+ WORD class;
+ WORD title;
+ } temp = {0};
+
+ parent = CreateWindowExA(0, WC_STATICA, "parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100,
+ 200, 200, 0, 0, 0, NULL);
+ ok(!!parent, "CreateWindowExA failed, error %d\n", GetLastError());
+
+ temp.tmplate.style = WS_CHILD | WS_VISIBLE;
+ temp.tmplate.cx = 50;
+ temp.tmplate.cy = 50;
+ dialog = CreateDialogIndirectParamA(NULL, &temp.tmplate, parent, wm_syscolorchange_dlg_proc, 0);
+ ok(!!dialog, "CreateDialogIndirectParamA failed, error %d\n", GetLastError());
+ flush_events();
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ SendMessageW(dialog, WM_SYSCOLORCHANGE, 0, 0);
+ todo = pIsThemeActive && pIsThemeActive();
+ ok_sequence(sequences, CHILD_SEQ_INDEX, wm_syscolorchange_seq, "test dialog WM_SYSCOLORCHANGE", todo);
+
+ EndDialog(dialog, 0);
+ DestroyWindow(parent);
+}
+
START_TEST(misc)
{
ULONG_PTR ctx_cookie;
@@ -628,7 +683,9 @@ START_TEST(misc)
test_builtin_classes();
test_LoadIconWithScaleDown();
test_WM_THEMECHANGED();
+ test_WM_SYSCOLORCHANGE();
unload_v6_module(ctx_cookie, hCtx);
FreeLibrary(hComctl32);
+ FreeLibrary(hUxtheme);
}
--
2.30.2
1
0
[PATCH 3/5] comctl32/theming: Register themed dialog and scrollbar even when theming is not active.
by Zhiyi Zhang 26 Apr '21
by Zhiyi Zhang 26 Apr '21
26 Apr '21
So that we can turn on theming in runtime. Otherwise, themed dialog and scrollbar
are not enabled even if a theme is made active in winecfg if theming is disabled at start.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44511
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/tests/misc.c | 2 +-
dlls/comctl32/theming.c | 3 ---
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
index 4b0c1f9a4d0..15ff3b2d099 100644
--- a/dlls/comctl32/tests/misc.c
+++ b/dlls/comctl32/tests/misc.c
@@ -580,7 +580,7 @@ static void test_WM_THEMECHANGED(void)
{TRACKBAR_CLASSA, wm_themechanged_paint_seq},
{WC_TREEVIEWA, wm_themechanged_paint_erase_seq, 1, {0x1128}},
{UPDOWN_CLASSA, wm_themechanged_paint_erase_seq},
- {WC_SCROLLBARA, wm_themechanged_paint_erase_seq, 1, {SBM_GETSCROLLINFO}, TRUE},
+ {WC_SCROLLBARA, wm_themechanged_paint_erase_seq, 1, {SBM_GETSCROLLINFO}},
};
parent = CreateWindowExA(0, WC_STATICA, "parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100,
diff --git a/dlls/comctl32/theming.c b/dlls/comctl32/theming.c
index ed7bb0a5b33..8078e661b76 100644
--- a/dlls/comctl32/theming.c
+++ b/dlls/comctl32/theming.c
@@ -26,7 +26,6 @@
#include "wingdi.h"
#include "winuser.h"
#include "comctl32.h"
-#include "uxtheme.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(theming);
@@ -96,8 +95,6 @@ void THEMING_Initialize (void)
{
unsigned int i;
- if (!IsThemeActive()) return;
-
atSubclassProp = GlobalAddAtomW (L"CC32ThemingSubCl");
atRefDataProp = GlobalAddAtomW (L"CC32ThemingData");
--
2.30.2
1
0
[PATCH 2/5] comctl32: Repaint after the WM_THEMECHANGED message is received.
by Zhiyi Zhang 26 Apr '21
by Zhiyi Zhang 26 Apr '21
26 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/button.c | 1 +
dlls/comctl32/combo.c | 1 +
dlls/comctl32/datetime.c | 1 +
dlls/comctl32/edit.c | 1 +
dlls/comctl32/header.c | 2 +-
dlls/comctl32/ipaddress.c | 1 +
dlls/comctl32/listbox.c | 1 +
dlls/comctl32/listview.c | 1 +
dlls/comctl32/monthcal.c | 1 +
dlls/comctl32/pager.c | 9 +++++++++
dlls/comctl32/progress.c | 2 +-
dlls/comctl32/static.c | 4 ++++
dlls/comctl32/status.c | 1 +
dlls/comctl32/tab.c | 1 +
dlls/comctl32/tests/misc.c | 36 ++++++++++++++++-----------------
dlls/comctl32/theme_scrollbar.c | 1 +
dlls/comctl32/toolbar.c | 1 +
dlls/comctl32/trackbar.c | 1 +
dlls/comctl32/treeview.c | 1 +
dlls/comctl32/updown.c | 2 +-
20 files changed, 48 insertions(+), 21 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index b5a9ee7f7f6..d3dcc67b169 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -534,6 +534,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
theme = GetWindowTheme( hWnd );
CloseThemeData( theme );
OpenThemeData( hWnd, WC_BUTTONW );
+ InvalidateRect( hWnd, NULL, TRUE );
break;
case WM_ERASEBKGND:
diff --git a/dlls/comctl32/combo.c b/dlls/comctl32/combo.c
index 887587a053b..074f54f0937 100644
--- a/dlls/comctl32/combo.c
+++ b/dlls/comctl32/combo.c
@@ -1698,6 +1698,7 @@ static LRESULT CALLBACK COMBO_WindowProc( HWND hwnd, UINT message, WPARAM wParam
theme = GetWindowTheme( hwnd );
CloseThemeData( theme );
OpenThemeData( hwnd, WC_COMBOBOXW );
+ InvalidateRect( hwnd, NULL, TRUE );
break;
case WM_PRINTCLIENT:
diff --git a/dlls/comctl32/datetime.c b/dlls/comctl32/datetime.c
index 93bca8c2f5c..ac5268f146c 100644
--- a/dlls/comctl32/datetime.c
+++ b/dlls/comctl32/datetime.c
@@ -1544,6 +1544,7 @@ static LRESULT DATETIME_ThemeChanged (DATETIME_INFO *infoPtr)
theme = GetWindowTheme(infoPtr->hwndSelf);
CloseThemeData(theme);
OpenThemeData(infoPtr->hwndSelf, themeClass);
+ InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/edit.c b/dlls/comctl32/edit.c
index 639443bc338..d9354a107b1 100644
--- a/dlls/comctl32/edit.c
+++ b/dlls/comctl32/edit.c
@@ -5097,6 +5097,7 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
case WM_THEMECHANGED:
CloseThemeData(GetWindowTheme(hwnd));
OpenThemeData(hwnd, WC_EDITW);
+ InvalidateRect(hwnd, NULL, TRUE);
break;
default:
diff --git a/dlls/comctl32/header.c b/dlls/comctl32/header.c
index 085549fed65..8bb39261dd1 100644
--- a/dlls/comctl32/header.c
+++ b/dlls/comctl32/header.c
@@ -2110,7 +2110,7 @@ static LRESULT HEADER_ThemeChanged(const HEADER_INFO *infoPtr)
HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
CloseThemeData(theme);
OpenThemeData(infoPtr->hwndSelf, themeClass);
- InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+ InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/ipaddress.c b/dlls/comctl32/ipaddress.c
index b6302a89ba6..f24fb4a9335 100644
--- a/dlls/comctl32/ipaddress.c
+++ b/dlls/comctl32/ipaddress.c
@@ -462,6 +462,7 @@ static LRESULT IPADDRESS_ThemeChanged (const IPADDRESS_INFO *infoPtr)
HTHEME theme = GetWindowTheme (infoPtr->Self);
CloseThemeData (theme);
theme = OpenThemeData (theme, WC_EDITW);
+ InvalidateRect (infoPtr->Self, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index 239f54aafab..f9283f45282 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -3136,6 +3136,7 @@ static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg, WPARAM wParam,
theme = GetWindowTheme( hwnd );
CloseThemeData( theme );
OpenThemeData( hwnd, WC_LISTBOXW );
+ InvalidateRect( hwnd, NULL, TRUE );
break;
default:
diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index 799ec509f33..05a772ab175 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -9345,6 +9345,7 @@ static LRESULT LISTVIEW_ThemeChanged(const LISTVIEW_INFO *infoPtr)
HTHEME theme = GetWindowTheme(infoPtr->hwndSelf);
CloseThemeData(theme);
OpenThemeData(infoPtr->hwndSelf, themeClass);
+ InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c
index 98c682df334..c0bec07f477 100644
--- a/dlls/comctl32/monthcal.c
+++ b/dlls/comctl32/monthcal.c
@@ -2697,6 +2697,7 @@ static LRESULT theme_changed (const MONTHCAL_INFO* infoPtr)
HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
CloseThemeData (theme);
OpenThemeData (infoPtr->hwndSelf, themeClass);
+ InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c
index 4763ed5640d..b8baa93e15f 100644
--- a/dlls/comctl32/pager.c
+++ b/dlls/comctl32/pager.c
@@ -966,6 +966,12 @@ PAGER_Timer (PAGER_INFO* infoPtr, INT nTimerId)
return 0;
}
+static LRESULT PAGER_ThemeChanged (const PAGER_INFO* infoPtr)
+{
+ InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
+ return 0;
+}
+
static LRESULT
PAGER_EraseBackground (const PAGER_INFO* infoPtr, HDC hdc)
{
@@ -1553,6 +1559,9 @@ PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_COMMAND:
return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam);
+ case WM_THEMECHANGED:
+ return PAGER_ThemeChanged (infoPtr);
+
default:
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
}
diff --git a/dlls/comctl32/progress.c b/dlls/comctl32/progress.c
index 5cf2ccda20f..fb4c2dc66dd 100644
--- a/dlls/comctl32/progress.c
+++ b/dlls/comctl32/progress.c
@@ -615,7 +615,7 @@ static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
dwExStyle |= WS_EX_STATICEDGE;
SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
- InvalidateRect (hwnd, NULL, FALSE);
+ InvalidateRect (hwnd, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/static.c b/dlls/comctl32/static.c
index b3254e5761b..2bd2b22bc20 100644
--- a/dlls/comctl32/static.c
+++ b/dlls/comctl32/static.c
@@ -505,6 +505,10 @@ static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam,
STATIC_TryPaintFcn( hwnd, full_style );
break;
+ case WM_THEMECHANGED:
+ InvalidateRect( hwnd, 0, TRUE );
+ break;
+
case WM_NCCREATE:
{
CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
diff --git a/dlls/comctl32/status.c b/dlls/comctl32/status.c
index 0c3a90887c8..7bc9ec4386f 100644
--- a/dlls/comctl32/status.c
+++ b/dlls/comctl32/status.c
@@ -1111,6 +1111,7 @@ static LRESULT theme_changed (const STATUS_INFO* infoPtr)
HTHEME theme = GetWindowTheme (infoPtr->Self);
CloseThemeData (theme);
OpenThemeData (infoPtr->Self, themeClass);
+ InvalidateRect (infoPtr->Self, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/tab.c b/dlls/comctl32/tab.c
index 3bb5310d1f3..017719a183d 100644
--- a/dlls/comctl32/tab.c
+++ b/dlls/comctl32/tab.c
@@ -3106,6 +3106,7 @@ static LRESULT theme_changed(const TAB_INFO *infoPtr)
HTHEME theme = GetWindowTheme (infoPtr->hwnd);
CloseThemeData (theme);
OpenThemeData (infoPtr->hwnd, themeClass);
+ InvalidateRect (infoPtr->hwnd, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
index f4fcb300bb2..4b0c1f9a4d0 100644
--- a/dlls/comctl32/tests/misc.c
+++ b/dlls/comctl32/tests/misc.c
@@ -556,30 +556,30 @@ static void test_WM_THEMECHANGED(void)
static const struct wm_themechanged_test tests[] =
{
{ANIMATE_CLASSA, wm_themechanged_no_paint_seq},
- {WC_BUTTONA, wm_themechanged_paint_erase_seq, 2, {WM_GETTEXT, WM_GETTEXTLENGTH}, TRUE},
- {WC_COMBOBOXA, wm_themechanged_paint_erase_seq, 1, {WM_CTLCOLOREDIT}, TRUE},
+ {WC_BUTTONA, wm_themechanged_paint_erase_seq, 2, {WM_GETTEXT, WM_GETTEXTLENGTH}},
+ {WC_COMBOBOXA, wm_themechanged_paint_erase_seq, 1, {WM_CTLCOLOREDIT}},
{WC_COMBOBOXEXA, wm_themechanged_no_paint_seq},
- {DATETIMEPICK_CLASSA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
- {WC_EDITA, wm_themechanged_paint_erase_seq, 7, {WM_GETTEXTLENGTH, WM_GETFONT, EM_GETSEL, EM_GETRECT, EM_CHARFROMPOS, EM_LINEFROMCHAR, EM_POSFROMCHAR}, TRUE},
- {WC_HEADERA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {DATETIMEPICK_CLASSA, wm_themechanged_paint_erase_seq},
+ {WC_EDITA, wm_themechanged_paint_erase_seq, 7, {WM_GETTEXTLENGTH, WM_GETFONT, EM_GETSEL, EM_GETRECT, EM_CHARFROMPOS, EM_LINEFROMCHAR, EM_POSFROMCHAR}},
+ {WC_HEADERA, wm_themechanged_paint_erase_seq},
{HOTKEY_CLASSA, wm_themechanged_no_paint_seq},
- {WC_IPADDRESSA, wm_themechanged_paint_erase_seq, 1, {WM_CTLCOLOREDIT}, TRUE},
- {WC_LISTBOXA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
- {WC_LISTVIEWA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
- {MONTHCAL_CLASSA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {WC_IPADDRESSA, wm_themechanged_paint_erase_seq, 1, {WM_CTLCOLOREDIT}},
+ {WC_LISTBOXA, wm_themechanged_paint_erase_seq},
+ {WC_LISTVIEWA, wm_themechanged_paint_erase_seq},
+ {MONTHCAL_CLASSA, wm_themechanged_paint_erase_seq},
{WC_NATIVEFONTCTLA, wm_themechanged_no_paint_seq},
- {WC_PAGESCROLLERA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
- {PROGRESS_CLASSA, wm_themechanged_paint_erase_seq, 3, {WM_STYLECHANGING, WM_STYLECHANGED, WM_NCPAINT}, TRUE},
+ {WC_PAGESCROLLERA, wm_themechanged_paint_erase_seq},
+ {PROGRESS_CLASSA, wm_themechanged_paint_erase_seq, 3, {WM_STYLECHANGING, WM_STYLECHANGED, WM_NCPAINT}},
{REBARCLASSNAMEA, wm_themechanged_no_paint_seq, 1, {WM_WINDOWPOSCHANGING}},
- {WC_STATICA, wm_themechanged_paint_erase_seq, 2, {WM_GETTEXT, WM_GETTEXTLENGTH}, TRUE},
- {STATUSCLASSNAMEA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {WC_STATICA, wm_themechanged_paint_erase_seq, 2, {WM_GETTEXT, WM_GETTEXTLENGTH}},
+ {STATUSCLASSNAMEA, wm_themechanged_paint_erase_seq},
{"SysLink", wm_themechanged_no_paint_seq},
- {WC_TABCONTROLA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
- {TOOLBARCLASSNAMEA, wm_themechanged_paint_erase_seq, 1, {WM_WINDOWPOSCHANGING}, TRUE},
+ {WC_TABCONTROLA, wm_themechanged_paint_erase_seq},
+ {TOOLBARCLASSNAMEA, wm_themechanged_paint_erase_seq, 1, {WM_WINDOWPOSCHANGING}},
{TOOLTIPS_CLASSA, wm_themechanged_no_paint_seq},
- {TRACKBAR_CLASSA, wm_themechanged_paint_seq, 0, {0}, TRUE},
- {WC_TREEVIEWA, wm_themechanged_paint_erase_seq, 1, {0x1128}, TRUE},
- {UPDOWN_CLASSA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {TRACKBAR_CLASSA, wm_themechanged_paint_seq},
+ {WC_TREEVIEWA, wm_themechanged_paint_erase_seq, 1, {0x1128}},
+ {UPDOWN_CLASSA, wm_themechanged_paint_erase_seq},
{WC_SCROLLBARA, wm_themechanged_paint_erase_seq, 1, {SBM_GETSCROLLINFO}, TRUE},
};
diff --git a/dlls/comctl32/theme_scrollbar.c b/dlls/comctl32/theme_scrollbar.c
index 27d31bd4ac5..304ff5bacbc 100644
--- a/dlls/comctl32/theme_scrollbar.c
+++ b/dlls/comctl32/theme_scrollbar.c
@@ -547,6 +547,7 @@ LRESULT CALLBACK THEMING_ScrollbarSubclassProc (HWND hwnd, UINT msg,
theme = GetWindowTheme(hwnd);
CloseThemeData(theme);
OpenThemeData(hwnd, themeClass);
+ InvalidateRect(hwnd, NULL, TRUE);
break;
case WM_SYSCOLORCHANGE:
diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c
index 667a2f4c277..1aeb499c45f 100644
--- a/dlls/comctl32/toolbar.c
+++ b/dlls/comctl32/toolbar.c
@@ -6556,6 +6556,7 @@ static LRESULT theme_changed (HWND hwnd)
HTHEME theme = GetWindowTheme (hwnd);
CloseThemeData (theme);
OpenThemeData (hwnd, themeClass);
+ InvalidateRect (hwnd, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/trackbar.c b/dlls/comctl32/trackbar.c
index 66522fd8582..1859cf0f516 100644
--- a/dlls/comctl32/trackbar.c
+++ b/dlls/comctl32/trackbar.c
@@ -1720,6 +1720,7 @@ static LRESULT theme_changed (const TRACKBAR_INFO* infoPtr)
HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
CloseThemeData (theme);
OpenThemeData (infoPtr->hwndSelf, themeClass);
+ InvalidateRect (infoPtr->hwndSelf, NULL, FALSE);
return 0;
}
diff --git a/dlls/comctl32/treeview.c b/dlls/comctl32/treeview.c
index a45096d8239..98cf5489f2b 100644
--- a/dlls/comctl32/treeview.c
+++ b/dlls/comctl32/treeview.c
@@ -5633,6 +5633,7 @@ static LRESULT TREEVIEW_ThemeChanged(const TREEVIEW_INFO *infoPtr)
HTHEME theme = GetWindowTheme (infoPtr->hwnd);
CloseThemeData (theme);
OpenThemeData (infoPtr->hwnd, themeClass);
+ InvalidateRect (infoPtr->hwnd, NULL, TRUE);
return 0;
}
diff --git a/dlls/comctl32/updown.c b/dlls/comctl32/updown.c
index a804018d5f8..d5625839db3 100644
--- a/dlls/comctl32/updown.c
+++ b/dlls/comctl32/updown.c
@@ -966,7 +966,7 @@ static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, L
theme = GetWindowTheme (hwnd);
CloseThemeData (theme);
OpenThemeData (hwnd, L"Spin");
- InvalidateRect (hwnd, NULL, FALSE);
+ InvalidateRect (hwnd, NULL, TRUE);
break;
case WM_TIMER:
--
2.30.2
1
0
[PATCH 1/5] comctl32/tests: Test that WM_THEMECHANGED should invalidate client area.
by Zhiyi Zhang 26 Apr '21
by Zhiyi Zhang 26 Apr '21
26 Apr '21
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/tests/misc.c | 206 ++++++++++++++++++++++++++++++++++++-
1 file changed, 205 insertions(+), 1 deletion(-)
diff --git a/dlls/comctl32/tests/misc.c b/dlls/comctl32/tests/misc.c
index a3ba2028873..f4fcb300bb2 100644
--- a/dlls/comctl32/tests/misc.c
+++ b/dlls/comctl32/tests/misc.c
@@ -24,6 +24,7 @@
#include "wine/test.h"
#include "v6util.h"
+#include "msg.h"
static PVOID (WINAPI * pAlloc)(LONG);
static PVOID (WINAPI * pReAlloc)(PVOID, LONG);
@@ -35,8 +36,21 @@ static BOOL (WINAPI * pStr_SetPtrA)(LPSTR, LPCSTR);
static INT (WINAPI * pStr_GetPtrW)(LPCWSTR, LPWSTR, INT);
static BOOL (WINAPI * pStr_SetPtrW)(LPWSTR, LPCWSTR);
+static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
+static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
+
static HMODULE hComctl32 = 0;
+/* For message tests */
+enum seq_index
+{
+ CHILD_SEQ_INDEX,
+ NUM_MSG_SEQUENCES
+};
+
+static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
+
static char testicon_data[] =
{
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x00,
@@ -79,6 +93,40 @@ static BOOL InitFunctionPtrs(void)
return TRUE;
}
+static BOOL init_functions_v6(void)
+{
+ hComctl32 = LoadLibraryA("comctl32.dll");
+ if (!hComctl32)
+ {
+ trace("Could not load comctl32.dll version 6\n");
+ return FALSE;
+ }
+
+ COMCTL32_GET_PROC(410, SetWindowSubclass)
+ COMCTL32_GET_PROC(412, RemoveWindowSubclass)
+ COMCTL32_GET_PROC(413, DefSubclassProc)
+
+ return TRUE;
+}
+
+/* try to make sure pending X events have been processed before continuing */
+static void flush_events(void)
+{
+ MSG msg;
+ int diff = 200;
+ int min_timeout = 100;
+ DWORD time = GetTickCount() + diff;
+
+ while (diff > 0)
+ {
+ if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT)
+ break;
+ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+ DispatchMessageA(&msg);
+ diff = time - GetTickCount();
+ }
+}
+
static void test_GetPtrAW(void)
{
if (pStr_GetPtrA)
@@ -406,6 +454,156 @@ static void test_comctl32_classes(BOOL v6)
check_class("SysLink", v6, CS_GLOBALCLASS, 0, FALSE);
}
+struct wm_themechanged_test
+{
+ const char *class;
+ const struct message *expected_msg;
+ int ignored_msg_count;
+ DWORD ignored_msgs[16];
+ BOOL todo;
+};
+
+static BOOL ignore_message(UINT msg)
+{
+ /* these are always ignored */
+ return (msg >= 0xc000 ||
+ msg == WM_GETICON ||
+ msg == WM_GETOBJECT ||
+ msg == WM_TIMECHANGE ||
+ msg == WM_DISPLAYCHANGE ||
+ msg == WM_DEVICECHANGE ||
+ msg == WM_DWMNCRENDERINGCHANGED ||
+ msg == WM_WININICHANGE ||
+ msg == WM_CHILDACTIVATE);
+}
+
+static LRESULT CALLBACK test_wm_themechanged_proc(HWND hwnd, UINT message, WPARAM wParam,
+ LPARAM lParam, UINT_PTR id, DWORD_PTR ref_data)
+{
+ const struct wm_themechanged_test *test = (const struct wm_themechanged_test *)ref_data;
+ static int defwndproc_counter = 0;
+ struct message msg = {0};
+ LRESULT ret;
+ int i;
+
+ if (ignore_message(message))
+ return pDefSubclassProc(hwnd, message, wParam, lParam);
+
+ /* Extra messages to be ignored for a test case */
+ for (i = 0; i < test->ignored_msg_count; ++i)
+ {
+ if (message == test->ignored_msgs[i])
+ return pDefSubclassProc(hwnd, message, wParam, lParam);
+ }
+
+ msg.message = message;
+ msg.flags = sent | wparam | lparam;
+ if (defwndproc_counter)
+ msg.flags |= defwinproc;
+ msg.wParam = wParam;
+ msg.lParam = lParam;
+ add_message(sequences, CHILD_SEQ_INDEX, &msg);
+
+ if (message == WM_NCDESTROY)
+ pRemoveWindowSubclass(hwnd, test_wm_themechanged_proc, 0);
+
+ ++defwndproc_counter;
+ ret = pDefSubclassProc(hwnd, message, wParam, lParam);
+ --defwndproc_counter;
+
+ return ret;
+}
+
+static HWND create_control(const char *class, DWORD style, HWND parent, DWORD_PTR data)
+{
+ HWND hwnd;
+
+ if (parent)
+ style |= WS_CHILD;
+ hwnd = CreateWindowExA(0, class, "test", style, 0, 0, 50, 20, parent, 0, 0, NULL);
+ ok(!!hwnd, "Failed to create %s style %#x parent %p\n", class, style, parent);
+ pSetWindowSubclass(hwnd, test_wm_themechanged_proc, 0, data);
+ return hwnd;
+}
+
+static const struct message wm_themechanged_paint_erase_seq[] =
+{
+ {WM_THEMECHANGED, sent | wparam | lparam},
+ {WM_PAINT, sent | wparam | lparam},
+ {WM_ERASEBKGND, sent | defwinproc},
+ {0},
+};
+
+static const struct message wm_themechanged_paint_seq[] =
+{
+ {WM_THEMECHANGED, sent | wparam | lparam},
+ {WM_PAINT, sent | wparam | lparam},
+ {0},
+};
+
+static const struct message wm_themechanged_no_paint_seq[] =
+{
+ {WM_THEMECHANGED, sent | wparam | lparam},
+ {0},
+};
+
+static void test_WM_THEMECHANGED(void)
+{
+ HWND parent, child;
+ char buffer[64];
+ int i;
+
+ static const struct wm_themechanged_test tests[] =
+ {
+ {ANIMATE_CLASSA, wm_themechanged_no_paint_seq},
+ {WC_BUTTONA, wm_themechanged_paint_erase_seq, 2, {WM_GETTEXT, WM_GETTEXTLENGTH}, TRUE},
+ {WC_COMBOBOXA, wm_themechanged_paint_erase_seq, 1, {WM_CTLCOLOREDIT}, TRUE},
+ {WC_COMBOBOXEXA, wm_themechanged_no_paint_seq},
+ {DATETIMEPICK_CLASSA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {WC_EDITA, wm_themechanged_paint_erase_seq, 7, {WM_GETTEXTLENGTH, WM_GETFONT, EM_GETSEL, EM_GETRECT, EM_CHARFROMPOS, EM_LINEFROMCHAR, EM_POSFROMCHAR}, TRUE},
+ {WC_HEADERA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {HOTKEY_CLASSA, wm_themechanged_no_paint_seq},
+ {WC_IPADDRESSA, wm_themechanged_paint_erase_seq, 1, {WM_CTLCOLOREDIT}, TRUE},
+ {WC_LISTBOXA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {WC_LISTVIEWA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {MONTHCAL_CLASSA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {WC_NATIVEFONTCTLA, wm_themechanged_no_paint_seq},
+ {WC_PAGESCROLLERA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {PROGRESS_CLASSA, wm_themechanged_paint_erase_seq, 3, {WM_STYLECHANGING, WM_STYLECHANGED, WM_NCPAINT}, TRUE},
+ {REBARCLASSNAMEA, wm_themechanged_no_paint_seq, 1, {WM_WINDOWPOSCHANGING}},
+ {WC_STATICA, wm_themechanged_paint_erase_seq, 2, {WM_GETTEXT, WM_GETTEXTLENGTH}, TRUE},
+ {STATUSCLASSNAMEA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {"SysLink", wm_themechanged_no_paint_seq},
+ {WC_TABCONTROLA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {TOOLBARCLASSNAMEA, wm_themechanged_paint_erase_seq, 1, {WM_WINDOWPOSCHANGING}, TRUE},
+ {TOOLTIPS_CLASSA, wm_themechanged_no_paint_seq},
+ {TRACKBAR_CLASSA, wm_themechanged_paint_seq, 0, {0}, TRUE},
+ {WC_TREEVIEWA, wm_themechanged_paint_erase_seq, 1, {0x1128}, TRUE},
+ {UPDOWN_CLASSA, wm_themechanged_paint_erase_seq, 0, {0}, TRUE},
+ {WC_SCROLLBARA, wm_themechanged_paint_erase_seq, 1, {SBM_GETSCROLLINFO}, TRUE},
+ };
+
+ parent = CreateWindowExA(0, WC_STATICA, "parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100,
+ 200, 200, 0, 0, 0, NULL);
+ ok(!!parent, "Failed to create parent window\n");
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ child = create_control(tests[i].class, WS_VISIBLE, parent, (DWORD_PTR)&tests[i]);
+ flush_events();
+ flush_sequences(sequences, NUM_MSG_SEQUENCES);
+
+ SendMessageW(child, WM_THEMECHANGED, 0, 0);
+ flush_events();
+
+ sprintf(buffer, "Test %d class %s WM_THEMECHANGED", i, tests[i].class);
+ ok_sequence(sequences, CHILD_SEQ_INDEX, tests[i].expected_msg, buffer, tests[i].todo);
+ DestroyWindow(child);
+ }
+
+ DestroyWindow(parent);
+}
+
START_TEST(misc)
{
ULONG_PTR ctx_cookie;
@@ -416,15 +614,21 @@ START_TEST(misc)
test_GetPtrAW();
test_Alloc();
-
test_comctl32_classes(FALSE);
+ FreeLibrary(hComctl32);
+
if (!load_v6_module(&ctx_cookie, &hCtx))
return;
+ if(!init_functions_v6())
+ return;
+ init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
test_comctl32_classes(TRUE);
test_builtin_classes();
test_LoadIconWithScaleDown();
+ test_WM_THEMECHANGED();
unload_v6_module(ctx_cookie, hCtx);
+ FreeLibrary(hComctl32);
}
--
2.30.2
1
0
26 Apr '21
This lets programs know tracing is not available.
Signed-off-by: David Koolhoven <david(a)koolhoven-home.net>
---
dlls/sechost/trace.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/sechost/trace.c b/dlls/sechost/trace.c
index 01733690ac8..8f8c316a353 100644
--- a/dlls/sechost/trace.c
+++ b/dlls/sechost/trace.c
@@ -37,7 +37,7 @@ ULONG WINAPI ControlTraceA( TRACEHANDLE handle, const char *session,
EVENT_TRACE_PROPERTIES *properties, ULONG control )
{
FIXME("(%s, %s, %p, %d) stub\n", wine_dbgstr_longlong(handle), debugstr_a(session), properties, control);
- return ERROR_SUCCESS;
+ return ERROR_WMI_INSTANCE_NOT_FOUND;
}
/******************************************************************************
@@ -47,7 +47,7 @@ ULONG WINAPI ControlTraceW( TRACEHANDLE handle, const WCHAR *session,
EVENT_TRACE_PROPERTIES *properties, ULONG control )
{
FIXME("(%s, %s, %p, %d) stub\n", wine_dbgstr_longlong(handle), debugstr_w(session), properties, control);
- return ERROR_SUCCESS;
+ return ERROR_WMI_INSTANCE_NOT_FOUND;
}
/******************************************************************************
--
2.19.1
2
4
26 Apr '21
Implements StorageDeviceSeekPenaltyProperty for
query_propery()
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51065
Signed-off-by: David Koolhoven <david(a)koolhoven-home.net>
---
dlls/mountmgr.sys/device.c | 120 ++++++++++++++++++++++++++++++++++++-
include/ntddstor.h | 9 ++-
2 files changed, 126 insertions(+), 3 deletions(-)
diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index 04e8fe3c0f5..d031080c459 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -28,6 +28,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
+#ifdef linux
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
@@ -1867,8 +1871,6 @@ static NTSTATUS query_property( struct disk_device *device, IRP *irp )
}
else
{
- FIXME( "Faking StorageDeviceProperty data\n" );
-
memset( irp->AssociatedIrp.SystemBuffer, 0, irpsp->Parameters.DeviceIoControl.OutputBufferLength );
descriptor = irp->AssociatedIrp.SystemBuffer;
descriptor->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
@@ -1894,6 +1896,120 @@ static NTSTATUS query_property( struct disk_device *device, IRP *irp )
break;
}
+ case StorageDeviceSeekPenaltyProperty:
+ {
+#ifdef linux
+ FILE *fp;
+ char isrotapathstr[260];
+ char evpath[260];
+ char ueventbufstr[260];
+ char isrotastrbuf[2];
+ char *fgetsret = NULL;
+ int ret = 0;
+ char *rptr = NULL;
+ char *sptr = NULL;
+ char *devstr_edited = NULL;
+ char *mountstr = NULL;
+ char mountpath[260];
+ char *part_dev = NULL;
+ char *path, *p = NULL;
+ int c = 0;
+ struct stat statbuf;
+ DEVICE_SEEK_PENALTY_DESCRIPTOR *descriptor;
+
+ memset( irp->AssociatedIrp.SystemBuffer, 0, irpsp->Parameters.DeviceIoControl.OutputBufferLength );
+ descriptor = irp->AssociatedIrp.SystemBuffer;
+ descriptor->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
+ descriptor->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
+
+ if (!device->unix_mount) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ if (!(path = get_dosdevices_path( &p ))) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ /* Crop any drive letters off the end of the string */
+ if (!strncmp(&path[strlen(path) - 2], "::", 2)) {
+ path[strlen(path) - 3] = '\0';
+ }
+
+ snprintf (mountpath, 260, "%s%s", path, device->unix_mount);
+ ret = stat (mountpath, &statbuf);
+ if (ret == -1) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+ HeapFree( GetProcessHeap(), 0, path );
+ sprintf (evpath, "/sys/dev/block/%d:%d/uevent", major(statbuf.st_dev), minor(statbuf.st_dev));
+ fp = fopen(evpath, "r");
+ if (!fp) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+ while ((rptr = fgets (ueventbufstr, 260, fp))) {
+ sptr = strstr (rptr, "DEVNAME=");
+ if (sptr) {
+ sptr += strlen ("DEVNAME=");
+ break;
+ }
+ }
+ fclose (fp);
+ devstr_edited = sptr;
+ if (!devstr_edited) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+ /* Find first character after forwardslash '/' */
+ part_dev = strrchr (devstr_edited, '/');
+ if (!part_dev || (part_dev == devstr_edited)) part_dev = devstr_edited;
+ else part_dev++;
+ /* Trim off trailing digits and whitespace */
+ c = strlen (devstr_edited);
+ c--;
+ while ((devstr_edited[c] >= '0' && devstr_edited[c] <= '9')
+ || (devstr_edited[c] == '\n' || devstr_edited[c] == '\r'))
+ devstr_edited[c--] = '\0';
+
+ ret = snprintf (isrotapathstr, 260, "/sys/block/%s/queue/rotational", part_dev);
+ if (ret < 1 || ret == 260) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ fp = fopen(isrotapathstr, "r");
+ if (!fp) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ fgetsret = fgets(isrotastrbuf, 2, fp);
+ if (!fgetsret) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ fclose (fp);
+
+ if (isrotastrbuf[0] == '1') {
+ descriptor->IncursSeekPenalty = TRUE;
+ } else if (isrotastrbuf[0] == '0') {
+ descriptor->IncursSeekPenalty = FALSE;
+ } else {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ status = STATUS_SUCCESS;
+#else
+ FIXME( "Unsupported property StorageDeviceSeekPenalty\n" );
+ status = STATUS_NOT_SUPPORTED;
+#endif
+ break;
+ }
default:
FIXME( "Unsupported property %#x\n", query->PropertyId );
status = STATUS_NOT_SUPPORTED;
diff --git a/include/ntddstor.h b/include/ntddstor.h
index b8c4bb73b0d..836def413fe 100644
--- a/include/ntddstor.h
+++ b/include/ntddstor.h
@@ -214,7 +214,8 @@ typedef enum _STORAGE_QUERY_TYPE {
typedef enum _STORAGE_PROPERTY_ID {
StorageDeviceProperty = 0,
- StorageAdapterProperty
+ StorageAdapterProperty = 1,
+ StorageDeviceSeekPenaltyProperty = 7,
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
typedef struct _STORAGE_PROPERTY_QUERY {
@@ -272,6 +273,12 @@ typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
USHORT BusMinorVersion;
} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
+typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR {
+ ULONG Version;
+ ULONG Size;
+ BOOLEAN IncursSeekPenalty;
+} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR;
+
#ifdef __cplusplus
}
#endif
--
2.19.1
1
0
26 Apr '21
Implements StorageDeviceSeekPenaltyProperty for
query_propery()
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51065
Signed-off-by: David Koolhoven <david(a)koolhoven-home.net>
---
dlls/mountmgr.sys/device.c | 120 ++++++++++++++++++++++++++++++++++++-
include/ntddstor.h | 9 ++-
2 files changed, 126 insertions(+), 3 deletions(-)
diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c
index 04e8fe3c0f5..d031080c459 100644
--- a/dlls/mountmgr.sys/device.c
+++ b/dlls/mountmgr.sys/device.c
@@ -28,6 +28,10 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
+#ifdef linux
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
@@ -1867,8 +1871,6 @@ static NTSTATUS query_property( struct disk_device *device, IRP *irp )
}
else
{
- FIXME( "Faking StorageDeviceProperty data\n" );
-
memset( irp->AssociatedIrp.SystemBuffer, 0, irpsp->Parameters.DeviceIoControl.OutputBufferLength );
descriptor = irp->AssociatedIrp.SystemBuffer;
descriptor->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
@@ -1894,6 +1896,120 @@ static NTSTATUS query_property( struct disk_device *device, IRP *irp )
break;
}
+ case StorageDeviceSeekPenaltyProperty:
+ {
+#ifdef linux
+ FILE *fp;
+ char isrotapathstr[260];
+ char evpath[260];
+ char ueventbufstr[260];
+ char isrotastrbuf[2];
+ char *fgetsret = NULL;
+ int ret = 0;
+ char *rptr = NULL;
+ char *sptr = NULL;
+ char *devstr_edited = NULL;
+ char *mountstr = NULL;
+ char mountpath[260];
+ char *part_dev = NULL;
+ char *path, *p = NULL;
+ int c = 0;
+ struct stat statbuf;
+ DEVICE_SEEK_PENALTY_DESCRIPTOR *descriptor;
+
+ memset( irp->AssociatedIrp.SystemBuffer, 0, irpsp->Parameters.DeviceIoControl.OutputBufferLength );
+ descriptor = irp->AssociatedIrp.SystemBuffer;
+ descriptor->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
+ descriptor->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
+
+ if (!device->unix_mount) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ if (!(path = get_dosdevices_path( &p ))) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ /* Crop any drive letters off the end of the string */
+ if (!strncmp(&path[strlen(path) - 2], "::", 2)) {
+ path[strlen(path) - 3] = '\0';
+ }
+
+ snprintf (mountpath, 260, "%s%s", path, device->unix_mount);
+ ret = stat (mountpath, &statbuf);
+ if (ret == -1) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+ HeapFree( GetProcessHeap(), 0, path );
+ sprintf (evpath, "/sys/dev/block/%d:%d/uevent", major(statbuf.st_dev), minor(statbuf.st_dev));
+ fp = fopen(evpath, "r");
+ if (!fp) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+ while ((rptr = fgets (ueventbufstr, 260, fp))) {
+ sptr = strstr (rptr, "DEVNAME=");
+ if (sptr) {
+ sptr += strlen ("DEVNAME=");
+ break;
+ }
+ }
+ fclose (fp);
+ devstr_edited = sptr;
+ if (!devstr_edited) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+ /* Find first character after forwardslash '/' */
+ part_dev = strrchr (devstr_edited, '/');
+ if (!part_dev || (part_dev == devstr_edited)) part_dev = devstr_edited;
+ else part_dev++;
+ /* Trim off trailing digits and whitespace */
+ c = strlen (devstr_edited);
+ c--;
+ while ((devstr_edited[c] >= '0' && devstr_edited[c] <= '9')
+ || (devstr_edited[c] == '\n' || devstr_edited[c] == '\r'))
+ devstr_edited[c--] = '\0';
+
+ ret = snprintf (isrotapathstr, 260, "/sys/block/%s/queue/rotational", part_dev);
+ if (ret < 1 || ret == 260) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ fp = fopen(isrotapathstr, "r");
+ if (!fp) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ fgetsret = fgets(isrotastrbuf, 2, fp);
+ if (!fgetsret) {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ fclose (fp);
+
+ if (isrotastrbuf[0] == '1') {
+ descriptor->IncursSeekPenalty = TRUE;
+ } else if (isrotastrbuf[0] == '0') {
+ descriptor->IncursSeekPenalty = FALSE;
+ } else {
+ status = STATUS_DATA_ERROR;
+ break;
+ }
+
+ status = STATUS_SUCCESS;
+#else
+ FIXME( "Unsupported property StorageDeviceSeekPenalty\n" );
+ status = STATUS_NOT_SUPPORTED;
+#endif
+ break;
+ }
default:
FIXME( "Unsupported property %#x\n", query->PropertyId );
status = STATUS_NOT_SUPPORTED;
diff --git a/include/ntddstor.h b/include/ntddstor.h
index b8c4bb73b0d..836def413fe 100644
--- a/include/ntddstor.h
+++ b/include/ntddstor.h
@@ -214,7 +214,8 @@ typedef enum _STORAGE_QUERY_TYPE {
typedef enum _STORAGE_PROPERTY_ID {
StorageDeviceProperty = 0,
- StorageAdapterProperty
+ StorageAdapterProperty = 1,
+ StorageDeviceSeekPenaltyProperty = 7,
} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
typedef struct _STORAGE_PROPERTY_QUERY {
@@ -272,6 +273,12 @@ typedef struct _STORAGE_ADAPTER_DESCRIPTOR {
USHORT BusMinorVersion;
} STORAGE_ADAPTER_DESCRIPTOR, *PSTORAGE_ADAPTER_DESCRIPTOR;
+typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR {
+ ULONG Version;
+ ULONG Size;
+ BOOLEAN IncursSeekPenalty;
+} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR;
+
#ifdef __cplusplus
}
#endif
--
2.19.1
1
1
This patch introduces no functional change, but makes some ugly code a little
prettier.
---
server/region.c | 1036 ++++++++++++++++-------------------------------
1 file changed, 339 insertions(+), 697 deletions(-)
diff --git a/server/region.c b/server/region.c
index 9f377ee05d3..ca5aba8cd63 100644
--- a/server/region.c
+++ b/server/region.c
@@ -72,709 +72,351 @@ SOFTWARE.
************************************************************************/
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
-#include "winternl.h"
-#include "request.h"
-#include "user.h"
-struct region
-{
- int size;
- int num_rects;
- rectangle_t *rects;
- rectangle_t extents;
-};
+#include <stdarg.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include "ntstatus.h"
+ #define WIN32_NO_STATUS
+ #include "winternl.h"
+ #include "request.h"
+ #include"user.h"
+ struct region
+ {int size;int
+ num_rects ;
+ rectangle_t
+ *rects; rectangle_t extents;};
+ # define RGN_DEFAULT_RECTS 2
+ # define EXTENTCHECK( \
+ r1 ,r2)((r1 )->right >\
+ (r2)->left &&(\
+ r1) ->left<(\
+ r2)->right\
+ &&(r1 )->bottom > (r2)\
+ ->top&&(r1 )->top<(r2) ->bottom)
+ typedef int(* overlap_func_t)( struct region
+ * reg, const rectangle_t*r1,const rectangle_t*
+ r1End, const rectangle_t*r2,const rectangle_t*
+ r2End ,int top ,int bottom ); typedef int(*
+ non_overlap_func_t )(struct region* reg ,const
+ rectangle_t* r,const rectangle_t* rEnd,int top
+ ,int bottom );static const rectangle_t
+ empty_rect; /*all-zero rectangle for empty
+ regions */ /*add a rectangle to a region
+ */ static inline rectangle_t *add_rect (
+ struct region * reg ){ if (reg-> num_rects >=
+ reg ->size ){ rectangle_t*new_rect =realloc(reg
+ -> rects , 2* sizeof(rectangle_t )*reg->size);
+ if(!new_rect) { set_error ( STATUS_NO_MEMORY
+ );return NULL;}reg->rects=new_rect;reg->size *= 2;
+ }return reg->rects +reg->num_rects++;}/*
+ make sure all the rectangles
+ are valid and that
+ the region is
+ properly y-x-
+ banded */static
+ inline int validate_rectangles (const
+ rectangle_t *rects,unsigned int nb_rects){
+ const rectangle_t*ptr,*end; for(ptr
+ =rects ,end=rects+nb_rects; ptr<end
+ ;ptr++ ){ if(is_rect_empty( ptr ))
+ return 0 ;/*empty rectangle*/ if(ptr==
+ end-1)break; if(ptr[0].top == ptr[1 ].top)/*same
+ band*/{if(ptr[0]. bottom!=ptr[1].bottom) return 0; /* not
+ same y extent*/if ( ptr[0].right >= ptr[1].left)return 0;/*not
+ properly x ordered*/}else/*new band*/{if(ptr[0].bottom>
+ ptr[1].top)return 0;/*not properly y ordered
+ */}}return 1;}/*attempt to merge
+ the rects in the current band with those in
+ the previous one. Used only by region_op. */ static int
+ coalesce_region(struct region*pReg,int prevStart,int curStart){
+ int curNumRects; rectangle_t*pRegEnd= & pReg->rects[pReg
+ ->num_rects]; rectangle_t*pPrevRect= &pReg->rects
+ [prevStart ];rectangle_t*pCurRect =&pReg->
+ rects[ curStart];int prevNumRects= curStart-
+prevStart ;int bandtop=pCurRect-> top;for(
+curNumRects =0;(pCurRect!=pRegEnd) &&(pCurRect
+ ->top==bandtop );curNumRects++){pCurRect ++;}if(pCurRect
+ !=pRegEnd){pRegEnd --;while(pRegEnd[-1].top == pRegEnd -> top)
+ pRegEnd--;curStart= pRegEnd-pReg->rects; pRegEnd=pReg->rects+
+ pReg->num_rects;}if((curNumRects==prevNumRects)&&(curNumRects
+ !=0)){pCurRect-=curNumRects;if (pPrevRect->bottom ==
+ pCurRect->top){ do{ if((pPrevRect->left !=
+ pCurRect->left) ||(pPrevRect->
+ right != pCurRect->right))return curStart;
+ pPrevRect++; pCurRect++; prevNumRects -= 1; } while(
+ prevNumRects != 0);pReg->num_rects -= curNumRects;pCurRect -=
+ curNumRects;pPrevRect -= curNumRects;do{ pPrevRect->bottom=
+ pCurRect->bottom; pPrevRect++;pCurRect ++; curNumRects-=
+ 1;} while ( curNumRects != 0);if ( pCurRect ==
+ pRegEnd) curStart= prevStart; else do{*
+pPrevRect ++ = *pCurRect++;} while (
+pCurRect !=pRegEnd);}} return curStart
+ ;}/*apply an operation to two regions */
+ /*check the GDI version of the code for
+ explanations */ static int region_op (struct region*
+ newReg,const struct region*reg1,const struct region *reg2,
+ overlap_func_t overlap_func,non_overlap_func_t
+ non_overlap1_func,non_overlap_func_t
+ non_overlap2_func){int ybot,ytop,top,bot,prevBand
+ ,curBand; const rectangle_t * r1BandEnd, *r2BandEnd; const
+ rectangle_t*r1= reg1->rects; const rectangle_t*r2=
+ reg2->rects ;const rectangle_t *r1End =r1+
+ reg1-> num_rects ;const rectangle_t
+ *r2End =r2+reg2->num_rects; rectangle_t*
+new_rects ,*old_rects=newReg ->rects;
+ int new_size ,ret=0;new_size=max( reg1->num_rects
+ ,reg2->num_rects )*2;if(!(new_rects= mem_alloc(new_size
+ *sizeof(*newReg ->rects)))) return 0;newReg->size=
+ new_size; newReg ->rects=new_rects; newReg->num_rects
+ =0;if(reg1->extents.top< reg2->extents.top)ybot=reg1->
+ extents.top;else ybot = reg2->extents.top;
+ prevBand=0;do{curBand=newReg->num_rects; r1BandEnd=r1;
+ while((r1BandEnd!=r1End) && (r1BandEnd->top==r1->top))
+ r1BandEnd++;r2BandEnd=r2;while((r2BandEnd != r2End)&&(
+ r2BandEnd->top == r2->top))r2BandEnd++;if(r1->top<r2->
+ top){top=max(r1->top,ybot);bot=min(r1->bottom,r2->top)
+ ;if(top!=bot&&non_overlap1_func){if(!non_overlap1_func
+ (newReg,r1,r1BandEnd,top,bot))goto done;}ytop=r2->top;
+ }else if(r2->top < r1->top){top=max(r2->top,ybot);bot=
+ min(r2->bottom,r1->top);if(top!=bot&&non_overlap2_func
+ ){if (!non_overlap2_func(newReg,r2,r2BandEnd,top,bot)) goto done;}
+ ytop=r1->top;}else{ytop=r1->top;}if (newReg->num_rects != curBand)
+ prevBand = coalesce_region(newReg,prevBand,curBand); ybot=min(r1->
+ bottom,r2->bottom); curBand = newReg->num_rects;if(ybot>ytop){if(!
+ overlap_func(newReg,r1,r1BandEnd,r2,r2BandEnd,ytop,ybot))goto done
+ ;}if(newReg->num_rects!=curBand)prevBand = coalesce_region(newReg,
+ prevBand,curBand);if(r1->bottom==ybot)r1=r1BandEnd;if(r2->bottom==
+ybot)r2=r2BandEnd;}while((r1!=r1End)&&(r2!=r2End));curBand=newReg->num_rects;if(
+r1 != r1End){if (non_overlap1_func){do{r1BandEnd=r1;while((r1BandEnd < r1End)&&(
+r1BandEnd->top==r1->top))r1BandEnd++;if (!non_overlap1_func(newReg,r1,r1BandEnd,
+max(r1->top,ybot),r1->bottom))goto done;r1=r1BandEnd;}while(r1!=r1End);}}else if
+((r2!=r2End) && non_overlap2_func){do{r2BandEnd=r2;while ((r2BandEnd < r2End)&&(
+r2BandEnd->top==r2->top))r2BandEnd++;if (!non_overlap2_func(newReg,r2,r2BandEnd,
+max(r2->top, ybot ),r2->bottom
+))goto done; r2=r2BandEnd;} while (r2!=r2End);
+}if(newReg-> num_rects!=curBand)coalesce_region ( newReg ,
+prevBand , curBand);if((newReg->num_rects<(newReg->size/ 2))&&(newReg
+->size >2)){ new_size=max(newReg->num_rects,RGN_DEFAULT_RECTS); if(new_rects
+= realloc( newReg->rects, sizeof (* newReg ->rects)* new_size )){
+newReg->rects=new_rects;newReg ->size=new_size;}}ret=1; done:
+free(old_rects);return ret; }/* recalculate the extents
+of a region */static void set_region_extents(struct
+region*region){rectangle_t *pRect,*pRectEnd;if(region
+->num_rects==0){region-> extents.left= 0;region->
+extents.top = 0;region-> extents.right=0;region->
+extents.bottom=0;return; }pRect = region-> rects;
+pRectEnd =&pRect[region-> num_rects - 1]; region->
+extents.left=pRect->left; region->extents.top=pRect
+->top;region->extents.right =pRectEnd-> right; region->
+extents.bottom=pRectEnd->bottom ;while(pRect <= pRectEnd){if (
+pRect->left< region->extents.left) region->extents.left= pRect->left;
+if (pRect-> right>region->extents.right)region->extents.right= pRect->right
+;pRect++; }} /*handle an overlapping band for intersect _region */
+static int intersect_overlapping(struct region *pReg, const
+rectangle_t* r1,const rectangle_t *r1End,const
+rectangle_t *r2, const
+rectangle_t*r2End,int top,int bottom){int left,right;while ((r1 != r1End)&&(r2!=
+r2End)){left=max(r1->left,r2->left);right=min(r1->right,r2->right);if(left<right
+){rectangle_t*rect = add_rect(pReg);if(!rect)return 0;rect->left=left;rect->top=
+top;rect->right=right;rect->bottom=bottom;}if (r1->right<r2->right)r1++;else if(
+r2->right<r1->right)r2++;else{r1++;r2++;}}return 1;} /* handle a non-overlapping
+band for subtract_region*/static int subtract_non_overlapping(struct region*pReg
+,const rectangle_t*r,const rectangle_t*rEnd, int top,int bottom){while(r!=rEnd){
+ rectangle_t*rect =add_rect(pReg);
+ if(!rect) return 0;rect->left=r->
+ left;rect->top = top;rect->right=
+ r->right; rect-> bottom = bottom;
+ r++;} return 1;} /* handle an
+ overlapping band for subtract_region */
+ static int subtract_overlapping(struct region *pReg,
+ const rectangle_t*r1, const rectangle_t*r1End, const
+ rectangle_t *r2,const rectangle_t *r2End,int top,int
+ bottom){int left=r1->left; while((r1!=r1End
+ )&&(r2!=r2End)){ if (r2->right <=
+ left) r2++; else if (r2->left <=
+ left){left =r2-> right; if(left>=
+ r1->right){r1++; if(r1!=r1End)left=r1->left
+ ;}else r2++;}else if(r2->left<r1->right){rectangle_t
+ *rect=add_rect(pReg); if(!rect)return 0; rect->left=
+ left;rect->top=top;rect->right=r2->left;rect->bottom
+ =bottom;left=r2->right;if (left>=r1->right
+ ){r1++; if(r1 != r1End) left=r1->
+ left;}else r2++; } else {if (r1->
+ right > left ) { rectangle_t*rect
+ =add_rect(pReg); if(!rect)return 0;rect
+ ->left=left;rect->top=top;rect->right=r1->right;rect
+ ->bottom=bottom;}r1++;if(r1!=r1End) left=r1->left;}}
+ while(r1!=r1End){rectangle_t*rect=add_rect(pReg);if(
+ !rect)return 0;rect->left= left; rect->top=
+ top;rect->right= r1->right;rect->
+ bottom=bottom;r1 ++;if(r1!=r1End)
+ left= r1->left;} return 1;}/*handle a
+ non-overlapping band for union_region*/static int
+ union_non_overlapping( struct region *pReg, const
+ rectangle_t *r, const rectangle_t *rEnd, int top,int
+ bottom){while(r != rEnd){rectangle_t *rect=add_rect(
+ pReg);if(!rect)return 0; rect->left = r->
+ left; rect->top= top;rect->right=
+ r->right; rect-> bottom=bottom; r
+ ++;} return 1;} /* handle an overlapping band for union_region */ static int
+ union_overlapping(struct region*pReg,const rectangle_t *r1,const rectangle_t
+ *r1End, const rectangle_t *r2,const rectangle_t *r2End,int top, int bottom){
+ #define MERGERECT(r)if((pReg->num_rects!=0)&&(pReg->rects[pReg->num_rects-1\
+ ].top==top)&&(pReg->rects[ pReg->num_rects-1].bottom\
+ ==bottom) && (pReg->rects[ pReg->num_rects -1].right\
+ >=r->left)){if(pReg->rects [pReg->num_rects-1].right<\
+ r->right){pReg->rects[pReg ->num_rects-1].right = r->\
+ right;}}else {rectangle_t* rect = add_rect(pReg);if(\
+ !rect)return 0;rect->top= top;rect->bottom=bottom;\
+ rect->left=r->left;rect ->right = r->right;}r++;
+ while((r1!=r1End)&&(r2 !=r2End)){if(r1->left<r2
+ ->left){MERGERECT(r1);} else{MERGERECT(r2);}}if(
+ r1!=r1End){do{MERGERECT(r1);}while(r1!=
+ r1End);}else while (r2!=r2End){
+ MERGERECT(r2);}return 1;
+ #undef MERGERECT
+ }/*create an empty region*/
+ struct region*create_empty_region(void
+ ){struct region*region;if(!(region=mem_alloc(sizeof
+ (*region))))return NULL;if (!(region->rects=mem_alloc
+ (RGN_DEFAULT_RECTS *sizeof (*region->rects )))){free(
+ region);return NULL;}region ->size = RGN_DEFAULT_RECTS;
+ region->num_rects=0;region ->extents.left=0; region->
+ extents.top = 0; region-> extents.right = 0;region->
+ extents.bottom = 0; return region;}/* create a region
+ from request data */struct region* create_region_from_req_data
+ (const void*data,data_size_t size){ unsigned int alloc_rects;
+ struct region*region;const rectangle_t *rects = data;
+ int nb_rects = size/sizeof( rectangle_t ); /* special
+ case: empty region can be specified by a single all-
+ zero rectangle*/if(nb_rects== 1&&!memcmp(rects,&empty_rect
+ ,sizeof(empty_rect)))nb_rects =0;if(!validate_rectangles
+ (rects,nb_rects)){set_error (STATUS_INVALID_PARAMETER)
+ ;return NULL;}if(!(region= mem_alloc(sizeof(*region)
+ ))) return NULL; alloc_rects = max(nb_rects,
+ RGN_DEFAULT_RECTS);if(!(region->rects
+ = mem_alloc( alloc_rects *
+ sizeof(*region->
+ rects)))){free(region);return
+ NULL;}region->size=alloc_rects; region->
+ num_rects=nb_rects;memcpy (region->rects, rects,
+ nb_rects*sizeof(*rects)); set_region_extents(region
+ );return region;}/*free a region */void free_region
+ (struct region*region){free (region->rects);free(region
+ );}/*set region to a simple rectangle*/void set_region_rect
+ (struct region *region, const rectangle_t*rect){if
+ (!is_rect_empty ( rect )){ region ->num_rects=1;region->rects
+ [0]=region->extents=*rect; }else{ region->num_rects=0;region
+ ->extents=empty_rect;}} /* retrieve the region data
+ for sending to the client*/ rectangle_t*get_region_data
+ (const struct region*region ,data_size_t max_size,
+ data_size_t *total_size ){ const rectangle_t *data =
+ region->rects;if(!(*total_size =region->num_rects*sizeof(
+ rectangle_t))){/* return a single empty rect for empty
+ regions*/*total_size=sizeof (empty_rect);data=&empty_rect
+ ;}if (max_size >= *total_size)return memdup(data,*
+ total_size);set_error(STATUS_BUFFER_OVERFLOW
+ );return NULL;}/*retrieve the region
+ data for sending to the
+ client and free
+ the region at the same time
+ */rectangle_t*get_region_data_and_free
+ (struct region *region, data_size_t max_size,
+ data_size_t*total_size) {rectangle_t*ret=region
+ ->rects;if(!(*total_size =region->num_rects*sizeof
+ (rectangle_t))){/* return a single empty rect for
+ empty regions*/*total_size =sizeof( empty_rect );if(
+ max_size>=sizeof(empty_rect )){ret=memdup(&empty_rect,
+ sizeof( empty_rect ));free( region->rects);}}if(max_size
+ <*total_size){free( region ->rects); set_error(
+ STATUS_BUFFER_OVERFLOW ); ret = NULL;}free(region);return
+ ret;} /* check if a given region is empty*/int is_region_empty
+ (const struct region*region ){return region->num_rects == 0;}/*
+ get the extents rect of a region */void get_region_extents
+ (const struct region*region ,rectangle_t*rect){*rect=
+ region->extents;}/* add an offset to a region */void
+ offset_region(struct region *region, int x, int y ){
+ rectangle_t*rect,*end;if(! region->num_rects)return;
+ for(rect=region->rects,end =rect+region->num_rects;
+ rect<end;rect++)offset_rect(rect,x,y);offset_rect(
+ ®ion->extents,x,y);}/*mirror a region
+ relative to a window client
+ rect */ void
+ mirror_region(const rectangle_t
+ *client_rect,struct region*region){int start
+ ,end,i,j;for(start=0;start <region->num_rects;start=
+ end+1){for(end=start;end <region->num_rects-1;end
+ ++)if(region->rects[end+1] .top!=region->rects[end].
+ top)break;for(i=start,j=end ;i<j;i++,j--){rectangle_t
+ rect=region->rects[j];region ->rects[i]=region->rects[j
+ ];region->rects[j] = rect; mirror_rect(client_rect,&
+ region->rects[j]);mirror_rect (client_rect,®ion->rects
+ [i]);}if(i==j)mirror_rect( client_rect,®ion->rects
+ [i]);} mirror_rect( client_rect, ®ion->extents );}/* scale a region for a
+ given dpi factor */ void scale_region( struct region * region, unsigned int
+
+
+
+
+
+
+
+
+
+ dpi_from,unsigned int dpi_to ){rectangle_t
+ *rect,*end;if(!region->num_rects)return;for(
+ rect=region->rects, end=rect+region->num_rects
+ ;rect<end;rect++)scale_dpi_rect(rect,dpi_from,
+ dpi_to); scale_dpi_rect(®ion->extents,
+ dpi_from,dpi_to);} /* make a copy of a region;
+ returns dst or NULL on error */ struct region*
+ copy_region ( struct region *dst, const struct
+ region*src){if(dst == src)return dst; if(dst->
+ size<src->num_rects){rectangle_t*rect=realloc(
+ dst->rects,src->num_rects*sizeof(*rect)); if(!
+ rect){set_error(STATUS_NO_MEMORY);return NULL;
+ }dst->rects=rect;dst->size=src->num_rects;}dst
+ ->num_rects=src->num_rects; dst->extents=src->
+ extents; memcpy( dst->rects,src->rects,src->
+ num_rects*sizeof(*dst->rects)); return dst;}
+ /* compute the intersection of two regions
+ into dst, which can be one of the source
+ regions*/struct region*intersect_region(
+ struct region*dst,const struct region
+ *src1,const struct region *src2)
+ {if (!src1->num_rects||!
+ src2->num_rects||!
+ EXTENTCHECK(
+ &src1->
+ extents
+ ,&src2->
+ extents
+ )){dst->
+ num_rects
+ =0;dst->
+ extents
+ .left=0
+ ;dst->
+ extents
+ .top=0
+ ;dst->
+ extents
+ .right=
+ 0;dst->
+ extents
+ .bottom=
+ 0;return
+ dst;}if(!
+ region_op
+ (dst,src1,src2
+ ,intersect_overlapping,NULL,
+ NULL))return NULL;set_region_extents(dst);return dst;}
-#define RGN_DEFAULT_RECTS 2
-#define EXTENTCHECK(r1, r2) \
- ((r1)->right > (r2)->left && \
- (r1)->left < (r2)->right && \
- (r1)->bottom > (r2)->top && \
- (r1)->top < (r2)->bottom)
-typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End, int top, int bottom );
-typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r,
- const rectangle_t *rEnd, int top, int bottom );
-static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */
-
-/* add a rectangle to a region */
-static inline rectangle_t *add_rect( struct region *reg )
-{
- if (reg->num_rects >= reg->size)
- {
- rectangle_t *new_rect = realloc( reg->rects, 2 * sizeof(rectangle_t) * reg->size );
- if (!new_rect)
- {
- set_error( STATUS_NO_MEMORY );
- return NULL;
- }
- reg->rects = new_rect;
- reg->size *= 2;
- }
- return reg->rects + reg->num_rects++;
-}
-
-/* make sure all the rectangles are valid and that the region is properly y-x-banded */
-static inline int validate_rectangles( const rectangle_t *rects, unsigned int nb_rects )
-{
- const rectangle_t *ptr, *end;
-
- for (ptr = rects, end = rects + nb_rects; ptr < end; ptr++)
- {
- if (is_rect_empty( ptr )) return 0; /* empty rectangle */
- if (ptr == end - 1) break;
- if (ptr[0].top == ptr[1].top) /* same band */
- {
- if (ptr[0].bottom != ptr[1].bottom) return 0; /* not same y extent */
- if (ptr[0].right >= ptr[1].left) return 0; /* not properly x ordered */
- }
- else /* new band */
- {
- if (ptr[0].bottom > ptr[1].top) return 0; /* not properly y ordered */
- }
- }
- return 1;
-}
-
-/* attempt to merge the rects in the current band with those in the */
-/* previous one. Used only by region_op. */
-static int coalesce_region( struct region *pReg, int prevStart, int curStart )
-{
- int curNumRects;
- rectangle_t *pRegEnd = &pReg->rects[pReg->num_rects];
- rectangle_t *pPrevRect = &pReg->rects[prevStart];
- rectangle_t *pCurRect = &pReg->rects[curStart];
- int prevNumRects = curStart - prevStart;
- int bandtop = pCurRect->top;
-
- for (curNumRects = 0;
- (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
- curNumRects++)
- {
- pCurRect++;
- }
-
- if (pCurRect != pRegEnd)
- {
- pRegEnd--;
- while (pRegEnd[-1].top == pRegEnd->top) pRegEnd--;
- curStart = pRegEnd - pReg->rects;
- pRegEnd = pReg->rects + pReg->num_rects;
- }
-
- if ((curNumRects == prevNumRects) && (curNumRects != 0))
- {
- pCurRect -= curNumRects;
- if (pPrevRect->bottom == pCurRect->top)
- {
- do
- {
- if ((pPrevRect->left != pCurRect->left) ||
- (pPrevRect->right != pCurRect->right)) return curStart;
- pPrevRect++;
- pCurRect++;
- prevNumRects -= 1;
- } while (prevNumRects != 0);
-
- pReg->num_rects -= curNumRects;
- pCurRect -= curNumRects;
- pPrevRect -= curNumRects;
-
- do
- {
- pPrevRect->bottom = pCurRect->bottom;
- pPrevRect++;
- pCurRect++;
- curNumRects -= 1;
- } while (curNumRects != 0);
-
- if (pCurRect == pRegEnd) curStart = prevStart;
- else do { *pPrevRect++ = *pCurRect++; } while (pCurRect != pRegEnd);
-
- }
- }
- return curStart;
-}
-
-/* apply an operation to two regions */
-/* check the GDI version of the code for explanations */
-static int region_op( struct region *newReg, const struct region *reg1, const struct region *reg2,
- overlap_func_t overlap_func,
- non_overlap_func_t non_overlap1_func,
- non_overlap_func_t non_overlap2_func )
-{
- int ybot, ytop, top, bot, prevBand, curBand;
- const rectangle_t *r1BandEnd, *r2BandEnd;
-
- const rectangle_t *r1 = reg1->rects;
- const rectangle_t *r2 = reg2->rects;
- const rectangle_t *r1End = r1 + reg1->num_rects;
- const rectangle_t *r2End = r2 + reg2->num_rects;
-
- rectangle_t *new_rects, *old_rects = newReg->rects;
- int new_size, ret = 0;
-
- new_size = max( reg1->num_rects, reg2->num_rects ) * 2;
- if (!(new_rects = mem_alloc( new_size * sizeof(*newReg->rects) ))) return 0;
-
- newReg->size = new_size;
- newReg->rects = new_rects;
- newReg->num_rects = 0;
-
- if (reg1->extents.top < reg2->extents.top)
- ybot = reg1->extents.top;
- else
- ybot = reg2->extents.top;
-
- prevBand = 0;
-
- do
- {
- curBand = newReg->num_rects;
-
- r1BandEnd = r1;
- while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
-
- r2BandEnd = r2;
- while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
-
- if (r1->top < r2->top)
- {
- top = max(r1->top,ybot);
- bot = min(r1->bottom,r2->top);
-
- if ((top != bot) && non_overlap1_func)
- {
- if (!non_overlap1_func( newReg, r1, r1BandEnd, top, bot )) goto done;
- }
-
- ytop = r2->top;
- }
- else if (r2->top < r1->top)
- {
- top = max(r2->top,ybot);
- bot = min(r2->bottom,r1->top);
-
- if ((top != bot) && non_overlap2_func)
- {
- if (!non_overlap2_func( newReg, r2, r2BandEnd, top, bot )) goto done;
- }
-
- ytop = r1->top;
- }
- else
- {
- ytop = r1->top;
- }
-
- if (newReg->num_rects != curBand)
- prevBand = coalesce_region(newReg, prevBand, curBand);
-
- ybot = min(r1->bottom, r2->bottom);
- curBand = newReg->num_rects;
- if (ybot > ytop)
- {
- if (!overlap_func( newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot )) goto done;
- }
-
- if (newReg->num_rects != curBand)
- prevBand = coalesce_region(newReg, prevBand, curBand);
-
- if (r1->bottom == ybot) r1 = r1BandEnd;
- if (r2->bottom == ybot) r2 = r2BandEnd;
- } while ((r1 != r1End) && (r2 != r2End));
-
- curBand = newReg->num_rects;
- if (r1 != r1End)
- {
- if (non_overlap1_func)
- {
- do
- {
- r1BandEnd = r1;
- while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++;
- if (!non_overlap1_func( newReg, r1, r1BandEnd, max(r1->top,ybot), r1->bottom ))
- goto done;
- r1 = r1BandEnd;
- } while (r1 != r1End);
- }
- }
- else if ((r2 != r2End) && non_overlap2_func)
- {
- do
- {
- r2BandEnd = r2;
- while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++;
- if (!non_overlap2_func( newReg, r2, r2BandEnd, max(r2->top,ybot), r2->bottom ))
- goto done;
- r2 = r2BandEnd;
- } while (r2 != r2End);
- }
-
- if (newReg->num_rects != curBand) coalesce_region(newReg, prevBand, curBand);
-
- if ((newReg->num_rects < (newReg->size / 2)) && (newReg->size > 2))
- {
- new_size = max( newReg->num_rects, RGN_DEFAULT_RECTS );
- if ((new_rects = realloc( newReg->rects, sizeof(*newReg->rects) * new_size )))
- {
- newReg->rects = new_rects;
- newReg->size = new_size;
- }
- }
- ret = 1;
-done:
- free( old_rects );
- return ret;
-}
-
-/* recalculate the extents of a region */
-static void set_region_extents( struct region *region )
-{
- rectangle_t *pRect, *pRectEnd;
-
- if (region->num_rects == 0)
- {
- region->extents.left = 0;
- region->extents.top = 0;
- region->extents.right = 0;
- region->extents.bottom = 0;
- return;
- }
-
- pRect = region->rects;
- pRectEnd = &pRect[region->num_rects - 1];
-
- region->extents.left = pRect->left;
- region->extents.top = pRect->top;
- region->extents.right = pRectEnd->right;
- region->extents.bottom = pRectEnd->bottom;
-
- while (pRect <= pRectEnd)
- {
- if (pRect->left < region->extents.left) region->extents.left = pRect->left;
- if (pRect->right > region->extents.right) region->extents.right = pRect->right;
- pRect++;
- }
-}
-
-/* handle an overlapping band for intersect_region */
-static int intersect_overlapping( struct region *pReg,
- const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End,
- int top, int bottom )
-
-{
- int left, right;
-
- while ((r1 != r1End) && (r2 != r2End))
- {
- left = max(r1->left, r2->left);
- right = min(r1->right, r2->right);
-
- if (left < right)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = right;
- rect->bottom = bottom;
- }
-
- if (r1->right < r2->right) r1++;
- else if (r2->right < r1->right) r2++;
- else
- {
- r1++;
- r2++;
- }
- }
- return 1;
-}
-
-/* handle a non-overlapping band for subtract_region */
-static int subtract_non_overlapping( struct region *pReg, const rectangle_t *r,
- const rectangle_t *rEnd, int top, int bottom )
-{
- while (r != rEnd)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = r->left;
- rect->top = top;
- rect->right = r->right;
- rect->bottom = bottom;
- r++;
- }
- return 1;
-}
-
-/* handle an overlapping band for subtract_region */
-static int subtract_overlapping( struct region *pReg,
- const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End,
- int top, int bottom )
-{
- int left = r1->left;
-
- while ((r1 != r1End) && (r2 != r2End))
- {
- if (r2->right <= left) r2++;
- else if (r2->left <= left)
- {
- left = r2->right;
- if (left >= r1->right)
- {
- r1++;
- if (r1 != r1End)
- left = r1->left;
- }
- else r2++;
- }
- else if (r2->left < r1->right)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = r2->left;
- rect->bottom = bottom;
- left = r2->right;
- if (left >= r1->right)
- {
- r1++;
- if (r1 != r1End)
- left = r1->left;
- }
- else r2++;
- }
- else
- {
- if (r1->right > left)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = r1->right;
- rect->bottom = bottom;
- }
- r1++;
- if (r1 != r1End)
- left = r1->left;
- }
- }
-
- while (r1 != r1End)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = left;
- rect->top = top;
- rect->right = r1->right;
- rect->bottom = bottom;
- r1++;
- if (r1 != r1End) left = r1->left;
- }
- return 1;
-}
-
-/* handle a non-overlapping band for union_region */
-static int union_non_overlapping( struct region *pReg, const rectangle_t *r,
- const rectangle_t *rEnd, int top, int bottom )
-{
- while (r != rEnd)
- {
- rectangle_t *rect = add_rect( pReg );
- if (!rect) return 0;
- rect->left = r->left;
- rect->top = top;
- rect->right = r->right;
- rect->bottom = bottom;
- r++;
- }
- return 1;
-}
-
-/* handle an overlapping band for union_region */
-static int union_overlapping( struct region *pReg,
- const rectangle_t *r1, const rectangle_t *r1End,
- const rectangle_t *r2, const rectangle_t *r2End,
- int top, int bottom )
-{
-#define MERGERECT(r) \
- if ((pReg->num_rects != 0) && \
- (pReg->rects[pReg->num_rects-1].top == top) && \
- (pReg->rects[pReg->num_rects-1].bottom == bottom) && \
- (pReg->rects[pReg->num_rects-1].right >= r->left)) \
- { \
- if (pReg->rects[pReg->num_rects-1].right < r->right) \
- { \
- pReg->rects[pReg->num_rects-1].right = r->right; \
- } \
- } \
- else \
- { \
- rectangle_t *rect = add_rect( pReg ); \
- if (!rect) return 0; \
- rect->top = top; \
- rect->bottom = bottom; \
- rect->left = r->left; \
- rect->right = r->right; \
- } \
- r++;
-
- while ((r1 != r1End) && (r2 != r2End))
- {
- if (r1->left < r2->left)
- {
- MERGERECT(r1);
- }
- else
- {
- MERGERECT(r2);
- }
- }
-
- if (r1 != r1End)
- {
- do
- {
- MERGERECT(r1);
- } while (r1 != r1End);
- }
- else while (r2 != r2End)
- {
- MERGERECT(r2);
- }
- return 1;
-#undef MERGERECT
-}
-
-
-/* create an empty region */
-struct region *create_empty_region(void)
-{
- struct region *region;
-
- if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
- if (!(region->rects = mem_alloc( RGN_DEFAULT_RECTS * sizeof(*region->rects) )))
- {
- free( region );
- return NULL;
- }
- region->size = RGN_DEFAULT_RECTS;
- region->num_rects = 0;
- region->extents.left = 0;
- region->extents.top = 0;
- region->extents.right = 0;
- region->extents.bottom = 0;
- return region;
-}
-
-/* create a region from request data */
-struct region *create_region_from_req_data( const void *data, data_size_t size )
-{
- unsigned int alloc_rects;
- struct region *region;
- const rectangle_t *rects = data;
- int nb_rects = size / sizeof(rectangle_t);
-
- /* special case: empty region can be specified by a single all-zero rectangle */
- if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) nb_rects = 0;
-
- if (!validate_rectangles( rects, nb_rects ))
- {
- set_error( STATUS_INVALID_PARAMETER );
- return NULL;
- }
-
- if (!(region = mem_alloc( sizeof(*region) ))) return NULL;
-
- alloc_rects = max( nb_rects, RGN_DEFAULT_RECTS );
- if (!(region->rects = mem_alloc( alloc_rects * sizeof(*region->rects) )))
- {
- free( region );
- return NULL;
- }
- region->size = alloc_rects;
- region->num_rects = nb_rects;
- memcpy( region->rects, rects, nb_rects * sizeof(*rects) );
- set_region_extents( region );
- return region;
-}
-
-/* free a region */
-void free_region( struct region *region )
-{
- free( region->rects );
- free( region );
-}
-
-/* set region to a simple rectangle */
-void set_region_rect( struct region *region, const rectangle_t *rect )
-{
- if (!is_rect_empty( rect ))
- {
- region->num_rects = 1;
- region->rects[0] = region->extents = *rect;
- }
- else
- {
- region->num_rects = 0;
- region->extents = empty_rect;
- }
-}
-
-/* retrieve the region data for sending to the client */
-rectangle_t *get_region_data( const struct region *region, data_size_t max_size, data_size_t *total_size )
-{
- const rectangle_t *data = region->rects;
-
- if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
- {
- /* return a single empty rect for empty regions */
- *total_size = sizeof(empty_rect);
- data = &empty_rect;
- }
- if (max_size >= *total_size) return memdup( data, *total_size );
- set_error( STATUS_BUFFER_OVERFLOW );
- return NULL;
-}
-
-/* retrieve the region data for sending to the client and free the region at the same time */
-rectangle_t *get_region_data_and_free( struct region *region, data_size_t max_size, data_size_t *total_size )
-{
- rectangle_t *ret = region->rects;
-
- if (!(*total_size = region->num_rects * sizeof(rectangle_t)))
- {
- /* return a single empty rect for empty regions */
- *total_size = sizeof(empty_rect);
- if (max_size >= sizeof(empty_rect))
- {
- ret = memdup( &empty_rect, sizeof(empty_rect) );
- free( region->rects );
- }
- }
-
- if (max_size < *total_size)
- {
- free( region->rects );
- set_error( STATUS_BUFFER_OVERFLOW );
- ret = NULL;
- }
- free( region );
- return ret;
-}
-
-/* check if a given region is empty */
-int is_region_empty( const struct region *region )
-{
- return region->num_rects == 0;
-}
-
-
-/* get the extents rect of a region */
-void get_region_extents( const struct region *region, rectangle_t *rect )
-{
- *rect = region->extents;
-}
-
-/* add an offset to a region */
-void offset_region( struct region *region, int x, int y )
-{
- rectangle_t *rect, *end;
-
- if (!region->num_rects) return;
- for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++)
- offset_rect( rect, x, y );
- offset_rect( ®ion->extents, x, y );
-}
-
-/* mirror a region relative to a window client rect */
-void mirror_region( const rectangle_t *client_rect, struct region *region )
-{
- int start, end, i, j;
-
- for (start = 0; start < region->num_rects; start = end + 1)
- {
- for (end = start; end < region->num_rects - 1; end++)
- if (region->rects[end + 1].top != region->rects[end].top) break;
- for (i = start, j = end; i < j; i++, j--)
- {
- rectangle_t rect = region->rects[j];
- region->rects[i] = region->rects[j];
- region->rects[j] = rect;
- mirror_rect( client_rect, ®ion->rects[j] );
- mirror_rect( client_rect, ®ion->rects[i] );
- }
- if (i == j) mirror_rect( client_rect, ®ion->rects[i] );
- }
- mirror_rect( client_rect, ®ion->extents );
-}
-
-
-/* scale a region for a given dpi factor */
-void scale_region( struct region *region, unsigned int dpi_from, unsigned int dpi_to )
-{
- rectangle_t *rect, *end;
-
- if (!region->num_rects) return;
- for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++)
- scale_dpi_rect( rect, dpi_from, dpi_to );
- scale_dpi_rect( ®ion->extents, dpi_from, dpi_to );
-}
-
-
-/* make a copy of a region; returns dst or NULL on error */
-struct region *copy_region( struct region *dst, const struct region *src )
-{
- if (dst == src) return dst;
-
- if (dst->size < src->num_rects)
- {
- rectangle_t *rect = realloc( dst->rects, src->num_rects * sizeof(*rect) );
- if (!rect)
- {
- set_error( STATUS_NO_MEMORY );
- return NULL;
- }
- dst->rects = rect;
- dst->size = src->num_rects;
- }
- dst->num_rects = src->num_rects;
- dst->extents = src->extents;
- memcpy( dst->rects, src->rects, src->num_rects * sizeof(*dst->rects) );
- return dst;
-}
-
-/* compute the intersection of two regions into dst, which can be one of the source regions */
-struct region *intersect_region( struct region *dst, const struct region *src1,
- const struct region *src2 )
-{
- if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents))
- {
- dst->num_rects = 0;
- dst->extents.left = 0;
- dst->extents.top = 0;
- dst->extents.right = 0;
- dst->extents.bottom = 0;
- return dst;
- }
- if (!region_op( dst, src1, src2, intersect_overlapping, NULL, NULL )) return NULL;
- set_region_extents( dst );
- return dst;
-}
/* compute the subtraction of two regions into dst, which can be one of the source regions */
struct region *subtract_region( struct region *dst, const struct region *src1,
--
2.30.2
5
4
26 Apr '21
As a default implementation for en_US keyboard layout, calling the
driver implementation next so that it can override the result.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v2: Move code from driver to user32 common code instead of nulldrv,
graphics drivers callbacks are then called to have a chance to
override the default values.
The last patch completely removes LoadKeyboardLayout driver call,
it was unimplemented anyway. It can just be ignored if that's not
the right way forward.
IMHO it'd make things easier to have an internal keyboard layout
management, with key translations being done according to the thread
and process active layouts, but I can also see why we would like to
make it more seamlessly integrated with the system (although I'm not
sure if it's possible to map all Windows specificities).
Supersdes: 204099-204104
dlls/user32/driver.c | 8 +-
dlls/user32/input.c | 79 ++++++++++++++++++-
dlls/user32/user_private.h | 2 +-
dlls/wineandroid.drv/keyboard.c | 94 -----------------------
dlls/wineandroid.drv/wineandroid.drv.spec | 1 -
dlls/winemac.drv/keyboard.c | 2 +-
dlls/winemac.drv/winemac.drv.spec | 2 +-
dlls/winex11.drv/keyboard.c | 2 +-
dlls/winex11.drv/winex11.drv.spec | 2 +-
9 files changed, 84 insertions(+), 108 deletions(-)
diff --git a/dlls/user32/driver.c b/dlls/user32/driver.c
index 7ac77141696..7f26a48657f 100644
--- a/dlls/user32/driver.c
+++ b/dlls/user32/driver.c
@@ -284,9 +284,9 @@ static BOOL CDECL nulldrv_RegisterHotKey( HWND hwnd, UINT modifiers, UINT vk )
}
static INT CDECL nulldrv_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, LPWSTR str,
- int size, UINT flags, HKL layout )
+ int size, UINT flags, HKL layout, INT default_ret )
{
- return 0;
+ return default_ret;
}
static BOOL CDECL nulldrv_UnloadKeyboardLayout( HKL layout )
@@ -592,9 +592,9 @@ static BOOL CDECL loaderdrv_RegisterHotKey( HWND hwnd, UINT modifiers, UINT vk )
}
static INT CDECL loaderdrv_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state, LPWSTR str,
- int size, UINT flags, HKL layout )
+ int size, UINT flags, HKL layout, INT default_ret )
{
- return load_driver()->pToUnicodeEx( virt, scan, state, str, size, flags, layout );
+ return load_driver()->pToUnicodeEx( virt, scan, state, str, size, flags, layout, default_ret );
}
static BOOL CDECL loaderdrv_UnloadKeyboardLayout( HKL layout )
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 805bfe3e9de..4f0be6be3f2 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -877,11 +877,82 @@ INT WINAPI ToUnicode(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
/****************************************************************************
* ToUnicodeEx (USER32.@)
*/
-INT WINAPI ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
- LPWSTR lpwStr, int size, UINT flags, HKL hkl)
+INT WINAPI ToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
+ WCHAR *str, int size, UINT flags, HKL layout )
{
- if (!lpKeyState) return 0;
- return USER_Driver->pToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, hkl);
+ static HKL us_layout = (HKL)MAKELONG(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT));
+ BOOL shift, ctrl, numlock;
+ WCHAR buffer[2];
+ INT len;
+
+ TRACE_(keyboard)( "virt %u, scan %u, state %p, str %p, size %d, flags %x, layout %p.\n",
+ virt, scan, state, str, size, flags, layout );
+
+ if (!state) return 0;
+
+ shift = state[VK_SHIFT] & 0x80;
+ ctrl = state[VK_CONTROL] & 0x80;
+ numlock = state[VK_NUMLOCK] & 0x01;
+
+ if (layout != us_layout) buffer[0] = 0; /* FIXME: non-us layout */
+ else if (scan & 0x8000) buffer[0] = 0; /* key up */
+ else if (!ctrl)
+ {
+ switch (virt)
+ {
+ case VK_BACK: buffer[0] = '\b'; break;
+ case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break;
+ case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break;
+ case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break;
+ case VK_OEM_4: buffer[0] = shift ? '{' : '['; break;
+ case VK_OEM_5: buffer[0] = shift ? '|' : '\\'; break;
+ case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break;
+ case VK_OEM_7: buffer[0] = shift ? '"' : '\''; break;
+ case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break;
+ case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break;
+ case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break;
+ case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break;
+ case VK_RETURN: buffer[0] = '\r'; break;
+ case VK_SPACE: buffer[0] = ' '; break;
+ case VK_TAB: buffer[0] = '\t'; break;
+ case VK_MULTIPLY: buffer[0] = '*'; break;
+ case VK_ADD: buffer[0] = '+'; break;
+ case VK_SUBTRACT: buffer[0] = '-'; break;
+ case VK_DIVIDE: buffer[0] = '/'; break;
+ default:
+ if (virt >= '0' && virt <= '9')
+ buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt;
+ else if (virt >= 'A' && virt <= 'Z')
+ buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A';
+ else if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift)
+ buffer[0] = '0' + virt - VK_NUMPAD0;
+ else if (virt == VK_DECIMAL && numlock && !shift)
+ buffer[0] = '.';
+ else
+ buffer[0] = 0;
+ break;
+ }
+ }
+ else /* Control codes */
+ {
+ switch (virt)
+ {
+ case VK_OEM_4: buffer[0] = 0x1b; break;
+ case VK_OEM_5: buffer[0] = 0x1c; break;
+ case VK_OEM_6: buffer[0] = 0x1d; break;
+ case VK_SUBTRACT: buffer[0] = 0x1e; break;
+ default:
+ if (virt >= 'A' && virt <= 'Z') buffer[0] = virt - 'A' + 1;
+ else buffer[0] = 0;
+ break;
+ }
+ }
+ buffer[1] = 0;
+
+ wcsncpy( str, buffer, size );
+ len = USER_Driver->pToUnicodeEx( virt, scan, state, str, size, flags, layout, wcslen( buffer ) );
+ TRACE_(keyboard)( "ret %d, str %s.\n", len, debugstr_wn(str, len) );
+ return len;
}
/****************************************************************************
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 5f8059a12a0..98eec94da57 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -71,7 +71,7 @@ typedef struct tagUSER_DRIVER {
HKL (CDECL *pLoadKeyboardLayout)(LPCWSTR, UINT);
UINT (CDECL *pMapVirtualKeyEx)(UINT, UINT, HKL);
BOOL (CDECL *pRegisterHotKey)(HWND, UINT, UINT);
- INT (CDECL *pToUnicodeEx)(UINT, UINT, const BYTE *, LPWSTR, int, UINT, HKL);
+ INT (CDECL *pToUnicodeEx)(UINT, UINT, const BYTE *, LPWSTR, int, UINT, HKL, INT);
BOOL (CDECL *pUnloadKeyboardLayout)(HKL);
void (CDECL *pUnregisterHotKey)(HWND, UINT, UINT);
SHORT (CDECL *pVkKeyScanEx)(WCHAR, HKL);
diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c
index 0a6ede0ec5f..04565c3fad8 100644
--- a/dlls/wineandroid.drv/keyboard.c
+++ b/dlls/wineandroid.drv/keyboard.c
@@ -750,100 +750,6 @@ jboolean keyboard_event( JNIEnv *env, jobject obj, jint win, jint action, jint k
}
-/***********************************************************************
- * ANDROID_ToUnicodeEx
- */
-INT CDECL ANDROID_ToUnicodeEx( UINT virt, UINT scan, const BYTE *state,
- LPWSTR buf, int size, UINT flags, HKL hkl )
-{
- WCHAR buffer[2];
- BOOL shift = state[VK_SHIFT] & 0x80;
- BOOL ctrl = state[VK_CONTROL] & 0x80;
- BOOL numlock = state[VK_NUMLOCK] & 0x01;
-
- buffer[0] = buffer[1] = 0;
-
- if (scan & 0x8000) return 0; /* key up */
-
- /* FIXME: hardcoded layout */
-
- if (!ctrl)
- {
- switch (virt)
- {
- case VK_BACK: buffer[0] = '\b'; break;
- case VK_OEM_1: buffer[0] = shift ? ':' : ';'; break;
- case VK_OEM_2: buffer[0] = shift ? '?' : '/'; break;
- case VK_OEM_3: buffer[0] = shift ? '~' : '`'; break;
- case VK_OEM_4: buffer[0] = shift ? '{' : '['; break;
- case VK_OEM_5: buffer[0] = shift ? '|' : '\\'; break;
- case VK_OEM_6: buffer[0] = shift ? '}' : ']'; break;
- case VK_OEM_7: buffer[0] = shift ? '"' : '\''; break;
- case VK_OEM_COMMA: buffer[0] = shift ? '<' : ','; break;
- case VK_OEM_MINUS: buffer[0] = shift ? '_' : '-'; break;
- case VK_OEM_PERIOD: buffer[0] = shift ? '>' : '.'; break;
- case VK_OEM_PLUS: buffer[0] = shift ? '+' : '='; break;
- case VK_RETURN: buffer[0] = '\r'; break;
- case VK_SPACE: buffer[0] = ' '; break;
- case VK_TAB: buffer[0] = '\t'; break;
- case VK_MULTIPLY: buffer[0] = '*'; break;
- case VK_ADD: buffer[0] = '+'; break;
- case VK_SUBTRACT: buffer[0] = '-'; break;
- case VK_DIVIDE: buffer[0] = '/'; break;
- default:
- if (virt >= '0' && virt <= '9')
- {
- buffer[0] = shift ? ")!@#$%^&*("[virt - '0'] : virt;
- break;
- }
- if (virt >= 'A' && virt <= 'Z')
- {
- buffer[0] = shift || (state[VK_CAPITAL] & 0x01) ? virt : virt + 'a' - 'A';
- break;
- }
- if (virt >= VK_NUMPAD0 && virt <= VK_NUMPAD9 && numlock && !shift)
- {
- buffer[0] = '0' + virt - VK_NUMPAD0;
- break;
- }
- if (virt == VK_DECIMAL && numlock && !shift)
- {
- buffer[0] = '.';
- break;
- }
- break;
- }
- }
- else /* Control codes */
- {
- if (virt >= 'A' && virt <= 'Z')
- buffer[0] = virt - 'A' + 1;
- else
- {
- switch (virt)
- {
- case VK_OEM_4:
- buffer[0] = 0x1b;
- break;
- case VK_OEM_5:
- buffer[0] = 0x1c;
- break;
- case VK_OEM_6:
- buffer[0] = 0x1d;
- break;
- case VK_SUBTRACT:
- buffer[0] = 0x1e;
- break;
- }
- }
- }
-
- lstrcpynW( buf, buffer, size );
- TRACE( "returning %d / %s\n", strlenW( buffer ), debugstr_wn(buf, strlenW( buffer )));
- return strlenW( buffer );
-}
-
-
/***********************************************************************
* ANDROID_GetKeyNameText
*/
diff --git a/dlls/wineandroid.drv/wineandroid.drv.spec b/dlls/wineandroid.drv/wineandroid.drv.spec
index 00de23de27e..6f27c1586b3 100644
--- a/dlls/wineandroid.drv/wineandroid.drv.spec
+++ b/dlls/wineandroid.drv/wineandroid.drv.spec
@@ -7,7 +7,6 @@
@ cdecl GetKeyNameText(long ptr long) ANDROID_GetKeyNameText
@ cdecl GetKeyboardLayout(long) ANDROID_GetKeyboardLayout
@ cdecl MapVirtualKeyEx(long long long) ANDROID_MapVirtualKeyEx
-@ cdecl ToUnicodeEx(long long ptr ptr long long long) ANDROID_ToUnicodeEx
@ cdecl VkKeyScanEx(long long) ANDROID_VkKeyScanEx
@ cdecl SetCursor(long) ANDROID_SetCursor
@ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) ANDROID_ChangeDisplaySettingsEx
diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c
index 1ea15f59341..5e4b5882c77 100644
--- a/dlls/winemac.drv/keyboard.c
+++ b/dlls/winemac.drv/keyboard.c
@@ -1553,7 +1553,7 @@ BOOL CDECL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey)
*
*/
INT CDECL macdrv_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
- LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
+ LPWSTR bufW, int bufW_size, UINT flags, HKL hkl, INT default_ret)
{
struct macdrv_thread_data *thread_data = macdrv_init_thread_data();
INT ret = 0;
diff --git a/dlls/winemac.drv/winemac.drv.spec b/dlls/winemac.drv/winemac.drv.spec
index 39cf33370b4..3baa730eabc 100644
--- a/dlls/winemac.drv/winemac.drv.spec
+++ b/dlls/winemac.drv/winemac.drv.spec
@@ -34,7 +34,7 @@
@ cdecl SysCommand(long long long) macdrv_SysCommand
@ cdecl SystemParametersInfo(long long ptr long) macdrv_SystemParametersInfo
@ cdecl ThreadDetach() macdrv_ThreadDetach
-@ cdecl ToUnicodeEx(long long ptr ptr long long long) macdrv_ToUnicodeEx
+@ cdecl ToUnicodeEx(long long ptr ptr long long long long) macdrv_ToUnicodeEx
@ cdecl UnregisterHotKey(long long long) macdrv_UnregisterHotKey
@ cdecl UpdateClipboard() macdrv_UpdateClipboard
@ cdecl UpdateLayeredWindow(long ptr ptr) macdrv_UpdateLayeredWindow
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 01620c5e4a4..82dd67d9373 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -2432,7 +2432,7 @@ static char KEYBOARD_MapDeadKeysym(KeySym keysym)
*
*/
INT CDECL X11DRV_ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
- LPWSTR bufW, int bufW_size, UINT flags, HKL hkl)
+ LPWSTR bufW, int bufW_size, UINT flags, HKL hkl, INT default_ret)
{
Display *display = thread_init_display();
XKeyEvent e;
diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec
index c0e24d8fe82..7aecac2c016 100644
--- a/dlls/winex11.drv/winex11.drv.spec
+++ b/dlls/winex11.drv/winex11.drv.spec
@@ -11,7 +11,7 @@
@ cdecl GetKeyboardLayoutName(ptr) X11DRV_GetKeyboardLayoutName
@ cdecl LoadKeyboardLayout(wstr long) X11DRV_LoadKeyboardLayout
@ cdecl MapVirtualKeyEx(long long long) X11DRV_MapVirtualKeyEx
-@ cdecl ToUnicodeEx(long long ptr ptr long long long) X11DRV_ToUnicodeEx
+@ cdecl ToUnicodeEx(long long ptr ptr long long long long) X11DRV_ToUnicodeEx
@ cdecl UnloadKeyboardLayout(long) X11DRV_UnloadKeyboardLayout
@ cdecl VkKeyScanEx(long long) X11DRV_VkKeyScanEx
@ cdecl DestroyCursorIcon(long) X11DRV_DestroyCursorIcon
--
2.31.0
4
12