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
= calloc( 1, sizeof(struct appbar_data
) );
152 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
);
170 else WARN( "removing hwnd %p not on the list\n", hwnd
);
173 if (abd
->uEdge
> ABE_BOTTOM
) WARN( "invalid edge %i for %p\n", abd
->uEdge
, hwnd
);
174 appbar_cliprect( hwnd
, &abd
->rc
);
177 if (abd
->uEdge
> ABE_BOTTOM
)
179 WARN( "invalid edge %i for %p\n", abd
->uEdge
, hwnd
);
182 if ((data
= get_appbar(hwnd
)))
184 /* calculate acceptable space */
185 appbar_cliprect( hwnd
, &abd
->rc
);
187 if (!EqualRect(&abd
->rc
, &data
->rc
))
188 send_poschanged(hwnd
);
190 /* reserve that space for this appbar */
191 data
->edge
= abd
->uEdge
;
193 data
->space_reserved
= TRUE
;
197 WARN( "app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd
);
201 FIXME( "SHAppBarMessage(ABM_GETSTATE): stub\n" );
202 return ABS_ALWAYSONTOP
| ABS_AUTOHIDE
;
203 case ABM_GETTASKBARPOS
:
204 FIXME( "SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd
);
205 /* Report the taskbar is at the bottom of the screen. */
207 abd
->rc
.right
= GetSystemMetrics(SM_CXSCREEN
);
208 abd
->rc
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
209 abd
->rc
.top
= abd
->rc
.bottom
-1;
210 abd
->uEdge
= ABE_BOTTOM
;
214 case ABM_GETAUTOHIDEBAR
:
215 FIXME( "SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd
, abd
->uEdge
);
217 case ABM_SETAUTOHIDEBAR
:
218 FIXME( "SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n", hwnd
,
219 abd
->uEdge
, wine_dbgstr_longlong( abd
->lParam
) );
221 case ABM_WINDOWPOSCHANGED
:
224 FIXME( "SHAppBarMessage(%lx) unimplemented\n", msg
);
229 static LRESULT CALLBACK
appbar_wndproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
236 struct appbar_cmd cmd
;
241 struct appbar_response
* response
;
243 cds
= (COPYDATASTRUCT
*)lparam
;
244 if (cds
->cbData
!= sizeof(struct appbar_cmd
))
246 CopyMemory(&cmd
, cds
->lpData
, cds
->cbData
);
248 result
= handle_appbarmessage(cds
->dwData
, &cmd
.abd
);
250 return_hproc
= OpenProcess(PROCESS_DUP_HANDLE
, FALSE
, cmd
.return_process
);
251 if (return_hproc
== NULL
)
253 ERR( "couldn't open calling process\n" );
257 if (!DuplicateHandle(return_hproc
, UlongToHandle(cmd
.return_map
),
258 GetCurrentProcess(), &return_map
, 0, FALSE
, DUPLICATE_SAME_ACCESS
))
260 ERR( "couldn't duplicate handle\n" );
261 CloseHandle(return_hproc
);
264 CloseHandle(return_hproc
);
266 return_view
= MapViewOfFile(return_map
, FILE_MAP_WRITE
, 0, 0, sizeof(struct appbar_response
));
270 response
= (struct appbar_response
*)return_view
;
271 response
->result
= result
;
272 response
->abd
= cmd
.abd
;
274 UnmapViewOfFile(return_view
);
276 else ERR( "couldn't map view of file\n" );
278 CloseHandle(return_map
);
285 return DefWindowProcW(hwnd
, msg
, wparam
, lparam
);
288 void initialize_appbar(void)
292 /* register the appbar window class */
293 ZeroMemory(&class, sizeof(class));
294 class.cbSize
= sizeof(class);
295 class.lpfnWndProc
= appbar_wndproc
;
296 class.hInstance
= NULL
;
297 class.lpszClassName
= L
"WineAppBar";
299 if (!RegisterClassExW(&class))
301 ERR( "Could not register appbar message window class\n" );
305 appbarmsg_window
= CreateWindowW(class.lpszClassName
, class.lpszClassName
, 0, 0, 0, 0, 0, HWND_MESSAGE
, NULL
, NULL
, NULL
);
306 if (!appbarmsg_window
)
308 ERR( "Could not create appbar message window\n" );