| 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 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 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 MONITORINFO info; |
|
| 51 |
|
| 52 if (!(the_GetMonitorInfo = (gaim_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 gaim_MonitorFromPoint *the_MonitorFromPoint; |
|
| 75 HMONITOR monitor; |
|
| 76 |
|
| 77 if (!(hmod = GetModuleHandle("user32"))) { |
|
| 78 return FALSE; |
|
| 79 } |
|
| 80 |
|
| 81 if (!(the_MonitorFromPoint = (gaim_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 gaim_MonitorFromWindow *the_MonitorFromWindow; |
|
| 100 HMONITOR monitor; |
|
| 101 |
|
| 102 if (!(hmod = GetModuleHandle("user32"))) { |
|
| 103 return FALSE; |
|
| 104 } |
|
| 105 |
|
| 106 if (!(the_MonitorFromWindow = (gaim_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 RECT get_rect_at_point(POINT pt) { |
|
| 132 RECT rc; |
|
| 133 if (!get_rect_at_point_multimonitor(pt, &rc)) { |
|
| 134 get_default_workarea(&rc); |
|
| 135 } |
|
| 136 return rc; |
|
| 137 } |
|
| 138 |
|
| 139 /* Retrieve the rectangle of the active work area of a window*/ |
|
| 140 static RECT get_rect_of_window(HWND window) { |
|
| 141 RECT rc; |
|
| 142 if (!get_rect_of_window_multimonitor(window, &rc)) { |
|
| 143 get_default_workarea(&rc); |
|
| 144 } |
|
| 145 return rc; |
|
| 146 } |
|
| 147 |
|
| 148 static void get_window_normal_rc(HWND hwnd, RECT *rc) { |
|
| 149 WINDOWPLACEMENT wplc; |
|
| 150 GetWindowPlacement(hwnd, &wplc); |
|
| 151 CopyRect(rc, &wplc.rcNormalPosition); |
|
| 152 } |
|
| 153 #if 0 |
|
| 154 static void print_rect(RECT *rc) { |
|
| 155 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "RECT: L:%ld R:%ld T:%ld B:%ld\n", |
|
| 156 rc->left, rc->right, rc->top, rc->bottom); |
|
| 157 } |
|
| 158 #endif |
|
| 159 /** Set the window style to be the "Tool Window" style - small header, no min/max buttons */ |
|
| 160 static void set_toolbar(HWND hwnd, gboolean val) { |
|
| 161 LONG style=0; |
|
| 162 |
|
| 163 style = GetWindowLong(hwnd, GWL_EXSTYLE); |
|
| 164 if(val && !(style & WS_EX_TOOLWINDOW)) |
|
| 165 style |= WS_EX_TOOLWINDOW; |
|
| 166 else if(!val && style & WS_EX_TOOLWINDOW) |
|
| 167 style &= ~WS_EX_TOOLWINDOW; |
|
| 168 else |
|
| 169 return; |
|
| 170 SetWindowLong(hwnd, GWL_EXSTYLE, style); |
|
| 171 SetWindowPos(hwnd, 0, 0, 0, 0, 0, |
|
| 172 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); |
|
| 173 |
|
| 174 /* This really should be the following, but SWP_FRAMECHANGED strangely causes initermittent problems "Show Desktop" done more than once. |
|
| 175 * Not having SWP_FRAMECHANGED *should* cause the Style not to be applied, but i haven't noticed any problems |
|
| 176 * SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); |
|
| 177 */ |
|
| 178 } |
|
| 179 /** Register the window as an appbar */ |
|
| 180 static gboolean gtk_appbar_register(GtkAppBar *ab, HWND hwnd) { |
|
| 181 APPBARDATA abd; |
|
| 182 |
|
| 183 abd.cbSize = sizeof(APPBARDATA); |
|
| 184 abd.hWnd = hwnd; |
|
| 185 abd.uCallbackMessage = APPBAR_CALLBACK; |
|
| 186 |
|
| 187 ab->registered = SHAppBarMessage(ABM_NEW, &abd); |
|
| 188 |
|
| 189 return ab->registered; |
|
| 190 } |
|
| 191 /** Unregister the window as an appbar */ |
|
| 192 static gboolean gtk_appbar_unregister(GtkAppBar *ab, HWND hwnd) { |
|
| 193 APPBARDATA abd; |
|
| 194 |
|
| 195 if(!ab->registered) |
|
| 196 return TRUE; |
|
| 197 |
|
| 198 abd.cbSize = sizeof(APPBARDATA); |
|
| 199 abd.hWnd = hwnd; |
|
| 200 |
|
| 201 SHAppBarMessage(ABM_REMOVE, &abd); /** This always returns TRUE */ |
|
| 202 |
|
| 203 ab->registered = FALSE; |
|
| 204 |
|
| 205 ab->docked = FALSE; |
|
| 206 ab->docking = FALSE; |
|
| 207 |
|
| 208 return TRUE; |
|
| 209 } |
|
| 210 |
|
| 211 static void gtk_appbar_querypos(GtkAppBar *ab, HWND hwnd, RECT rcWorkspace) { |
|
| 212 APPBARDATA abd; |
|
| 213 guint iWidth = 0; |
|
| 214 |
|
| 215 if(!ab->registered) |
|
| 216 gtk_appbar_register(ab, hwnd); |
|
| 217 |
|
| 218 abd.hWnd = hwnd; |
|
| 219 abd.cbSize = sizeof(APPBARDATA); |
|
| 220 abd.uEdge = ab->side; |
|
| 221 |
|
| 222 iWidth = ab->docked_rect.right - ab->docked_rect.left; |
|
| 223 |
|
| 224 abd.rc.top = rcWorkspace.top; |
|
| 225 abd.rc.bottom = rcWorkspace.bottom; |
|
| 226 switch (abd.uEdge) |
|
| 227 { |
|
| 228 case ABE_LEFT: |
|
| 229 abd.rc.left = rcWorkspace.left; |
|
| 230 abd.rc.right = rcWorkspace.left + iWidth; |
|
| 231 break; |
|
| 232 |
|
| 233 case ABE_RIGHT: |
|
| 234 abd.rc.right = rcWorkspace.right; |
|
| 235 abd.rc.left = rcWorkspace.right - iWidth; |
|
| 236 break; |
|
| 237 } |
|
| 238 |
|
| 239 /* Ask the system for the screen space */ |
|
| 240 SHAppBarMessage(ABM_QUERYPOS, &abd); |
|
| 241 |
|
| 242 switch (abd.uEdge) |
|
| 243 { |
|
| 244 case ABE_LEFT: |
|
| 245 abd.rc.right = abd.rc.left + iWidth; |
|
| 246 break; |
|
| 247 |
|
| 248 case ABE_RIGHT: |
|
| 249 abd.rc.left = abd.rc.right - iWidth; |
|
| 250 break; |
|
| 251 } |
|
| 252 |
|
| 253 CopyRect(&(ab->docked_rect), &abd.rc); |
|
| 254 } |
|
| 255 /* Actually set the size and screen location of the appbar */ |
|
| 256 static void gtk_appbar_setpos(GtkAppBar *ab, HWND hwnd) { |
|
| 257 APPBARDATA abd; |
|
| 258 |
|
| 259 if(!ab->registered) |
|
| 260 gtk_appbar_register(ab, hwnd); |
|
| 261 |
|
| 262 abd.hWnd = hwnd; |
|
| 263 abd.cbSize = sizeof(APPBARDATA); |
|
| 264 CopyRect(&abd.rc, &(ab->docked_rect)); |
|
| 265 abd.uEdge = ab->side; |
|
| 266 |
|
| 267 SHAppBarMessage(ABM_SETPOS, &abd); |
|
| 268 } |
|
| 269 /** Let any callbacks know that we have docked or undocked */ |
|
| 270 static void gtk_appbar_dispatch_dock_cbs(GtkAppBar *ab, gboolean val) { |
|
| 271 GList *lst = ab->dock_cbs; |
|
| 272 |
|
| 273 while(lst) { |
|
| 274 GtkAppBarDockCB dock_cb = lst->data; |
|
| 275 dock_cb(val); |
|
| 276 lst = lst->next; |
|
| 277 } |
|
| 278 } |
|
| 279 |
|
| 280 static GdkFilterReturn wnd_moving(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 281 MSG *msg = (MSG*)xevent; |
|
| 282 POINT cp; |
|
| 283 RECT *rc = (RECT*)msg->lParam; |
|
| 284 RECT monRect; |
|
| 285 int side = -1; |
|
| 286 long dockAreaWidth = 0; |
|
| 287 |
|
| 288 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_moving\n"); |
|
| 289 |
|
| 290 GetCursorPos(&cp); |
|
| 291 monRect = get_rect_at_point(cp); |
|
| 292 |
|
| 293 dockAreaWidth = (monRect.right - monRect.left) / 10; |
|
| 294 /* Which part of the screen are we in ? */ |
|
| 295 if (cp.x > (monRect.right - dockAreaWidth)) { |
|
| 296 side = ABE_RIGHT; |
|
| 297 } else if (cp.x < (monRect.left + dockAreaWidth)) { |
|
| 298 side = ABE_LEFT; |
|
| 299 } |
|
| 300 |
|
| 301 if(!ab->docked) { |
|
| 302 if( (side == ABE_RIGHT || side == ABE_LEFT) ) { |
|
| 303 if( !ab->docking ) { |
|
| 304 ab->side = side; |
|
| 305 GetWindowRect(msg->hwnd, &(ab->docked_rect)); |
|
| 306 gtk_appbar_querypos(ab, msg->hwnd, monRect); |
|
| 307 |
|
| 308 /* save pre-docking height */ |
|
| 309 ab->undocked_height = rc->bottom - rc->top; |
|
| 310 ab->docking = TRUE; |
|
| 311 } |
|
| 312 } |
|
| 313 else |
|
| 314 ab->docking = FALSE; |
|
| 315 } |
|
| 316 else if(side < 0) { |
|
| 317 gtk_appbar_unregister(ab, msg->hwnd); |
|
| 318 rc->bottom = rc->top + ab->undocked_height; |
|
| 319 } |
|
| 320 |
|
| 321 /* Switch to toolbar/regular caption*/ |
|
| 322 if(ab->docking) |
|
| 323 set_toolbar(msg->hwnd, TRUE); |
|
| 324 else if(!ab->docked) |
|
| 325 set_toolbar(msg->hwnd, FALSE); |
|
| 326 |
|
| 327 return GDK_FILTER_CONTINUE; |
|
| 328 } |
|
| 329 |
|
| 330 static GdkFilterReturn wnd_sizing(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 331 MSG *msg = (MSG*)xevent; |
|
| 332 |
|
| 333 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_sizing\n"); |
|
| 334 if(ab->docked) { |
|
| 335 RECT *rc = (RECT*)msg->lParam; |
|
| 336 if(ab->side == ABE_LEFT && msg->wParam == WMSZ_RIGHT) { |
|
| 337 ab->docked_rect.right = rc->right; |
|
| 338 gtk_appbar_setpos(ab, msg->hwnd); |
|
| 339 } |
|
| 340 else if(ab->side == ABE_RIGHT && msg->wParam == WMSZ_LEFT) { |
|
| 341 ab->docked_rect.left = rc->left; |
|
| 342 gtk_appbar_setpos(ab, msg->hwnd); |
|
| 343 } |
|
| 344 return GDK_FILTER_REMOVE; |
|
| 345 } |
|
| 346 return GDK_FILTER_CONTINUE; |
|
| 347 } |
|
| 348 /** Notify the system that the appbar has been activated */ |
|
| 349 static GdkFilterReturn wnd_activate(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 350 if (ab->registered) { |
|
| 351 APPBARDATA abd; |
|
| 352 MSG *msg = (MSG*)xevent; |
|
| 353 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_activate\n"); |
|
| 354 |
|
| 355 abd.hWnd = msg->hwnd; |
|
| 356 abd.cbSize = sizeof(APPBARDATA); |
|
| 357 |
|
| 358 SHAppBarMessage(ABM_ACTIVATE, &abd); |
|
| 359 } |
|
| 360 return GDK_FILTER_CONTINUE; |
|
| 361 } |
|
| 362 /** Notify the system that the appbar's position has changed */ |
|
| 363 static GdkFilterReturn wnd_poschanged(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 364 if (ab->registered) { |
|
| 365 APPBARDATA abd; |
|
| 366 MSG *msg = (MSG*)xevent; |
|
| 367 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_poschanged\n"); |
|
| 368 |
|
| 369 abd.hWnd = msg->hwnd; |
|
| 370 abd.cbSize = sizeof(APPBARDATA); |
|
| 371 |
|
| 372 SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd); |
|
| 373 } |
|
| 374 return GDK_FILTER_CONTINUE; |
|
| 375 } |
|
| 376 /** The window is about to change */ |
|
| 377 static GdkFilterReturn wnd_poschanging(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 378 MSG *msg = (MSG*)xevent; |
|
| 379 WINDOWPOS *wpos = (WINDOWPOS*)msg->lParam; |
|
| 380 |
|
| 381 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_poschanging\n"); |
|
| 382 |
|
| 383 if(ab->docked || ab->docking) { |
|
| 384 wpos->x = ab->docked_rect.left; |
|
| 385 wpos->y = ab->docked_rect.top; |
|
| 386 wpos->cx = ab->docked_rect.right - ab->docked_rect.left; |
|
| 387 wpos->cy = ab->docked_rect.bottom - ab->docked_rect.top; |
|
| 388 if(IsIconic(msg->hwnd)) |
|
| 389 set_toolbar(msg->hwnd, FALSE); |
|
| 390 /*return GDK_FILTER_REMOVE;*/ |
|
| 391 } |
|
| 392 return GDK_FILTER_CONTINUE; |
|
| 393 } |
|
| 394 |
|
| 395 static GdkFilterReturn wnd_exitsizemove(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 396 MSG *msg = (MSG*)xevent; |
|
| 397 |
|
| 398 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_exitsizemove\n"); |
|
| 399 if(ab->docking) { |
|
| 400 gtk_appbar_setpos(ab, msg->hwnd); |
|
| 401 ab->docking = FALSE; |
|
| 402 ab->docked = TRUE; |
|
| 403 gtk_appbar_dispatch_dock_cbs(ab, TRUE); |
|
| 404 } |
|
| 405 else if(!ab->docked) { |
|
| 406 gtk_appbar_unregister(ab, msg->hwnd); |
|
| 407 gtk_appbar_dispatch_dock_cbs(ab, FALSE); |
|
| 408 } |
|
| 409 |
|
| 410 return GDK_FILTER_CONTINUE; |
|
| 411 } |
|
| 412 |
|
| 413 static GdkFilterReturn wnd_showwindow(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 414 MSG *msg = (MSG*)xevent; |
|
| 415 |
|
| 416 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_showwindow\n"); |
|
| 417 if(msg->wParam && ab->docked) { |
|
| 418 ab->iconized = FALSE; |
|
| 419 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "shown\n"); |
|
| 420 ab->docked = FALSE; |
|
| 421 gtk_appbar_dock(ab, ab->side); |
|
| 422 } |
|
| 423 else if(!msg->wParam && ab->docked) { |
|
| 424 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "hidden\n"); |
|
| 425 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); |
|
| 426 set_toolbar(GDK_WINDOW_HWND(ab->win->window), FALSE); |
|
| 427 ab->docked = TRUE; |
|
| 428 ab->iconized = TRUE; |
|
| 429 } |
|
| 430 return GDK_FILTER_CONTINUE; |
|
| 431 } |
|
| 432 /** The window's size has changed */ |
|
| 433 static GdkFilterReturn wnd_size(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 434 MSG *msg = (MSG*)xevent; |
|
| 435 |
|
| 436 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_size\n"); |
|
| 437 |
|
| 438 if(msg->wParam == SIZE_MINIMIZED) { |
|
| 439 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "Minimize\n"); |
|
| 440 if(ab->docked) { |
|
| 441 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); |
|
| 442 ab->docked = TRUE; |
|
| 443 } |
|
| 444 } |
|
| 445 else if(msg->wParam == SIZE_RESTORED) { |
|
| 446 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "Restore\n"); |
|
| 447 if (!ab->iconized && ab->docked) { |
|
| 448 gtk_appbar_dock(ab, ab->side); |
|
| 449 } |
|
| 450 } |
|
| 451 return GDK_FILTER_CONTINUE; |
|
| 452 } |
|
| 453 |
|
| 454 static GdkFilterReturn wnd_nchittest(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 455 MSG *msg = (MSG*)xevent; |
|
| 456 |
|
| 457 if(ab->docked) { |
|
| 458 UINT ret = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam); |
|
| 459 |
|
| 460 switch(ret) { |
|
| 461 case HTBOTTOM: |
|
| 462 case HTBOTTOMLEFT: |
|
| 463 case HTBOTTOMRIGHT: |
|
| 464 case HTTOP: |
|
| 465 case HTTOPLEFT: |
|
| 466 case HTTOPRIGHT: |
|
| 467 return GDK_FILTER_REMOVE; |
|
| 468 case HTLEFT: |
|
| 469 if(ab->side == ABE_LEFT) |
|
| 470 return GDK_FILTER_REMOVE; |
|
| 471 break; |
|
| 472 case HTRIGHT: |
|
| 473 if(ab->side == ABE_RIGHT) |
|
| 474 return GDK_FILTER_REMOVE; |
|
| 475 break; |
|
| 476 } |
|
| 477 } |
|
| 478 return GDK_FILTER_CONTINUE; |
|
| 479 } |
|
| 480 |
|
| 481 #if 0 |
|
| 482 static GdkFilterReturn wnd_initmenupopup(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 483 MSG *msg = (MSG*)xevent; |
|
| 484 |
|
| 485 if(ab->docked && HIWORD(msg->lParam)) { |
|
| 486 HMENU sysmenu = GetSystemMenu(msg->hwnd, FALSE); |
|
| 487 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "wnd_initpopupmenu: docked: %d ismenu: %d\n", ab->docked, IsMenu(sysmenu)); |
|
| 488 if(EnableMenuItem(sysmenu, SC_MAXIMIZE, MF_BYCOMMAND|MF_GRAYED)<0) |
|
| 489 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "SC_MAXIMIZE Menu item does not exist\n"); |
|
| 490 if(EnableMenuItem(sysmenu, SC_MOVE, MF_BYCOMMAND|MF_GRAYED)<0) |
|
| 491 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "SC_MOVE Menu item does not exist\n"); |
|
| 492 return GDK_FILTER_CONTINUE; |
|
| 493 } |
|
| 494 else |
|
| 495 GetSystemMenu(msg->hwnd, TRUE); |
|
| 496 return GDK_FILTER_CONTINUE; |
|
| 497 } |
|
| 498 #endif |
|
| 499 |
|
| 500 static GdkFilterReturn gtk_appbar_callback(GtkAppBar *ab, GdkXEvent *xevent) { |
|
| 501 MSG *msg = (MSG*)xevent; |
|
| 502 RECT orig; |
|
| 503 |
|
| 504 switch (msg->wParam) { |
|
| 505 case ABN_STATECHANGE: |
|
| 506 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_STATECHANGE\n"); |
|
| 507 break; |
|
| 508 |
|
| 509 case ABN_FULLSCREENAPP: |
|
| 510 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_FULLSCREENAPP: %d\n", (BOOL)msg->lParam); |
|
| 511 if (!ab->iconized && ab->docked) { |
|
| 512 if ((BOOL)msg->lParam) { |
|
| 513 SetWindowPos(msg->hwnd, HWND_BOTTOM, 0, 0, 0, 0, |
|
| 514 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); |
|
| 515 } else { |
|
| 516 SetWindowPos(msg->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, |
|
| 517 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_FRAMECHANGED); |
|
| 518 } |
|
| 519 } |
|
| 520 |
|
| 521 break; |
|
| 522 |
|
| 523 case ABN_POSCHANGED: |
|
| 524 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: ABN_POSCHANGED\n"); |
|
| 525 CopyRect(&orig, &(ab->docked_rect)); |
|
| 526 gtk_appbar_querypos(ab, msg->hwnd, get_rect_of_window(msg->hwnd)); |
|
| 527 if (EqualRect(&orig, &(ab->docked_rect)) == 0) { |
|
| 528 MoveWindow(msg->hwnd, ab->docked_rect.left, ab->docked_rect.top, |
|
| 529 ab->docked_rect.right - ab->docked_rect.left, |
|
| 530 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); |
|
| 531 } |
|
| 532 gtk_appbar_setpos(ab, msg->hwnd); |
|
| 533 break; |
|
| 534 #if 0 |
|
| 535 default: |
|
| 536 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_callback: %d\n", msg->wParam); |
|
| 537 #endif |
|
| 538 } |
|
| 539 return GDK_FILTER_CONTINUE; |
|
| 540 } |
|
| 541 |
|
| 542 static GdkFilterReturn gtk_appbar_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) { |
|
| 543 MSG *msg = (MSG*)xevent; |
|
| 544 |
|
| 545 /*printf("MSG: %s\n", message_to_string (msg->message));*/ |
|
| 546 switch(msg->message) { |
|
| 547 case WM_EXITSIZEMOVE: |
|
| 548 return wnd_exitsizemove(data, xevent); |
|
| 549 case WM_WINDOWPOSCHANGING: |
|
| 550 return wnd_poschanging(data, xevent); |
|
| 551 case WM_WINDOWPOSCHANGED: |
|
| 552 return wnd_poschanged(data, xevent); |
|
| 553 case WM_ACTIVATE: |
|
| 554 return wnd_activate(data, xevent); |
|
| 555 case WM_SIZING: |
|
| 556 return wnd_sizing(data, xevent); |
|
| 557 case WM_MOVING: |
|
| 558 return wnd_moving(data, xevent); |
|
| 559 case WM_SHOWWINDOW: |
|
| 560 return wnd_showwindow(data, xevent); |
|
| 561 case WM_NCHITTEST: |
|
| 562 return wnd_nchittest(data, xevent); |
|
| 563 #if 0 |
|
| 564 case WM_INITMENUPOPUP: |
|
| 565 return wnd_initmenupopup(data, xevent); |
|
| 566 #endif |
|
| 567 case WM_SIZE: |
|
| 568 return wnd_size(data, xevent); |
|
| 569 case APPBAR_CALLBACK: |
|
| 570 return gtk_appbar_callback(data, xevent); |
|
| 571 #if 0 |
|
| 572 default: |
|
| 573 gaim_debug_info("gtkappbar", "gtk_appbar_event_filter %d\n", msg->message); |
|
| 574 #endif |
|
| 575 } |
|
| 576 return GDK_FILTER_CONTINUE; |
|
| 577 } |
|
| 578 |
|
| 579 void gtk_appbar_dock(GtkAppBar *ab, UINT side) { |
|
| 580 RECT orig; |
|
| 581 |
|
| 582 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_dock\n"); |
|
| 583 |
|
| 584 if(!ab || !IsWindow(GDK_WINDOW_HWND(ab->win->window))) |
|
| 585 return; |
|
| 586 |
|
| 587 ab->side = side; |
|
| 588 get_window_normal_rc(GDK_WINDOW_HWND(ab->win->window), &(ab->docked_rect)); |
|
| 589 CopyRect(&orig, &(ab->docked_rect)); |
|
| 590 gtk_appbar_querypos(ab, GDK_WINDOW_HWND(ab->win->window), |
|
| 591 get_rect_of_window(GDK_WINDOW_HWND(ab->win->window))); |
|
| 592 if(EqualRect(&orig, &(ab->docked_rect)) == 0) |
|
| 593 MoveWindow(GDK_WINDOW_HWND(ab->win->window), |
|
| 594 ab->docked_rect.left, |
|
| 595 ab->docked_rect.top, |
|
| 596 ab->docked_rect.right - ab->docked_rect.left, |
|
| 597 ab->docked_rect.bottom - ab->docked_rect.top, TRUE); |
|
| 598 gtk_appbar_setpos(ab, GDK_WINDOW_HWND(ab->win->window)); |
|
| 599 set_toolbar(GDK_WINDOW_HWND(ab->win->window), TRUE); |
|
| 600 ab->docked = TRUE; |
|
| 601 } |
|
| 602 |
|
| 603 void gtk_appbar_add_dock_cb(GtkAppBar *ab, GtkAppBarDockCB dock_cb) { |
|
| 604 if(!ab) |
|
| 605 return; |
|
| 606 ab->dock_cbs = g_list_append(ab->dock_cbs, dock_cb); |
|
| 607 } |
|
| 608 |
|
| 609 GtkAppBar *gtk_appbar_add(GtkWidget *win) { |
|
| 610 GtkAppBar *ab; |
|
| 611 |
|
| 612 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_add\n"); |
|
| 613 |
|
| 614 if(!win) |
|
| 615 return NULL; |
|
| 616 ab = g_new0(GtkAppBar, 1); |
|
| 617 ab->win = win; |
|
| 618 |
|
| 619 /* init docking coords */ |
|
| 620 get_window_normal_rc(GDK_WINDOW_HWND(win->window), &(ab->docked_rect)); |
|
| 621 |
|
| 622 /* Add main window filter */ |
|
| 623 gdk_window_add_filter(win->window, |
|
| 624 gtk_appbar_event_filter, |
|
| 625 ab); |
|
| 626 return ab; |
|
| 627 } |
|
| 628 |
|
| 629 void gtk_appbar_remove(GtkAppBar *ab) { |
|
| 630 gaim_debug(GAIM_DEBUG_INFO, "gtkappbar", "gtk_appbar_remove\n"); |
|
| 631 |
|
| 632 if(!ab) |
|
| 633 return; |
|
| 634 gdk_window_remove_filter(ab->win->window, |
|
| 635 gtk_appbar_event_filter, |
|
| 636 ab); |
|
| 637 if(ab->docked) { |
|
| 638 gtk_window_resize(GTK_WINDOW(ab->win), |
|
| 639 ab->docked_rect.right - ab->docked_rect.left, |
|
| 640 ab->undocked_height); |
|
| 641 set_toolbar(GDK_WINDOW_HWND(ab->win->window), FALSE); |
|
| 642 } |
|
| 643 gtk_appbar_unregister(ab, GDK_WINDOW_HWND(ab->win->window)); |
|
| 644 |
|
| 645 g_free(ab); |
|
| 646 } |
|