| |
1 /* |
| |
2 * purple - WinPurple Options Plugin |
| |
3 * |
| |
4 * File: gtkappbar.c |
| |
5 * Date: August 2, 2003 |
| |
6 * Description: Appbar functionality for Windows GTK+ applications |
| |
7 * |
| |
8 * Copyright (C) 2003, Herman Bloggs <hermanator12002@yahoo.com> |
| |
9 * |
| |
10 * This program is free software; you can redistribute it and/or modify |
| |
11 * it under the terms of the GNU General Public License as published by |
| |
12 * the Free Software Foundation; either version 2 of the License, or |
| |
13 * (at your option) any later version. |
| |
14 * |
| |
15 * This program is distributed in the hope that it will be useful, |
| |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
18 * GNU General Public License for more details. |
| |
19 * |
| |
20 * You should have received a copy of the GNU General Public License |
| |
21 * along with this program; if not, write to the Free Software |
| |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
23 * |
| |
24 */ |
| |
25 /* |
| |
26 * TODO: |
| |
27 * - Move 'App on top' feature from Trans plugin to here |
| |
28 * - Bug: Multiple Show/Hide Desktop calls causes client area to disappear |
| |
29 */ |
| |
30 #include <windows.h> |
| |
31 #include <winver.h> |
| |
32 #include <stdio.h> |
| |
33 #include <gtk/gtk.h> |
| |
34 #include <gdk/gdkwin32.h> |
| |
35 #include "gtkappbar.h" |
| |
36 #include "debug.h" |
| |
37 |
| |
38 #define APPBAR_CALLBACK WM_USER + 1010 |
| |
39 |
| |
40 typedef HMONITOR WINAPI purple_MonitorFromPoint(POINT, DWORD); |
| |
41 typedef HMONITOR WINAPI purple_MonitorFromWindow(HWND, DWORD); |
| |
42 typedef BOOL WINAPI purple_GetMonitorInfo(HMONITOR, LPMONITORINFO); |
| |
43 |
| |
44 /* Retrieve the rectangular display area from the specified monitor |
| |
45 * Return TRUE if successful, otherwise FALSE |
| |
46 */ |
| |
47 static gboolean |
| |
48 get_rect_from_monitor(HMODULE hmod, HMONITOR monitor, RECT *rect) { |
| |
49 purple_GetMonitorInfo *the_GetMonitorInfo; |
| |
50 MONITORINFO info; |
| |
51 |
| |
52 if (!(the_GetMonitorInfo = (purple_GetMonitorInfo*) |
| |
53 GetProcAddress(hmod, "GetMonitorInfoA"))) { |
| |
54 return FALSE; |
| |
55 } |
| |
56 |
| |
57 info.cbSize = sizeof(info); |
| |
58 if (!the_GetMonitorInfo(monitor, &info)) { |
| |
59 return FALSE; |
| |
60 } |
| |
61 |
| |
62 CopyRect(rect, &(info.rcMonitor)); |
| |
63 |
| |
64 return TRUE; |
| |
65 } |
| |
66 |
| |
67 /** |
| |
68 * This will only work on Win98+ and Win2K+ |
| |
69 * Return TRUE if successful, otherwise FALSE |
| |
70 */ |
| |
71 static gboolean |
| |
72 get_rect_at_point_multimonitor(POINT pt, RECT *rect) { |
| |
73 HMODULE hmod; |
| |
74 purple_MonitorFromPoint *the_MonitorFromPoint; |
| |
75 HMONITOR monitor; |
| |
76 |
| |
77 if (!(hmod = GetModuleHandle("user32"))) { |
| |
78 return FALSE; |
| |
79 } |
| |
80 |
| |
81 if (!(the_MonitorFromPoint = (purple_MonitorFromPoint*) |
| |
82 GetProcAddress(hmod, "MonitorFromPoint"))) { |
| |
83 return FALSE; |
| |
84 } |
| |
85 |
| |
86 monitor = |
| |
87 the_MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); |
| |
88 |
| |
89 return get_rect_from_monitor(hmod, monitor, rect); |
| |
90 } |
| |
91 |
| |
92 /** |
| |
93 * This will only work on Win98+ and Win2K+ |
| |
94 * Return TRUE if successful, otherwise FALSE |
| |
95 */ |
| |
96 static gboolean |
| |
97 get_rect_of_window_multimonitor(HWND window, RECT *rect) { |
| |
98 HMODULE hmod; |
| |
99 purple_MonitorFromWindow *the_MonitorFromWindow; |
| |
100 HMONITOR monitor; |
| |
101 |
| |
102 if (!(hmod = GetModuleHandle("user32"))) { |
| |
103 return FALSE; |
| |
104 } |
| |
105 |
| |
106 if (!(the_MonitorFromWindow = (purple_MonitorFromWindow*) |
| |
107 GetProcAddress(hmod, "MonitorFromWindow"))) { |
| |
108 return FALSE; |
| |
109 } |
| |
110 |
| |
111 monitor = |
| |
112 the_MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); |
| |
113 |
| |
114 return get_rect_from_monitor(hmod, monitor, rect); |
| |
115 } |
| |
116 |
| |
117 /* |
| |
118 * Fallback if cannot get the RECT from the monitor directly |
| |
119 */ |
| |
120 static void get_default_workarea(RECT *rect) { |
| |
121 if (!SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, FALSE)) { |
| |
122 /* I don't think this will ever happen */ |
| |
123 rect->left = 0; |
| |
124 rect->top = 0; |
| |
125 rect->bottom = GetSystemMetrics(SM_CYSCREEN); |
| |
126 rect->right = GetSystemMetrics(SM_CXSCREEN); |
| |
127 } |
| |
128 } |
| |
129 |
| |
130 /* Retrieve the rectangle of the active work area at a point */ |
| |
131 static void get_rect_at_point(POINT pt, RECT *rc) { |
| |
132 if (!get_rect_at_point_multimonitor(pt, rc)) { |
| |
133 get_default_workarea(rc); |
| |
134 } |
| |
135 } |
| |
136 |
| |
137 /* Retrieve the rectangle of the active work area of a window*/ |
| |
138 static void get_rect_of_window(HWND window, RECT *rc) { |
| |
139 if (!get_rect_of_window_multimonitor(window, rc)) { |
| |
140 get_default_workarea(rc); |
| |
141 } |
| |
142 } |
| |
143 |
| |
144 static void get_window_normal_rc(HWND hwnd, RECT *rc) { |
| |
145 WINDOWPLACEMENT wplc; |
| |
146 GetWindowPlacement(hwnd, &wplc); |
| |
147 CopyRect(rc, &wplc.rcNormalPosition); |
| |
148 } |
| |
149 #if 0 |
| |
150 static void print_rect(RECT *rc) { |
| |
151 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "RECT: L:%ld R:%ld T:%ld B:%ld\n", |
| |
152 rc->left, rc->right, rc->top, rc->bottom); |
| |
153 } |
| |
154 #endif |
| |
155 /** Set the window style to be the "Tool Window" style - small header, no min/max buttons */ |
| |
156 static void set_toolbar(HWND hwnd, gboolean val) { |
| |
157 LONG style=0; |
| |
158 |
| |
159 style = GetWindowLong(hwnd, GWL_EXSTYLE); |
| |
160 if(val && !(style & WS_EX_TOOLWINDOW)) |
| |
161 style |= WS_EX_TOOLWINDOW; |
| |
162 else if(!val && style & WS_EX_TOOLWINDOW) |
| |
163 style &= ~WS_EX_TOOLWINDOW; |
| |
164 else |
| |
165 return; |
| |
166 SetWindowLong(hwnd, GWL_EXSTYLE, style); |
| |
167 SetWindowPos(hwnd, 0, 0, 0, 0, 0, |
| |
168 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); |
| |
169 |
| |
170 /* This really should be the following, but SWP_FRAMECHANGED strangely causes initermittent problems "Show Desktop" done more than once. |
| |
171 * Not having SWP_FRAMECHANGED *should* cause the Style not to be applied, but i haven't noticed any problems |
| |
172 * SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); |
| |
173 */ |
| |
174 } |
| |
175 /** Register the window as an appbar */ |
| |
176 static gboolean gtk_appbar_register(GtkAppBar *ab, HWND hwnd) { |
| |
177 APPBARDATA abd; |
| |
178 |
| |
179 abd.cbSize = sizeof(APPBARDATA); |
| |
180 abd.hWnd = hwnd; |
| |
181 abd.uCallbackMessage = APPBAR_CALLBACK; |
| |
182 |
| |
183 ab->registered = SHAppBarMessage(ABM_NEW, &abd); |
| |
184 |
| |
185 return ab->registered; |
| |
186 } |
| |
187 /** Unregister the window as an appbar */ |
| |
188 static gboolean gtk_appbar_unregister(GtkAppBar *ab, HWND hwnd) { |
| |
189 APPBARDATA abd; |
| |
190 |
| |
191 if(!ab->registered) |
| |
192 return TRUE; |
| |
193 |
| |
194 abd.cbSize = sizeof(APPBARDATA); |
| |
195 abd.hWnd = hwnd; |
| |
196 |
| |
197 SHAppBarMessage(ABM_REMOVE, &abd); /** This always returns TRUE */ |
| |
198 |
| |
199 ab->registered = FALSE; |
| |
200 |
| |
201 ab->docked = FALSE; |
| |
202 ab->docking = FALSE; |
| |
203 |
| |
204 return TRUE; |
| |
205 } |
| |
206 |
| |
207 static void gtk_appbar_querypos(GtkAppBar *ab, HWND hwnd, RECT rcWorkspace) { |
| |
208 APPBARDATA abd; |
| |
209 guint iWidth = 0; |
| |
210 |
| |
211 if(!ab->registered) |
| |
212 gtk_appbar_register(ab, hwnd); |
| |
213 |
| |
214 abd.hWnd = hwnd; |
| |
215 abd.cbSize = sizeof(APPBARDATA); |
| |
216 abd.uEdge = ab->side; |
| |
217 |
| |
218 iWidth = ab->docked_rect.right - ab->docked_rect.left; |
| |
219 |
| |
220 abd.rc.top = rcWorkspace.top; |
| |
221 abd.rc.bottom = rcWorkspace.bottom; |
| |
222 switch (abd.uEdge) |
| |
223 { |
| |
224 case ABE_LEFT: |
| |
225 abd.rc.left = rcWorkspace.left; |
| |
226 abd.rc.right = rcWorkspace.left + iWidth; |
| |
227 break; |
| |
228 |
| |
229 case ABE_RIGHT: |
| |
230 abd.rc.right = rcWorkspace.right; |
| |
231 abd.rc.left = rcWorkspace.right - iWidth; |
| |
232 break; |
| |
233 } |
| |
234 |
| |
235 /* Ask the system for the screen space */ |
| |
236 SHAppBarMessage(ABM_QUERYPOS, &abd); |
| |
237 |
| |
238 switch (abd.uEdge) |
| |
239 { |
| |
240 case ABE_LEFT: |
| |
241 abd.rc.right = abd.rc.left + iWidth; |
| |
242 break; |
| |
243 |
| |
244 case ABE_RIGHT: |
| |
245 abd.rc.left = abd.rc.right - iWidth; |
| |
246 break; |
| |
247 } |
| |
248 |
| |
249 CopyRect(&(ab->docked_rect), &abd.rc); |
| |
250 } |
| |
251 /* Actually set the size and screen location of the appbar */ |
| |
252 static void gtk_appbar_setpos(GtkAppBar *ab, HWND hwnd) { |
| |
253 APPBARDATA abd; |
| |
254 |
| |
255 if(!ab->registered) |
| |
256 gtk_appbar_register(ab, hwnd); |
| |
257 |
| |
258 abd.hWnd = hwnd; |
| |
259 abd.cbSize = sizeof(APPBARDATA); |
| |
260 CopyRect(&abd.rc, &(ab->docked_rect)); |
| |
261 abd.uEdge = ab->side; |
| |
262 |
| |
263 SHAppBarMessage(ABM_SETPOS, &abd); |
| |
264 } |
| |
265 /** Let any callbacks know that we have docked or undocked */ |
| |
266 static void gtk_appbar_dispatch_dock_cbs(GtkAppBar *ab, gboolean val) { |
| |
267 GList *lst = ab->dock_cbs; |
| |
268 |
| |
269 while(lst) { |
| |
270 GtkAppBarDockCB dock_cb = lst->data; |
| |
271 dock_cb(val); |
| |
272 lst = lst->next; |
| |
273 } |
| |
274 } |
| |
275 |
| |
276 static GdkFilterReturn wnd_moving(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
277 MSG *msg = (MSG*)xevent; |
| |
278 POINT cp; |
| |
279 RECT *rc = (RECT*)msg->lParam; |
| |
280 RECT monRect; |
| |
281 int side = -1; |
| |
282 long dockAreaWidth = 0; |
| |
283 |
| |
284 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_moving\n"); |
| |
285 |
| |
286 GetCursorPos(&cp); |
| |
287 get_rect_at_point(cp, &monRect); |
| |
288 |
| |
289 dockAreaWidth = (monRect.right - monRect.left) / 10; |
| |
290 /* Which part of the screen are we in ? */ |
| |
291 if (cp.x > (monRect.right - dockAreaWidth)) { |
| |
292 side = ABE_RIGHT; |
| |
293 } else if (cp.x < (monRect.left + dockAreaWidth)) { |
| |
294 side = ABE_LEFT; |
| |
295 } |
| |
296 |
| |
297 if(!ab->docked) { |
| |
298 if( (side == ABE_RIGHT || side == ABE_LEFT) ) { |
| |
299 if( !ab->docking ) { |
| |
300 ab->side = side; |
| |
301 GetWindowRect(msg->hwnd, &(ab->docked_rect)); |
| |
302 gtk_appbar_querypos(ab, msg->hwnd, monRect); |
| |
303 |
| |
304 /* save pre-docking height */ |
| |
305 ab->undocked_height = rc->bottom - rc->top; |
| |
306 ab->docking = TRUE; |
| |
307 } |
| |
308 } |
| |
309 else |
| |
310 ab->docking = FALSE; |
| |
311 } |
| |
312 else if(side < 0) { |
| |
313 gtk_appbar_unregister(ab, msg->hwnd); |
| |
314 rc->bottom = rc->top + ab->undocked_height; |
| |
315 } |
| |
316 |
| |
317 /* Switch to toolbar/regular caption*/ |
| |
318 if(ab->docking) |
| |
319 set_toolbar(msg->hwnd, TRUE); |
| |
320 else if(!ab->docked) |
| |
321 set_toolbar(msg->hwnd, FALSE); |
| |
322 |
| |
323 return GDK_FILTER_CONTINUE; |
| |
324 } |
| |
325 |
| |
326 static GdkFilterReturn wnd_sizing(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
327 MSG *msg = (MSG*)xevent; |
| |
328 |
| |
329 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_sizing\n"); |
| |
330 if(ab->docked) { |
| |
331 RECT *rc = (RECT*)msg->lParam; |
| |
332 if(ab->side == ABE_LEFT && msg->wParam == WMSZ_RIGHT) { |
| |
333 ab->docked_rect.right = rc->right; |
| |
334 gtk_appbar_setpos(ab, msg->hwnd); |
| |
335 } |
| |
336 else if(ab->side == ABE_RIGHT && msg->wParam == WMSZ_LEFT) { |
| |
337 ab->docked_rect.left = rc->left; |
| |
338 gtk_appbar_setpos(ab, msg->hwnd); |
| |
339 } |
| |
340 return GDK_FILTER_REMOVE; |
| |
341 } |
| |
342 return GDK_FILTER_CONTINUE; |
| |
343 } |
| |
344 /** Notify the system that the appbar has been activated */ |
| |
345 static GdkFilterReturn wnd_activate(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
346 if (ab->registered) { |
| |
347 APPBARDATA abd; |
| |
348 MSG *msg = (MSG*)xevent; |
| |
349 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_activate\n"); |
| |
350 |
| |
351 abd.hWnd = msg->hwnd; |
| |
352 abd.cbSize = sizeof(APPBARDATA); |
| |
353 |
| |
354 SHAppBarMessage(ABM_ACTIVATE, &abd); |
| |
355 } |
| |
356 return GDK_FILTER_CONTINUE; |
| |
357 } |
| |
358 /** Notify the system that the appbar's position has changed */ |
| |
359 static GdkFilterReturn wnd_poschanged(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
360 if (ab->registered) { |
| |
361 APPBARDATA abd; |
| |
362 MSG *msg = (MSG*)xevent; |
| |
363 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_poschanged\n"); |
| |
364 |
| |
365 abd.hWnd = msg->hwnd; |
| |
366 abd.cbSize = sizeof(APPBARDATA); |
| |
367 |
| |
368 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd); |
| |
369 } |
| |
370 return GDK_FILTER_CONTINUE; |
| |
371 } |
| |
372 /** The window is about to change */ |
| |
373 static GdkFilterReturn wnd_poschanging(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
374 MSG *msg = (MSG*)xevent; |
| |
375 WINDOWPOS *wpos = (WINDOWPOS*)msg->lParam; |
| |
376 |
| |
377 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_poschanging\n"); |
| |
378 |
| |
379 if(ab->docked || ab->docking) { |
| |
380 wpos->x = ab->docked_rect.left; |
| |
381 wpos->y = ab->docked_rect.top; |
| |
382 wpos->cx = ab->docked_rect.right - ab->docked_rect.left; |
| |
383 wpos->cy = ab->docked_rect.bottom - ab->docked_rect.top; |
| |
384 if(IsIconic(msg->hwnd)) |
| |
385 set_toolbar(msg->hwnd, FALSE); |
| |
386 /*return GDK_FILTER_REMOVE;*/ |
| |
387 } |
| |
388 return GDK_FILTER_CONTINUE; |
| |
389 } |
| |
390 |
| |
391 static GdkFilterReturn wnd_exitsizemove(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
392 MSG *msg = (MSG*)xevent; |
| |
393 |
| |
394 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_exitsizemove\n"); |
| |
395 if(ab->docking) { |
| |
396 gtk_appbar_setpos(ab, msg->hwnd); |
| |
397 ab->docking = FALSE; |
| |
398 ab->docked = TRUE; |
| |
399 gtk_appbar_dispatch_dock_cbs(ab, TRUE); |
| |
400 } |
| |
401 else if(!ab->docked) { |
| |
402 gtk_appbar_unregister(ab, msg->hwnd); |
| |
403 gtk_appbar_dispatch_dock_cbs(ab, FALSE); |
| |
404 } |
| |
405 |
| |
406 return GDK_FILTER_CONTINUE; |
| |
407 } |
| |
408 |
| |
409 static GdkFilterReturn wnd_showwindow(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
410 MSG *msg = (MSG*)xevent; |
| |
411 |
| |
412 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_showwindow\n"); |
| |
413 if(msg->wParam && ab->docked) { |
| |
414 ab->iconized = FALSE; |
| |
415 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "shown\n"); |
| |
416 ab->docked = FALSE; |
| |
417 gtk_appbar_dock(ab, ab->side); |
| |
418 } |
| |
419 else if(!msg->wParam && ab->docked) { |
| |
420 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "hidden\n"); |
| |
421 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); |
| |
422 set_toolbar(GDK_WINDOW_HWND(ab->win->window), FALSE); |
| |
423 ab->docked = TRUE; |
| |
424 ab->iconized = TRUE; |
| |
425 } |
| |
426 return GDK_FILTER_CONTINUE; |
| |
427 } |
| |
428 /** The window's size has changed */ |
| |
429 static GdkFilterReturn wnd_size(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
430 MSG *msg = (MSG*)xevent; |
| |
431 |
| |
432 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_size\n"); |
| |
433 |
| |
434 if(msg->wParam == SIZE_MINIMIZED) { |
| |
435 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "Minimize\n"); |
| |
436 if(ab->docked) { |
| |
437 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); |
| |
438 ab->docked = TRUE; |
| |
439 } |
| |
440 } |
| |
441 else if(msg->wParam == SIZE_RESTORED) { |
| |
442 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "Restore\n"); |
| |
443 if (!ab->iconized && ab->docked) { |
| |
444 gtk_appbar_dock(ab, ab->side); |
| |
445 } |
| |
446 } |
| |
447 return GDK_FILTER_CONTINUE; |
| |
448 } |
| |
449 |
| |
450 static GdkFilterReturn wnd_nchittest(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
451 MSG *msg = (MSG*)xevent; |
| |
452 |
| |
453 if(ab->docked) { |
| |
454 UINT ret = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam); |
| |
455 |
| |
456 switch(ret) { |
| |
457 case HTBOTTOM: |
| |
458 case HTBOTTOMLEFT: |
| |
459 case HTBOTTOMRIGHT: |
| |
460 case HTTOP: |
| |
461 case HTTOPLEFT: |
| |
462 case HTTOPRIGHT: |
| |
463 return GDK_FILTER_REMOVE; |
| |
464 case HTLEFT: |
| |
465 if(ab->side == ABE_LEFT) |
| |
466 return GDK_FILTER_REMOVE; |
| |
467 break; |
| |
468 case HTRIGHT: |
| |
469 if(ab->side == ABE_RIGHT) |
| |
470 return GDK_FILTER_REMOVE; |
| |
471 break; |
| |
472 } |
| |
473 } |
| |
474 return GDK_FILTER_CONTINUE; |
| |
475 } |
| |
476 |
| |
477 #if 0 |
| |
478 static GdkFilterReturn wnd_initmenupopup(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
479 MSG *msg = (MSG*)xevent; |
| |
480 |
| |
481 if(ab->docked && HIWORD(msg->lParam)) { |
| |
482 HMENU sysmenu = GetSystemMenu(msg->hwnd, FALSE); |
| |
483 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "wnd_initpopupmenu: docked: %d ismenu: %d\n", ab->docked, IsMenu(sysmenu)); |
| |
484 if(EnableMenuItem(sysmenu, SC_MAXIMIZE, MF_BYCOMMAND|MF_GRAYED)<0) |
| |
485 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "SC_MAXIMIZE Menu item does not exist\n"); |
| |
486 if(EnableMenuItem(sysmenu, SC_MOVE, MF_BYCOMMAND|MF_GRAYED)<0) |
| |
487 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "SC_MOVE Menu item does not exist\n"); |
| |
488 return GDK_FILTER_CONTINUE; |
| |
489 } |
| |
490 else |
| |
491 GetSystemMenu(msg->hwnd, TRUE); |
| |
492 return GDK_FILTER_CONTINUE; |
| |
493 } |
| |
494 #endif |
| |
495 |
| |
496 static GdkFilterReturn gtk_appbar_callback(GtkAppBar *ab, GdkXEvent *xevent) { |
| |
497 MSG *msg = (MSG*)xevent; |
| |
498 RECT orig, windowRect; |
| |
499 |
| |
500 switch (msg->wParam) { |
| |
501 case ABN_STATECHANGE: |
| |
502 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_STATECHANGE\n"); |
| |
503 break; |
| |
504 |
| |
505 case ABN_FULLSCREENAPP: |
| |
506 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_FULLSCREENAPP: %d\n", (BOOL)msg->lParam); |
| |
507 if (!ab->iconized && ab->docked) { |
| |
508 if ((BOOL)msg->lParam) { |
| |
509 SetWindowPos(msg->hwnd, HWND_BOTTOM, 0, 0, 0, 0, |
| |
510 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); |
| |
511 } else { |
| |
512 SetWindowPos(msg->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, |
| |
513 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_FRAMECHANGED); |
| |
514 } |
| |
515 } |
| |
516 |
| |
517 break; |
| |
518 case ABN_POSCHANGED: |
| |
519 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_POSCHANGED\n"); |
| |
520 CopyRect(&orig, &(ab->docked_rect)); |
| |
521 get_rect_of_window(msg->hwnd, &windowRect); |
| |
522 gtk_appbar_querypos(ab, msg->hwnd, windowRect); |
| |
523 if (EqualRect(&orig, &(ab->docked_rect)) == 0) { |
| |
524 MoveWindow(msg->hwnd, ab->docked_rect.left, ab->docked_rect.top, |
| |
525 ab->docked_rect.right - ab->docked_rect.left, |
| |
526 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); |
| |
527 } |
| |
528 gtk_appbar_setpos(ab, msg->hwnd); |
| |
529 break; |
| |
530 #if 0 |
| |
531 default: |
| |
532 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: %d\n", msg->wParam); |
| |
533 #endif |
| |
534 } |
| |
535 return GDK_FILTER_CONTINUE; |
| |
536 } |
| |
537 |
| |
538 static GdkFilterReturn gtk_appbar_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) { |
| |
539 MSG *msg = (MSG*)xevent; |
| |
540 |
| |
541 /*printf("MSG: %s\n", message_to_string (msg->message));*/ |
| |
542 switch(msg->message) { |
| |
543 case WM_EXITSIZEMOVE: |
| |
544 return wnd_exitsizemove(data, xevent); |
| |
545 case WM_WINDOWPOSCHANGING: |
| |
546 return wnd_poschanging(data, xevent); |
| |
547 case WM_WINDOWPOSCHANGED: |
| |
548 return wnd_poschanged(data, xevent); |
| |
549 case WM_ACTIVATE: |
| |
550 return wnd_activate(data, xevent); |
| |
551 case WM_SIZING: |
| |
552 return wnd_sizing(data, xevent); |
| |
553 case WM_MOVING: |
| |
554 return wnd_moving(data, xevent); |
| |
555 case WM_SHOWWINDOW: |
| |
556 return wnd_showwindow(data, xevent); |
| |
557 case WM_NCHITTEST: |
| |
558 return wnd_nchittest(data, xevent); |
| |
559 #if 0 |
| |
560 case WM_INITMENUPOPUP: |
| |
561 return wnd_initmenupopup(data, xevent); |
| |
562 #endif |
| |
563 case WM_SIZE: |
| |
564 return wnd_size(data, xevent); |
| |
565 case APPBAR_CALLBACK: |
| |
566 return gtk_appbar_callback(data, xevent); |
| |
567 #if 0 |
| |
568 default: |
| |
569 purple_debug_info("gtkappbar", "gtk_appbar_event_filter %d\n", msg->message); |
| |
570 #endif |
| |
571 } |
| |
572 return GDK_FILTER_CONTINUE; |
| |
573 } |
| |
574 |
| |
575 void gtk_appbar_dock(GtkAppBar *ab, UINT side) { |
| |
576 RECT orig, windowRect; |
| |
577 |
| |
578 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_dock\n"); |
| |
579 |
| |
580 if(!ab || !IsWindow(GDK_WINDOW_HWND(ab->win->window))) |
| |
581 return; |
| |
582 |
| |
583 ab->side = side; |
| |
584 get_window_normal_rc(GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect)); |
| |
585 CopyRect(&orig, &(ab->docked_rect)); |
| |
586 get_rect_of_window(GDK_WINDOW_HWND(ab->win->window), &windowRect); |
| |
587 gtk_appbar_querypos(ab, GDK_WINDOW_HWND(ab->win->window), windowRect); |
| |
588 if(EqualRect(&orig, &(ab->docked_rect)) == 0) |
| |
589 MoveWindow(GDK_WINDOW_HWND(ab->win->window), |
| |
590 ab->docked_rect.left, |
| |
591 ab->docked_rect.top, |
| |
592 ab->docked_rect.right - ab->docked_rect.left, |
| |
593 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); |
| |
594 gtk_appbar_setpos(ab, GDK_WINDOW_HWND(ab->win->window)); |
| |
595 set_toolbar(GDK_WINDOW_HWND(ab->win->window), TRUE); |
| |
596 ab->docked = TRUE; |
| |
597 } |
| |
598 |
| |
599 void gtk_appbar_add_dock_cb(GtkAppBar *ab, GtkAppBarDockCB dock_cb) { |
| |
600 if(!ab) |
| |
601 return; |
| |
602 ab->dock_cbs = g_list_append(ab->dock_cbs, dock_cb); |
| |
603 } |
| |
604 |
| |
605 GtkAppBar *gtk_appbar_add(GtkWidget *win) { |
| |
606 GtkAppBar *ab; |
| |
607 |
| |
608 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_add\n"); |
| |
609 |
| |
610 if(!win) |
| |
611 return NULL; |
| |
612 ab = g_new0(GtkAppBar, 1); |
| |
613 ab->win = win; |
| |
614 |
| |
615 /* init docking coords */ |
| |
616 get_window_normal_rc(GDK_WINDOW_HWND(win->window), &(ab->docked_rect)); |
| |
617 |
| |
618 /* Add main window filter */ |
| |
619 gdk_window_add_filter(win->window, |
| |
620 gtk_appbar_event_filter, |
| |
621 ab); |
| |
622 return ab; |
| |
623 } |
| |
624 |
| |
625 void gtk_appbar_remove(GtkAppBar *ab) { |
| |
626 purple_debug(PURPLE_DEBUG_INFO, "gtkappbar", "gtk_appbar_remove\n"); |
| |
627 |
| |
628 if(!ab) |
| |
629 return; |
| |
630 gdk_window_remove_filter(ab->win->window, |
| |
631 gtk_appbar_event_filter, |
| |
632 ab); |
| |
633 if(ab->docked) { |
| |
634 gtk_window_resize(GTK_WINDOW(ab->win), |
| |
635 ab->docked_rect.right - ab->docked_rect.left, |
| |
636 ab->undocked_height); |
| |
637 set_toolbar(GDK_WINDOW_HWND(ab->win->window), FALSE); |
| |
638 } |
| |
639 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); |
| |
640 |
| |
641 g_free(ab); |
| |
642 } |