Update wine to 1.2.
[sugaredwine.git] / patches / 0009-explorer-add-a-window-switcher-tasklist-to-the-ta.patch
blob3607cc2f1c3973b9d8508f73b6d0139dcc1e5ad1
1 From 2718b0d7ecb5b054570c0cc37575ab796a9e86ae 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
6 ---
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 55626f8..899e668 100644
18 --- a/programs/explorer/Makefile.in
19 +++ b/programs/explorer/Makefile.in
20 @@ -14,6 +14,7 @@ C_SRCS = \
21 explorer.c \
22 startmenu.c \
23 systray.c \
24 - taskbar.c
25 + taskbar.c \
26 + tasklist.c
28 @MAKE_PROG_RULES@
29 diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c
30 index f5a268a..3741315 100644
31 --- a/programs/explorer/desktop.c
32 +++ b/programs/explorer/desktop.c
33 @@ -379,6 +379,9 @@ void manage_desktop( WCHAR *arg )
34 while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg );
35 WINE_TRACE( "desktop message loop exiting for hwnd %p\n", hwnd );
38 + if (using_root)
39 + finalize_taskbar();
41 ExitProcess( 0 );
43 diff --git a/programs/explorer/explorer_private.h b/programs/explorer/explorer_private.h
44 index 22bc009..c6f3b09 100644
45 --- a/programs/explorer/explorer_private.h
46 +++ b/programs/explorer/explorer_private.h
47 @@ -23,9 +23,14 @@
49 extern void manage_desktop( WCHAR *arg );
50 extern HWND initialize_systray(HWND parent);
51 -extern void initialize_taskbar(void);
52 extern void initialize_appbar(void);
54 +extern void initialize_taskbar(void);
55 +extern void finalize_taskbar(void);
57 extern void do_startmenu(HWND hwnd, HWND button);
58 extern LRESULT handle_menu(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
59 +extern HWND initialize_tasklist(HWND parent);
60 +extern void finalize_tasklist(void);
62 #endif /* __WINE_EXPLORER_PRIVATE_H */
63 diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c
64 index 286aa08..ba55c78 100644
65 --- a/programs/explorer/systray.c
66 +++ b/programs/explorer/systray.c
67 @@ -85,7 +85,7 @@ static BOOL hide_systray;
68 static HWND parent_window;
69 static int icon_cx, icon_cy;
71 -#define MIN_DISPLAYED (parent_window?0:8)
72 +#define MIN_DISPLAYED 8
73 #define ICON_BORDER 2
75 /* Retrieves icon record by owner window and ID */
76 @@ -108,9 +108,13 @@ static SIZE get_window_size(void)
78 rect.left = 0;
79 rect.top = 0;
80 - rect.right = icon_cx * max( nb_displayed, MIN_DISPLAYED );
81 + if (parent_window)
82 + rect.right = icon_cy * nb_displayed;
83 + else
84 + rect.right = icon_cx * max( nb_displayed, MIN_DISPLAYED );
85 rect.bottom = icon_cy;
86 - AdjustWindowRect( &rect, WS_CAPTION, FALSE );
87 + if (!parent_window)
88 + AdjustWindowRect( &rect, WS_CAPTION, FALSE );
89 size.cx = rect.right - rect.left;
90 size.cy = rect.bottom - rect.top;
91 return size;
92 @@ -228,7 +232,7 @@ static BOOL show_icon(struct icon *icon)
93 update_tooltip_position( icon );
94 invalidate_icons( nb_displayed-1, nb_displayed-1 );
96 - if (nb_displayed > MIN_DISPLAYED)
97 + if (parent_window || nb_displayed > MIN_DISPLAYED)
99 SIZE size = get_window_size();
100 SetWindowPos( tray_window, 0, 0, 0, size.cx, size.cy, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
101 @@ -262,7 +266,7 @@ static BOOL hide_icon(struct icon *icon)
102 invalidate_icons( icon->display, nb_displayed );
103 icon->display = -1;
105 - if (nb_displayed >= MIN_DISPLAYED)
106 + if (parent_window || nb_displayed >= MIN_DISPLAYED)
108 SIZE size = get_window_size();
109 SetWindowPos( tray_window, 0, 0, 0, size.cx, size.cy, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
110 diff --git a/programs/explorer/taskbar.c b/programs/explorer/taskbar.c
111 index aa443d6..0a7becf 100644
112 --- a/programs/explorer/taskbar.c
113 +++ b/programs/explorer/taskbar.c
114 @@ -30,6 +30,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(explorer);
116 static HWND taskbar_window;
117 static HWND systray_window;
118 +static HWND tasklist_window;
119 static HWND startbutton;
121 static void taskbar_setpos(void)
122 @@ -62,6 +63,8 @@ static void taskbar_setpos(void)
123 GetWindowRect(systray_window, &rc);
125 SetWindowPos(systray_window, HWND_TOP, abd.rc.right - abd.rc.left - (rc.right - rc.left), 1, 0, 0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
127 + MoveWindow(tasklist_window, 76, 1, abd.rc.right - abd.rc.left - (rc.right - rc.left) - 80, 24, TRUE);
130 static LRESULT WINAPI taskbar_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
131 @@ -196,19 +199,27 @@ void initialize_taskbar(void)
133 systray_window = initialize_systray(taskbar_window);
135 - taskbar_setpos();
137 initcomctl.dwSize = sizeof(initcomctl);
138 initcomctl.dwICC = ICC_STANDARD_CLASSES;
139 InitCommonControlsEx(&initcomctl);
142 /* FIXME: make the caption translateable */
143 startbutton = CreateWindowA( "Button", "Start", WS_CHILD|BS_PUSHBUTTON, 0, 1, 72, 24,
144 taskbar_window, 0, 0, 0);
146 + tasklist_window = initialize_tasklist(taskbar_window);
148 + taskbar_setpos();
150 ShowWindow(systray_window, SW_SHOW);
151 ShowWindow(startbutton, SW_SHOW);
152 ShowWindow(taskbar_window, SW_SHOW);
155 +void finalize_taskbar(void)
157 + finalize_tasklist();
159 + DestroyWindow(taskbar_window);
162 diff --git a/programs/explorer/tasklist.c b/programs/explorer/tasklist.c
163 new file mode 100644
164 index 0000000..3aca53b
165 --- /dev/null
166 +++ b/programs/explorer/tasklist.c
167 @@ -0,0 +1,339 @@
169 + * Copyright (C) 2008 Vincent Povirk for CodeWeavers
171 + * This library is free software; you can redistribute it and/or
172 + * modify it under the terms of the GNU Lesser General Public
173 + * License as published by the Free Software Foundation; either
174 + * version 2.1 of the License, or (at your option) any later version.
176 + * This library is distributed in the hope that it will be useful,
177 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
178 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
179 + * Lesser General Public License for more details.
181 + * You should have received a copy of the GNU Lesser General Public
182 + * License along with this library; if not, write to the Free Software
183 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
184 + */
186 +#define UNICODE
187 +#include <windows.h>
188 +#include <commctrl.h>
189 +#include <wine/debug.h>
191 +WINE_DEFAULT_DEBUG_CHANNEL(explorer);
193 +static HWND tasklist;
195 +static WCHAR classname[] = {'t','a','s','k','l','i','s','t',0};
197 +struct toplevel_window
199 + HWND hwnd;
200 + BOOL still_alive;
201 + HWND button;
202 + LPWSTR caption;
205 +static struct toplevel_window *toplevels=NULL;
206 +static int toplevels_len = 0; /* number of top-level windows in toplevels[] */
207 +static int toplevels_size = 0; /* amount of allocated memory in toplevels[] */
209 +HWND foreground;
211 +#define MAX_BUTTON_WIDTH 150
212 +static int button_width = 0;
214 +/* get the index of a window in the toplevels list; this can change */
215 +static int get_toplevel(HWND hwnd)
217 + int i;
219 + for (i=0; i<toplevels_len; i++)
221 + if (toplevels[i].hwnd == hwnd)
222 + return i;
225 + return -1;
228 +static void refresh_buttons(void)
230 + int i;
231 + RECT rc;
233 + if (toplevels_len == 0)
234 + return;
236 + GetWindowRect(tasklist, &rc);
238 + button_width = min(MAX_BUTTON_WIDTH, (rc.right - rc.left) / toplevels_len);
240 + for (i=0; i<toplevels_len; i++)
242 + SetWindowLongPtrW(toplevels[i].button, GWLP_ID, i);
244 + MoveWindow(toplevels[i].button, button_width*i, 0, button_width, (rc.bottom - rc.top), TRUE);
248 +static void update_window_caption(int index)
250 + int length;
251 + LPWSTR caption;
253 + length = GetWindowTextLengthW(toplevels[index].hwnd);
255 + caption = HeapAlloc(GetProcessHeap(), 0, (length+1)*sizeof(WCHAR));
256 + if (length == 0 || !GetWindowTextW(toplevels[index].hwnd, caption, length+1))
257 + caption[0] = 0;
259 + SetWindowTextW(toplevels[index].button, caption);
262 +/* add a window to the list and return its index */
263 +static int add_hwnd(HWND hwnd)
265 + int result;
266 + static const WCHAR buttonW[] = {'B','u','t','t','o','n',0};
268 + if (toplevels_len == toplevels_size)
270 + toplevels = HeapReAlloc(GetProcessHeap(), 0, toplevels, sizeof(struct toplevel_window)*toplevels_size+10);
271 + if (!toplevels)
272 + WINE_ERR("Out of memory\n");
273 + toplevels_size = HeapSize(GetProcessHeap(), 0, toplevels) / sizeof(struct toplevel_window);
276 + WINE_TRACE("adding %p to task list\n", hwnd);
278 + result = toplevels_len;
279 + toplevels_len++;
280 + toplevels[result].hwnd = hwnd;
282 + toplevels[result].button = CreateWindowW(buttonW, buttonW, WS_VISIBLE|WS_CHILD|BS_PUSHBUTTON|BS_LEFT, 0, 0, 0, 0, tasklist, (HMENU)result, NULL, NULL);
284 + toplevels[result].caption = NULL;
286 + update_window_caption(result);
288 + refresh_buttons();
290 + return result;
293 +/* Called before a window is removed from the list.
294 + *
295 + * If several windows are being removed at once, the structure at *toplevel may
296 + * not be at the given index in toplevels. The index given is where it would be
297 + * just before it is removed if we were removing each item individually.
298 + */
299 +static void removing_window(int index, struct toplevel_window* toplevel)
301 + WINE_TRACE("removing %p from task list\n", toplevel->hwnd);
303 + DestroyWindow(toplevel->button);
305 + HeapFree(GetProcessHeap(), 0, toplevel->caption);
308 +#if 0
309 +static void del_window(int window)
311 + removing_window(window);
313 + toplevels_len--;
315 + if (toplevels_len != window)
316 + MoveMemory(&toplevels[window], &toplevels[window+1], sizeof(struct toplevel_window) * (toplevels_len - window));
318 +#endif
320 +static void cull_windows()
322 + int i, j;
323 + BOOL needs_refresh=FALSE;
325 + j=0;
326 + for (i=0; i<toplevels_len; i++)
328 + if (toplevels[i].still_alive)
330 + if (i != j)
331 + CopyMemory(&toplevels[j], &toplevels[i], sizeof(struct toplevel_window));
333 + j++;
335 + else
337 + removing_window(j, &toplevels[i]);
338 + needs_refresh = TRUE;
342 + toplevels_len = j;
344 + if (needs_refresh)
345 + refresh_buttons();
348 +static void foreground_changed(HWND new_foreground)
350 + int i;
352 + i = get_toplevel(foreground);
353 + if (i != -1)
354 + SendMessageW(toplevels[i].button, BM_SETSTATE, (WPARAM)BST_UNCHECKED, 0);
356 + i = get_toplevel(new_foreground);
357 + if (i != -1)
358 + SendMessageW(toplevels[i].button, BM_SETSTATE, (WPARAM)BST_PUSHED, 0);
360 + foreground = new_foreground;
363 +static BOOL CALLBACK handle_enumwindow(HWND hwnd, LPARAM lparam)
365 + int window;
366 + WINDOWINFO wi;
368 + if (GetWindow(hwnd, GW_OWNER))
369 + return TRUE;
371 + wi.cbSize = sizeof(wi);
372 + if (!GetWindowInfo(hwnd, &wi))
373 + return TRUE;
375 + if (wi.dwExStyle & WS_EX_TOOLWINDOW || !(wi.dwStyle & WS_VISIBLE))
376 + return TRUE;
378 + if ((window = get_toplevel(hwnd)) == -1)
380 + window = add_hwnd(hwnd);
382 + else
384 + update_window_caption(window);
387 + toplevels[window].still_alive = TRUE;
389 + return TRUE;
392 +/* update the window list using a blunt object */
393 +static void do_polling(void)
395 + int i;
396 + HWND new_foreground, parent;
398 + /* mark all top-level windows as dead */
399 + for (i=0; i<toplevels_len; i++)
400 + toplevels[i].still_alive = FALSE;
402 + /* mark the alive ones as still alive, and add any new ones */
403 + EnumWindows(handle_enumwindow, 0);
405 + /* remove dead windows */
406 + cull_windows();
408 + new_foreground = GetForegroundWindow();
409 + while ((parent = GetParent(new_foreground)))
410 + new_foreground = parent;
411 + if (foreground != new_foreground)
412 + foreground_changed(new_foreground);
415 +static void handle_click(int index)
417 + HWND hwnd=toplevels[index].hwnd;
418 + LONG_PTR style = GetWindowLongPtrW(hwnd, GWL_STYLE);
420 + if (hwnd == foreground && !(style & WS_MINIMIZE))
422 + ShowWindow(hwnd, SW_SHOWMINNOACTIVE); /* MSDN suggests that SW_FORCEMINIMIZE is
423 + more appropriate, but it seems to make them vanish on Windows.. */
424 + foreground_changed(0);
426 + else
428 + SetForegroundWindow(hwnd);
429 + if (style & WS_MAXIMIZE)
430 + ShowWindow(hwnd, SW_SHOWMAXIMIZED);
431 + else
432 + ShowWindow(hwnd, SW_SHOWNORMAL);
433 + foreground_changed(hwnd);
437 +static LRESULT WINAPI tasklist_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
439 + switch (msg)
441 + case WM_TIMER:
442 + do_polling();
443 + return 0;
444 + case WM_SIZE:
445 + refresh_buttons();
446 + return 0;
447 + case WM_COMMAND:
448 + switch (HIWORD(wparam))
450 + case BN_CLICKED:
451 + handle_click(LOWORD(wparam));
452 + break;
454 + break;
457 + return DefWindowProcW(hwnd, msg, wparam, lparam);
460 +HWND initialize_tasklist(HWND parent)
462 + WNDCLASSEXW class;
464 + ZeroMemory(&class, sizeof(class));
465 + class.cbSize = sizeof(class);
466 + class.style = CS_DBLCLKS;
467 + class.lpfnWndProc = tasklist_wndproc;
468 + class.hInstance = NULL;
469 + class.hIcon = LoadIconW(0, (LPCWSTR)IDI_WINLOGO);
470 + class.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
471 + class.hbrBackground = (HBRUSH) COLOR_WINDOW;
472 + class.lpszClassName = (WCHAR *) &classname;
474 + if (!RegisterClassExW(&class))
476 + WINE_ERR("Couldn't register tasklist class\n");
477 + return NULL;
480 + tasklist = CreateWindowExW(0, classname, classname, WS_CHILD|WS_VISIBLE, 73, 1, 100, 24, parent, NULL, NULL, NULL);
481 + if (!tasklist)
483 + WINE_ERR("Couldn't create tasklist window\n");
484 + return NULL;
487 + toplevels = HeapAlloc(GetProcessHeap(), 0, sizeof(struct toplevel_window)*10);
488 + if (!toplevels)
490 + WINE_ERR("Out of memory\n");
491 + return NULL;
493 + toplevels_size = HeapSize(GetProcessHeap(), 0, toplevels) / sizeof(struct toplevel_window);
495 + SetTimer(tasklist, 0, 1500, NULL);
497 + return tasklist;
500 +void finalize_tasklist(void)
502 + DestroyWindow(tasklist);
504 + HeapFree(GetProcessHeap(), 0, toplevels);
508 1.5.6.5