From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/user32/hook.c | 1 + dlls/user32/nonclient.c | 48 ++++++++++++++++++++++++++++++++++++ dlls/user32/user_main.c | 8 ++++++ dlls/user32/user_private.h | 1 + dlls/uxtheme/Makefile.in | 3 ++- dlls/uxtheme/system.c | 1 + dlls/uxtheme/uxthemedll.h | 2 ++ dlls/uxtheme/window.c | 32 ++++++++++++++++++++++++ dlls/win32u/defwnd.c | 16 ++++++++++++ dlls/win32u/menu.c | 25 ++++++++++--------- dlls/win32u/win32u_private.h | 2 +- dlls/wow64win/user.c | 23 +++++++++++++++++ include/ntuser.h | 12 +++++++++ include/winuser.h | 10 ++++++++ 14 files changed, 171 insertions(+), 13 deletions(-) create mode 100644 dlls/uxtheme/window.c
diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c index cb4b20d6252..9fea8a59e0e 100644 --- a/dlls/user32/hook.c +++ b/dlls/user32/hook.c @@ -72,6 +72,7 @@ WINE_DECLARE_DEBUG_CHANNEL(relay); static struct user_api_hook original_user_api = { USER_DefDlgProc, + USER_NonClientButtonDraw, USER_ScrollBarDraw, USER_ScrollBarProc, }; diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c index a6b72f74997..00c7368c516 100644 --- a/dlls/user32/nonclient.c +++ b/dlls/user32/nonclient.c @@ -172,3 +172,51 @@ LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam ) } return 0; } + +static void user_draw_mdi_button( HDC hdc, enum NONCLIENT_BUTTON_TYPE type, RECT rect, BOOL down, BOOL grayed ) +{ + UINT flags; + + switch (type) + { + case MENU_CLOSE_BUTTON: + flags = DFCS_CAPTIONCLOSE; + break; + case MENU_MIN_BUTTON: + flags = DFCS_CAPTIONMIN; + break; + case MENU_MAX_BUTTON: + flags = DFCS_CAPTIONMAX; + break; + case MENU_RESTORE_BUTTON: + flags = DFCS_CAPTIONRESTORE; + break; + case MENU_HELP_BUTTON: + flags = DFCS_CAPTIONHELP; + break; + default: + return; + } + + if (down) + flags |= DFCS_PUSHED; + if (grayed) + flags |= DFCS_INACTIVE; + + DrawFrameControl( hdc, &rect, DFC_CAPTION, flags ); +} + +void WINAPI USER_NonClientButtonDraw( HWND hwnd, HDC hdc, enum NONCLIENT_BUTTON_TYPE type, + RECT rect, BOOL down, BOOL grayed ) +{ + switch (type) + { + case MENU_CLOSE_BUTTON: + case MENU_MIN_BUTTON: + case MENU_MAX_BUTTON: + case MENU_RESTORE_BUTTON: + case MENU_HELP_BUTTON: + user_draw_mdi_button( hdc, type, rect, down, grayed ); + return; + } +} diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 963f07b70ef..0ddbd710b6b 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -104,6 +104,13 @@ static NTSTATUS WINAPI User32CopyImage( const struct copy_image_params *params, return HandleToUlong( ret ); }
+static NTSTATUS WINAPI User32DrawNonClientButton( const struct draw_non_client_button_params *params, ULONG size ) +{ + user_api->pNonClientButtonDraw( params->hwnd, params->hdc, params->type, params->rect, + params->down, params->grayed ); + return 0; +} + static NTSTATUS WINAPI User32DrawScrollBar( const struct draw_scroll_bar_params *params, ULONG size ) { RECT rect = params->rect; @@ -200,6 +207,7 @@ static const void *kernel_callback_table[NtUserCallCount] = User32CallWindowProc, User32CallWindowsHook, User32CopyImage, + User32DrawNonClientButton, User32DrawScrollBar, User32DrawText, User32FreeCachedClipboardData, diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index f4169ebb642..430ac826f7e 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -158,6 +158,7 @@ extern BOOL get_icon_size( HICON handle, SIZE *size ) DECLSPEC_HIDDEN; extern struct user_api_hook *user_api DECLSPEC_HIDDEN; LRESULT WINAPI USER_DefDlgProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HIDDEN; LRESULT WINAPI USER_ScrollBarProc(HWND, UINT, WPARAM, LPARAM, BOOL) DECLSPEC_HIDDEN; +void WINAPI USER_NonClientButtonDraw(HWND, HDC, enum NONCLIENT_BUTTON_TYPE, RECT, BOOL, BOOL) DECLSPEC_HIDDEN; void WINAPI USER_ScrollBarDraw(HWND, HDC, INT, enum SCROLL_HITTEST, const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, UINT, INT, INT, INT, BOOL) DECLSPEC_HIDDEN; diff --git a/dlls/uxtheme/Makefile.in b/dlls/uxtheme/Makefile.in index 933650f4261..e4727e08fc8 100644 --- a/dlls/uxtheme/Makefile.in +++ b/dlls/uxtheme/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ scrollbar.c \ stylemap.c \ system.c \ - uxini.c + uxini.c \ + window.c
RC_SRCS = version.rc diff --git a/dlls/uxtheme/system.c b/dlls/uxtheme/system.c index c7ae319da28..25f495d29f3 100644 --- a/dlls/uxtheme/system.c +++ b/dlls/uxtheme/system.c @@ -1245,6 +1245,7 @@ BOOL WINAPI ThemeHooksInstall(void) struct user_api_hook hooks;
hooks.pDefDlgProc = UXTHEME_DefDlgProc; + hooks.pNonClientButtonDraw = UXTHEME_NonClientButtonDraw; hooks.pScrollBarDraw = UXTHEME_ScrollBarDraw; hooks.pScrollBarWndProc = UXTHEME_ScrollbarWndProc; return RegisterUserApiHook(&hooks, &user_api); diff --git a/dlls/uxtheme/uxthemedll.h b/dlls/uxtheme/uxthemedll.h index 85b834e20e8..7abc2a58144 100644 --- a/dlls/uxtheme/uxthemedll.h +++ b/dlls/uxtheme/uxthemedll.h @@ -107,6 +107,8 @@ extern void UXTHEME_UninitSystem(void) DECLSPEC_HIDDEN;
extern struct user_api_hook user_api DECLSPEC_HIDDEN; LRESULT WINAPI UXTHEME_DefDlgProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL unicode) DECLSPEC_HIDDEN; +void WINAPI UXTHEME_NonClientButtonDraw(HWND hwnd, HDC hdc, enum NONCLIENT_BUTTON_TYPE type, + RECT rect, BOOL down, BOOL grayed) DECLSPEC_HIDDEN; void WINAPI UXTHEME_ScrollBarDraw(HWND hwnd, HDC dc, INT bar, enum SCROLL_HITTEST hit_test, const struct SCROLL_TRACKING_INFO *tracking_info, BOOL draw_arrows, BOOL draw_interior, RECT *rect, UINT enable_flags, diff --git a/dlls/uxtheme/window.c b/dlls/uxtheme/window.c new file mode 100644 index 00000000000..d94bd8425c7 --- /dev/null +++ b/dlls/uxtheme/window.c @@ -0,0 +1,32 @@ +/* + * Window theming support + * + * Copyright 2022 Zhiyi Zhang for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "uxthemedll.h" + +void WINAPI UXTHEME_NonClientButtonDraw(HWND hwnd, HDC hdc, enum NONCLIENT_BUTTON_TYPE type, + RECT rect, BOOL down, BOOL grayed) +{ + user_api.pNonClientButtonDraw(hwnd, hdc, type, rect, down, grayed); +} diff --git a/dlls/win32u/defwnd.c b/dlls/win32u/defwnd.c index e26e68442ab..eb5881a00a1 100644 --- a/dlls/win32u/defwnd.c +++ b/dlls/win32u/defwnd.c @@ -1351,6 +1351,22 @@ BOOL draw_frame_caption( HDC dc, RECT *r, UINT flags ) return TRUE; }
+BOOL draw_menu_button( HWND hwnd, HDC dc, RECT *r, enum NONCLIENT_BUTTON_TYPE type, BOOL down, + BOOL grayed ) +{ + struct draw_non_client_button_params params; + void *ret_ptr; + ULONG ret_len; + + params.hwnd = hwnd; + params.hdc = dc; + params.type = type; + params.rect = *r; + params.down = down; + params.grayed = grayed; + return KeUserModeCallback( NtUserDrawNonClientButton, ¶ms, sizeof(params), &ret_ptr, &ret_len ); +} + BOOL draw_frame_menu( HDC dc, RECT *r, UINT flags ) { RECT rect; diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index ff11fbb804a..0ff6d9c1fc2 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -2221,7 +2221,7 @@ static void draw_popup_arrow( HDC hdc, RECT rect, UINT arrow_width, UINT arrow_h NtGdiDeleteObjectApp( mem_hdc ); }
-static void draw_bitmap_item( HDC hdc, struct menu_item *item, const RECT *rect, +static void draw_bitmap_item( HWND hwnd, HDC hdc, struct menu_item *item, const RECT *rect, struct menu *menu, HWND owner, UINT odaction ) { int w = rect->right - rect->left; @@ -2236,7 +2236,8 @@ static void draw_bitmap_item( HDC hdc, struct menu_item *item, const RECT *rect, /* Check if there is a magic menu item associated with this item */ if (IS_MAGIC_BITMAP( bmp_to_draw )) { - UINT flags = 0; + BOOL down = FALSE, grayed = FALSE; + enum NONCLIENT_BUTTON_TYPE type; WCHAR bmchr = 0; RECT r;
@@ -2262,19 +2263,21 @@ static void draw_bitmap_item( HDC hdc, struct menu_item *item, const RECT *rect, } goto got_bitmap; case (INT_PTR)HBMMENU_MBAR_RESTORE: - flags = DFCS_CAPTIONRESTORE; + type = MENU_RESTORE_BUTTON; break; case (INT_PTR)HBMMENU_MBAR_MINIMIZE: - flags = DFCS_CAPTIONMIN; + type = MENU_MIN_BUTTON; break; case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D: - flags = DFCS_CAPTIONMIN | DFCS_INACTIVE; + type = MENU_MIN_BUTTON; + grayed = TRUE; break; case (INT_PTR)HBMMENU_MBAR_CLOSE: - flags = DFCS_CAPTIONCLOSE; + type = MENU_CLOSE_BUTTON; break; case (INT_PTR)HBMMENU_MBAR_CLOSE_D: - flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE; + type = MENU_CLOSE_BUTTON; + grayed = TRUE; break; case (INT_PTR)HBMMENU_CALLBACK: { @@ -2333,8 +2336,8 @@ static void draw_bitmap_item( HDC hdc, struct menu_item *item, const RECT *rect, { r = *rect; InflateRect( &r, -1, -1 ); - if (item->fState & MF_HILITE) flags |= DFCS_PUSHED; - draw_frame_caption( hdc, &r, flags ); + if (item->fState & MF_HILITE) down = TRUE; + draw_menu_button( hwnd, hdc, &r, type, down, grayed ); } return; } @@ -2605,7 +2608,7 @@ static void draw_menu_item( HWND hwnd, struct menu *menu, HWND owner, HDC hdc, POINT origorg; /* some applications make this assumption on the DC's origin */ set_viewport_org( hdc, rect.left, rect.top, &origorg ); - draw_bitmap_item( hdc, item, &bmprc, menu, owner, odaction ); + draw_bitmap_item( hwnd, hdc, item, &bmprc, menu, owner, odaction ); set_viewport_org( hdc, origorg.x, origorg.y, NULL ); } /* Draw the popup-menu arrow */ @@ -2621,7 +2624,7 @@ static void draw_menu_item( HWND hwnd, struct menu *menu, HWND owner, HDC hdc, POINT origorg;
set_viewport_org( hdc, rect.left, rect.top, &origorg); - draw_bitmap_item( hdc, item, &bmprc, menu, owner, odaction ); + draw_bitmap_item( hwnd, hdc, item, &bmprc, menu, owner, odaction ); set_viewport_org( hdc, origorg.x, origorg.y, NULL); } /* process text if present */ diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 4be068b968d..e8ff02ffb75 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -241,7 +241,7 @@ extern void register_window_surface( struct window_surface *old, extern LRESULT default_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, BOOL ansi ) DECLSPEC_HIDDEN; extern LRESULT desktop_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) DECLSPEC_HIDDEN; -extern BOOL draw_frame_caption( HDC dc, LPRECT r, UINT uFlags ) DECLSPEC_HIDDEN; +extern BOOL draw_menu_button( HWND hwnd, HDC dc, RECT *r, enum NONCLIENT_BUTTON_TYPE, BOOL down, BOOL grayed ) DECLSPEC_HIDDEN; extern BOOL draw_frame_menu( HDC dc, RECT *r, UINT flags ) DECLSPEC_HIDDEN; extern BOOL draw_nc_sys_button( HWND hwnd, HDC hdc, BOOL down ) DECLSPEC_HIDDEN; extern BOOL draw_rect_edge( HDC hdc, RECT *rc, UINT uType, UINT uFlags, UINT width ) DECLSPEC_HIDDEN; diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index e1454347ecf..3b4115a700c 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -770,6 +770,28 @@ static NTSTATUS WINAPI wow64_NtUserCopyImage( void *arg, ULONG size ) return dispatch_callback( NtUserCopyImage, ¶ms32, sizeof(params32) ); }
+static NTSTATUS WINAPI wow64_NtUserDrawNonClientButton( void *arg, ULONG size ) +{ + struct draw_non_client_button_params *params = arg; + struct + { + ULONG hwnd; + ULONG hdc; + enum NONCLIENT_BUTTON_TYPE type; + RECT rect; + BOOL down; + BOOL grayed; + } params32; + + params32.hwnd = HandleToUlong( params->hwnd ); + params32.hdc = HandleToUlong( params->hdc ); + params32.type = params->type; + params32.rect = params->rect; + params32.down = params->down; + params32.grayed = params->grayed; + return dispatch_callback( NtUserDrawNonClientButton, ¶ms32, sizeof(params32) ); +} + static NTSTATUS WINAPI wow64_NtUserDrawScrollBar( void *arg, ULONG size ) { struct draw_scroll_bar_params *params = arg; @@ -1067,6 +1089,7 @@ user_callback user_callbacks[] = wow64_NtUserCallWinProc, wow64_NtUserCallWindowsHook, wow64_NtUserCopyImage, + wow64_NtUserDrawNonClientButton, wow64_NtUserDrawScrollBar, wow64_NtUserDrawText, wow64_NtUserFreeCachedClipboardData, diff --git a/include/ntuser.h b/include/ntuser.h index 7759f2b3174..9e1df9a836d 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -34,6 +34,7 @@ enum NtUserCallWinProc, NtUserCallWindowsHook, NtUserCopyImage, + NtUserDrawNonClientButton, NtUserDrawScrollBar, NtUserDrawText, NtUserFreeCachedClipboardData, @@ -418,6 +419,17 @@ struct set_clipboard_params UINT seqno; };
+/* NtUserNonClientButton params */ +struct draw_non_client_button_params +{ + HWND hwnd; + HDC hdc; + enum NONCLIENT_BUTTON_TYPE type; + RECT rect; + BOOL down; + BOOL grayed; +}; + /* NtUserDrawScrollBar params */ struct draw_scroll_bar_params { diff --git a/include/winuser.h b/include/winuser.h index 2f4afffb8a3..a82a6ec26c5 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -4789,9 +4789,19 @@ struct SCROLL_TRACKING_INFO enum SCROLL_HITTEST hit_test; /* Hit Test code of the last button-down event */ };
+enum NONCLIENT_BUTTON_TYPE +{ + MENU_CLOSE_BUTTON, /* Menu close button */ + MENU_MIN_BUTTON, /* Menu min button */ + MENU_MAX_BUTTON, /* Menu max button */ + MENU_RESTORE_BUTTON, /* Menu restore button */ + MENU_HELP_BUTTON, /* Menu help button */ +}; + struct user_api_hook { LRESULT (WINAPI *pDefDlgProc)(HWND, UINT, WPARAM, LPARAM, BOOL); + void (WINAPI *pNonClientButtonDraw)(HWND, HDC, enum NONCLIENT_BUTTON_TYPE, RECT, BOOL, BOOL); void (WINAPI *pScrollBarDraw)(HWND, HDC, INT, enum SCROLL_HITTEST, const struct SCROLL_TRACKING_INFO *, BOOL, BOOL, RECT *, UINT, INT, INT, INT, BOOL);