From 446d8321a7388d2a27b9c18064bc489dc8599bbf Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 31 Dec 2003 23:51:52 +0000 Subject: [PATCH] Store window icons in the window structure so that WM_SETICON can do the right thing (based on a patch by Aric Stewart). --- dlls/user/tests/win.c | 63 +++++++++++++++++++++++++++++++++++++++++++ dlls/x11drv/window.c | 16 +++++------ include/user.h | 2 +- include/win.h | 2 ++ windows/defwnd.c | 59 +++++++++++++++++++++++++++++++++------- windows/nonclient.c | 11 +++++++- windows/win.c | 2 ++ 7 files changed, 134 insertions(+), 21 deletions(-) diff --git a/dlls/user/tests/win.c b/dlls/user/tests/win.c index eb7d0532636..e5f65a889df 100644 --- a/dlls/user/tests/win.c +++ b/dlls/user/tests/win.c @@ -845,6 +845,68 @@ static void test_mdi(void) */ } +static void test_icons(void) +{ + WNDCLASSEXA cls; + HWND hwnd; + HICON icon = LoadIconA(0, (LPSTR)IDI_APPLICATION); + HICON icon2 = LoadIconA(0, (LPSTR)IDI_QUESTION); + HICON small_icon = LoadImageA(0, (LPSTR)IDI_APPLICATION, IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED ); + HICON res; + + cls.cbSize = sizeof(cls); + cls.style = 0; + cls.lpfnWndProc = DefWindowProcA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = 0; + cls.hIcon = LoadIconA(0, (LPSTR)IDI_HAND); + cls.hIconSm = small_icon; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "IconWindowClass"; + + RegisterClassExA(&cls); + + hwnd = CreateWindowExA(0, "IconWindowClass", "icon test", 0, + 100, 100, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL); + assert( hwnd ); + + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); + ok( res == 0, "wrong big icon %p/0\n", res ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon ); + ok( res == 0, "wrong previous big icon %p/0\n", res ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); + ok( res == icon, "wrong big icon after set %p/%p\n", res, icon ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 ); + ok( res == icon, "wrong previous big icon %p/%p\n", res, icon ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); + ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); + ok( res == 0, "wrong small icon %p/0\n", res ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res != 0, "wrong small icon %p\n", res ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon ); + ok( res == 0, "wrong previous small icon %p/0\n", res ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); + ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon ); + ok( res == icon, "wrong previous small icon %p/%p\n", res, icon ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); + ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); + + /* make sure the big icon hasn't changed */ + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); + ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); +} + START_TEST(win) { pGetAncestor = (void *)GetProcAddress( GetModuleHandleA("user32.dll"), "GetAncestor" ); @@ -871,6 +933,7 @@ START_TEST(win) test_shell_window(); test_mdi(); + test_icons(); UnhookWindowsHookEx(hhook); } diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c index e35866b6cb2..6f402366ed3 100644 --- a/dlls/x11drv/window.c +++ b/dlls/x11drv/window.c @@ -281,10 +281,9 @@ inline static void destroy_icon_window( Display *display, WND *win ) * * Set the icon wm hints */ -static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints ) +static void set_icon_hints( Display *display, WND *wndPtr, XWMHints *hints, HICON hIcon ) { X11DRV_WND_DATA *data = wndPtr->pDriverData; - HICON hIcon = (HICON)GetClassLongA( wndPtr->hwndSelf, GCL_HICON ); if (data->hWMIconBitmap) DeleteObject( data->hWMIconBitmap ); if (data->hWMIconMask) DeleteObject( data->hWMIconMask); @@ -473,7 +472,7 @@ void X11DRV_set_wm_hints( Display *display, WND *win ) wm_hints->flags = InputHint | StateHint | WindowGroupHint; wm_hints->input = !(win->dwStyle & WS_DISABLED); - set_icon_hints( display, win, wm_hints ); + set_icon_hints( display, win, wm_hints, (HICON)GetClassLongA( win->hwndSelf, GCL_HICON )); wm_hints->initial_state = (win->dwStyle & WS_MINIMIZE) ? IconicState : NormalState; wm_hints->window_group = group_leader; @@ -1312,16 +1311,14 @@ void X11DRV_SetFocus( HWND hwnd ) * This is not entirely correct, may need to create * an icon window and set the pixmap as a background */ -HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small ) +void X11DRV_SetWindowIcon( HWND hwnd, UINT type, HICON icon ) { WND *wndPtr; Display *display = thread_display(); - HICON old = (HICON)SetClassLongW(hwnd, small ? GCL_HICONSM : GCL_HICON, (LONG)icon ); - SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | - SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER ); + if (type != ICON_BIG) return; /* nothing to do here */ - if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return old; + if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return; if (wndPtr->dwExStyle & WS_EX_MANAGED) { @@ -1333,7 +1330,7 @@ HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small ) wine_tsx11_unlock(); if (wm_hints) { - set_icon_hints( display, wndPtr, wm_hints ); + set_icon_hints( display, wndPtr, wm_hints, icon ); wine_tsx11_lock(); XSetWMHints( display, win, wm_hints ); XFree( wm_hints ); @@ -1341,5 +1338,4 @@ HICON X11DRV_SetWindowIcon( HWND hwnd, HICON icon, BOOL small ) } } WIN_ReleasePtr( wndPtr ); - return old; } diff --git a/include/user.h b/include/user.h index f87e0e3d0e4..46756b27825 100644 --- a/include/user.h +++ b/include/user.h @@ -119,7 +119,7 @@ typedef struct tagUSER_DRIVER { HWND (*pSetParent)(HWND,HWND); BOOL (*pSetWindowPos)(WINDOWPOS *); int (*pSetWindowRgn)(HWND,HRGN,BOOL); - HICON (*pSetWindowIcon)(HWND,HICON,BOOL); + void (*pSetWindowIcon)(HWND,UINT,HICON); void (*pSetWindowStyle)(HWND,DWORD); BOOL (*pSetWindowText)(HWND,LPCWSTR); BOOL (*pShowWindow)(HWND,INT); diff --git a/include/win.h b/include/win.h index b403c9f3e49..f18e2d122db 100644 --- a/include/win.h +++ b/include/win.h @@ -61,6 +61,8 @@ typedef struct tagWND DWORD helpContext; /* Help context ID */ UINT flags; /* Misc. flags (see below) */ HMENU hSysMenu; /* window's copy of System Menu */ + HICON hIcon; /* window's icon */ + HICON hIconSmall; /* window's small icon */ int cbWndExtra; /* class cbWndExtra at window creation */ int irefCount; /* window's reference count*/ DWORD userdata; /* User private data */ diff --git a/windows/defwnd.c b/windows/defwnd.c index 9b94149e2ee..77205d1b60e 100644 --- a/windows/defwnd.c +++ b/windows/defwnd.c @@ -653,19 +653,60 @@ static LRESULT DEFWND_DefWinProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPa return 1; case WM_SETICON: - if (USER_Driver.pSetWindowIcon) - return (LRESULT)USER_Driver.pSetWindowIcon( hwnd, (HICON)lParam, (wParam != ICON_SMALL) ); - else - { - HICON hOldIcon = (HICON)SetClassLongW( hwnd, (wParam != ICON_SMALL) ? GCL_HICON : GCL_HICONSM, - lParam); + { + HICON ret; + WND *wndPtr = WIN_GetPtr( hwnd ); + + switch(wParam) + { + case ICON_SMALL: + ret = wndPtr->hIconSmall; + wndPtr->hIconSmall = (HICON)lParam; + break; + case ICON_BIG: + ret = wndPtr->hIcon; + wndPtr->hIcon = (HICON)lParam; + break; + default: + ret = 0; + break; + } + WIN_ReleasePtr( wndPtr ); + + if (USER_Driver.pSetWindowIcon) + USER_Driver.pSetWindowIcon( hwnd, wParam, (HICON)lParam ); + SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER); - return (LRESULT)hOldIcon; - } + + return (LRESULT)ret; + } case WM_GETICON: - return GetClassLongW( hwnd, (wParam != ICON_SMALL) ? GCL_HICON : GCL_HICONSM ); + { + HICON ret; + WND *wndPtr = WIN_GetPtr( hwnd ); + + switch(wParam) + { + case ICON_SMALL: + ret = wndPtr->hIconSmall; + break; + case ICON_BIG: + ret = wndPtr->hIcon; + break; + case ICON_SMALL2: + ret = wndPtr->hIconSmall; + if (!ret) ret = (HICON)GetClassLongA( hwnd, GCL_HICONSM ); + /* FIXME: should have a default here if class icon is null */ + break; + default: + ret = 0; + break; + } + WIN_ReleasePtr( wndPtr ); + return (LRESULT)ret; + } case WM_HELP: SendMessageW( GetParent(hwnd), msg, wParam, lParam ); diff --git a/windows/nonclient.c b/windows/nonclient.c index 0ff1c7e9000..bfd1340634e 100644 --- a/windows/nonclient.c +++ b/windows/nonclient.c @@ -241,7 +241,16 @@ NC_AdjustRectInner95 (LPRECT rect, DWORD style, DWORD exStyle) static HICON NC_IconForWindow( HWND hwnd ) { - HICON hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM ); + HICON hIcon = 0; + WND *wndPtr = WIN_GetPtr( hwnd ); + + if (wndPtr && wndPtr != WND_OTHER_PROCESS) + { + hIcon = wndPtr->hIconSmall; + if (!hIcon) hIcon = wndPtr->hIcon; + WIN_ReleasePtr( wndPtr ); + } + if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM ); if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICON ); /* If there is no hIcon specified and this is a modal dialog, diff --git a/windows/win.c b/windows/win.c index 6dc7baf7a84..9b7eff9b6b0 100644 --- a/windows/win.c +++ b/windows/win.c @@ -1071,6 +1071,8 @@ static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom, wndPtr->pVScroll = NULL; wndPtr->pHScroll = NULL; wndPtr->userdata = 0; + wndPtr->hIcon = 0; + wndPtr->hIconSmall = 0; wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0; /* Correct the window style - stage 2 */