2 * SHAppBarMessage implementation
4 * Copyright 2008 Vincent Povirk for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * TODO: freedesktop _NET_WM_STRUT integration
22 * TODO: find when a fullscreen app is in the foreground and send FULLSCREENAPP
25 * TODO: detect changes in the screen size and send ABN_POSCHANGED ?
27 * TODO: multiple monitor support
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "explorer_private.h"
36 #include "wine/list.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(appbar
);
40 struct appbar_data_msg
/* platform-independent data */
43 UINT uCallbackMessage
;
53 struct appbar_data_msg abd
;
56 struct appbar_response
59 struct appbar_data_msg abd
;
62 static HWND appbarmsg_window
= NULL
;
75 static struct list appbars
= LIST_INIT(appbars
);
77 static struct appbar_data
* get_appbar(HWND hwnd
)
79 struct appbar_data
* data
;
81 LIST_FOR_EACH_ENTRY(data
, &appbars
, struct appbar_data
, entry
)
83 if (data
->hwnd
== hwnd
)
90 /* send_poschanged: send ABN_POSCHANGED to every appbar except one */
91 static void send_poschanged(HWND hwnd
)
93 struct appbar_data
* data
;
94 LIST_FOR_EACH_ENTRY(data
, &appbars
, struct appbar_data
, entry
)
96 if (data
->hwnd
!= hwnd
)
98 PostMessageW(data
->hwnd
, data
->callback_msg
, ABN_POSCHANGED
, 0);
103 /* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */
104 static void appbar_cliprect( HWND hwnd
, RECT
*rect
)
106 struct appbar_data
* data
;
107 LIST_FOR_EACH_ENTRY(data
, &appbars
, struct appbar_data
, entry
)
109 if (data
->hwnd
== hwnd
)
111 /* we only care about appbars that were added before this one */
114 if (data
->space_reserved
)
116 /* move in the side that corresponds to the other appbar's edge */
120 rect
->bottom
= min(rect
->bottom
, data
->rc
.top
);
123 rect
->left
= max(rect
->left
, data
->rc
.right
);
126 rect
->right
= min(rect
->right
, data
->rc
.left
);
129 rect
->top
= max(rect
->top
, data
->rc
.bottom
);
136 static UINT_PTR
handle_appbarmessage(DWORD msg
, struct appbar_data_msg
*abd
)
138 struct appbar_data
* data
;
139 HWND hwnd
= LongToHandle( abd
->hWnd
);
144 if (get_appbar(hwnd
))
146 /* fail when adding an hwnd the second time */
150 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct appbar_data
));
153 WINE_ERR("out of memory\n");
157 data
->callback_msg
= abd
->uCallbackMessage
;
159 list_add_tail(&appbars
, &data
->entry
);
163 if ((data
= get_appbar(hwnd
)))
165 list_remove(&data
->entry
);
167 send_poschanged(hwnd
);
169 HeapFree(GetProcessHeap(), 0, data
);
172 WINE_WARN("removing hwnd %p not on the list\n", hwnd
);
175 if (abd
->uEdge
> ABE_BOTTOM
)
176 WINE_WARN("invalid edge %i for %p\n", abd
->uEdge
, hwnd
);
177 appbar_cliprect( hwnd
, &abd
->rc
);
180 if (abd
->uEdge
> ABE_BOTTOM
)
182 WINE_WARN("invalid edge %i for %p\n", abd
->uEdge
, hwnd
);
185 if ((data
= get_appbar(hwnd
)))
187 /* calculate acceptable space */
188 appbar_cliprect( hwnd
, &abd
->rc
);
190 if (!EqualRect(&abd
->rc
, &data
->rc
))
191 send_poschanged(hwnd
);
193 /* reserve that space for this appbar */
194 data
->edge
= abd
->uEdge
;
196 data
->space_reserved
= TRUE
;
200 WINE_WARN("app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd
);
204 WINE_FIXME("SHAppBarMessage(ABM_GETSTATE): stub\n");
205 return ABS_ALWAYSONTOP
| ABS_AUTOHIDE
;
206 case ABM_GETTASKBARPOS
:
207 WINE_FIXME("SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd
);
208 /* Report the taskbar is at the bottom of the screen. */
210 abd
->rc
.right
= GetSystemMetrics(SM_CXSCREEN
);
211 abd
->rc
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
212 abd
->rc
.top
= abd
->rc
.bottom
-1;
213 abd
->uEdge
= ABE_BOTTOM
;
217 case ABM_GETAUTOHIDEBAR
:
218 WINE_FIXME("SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd
, abd
->uEdge
);
220 case ABM_SETAUTOHIDEBAR
:
221 WINE_FIXME("SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n",
222 hwnd
, abd
->uEdge
, wine_dbgstr_longlong(abd
->lParam
));
224 case ABM_WINDOWPOSCHANGED
:
227 WINE_FIXME("SHAppBarMessage(%x) unimplemented\n", msg
);
232 static LRESULT CALLBACK
appbar_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
239 struct appbar_cmd cmd
;
244 struct appbar_response
* response
;
246 cds
= (COPYDATASTRUCT
*)lparam
;
247 if (cds
->cbData
!= sizeof(struct appbar_cmd
))
249 CopyMemory(&cmd
, cds
->lpData
, cds
->cbData
);
251 result
= handle_appbarmessage(cds
->dwData
, &cmd
.abd
);
253 return_hproc
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, cmd
.return_process
);
254 if (return_hproc
== NULL
)
256 WINE_ERR("couldn't open calling process\n");
260 if (!DuplicateHandle(return_hproc
, UlongToHandle(cmd
.return_map
),
261 GetCurrentProcess(), &return_map
, 0, FALSE
, DUPLICATE_SAME_ACCESS
))
263 WINE_ERR("couldn't duplicate handle\n");
264 CloseHandle(return_hproc
);
267 CloseHandle(return_hproc
);
269 return_view
= MapViewOfFile(return_map
, FILE_MAP_WRITE
, 0, 0, sizeof(struct appbar_response
));
273 response
= (struct appbar_response
*)return_view
;
274 response
->result
= result
;
275 response
->abd
= cmd
.abd
;
277 UnmapViewOfFile(return_view
);
280 WINE_ERR("couldn't map view of file\n");
282 CloseHandle(return_map
);
289 return DefWindowProcW(hwnd
, msg
, wparam
, lparam
);
292 void initialize_appbar(void)
295 static const WCHAR classname
[] = {'W','i','n','e','A','p','p','B','a','r',0};
297 /* register the appbar window class */
298 ZeroMemory(&class, sizeof(class));
299 class.cbSize
= sizeof(class);
300 class.lpfnWndProc
= appbar_wndproc
;
301 class.hInstance
= NULL
;
302 class.lpszClassName
= classname
;
304 if (!RegisterClassExW(&class))
306 WINE_ERR("Could not register appbar message window class\n");
310 appbarmsg_window
= CreateWindowW(classname
, classname
, 0, 0, 0, 0, 0, HWND_MESSAGE
, NULL
, NULL
, NULL
);
311 if (!appbarmsg_window
)
313 WINE_ERR("Could not create appbar message window\n");