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/debug.h"
33 #include "explorer_private.h"
35 #include "wine/list.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(appbar
);
39 struct appbar_data_msg
/* platform-independent data */
42 UINT uCallbackMessage
;
52 struct appbar_data_msg abd
;
55 struct appbar_response
58 struct appbar_data_msg abd
;
61 static HWND appbarmsg_window
= NULL
;
74 static struct list appbars
= LIST_INIT(appbars
);
76 static struct appbar_data
* get_appbar(HWND hwnd
)
78 struct appbar_data
* data
;
80 LIST_FOR_EACH_ENTRY(data
, &appbars
, struct appbar_data
, entry
)
82 if (data
->hwnd
== hwnd
)
89 /* send_poschanged: send ABN_POSCHANGED to every appbar except one */
90 static void send_poschanged(HWND hwnd
)
92 struct appbar_data
* data
;
93 LIST_FOR_EACH_ENTRY(data
, &appbars
, struct appbar_data
, entry
)
95 if (data
->hwnd
!= hwnd
)
97 PostMessageW(data
->hwnd
, data
->callback_msg
, ABN_POSCHANGED
, 0);
102 /* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */
103 static void appbar_cliprect( HWND hwnd
, RECT
*rect
)
105 struct appbar_data
* data
;
106 LIST_FOR_EACH_ENTRY(data
, &appbars
, struct appbar_data
, entry
)
108 if (data
->hwnd
== hwnd
)
110 /* we only care about appbars that were added before this one */
113 if (data
->space_reserved
)
115 /* move in the side that corresponds to the other appbar's edge */
119 rect
->bottom
= min(rect
->bottom
, data
->rc
.top
);
122 rect
->left
= max(rect
->left
, data
->rc
.right
);
125 rect
->right
= min(rect
->right
, data
->rc
.left
);
128 rect
->top
= max(rect
->top
, data
->rc
.bottom
);
135 static UINT_PTR
handle_appbarmessage(DWORD msg
, struct appbar_data_msg
*abd
)
137 struct appbar_data
* data
;
138 HWND hwnd
= LongToHandle( abd
->hWnd
);
143 if (get_appbar(hwnd
))
145 /* fail when adding an hwnd the second time */
149 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct appbar_data
));
152 WINE_ERR("out of memory\n");
156 data
->callback_msg
= abd
->uCallbackMessage
;
158 list_add_tail(&appbars
, &data
->entry
);
162 if ((data
= get_appbar(hwnd
)))
164 list_remove(&data
->entry
);
166 send_poschanged(hwnd
);
168 HeapFree(GetProcessHeap(), 0, data
);
171 WINE_WARN("removing hwnd %p not on the list\n", hwnd
);
174 if (abd
->uEdge
> ABE_BOTTOM
)
175 WINE_WARN("invalid edge %i for %p\n", abd
->uEdge
, hwnd
);
176 appbar_cliprect( hwnd
, &abd
->rc
);
179 if (abd
->uEdge
> ABE_BOTTOM
)
181 WINE_WARN("invalid edge %i for %p\n", abd
->uEdge
, hwnd
);
184 if ((data
= get_appbar(hwnd
)))
186 /* calculate acceptable space */
187 appbar_cliprect( hwnd
, &abd
->rc
);
189 if (!EqualRect(&abd
->rc
, &data
->rc
))
190 send_poschanged(hwnd
);
192 /* reserve that space for this appbar */
193 data
->edge
= abd
->uEdge
;
195 data
->space_reserved
= TRUE
;
199 WINE_WARN("app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd
);
203 WINE_FIXME("SHAppBarMessage(ABM_GETSTATE): stub\n");
204 return ABS_ALWAYSONTOP
| ABS_AUTOHIDE
;
205 case ABM_GETTASKBARPOS
:
206 WINE_FIXME("SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd
);
207 /* Report the taskbar is at the bottom of the screen. */
209 abd
->rc
.right
= GetSystemMetrics(SM_CXSCREEN
);
210 abd
->rc
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
211 abd
->rc
.top
= abd
->rc
.bottom
-1;
212 abd
->uEdge
= ABE_BOTTOM
;
216 case ABM_GETAUTOHIDEBAR
:
217 WINE_FIXME("SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd
, abd
->uEdge
);
219 case ABM_SETAUTOHIDEBAR
:
220 WINE_FIXME("SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n",
221 hwnd
, abd
->uEdge
, wine_dbgstr_longlong(abd
->lParam
));
223 case ABM_WINDOWPOSCHANGED
:
226 WINE_FIXME("SHAppBarMessage(%x) unimplemented\n", msg
);
231 static LRESULT CALLBACK
appbar_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
238 struct appbar_cmd cmd
;
243 struct appbar_response
* response
;
245 cds
= (COPYDATASTRUCT
*)lparam
;
246 if (cds
->cbData
!= sizeof(struct appbar_cmd
))
248 CopyMemory(&cmd
, cds
->lpData
, cds
->cbData
);
250 result
= handle_appbarmessage(cds
->dwData
, &cmd
.abd
);
252 return_hproc
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, cmd
.return_process
);
253 if (return_hproc
== NULL
)
255 WINE_ERR("couldn't open calling process\n");
259 if (!DuplicateHandle(return_hproc
, UlongToHandle(cmd
.return_map
),
260 GetCurrentProcess(), &return_map
, 0, FALSE
, DUPLICATE_SAME_ACCESS
))
262 WINE_ERR("couldn't duplicate handle\n");
263 CloseHandle(return_hproc
);
266 CloseHandle(return_hproc
);
268 return_view
= MapViewOfFile(return_map
, FILE_MAP_WRITE
, 0, 0, sizeof(struct appbar_response
));
272 response
= (struct appbar_response
*)return_view
;
273 response
->result
= result
;
274 response
->abd
= cmd
.abd
;
276 UnmapViewOfFile(return_view
);
279 WINE_ERR("couldn't map view of file\n");
281 CloseHandle(return_map
);
288 return DefWindowProcW(hwnd
, msg
, wparam
, lparam
);
291 void initialize_appbar(void)
294 static const WCHAR classname
[] = {'W','i','n','e','A','p','p','B','a','r',0};
296 /* register the appbar window class */
297 ZeroMemory(&class, sizeof(class));
298 class.cbSize
= sizeof(class);
299 class.lpfnWndProc
= appbar_wndproc
;
300 class.hInstance
= NULL
;
301 class.lpszClassName
= classname
;
303 if (!RegisterClassExW(&class))
305 WINE_ERR("Could not register appbar message window class\n");
309 appbarmsg_window
= CreateWindowW(classname
, classname
, 0, 0, 0, 0, 0, HWND_MESSAGE
, NULL
, NULL
, NULL
);
310 if (!appbarmsg_window
)
312 WINE_ERR("Could not create appbar message window\n");