110d1afeaSjimtabor /*
210d1afeaSjimtabor * SHAppBarMessage implementation
310d1afeaSjimtabor *
410d1afeaSjimtabor * Copyright 2008 Vincent Povirk for CodeWeavers
510d1afeaSjimtabor *
610d1afeaSjimtabor * This library is free software; you can redistribute it and/or
710d1afeaSjimtabor * modify it under the terms of the GNU Lesser General Public
810d1afeaSjimtabor * License as published by the Free Software Foundation; either
910d1afeaSjimtabor * version 2.1 of the License, or (at your option) any later version.
1010d1afeaSjimtabor *
1110d1afeaSjimtabor * This library is distributed in the hope that it will be useful,
1210d1afeaSjimtabor * but WITHOUT ANY WARRANTY; without even the implied warranty of
1310d1afeaSjimtabor * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1410d1afeaSjimtabor * Lesser General Public License for more details.
1510d1afeaSjimtabor *
1610d1afeaSjimtabor * You should have received a copy of the GNU Lesser General Public
1710d1afeaSjimtabor * License along with this library; if not, write to the Free Software
1810d1afeaSjimtabor * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
1910d1afeaSjimtabor *
2010d1afeaSjimtabor * TODO: freedesktop _NET_WM_STRUT integration
2110d1afeaSjimtabor *
2210d1afeaSjimtabor * TODO: find when a fullscreen app is in the foreground and send FULLSCREENAPP
2310d1afeaSjimtabor * notifications
2410d1afeaSjimtabor *
2510d1afeaSjimtabor * TODO: detect changes in the screen size and send ABN_POSCHANGED ?
2610d1afeaSjimtabor *
2710d1afeaSjimtabor * TODO: multiple monitor support
2810d1afeaSjimtabor */
2910d1afeaSjimtabor
3010d1afeaSjimtabor //
3110d1afeaSjimtabor // Adapted from Wine appbar.c .
3210d1afeaSjimtabor //
3310d1afeaSjimtabor
3410d1afeaSjimtabor #include "precomp.h"
3510d1afeaSjimtabor
3610d1afeaSjimtabor #include <wine/list.h>
3710d1afeaSjimtabor
3810d1afeaSjimtabor struct appbar_cmd
3910d1afeaSjimtabor {
4010d1afeaSjimtabor DWORD dwMsg;
4110d1afeaSjimtabor ULONG return_map;
4210d1afeaSjimtabor DWORD return_process;
4310d1afeaSjimtabor struct _AppBarData abd;
4410d1afeaSjimtabor };
4510d1afeaSjimtabor
4610d1afeaSjimtabor struct appbar_response
4710d1afeaSjimtabor {
4810d1afeaSjimtabor ULONGLONG result;
4910d1afeaSjimtabor struct _AppBarData abd;
5010d1afeaSjimtabor };
5110d1afeaSjimtabor
5210d1afeaSjimtabor struct appbar_data
5310d1afeaSjimtabor {
5410d1afeaSjimtabor struct list entry;
5510d1afeaSjimtabor HWND hwnd;
5610d1afeaSjimtabor UINT callback_msg;
5710d1afeaSjimtabor UINT edge;
5810d1afeaSjimtabor RECT rc;
5910d1afeaSjimtabor BOOL space_reserved;
6010d1afeaSjimtabor /* BOOL autohide; */
6110d1afeaSjimtabor };
6210d1afeaSjimtabor
6310d1afeaSjimtabor static struct list appbars = LIST_INIT(appbars);
6410d1afeaSjimtabor
get_appbar(HWND hwnd)6510d1afeaSjimtabor static struct appbar_data* get_appbar(HWND hwnd)
6610d1afeaSjimtabor {
6710d1afeaSjimtabor struct appbar_data* data;
6810d1afeaSjimtabor
6910d1afeaSjimtabor LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
7010d1afeaSjimtabor {
7110d1afeaSjimtabor if (data->hwnd == hwnd)
7210d1afeaSjimtabor return data;
7310d1afeaSjimtabor }
7410d1afeaSjimtabor
7510d1afeaSjimtabor return NULL;
7610d1afeaSjimtabor }
7710d1afeaSjimtabor
appbar_notify_all(HMONITOR hMon,UINT uMsg,HWND hwndExclude,LPARAM lParam)78*451a9c6fSKatayama Hirofumi MZ void appbar_notify_all(HMONITOR hMon, UINT uMsg, HWND hwndExclude, LPARAM lParam)
79*451a9c6fSKatayama Hirofumi MZ {
80*451a9c6fSKatayama Hirofumi MZ struct appbar_data* data;
81*451a9c6fSKatayama Hirofumi MZ
82*451a9c6fSKatayama Hirofumi MZ LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
83*451a9c6fSKatayama Hirofumi MZ {
84*451a9c6fSKatayama Hirofumi MZ if (data->hwnd == hwndExclude)
85*451a9c6fSKatayama Hirofumi MZ continue;
86*451a9c6fSKatayama Hirofumi MZ
87*451a9c6fSKatayama Hirofumi MZ if (hMon && hMon != MonitorFromWindow(data->hwnd, MONITOR_DEFAULTTONULL))
88*451a9c6fSKatayama Hirofumi MZ continue;
89*451a9c6fSKatayama Hirofumi MZ
90*451a9c6fSKatayama Hirofumi MZ SendMessageW(data->hwnd, data->callback_msg, uMsg, lParam);
91*451a9c6fSKatayama Hirofumi MZ }
92*451a9c6fSKatayama Hirofumi MZ }
93*451a9c6fSKatayama Hirofumi MZ
9410d1afeaSjimtabor /* send_poschanged: send ABN_POSCHANGED to every appbar except one */
send_poschanged(HWND hwnd)9510d1afeaSjimtabor static void send_poschanged(HWND hwnd)
9610d1afeaSjimtabor {
97*451a9c6fSKatayama Hirofumi MZ appbar_notify_all(NULL, ABN_POSCHANGED, hwnd, 0);
9810d1afeaSjimtabor }
9910d1afeaSjimtabor
10010d1afeaSjimtabor /* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */
appbar_cliprect(HWND hwnd,RECT * rect)10110d1afeaSjimtabor static void appbar_cliprect( HWND hwnd, RECT *rect )
10210d1afeaSjimtabor {
10310d1afeaSjimtabor struct appbar_data* data;
10410d1afeaSjimtabor LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
10510d1afeaSjimtabor {
10610d1afeaSjimtabor if (data->hwnd == hwnd)
10710d1afeaSjimtabor {
10810d1afeaSjimtabor /* we only care about appbars that were added before this one */
10910d1afeaSjimtabor return;
11010d1afeaSjimtabor }
11110d1afeaSjimtabor if (data->space_reserved)
11210d1afeaSjimtabor {
11310d1afeaSjimtabor /* move in the side that corresponds to the other appbar's edge */
11410d1afeaSjimtabor switch (data->edge)
11510d1afeaSjimtabor {
11610d1afeaSjimtabor case ABE_BOTTOM:
11710d1afeaSjimtabor rect->bottom = min(rect->bottom, data->rc.top);
11810d1afeaSjimtabor break;
11910d1afeaSjimtabor case ABE_LEFT:
12010d1afeaSjimtabor rect->left = max(rect->left, data->rc.right);
12110d1afeaSjimtabor break;
12210d1afeaSjimtabor case ABE_RIGHT:
12310d1afeaSjimtabor rect->right = min(rect->right, data->rc.left);
12410d1afeaSjimtabor break;
12510d1afeaSjimtabor case ABE_TOP:
12610d1afeaSjimtabor rect->top = max(rect->top, data->rc.bottom);
12710d1afeaSjimtabor break;
12810d1afeaSjimtabor }
12910d1afeaSjimtabor }
13010d1afeaSjimtabor }
13110d1afeaSjimtabor }
13210d1afeaSjimtabor
handle_appbarmessage(DWORD msg,_AppBarData * abd)13310d1afeaSjimtabor static UINT_PTR handle_appbarmessage(DWORD msg, _AppBarData *abd)
13410d1afeaSjimtabor {
13510d1afeaSjimtabor struct appbar_data* data;
13610d1afeaSjimtabor HWND hwnd = abd->hWnd;
13710d1afeaSjimtabor
13810d1afeaSjimtabor switch (msg)
13910d1afeaSjimtabor {
14010d1afeaSjimtabor case ABM_NEW:
14110d1afeaSjimtabor if (get_appbar(hwnd))
14210d1afeaSjimtabor {
14310d1afeaSjimtabor /* fail when adding an hwnd the second time */
14410d1afeaSjimtabor return FALSE;
14510d1afeaSjimtabor }
14610d1afeaSjimtabor
14710d1afeaSjimtabor data = (struct appbar_data*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct appbar_data));
14810d1afeaSjimtabor if (!data)
14910d1afeaSjimtabor {
15010d1afeaSjimtabor ERR("out of memory\n");
15110d1afeaSjimtabor return FALSE;
15210d1afeaSjimtabor }
15310d1afeaSjimtabor data->hwnd = hwnd;
15410d1afeaSjimtabor data->callback_msg = abd->uCallbackMessage;
15510d1afeaSjimtabor
15610d1afeaSjimtabor list_add_tail(&appbars, &data->entry);
15710d1afeaSjimtabor
15810d1afeaSjimtabor return TRUE;
15910d1afeaSjimtabor case ABM_REMOVE:
16010d1afeaSjimtabor if ((data = get_appbar(hwnd)))
16110d1afeaSjimtabor {
16210d1afeaSjimtabor list_remove(&data->entry);
16310d1afeaSjimtabor
16410d1afeaSjimtabor send_poschanged(hwnd);
16510d1afeaSjimtabor
16610d1afeaSjimtabor HeapFree(GetProcessHeap(), 0, data);
16710d1afeaSjimtabor }
16810d1afeaSjimtabor else
16910d1afeaSjimtabor WARN("removing hwnd %p not on the list\n", hwnd);
17010d1afeaSjimtabor return TRUE;
17110d1afeaSjimtabor case ABM_QUERYPOS:
17210d1afeaSjimtabor if (abd->uEdge > ABE_BOTTOM)
17310d1afeaSjimtabor WARN("invalid edge %i for %p\n", abd->uEdge, hwnd);
17410d1afeaSjimtabor appbar_cliprect( hwnd, &abd->rc );
17510d1afeaSjimtabor return TRUE;
17610d1afeaSjimtabor case ABM_SETPOS:
17710d1afeaSjimtabor if (abd->uEdge > ABE_BOTTOM)
17810d1afeaSjimtabor {
17910d1afeaSjimtabor WARN("invalid edge %i for %p\n", abd->uEdge, hwnd);
18010d1afeaSjimtabor return TRUE;
18110d1afeaSjimtabor }
18210d1afeaSjimtabor if ((data = get_appbar(hwnd)))
18310d1afeaSjimtabor {
18410d1afeaSjimtabor /* calculate acceptable space */
18510d1afeaSjimtabor appbar_cliprect( hwnd, &abd->rc );
18610d1afeaSjimtabor
18710d1afeaSjimtabor if (!EqualRect(&abd->rc, &data->rc))
18810d1afeaSjimtabor send_poschanged(hwnd);
18910d1afeaSjimtabor
19010d1afeaSjimtabor /* reserve that space for this appbar */
19110d1afeaSjimtabor data->edge = abd->uEdge;
19210d1afeaSjimtabor data->rc = abd->rc;
19310d1afeaSjimtabor data->space_reserved = TRUE;
19410d1afeaSjimtabor }
19510d1afeaSjimtabor else
19610d1afeaSjimtabor {
19710d1afeaSjimtabor WARN("app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd);
19810d1afeaSjimtabor }
19910d1afeaSjimtabor return TRUE;
20010d1afeaSjimtabor case ABM_GETSTATE:
20110d1afeaSjimtabor FIXME("SHAppBarMessage(ABM_GETSTATE): stub\n");
20210d1afeaSjimtabor return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
20310d1afeaSjimtabor case ABM_GETTASKBARPOS:
20410d1afeaSjimtabor FIXME("SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd);
20510d1afeaSjimtabor /* Report the taskbar is at the bottom of the screen. */
20610d1afeaSjimtabor abd->rc.left = 0;
20710d1afeaSjimtabor abd->rc.right = GetSystemMetrics(SM_CXSCREEN);
20810d1afeaSjimtabor abd->rc.bottom = GetSystemMetrics(SM_CYSCREEN);
20910d1afeaSjimtabor abd->rc.top = abd->rc.bottom-1;
21010d1afeaSjimtabor abd->uEdge = ABE_BOTTOM;
21110d1afeaSjimtabor return TRUE;
21210d1afeaSjimtabor case ABM_ACTIVATE:
21310d1afeaSjimtabor return TRUE;
21410d1afeaSjimtabor case ABM_GETAUTOHIDEBAR:
21510d1afeaSjimtabor FIXME("SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd, abd->uEdge);
21610d1afeaSjimtabor return 0;
21710d1afeaSjimtabor case ABM_SETAUTOHIDEBAR:
21810d1afeaSjimtabor FIXME("SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n",
21910d1afeaSjimtabor hwnd, abd->uEdge, wine_dbgstr_longlong(abd->lParam));
22010d1afeaSjimtabor return TRUE;
22110d1afeaSjimtabor case ABM_WINDOWPOSCHANGED:
22210d1afeaSjimtabor return TRUE;
22310d1afeaSjimtabor default:
22410d1afeaSjimtabor FIXME("SHAppBarMessage(%x) unimplemented\n", msg);
22510d1afeaSjimtabor return FALSE;
22610d1afeaSjimtabor }
22710d1afeaSjimtabor }
22810d1afeaSjimtabor
appbar_message(COPYDATASTRUCT * cds)22910d1afeaSjimtabor LRESULT appbar_message ( COPYDATASTRUCT* cds )
23010d1afeaSjimtabor {
23110d1afeaSjimtabor struct appbar_cmd cmd;
23210d1afeaSjimtabor UINT_PTR result;
23310d1afeaSjimtabor HANDLE return_hproc;
23410d1afeaSjimtabor HANDLE return_map;
23510d1afeaSjimtabor LPVOID return_view;
23610d1afeaSjimtabor struct appbar_response* response;
23710d1afeaSjimtabor
23810d1afeaSjimtabor if (cds->cbData != sizeof(struct appbar_cmd))
23910d1afeaSjimtabor return TRUE;
24010d1afeaSjimtabor
24110d1afeaSjimtabor RtlCopyMemory(&cmd, cds->lpData, cds->cbData);
24210d1afeaSjimtabor
24310d1afeaSjimtabor result = handle_appbarmessage(cmd.dwMsg, &cmd.abd);
24410d1afeaSjimtabor
24510d1afeaSjimtabor return_hproc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, cmd.return_process);
24610d1afeaSjimtabor if (return_hproc == NULL)
24710d1afeaSjimtabor {
24810d1afeaSjimtabor ERR("couldn't open calling process\n");
24910d1afeaSjimtabor return TRUE;
25010d1afeaSjimtabor }
25110d1afeaSjimtabor
25210d1afeaSjimtabor if (!DuplicateHandle(return_hproc, UlongToHandle(cmd.return_map), GetCurrentProcess(), &return_map, 0, FALSE, DUPLICATE_SAME_ACCESS))
25310d1afeaSjimtabor {
25410d1afeaSjimtabor ERR("couldn't duplicate handle\n");
25510d1afeaSjimtabor CloseHandle(return_hproc);
25610d1afeaSjimtabor return TRUE;
25710d1afeaSjimtabor }
25810d1afeaSjimtabor CloseHandle(return_hproc);
25910d1afeaSjimtabor
26010d1afeaSjimtabor return_view = MapViewOfFile(return_map, FILE_MAP_WRITE, 0, 0, sizeof(struct appbar_response));
26110d1afeaSjimtabor
26210d1afeaSjimtabor if (return_view)
26310d1afeaSjimtabor {
26410d1afeaSjimtabor response = (struct appbar_response*)return_view;
26510d1afeaSjimtabor response->result = result;
26610d1afeaSjimtabor response->abd = cmd.abd;
26710d1afeaSjimtabor
26810d1afeaSjimtabor UnmapViewOfFile(return_view);
26910d1afeaSjimtabor }
27010d1afeaSjimtabor else
27110d1afeaSjimtabor {
27210d1afeaSjimtabor ERR("couldn't map view of file\n");
27310d1afeaSjimtabor }
27410d1afeaSjimtabor
27510d1afeaSjimtabor CloseHandle(return_map);
27610d1afeaSjimtabor return TRUE;
27710d1afeaSjimtabor }
278