appbar.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. #include "windows.h"
  30. #include "shellapi.h"
  31. #include "wine/debug.h"
  32. #include "explorer_private.h"
  33. #include "wine/list.h"
  34. WINE_DEFAULT_DEBUG_CHANNEL(appbar);
  35. struct appbar_data_msg /* platform-independent data */
  36. {
  37. LONG hWnd;
  38. UINT uCallbackMessage;
  39. UINT uEdge;
  40. RECT rc;
  41. ULONGLONG lParam;
  42. };
  43. struct appbar_cmd
  44. {
  45. ULONG return_map;
  46. DWORD return_process;
  47. struct appbar_data_msg abd;
  48. };
  49. struct appbar_response
  50. {
  51. ULONGLONG result;
  52. struct appbar_data_msg abd;
  53. };
  54. static HWND appbarmsg_window = NULL;
  55. struct appbar_data
  56. {
  57. struct list entry;
  58. HWND hwnd;
  59. UINT callback_msg;
  60. UINT edge;
  61. RECT rc;
  62. BOOL space_reserved;
  63. /* BOOL autohide; */
  64. };
  65. static struct list appbars = LIST_INIT(appbars);
  66. static struct appbar_data* get_appbar(HWND hwnd)
  67. {
  68. struct appbar_data* data;
  69. LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
  70. {
  71. if (data->hwnd == hwnd)
  72. return data;
  73. }
  74. return NULL;
  75. }
  76. /* send_poschanged: send ABN_POSCHANGED to every appbar except one */
  77. static void send_poschanged(HWND hwnd)
  78. {
  79. struct appbar_data* data;
  80. LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
  81. {
  82. if (data->hwnd != hwnd)
  83. {
  84. PostMessageW(data->hwnd, data->callback_msg, ABN_POSCHANGED, 0);
  85. }
  86. }
  87. }
  88. /* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */
  89. static void appbar_cliprect( HWND hwnd, RECT *rect )
  90. {
  91. struct appbar_data* data;
  92. LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
  93. {
  94. if (data->hwnd == hwnd)
  95. {
  96. /* we only care about appbars that were added before this one */
  97. return;
  98. }
  99. if (data->space_reserved)
  100. {
  101. /* move in the side that corresponds to the other appbar's edge */
  102. switch (data->edge)
  103. {
  104. case ABE_BOTTOM:
  105. rect->bottom = min(rect->bottom, data->rc.top);
  106. break;
  107. case ABE_LEFT:
  108. rect->left = max(rect->left, data->rc.right);
  109. break;
  110. case ABE_RIGHT:
  111. rect->right = min(rect->right, data->rc.left);
  112. break;
  113. case ABE_TOP:
  114. rect->top = max(rect->top, data->rc.bottom);
  115. break;
  116. }
  117. }
  118. }
  119. }
  120. static UINT_PTR handle_appbarmessage(DWORD msg, struct appbar_data_msg *abd)
  121. {
  122. struct appbar_data* data;
  123. HWND hwnd = LongToHandle( abd->hWnd );
  124. switch (msg)
  125. {
  126. case ABM_NEW:
  127. if (get_appbar(hwnd))
  128. {
  129. /* fail when adding an hwnd the second time */
  130. return FALSE;
  131. }
  132. data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct appbar_data));
  133. if (!data)
  134. {
  135. WINE_ERR("out of memory\n");
  136. return FALSE;
  137. }
  138. data->hwnd = hwnd;
  139. data->callback_msg = abd->uCallbackMessage;
  140. list_add_tail(&appbars, &data->entry);
  141. return TRUE;
  142. case ABM_REMOVE:
  143. if ((data = get_appbar(hwnd)))
  144. {
  145. list_remove(&data->entry);
  146. send_poschanged(hwnd);
  147. HeapFree(GetProcessHeap(), 0, data);
  148. }
  149. else
  150. WINE_WARN("removing hwnd %p not on the list\n", hwnd);
  151. return TRUE;
  152. case ABM_QUERYPOS:
  153. if (abd->uEdge > ABE_BOTTOM)
  154. WINE_WARN("invalid edge %i for %p\n", abd->uEdge, hwnd);
  155. appbar_cliprect( hwnd, &abd->rc );
  156. return TRUE;
  157. case ABM_SETPOS:
  158. if (abd->uEdge > ABE_BOTTOM)
  159. {
  160. WINE_WARN("invalid edge %i for %p\n", abd->uEdge, hwnd);
  161. return TRUE;
  162. }
  163. if ((data = get_appbar(hwnd)))
  164. {
  165. /* calculate acceptable space */
  166. appbar_cliprect( hwnd, &abd->rc );
  167. if (!EqualRect(&abd->rc, &data->rc))
  168. send_poschanged(hwnd);
  169. /* reserve that space for this appbar */
  170. data->edge = abd->uEdge;
  171. data->rc = abd->rc;
  172. data->space_reserved = TRUE;
  173. }
  174. else
  175. {
  176. WINE_WARN("app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd);
  177. }
  178. return TRUE;
  179. case ABM_GETSTATE:
  180. WINE_FIXME("SHAppBarMessage(ABM_GETSTATE): stub\n");
  181. return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
  182. case ABM_GETTASKBARPOS:
  183. WINE_FIXME("SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd);
  184. /* Report the taskbar is at the bottom of the screen. */
  185. abd->rc.left = 0;
  186. abd->rc.right = GetSystemMetrics(SM_CXSCREEN);
  187. abd->rc.bottom = GetSystemMetrics(SM_CYSCREEN);
  188. abd->rc.top = abd->rc.bottom-1;
  189. abd->uEdge = ABE_BOTTOM;
  190. return TRUE;
  191. case ABM_ACTIVATE:
  192. return TRUE;
  193. case ABM_GETAUTOHIDEBAR:
  194. WINE_FIXME("SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd, abd->uEdge);
  195. return 0;
  196. case ABM_SETAUTOHIDEBAR:
  197. WINE_FIXME("SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n",
  198. hwnd, abd->uEdge, wine_dbgstr_longlong(abd->lParam));
  199. return TRUE;
  200. case ABM_WINDOWPOSCHANGED:
  201. return TRUE;
  202. default:
  203. WINE_FIXME("SHAppBarMessage(%x) unimplemented\n", msg);
  204. return FALSE;
  205. }
  206. }
  207. static LRESULT CALLBACK appbar_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
  208. {
  209. switch (msg)
  210. {
  211. case WM_COPYDATA:
  212. {
  213. COPYDATASTRUCT* cds;
  214. struct appbar_cmd cmd;
  215. UINT_PTR result;
  216. HANDLE return_hproc;
  217. HANDLE return_map;
  218. LPVOID return_view;
  219. struct appbar_response* response;
  220. cds = (COPYDATASTRUCT*)lparam;
  221. if (cds->cbData != sizeof(struct appbar_cmd))
  222. return TRUE;
  223. CopyMemory(&cmd, cds->lpData, cds->cbData);
  224. result = handle_appbarmessage(cds->dwData, &cmd.abd);
  225. return_hproc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, cmd.return_process);
  226. if (return_hproc == NULL)
  227. {
  228. WINE_ERR("couldn't open calling process\n");
  229. return TRUE;
  230. }
  231. if (!DuplicateHandle(return_hproc, UlongToHandle(cmd.return_map),
  232. GetCurrentProcess(), &return_map, 0, FALSE, DUPLICATE_SAME_ACCESS))
  233. {
  234. WINE_ERR("couldn't duplicate handle\n");
  235. CloseHandle(return_hproc);
  236. return TRUE;
  237. }
  238. CloseHandle(return_hproc);
  239. return_view = MapViewOfFile(return_map, FILE_MAP_WRITE, 0, 0, sizeof(struct appbar_response));
  240. if (return_view)
  241. {
  242. response = (struct appbar_response*)return_view;
  243. response->result = result;
  244. response->abd = cmd.abd;
  245. UnmapViewOfFile(return_view);
  246. }
  247. else
  248. WINE_ERR("couldn't map view of file\n");
  249. CloseHandle(return_map);
  250. return TRUE;
  251. }
  252. default:
  253. break;
  254. }
  255. return DefWindowProcW(hwnd, msg, wparam, lparam);
  256. }
  257. void initialize_appbar(void)
  258. {
  259. WNDCLASSEXW class;
  260. static const WCHAR classname[] = {'W','i','n','e','A','p','p','B','a','r',0};
  261. /* register the appbar window class */
  262. ZeroMemory(&class, sizeof(class));
  263. class.cbSize = sizeof(class);
  264. class.lpfnWndProc = appbar_wndproc;
  265. class.hInstance = NULL;
  266. class.lpszClassName = classname;
  267. if (!RegisterClassExW(&class))
  268. {
  269. WINE_ERR("Could not register appbar message window class\n");
  270. return;
  271. }
  272. appbarmsg_window = CreateWindowW(classname, classname, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
  273. if (!appbarmsg_window)
  274. {
  275. WINE_ERR("Could not create appbar message window\n");
  276. return;
  277. }
  278. }