1 /* 2 * SHAppBarMessage implementation 3 * 4 * Copyright 2008 Vincent Povirk for CodeWeavers 5 * 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. 10 * 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. 15 * 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 19 * 20 * TODO: freedesktop _NET_WM_STRUT integration 21 * 22 * TODO: find when a fullscreen app is in the foreground and send FULLSCREENAPP 23 * notifications 24 * 25 * TODO: detect changes in the screen size and send ABN_POSCHANGED ? 26 * 27 * TODO: multiple monitor support 28 */ 29 30 // 31 // Adapted from Wine appbar.c . 32 // 33 34 #include "precomp.h" 35 36 #include <wine/list.h> 37 38 struct appbar_cmd 39 { 40 DWORD dwMsg; 41 ULONG return_map; 42 DWORD return_process; 43 struct _AppBarData abd; 44 }; 45 46 struct appbar_response 47 { 48 ULONGLONG result; 49 struct _AppBarData abd; 50 }; 51 52 struct appbar_data 53 { 54 struct list entry; 55 HWND hwnd; 56 UINT callback_msg; 57 UINT edge; 58 RECT rc; 59 BOOL space_reserved; 60 /* BOOL autohide; */ 61 }; 62 63 static struct list appbars = LIST_INIT(appbars); 64 65 static struct appbar_data* get_appbar(HWND hwnd) 66 { 67 struct appbar_data* data; 68 69 LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry) 70 { 71 if (data->hwnd == hwnd) 72 return data; 73 } 74 75 return NULL; 76 } 77 78 void appbar_notify_all(HMONITOR hMon, UINT uMsg, HWND hwndExclude, LPARAM lParam) 79 { 80 struct appbar_data* data; 81 82 LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry) 83 { 84 if (data->hwnd == hwndExclude) 85 continue; 86 87 if (hMon && hMon != MonitorFromWindow(data->hwnd, MONITOR_DEFAULTTONULL)) 88 continue; 89 90 SendMessageW(data->hwnd, data->callback_msg, uMsg, lParam); 91 } 92 } 93 94 /* send_poschanged: send ABN_POSCHANGED to every appbar except one */ 95 static void send_poschanged(HWND hwnd) 96 { 97 appbar_notify_all(NULL, ABN_POSCHANGED, hwnd, 0); 98 } 99 100 /* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */ 101 static void appbar_cliprect( HWND hwnd, RECT *rect ) 102 { 103 struct appbar_data* data; 104 LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry) 105 { 106 if (data->hwnd == hwnd) 107 { 108 /* we only care about appbars that were added before this one */ 109 return; 110 } 111 if (data->space_reserved) 112 { 113 /* move in the side that corresponds to the other appbar's edge */ 114 switch (data->edge) 115 { 116 case ABE_BOTTOM: 117 rect->bottom = min(rect->bottom, data->rc.top); 118 break; 119 case ABE_LEFT: 120 rect->left = max(rect->left, data->rc.right); 121 break; 122 case ABE_RIGHT: 123 rect->right = min(rect->right, data->rc.left); 124 break; 125 case ABE_TOP: 126 rect->top = max(rect->top, data->rc.bottom); 127 break; 128 } 129 } 130 } 131 } 132 133 static UINT_PTR handle_appbarmessage(DWORD msg, _AppBarData *abd) 134 { 135 struct appbar_data* data; 136 HWND hwnd = abd->hWnd; 137 138 switch (msg) 139 { 140 case ABM_NEW: 141 if (get_appbar(hwnd)) 142 { 143 /* fail when adding an hwnd the second time */ 144 return FALSE; 145 } 146 147 data = (struct appbar_data*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct appbar_data)); 148 if (!data) 149 { 150 ERR("out of memory\n"); 151 return FALSE; 152 } 153 data->hwnd = hwnd; 154 data->callback_msg = abd->uCallbackMessage; 155 156 list_add_tail(&appbars, &data->entry); 157 158 return TRUE; 159 case ABM_REMOVE: 160 if ((data = get_appbar(hwnd))) 161 { 162 list_remove(&data->entry); 163 164 send_poschanged(hwnd); 165 166 HeapFree(GetProcessHeap(), 0, data); 167 } 168 else 169 WARN("removing hwnd %p not on the list\n", hwnd); 170 return TRUE; 171 case ABM_QUERYPOS: 172 if (abd->uEdge > ABE_BOTTOM) 173 WARN("invalid edge %i for %p\n", abd->uEdge, hwnd); 174 appbar_cliprect( hwnd, &abd->rc ); 175 return TRUE; 176 case ABM_SETPOS: 177 if (abd->uEdge > ABE_BOTTOM) 178 { 179 WARN("invalid edge %i for %p\n", abd->uEdge, hwnd); 180 return TRUE; 181 } 182 if ((data = get_appbar(hwnd))) 183 { 184 /* calculate acceptable space */ 185 appbar_cliprect( hwnd, &abd->rc ); 186 187 if (!EqualRect(&abd->rc, &data->rc)) 188 send_poschanged(hwnd); 189 190 /* reserve that space for this appbar */ 191 data->edge = abd->uEdge; 192 data->rc = abd->rc; 193 data->space_reserved = TRUE; 194 } 195 else 196 { 197 WARN("app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd); 198 } 199 return TRUE; 200 case ABM_GETSTATE: 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. */ 206 abd->rc.left = 0; 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; 211 return TRUE; 212 case ABM_ACTIVATE: 213 return TRUE; 214 case ABM_GETAUTOHIDEBAR: 215 FIXME("SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd, abd->uEdge); 216 return 0; 217 case ABM_SETAUTOHIDEBAR: 218 FIXME("SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n", 219 hwnd, abd->uEdge, wine_dbgstr_longlong(abd->lParam)); 220 return TRUE; 221 case ABM_WINDOWPOSCHANGED: 222 return TRUE; 223 default: 224 FIXME("SHAppBarMessage(%x) unimplemented\n", msg); 225 return FALSE; 226 } 227 } 228 229 LRESULT appbar_message ( COPYDATASTRUCT* cds ) 230 { 231 struct appbar_cmd cmd; 232 UINT_PTR result; 233 HANDLE return_hproc; 234 HANDLE return_map; 235 LPVOID return_view; 236 struct appbar_response* response; 237 238 if (cds->cbData != sizeof(struct appbar_cmd)) 239 return TRUE; 240 241 RtlCopyMemory(&cmd, cds->lpData, cds->cbData); 242 243 result = handle_appbarmessage(cmd.dwMsg, &cmd.abd); 244 245 return_hproc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, cmd.return_process); 246 if (return_hproc == NULL) 247 { 248 ERR("couldn't open calling process\n"); 249 return TRUE; 250 } 251 252 if (!DuplicateHandle(return_hproc, UlongToHandle(cmd.return_map), GetCurrentProcess(), &return_map, 0, FALSE, DUPLICATE_SAME_ACCESS)) 253 { 254 ERR("couldn't duplicate handle\n"); 255 CloseHandle(return_hproc); 256 return TRUE; 257 } 258 CloseHandle(return_hproc); 259 260 return_view = MapViewOfFile(return_map, FILE_MAP_WRITE, 0, 0, sizeof(struct appbar_response)); 261 262 if (return_view) 263 { 264 response = (struct appbar_response*)return_view; 265 response->result = result; 266 response->abd = cmd.abd; 267 268 UnmapViewOfFile(return_view); 269 } 270 else 271 { 272 ERR("couldn't map view of file\n"); 273 } 274 275 CloseHandle(return_map); 276 return TRUE; 277 } 278