comparison plugins/win32/winprefs/gtkappbar.c @ 10531:940f0d8ce380

[gaim-migrate @ 11858] This is multi-monitor support for docking. This also should fix the multiple "Show Desktop" request causing the contents of of the docked buddy list to permanently disappear. I also added a handling of a couple Window Manager events that probably aren't really necessary, but the MSDN docs say they are. This is certainly not C89 compliant (variable declaration), but it is win32 API, so it probably doesn't matter. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Thu, 20 Jan 2005 03:16:04 +0000
parents 719fc957e9ee
children f348b3439ce4
comparison
equal deleted inserted replaced
10530:a1eddb973f42 10531:940f0d8ce380
35 #include "gtkappbar.h" 35 #include "gtkappbar.h"
36 #include "debug.h" 36 #include "debug.h"
37 37
38 #define APPBAR_CALLBACK WM_USER + 1010 38 #define APPBAR_CALLBACK WM_USER + 1010
39 39
40 typedef HMONITOR WINAPI gaim_MonitorFromPoint(POINT, DWORD);
41 typedef HMONITOR WINAPI gaim_MonitorFromWindow(HWND, DWORD);
42 typedef BOOL WINAPI gaim_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 gaim_GetMonitorInfo *the_GetMonitorInfo;
50
51 if (!(the_GetMonitorInfo = (gaim_GetMonitorInfo*)
52 GetProcAddress(hmod, "GetMonitorInfoA"))) {
53 return FALSE;
54 }
55
56 MONITORINFO info;
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
75 if (!(hmod = GetModuleHandle("user32"))) {
76 return FALSE;
77 }
78
79 gaim_MonitorFromPoint *the_MonitorFromPoint;
80 if (!(the_MonitorFromPoint = (gaim_MonitorFromPoint*)
81 GetProcAddress(hmod, "MonitorFromPoint"))) {
82 return FALSE;
83 }
84
85 HMONITOR monitor =
86 the_MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
87
88 return get_rect_from_monitor(hmod, monitor, rect);
89 }
90
91 /**
92 * This will only work on Win98+ and Win2K+
93 * Return TRUE if successful, otherwise FALSE
94 */
95 static gboolean
96 get_rect_of_window_multimonitor(HWND window, RECT *rect) {
97 HMODULE hmod;
98
99 if (!(hmod = GetModuleHandle("user32"))) {
100 return FALSE;
101 }
102
103 gaim_MonitorFromWindow *the_MonitorFromWindow;
104 if (!(the_MonitorFromWindow = (gaim_MonitorFromWindow*)
105 GetProcAddress(hmod, "MonitorFromWindow"))) {
106 return FALSE;
107 }
108
109 HMONITOR monitor =
110 the_MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
111
112 return get_rect_from_monitor(hmod, monitor, rect);
113 }
114
115 /*
116 * Fallback if cannot get the RECT from the monitor directly
117 */
118 static void get_default_workarea(RECT *rect) {
119 if (!SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, FALSE)) {
120 /* I don't think this will ever happen */
121 rect->left = 0;
122 rect->top = 0;
123 rect->bottom = GetSystemMetrics(SM_CYSCREEN);
124 rect->right = GetSystemMetrics(SM_CXSCREEN);
125 }
126 }
127
128 /* Retrieve the rectangle of the active work area at a point */
129 static RECT get_rect_at_point(POINT pt) {
130 RECT rc;
131 if (!get_rect_at_point_multimonitor(pt, &rc)) {
132 get_default_workarea(&rc);
133 }
134 return rc;
135 }
136
137 /* Retrieve the rectangle of the active work area of a window*/
138 static RECT get_rect_of_window(HWND window) {
139 RECT rc;
140 if (!get_rect_of_window_multimonitor(window, &rc)) {
141 get_default_workarea(&rc);
142 }
143 return rc;
144 }
145
40 static void get_window_normal_rc(HWND hwnd, RECT *rc) { 146 static void get_window_normal_rc(HWND hwnd, RECT *rc) {
41 WINDOWPLACEMENT wplc; 147 WINDOWPLACEMENT wplc;
42 GetWindowPlacement(hwnd, &wplc); 148 GetWindowPlacement(hwnd, &wplc);
43 CopyRect(rc, &wplc.rcNormalPosition); 149 CopyRect(rc, &wplc.rcNormalPosition);
44 } 150 }
45 151 #if 0
46 static void print_rect(RECT *rc) { 152 static void print_rect(RECT *rc) {
47 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "RECT: L:%ld R:%ld T:%ld B:%ld\n", 153 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); 154 rc->left, rc->right, rc->top, rc->bottom);
49 } 155 }
50 156 #endif
51 static void set_toolbar(HWND hwnd, gboolean val) { 157 static void set_toolbar(HWND hwnd, gboolean val) {
52 LONG style=0; 158 LONG style=0;
53 159
54 style = GetWindowLong(hwnd, GWL_EXSTYLE); 160 style = GetWindowLong(hwnd, GWL_EXSTYLE);
55 if(val && !(style & WS_EX_TOOLWINDOW)) 161 if(val && !(style & WS_EX_TOOLWINDOW))
57 else if(!val && style & WS_EX_TOOLWINDOW) 163 else if(!val && style & WS_EX_TOOLWINDOW)
58 style &= ~WS_EX_TOOLWINDOW; 164 style &= ~WS_EX_TOOLWINDOW;
59 else 165 else
60 return; 166 return;
61 SetWindowLong(hwnd, GWL_EXSTYLE, style); 167 SetWindowLong(hwnd, GWL_EXSTYLE, style);
62 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); 168 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
169 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
170
171 /* This really should be the following, but SWP_FRAMECHANGED strangely causes initermittent problems "Show Desktop" done more than once.
172 * Not having SWP_FRAMECHANGED *should* cause the Style not to be applied, but i haven't noticed any problems
173 * SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
174 */
63 } 175 }
64 176
65 static gboolean gtk_appbar_register(GtkAppBar *ab, HWND hwnd) { 177 static gboolean gtk_appbar_register(GtkAppBar *ab, HWND hwnd) {
66 APPBARDATA abd; 178 APPBARDATA abd;
67 179
90 ab->docking = FALSE; 202 ab->docking = FALSE;
91 } 203 }
92 return !ab->registered; 204 return !ab->registered;
93 } 205 }
94 206
95 static void gtk_appbar_querypos(GtkAppBar *ab, HWND hwnd, RECT *rc) { 207 static void gtk_appbar_querypos(GtkAppBar *ab, HWND hwnd, RECT rcWorkspace) {
96 APPBARDATA abd; 208 APPBARDATA abd;
97 int iWidth = 0; 209 guint iWidth = 0;
98 210
99 if(!ab->registered) 211 if(!ab->registered)
100 gtk_appbar_register(ab, hwnd); 212 gtk_appbar_register(ab, hwnd);
101 213
102 abd.hWnd = hwnd; 214 abd.hWnd = hwnd;
103 abd.cbSize = sizeof(APPBARDATA); 215 abd.cbSize = sizeof(APPBARDATA);
104 CopyRect(&abd.rc, rc);
105 abd.uEdge = ab->side; 216 abd.uEdge = ab->side;
106 217
107 iWidth = abd.rc.right - abd.rc.left; 218 iWidth = ab->docked_rect.right - ab->docked_rect.left;
108 219
109 abd.rc.top = 0; 220 abd.rc.top = rcWorkspace.top;
110 abd.rc.bottom = GetSystemMetrics(SM_CYSCREEN); 221 abd.rc.bottom = rcWorkspace.bottom;
111 switch (abd.uEdge) 222 switch (abd.uEdge)
112 { 223 {
113 case ABE_LEFT: 224 case ABE_LEFT:
114 abd.rc.left = 0; 225 abd.rc.left = rcWorkspace.left;
115 abd.rc.right = iWidth; 226 abd.rc.right = rcWorkspace.left + iWidth;
116 break; 227 break;
117 228
118 case ABE_RIGHT: 229 case ABE_RIGHT:
119 abd.rc.right = GetSystemMetrics(SM_CXSCREEN); 230 abd.rc.right = rcWorkspace.right;
120 abd.rc.left = abd.rc.right - iWidth; 231 abd.rc.left = rcWorkspace.right - iWidth;
121 break; 232 break;
122 } 233 }
123 234
124 /* Ask the system for the screen space */ 235 /* Ask the system for the screen space */
125 SHAppBarMessage(ABM_QUERYPOS, &abd); 236 SHAppBarMessage(ABM_QUERYPOS, &abd);
133 case ABE_RIGHT: 244 case ABE_RIGHT:
134 abd.rc.left = abd.rc.right - iWidth; 245 abd.rc.left = abd.rc.right - iWidth;
135 break; 246 break;
136 } 247 }
137 248
138 CopyRect(rc, &abd.rc); 249 CopyRect(&(ab->docked_rect), &abd.rc);
139 } 250 }
140 251
141 static void gtk_appbar_setpos(GtkAppBar *ab, HWND hwnd) { 252 static void gtk_appbar_setpos(GtkAppBar *ab, HWND hwnd) {
142 APPBARDATA abd; 253 APPBARDATA abd;
143 254
163 } 274 }
164 275
165 static GdkFilterReturn wnd_moving(GtkAppBar *ab, GdkXEvent *xevent) { 276 static GdkFilterReturn wnd_moving(GtkAppBar *ab, GdkXEvent *xevent) {
166 MSG *msg = (MSG*)xevent; 277 MSG *msg = (MSG*)xevent;
167 POINT cp; 278 POINT cp;
168 LONG cxScreen;
169 RECT *rc = (RECT*)msg->lParam; 279 RECT *rc = (RECT*)msg->lParam;
280 RECT monRect;
170 int side = -1; 281 int side = -1;
282 long dockAreaWidth = 0;
171 283
172 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_moving\n"); 284 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_moving\n");
173 285
174 cxScreen = GetSystemMetrics(SM_CXSCREEN);
175 GetCursorPos(&cp); 286 GetCursorPos(&cp);
176 287 monRect = get_rect_at_point(cp);
288
289 dockAreaWidth = (monRect.right - monRect.left) / 10;
177 /* Which part of the screen are we in ? */ 290 /* Which part of the screen are we in ? */
178 if( cp.x > (cxScreen - (cxScreen / 10)) ) 291 if (cp.x > (monRect.right - dockAreaWidth)) {
179 side = ABE_RIGHT; 292 side = ABE_RIGHT;
180 else if( cp.x < (cxScreen / 10) ) 293 } else if (cp.x < (monRect.left + dockAreaWidth)) {
181 side = ABE_LEFT; 294 side = ABE_LEFT;
295 }
182 296
183 if(!ab->docked) { 297 if(!ab->docked) {
184 if( (side == ABE_RIGHT || side == ABE_LEFT) ) { 298 if( (side == ABE_RIGHT || side == ABE_LEFT) ) {
185 if( !ab->docking ) { 299 if( !ab->docking ) {
186 ab->side = side; 300 ab->side = side;
187 GetWindowRect(msg->hwnd, &(ab->docked_rect)); 301 GetWindowRect(msg->hwnd, &(ab->docked_rect));
188 gtk_appbar_querypos(ab, msg->hwnd, &(ab->docked_rect)); 302 gtk_appbar_querypos(ab, msg->hwnd, monRect);
189 303
190 /* save pre-docking height */ 304 /* save pre-docking height */
191 ab->undocked_height = rc->bottom - rc->top; 305 ab->undocked_height = rc->bottom - rc->top;
192 ab->docking = TRUE; 306 ab->docking = TRUE;
193 } 307 }
224 gtk_appbar_setpos(ab, msg->hwnd); 338 gtk_appbar_setpos(ab, msg->hwnd);
225 } 339 }
226 return GDK_FILTER_REMOVE; 340 return GDK_FILTER_REMOVE;
227 } 341 }
228 return GDK_FILTER_CONTINUE; 342 return GDK_FILTER_CONTINUE;
343 }
344
345 static GdkFilterReturn wnd_activate(GdkXEvent *xevent) {
346 APPBARDATA abd;
347 MSG *msg = (MSG*)xevent;
348 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_activate\n");
349
350 abd.hWnd = msg->hwnd;
351 abd.cbSize = sizeof(APPBARDATA);
352
353 SHAppBarMessage(ABM_ACTIVATE, &abd);
354 return GDK_FILTER_CONTINUE;
355 }
356
357 static GdkFilterReturn wnd_poschanged(GdkXEvent *xevent) {
358 APPBARDATA abd;
359 MSG *msg = (MSG*)xevent;
360 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_poschanged\n");
361
362 abd.hWnd = msg->hwnd;
363 abd.cbSize = sizeof(APPBARDATA);
364
365 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
366 return GDK_FILTER_CONTINUE;
229 } 367 }
230 368
231 static GdkFilterReturn wnd_poschanging(GtkAppBar *ab, GdkXEvent *xevent) { 369 static GdkFilterReturn wnd_poschanging(GtkAppBar *ab, GdkXEvent *xevent) {
232 MSG *msg = (MSG*)xevent; 370 MSG *msg = (MSG*)xevent;
233 WINDOWPOS *wpos = (WINDOWPOS*)msg->lParam; 371 WINDOWPOS *wpos = (WINDOWPOS*)msg->lParam;
349 } 487 }
350 #endif 488 #endif
351 489
352 static GdkFilterReturn gtk_appbar_callback(GtkAppBar *ab, GdkXEvent *xevent) { 490 static GdkFilterReturn gtk_appbar_callback(GtkAppBar *ab, GdkXEvent *xevent) {
353 MSG *msg = (MSG*)xevent; 491 MSG *msg = (MSG*)xevent;
354 492 RECT orig;
355 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback\n"); 493
356 switch (msg->wParam) { 494 switch (msg->wParam) {
357 case ABN_STATECHANGE: 495 case ABN_STATECHANGE:
358 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_STATECHANGE\n"); 496 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_STATECHANGE\n");
359 break; 497 break;
360 498
361 case ABN_FULLSCREENAPP: 499 case ABN_FULLSCREENAPP:
362 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_FULLSCREENAPP: %d\n", (BOOL)msg->lParam); 500 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_FULLSCREENAPP: %d\n", (BOOL)msg->lParam);
501 if ((BOOL)msg->lParam) {
502 SetWindowPos(msg->hwnd, HWND_BOTTOM, 0, 0, 0, 0,
503 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
504 } else {
505 SetWindowPos(msg->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
506 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
507 }
508
363 break; 509 break;
364 510
365 case ABN_POSCHANGED: 511 case ABN_POSCHANGED:
366 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_POSCHANGED\n"); 512 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_POSCHANGED\n");
367 gtk_appbar_querypos(ab, msg->hwnd, &(ab->docked_rect)); 513 CopyRect(&orig, &(ab->docked_rect));
368 MoveWindow(msg->hwnd, ab->docked_rect.left, ab->docked_rect.top, 514 gtk_appbar_querypos(ab, msg->hwnd, get_rect_of_window(msg->hwnd));
369 ab->docked_rect.right - ab->docked_rect.left, 515 if (EqualRect(&orig, &(ab->docked_rect)) == 0) {
370 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); 516 MoveWindow(msg->hwnd, ab->docked_rect.left, ab->docked_rect.top,
517 ab->docked_rect.right - ab->docked_rect.left,
518 ab->docked_rect.bottom - ab->docked_rect.top, TRUE);
519 }
371 gtk_appbar_setpos(ab, msg->hwnd); 520 gtk_appbar_setpos(ab, msg->hwnd);
372 break; 521 break;
522 #if 0
523 default:
524 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: %d\n", msg->wParam);
525 #endif
373 } 526 }
374 return GDK_FILTER_CONTINUE; 527 return GDK_FILTER_CONTINUE;
375 } 528 }
376 529
377 static GdkFilterReturn gtk_appbar_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) { 530 static GdkFilterReturn gtk_appbar_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) {
381 switch(msg->message) { 534 switch(msg->message) {
382 case WM_EXITSIZEMOVE: 535 case WM_EXITSIZEMOVE:
383 return wnd_exitsizemove(data, xevent); 536 return wnd_exitsizemove(data, xevent);
384 case WM_WINDOWPOSCHANGING: 537 case WM_WINDOWPOSCHANGING:
385 return wnd_poschanging(data, xevent); 538 return wnd_poschanging(data, xevent);
539 case WM_WINDOWPOSCHANGED:
540 return wnd_poschanged(xevent);
541 case WM_ACTIVATE:
542 return wnd_activate(xevent);
386 case WM_SIZING: 543 case WM_SIZING:
387 return wnd_sizing(data, xevent); 544 return wnd_sizing(data, xevent);
388 case WM_MOVING: 545 case WM_MOVING:
389 return wnd_moving(data, xevent); 546 return wnd_moving(data, xevent);
390 case WM_SHOWWINDOW: 547 case WM_SHOWWINDOW:
397 #endif 554 #endif
398 case WM_SIZE: 555 case WM_SIZE:
399 return wnd_size(data, xevent); 556 return wnd_size(data, xevent);
400 case APPBAR_CALLBACK: 557 case APPBAR_CALLBACK:
401 return gtk_appbar_callback(data, xevent); 558 return gtk_appbar_callback(data, xevent);
559 #if 0
560 default:
561 gaim_debug_info("gtkappbar", "gtk_appbar_event_filter %d\n", msg->message);
562 #endif
402 } 563 }
403 return GDK_FILTER_CONTINUE; 564 return GDK_FILTER_CONTINUE;
404 } 565 }
405 566
406 void gtk_appbar_dock(GtkAppBar *ab, UINT side) { 567 void gtk_appbar_dock(GtkAppBar *ab, UINT side) {
412 return; 573 return;
413 574
414 ab->side = side; 575 ab->side = side;
415 get_window_normal_rc(GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect)); 576 get_window_normal_rc(GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect));
416 CopyRect(&orig, &(ab->docked_rect)); 577 CopyRect(&orig, &(ab->docked_rect));
417 print_rect(&(ab->docked_rect)); 578 gtk_appbar_querypos(ab, GDK_WINDOW_HWND(ab->win->window),
418 gtk_appbar_querypos(ab, GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect)); 579 get_rect_of_window(GDK_WINDOW_HWND(ab->win->window)));
419 if(EqualRect(&orig, &(ab->docked_rect)) == 0) 580 if(EqualRect(&orig, &(ab->docked_rect)) == 0)
420 MoveWindow(GDK_WINDOW_HWND(ab->win->window), 581 MoveWindow(GDK_WINDOW_HWND(ab->win->window),
421 ab->docked_rect.left, 582 ab->docked_rect.left,
422 ab->docked_rect.top, 583 ab->docked_rect.top,
423 ab->docked_rect.right - ab->docked_rect.left, 584 ab->docked_rect.right - ab->docked_rect.left,