1 From 642881270d9d997440df594a1bd1d080ca5b5aad Mon Sep 17 00:00:00 2001
2 From: Vincent Povirk <vincent@codeweavers.com>
3 Date: Mon, 25 Aug 2008 08:39:06 -0500
4 Subject: [PATCH] explorer: add a window switcher (tasklist) to the taskbar
7 programs/explorer/Makefile.in | 3 +-
8 programs/explorer/desktop.c | 3 +
9 programs/explorer/explorer_private.h | 7 +-
10 programs/explorer/systray.c | 14 +-
11 programs/explorer/taskbar.c | 17 ++-
12 programs/explorer/tasklist.c | 339 ++++++++++++++++++++++++++++++++++
13 6 files changed, 373 insertions(+), 10 deletions(-)
14 create mode 100644 programs/explorer/tasklist.c
16 diff --git a/programs/explorer/Makefile.in b/programs/explorer/Makefile.in
17 index f2fc10a..99500b9 100644
18 --- a/programs/explorer/Makefile.in
19 +++ b/programs/explorer/Makefile.in
20 @@ -14,7 +14,8 @@ C_SRCS = \
30 diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
31 index 3518603..b9345f4 100644
32 --- a/programs/explorer/desktop.c
33 +++ b/programs/explorer/desktop.c
34 @@ -369,6 +369,9 @@ void manage_desktop( WCHAR *arg )
35 while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg );
36 WINE_TRACE( "desktop message loop exiting for hwnd %p\n", hwnd );
44 diff --git a/programs/explorer/explorer_private.h b/programs/explorer/explorer_private.h
45 index 22bc009..c6f3b09 100644
46 --- a/programs/explorer/explorer_private.h
47 +++ b/programs/explorer/explorer_private.h
50 extern void manage_desktop( WCHAR *arg );
51 extern HWND initialize_systray(HWND parent);
52 -extern void initialize_taskbar(void);
53 extern void initialize_appbar(void);
55 +extern void initialize_taskbar(void);
56 +extern void finalize_taskbar(void);
58 extern void do_startmenu(HWND hwnd, HWND button);
59 extern LRESULT handle_menu(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
60 +extern HWND initialize_tasklist(HWND parent);
61 +extern void finalize_tasklist(void);
63 #endif /* __WINE_EXPLORER_PRIVATE_H */
64 diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c
65 index 35443e2..546b175 100644
66 --- a/programs/explorer/systray.c
67 +++ b/programs/explorer/systray.c
68 @@ -61,7 +61,7 @@ static BOOL hide_systray;
69 static HWND parent_window;
70 static int icon_cx, icon_cy;
72 -#define MIN_DISPLAYED (parent_window?0:8)
73 +#define MIN_DISPLAYED 8
76 /* Retrieves icon record by owner window and ID */
77 @@ -84,9 +84,13 @@ static SIZE get_window_size(void)
81 - rect.right = icon_cx * max( nb_displayed, MIN_DISPLAYED );
83 + rect.right = icon_cy * nb_displayed;
85 + rect.right = icon_cx * max( nb_displayed, MIN_DISPLAYED );
86 rect.bottom = icon_cy;
87 - AdjustWindowRect( &rect, WS_CAPTION, FALSE );
89 + AdjustWindowRect( &rect, WS_CAPTION, FALSE );
90 size.cx = rect.right - rect.left;
91 size.cy = rect.bottom - rect.top;
93 @@ -204,7 +208,7 @@ static BOOL show_icon(struct icon *icon)
94 update_tooltip_position( icon );
95 invalidate_icons( nb_displayed-1, nb_displayed-1 );
97 - if (nb_displayed > MIN_DISPLAYED)
98 + if (parent_window || nb_displayed > MIN_DISPLAYED)
100 SIZE size = get_window_size();
101 SetWindowPos( tray_window, 0, 0, 0, size.cx, size.cy, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
102 @@ -238,7 +242,7 @@ static BOOL hide_icon(struct icon *icon)
103 invalidate_icons( icon->display, nb_displayed );
106 - if (nb_displayed >= MIN_DISPLAYED)
107 + if (parent_window || nb_displayed >= MIN_DISPLAYED)
109 SIZE size = get_window_size();
110 SetWindowPos( tray_window, 0, 0, 0, size.cx, size.cy, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
111 diff --git a/programs/explorer/taskbar.c b/programs/explorer/taskbar.c
112 index aa443d6..0a7becf 100644
113 --- a/programs/explorer/taskbar.c
114 +++ b/programs/explorer/taskbar.c
115 @@ -30,6 +30,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(explorer);
117 static HWND taskbar_window;
118 static HWND systray_window;
119 +static HWND tasklist_window;
120 static HWND startbutton;
122 static void taskbar_setpos(void)
123 @@ -62,6 +63,8 @@ static void taskbar_setpos(void)
124 GetWindowRect(systray_window, &rc);
126 SetWindowPos(systray_window, HWND_TOP, abd.rc.right - abd.rc.left - (rc.right - rc.left), 1, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
128 + MoveWindow(tasklist_window, 76, 1, abd.rc.right - abd.rc.left - (rc.right - rc.left) - 80, 24, TRUE);
131 static LRESULT WINAPI taskbar_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
132 @@ -196,19 +199,27 @@ void initialize_taskbar(void)
134 systray_window = initialize_systray(taskbar_window);
138 initcomctl.dwSize = sizeof(initcomctl);
139 initcomctl.dwICC = ICC_STANDARD_CLASSES;
140 InitCommonControlsEx(&initcomctl);
143 /* FIXME: make the caption translateable */
144 startbutton = CreateWindowA( "Button", "Start", WS_CHILD|BS_PUSHBUTTON, 0, 1, 72, 24,
145 taskbar_window, 0, 0, 0);
147 + tasklist_window = initialize_tasklist(taskbar_window);
151 ShowWindow(systray_window, SW_SHOW);
152 ShowWindow(startbutton, SW_SHOW);
153 ShowWindow(taskbar_window, SW_SHOW);
156 +void finalize_taskbar(void)
158 + finalize_tasklist();
160 + DestroyWindow(taskbar_window);
163 diff --git a/programs/explorer/tasklist.c b/programs/explorer/tasklist.c
165 index 0000000..3aca53b
167 +++ b/programs/explorer/tasklist.c
170 + * Copyright (C) 2008 Vincent Povirk for CodeWeavers
172 + * This library is free software; you can redistribute it and/or
173 + * modify it under the terms of the GNU Lesser General Public
174 + * License as published by the Free Software Foundation; either
175 + * version 2.1 of the License, or (at your option) any later version.
177 + * This library is distributed in the hope that it will be useful,
178 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
179 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
180 + * Lesser General Public License for more details.
182 + * You should have received a copy of the GNU Lesser General Public
183 + * License along with this library; if not, write to the Free Software
184 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
188 +#include <windows.h>
189 +#include <commctrl.h>
190 +#include <wine/debug.h>
192 +WINE_DEFAULT_DEBUG_CHANNEL(explorer);
194 +static HWND tasklist;
196 +static WCHAR classname[] = {'t','a','s','k','l','i','s','t',0};
198 +struct toplevel_window
206 +static struct toplevel_window *toplevels=NULL;
207 +static int toplevels_len = 0; /* number of top-level windows in toplevels[] */
208 +static int toplevels_size = 0; /* amount of allocated memory in toplevels[] */
212 +#define MAX_BUTTON_WIDTH 150
213 +static int button_width = 0;
215 +/* get the index of a window in the toplevels list; this can change */
216 +static int get_toplevel(HWND hwnd)
220 + for (i=0; i<toplevels_len; i++)
222 + if (toplevels[i].hwnd == hwnd)
229 +static void refresh_buttons(void)
234 + if (toplevels_len == 0)
237 + GetWindowRect(tasklist, &rc);
239 + button_width = min(MAX_BUTTON_WIDTH, (rc.right - rc.left) / toplevels_len);
241 + for (i=0; i<toplevels_len; i++)
243 + SetWindowLongPtrW(toplevels[i].button, GWLP_ID, i);
245 + MoveWindow(toplevels[i].button, button_width*i, 0, button_width, (rc.bottom - rc.top), TRUE);
249 +static void update_window_caption(int index)
254 + length = GetWindowTextLengthW(toplevels[index].hwnd);
256 + caption = HeapAlloc(GetProcessHeap(), 0, (length+1)*sizeof(WCHAR));
257 + if (length == 0 || !GetWindowTextW(toplevels[index].hwnd, caption, length+1))
260 + SetWindowTextW(toplevels[index].button, caption);
263 +/* add a window to the list and return its index */
264 +static int add_hwnd(HWND hwnd)
267 + static const WCHAR buttonW[] = {'B','u','t','t','o','n',0};
269 + if (toplevels_len == toplevels_size)
271 + toplevels = HeapReAlloc(GetProcessHeap(), 0, toplevels, sizeof(struct toplevel_window)*toplevels_size+10);
273 + WINE_ERR("Out of memory\n");
274 + toplevels_size = HeapSize(GetProcessHeap(), 0, toplevels) / sizeof(struct toplevel_window);
277 + WINE_TRACE("adding %p to task list\n", hwnd);
279 + result = toplevels_len;
281 + toplevels[result].hwnd = hwnd;
283 + toplevels[result].button = CreateWindowW(buttonW, buttonW, WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_LEFT, 0, 0, 0, 0, tasklist, (HMENU)result, NULL, NULL);
285 + toplevels[result].caption = NULL;
287 + update_window_caption(result);
294 +/* Called before a window is removed from the list.
296 + * If several windows are being removed at once, the structure at *toplevel may
297 + * not be at the given index in toplevels. The index given is where it would be
298 + * just before it is removed if we were removing each item individually.
300 +static void removing_window(int index, struct toplevel_window* toplevel)
302 + WINE_TRACE("removing %p from task list\n", toplevel->hwnd);
304 + DestroyWindow(toplevel->button);
306 + HeapFree(GetProcessHeap(), 0, toplevel->caption);
310 +static void del_window(int window)
312 + removing_window(window);
316 + if (toplevels_len != window)
317 + MoveMemory(&toplevels[window], &toplevels[window+1], sizeof(struct toplevel_window) * (toplevels_len - window));
321 +static void cull_windows()
324 + BOOL needs_refresh=FALSE;
327 + for (i=0; i<toplevels_len; i++)
329 + if (toplevels[i].still_alive)
332 + CopyMemory(&toplevels[j], &toplevels[i], sizeof(struct toplevel_window));
338 + removing_window(j, &toplevels[i]);
339 + needs_refresh = TRUE;
349 +static void foreground_changed(HWND new_foreground)
353 + i = get_toplevel(foreground);
355 + SendMessageW(toplevels[i].button, BM_SETSTATE, (WPARAM)BST_UNCHECKED, 0);
357 + i = get_toplevel(new_foreground);
359 + SendMessageW(toplevels[i].button, BM_SETSTATE, (WPARAM)BST_PUSHED, 0);
361 + foreground = new_foreground;
364 +static BOOL CALLBACK handle_enumwindow(HWND hwnd, LPARAM lparam)
369 + if (GetWindow(hwnd, GW_OWNER))
372 + wi.cbSize = sizeof(wi);
373 + if (!GetWindowInfo(hwnd, &wi))
376 + if (wi.dwExStyle & WS_EX_TOOLWINDOW || !(wi.dwStyle & WS_VISIBLE))
379 + if ((window = get_toplevel(hwnd)) == -1)
381 + window = add_hwnd(hwnd);
385 + update_window_caption(window);
388 + toplevels[window].still_alive = TRUE;
393 +/* update the window list using a blunt object */
394 +static void do_polling(void)
397 + HWND new_foreground, parent;
399 + /* mark all top-level windows as dead */
400 + for (i=0; i<toplevels_len; i++)
401 + toplevels[i].still_alive = FALSE;
403 + /* mark the alive ones as still alive, and add any new ones */
404 + EnumWindows(handle_enumwindow, 0);
406 + /* remove dead windows */
409 + new_foreground = GetForegroundWindow();
410 + while ((parent = GetParent(new_foreground)))
411 + new_foreground = parent;
412 + if (foreground != new_foreground)
413 + foreground_changed(new_foreground);
416 +static void handle_click(int index)
418 + HWND hwnd=toplevels[index].hwnd;
419 + LONG_PTR style = GetWindowLongPtrW(hwnd, GWL_STYLE);
421 + if (hwnd == foreground && !(style & WS_MINIMIZE))
423 + ShowWindow(hwnd, SW_SHOWMINNOACTIVE); /* MSDN suggests that SW_FORCEMINIMIZE is
424 + more appropriate, but it seems to make them vanish on Windows.. */
425 + foreground_changed(0);
429 + SetForegroundWindow(hwnd);
430 + if (style & WS_MAXIMIZE)
431 + ShowWindow(hwnd, SW_SHOWMAXIMIZED);
433 + ShowWindow(hwnd, SW_SHOWNORMAL);
434 + foreground_changed(hwnd);
438 +static LRESULT WINAPI tasklist_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
449 + switch (HIWORD(wparam))
452 + handle_click(LOWORD(wparam));
458 + return DefWindowProcW(hwnd, msg, wparam, lparam);
461 +HWND initialize_tasklist(HWND parent)
465 + ZeroMemory(&class, sizeof(class));
466 + class.cbSize = sizeof(class);
467 + class.style = CS_DBLCLKS;
468 + class.lpfnWndProc = tasklist_wndproc;
469 + class.hInstance = NULL;
470 + class.hIcon = LoadIconW(0, (LPCWSTR)IDI_WINLOGO);
471 + class.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
472 + class.hbrBackground = (HBRUSH) COLOR_WINDOW;
473 + class.lpszClassName = (WCHAR *) &classname;
475 + if (!RegisterClassExW(&class))
477 + WINE_ERR("Couldn't register tasklist class\n");
481 + tasklist = CreateWindowExW(0, classname, classname, WS_CHILD|WS_VISIBLE, 73, 1, 100, 24, parent, NULL, NULL, NULL);
484 + WINE_ERR("Couldn't create tasklist window\n");
488 + toplevels = HeapAlloc(GetProcessHeap(), 0, sizeof(struct toplevel_window)*10);
491 + WINE_ERR("Out of memory\n");
494 + toplevels_size = HeapSize(GetProcessHeap(), 0, toplevels) / sizeof(struct toplevel_window);
496 + SetTimer(tasklist, 0, 1500, NULL);
501 +void finalize_tasklist(void)
503 + DestroyWindow(tasklist);
505 + HeapFree(GetProcessHeap(), 0, toplevels);