xref: /reactos/base/shell/explorer/appbar.cpp (revision 451a9c6f)
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