Mercurial > pidgin
comparison plugins/win32/winprefs/gtkappbar.c @ 6409:752d0600b514
[gaim-migrate @ 6915]
Blist can now be docked, using Windows appbar features
committer: Tailor Script <tailor@pidgin.im>
author | Herman Bloggs <hermanator12002@yahoo.com> |
---|---|
date | Fri, 08 Aug 2003 01:05:03 +0000 |
parents | |
children | 759a81390b36 |
comparison
equal
deleted
inserted
replaced
6408:90fc2199c156 | 6409:752d0600b514 |
---|---|
1 /* | |
2 * gaim - WinGaim 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 disapear | |
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 static void get_window_normal_rc(HWND hwnd, RECT *rc) { | |
41 WINDOWPLACEMENT wplc; | |
42 GetWindowPlacement(hwnd, &wplc); | |
43 CopyRect(rc, &wplc.rcNormalPosition); | |
44 } | |
45 | |
46 static void print_rect(RECT *rc) { | |
47 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "RECT: L:%ld R:%ld T:%ld B:%ld\n", | |
48 rc->left, rc->right, rc->top, rc->bottom); | |
49 } | |
50 | |
51 static void set_toolbar(HWND hwnd, gboolean val) { | |
52 LONG style=0; | |
53 | |
54 style = GetWindowLong(hwnd, GWL_EXSTYLE); | |
55 if(val && !(style & WS_EX_TOOLWINDOW)) | |
56 style |= WS_EX_TOOLWINDOW; | |
57 else if(!val && style & WS_EX_TOOLWINDOW) | |
58 style &= ~WS_EX_TOOLWINDOW; | |
59 else | |
60 return; | |
61 SetWindowLong(hwnd, GWL_EXSTYLE, style); | |
62 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); | |
63 } | |
64 | |
65 static gboolean gtk_appbar_register(GtkAppBar *ab, HWND hwnd) { | |
66 APPBARDATA abd; | |
67 | |
68 abd.cbSize = sizeof(APPBARDATA); | |
69 abd.hWnd = hwnd; | |
70 abd.uCallbackMessage = APPBAR_CALLBACK; | |
71 | |
72 ab->registered = SHAppBarMessage(ABM_NEW, &abd); | |
73 | |
74 return ab->registered; | |
75 } | |
76 | |
77 static gboolean gtk_appbar_unregister(GtkAppBar *ab, HWND hwnd) { | |
78 APPBARDATA abd; | |
79 | |
80 if(!ab->registered) | |
81 return TRUE; | |
82 | |
83 abd.cbSize = sizeof(APPBARDATA); | |
84 abd.hWnd = hwnd; | |
85 | |
86 ab->registered = !SHAppBarMessage(ABM_REMOVE, &abd); | |
87 | |
88 if(!ab->registered) { | |
89 ab->docked = FALSE; | |
90 ab->docking = FALSE; | |
91 } | |
92 return !ab->registered; | |
93 } | |
94 | |
95 static void gtk_appbar_querypos(GtkAppBar *ab, HWND hwnd, RECT *rc) { | |
96 APPBARDATA abd; | |
97 int iWidth = 0; | |
98 | |
99 if(!ab->registered) | |
100 gtk_appbar_register(ab, hwnd); | |
101 | |
102 abd.hWnd = hwnd; | |
103 abd.cbSize = sizeof(APPBARDATA); | |
104 CopyRect(&abd.rc, rc); | |
105 abd.uEdge = ab->side; | |
106 | |
107 iWidth = abd.rc.right - abd.rc.left; | |
108 | |
109 abd.rc.top = 0; | |
110 abd.rc.bottom = GetSystemMetrics(SM_CYSCREEN); | |
111 switch (abd.uEdge) | |
112 { | |
113 case ABE_LEFT: | |
114 abd.rc.left = 0; | |
115 abd.rc.right = iWidth; | |
116 break; | |
117 | |
118 case ABE_RIGHT: | |
119 abd.rc.right = GetSystemMetrics(SM_CXSCREEN); | |
120 abd.rc.left = abd.rc.right - iWidth; | |
121 break; | |
122 } | |
123 | |
124 /* Ask the system for the screen space */ | |
125 SHAppBarMessage(ABM_QUERYPOS, &abd); | |
126 | |
127 switch (abd.uEdge) | |
128 { | |
129 case ABE_LEFT: | |
130 abd.rc.right = abd.rc.left + iWidth; | |
131 break; | |
132 | |
133 case ABE_RIGHT: | |
134 abd.rc.left = abd.rc.right - iWidth; | |
135 break; | |
136 } | |
137 | |
138 CopyRect(rc, &abd.rc); | |
139 } | |
140 | |
141 static void gtk_appbar_setpos(GtkAppBar *ab, HWND hwnd) { | |
142 APPBARDATA abd; | |
143 | |
144 if(!ab->registered) | |
145 gtk_appbar_register(ab, hwnd); | |
146 | |
147 abd.hWnd = hwnd; | |
148 abd.cbSize = sizeof(APPBARDATA); | |
149 CopyRect(&abd.rc, &(ab->docked_rect)); | |
150 abd.uEdge = ab->side; | |
151 | |
152 SHAppBarMessage(ABM_SETPOS, &abd); | |
153 } | |
154 | |
155 static GdkFilterReturn wnd_moving(GtkAppBar *ab, GdkXEvent *xevent) { | |
156 MSG *msg = (MSG*)xevent; | |
157 POINT cp; | |
158 LONG cxScreen; | |
159 RECT *rc = (RECT*)msg->lParam; | |
160 int side = -1; | |
161 | |
162 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_moving\n"); | |
163 | |
164 cxScreen = GetSystemMetrics(SM_CXSCREEN); | |
165 GetCursorPos(&cp); | |
166 | |
167 /* Which part of the screen are we in ? */ | |
168 if( cp.x > (cxScreen - (cxScreen / 10)) ) | |
169 side = ABE_RIGHT; | |
170 else if( cp.x < (cxScreen / 10) ) | |
171 side = ABE_LEFT; | |
172 | |
173 if(!ab->docked) { | |
174 if( (side == ABE_RIGHT || side == ABE_LEFT) ) { | |
175 if( !ab->docking ) { | |
176 ab->side = side; | |
177 GetWindowRect(msg->hwnd, &(ab->docked_rect)); | |
178 gtk_appbar_querypos(ab, msg->hwnd, &(ab->docked_rect)); | |
179 | |
180 /* save pre-docking height */ | |
181 ab->undocked_height = rc->bottom - rc->top; | |
182 ab->docking = TRUE; | |
183 } | |
184 } | |
185 else | |
186 ab->docking = FALSE; | |
187 } | |
188 else if(side < 0) { | |
189 gtk_appbar_unregister(ab, msg->hwnd); | |
190 rc->bottom = rc->top + ab->undocked_height; | |
191 } | |
192 | |
193 /* Switch to toolbar/regular caption*/ | |
194 if(ab->docking) | |
195 set_toolbar(msg->hwnd, TRUE); | |
196 else if(!ab->docked) | |
197 set_toolbar(msg->hwnd, FALSE); | |
198 | |
199 return GDK_FILTER_CONTINUE; | |
200 } | |
201 | |
202 static GdkFilterReturn wnd_sizing(GtkAppBar *ab, GdkXEvent *xevent) { | |
203 MSG *msg = (MSG*)xevent; | |
204 | |
205 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_sizing\n"); | |
206 if(ab->docked) { | |
207 RECT *rc = (RECT*)msg->lParam; | |
208 if(ab->side == ABE_LEFT && msg->wParam == WMSZ_RIGHT) { | |
209 ab->docked_rect.right = rc->right; | |
210 gtk_appbar_setpos(ab, msg->hwnd); | |
211 } | |
212 else if(ab->side == ABE_RIGHT && msg->wParam == WMSZ_LEFT) { | |
213 ab->docked_rect.left = rc->left; | |
214 gtk_appbar_setpos(ab, msg->hwnd); | |
215 } | |
216 return GDK_FILTER_REMOVE; | |
217 } | |
218 return GDK_FILTER_CONTINUE; | |
219 } | |
220 | |
221 static GdkFilterReturn wnd_poschanging(GtkAppBar *ab, GdkXEvent *xevent) { | |
222 MSG *msg = (MSG*)xevent; | |
223 WINDOWPOS *wpos = (WINDOWPOS*)msg->lParam; | |
224 | |
225 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_poschanging\n"); | |
226 | |
227 if(ab->docked || ab->docking) { | |
228 wpos->x = ab->docked_rect.left; | |
229 wpos->y = ab->docked_rect.top; | |
230 wpos->cx = ab->docked_rect.right - ab->docked_rect.left; | |
231 wpos->cy = ab->docked_rect.bottom - ab->docked_rect.top; | |
232 if(IsIconic(msg->hwnd)) | |
233 set_toolbar(msg->hwnd, FALSE); | |
234 /*return GDK_FILTER_REMOVE;*/ | |
235 } | |
236 return GDK_FILTER_CONTINUE; | |
237 } | |
238 | |
239 static GdkFilterReturn wnd_exitsizemove(GtkAppBar *ab, GdkXEvent *xevent) { | |
240 MSG *msg = (MSG*)xevent; | |
241 | |
242 if(ab->docking) { | |
243 gtk_appbar_setpos(ab, msg->hwnd); | |
244 ab->docking = FALSE; | |
245 ab->docked = TRUE; | |
246 } | |
247 else if(!ab->docked) { | |
248 gtk_appbar_unregister(ab, msg->hwnd); | |
249 } | |
250 | |
251 return GDK_FILTER_CONTINUE; | |
252 } | |
253 | |
254 static GdkFilterReturn wnd_showwindow(GtkAppBar *ab, GdkXEvent *xevent) { | |
255 MSG *msg = (MSG*)xevent; | |
256 | |
257 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_showwindow\n"); | |
258 if(msg->wParam && ab->docked) { | |
259 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "shown\n"); | |
260 ab->docked = FALSE; | |
261 gtk_appbar_dock(ab, ab->side); | |
262 | |
263 } | |
264 else if(!msg->wParam && ab->docked) { | |
265 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "hidden\n"); | |
266 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); | |
267 set_toolbar(GDK_WINDOW_HWND(ab->win->window), FALSE); | |
268 ab->docked = TRUE; | |
269 } | |
270 return GDK_FILTER_CONTINUE; | |
271 } | |
272 | |
273 static GdkFilterReturn wnd_size(GtkAppBar *ab, GdkXEvent *xevent) { | |
274 MSG *msg = (MSG*)xevent; | |
275 | |
276 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_size\n"); | |
277 | |
278 if(msg->wParam == SIZE_MINIMIZED) { | |
279 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "Minimize\n"); | |
280 if(ab->docked) { | |
281 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); | |
282 ab->docked = TRUE; | |
283 } | |
284 } | |
285 else if(msg->wParam == SIZE_RESTORED) { | |
286 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "Restore\n"); | |
287 if(ab->docked) { | |
288 gtk_appbar_dock(ab, ab->side); | |
289 } | |
290 } | |
291 return GDK_FILTER_CONTINUE; | |
292 } | |
293 | |
294 static GdkFilterReturn wnd_nchittest(GtkAppBar *ab, GdkXEvent *xevent) { | |
295 MSG *msg = (MSG*)xevent; | |
296 | |
297 if(ab->docked) { | |
298 UINT ret = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam); | |
299 | |
300 switch(ret) { | |
301 case HTBOTTOM: | |
302 case HTBOTTOMLEFT: | |
303 case HTBOTTOMRIGHT: | |
304 case HTTOP: | |
305 case HTTOPLEFT: | |
306 case HTTOPRIGHT: | |
307 return GDK_FILTER_REMOVE; | |
308 case HTLEFT: | |
309 if(ab->side == ABE_LEFT) | |
310 return GDK_FILTER_REMOVE; | |
311 break; | |
312 case HTRIGHT: | |
313 if(ab->side == ABE_RIGHT) | |
314 return GDK_FILTER_REMOVE; | |
315 break; | |
316 } | |
317 } | |
318 return GDK_FILTER_CONTINUE; | |
319 } | |
320 | |
321 #if 0 | |
322 static GdkFilterReturn wnd_initmenupopup(GtkAppBar *ab, GdkXEvent *xevent) { | |
323 MSG *msg = (MSG*)xevent; | |
324 | |
325 if(ab->docked && HIWORD(msg->lParam)) { | |
326 HMENU sysmenu = GetSystemMenu(msg->hwnd, FALSE); | |
327 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_initpopupmenu: docked: %d ismenu: %d\n", ab->docked, IsMenu(sysmenu)); | |
328 if(EnableMenuItem(sysmenu, SC_MAXIMIZE, MF_BYCOMMAND|MF_GRAYED)<0) | |
329 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "SC_MAXIMIZE Menu item does not exist\n"); | |
330 if(EnableMenuItem(sysmenu, SC_MOVE, MF_BYCOMMAND|MF_GRAYED)<0) | |
331 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "SC_MOVE Menu item does not exist\n"); | |
332 return GDK_FILTER_CONTINUE; | |
333 } | |
334 else | |
335 GetSystemMenu(msg->hwnd, TRUE); | |
336 return GDK_FILTER_CONTINUE; | |
337 } | |
338 #endif | |
339 | |
340 static GdkFilterReturn gtk_appbar_callback(GtkAppBar *ab, GdkXEvent *xevent) { | |
341 MSG *msg = (MSG*)xevent; | |
342 | |
343 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback\n"); | |
344 switch (msg->wParam) { | |
345 case ABN_STATECHANGE: | |
346 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_STATECHANGE\n"); | |
347 break; | |
348 | |
349 case ABN_FULLSCREENAPP: | |
350 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_FULLSCREENAPP: %d\n", (BOOL)msg->lParam); | |
351 break; | |
352 | |
353 case ABN_POSCHANGED: | |
354 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_POSCHANGED\n"); | |
355 gtk_appbar_querypos(ab, msg->hwnd, &(ab->docked_rect)); | |
356 MoveWindow(msg->hwnd, ab->docked_rect.left, ab->docked_rect.top, | |
357 ab->docked_rect.right - ab->docked_rect.left, | |
358 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); | |
359 gtk_appbar_setpos(ab, msg->hwnd); | |
360 break; | |
361 } | |
362 return GDK_FILTER_CONTINUE; | |
363 } | |
364 | |
365 static GdkFilterReturn gtk_appbar_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) { | |
366 MSG *msg = (MSG*)xevent; | |
367 | |
368 /*printf("MSG: %s\n", message_to_string (msg->message));*/ | |
369 switch(msg->message) { | |
370 case WM_EXITSIZEMOVE: | |
371 return wnd_exitsizemove(data, xevent); | |
372 case WM_WINDOWPOSCHANGING: | |
373 return wnd_poschanging(data, xevent); | |
374 case WM_SIZING: | |
375 return wnd_sizing(data, xevent); | |
376 case WM_MOVING: | |
377 return wnd_moving(data, xevent); | |
378 case WM_SHOWWINDOW: | |
379 return wnd_showwindow(data, xevent); | |
380 case WM_NCHITTEST: | |
381 return wnd_nchittest(data, xevent); | |
382 #if 0 | |
383 case WM_INITMENUPOPUP: | |
384 return wnd_initmenupopup(data, xevent); | |
385 #endif | |
386 case WM_SIZE: | |
387 return wnd_size(data, xevent); | |
388 case APPBAR_CALLBACK: | |
389 return gtk_appbar_callback(data, xevent); | |
390 default: | |
391 } | |
392 return GDK_FILTER_CONTINUE; | |
393 } | |
394 | |
395 void gtk_appbar_dock(GtkAppBar *ab, UINT side) { | |
396 RECT orig; | |
397 | |
398 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_dock\n"); | |
399 | |
400 if(!ab || !IsWindow(GDK_WINDOW_HWND(ab->win->window))) | |
401 return; | |
402 | |
403 ab->side = side; | |
404 get_window_normal_rc(GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect)); | |
405 CopyRect(&orig, &(ab->docked_rect)); | |
406 print_rect(&(ab->docked_rect)); | |
407 gtk_appbar_querypos(ab, GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect)); | |
408 if(EqualRect(&orig, &(ab->docked_rect)) == 0) | |
409 MoveWindow(GDK_WINDOW_HWND(ab->win->window), | |
410 ab->docked_rect.left, | |
411 ab->docked_rect.top, | |
412 ab->docked_rect.right - ab->docked_rect.left, | |
413 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); | |
414 gtk_appbar_setpos(ab, GDK_WINDOW_HWND(ab->win->window)); | |
415 set_toolbar(GDK_WINDOW_HWND(ab->win->window), TRUE); | |
416 ab->docked = TRUE; | |
417 } | |
418 | |
419 GtkAppBar *gtk_appbar_add(GtkWidget *win) { | |
420 GtkAppBar *ab; | |
421 | |
422 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_add\n"); | |
423 | |
424 if(!win) | |
425 return NULL; | |
426 ab = g_new0(GtkAppBar, 1); | |
427 ab->win = win; | |
428 | |
429 /* init docking coords */ | |
430 get_window_normal_rc(GDK_WINDOW_HWND(win->window), &(ab->docked_rect)); | |
431 | |
432 /* Add main window filter */ | |
433 gdk_window_add_filter(win->window, | |
434 gtk_appbar_event_filter, | |
435 ab); | |
436 return ab; | |
437 } | |
438 | |
439 void gtk_appbar_remove(GtkAppBar *ab) { | |
440 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_remove\n"); | |
441 | |
442 if(!ab) | |
443 return; | |
444 gdk_window_remove_filter(ab->win->window, | |
445 gtk_appbar_event_filter, | |
446 ab); | |
447 if(ab->docked) { | |
448 gtk_window_resize(GTK_WINDOW(ab->win), | |
449 ab->docked_rect.right - ab->docked_rect.left, | |
450 ab->undocked_height); | |
451 set_toolbar(GDK_WINDOW_HWND(ab->win->window), FALSE); | |
452 } | |
453 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); | |
454 | |
455 g_free(ab); | |
456 } |