00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <config.h>
00028 #include "window-private.h"
00029 #include "edge-resistance.h"
00030 #include "util.h"
00031 #include "frame-private.h"
00032 #include "errors.h"
00033 #include "workspace.h"
00034 #include "stack.h"
00035 #include "keybindings.h"
00036 #include "ui.h"
00037 #include "place.h"
00038 #include "session.h"
00039 #include "effects.h"
00040 #include "prefs.h"
00041 #include "resizepopup.h"
00042 #include "xprops.h"
00043 #include "group.h"
00044 #include "window-props.h"
00045 #include "constraints.h"
00046 #include "compositor.h"
00047 #include "effects.h"
00048
00049 #include <X11/Xatom.h>
00050 #include <string.h>
00051
00052 #ifdef HAVE_SHAPE
00053 #include <X11/extensions/shape.h>
00054 #endif
00055
00056 static int destroying_windows_disallowed = 0;
00057
00058
00059 static void update_sm_hints (MetaWindow *window);
00060 static void update_role (MetaWindow *window);
00061 static void update_net_wm_type (MetaWindow *window);
00062 static void update_net_frame_extents (MetaWindow *window);
00063 static void recalc_window_type (MetaWindow *window);
00064 static void recalc_window_features (MetaWindow *window);
00065 static void invalidate_work_areas (MetaWindow *window);
00066 static void recalc_window_type (MetaWindow *window);
00067 static void set_wm_state (MetaWindow *window,
00068 int state);
00069 static void set_net_wm_state (MetaWindow *window);
00070
00071 static void send_configure_notify (MetaWindow *window);
00072 static gboolean process_property_notify (MetaWindow *window,
00073 XPropertyEvent *event);
00074 static void meta_window_show (MetaWindow *window);
00075 static void meta_window_hide (MetaWindow *window);
00076
00077 static void meta_window_save_rect (MetaWindow *window);
00078 static void save_user_window_placement (MetaWindow *window);
00079 static void force_save_user_window_placement (MetaWindow *window);
00080
00081 static void meta_window_move_resize_internal (MetaWindow *window,
00082 MetaMoveResizeFlags flags,
00083 int resize_gravity,
00084 int root_x_nw,
00085 int root_y_nw,
00086 int w,
00087 int h);
00088
00089 static void ensure_mru_position_after (MetaWindow *window,
00090 MetaWindow *after_this_one);
00091
00092
00093 static void meta_window_move_resize_now (MetaWindow *window);
00094
00095 static void meta_window_unqueue (MetaWindow *window, guint queuebits);
00096
00097 static void update_move (MetaWindow *window,
00098 gboolean snap,
00099 int x,
00100 int y);
00101 static gboolean update_move_timeout (gpointer data);
00102 static void update_resize (MetaWindow *window,
00103 gboolean snap,
00104 int x,
00105 int y,
00106 gboolean force);
00107 static gboolean update_resize_timeout (gpointer data);
00108
00109
00110 static void meta_window_flush_calc_showing (MetaWindow *window);
00111
00112 static gboolean queue_calc_showing_func (MetaWindow *window,
00113 void *data);
00114
00115 static void meta_window_apply_session_info (MetaWindow *window,
00116 const MetaWindowSessionInfo *info);
00117
00118 static void unmaximize_window_before_freeing (MetaWindow *window);
00119 static void unminimize_window_and_all_transient_parents (MetaWindow *window);
00120
00121
00122
00123
00124
00125
00126
00127 static gboolean idle_calc_showing (gpointer data);
00128 static gboolean idle_move_resize (gpointer data);
00129 static gboolean idle_update_icon (gpointer data);
00130
00131 #ifdef WITH_VERBOSE_MODE
00132 static const char*
00133 wm_state_to_string (int state)
00134 {
00135 switch (state)
00136 {
00137 case NormalState:
00138 return "NormalState";
00139 case IconicState:
00140 return "IconicState";
00141 case WithdrawnState:
00142 return "WithdrawnState";
00143 }
00144
00145 return "Unknown";
00146 }
00147 #endif
00148
00149 static gboolean
00150 is_desktop_or_dock_foreach (MetaWindow *window,
00151 void *data)
00152 {
00153 gboolean *result = data;
00154
00155 *result =
00156 window->type == META_WINDOW_DESKTOP ||
00157 window->type == META_WINDOW_DOCK;
00158 if (*result)
00159 return FALSE;
00160 else
00161 return TRUE;
00162 }
00163
00164
00165
00166
00167 static void
00168 maybe_leave_show_desktop_mode (MetaWindow *window)
00169 {
00170 gboolean is_desktop_or_dock;
00171
00172 if (!window->screen->active_workspace->showing_desktop)
00173 return;
00174
00175
00176
00177
00178
00179
00180 is_desktop_or_dock = FALSE;
00181 is_desktop_or_dock_foreach (window,
00182 &is_desktop_or_dock);
00183
00184 meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
00185 &is_desktop_or_dock);
00186
00187 if (!is_desktop_or_dock)
00188 {
00189 meta_screen_minimize_all_on_active_workspace_except (window->screen,
00190 window);
00191 meta_screen_unshow_desktop (window->screen);
00192 }
00193 }
00194
00195 MetaWindow*
00196 meta_window_new (MetaDisplay *display,
00197 Window xwindow,
00198 gboolean must_be_viewable)
00199 {
00200 XWindowAttributes attrs;
00201 MetaWindow *window;
00202
00203 meta_display_grab (display);
00204 meta_error_trap_push (display);
00205
00206
00207
00208 meta_error_trap_push_with_return (display);
00209
00210 if (XGetWindowAttributes (display->xdisplay,xwindow, &attrs))
00211 {
00212 if(meta_error_trap_pop_with_return (display, TRUE) != Success)
00213 {
00214 meta_verbose ("Failed to get attributes for window 0x%lx\n",
00215 xwindow);
00216 meta_error_trap_pop (display, TRUE);
00217 meta_display_ungrab (display);
00218 return NULL;
00219 }
00220 window = meta_window_new_with_attrs (display, xwindow,
00221 must_be_viewable, &attrs);
00222 }
00223 else
00224 {
00225 meta_error_trap_pop_with_return (display, TRUE);
00226 meta_verbose ("Failed to get attributes for window 0x%lx\n",
00227 xwindow);
00228 meta_error_trap_pop (display, TRUE);
00229 meta_display_ungrab (display);
00230 return NULL;
00231 }
00232
00233
00234 meta_error_trap_pop (display, FALSE);
00235 meta_display_ungrab (display);
00236
00237 return window;
00238 }
00239
00240 MetaWindow*
00241 meta_window_new_with_attrs (MetaDisplay *display,
00242 Window xwindow,
00243 gboolean must_be_viewable,
00244 XWindowAttributes *attrs)
00245 {
00246 MetaWindow *window;
00247 GSList *tmp;
00248 MetaWorkspace *space;
00249 gulong existing_wm_state;
00250 gulong event_mask;
00251 MetaMoveResizeFlags flags;
00252 #define N_INITIAL_PROPS 18
00253 Atom initial_props[N_INITIAL_PROPS];
00254 int i;
00255 gboolean has_shape;
00256
00257 g_assert (attrs != NULL);
00258 g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props));
00259
00260 meta_verbose ("Attempting to manage 0x%lx\n", xwindow);
00261
00262 if (meta_display_xwindow_is_a_no_focus_window (display, xwindow))
00263 {
00264 meta_verbose ("Not managing no_focus_window 0x%lx\n",
00265 xwindow);
00266 return NULL;
00267 }
00268
00269 if (attrs->override_redirect)
00270 {
00271 meta_verbose ("Deciding not to manage override_redirect window 0x%lx\n", xwindow);
00272 return NULL;
00273 }
00274
00275
00276 meta_display_grab (display);
00277 meta_error_trap_push (display);
00278
00279
00280
00281 meta_verbose ("must_be_viewable = %d attrs->map_state = %d (%s)\n",
00282 must_be_viewable,
00283 attrs->map_state,
00284 (attrs->map_state == IsUnmapped) ?
00285 "IsUnmapped" :
00286 (attrs->map_state == IsViewable) ?
00287 "IsViewable" :
00288 (attrs->map_state == IsUnviewable) ?
00289 "IsUnviewable" :
00290 "(unknown)");
00291
00292 existing_wm_state = WithdrawnState;
00293 if (must_be_viewable && attrs->map_state != IsViewable)
00294 {
00295
00296 gulong state;
00297
00298
00299 if (!(meta_prop_get_cardinal_with_atom_type (display, xwindow,
00300 display->atom_WM_STATE,
00301 display->atom_WM_STATE,
00302 &state) &&
00303 (state == IconicState || state == NormalState)))
00304 {
00305 meta_verbose ("Deciding not to manage unmapped or unviewable window 0x%lx\n", xwindow);
00306 meta_error_trap_pop (display, TRUE);
00307 meta_display_ungrab (display);
00308 return NULL;
00309 }
00310
00311 existing_wm_state = state;
00312 meta_verbose ("WM_STATE of %lx = %s\n", xwindow,
00313 wm_state_to_string (existing_wm_state));
00314 }
00315
00316 meta_error_trap_push_with_return (display);
00317
00318 XAddToSaveSet (display->xdisplay, xwindow);
00319
00320 event_mask =
00321 PropertyChangeMask | EnterWindowMask | LeaveWindowMask |
00322 FocusChangeMask | ColormapChangeMask;
00323
00324 XSelectInput (display->xdisplay, xwindow, event_mask);
00325
00326 has_shape = FALSE;
00327 #ifdef HAVE_SHAPE
00328 if (META_DISPLAY_HAS_SHAPE (display))
00329 {
00330 int x_bounding, y_bounding, x_clip, y_clip;
00331 unsigned w_bounding, h_bounding, w_clip, h_clip;
00332 int bounding_shaped, clip_shaped;
00333
00334 XShapeSelectInput (display->xdisplay, xwindow, ShapeNotifyMask);
00335
00336 XShapeQueryExtents (display->xdisplay, xwindow,
00337 &bounding_shaped, &x_bounding, &y_bounding,
00338 &w_bounding, &h_bounding,
00339 &clip_shaped, &x_clip, &y_clip,
00340 &w_clip, &h_clip);
00341
00342 has_shape = bounding_shaped != FALSE;
00343
00344 meta_topic (META_DEBUG_SHAPES,
00345 "Window has_shape = %d extents %d,%d %u x %u\n",
00346 has_shape, x_bounding, y_bounding,
00347 w_bounding, h_bounding);
00348 }
00349 #endif
00350
00351
00352 if (attrs->border_width != 0)
00353 XSetWindowBorderWidth (display->xdisplay, xwindow, 0);
00354
00355
00356 if (attrs->win_gravity != NorthWestGravity)
00357 {
00358 XSetWindowAttributes set_attrs;
00359
00360 set_attrs.win_gravity = NorthWestGravity;
00361
00362 XChangeWindowAttributes (display->xdisplay,
00363 xwindow,
00364 CWWinGravity,
00365 &set_attrs);
00366 }
00367
00368 if (meta_error_trap_pop_with_return (display, FALSE) != Success)
00369 {
00370 meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n",
00371 xwindow);
00372 meta_error_trap_pop (display, FALSE);
00373 meta_display_ungrab (display);
00374 return NULL;
00375 }
00376
00377 g_assert (!attrs->override_redirect);
00378
00379 window = g_new (MetaWindow, 1);
00380
00381 window->constructing = TRUE;
00382
00383 window->dialog_pid = -1;
00384 window->dialog_pipe = -1;
00385
00386 window->xwindow = xwindow;
00387
00388
00389
00390
00391 window->display = display;
00392 window->workspace = NULL;
00393
00394 #ifdef HAVE_XSYNC
00395 window->sync_request_counter = None;
00396 window->sync_request_serial = 0;
00397 window->sync_request_time.tv_sec = 0;
00398 window->sync_request_time.tv_usec = 0;
00399 #endif
00400
00401 window->screen = NULL;
00402 tmp = display->screens;
00403 while (tmp != NULL)
00404 {
00405 MetaScreen *scr = tmp->data;
00406
00407 if (scr->xroot == attrs->root)
00408 {
00409 window->screen = tmp->data;
00410 break;
00411 }
00412
00413 tmp = tmp->next;
00414 }
00415
00416 g_assert (window->screen);
00417
00418 window->desc = g_strdup_printf ("0x%lx", window->xwindow);
00419
00420
00421 meta_stack_freeze (window->screen->stack);
00422
00423 window->has_shape = has_shape;
00424
00425 window->rect.x = attrs->x;
00426 window->rect.y = attrs->y;
00427 window->rect.width = attrs->width;
00428 window->rect.height = attrs->height;
00429
00430
00431 window->border_width = attrs->border_width;
00432 window->size_hints.x = attrs->x;
00433 window->size_hints.y = attrs->y;
00434 window->size_hints.width = attrs->width;
00435 window->size_hints.height = attrs->height;
00436
00437 meta_set_normal_hints (window, NULL);
00438
00439
00440 window->saved_rect = window->rect;
00441 window->user_rect = window->rect;
00442
00443 window->depth = attrs->depth;
00444 window->xvisual = attrs->visual;
00445 window->colormap = attrs->colormap;
00446
00447 window->title = NULL;
00448 window->icon_name = NULL;
00449 window->icon = NULL;
00450 window->mini_icon = NULL;
00451 meta_icon_cache_init (&window->icon_cache);
00452 window->wm_hints_pixmap = None;
00453 window->wm_hints_mask = None;
00454
00455 window->frame = NULL;
00456 window->has_focus = FALSE;
00457
00458 window->maximized_horizontally = FALSE;
00459 window->maximized_vertically = FALSE;
00460 window->maximize_horizontally_after_placement = FALSE;
00461 window->maximize_vertically_after_placement = FALSE;
00462 window->minimize_after_placement = FALSE;
00463 window->fullscreen = FALSE;
00464 window->require_fully_onscreen = TRUE;
00465 window->require_on_single_xinerama = TRUE;
00466 window->require_titlebar_visible = TRUE;
00467 window->on_all_workspaces = FALSE;
00468 window->shaded = FALSE;
00469 window->initially_iconic = FALSE;
00470 window->minimized = FALSE;
00471 window->was_minimized = FALSE;
00472 window->tab_unminimized = FALSE;
00473 window->iconic = FALSE;
00474 window->mapped = attrs->map_state != IsUnmapped;
00475
00476 window->showing_for_first_time = !window->mapped;
00477
00478 window->placed = window->mapped;
00479 if (window->placed)
00480 meta_topic (META_DEBUG_PLACEMENT,
00481 "Not placing window 0x%lx since it's already mapped\n",
00482 xwindow);
00483 window->denied_focus_and_not_transient = FALSE;
00484 window->unmanaging = FALSE;
00485 window->is_in_queues = 0;
00486 window->keys_grabbed = FALSE;
00487 window->grab_on_frame = FALSE;
00488 window->all_keys_grabbed = FALSE;
00489 window->withdrawn = FALSE;
00490 window->initial_workspace_set = FALSE;
00491 window->initial_timestamp_set = FALSE;
00492 window->net_wm_user_time_set = FALSE;
00493 window->user_time_window = None;
00494 window->calc_placement = FALSE;
00495 window->shaken_loose = FALSE;
00496 window->have_focus_click_grab = FALSE;
00497 window->disable_sync = FALSE;
00498
00499 window->unmaps_pending = 0;
00500
00501 window->mwm_decorated = TRUE;
00502 window->mwm_border_only = FALSE;
00503 window->mwm_has_close_func = TRUE;
00504 window->mwm_has_minimize_func = TRUE;
00505 window->mwm_has_maximize_func = TRUE;
00506 window->mwm_has_move_func = TRUE;
00507 window->mwm_has_resize_func = TRUE;
00508
00509 window->decorated = TRUE;
00510 window->has_close_func = TRUE;
00511 window->has_minimize_func = TRUE;
00512 window->has_maximize_func = TRUE;
00513 window->has_move_func = TRUE;
00514 window->has_resize_func = TRUE;
00515
00516 window->has_shade_func = TRUE;
00517
00518 window->has_fullscreen_func = TRUE;
00519
00520 window->always_sticky = FALSE;
00521
00522 window->wm_state_modal = FALSE;
00523 window->skip_taskbar = FALSE;
00524 window->skip_pager = FALSE;
00525 window->wm_state_skip_taskbar = FALSE;
00526 window->wm_state_skip_pager = FALSE;
00527 window->wm_state_above = FALSE;
00528 window->wm_state_below = FALSE;
00529 window->wm_state_demands_attention = FALSE;
00530
00531 window->res_class = NULL;
00532 window->res_name = NULL;
00533 window->role = NULL;
00534 window->sm_client_id = NULL;
00535 window->wm_client_machine = NULL;
00536 window->startup_id = NULL;
00537
00538 window->net_wm_pid = -1;
00539
00540 window->xtransient_for = None;
00541 window->xclient_leader = None;
00542 window->transient_parent_is_root_window = FALSE;
00543
00544 window->type = META_WINDOW_NORMAL;
00545 window->type_atom = None;
00546
00547 window->struts = NULL;
00548
00549 window->using_net_wm_name = FALSE;
00550 window->using_net_wm_visible_name = FALSE;
00551 window->using_net_wm_icon_name = FALSE;
00552 window->using_net_wm_visible_icon_name = FALSE;
00553
00554 window->need_reread_icon = TRUE;
00555
00556 window->layer = META_LAYER_LAST;
00557 window->stack_position = -1;
00558 window->initial_workspace = 0;
00559 window->initial_timestamp = 0;
00560
00561 meta_display_register_x_window (display, &window->xwindow, window);
00562
00563
00564
00565
00566 window->group = NULL;
00567 window->xgroup_leader = None;
00568 meta_window_compute_group (window);
00569
00570
00571
00572
00573
00574
00575 i = 0;
00576 initial_props[i++] = display->atom_WM_CLIENT_MACHINE;
00577 initial_props[i++] = display->atom__NET_WM_NAME;
00578 initial_props[i++] = XA_WM_CLASS;
00579 initial_props[i++] = display->atom__NET_WM_PID;
00580 initial_props[i++] = XA_WM_NAME;
00581 initial_props[i++] = display->atom__NET_WM_ICON_NAME;
00582 initial_props[i++] = XA_WM_ICON_NAME;
00583 initial_props[i++] = display->atom__NET_WM_DESKTOP;
00584 initial_props[i++] = display->atom__NET_STARTUP_ID;
00585 initial_props[i++] = display->atom__NET_WM_SYNC_REQUEST_COUNTER;
00586 initial_props[i++] = XA_WM_NORMAL_HINTS;
00587 initial_props[i++] = display->atom_WM_PROTOCOLS;
00588 initial_props[i++] = XA_WM_HINTS;
00589 initial_props[i++] = display->atom__NET_WM_USER_TIME;
00590 initial_props[i++] = display->atom__NET_WM_STATE;
00591 initial_props[i++] = display->atom__MOTIF_WM_HINTS;
00592 initial_props[i++] = XA_WM_TRANSIENT_FOR;
00593 initial_props[i++] = display->atom__NET_WM_USER_TIME_WINDOW;
00594 g_assert (N_INITIAL_PROPS == i);
00595
00596 meta_window_reload_properties (window, initial_props, N_INITIAL_PROPS);
00597
00598 update_sm_hints (window);
00599 update_role (window);
00600 update_net_wm_type (window);
00601 meta_window_update_icon_now (window);
00602
00603 if (window->initially_iconic)
00604 {
00605
00606 window->minimized = TRUE;
00607 meta_verbose ("Window %s asked to start out minimized\n", window->desc);
00608 }
00609
00610 if (existing_wm_state == IconicState)
00611 {
00612
00613 window->minimized = TRUE;
00614 meta_verbose ("Window %s had preexisting WM_STATE = IconicState, minimizing\n",
00615 window->desc);
00616
00617
00618
00619
00620 window->placed = TRUE;
00621 }
00622
00623
00624
00625
00626 meta_screen_apply_startup_properties (window->screen, window);
00627
00628
00629
00630
00631
00632
00633
00634 if (!window->net_wm_user_time_set) {
00635 MetaWindow *parent = NULL;
00636 if (window->xtransient_for)
00637 parent = meta_display_lookup_x_window (window->display,
00638 window->xtransient_for);
00639
00640
00641
00642
00643 if (window->initial_timestamp_set)
00644
00645
00646
00647 window->net_wm_user_time = window->initial_timestamp;
00648 else if (parent != NULL)
00649 meta_window_set_user_time(window, parent->net_wm_user_time);
00650 else
00651
00652
00653
00654 window->net_wm_user_time =
00655 meta_display_get_current_time_roundtrip (window->display);
00656 }
00657
00658 if (window->decorated)
00659 meta_window_ensure_frame (window);
00660
00661 meta_window_grab_keys (window);
00662 meta_display_grab_window_buttons (window->display, window->xwindow);
00663 meta_display_grab_focus_window_button (window->display, window);
00664
00665 if (window->type == META_WINDOW_DESKTOP ||
00666 window->type == META_WINDOW_DOCK)
00667 {
00668
00669
00670
00671
00672
00673 window->on_all_workspaces = TRUE;
00674 }
00675
00676
00677
00678
00679
00680
00681 if (window->initial_workspace_set)
00682 {
00683 if (window->initial_workspace == (int) 0xFFFFFFFF)
00684 {
00685 meta_topic (META_DEBUG_PLACEMENT,
00686 "Window %s is initially on all spaces\n",
00687 window->desc);
00688
00689
00690
00691
00692 window->on_all_workspaces = TRUE;
00693 meta_workspace_add_window (window->screen->active_workspace, window);
00694 }
00695 else
00696 {
00697 meta_topic (META_DEBUG_PLACEMENT,
00698 "Window %s is initially on space %d\n",
00699 window->desc, window->initial_workspace);
00700
00701 space =
00702 meta_screen_get_workspace_by_index (window->screen,
00703 window->initial_workspace);
00704
00705 if (space)
00706 meta_workspace_add_window (space, window);
00707 }
00708 }
00709
00710 if (window->workspace == NULL &&
00711 window->xtransient_for != None)
00712 {
00713
00714 MetaWindow *parent;
00715
00716 parent = meta_display_lookup_x_window (window->display,
00717 window->xtransient_for);
00718
00719 if (parent && parent->workspace)
00720 {
00721 meta_topic (META_DEBUG_PLACEMENT,
00722 "Putting window %s on same workspace as parent %s\n",
00723 window->desc, parent->desc);
00724
00725 if (parent->on_all_workspaces)
00726 window->on_all_workspaces = TRUE;
00727
00728
00729
00730 meta_workspace_add_window (parent->workspace, window);
00731 }
00732 }
00733
00734 if (window->workspace == NULL)
00735 {
00736 meta_topic (META_DEBUG_PLACEMENT,
00737 "Putting window %s on active workspace\n",
00738 window->desc);
00739
00740 space = window->screen->active_workspace;
00741
00742 meta_workspace_add_window (space, window);
00743 }
00744
00745
00746 meta_window_set_current_workspace_hint (window);
00747
00748 meta_window_update_struts (window);
00749
00750
00751
00752
00753
00754
00755
00756
00757 meta_stack_add (window->screen->stack,
00758 window);
00759
00760
00761
00762
00763
00764 flags =
00765 META_IS_CONFIGURE_REQUEST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
00766 meta_window_move_resize_internal (window,
00767 flags,
00768 window->size_hints.win_gravity,
00769 window->size_hints.x,
00770 window->size_hints.y,
00771 window->size_hints.width,
00772 window->size_hints.height);
00773
00774
00775 {
00776 const MetaWindowSessionInfo *info;
00777
00778 info = meta_window_lookup_saved_state (window);
00779
00780 if (info)
00781 {
00782 meta_window_apply_session_info (window, info);
00783 meta_window_release_saved_state (info);
00784 }
00785 }
00786
00787
00788
00789
00790 set_wm_state (window, window->iconic ? IconicState : NormalState);
00791 set_net_wm_state (window);
00792
00793
00794 meta_stack_thaw (window->screen->stack);
00795
00796
00797 maybe_leave_show_desktop_mode (window);
00798
00799 meta_window_queue (window, META_QUEUE_CALC_SHOWING);
00800
00801
00802
00803 meta_window_foreach_transient (window,
00804 queue_calc_showing_func,
00805 NULL);
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816 if (!display->display_opening && !window->initially_iconic)
00817 unminimize_window_and_all_transient_parents (window);
00818
00819 meta_error_trap_pop (display, FALSE);
00820 meta_display_ungrab (display);
00821
00822 window->constructing = FALSE;
00823
00824 return window;
00825 }
00826
00827
00828 static void
00829 meta_window_apply_session_info (MetaWindow *window,
00830 const MetaWindowSessionInfo *info)
00831 {
00832 if (info->stack_position_set)
00833 {
00834 meta_topic (META_DEBUG_SM,
00835 "Restoring stack position %d for window %s\n",
00836 info->stack_position, window->desc);
00837
00838
00839 }
00840
00841 if (info->minimized_set)
00842 {
00843 meta_topic (META_DEBUG_SM,
00844 "Restoring minimized state %d for window %s\n",
00845 info->minimized, window->desc);
00846
00847 if (window->has_minimize_func && info->minimized)
00848 meta_window_minimize (window);
00849 }
00850
00851 if (info->maximized_set)
00852 {
00853 meta_topic (META_DEBUG_SM,
00854 "Restoring maximized state %d for window %s\n",
00855 info->maximized, window->desc);
00856
00857 if (window->has_maximize_func && info->maximized)
00858 {
00859 meta_window_maximize (window,
00860 META_MAXIMIZE_HORIZONTAL |
00861 META_MAXIMIZE_VERTICAL);
00862
00863 if (info->saved_rect_set)
00864 {
00865 meta_topic (META_DEBUG_SM,
00866 "Restoring saved rect %d,%d %dx%d for window %s\n",
00867 info->saved_rect.x,
00868 info->saved_rect.y,
00869 info->saved_rect.width,
00870 info->saved_rect.height,
00871 window->desc);
00872
00873 window->saved_rect.x = info->saved_rect.x;
00874 window->saved_rect.y = info->saved_rect.y;
00875 window->saved_rect.width = info->saved_rect.width;
00876 window->saved_rect.height = info->saved_rect.height;
00877 }
00878 }
00879 }
00880
00881 if (info->on_all_workspaces_set)
00882 {
00883 window->on_all_workspaces = info->on_all_workspaces;
00884 meta_topic (META_DEBUG_SM,
00885 "Restoring sticky state %d for window %s\n",
00886 window->on_all_workspaces, window->desc);
00887 }
00888
00889 if (info->workspace_indices)
00890 {
00891 GSList *tmp;
00892 GSList *spaces;
00893
00894 spaces = NULL;
00895
00896 tmp = info->workspace_indices;
00897 while (tmp != NULL)
00898 {
00899 MetaWorkspace *space;
00900
00901 space =
00902 meta_screen_get_workspace_by_index (window->screen,
00903 GPOINTER_TO_INT (tmp->data));
00904
00905 if (space)
00906 spaces = g_slist_prepend (spaces, space);
00907
00908 tmp = tmp->next;
00909 }
00910
00911 if (spaces)
00912 {
00913
00914
00915
00916
00917
00918 if (window->workspace)
00919 meta_workspace_remove_window (window->workspace, window);
00920
00921
00922
00923
00924
00925 meta_workspace_add_window (spaces->data, window);
00926
00927 meta_topic (META_DEBUG_SM,
00928 "Restoring saved window %s to workspace %d\n",
00929 window->desc,
00930 meta_workspace_index (spaces->data));
00931
00932 g_slist_free (spaces);
00933 }
00934 }
00935
00936 if (info->geometry_set)
00937 {
00938 int x, y, w, h;
00939 MetaMoveResizeFlags flags;
00940
00941 window->placed = TRUE;
00942
00943 x = info->rect.x;
00944 y = info->rect.y;
00945
00946 w = window->size_hints.base_width +
00947 info->rect.width * window->size_hints.width_inc;
00948 h = window->size_hints.base_height +
00949 info->rect.height * window->size_hints.height_inc;
00950
00951
00952 window->size_hints.win_gravity = info->gravity;
00953
00954 meta_topic (META_DEBUG_SM,
00955 "Restoring pos %d,%d size %d x %d for %s\n",
00956 x, y, w, h, window->desc);
00957
00958 flags = META_DO_GRAVITY_ADJUST | META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
00959 meta_window_move_resize_internal (window,
00960 flags,
00961 window->size_hints.win_gravity,
00962 x, y, w, h);
00963 }
00964 }
00965
00966 void
00967 meta_window_free (MetaWindow *window,
00968 guint32 timestamp)
00969 {
00970 GList *tmp;
00971
00972 meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
00973
00974 if (window->display->compositor)
00975 meta_compositor_free_window (window->display->compositor, window);
00976
00977 if (window->display->window_with_menu == window)
00978 {
00979 meta_ui_window_menu_free (window->display->window_menu);
00980 window->display->window_menu = NULL;
00981 window->display->window_with_menu = NULL;
00982 }
00983
00984 if (destroying_windows_disallowed > 0)
00985 meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
00986 window->desc);
00987
00988 window->unmanaging = TRUE;
00989
00990 if (window->fullscreen)
00991 {
00992 MetaGroup *group;
00993
00994
00995
00996
00997
00998 meta_stack_freeze (window->screen->stack);
00999 group = meta_window_get_group (window);
01000 if (group)
01001 meta_group_update_layers (group);
01002 meta_stack_thaw (window->screen->stack);
01003 }
01004
01005 meta_window_shutdown_group (window);
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016 if (window->has_focus)
01017 {
01018 meta_topic (META_DEBUG_FOCUS,
01019 "Focusing default window since we're unmanaging %s\n",
01020 window->desc);
01021 meta_workspace_focus_default_window (window->screen->active_workspace,
01022 window,
01023 timestamp);
01024 }
01025 else if (window->display->expected_focus_window == window)
01026 {
01027 meta_topic (META_DEBUG_FOCUS,
01028 "Focusing default window since expected focus window freed %s\n",
01029 window->desc);
01030 window->display->expected_focus_window = NULL;
01031 meta_workspace_focus_default_window (window->screen->active_workspace,
01032 window,
01033 timestamp);
01034 }
01035 else
01036 {
01037 meta_topic (META_DEBUG_FOCUS,
01038 "Unmanaging window %s which doesn't currently have focus\n",
01039 window->desc);
01040 }
01041
01042 if (window->struts)
01043 {
01044 meta_free_gslist_and_elements (window->struts);
01045 window->struts = NULL;
01046
01047 meta_topic (META_DEBUG_WORKAREA,
01048 "Unmanaging window %s which has struts, so invalidating work areas\n",
01049 window->desc);
01050 invalidate_work_areas (window);
01051 }
01052
01053 if (window->display->grab_window == window)
01054 meta_display_end_grab_op (window->display, timestamp);
01055
01056 g_assert (window->display->grab_window != window);
01057
01058 if (window->display->focus_window == window)
01059 {
01060 window->display->focus_window = NULL;
01061 meta_compositor_set_active_window (window->display->compositor,
01062 window->screen, NULL);
01063 }
01064
01065 if (window->maximized_horizontally || window->maximized_vertically)
01066 unmaximize_window_before_freeing (window);
01067
01068
01069
01070
01071
01072 send_configure_notify (window);
01073
01074 meta_window_unqueue (window, META_QUEUE_CALC_SHOWING |
01075 META_QUEUE_MOVE_RESIZE |
01076 META_QUEUE_UPDATE_ICON);
01077 meta_window_free_delete_dialog (window);
01078
01079 if (window->workspace)
01080 meta_workspace_remove_window (window->workspace, window);
01081
01082 g_assert (window->workspace == NULL);
01083
01084 #ifndef G_DISABLE_CHECKS
01085 tmp = window->screen->workspaces;
01086 while (tmp != NULL)
01087 {
01088 MetaWorkspace *workspace = tmp->data;
01089
01090 g_assert (g_list_find (workspace->windows, window) == NULL);
01091 g_assert (g_list_find (workspace->mru_list, window) == NULL);
01092
01093 tmp = tmp->next;
01094 }
01095 #endif
01096
01097 meta_stack_remove (window->screen->stack, window);
01098
01099 if (window->frame)
01100 meta_window_destroy_frame (window);
01101
01102 if (window->withdrawn)
01103 {
01104
01105
01106
01107 meta_error_trap_push (window->display);
01108 meta_verbose ("Cleaning state from window %s\n", window->desc);
01109 XDeleteProperty (window->display->xdisplay,
01110 window->xwindow,
01111 window->display->atom__NET_WM_DESKTOP);
01112 XDeleteProperty (window->display->xdisplay,
01113 window->xwindow,
01114 window->display->atom__NET_WM_STATE);
01115 set_wm_state (window, WithdrawnState);
01116 meta_error_trap_pop (window->display, FALSE);
01117 }
01118 else
01119 {
01120
01121
01122
01123 if (!window->minimized)
01124 {
01125 meta_error_trap_push (window->display);
01126 set_wm_state (window, NormalState);
01127 meta_error_trap_pop (window->display, FALSE);
01128 }
01129
01130
01131
01132
01133 meta_error_trap_push (window->display);
01134 XMapWindow (window->display->xdisplay,
01135 window->xwindow);
01136 meta_error_trap_pop (window->display, FALSE);
01137 }
01138
01139 meta_window_ungrab_keys (window);
01140 meta_display_ungrab_window_buttons (window->display, window->xwindow);
01141 meta_display_ungrab_focus_window_button (window->display, window);
01142
01143 meta_display_unregister_x_window (window->display, window->xwindow);
01144
01145
01146 meta_error_trap_push (window->display);
01147
01148
01149 if (window->border_width != 0)
01150 XSetWindowBorderWidth (window->display->xdisplay,
01151 window->xwindow,
01152 window->border_width);
01153
01154
01155 XRemoveFromSaveSet (window->display->xdisplay,
01156 window->xwindow);
01157
01158
01159 XSelectInput (window->display->xdisplay,
01160 window->xwindow,
01161 NoEventMask);
01162
01163
01164 if (window->user_time_window != None)
01165 {
01166 meta_display_unregister_x_window (window->display,
01167 window->user_time_window);
01168 XSelectInput (window->display->xdisplay,
01169 window->user_time_window,
01170 NoEventMask);
01171 window->user_time_window = None;
01172 }
01173
01174 #ifdef HAVE_SHAPE
01175 if (META_DISPLAY_HAS_SHAPE (window->display))
01176 XShapeSelectInput (window->display->xdisplay, window->xwindow, NoEventMask);
01177 #endif
01178
01179 meta_error_trap_pop (window->display, FALSE);
01180
01181 if (window->icon)
01182 g_object_unref (G_OBJECT (window->icon));
01183
01184 if (window->mini_icon)
01185 g_object_unref (G_OBJECT (window->mini_icon));
01186
01187 meta_icon_cache_free (&window->icon_cache);
01188
01189 g_free (window->sm_client_id);
01190 g_free (window->wm_client_machine);
01191 g_free (window->startup_id);
01192 g_free (window->role);
01193 g_free (window->res_class);
01194 g_free (window->res_name);
01195 g_free (window->title);
01196 g_free (window->icon_name);
01197 g_free (window->desc);
01198 g_free (window);
01199 }
01200
01201 static void
01202 set_wm_state (MetaWindow *window,
01203 int state)
01204 {
01205 unsigned long data[2];
01206
01207 meta_verbose ("Setting wm state %s on %s\n",
01208 wm_state_to_string (state), window->desc);
01209
01210
01211
01212
01213 data[0] = state;
01214 data[1] = None;
01215
01216 meta_error_trap_push (window->display);
01217 XChangeProperty (window->display->xdisplay, window->xwindow,
01218 window->display->atom_WM_STATE,
01219 window->display->atom_WM_STATE,
01220 32, PropModeReplace, (guchar*) data, 2);
01221 meta_error_trap_pop (window->display, FALSE);
01222 }
01223
01224 static void
01225 set_net_wm_state (MetaWindow *window)
01226 {
01227 int i;
01228 unsigned long data[11];
01229
01230 i = 0;
01231 if (window->shaded)
01232 {
01233 data[i] = window->display->atom__NET_WM_STATE_SHADED;
01234 ++i;
01235 }
01236 if (window->wm_state_modal)
01237 {
01238 data[i] = window->display->atom__NET_WM_STATE_MODAL;
01239 ++i;
01240 }
01241 if (window->skip_pager)
01242 {
01243 data[i] = window->display->atom__NET_WM_STATE_SKIP_PAGER;
01244 ++i;
01245 }
01246 if (window->skip_taskbar)
01247 {
01248 data[i] = window->display->atom__NET_WM_STATE_SKIP_TASKBAR;
01249 ++i;
01250 }
01251 if (window->maximized_horizontally)
01252 {
01253 data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_HORZ;
01254 ++i;
01255 }
01256 if (window->maximized_vertically)
01257 {
01258 data[i] = window->display->atom__NET_WM_STATE_MAXIMIZED_VERT;
01259 ++i;
01260 }
01261 if (window->fullscreen)
01262 {
01263 data[i] = window->display->atom__NET_WM_STATE_FULLSCREEN;
01264 ++i;
01265 }
01266 if (!meta_window_showing_on_its_workspace (window) || window->shaded)
01267 {
01268 data[i] = window->display->atom__NET_WM_STATE_HIDDEN;
01269 ++i;
01270 }
01271 if (window->wm_state_above)
01272 {
01273 data[i] = window->display->atom__NET_WM_STATE_ABOVE;
01274 ++i;
01275 }
01276 if (window->wm_state_below)
01277 {
01278 data[i] = window->display->atom__NET_WM_STATE_BELOW;
01279 ++i;
01280 }
01281 if (window->wm_state_demands_attention)
01282 {
01283 data[i] = window->display->atom__NET_WM_STATE_DEMANDS_ATTENTION;
01284 ++i;
01285 }
01286
01287 meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i);
01288
01289 meta_error_trap_push (window->display);
01290 XChangeProperty (window->display->xdisplay, window->xwindow,
01291 window->display->atom__NET_WM_STATE,
01292 XA_ATOM,
01293 32, PropModeReplace, (guchar*) data, i);
01294 meta_error_trap_pop (window->display, FALSE);
01295 }
01296
01297 gboolean
01298 meta_window_located_on_workspace (MetaWindow *window,
01299 MetaWorkspace *workspace)
01300 {
01301 return (window->on_all_workspaces && window->screen == workspace->screen) ||
01302 (window->workspace == workspace);
01303 }
01304
01305 static gboolean
01306 is_minimized_foreach (MetaWindow *window,
01307 void *data)
01308 {
01309 gboolean *result = data;
01310
01311 *result = window->minimized;
01312 if (*result)
01313 return FALSE;
01314 else
01315 return TRUE;
01316 }
01317
01318 static gboolean
01319 ancestor_is_minimized (MetaWindow *window)
01320 {
01321 gboolean is_minimized;
01322
01323 is_minimized = FALSE;
01324
01325 meta_window_foreach_ancestor (window, is_minimized_foreach, &is_minimized);
01326
01327 return is_minimized;
01328 }
01329
01330 gboolean
01331 meta_window_showing_on_its_workspace (MetaWindow *window)
01332 {
01333 gboolean showing;
01334 gboolean is_desktop_or_dock;
01335 MetaWorkspace* workspace_of_window;
01336
01337 showing = TRUE;
01338
01339
01340 if (window->minimized)
01341 showing = FALSE;
01342
01343
01344 is_desktop_or_dock = FALSE;
01345 is_desktop_or_dock_foreach (window,
01346 &is_desktop_or_dock);
01347
01348 meta_window_foreach_ancestor (window, is_desktop_or_dock_foreach,
01349 &is_desktop_or_dock);
01350
01351 if (window->on_all_workspaces)
01352 workspace_of_window = window->screen->active_workspace;
01353 else if (window->workspace)
01354 workspace_of_window = window->workspace;
01355 else
01356 workspace_of_window = NULL;
01357
01358 if (showing &&
01359 workspace_of_window && workspace_of_window->showing_desktop &&
01360 !is_desktop_or_dock)
01361 {
01362 meta_verbose ("We're showing the desktop on the workspace(s) that window %s is on\n",
01363 window->desc);
01364 showing = FALSE;
01365 }
01366
01367
01368
01369
01370
01371
01372 if (showing)
01373 {
01374 if (ancestor_is_minimized (window))
01375 showing = FALSE;
01376 }
01377
01378 #if 0
01379
01380
01381 if (window->display->grab_window == window &&
01382 window->display->grab_wireframe_active)
01383 showing = FALSE;
01384 #endif
01385
01386 return showing;
01387 }
01388
01389 gboolean
01390 meta_window_should_be_showing (MetaWindow *window)
01391 {
01392 gboolean on_workspace;
01393
01394 meta_verbose ("Should be showing for window %s\n", window->desc);
01395
01396
01397 on_workspace = meta_window_located_on_workspace (window,
01398 window->screen->active_workspace);
01399
01400 if (!on_workspace)
01401 meta_verbose ("Window %s is not on workspace %d\n",
01402 window->desc,
01403 meta_workspace_index (window->screen->active_workspace));
01404 else
01405 meta_verbose ("Window %s is on the active workspace %d\n",
01406 window->desc,
01407 meta_workspace_index (window->screen->active_workspace));
01408
01409 if (window->on_all_workspaces)
01410 meta_verbose ("Window %s is on all workspaces\n", window->desc);
01411
01412 return on_workspace && meta_window_showing_on_its_workspace (window);
01413 }
01414
01415 static void
01416 finish_minimize (gpointer data)
01417 {
01418 MetaWindow *window = data;
01419
01420
01421
01422
01423
01424
01425 guint32 timestamp = meta_display_get_current_time_roundtrip (window->display);
01426
01427 meta_window_hide (window);
01428 if (window->has_focus)
01429 {
01430 meta_workspace_focus_default_window (window->screen->active_workspace,
01431 window,
01432 timestamp);
01433 }
01434 }
01435
01436 static void
01437 implement_showing (MetaWindow *window,
01438 gboolean showing)
01439 {
01440
01441 meta_verbose ("Implement showing = %d for window %s\n",
01442 showing, window->desc);
01443
01444 if (!showing)
01445 {
01446 gboolean on_workspace;
01447
01448 on_workspace = meta_window_located_on_workspace (window,
01449 window->screen->active_workspace);
01450
01451
01452
01453
01454
01455
01456
01457 if (on_workspace && window->minimized && window->mapped &&
01458 !meta_prefs_get_reduced_resources ())
01459 {
01460 MetaRectangle icon_rect, window_rect;
01461 gboolean result;
01462
01463
01464 result = meta_window_get_icon_geometry (window, &icon_rect);
01465
01466 if (!result)
01467 {
01468
01469
01470
01471 icon_rect.x = window->screen->rect.width;
01472 icon_rect.y = window->screen->rect.height;
01473 icon_rect.width = 1;
01474 icon_rect.height = 1;
01475 }
01476
01477 meta_window_get_outer_rect (window, &window_rect);
01478
01479 meta_effect_run_minimize (window,
01480 &window_rect,
01481 &icon_rect,
01482 finish_minimize,
01483 window);
01484 }
01485 else
01486 {
01487 finish_minimize (window);
01488 }
01489 }
01490 else
01491 {
01492 meta_window_show (window);
01493 }
01494 }
01495
01496 void
01497 meta_window_calc_showing (MetaWindow *window)
01498 {
01499 implement_showing (window, meta_window_should_be_showing (window));
01500 }
01501
01502 static guint queue_idle[NUMBER_OF_QUEUES] = {0, 0, 0};
01503 static GSList *queue_pending[NUMBER_OF_QUEUES] = {NULL, NULL, NULL};
01504
01505 static int
01506 stackcmp (gconstpointer a, gconstpointer b)
01507 {
01508 MetaWindow *aw = (gpointer) a;
01509 MetaWindow *bw = (gpointer) b;
01510
01511 if (aw->screen != bw->screen)
01512 return 0;
01513 else
01514 return meta_stack_windows_cmp (aw->screen->stack,
01515 aw, bw);
01516 }
01517
01518 static gboolean
01519 idle_calc_showing (gpointer data)
01520 {
01521 GSList *tmp;
01522 GSList *copy;
01523 GSList *should_show;
01524 GSList *should_hide;
01525 GSList *unplaced;
01526 GSList *displays;
01527 MetaWindow *first_window;
01528 guint queue_index = GPOINTER_TO_INT (data);
01529
01530 meta_topic (META_DEBUG_WINDOW_STATE,
01531 "Clearing the calc_showing queue\n");
01532
01533
01534
01535
01536
01537 copy = g_slist_copy (queue_pending[queue_index]);
01538 g_slist_free (queue_pending[queue_index]);
01539 queue_pending[queue_index] = NULL;
01540 queue_idle[queue_index] = 0;
01541
01542 destroying_windows_disallowed += 1;
01543
01544
01545
01546
01547
01548
01549 should_show = NULL;
01550 should_hide = NULL;
01551 unplaced = NULL;
01552 displays = NULL;
01553
01554 tmp = copy;
01555 while (tmp != NULL)
01556 {
01557 MetaWindow *window;
01558
01559 window = tmp->data;
01560
01561 if (!window->placed)
01562 unplaced = g_slist_prepend (unplaced, window);
01563 else if (meta_window_should_be_showing (window))
01564 should_show = g_slist_prepend (should_show, window);
01565 else
01566 should_hide = g_slist_prepend (should_hide, window);
01567
01568 tmp = tmp->next;
01569 }
01570
01571
01572 unplaced = g_slist_sort (unplaced, stackcmp);
01573 should_hide = g_slist_sort (should_hide, stackcmp);
01574
01575 should_show = g_slist_sort (should_show, stackcmp);
01576 should_show = g_slist_reverse (should_show);
01577
01578 first_window = copy->data;
01579
01580 meta_display_grab (first_window->display);
01581
01582 tmp = unplaced;
01583 while (tmp != NULL)
01584 {
01585 MetaWindow *window;
01586
01587 window = tmp->data;
01588
01589 meta_window_calc_showing (window);
01590
01591 tmp = tmp->next;
01592 }
01593
01594 tmp = should_show;
01595 while (tmp != NULL)
01596 {
01597 MetaWindow *window;
01598
01599 window = tmp->data;
01600
01601 implement_showing (window, TRUE);
01602
01603 tmp = tmp->next;
01604 }
01605
01606 tmp = should_hide;
01607 while (tmp != NULL)
01608 {
01609 MetaWindow *window;
01610
01611 window = tmp->data;
01612
01613 implement_showing (window, FALSE);
01614
01615 tmp = tmp->next;
01616 }
01617
01618 tmp = copy;
01619 while (tmp != NULL)
01620 {
01621 MetaWindow *window;
01622
01623 window = tmp->data;
01624
01625
01626
01627
01628
01629
01630 window->is_in_queues &= ~META_QUEUE_CALC_SHOWING;
01631
01632 tmp = tmp->next;
01633 }
01634
01635 if (meta_prefs_get_focus_mode () != META_FOCUS_MODE_CLICK)
01636 {
01637
01638
01639
01640
01641
01642 tmp = should_show;
01643 while (tmp != NULL)
01644 {
01645 MetaWindow *window = tmp->data;
01646
01647 if (!window->display->mouse_mode)
01648 meta_display_increment_focus_sentinel (window->display);
01649
01650 tmp = tmp->next;
01651 }
01652 }
01653
01654 meta_display_ungrab (first_window->display);
01655
01656 g_slist_free (copy);
01657
01658 g_slist_free (unplaced);
01659 g_slist_free (should_show);
01660 g_slist_free (should_hide);
01661 g_slist_free (displays);
01662
01663 destroying_windows_disallowed -= 1;
01664
01665 return FALSE;
01666 }
01667
01668 static const gchar* meta_window_queue_names[NUMBER_OF_QUEUES] =
01669 {"calc_showing", "move_resize", "update_icon"};
01670
01671 static void
01672 meta_window_unqueue (MetaWindow *window, guint queuebits)
01673 {
01674 gint queuenum;
01675
01676 for (queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++)
01677 {
01678 if ((queuebits & 1<<queuenum)
01679 &&
01680 (window->is_in_queues & 1<<queuenum))
01681 {
01682
01683 meta_topic (META_DEBUG_WINDOW_STATE,
01684 "Removing %s from the %s queue\n",
01685 window->desc,
01686 meta_window_queue_names[queuenum]);
01687
01688
01689
01690
01691 queue_pending[queuenum] = g_slist_remove (queue_pending[queuenum], window);
01692 window->is_in_queues &= ~(1<<queuenum);
01693
01694
01695
01696
01697
01698 if (queue_pending[queuenum] == NULL && queue_idle[queuenum] != 0)
01699 {
01700 g_source_remove (queue_idle[queuenum]);
01701 queue_idle[queuenum] = 0;
01702 }
01703 }
01704 }
01705 }
01706
01707 static void
01708 meta_window_flush_calc_showing (MetaWindow *window)
01709 {
01710 if (window->is_in_queues & META_QUEUE_CALC_SHOWING)
01711 {
01712 meta_window_unqueue (window, META_QUEUE_CALC_SHOWING);
01713 meta_window_calc_showing (window);
01714 }
01715 }
01716
01717 void
01718 meta_window_queue (MetaWindow *window, guint queuebits)
01719 {
01720 guint queuenum;
01721
01722 for (queuenum=0; queuenum<NUMBER_OF_QUEUES; queuenum++)
01723 {
01724 if (queuebits & 1<<queuenum)
01725 {
01726
01727
01728
01729
01730
01731 const gint window_queue_idle_priority[NUMBER_OF_QUEUES] =
01732 {
01733 G_PRIORITY_DEFAULT_IDLE,
01734 META_PRIORITY_RESIZE,
01735 G_PRIORITY_DEFAULT_IDLE
01736 };
01737
01738 const GSourceFunc window_queue_idle_handler[NUMBER_OF_QUEUES] =
01739 {
01740 idle_calc_showing,
01741 idle_move_resize,
01742 idle_update_icon,
01743 };
01744
01745
01746
01747
01748 if (window->unmanaging)
01749 break;
01750
01751
01752
01753
01754 if (window->is_in_queues & 1<<queuenum)
01755 break;
01756
01757 meta_topic (META_DEBUG_WINDOW_STATE,
01758 "Putting %s in the %s queue\n",
01759 window->desc,
01760 meta_window_queue_names[queuenum]);
01761
01762
01763 window->is_in_queues |= 1<<queuenum;
01764
01765
01766
01767
01768
01769
01770
01771 if (queue_idle[queuenum] == 0)
01772 queue_idle[queuenum] = g_idle_add_full
01773 (
01774 window_queue_idle_priority[queuenum],
01775 window_queue_idle_handler[queuenum],
01776 GUINT_TO_POINTER(queuenum),
01777 NULL
01778 );
01779
01780
01781 queue_pending[queuenum] = g_slist_prepend (queue_pending[queuenum],
01782 window);
01783 }
01784 }
01785 }
01786
01787 static gboolean
01788 intervening_user_event_occurred (MetaWindow *window)
01789 {
01790 guint32 compare;
01791 MetaWindow *focus_window;
01792
01793 focus_window = window->display->focus_window;
01794
01795 meta_topic (META_DEBUG_STARTUP,
01796 "COMPARISON:\n"
01797 " net_wm_user_time_set : %d\n"
01798 " net_wm_user_time : %u\n"
01799 " initial_timestamp_set: %d\n"
01800 " initial_timestamp : %u\n",
01801 window->net_wm_user_time_set,
01802 window->net_wm_user_time,
01803 window->initial_timestamp_set,
01804 window->initial_timestamp);
01805 if (focus_window != NULL)
01806 {
01807 meta_topic (META_DEBUG_STARTUP,
01808 "COMPARISON (continued):\n"
01809 " focus_window : %s\n"
01810 " fw->net_wm_user_time_set : %d\n"
01811 " fw->net_wm_user_time : %u\n",
01812 focus_window->desc,
01813 focus_window->net_wm_user_time_set,
01814 focus_window->net_wm_user_time);
01815 }
01816
01817
01818
01819
01820
01821
01822 if ( ((window->net_wm_user_time_set == TRUE) &&
01823 (window->net_wm_user_time == 0))
01824 ||
01825 ((window->initial_timestamp_set == TRUE) &&
01826 (window->initial_timestamp == 0)))
01827 {
01828 meta_topic (META_DEBUG_STARTUP,
01829 "window %s explicitly requested no focus\n",
01830 window->desc);
01831 return TRUE;
01832 }
01833
01834 if (!(window->net_wm_user_time_set) && !(window->initial_timestamp_set))
01835 {
01836 meta_topic (META_DEBUG_STARTUP,
01837 "no information about window %s found\n",
01838 window->desc);
01839 return FALSE;
01840 }
01841
01842 if (focus_window != NULL &&
01843 !focus_window->net_wm_user_time_set)
01844 {
01845 meta_topic (META_DEBUG_STARTUP,
01846 "focus window, %s, doesn't have a user time set yet!\n",
01847 window->desc);
01848 return FALSE;
01849 }
01850
01851
01852
01853
01854
01855
01856
01857
01858
01859 compare = window->initial_timestamp_set ? window->initial_timestamp : 0;
01860 compare = window->net_wm_user_time_set ? window->net_wm_user_time : compare;
01861
01862 if ((focus_window != NULL) &&
01863 XSERVER_TIME_IS_BEFORE (compare, focus_window->net_wm_user_time))
01864 {
01865 meta_topic (META_DEBUG_STARTUP,
01866 "window %s focus prevented by other activity; %u < %u\n",
01867 window->desc,
01868 compare,
01869 focus_window->net_wm_user_time);
01870 return TRUE;
01871 }
01872 else
01873 {
01874 meta_topic (META_DEBUG_STARTUP,
01875 "new window %s with no intervening events\n",
01876 window->desc);
01877 return FALSE;
01878 }
01879 }
01880
01881
01882
01883
01884
01885
01886 gboolean
01887 __window_is_terminal (MetaWindow *window)
01888 {
01889 if (window == NULL || window->res_class == NULL)
01890 return FALSE;
01891
01892
01893
01894
01895
01896
01897
01898 if (strcmp (window->res_class, "Gnome-terminal") == 0)
01899 return TRUE;
01900
01901 else if (strcmp (window->res_class, "XTerm") == 0)
01902 return TRUE;
01903
01904 else if (strcmp (window->res_class, "Konsole") == 0)
01905 return TRUE;
01906
01907 else if (strcmp (window->res_class, "URxvt") == 0)
01908 return TRUE;
01909
01910 else if (strcmp (window->res_class, "Eterm") == 0)
01911 return TRUE;
01912
01913 else if (strcmp (window->res_class, "KTerm") == 0)
01914 return TRUE;
01915
01916 else if (strcmp (window->res_class, "Multi-gnome-terminal") == 0)
01917 return TRUE;
01918
01919 else if (strcmp (window->res_class, "mlterm") == 0)
01920 return TRUE;
01921
01922 return FALSE;
01923 }
01924
01925
01926
01927
01928 static void
01929 window_state_on_map (MetaWindow *window,
01930 gboolean *takes_focus,
01931 gboolean *places_on_top)
01932 {
01933 gboolean intervening_events;
01934
01935 intervening_events = intervening_user_event_occurred (window);
01936
01937 *takes_focus = !intervening_events;
01938 *places_on_top = *takes_focus;
01939
01940
01941
01942
01943 if (!(window->input || window->take_focus))
01944 {
01945 *takes_focus = FALSE;
01946 return;
01947 }
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957 if (*takes_focus &&
01958 meta_prefs_get_focus_new_windows () == META_FOCUS_NEW_WINDOWS_STRICT &&
01959 !window->display->allow_terminal_deactivation &&
01960 __window_is_terminal (window->display->focus_window) &&
01961 !meta_window_is_ancestor_of_transient (window->display->focus_window,
01962 window))
01963 {
01964 meta_topic (META_DEBUG_FOCUS,
01965 "focus_window is terminal; not focusing new window.\n");
01966 *takes_focus = FALSE;
01967 *places_on_top = FALSE;
01968 }
01969
01970 switch (window->type)
01971 {
01972 case META_WINDOW_UTILITY:
01973 case META_WINDOW_TOOLBAR:
01974 *takes_focus = FALSE;
01975 *places_on_top = FALSE;
01976 break;
01977 case META_WINDOW_DOCK:
01978 case META_WINDOW_DESKTOP:
01979 case META_WINDOW_SPLASHSCREEN:
01980 case META_WINDOW_MENU:
01981
01982
01983
01984
01985 *takes_focus = FALSE;
01986 break;
01987 case META_WINDOW_NORMAL:
01988 case META_WINDOW_DIALOG:
01989 case META_WINDOW_MODAL_DIALOG:
01990
01991 break;
01992 }
01993 }
01994
01995 static gboolean
01996 windows_overlap (const MetaWindow *w1, const MetaWindow *w2)
01997 {
01998 MetaRectangle w1rect, w2rect;
01999 meta_window_get_outer_rect (w1, &w1rect);
02000 meta_window_get_outer_rect (w2, &w2rect);
02001 return meta_rectangle_overlap (&w1rect, &w2rect);
02002 }
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015 static gboolean
02016 window_would_be_covered (const MetaWindow *newbie)
02017 {
02018 MetaWorkspace *workspace = newbie->workspace;
02019 GList *tmp, *windows;
02020
02021 windows = meta_workspace_list_windows (workspace);
02022
02023 tmp = windows;
02024 while (tmp != NULL)
02025 {
02026 MetaWindow *w = tmp->data;
02027
02028 if (w->wm_state_above && w != newbie)
02029 {
02030
02031 if (windows_overlap (w, newbie))
02032 {
02033 g_list_free (windows);
02034 return TRUE;
02035 }
02036 }
02037
02038 tmp = tmp->next;
02039 }
02040
02041 g_list_free (windows);
02042 return FALSE;
02043 }
02044
02045
02046 void
02047 meta_window_show (MetaWindow *window)
02048 {
02049 gboolean did_show;
02050 gboolean takes_focus_on_map;
02051 gboolean place_on_top_on_map;
02052 gboolean needs_stacking_adjustment;
02053 MetaWindow *focus_window;
02054 guint32 timestamp;
02055
02056
02057
02058
02059
02060 timestamp = meta_display_get_current_time_roundtrip (window->display);
02061
02062 meta_topic (META_DEBUG_WINDOW_STATE,
02063 "Showing window %s, shaded: %d iconic: %d placed: %d\n",
02064 window->desc, window->shaded, window->iconic, window->placed);
02065
02066 focus_window = window->display->focus_window;
02067 did_show = FALSE;
02068 window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map);
02069 needs_stacking_adjustment = FALSE;
02070
02071 meta_topic (META_DEBUG_WINDOW_STATE,
02072 "Window %s %s focus on map, and %s place on top on map.\n",
02073 window->desc,
02074 takes_focus_on_map ? "does" : "does not",
02075 place_on_top_on_map ? "does" : "does not");
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088 if ( focus_window != NULL && window->showing_for_first_time &&
02089 ( (!place_on_top_on_map && !takes_focus_on_map) ||
02090 window_would_be_covered (window) )
02091 ) {
02092 if (meta_window_is_ancestor_of_transient (focus_window, window))
02093 {
02094
02095
02096
02097
02098 meta_topic (META_DEBUG_STARTUP,
02099 "The focus window %s is an ancestor of the newly mapped "
02100 "window %s which isn't being focused. Unfocusing the "
02101 "ancestor.\n",
02102 focus_window->desc, window->desc);
02103
02104 meta_display_focus_the_no_focus_window (window->display,
02105 window->screen,
02106 timestamp);
02107 }
02108 else
02109 {
02110 needs_stacking_adjustment = TRUE;
02111 if (!window->placed)
02112 window->denied_focus_and_not_transient = TRUE;
02113 }
02114 }
02115
02116 if (!window->placed)
02117 {
02118
02119
02120
02121
02122
02123
02124
02125
02126 window->calc_placement = TRUE;
02127 meta_window_move_resize_now (window);
02128 window->calc_placement = FALSE;
02129
02130
02131
02132
02133
02134 window->placed = TRUE;
02135
02136
02137
02138
02139 window->denied_focus_and_not_transient = FALSE;
02140 }
02141
02142 if (needs_stacking_adjustment)
02143 {
02144 gboolean overlap;
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156 takes_focus_on_map = FALSE;
02157
02158 overlap = windows_overlap (window, focus_window);
02159
02160
02161 ensure_mru_position_after (window, focus_window);
02162
02163
02164
02165
02166
02167
02168
02169
02170
02171
02172
02173
02174 if (overlap ||
02175 (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK &&
02176 meta_prefs_get_raise_on_click ()))
02177 meta_window_stack_just_below (window, focus_window);
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188 if (overlap)
02189 window->wm_state_demands_attention = TRUE;
02190 }
02191
02192
02193
02194 if (window->frame && !window->frame->mapped)
02195 {
02196 meta_topic (META_DEBUG_WINDOW_STATE,
02197 "Frame actually needs map\n");
02198 window->frame->mapped = TRUE;
02199 meta_ui_map_frame (window->screen->ui, window->frame->xwindow);
02200 did_show = TRUE;
02201 }
02202
02203 if (window->shaded)
02204 {
02205 if (window->mapped)
02206 {
02207 meta_topic (META_DEBUG_WINDOW_STATE,
02208 "%s actually needs unmap (shaded)\n", window->desc);
02209 meta_topic (META_DEBUG_WINDOW_STATE,
02210 "Incrementing unmaps_pending on %s for shade\n",
02211 window->desc);
02212 window->mapped = FALSE;
02213 window->unmaps_pending += 1;
02214 meta_error_trap_push (window->display);
02215 XUnmapWindow (window->display->xdisplay, window->xwindow);
02216 meta_error_trap_pop (window->display, FALSE);
02217 }
02218
02219 if (!window->iconic)
02220 {
02221 window->iconic = TRUE;
02222 set_wm_state (window, IconicState);
02223 }
02224 }
02225 else
02226 {
02227 if (!window->mapped)
02228 {
02229 meta_topic (META_DEBUG_WINDOW_STATE,
02230 "%s actually needs map\n", window->desc);
02231 window->mapped = TRUE;
02232 meta_error_trap_push (window->display);
02233 XMapWindow (window->display->xdisplay, window->xwindow);
02234 meta_error_trap_pop (window->display, FALSE);
02235 did_show = TRUE;
02236
02237 if (window->was_minimized)
02238 {
02239 MetaRectangle window_rect;
02240 MetaRectangle icon_rect;
02241
02242 window->was_minimized = FALSE;
02243
02244 if (meta_window_get_icon_geometry (window, &icon_rect))
02245 {
02246 meta_window_get_outer_rect (window, &window_rect);
02247
02248 meta_effect_run_unminimize (window,
02249 &window_rect,
02250 &icon_rect,
02251 NULL, NULL);
02252 }
02253 }
02254 }
02255
02256 if (window->iconic)
02257 {
02258 window->iconic = FALSE;
02259 set_wm_state (window, NormalState);
02260 }
02261 }
02262
02263
02264
02265
02266
02267 if (window->showing_for_first_time)
02268 {
02269 window->showing_for_first_time = FALSE;
02270 if (takes_focus_on_map)
02271 {
02272 meta_window_focus (window, timestamp);
02273 }
02274 else
02275 {
02276
02277
02278
02279
02280
02281
02282 meta_display_increment_focus_sentinel (window->display);
02283 }
02284 }
02285
02286 set_net_wm_state (window);
02287
02288 if (did_show && window->struts)
02289 {
02290 meta_topic (META_DEBUG_WORKAREA,
02291 "Mapped window %s with struts, so invalidating work areas\n",
02292 window->desc);
02293 invalidate_work_areas (window);
02294 }
02295 }
02296
02297
02298 static void
02299 meta_window_hide (MetaWindow *window)
02300 {
02301 gboolean did_hide;
02302
02303 meta_topic (META_DEBUG_WINDOW_STATE,
02304 "Hiding window %s\n", window->desc);
02305
02306 did_hide = FALSE;
02307
02308 if (window->frame && window->frame->mapped)
02309 {
02310 meta_topic (META_DEBUG_WINDOW_STATE, "Frame actually needs unmap\n");
02311 window->frame->mapped = FALSE;
02312 meta_ui_unmap_frame (window->screen->ui, window->frame->xwindow);
02313 did_hide = TRUE;
02314 }
02315
02316 if (window->mapped)
02317 {
02318 meta_topic (META_DEBUG_WINDOW_STATE,
02319 "%s actually needs unmap\n", window->desc);
02320 meta_topic (META_DEBUG_WINDOW_STATE,
02321 "Incrementing unmaps_pending on %s for hide\n",
02322 window->desc);
02323 window->mapped = FALSE;
02324 window->unmaps_pending += 1;
02325 meta_error_trap_push (window->display);
02326 XUnmapWindow (window->display->xdisplay, window->xwindow);
02327 meta_error_trap_pop (window->display, FALSE);
02328 did_hide = TRUE;
02329 }
02330
02331 if (!window->iconic)
02332 {
02333 window->iconic = TRUE;
02334 set_wm_state (window, IconicState);
02335 }
02336
02337 set_net_wm_state (window);
02338
02339 if (did_hide && window->struts)
02340 {
02341 meta_topic (META_DEBUG_WORKAREA,
02342 "Unmapped window %s with struts, so invalidating work areas\n",
02343 window->desc);
02344 invalidate_work_areas (window);
02345 }
02346 }
02347
02348 static gboolean
02349 queue_calc_showing_func (MetaWindow *window,
02350 void *data)
02351 {
02352 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
02353 return TRUE;
02354 }
02355
02356 void
02357 meta_window_minimize (MetaWindow *window)
02358 {
02359 if (!window->minimized)
02360 {
02361 window->minimized = TRUE;
02362 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
02363
02364 meta_window_foreach_transient (window,
02365 queue_calc_showing_func,
02366 NULL);
02367
02368 if (window->has_focus)
02369 {
02370 meta_topic (META_DEBUG_FOCUS,
02371 "Focusing default window due to minimization of focus window %s\n",
02372 window->desc);
02373 }
02374 else
02375 {
02376 meta_topic (META_DEBUG_FOCUS,
02377 "Minimizing window %s which doesn't have the focus\n",
02378 window->desc);
02379 }
02380 }
02381 }
02382
02383 void
02384 meta_window_unminimize (MetaWindow *window)
02385 {
02386 if (window->minimized)
02387 {
02388 window->minimized = FALSE;
02389 window->was_minimized = TRUE;
02390 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
02391
02392 meta_window_foreach_transient (window,
02393 queue_calc_showing_func,
02394 NULL);
02395 }
02396 }
02397
02398 static void
02399 ensure_size_hints_satisfied (MetaRectangle *rect,
02400 const XSizeHints *size_hints)
02401 {
02402 int minw, minh, maxw, maxh;
02403 int basew, baseh, winc, hinc;
02404 int extra_width, extra_height;
02405
02406 minw = size_hints->min_width; minh = size_hints->min_height;
02407 maxw = size_hints->max_width; maxh = size_hints->max_height;
02408 basew = size_hints->base_width; baseh = size_hints->base_height;
02409 winc = size_hints->width_inc; hinc = size_hints->height_inc;
02410
02411
02412 rect->width = CLAMP (rect->width, minw, maxw);
02413 rect->height = CLAMP (rect->height, minh, maxh);
02414
02415
02416 extra_width = (rect->width - basew) % winc;
02417 extra_height = (rect->height - baseh) % hinc;
02418
02419 rect->width -= extra_width;
02420 rect->height -= extra_height;
02421
02422
02423
02424
02425 if (rect->width < minw)
02426 rect->width += ((minw - rect->width)/winc + 1)*winc;
02427 if (rect->height < minh)
02428 rect->height += ((minh - rect->height)/hinc + 1)*hinc;
02429 }
02430
02431 static void
02432 meta_window_save_rect (MetaWindow *window)
02433 {
02434 if (!(META_WINDOW_MAXIMIZED (window) || window->fullscreen))
02435 {
02436
02437 if (!window->maximized_horizontally)
02438 {
02439 window->saved_rect.x = window->rect.x;
02440 window->saved_rect.width = window->rect.width;
02441 if (window->frame)
02442 window->saved_rect.x += window->frame->rect.x;
02443 }
02444 if (!window->maximized_vertically)
02445 {
02446 window->saved_rect.y = window->rect.y;
02447 window->saved_rect.height = window->rect.height;
02448 if (window->frame)
02449 window->saved_rect.y += window->frame->rect.y;
02450 }
02451 }
02452 }
02453
02460 static void
02461 force_save_user_window_placement (MetaWindow *window)
02462 {
02463 meta_window_get_client_root_coords (window, &window->user_rect);
02464 }
02465
02473 static void
02474 save_user_window_placement (MetaWindow *window)
02475 {
02476 if (!(META_WINDOW_MAXIMIZED (window) || window->fullscreen))
02477 {
02478 MetaRectangle user_rect;
02479
02480 meta_window_get_client_root_coords (window, &user_rect);
02481
02482 if (!window->maximized_horizontally)
02483 {
02484 window->user_rect.x = user_rect.x;
02485 window->user_rect.width = user_rect.width;
02486 }
02487 if (!window->maximized_vertically)
02488 {
02489 window->user_rect.y = user_rect.y;
02490 window->user_rect.height = user_rect.height;
02491 }
02492 }
02493 }
02494
02495 void
02496 meta_window_maximize_internal (MetaWindow *window,
02497 MetaMaximizeFlags directions,
02498 MetaRectangle *saved_rect)
02499 {
02500
02501 gboolean maximize_horizontally, maximize_vertically;
02502 maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
02503 maximize_vertically = directions & META_MAXIMIZE_VERTICAL;
02504 g_assert (maximize_horizontally || maximize_vertically);
02505
02506 meta_topic (META_DEBUG_WINDOW_OPS,
02507 "Maximizing %s%s\n",
02508 window->desc,
02509 maximize_horizontally && maximize_vertically ? "" :
02510 maximize_horizontally ? " horizontally" :
02511 maximize_vertically ? " vertically" : "BUGGGGG");
02512
02513 if (saved_rect != NULL)
02514 window->saved_rect = *saved_rect;
02515 else
02516 meta_window_save_rect (window);
02517
02518 window->maximized_horizontally =
02519 window->maximized_horizontally || maximize_horizontally;
02520 window->maximized_vertically =
02521 window->maximized_vertically || maximize_vertically;
02522
02523
02524
02525
02526
02527
02528 if (window->frame)
02529 window->frame->need_reapply_frame_shape = TRUE;
02530
02531 recalc_window_features (window);
02532 set_net_wm_state (window);
02533 }
02534
02535 void
02536 meta_window_maximize (MetaWindow *window,
02537 MetaMaximizeFlags directions)
02538 {
02539
02540 gboolean maximize_horizontally, maximize_vertically;
02541 maximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
02542 maximize_vertically = directions & META_MAXIMIZE_VERTICAL;
02543 g_assert (maximize_horizontally || maximize_vertically);
02544
02545
02546
02547
02548 if ((maximize_horizontally && !window->maximized_horizontally) ||
02549 (maximize_vertically && !window->maximized_vertically))
02550 {
02551 if (window->shaded && maximize_vertically)
02552 {
02553
02554
02555
02556 guint32 timestamp =
02557 meta_display_get_current_time_roundtrip (window->display);
02558 meta_window_unshade (window, timestamp);
02559 }
02560
02561
02562
02563 if (!window->placed)
02564 {
02565 window->maximize_horizontally_after_placement =
02566 window->maximize_horizontally_after_placement ||
02567 maximize_horizontally;
02568 window->maximize_vertically_after_placement =
02569 window->maximize_vertically_after_placement ||
02570 maximize_vertically;
02571 return;
02572 }
02573
02574 meta_window_maximize_internal (window,
02575 directions,
02576 NULL);
02577
02578
02579
02580 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
02581 }
02582 }
02583
02584 static void
02585 unmaximize_window_before_freeing (MetaWindow *window)
02586 {
02587 meta_topic (META_DEBUG_WINDOW_OPS,
02588 "Unmaximizing %s just before freeing\n",
02589 window->desc);
02590
02591 window->maximized_horizontally = FALSE;
02592 window->maximized_vertically = FALSE;
02593
02594 if (window->withdrawn)
02595 {
02596 window->rect = window->saved_rect;
02597 set_net_wm_state (window);
02598 }
02599 else if (window->screen->closing)
02600 {
02601
02602
02603
02604
02605
02606
02607 meta_window_move_resize (window,
02608 FALSE,
02609 window->saved_rect.x,
02610 window->saved_rect.y,
02611 window->saved_rect.width,
02612 window->saved_rect.height);
02613 }
02614 }
02615
02616 void
02617 meta_window_unmaximize (MetaWindow *window,
02618 MetaMaximizeFlags directions)
02619 {
02620
02621 gboolean unmaximize_horizontally, unmaximize_vertically;
02622 unmaximize_horizontally = directions & META_MAXIMIZE_HORIZONTAL;
02623 unmaximize_vertically = directions & META_MAXIMIZE_VERTICAL;
02624 g_assert (unmaximize_horizontally || unmaximize_vertically);
02625
02626
02627
02628
02629 if ((unmaximize_horizontally && window->maximized_horizontally) ||
02630 (unmaximize_vertically && window->maximized_vertically))
02631 {
02632 MetaRectangle target_rect;
02633
02634 meta_topic (META_DEBUG_WINDOW_OPS,
02635 "Unmaximizing %s%s\n",
02636 window->desc,
02637 unmaximize_horizontally && unmaximize_vertically ? "" :
02638 unmaximize_horizontally ? " horizontally" :
02639 unmaximize_vertically ? " vertically" : "BUGGGGG");
02640
02641 window->maximized_horizontally =
02642 window->maximized_horizontally && !unmaximize_horizontally;
02643 window->maximized_vertically =
02644 window->maximized_vertically && !unmaximize_vertically;
02645
02646
02647
02648
02649 meta_window_get_client_root_coords (window, &target_rect);
02650 if (unmaximize_horizontally)
02651 {
02652 target_rect.x = window->saved_rect.x;
02653 target_rect.width = window->saved_rect.width;
02654 }
02655 if (unmaximize_vertically)
02656 {
02657 target_rect.y = window->saved_rect.y;
02658 target_rect.height = window->saved_rect.height;
02659 }
02660
02661
02662
02663
02664 ensure_size_hints_satisfied (&target_rect, &window->size_hints);
02665
02666
02667
02668
02669
02670
02671 if (meta_grab_op_is_moving (window->display->grab_op) &&
02672 window->display->grab_window == window)
02673 {
02674 window->display->grab_anchor_window_pos = target_rect;
02675 }
02676
02677 meta_window_move_resize (window,
02678 FALSE,
02679 target_rect.x,
02680 target_rect.y,
02681 target_rect.width,
02682 target_rect.height);
02683
02684 if (window->display->grab_wireframe_active)
02685 {
02686 window->display->grab_wireframe_rect = target_rect;
02687 }
02688
02689 recalc_window_features (window);
02690 set_net_wm_state (window);
02691 }
02692 }
02693
02694 void
02695 meta_window_make_above (MetaWindow *window)
02696 {
02697 window->wm_state_above = TRUE;
02698 meta_window_update_layer (window);
02699 meta_window_raise (window);
02700 set_net_wm_state (window);
02701 }
02702
02703 void
02704 meta_window_unmake_above (MetaWindow *window)
02705 {
02706 window->wm_state_above = FALSE;
02707 meta_window_raise (window);
02708 meta_window_update_layer (window);
02709 set_net_wm_state (window);
02710 }
02711
02712 void
02713 meta_window_make_fullscreen_internal (MetaWindow *window)
02714 {
02715 if (!window->fullscreen)
02716 {
02717 meta_topic (META_DEBUG_WINDOW_OPS,
02718 "Fullscreening %s\n", window->desc);
02719
02720 if (window->shaded)
02721 {
02722
02723
02724
02725 guint32 timestamp =
02726 meta_display_get_current_time_roundtrip (window->display);
02727 meta_window_unshade (window, timestamp);
02728 }
02729
02730 meta_window_save_rect (window);
02731
02732 window->fullscreen = TRUE;
02733
02734 meta_stack_freeze (window->screen->stack);
02735 meta_window_update_layer (window);
02736
02737 meta_window_raise (window);
02738 meta_stack_thaw (window->screen->stack);
02739
02740 recalc_window_features (window);
02741 set_net_wm_state (window);
02742 }
02743 }
02744
02745 void
02746 meta_window_make_fullscreen (MetaWindow *window)
02747 {
02748 if (!window->fullscreen)
02749 {
02750 meta_window_make_fullscreen_internal (window);
02751
02752
02753 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
02754 }
02755 }
02756
02757 void
02758 meta_window_unmake_fullscreen (MetaWindow *window)
02759 {
02760 if (window->fullscreen)
02761 {
02762 MetaRectangle target_rect;
02763
02764 meta_topic (META_DEBUG_WINDOW_OPS,
02765 "Unfullscreening %s\n", window->desc);
02766
02767 window->fullscreen = FALSE;
02768 target_rect = window->saved_rect;
02769
02770
02771
02772
02773 ensure_size_hints_satisfied (&target_rect, &window->size_hints);
02774
02775 meta_window_move_resize (window,
02776 FALSE,
02777 target_rect.x,
02778 target_rect.y,
02779 target_rect.width,
02780 target_rect.height);
02781
02782 meta_window_update_layer (window);
02783
02784 recalc_window_features (window);
02785 set_net_wm_state (window);
02786 }
02787 }
02788
02789 void
02790 meta_window_shade (MetaWindow *window,
02791 guint32 timestamp)
02792 {
02793 meta_topic (META_DEBUG_WINDOW_OPS,
02794 "Shading %s\n", window->desc);
02795 if (!window->shaded)
02796 {
02797 window->shaded = TRUE;
02798
02799 meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
02800
02801
02802
02803
02804 meta_topic (META_DEBUG_FOCUS,
02805 "Re-focusing window %s after shading it\n",
02806 window->desc);
02807 meta_window_focus (window, timestamp);
02808
02809 set_net_wm_state (window);
02810 }
02811 }
02812
02813 void
02814 meta_window_unshade (MetaWindow *window,
02815 guint32 timestamp)
02816 {
02817 meta_topic (META_DEBUG_WINDOW_OPS,
02818 "Unshading %s\n", window->desc);
02819 if (window->shaded)
02820 {
02821 window->shaded = FALSE;
02822 meta_window_queue(window, META_QUEUE_MOVE_RESIZE | META_QUEUE_CALC_SHOWING);
02823
02824
02825 meta_topic (META_DEBUG_FOCUS,
02826 "Focusing window %s after unshading it\n",
02827 window->desc);
02828 meta_window_focus (window, timestamp);
02829
02830 set_net_wm_state (window);
02831 }
02832 }
02833
02834 static gboolean
02835 unminimize_func (MetaWindow *window,
02836 void *data)
02837 {
02838 meta_window_unminimize (window);
02839 return TRUE;
02840 }
02841
02842 static void
02843 unminimize_window_and_all_transient_parents (MetaWindow *window)
02844 {
02845 meta_window_unminimize (window);
02846 meta_window_foreach_ancestor (window, unminimize_func, NULL);
02847 }
02848
02849 static void
02850 window_activate (MetaWindow *window,
02851 guint32 timestamp,
02852 MetaClientType source_indication,
02853 MetaWorkspace *workspace)
02854 {
02855 gboolean can_ignore_outdated_timestamps;
02856 meta_topic (META_DEBUG_FOCUS,
02857 "_NET_ACTIVE_WINDOW message sent for %s at time %u "
02858 "by client type %u.\n",
02859 window->desc, timestamp, source_indication);
02860
02861
02862
02863
02864
02865
02866
02867
02868 can_ignore_outdated_timestamps =
02869 (timestamp != 0 || (FALSE && source_indication != META_CLIENT_TYPE_PAGER));
02870 if (XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time) &&
02871 can_ignore_outdated_timestamps)
02872 {
02873 meta_topic (META_DEBUG_FOCUS,
02874 "last_user_time (%u) is more recent; ignoring "
02875 " _NET_ACTIVE_WINDOW message.\n",
02876 window->display->last_user_time);
02877 meta_window_set_demands_attention(window);
02878 return;
02879 }
02880
02881
02882 if (timestamp == 0)
02883 {
02884 meta_warning ("meta_window_activate called by a pager with a 0 timestamp; "
02885 "the pager needs to be fixed.\n");
02886 timestamp = meta_display_get_current_time_roundtrip (window->display);
02887 }
02888
02889 meta_window_set_user_time (window, timestamp);
02890
02891
02892 maybe_leave_show_desktop_mode (window);
02893
02894
02895 if (workspace == NULL)
02896 workspace = window->screen->active_workspace;
02897 if (!meta_window_located_on_workspace (window, workspace))
02898 meta_window_change_workspace (window, workspace);
02899
02900 if (window->shaded)
02901 meta_window_unshade (window, timestamp);
02902
02903 unminimize_window_and_all_transient_parents (window);
02904
02905 if (meta_prefs_get_raise_on_click () ||
02906 source_indication == META_CLIENT_TYPE_PAGER)
02907 meta_window_raise (window);
02908
02909 meta_topic (META_DEBUG_FOCUS,
02910 "Focusing window %s due to activation\n",
02911 window->desc);
02912 meta_window_focus (window, timestamp);
02913 }
02914
02915
02916
02917
02918
02919 void
02920 meta_window_activate (MetaWindow *window,
02921 guint32 timestamp)
02922 {
02923
02924
02925
02926
02927 window_activate (window, timestamp, META_CLIENT_TYPE_PAGER, NULL);
02928 }
02929
02930 void
02931 meta_window_activate_with_workspace (MetaWindow *window,
02932 guint32 timestamp,
02933 MetaWorkspace *workspace)
02934 {
02935
02936
02937
02938
02939 window_activate (window, timestamp, META_CLIENT_TYPE_APPLICATION, workspace);
02940 }
02941
02942
02943
02944
02945
02946
02947 static void
02948 adjust_for_gravity (MetaWindow *window,
02949 MetaFrameGeometry *fgeom,
02950 gboolean coords_assume_border,
02951 int gravity,
02952 MetaRectangle *rect)
02953 {
02954 int ref_x, ref_y;
02955 int bw;
02956 int child_x, child_y;
02957 int frame_width, frame_height;
02958
02959 if (coords_assume_border)
02960 bw = window->border_width;
02961 else
02962 bw = 0;
02963
02964 if (fgeom)
02965 {
02966 child_x = fgeom->left_width;
02967 child_y = fgeom->top_height;
02968 frame_width = child_x + rect->width + fgeom->right_width;
02969 frame_height = child_y + rect->height + fgeom->bottom_height;
02970 }
02971 else
02972 {
02973 child_x = 0;
02974 child_y = 0;
02975 frame_width = rect->width;
02976 frame_height = rect->height;
02977 }
02978
02979
02980
02981
02982
02983
02984
02985
02986 switch (gravity)
02987 {
02988 case NorthWestGravity:
02989 ref_x = rect->x;
02990 ref_y = rect->y;
02991 break;
02992 case NorthGravity:
02993 ref_x = rect->x + rect->width / 2 + bw;
02994 ref_y = rect->y;
02995 break;
02996 case NorthEastGravity:
02997 ref_x = rect->x + rect->width + bw * 2;
02998 ref_y = rect->y;
02999 break;
03000 case WestGravity:
03001 ref_x = rect->x;
03002 ref_y = rect->y + rect->height / 2 + bw;
03003 break;
03004 case CenterGravity:
03005 ref_x = rect->x + rect->width / 2 + bw;
03006 ref_y = rect->y + rect->height / 2 + bw;
03007 break;
03008 case EastGravity:
03009 ref_x = rect->x + rect->width + bw * 2;
03010 ref_y = rect->y + rect->height / 2 + bw;
03011 break;
03012 case SouthWestGravity:
03013 ref_x = rect->x;
03014 ref_y = rect->y + rect->height + bw * 2;
03015 break;
03016 case SouthGravity:
03017 ref_x = rect->x + rect->width / 2 + bw;
03018 ref_y = rect->y + rect->height + bw * 2;
03019 break;
03020 case SouthEastGravity:
03021 ref_x = rect->x + rect->width + bw * 2;
03022 ref_y = rect->y + rect->height + bw * 2;
03023 break;
03024 case StaticGravity:
03025 default:
03026 ref_x = rect->x;
03027 ref_y = rect->y;
03028 break;
03029 }
03030
03031 switch (gravity)
03032 {
03033 case NorthWestGravity:
03034 rect->x = ref_x + child_x;
03035 rect->y = ref_y + child_y;
03036 break;
03037 case NorthGravity:
03038 rect->x = ref_x - frame_width / 2 + child_x;
03039 rect->y = ref_y + child_y;
03040 break;
03041 case NorthEastGravity:
03042 rect->x = ref_x - frame_width + child_x;
03043 rect->y = ref_y + child_y;
03044 break;
03045 case WestGravity:
03046 rect->x = ref_x + child_x;
03047 rect->y = ref_y - frame_height / 2 + child_y;
03048 break;
03049 case CenterGravity:
03050 rect->x = ref_x - frame_width / 2 + child_x;
03051 rect->y = ref_y - frame_height / 2 + child_y;
03052 break;
03053 case EastGravity:
03054 rect->x = ref_x - frame_width + child_x;
03055 rect->y = ref_y - frame_height / 2 + child_y;
03056 break;
03057 case SouthWestGravity:
03058 rect->x = ref_x + child_x;
03059 rect->y = ref_y - frame_height + child_y;
03060 break;
03061 case SouthGravity:
03062 rect->x = ref_x - frame_width / 2 + child_x;
03063 rect->y = ref_y - frame_height + child_y;
03064 break;
03065 case SouthEastGravity:
03066 rect->x = ref_x - frame_width + child_x;
03067 rect->y = ref_y - frame_height + child_y;
03068 break;
03069 case StaticGravity:
03070 default:
03071 rect->x = ref_x;
03072 rect->y = ref_y;
03073 break;
03074 }
03075 }
03076
03077 static gboolean
03078 static_gravity_works (MetaDisplay *display)
03079 {
03080 return display->static_gravity_works;
03081 }
03082
03083 #ifdef HAVE_XSYNC
03084 static void
03085 send_sync_request (MetaWindow *window)
03086 {
03087 XSyncValue value;
03088 XClientMessageEvent ev;
03089
03090 window->sync_request_serial++;
03091
03092 XSyncIntToValue (&value, window->sync_request_serial);
03093
03094 ev.type = ClientMessage;
03095 ev.window = window->xwindow;
03096 ev.message_type = window->display->atom_WM_PROTOCOLS;
03097 ev.format = 32;
03098 ev.data.l[0] = window->display->atom__NET_WM_SYNC_REQUEST;
03099
03100
03101
03102
03103
03104 ev.data.l[1] = meta_display_get_current_time (window->display);
03105 ev.data.l[2] = XSyncValueLow32 (value);
03106 ev.data.l[3] = XSyncValueHigh32 (value);
03107
03108
03109
03110
03111 XSendEvent (window->display->xdisplay,
03112 window->xwindow, False, 0, (XEvent*) &ev);
03113
03114 g_get_current_time (&window->sync_request_time);
03115 }
03116 #endif
03117
03118 static void
03119 meta_window_move_resize_internal (MetaWindow *window,
03120 MetaMoveResizeFlags flags,
03121 int gravity,
03122 int root_x_nw,
03123 int root_y_nw,
03124 int w,
03125 int h)
03126 {
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152
03153
03154
03155
03156
03157
03158
03159
03160 XWindowChanges values;
03161 unsigned int mask;
03162 gboolean need_configure_notify;
03163 MetaFrameGeometry fgeom;
03164 gboolean need_move_client = FALSE;
03165 gboolean need_move_frame = FALSE;
03166 gboolean need_resize_client = FALSE;
03167 gboolean need_resize_frame = FALSE;
03168 int frame_size_dx;
03169 int frame_size_dy;
03170 int size_dx;
03171 int size_dy;
03172 gboolean is_configure_request;
03173 gboolean do_gravity_adjust;
03174 gboolean is_user_action;
03175 gboolean configure_frame_first;
03176 gboolean use_static_gravity;
03177
03178
03179
03180 int client_move_x;
03181 int client_move_y;
03182 MetaRectangle new_rect;
03183 MetaRectangle old_rect;
03184
03185 is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
03186 do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
03187 is_user_action = (flags & META_IS_USER_ACTION) != 0;
03188
03189
03190 g_assert (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION));
03191
03192
03193 meta_window_unqueue (window, META_QUEUE_MOVE_RESIZE);
03194
03195 meta_window_get_client_root_coords (window, &old_rect);
03196
03197 meta_topic (META_DEBUG_GEOMETRY,
03198 "Move/resize %s to %d,%d %dx%d%s%s from %d,%d %dx%d\n",
03199 window->desc, root_x_nw, root_y_nw, w, h,
03200 is_configure_request ? " (configure request)" : "",
03201 is_user_action ? " (user move/resize)" : "",
03202 old_rect.x, old_rect.y, old_rect.width, old_rect.height);
03203
03204 if (window->frame)
03205 meta_frame_calc_geometry (window->frame,
03206 &fgeom);
03207
03208 new_rect.x = root_x_nw;
03209 new_rect.y = root_y_nw;
03210 new_rect.width = w;
03211 new_rect.height = h;
03212
03213
03214
03215
03216
03217 if ((flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION)) ==
03218 META_IS_RESIZE_ACTION)
03219 {
03220 meta_rectangle_resize_with_gravity (&old_rect,
03221 &new_rect,
03222 gravity,
03223 new_rect.width,
03224 new_rect.height);
03225
03226 meta_topic (META_DEBUG_GEOMETRY,
03227 "Compensated for gravity in resize action; new pos %d,%d\n",
03228 new_rect.x, new_rect.y);
03229 }
03230 else if (is_configure_request || do_gravity_adjust)
03231 {
03232 adjust_for_gravity (window,
03233 window->frame ? &fgeom : NULL,
03234
03235
03236
03237 is_configure_request,
03238 gravity,
03239 &new_rect);
03240
03241 meta_topic (META_DEBUG_GEOMETRY,
03242 "Compensated for configure_request/do_gravity_adjust needing "
03243 "weird positioning; new pos %d,%d\n",
03244 new_rect.x, new_rect.y);
03245 }
03246
03247 meta_window_constrain (window,
03248 window->frame ? &fgeom : NULL,
03249 flags,
03250 gravity,
03251 &old_rect,
03252 &new_rect);
03253
03254 w = new_rect.width;
03255 h = new_rect.height;
03256 root_x_nw = new_rect.x;
03257 root_y_nw = new_rect.y;
03258
03259 if (w != window->rect.width ||
03260 h != window->rect.height)
03261 need_resize_client = TRUE;
03262
03263 window->rect.width = w;
03264 window->rect.height = h;
03265
03266 if (window->frame)
03267 {
03268 int new_w, new_h;
03269
03270 new_w = window->rect.width + fgeom.left_width + fgeom.right_width;
03271
03272 if (window->shaded)
03273 new_h = fgeom.top_height;
03274 else
03275 new_h = window->rect.height + fgeom.top_height + fgeom.bottom_height;
03276
03277 frame_size_dx = new_w - window->frame->rect.width;
03278 frame_size_dy = new_h - window->frame->rect.height;
03279
03280 need_resize_frame = (frame_size_dx != 0 || frame_size_dy != 0);
03281
03282 window->frame->rect.width = new_w;
03283 window->frame->rect.height = new_h;
03284
03285 meta_topic (META_DEBUG_GEOMETRY,
03286 "Calculated frame size %dx%d\n",
03287 window->frame->rect.width,
03288 window->frame->rect.height);
03289 }
03290 else
03291 {
03292 frame_size_dx = 0;
03293 frame_size_dy = 0;
03294 }
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311 if (window->frame)
03312 {
03313 int new_x, new_y;
03314 int frame_pos_dx, frame_pos_dy;
03315
03316
03317 new_x = root_x_nw - fgeom.left_width;
03318 new_y = root_y_nw - fgeom.top_height;
03319
03320 frame_pos_dx = new_x - window->frame->rect.x;
03321 frame_pos_dy = new_y - window->frame->rect.y;
03322
03323 need_move_frame = (frame_pos_dx != 0 || frame_pos_dy != 0);
03324
03325 window->frame->rect.x = new_x;
03326 window->frame->rect.y = new_y;
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341 new_x = fgeom.left_width;
03342 new_y = fgeom.top_height;
03343
03344 if (need_resize_frame && need_move_frame &&
03345 static_gravity_works (window->display))
03346 {
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368 client_move_x = new_x + frame_pos_dx;
03369 client_move_y = new_y + frame_pos_dy;
03370
03371 if (need_move_frame)
03372 need_move_client = TRUE;
03373
03374 use_static_gravity = TRUE;
03375 }
03376 else
03377 {
03378 client_move_x = new_x;
03379 client_move_y = new_y;
03380
03381 if (client_move_x != window->rect.x ||
03382 client_move_y != window->rect.y)
03383 need_move_client = TRUE;
03384
03385 use_static_gravity = FALSE;
03386 }
03387
03388
03389
03390
03391
03392 window->rect.x = new_x;
03393 window->rect.y = new_y;
03394 }
03395 else
03396 {
03397 if (root_x_nw != window->rect.x ||
03398 root_y_nw != window->rect.y)
03399 need_move_client = TRUE;
03400
03401 window->rect.x = root_x_nw;
03402 window->rect.y = root_y_nw;
03403
03404 client_move_x = window->rect.x;
03405 client_move_y = window->rect.y;
03406
03407 use_static_gravity = FALSE;
03408 }
03409
03410
03411
03412 if (window->frame &&
03413 (window->frame->child_x != fgeom.left_width ||
03414 window->frame->child_y != fgeom.top_height ||
03415 window->frame->right_width != fgeom.right_width ||
03416 window->frame->bottom_height != fgeom.bottom_height))
03417 {
03418 window->frame->child_x = fgeom.left_width;
03419 window->frame->child_y = fgeom.top_height;
03420 window->frame->right_width = fgeom.right_width;
03421 window->frame->bottom_height = fgeom.bottom_height;
03422
03423 update_net_frame_extents (window);
03424 }
03425
03426
03427
03428 need_configure_notify = FALSE;
03429
03430
03431
03432
03433 if (is_configure_request &&
03434 !(need_move_client || need_move_frame ||
03435 need_resize_client || need_resize_frame ||
03436 window->border_width != 0))
03437 need_configure_notify = TRUE;
03438
03439
03440
03441
03442 if ((need_move_client || need_move_frame) &&
03443 !(need_resize_client || need_resize_frame))
03444 need_configure_notify = TRUE;
03445
03446
03447
03448
03449
03450
03451
03452
03453 if (window->constructing && window->frame &&
03454 ((window->size_hints.flags & PPosition) ||
03455 (window->size_hints.flags & USPosition)))
03456 need_configure_notify = TRUE;
03457
03458
03459
03460
03461
03462
03463
03464 size_dx = w - window->rect.width;
03465 size_dy = h - window->rect.height;
03466
03467 configure_frame_first = (size_dx + size_dy >= 0);
03468
03469 if (use_static_gravity)
03470 meta_window_set_gravity (window, StaticGravity);
03471
03472 if (configure_frame_first && window->frame)
03473 meta_frame_sync_to_window (window->frame,
03474 gravity,
03475 need_move_frame, need_resize_frame);
03476
03477 values.border_width = 0;
03478 values.x = client_move_x;
03479 values.y = client_move_y;
03480 values.width = window->rect.width;
03481 values.height = window->rect.height;
03482
03483 mask = 0;
03484 if (is_configure_request && window->border_width != 0)
03485 mask |= CWBorderWidth;
03486 if (need_move_client)
03487 mask |= (CWX | CWY);
03488 if (need_resize_client)
03489 mask |= (CWWidth | CWHeight);
03490
03491 if (mask != 0)
03492 {
03493 {
03494 int newx, newy;
03495 meta_window_get_position (window, &newx, &newy);
03496 meta_topic (META_DEBUG_GEOMETRY,
03497 "Syncing new client geometry %d,%d %dx%d, border: %s pos: %s size: %s\n",
03498 newx, newy,
03499 window->rect.width, window->rect.height,
03500 mask & CWBorderWidth ? "true" : "false",
03501 need_move_client ? "true" : "false",
03502 need_resize_client ? "true" : "false");
03503 }
03504
03505 meta_error_trap_push (window->display);
03506
03507 #ifdef HAVE_XSYNC
03508 if (window->sync_request_counter != None &&
03509 window->display->grab_sync_request_alarm != None &&
03510 window->sync_request_time.tv_usec == 0 &&
03511 window->sync_request_time.tv_sec == 0)
03512 {
03513
03514 if (window->display->compositor)
03515 meta_compositor_set_updates (window->display->compositor, window, FALSE);
03516
03517 send_sync_request (window);
03518 }
03519 #endif
03520
03521 XConfigureWindow (window->display->xdisplay,
03522 window->xwindow,
03523 mask,
03524 &values);
03525
03526 meta_error_trap_pop (window->display, FALSE);
03527 }
03528
03529 if (!configure_frame_first && window->frame)
03530 meta_frame_sync_to_window (window->frame,
03531 gravity,
03532 need_move_frame, need_resize_frame);
03533
03534
03535 if (use_static_gravity)
03536 meta_window_set_gravity (window, NorthWestGravity);
03537
03538 if (need_configure_notify)
03539 send_configure_notify (window);
03540
03541 if (!window->placed)
03542 force_save_user_window_placement (window);
03543 else if (is_user_action)
03544 save_user_window_placement (window);
03545
03546 if (need_move_frame || need_resize_frame ||
03547 need_move_client || need_resize_client)
03548 {
03549 int newx, newy;
03550 meta_window_get_position (window, &newx, &newy);
03551 meta_topic (META_DEBUG_GEOMETRY,
03552 "New size/position %d,%d %dx%d (user %d,%d %dx%d)\n",
03553 newx, newy, window->rect.width, window->rect.height,
03554 window->user_rect.x, window->user_rect.y,
03555 window->user_rect.width, window->user_rect.height);
03556 }
03557 else
03558 {
03559 meta_topic (META_DEBUG_GEOMETRY, "Size/position not modified\n");
03560 }
03561
03562 if (window->display->grab_wireframe_active)
03563 meta_window_update_wireframe (window, root_x_nw, root_y_nw, w, h);
03564 else
03565 meta_window_refresh_resize_popup (window);
03566
03567
03568
03569
03570
03571
03572 }
03573
03574 void
03575 meta_window_resize (MetaWindow *window,
03576 gboolean user_op,
03577 int w,
03578 int h)
03579 {
03580 int x, y;
03581 MetaMoveResizeFlags flags;
03582
03583 meta_window_get_position (window, &x, &y);
03584
03585 flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
03586 meta_window_move_resize_internal (window,
03587 flags,
03588 NorthWestGravity,
03589 x, y, w, h);
03590 }
03591
03592 void
03593 meta_window_move (MetaWindow *window,
03594 gboolean user_op,
03595 int root_x_nw,
03596 int root_y_nw)
03597 {
03598 MetaMoveResizeFlags flags =
03599 (user_op ? META_IS_USER_ACTION : 0) | META_IS_MOVE_ACTION;
03600 meta_window_move_resize_internal (window,
03601 flags,
03602 NorthWestGravity,
03603 root_x_nw, root_y_nw,
03604 window->rect.width,
03605 window->rect.height);
03606 }
03607
03608 void
03609 meta_window_move_resize (MetaWindow *window,
03610 gboolean user_op,
03611 int root_x_nw,
03612 int root_y_nw,
03613 int w,
03614 int h)
03615 {
03616 MetaMoveResizeFlags flags =
03617 (user_op ? META_IS_USER_ACTION : 0) |
03618 META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION;
03619 meta_window_move_resize_internal (window,
03620 flags,
03621 NorthWestGravity,
03622 root_x_nw, root_y_nw,
03623 w, h);
03624 }
03625
03626 void
03627 meta_window_resize_with_gravity (MetaWindow *window,
03628 gboolean user_op,
03629 int w,
03630 int h,
03631 int gravity)
03632 {
03633 int x, y;
03634 MetaMoveResizeFlags flags;
03635
03636 meta_window_get_position (window, &x, &y);
03637
03638 flags = (user_op ? META_IS_USER_ACTION : 0) | META_IS_RESIZE_ACTION;
03639 meta_window_move_resize_internal (window,
03640 flags,
03641 gravity,
03642 x, y, w, h);
03643 }
03644
03645 static void
03646 meta_window_move_resize_now (MetaWindow *window)
03647 {
03648
03649
03650
03651
03652 meta_window_move_resize (window, FALSE,
03653 window->user_rect.x,
03654 window->user_rect.y,
03655 window->user_rect.width,
03656 window->user_rect.height);
03657 }
03658
03659 static gboolean
03660 idle_move_resize (gpointer data)
03661 {
03662 GSList *tmp;
03663 GSList *copy;
03664 guint queue_index = GPOINTER_TO_INT (data);
03665
03666 meta_topic (META_DEBUG_GEOMETRY, "Clearing the move_resize queue\n");
03667
03668
03669
03670
03671
03672 copy = g_slist_copy (queue_pending[queue_index]);
03673 g_slist_free (queue_pending[queue_index]);
03674 queue_pending[queue_index] = NULL;
03675 queue_idle[queue_index] = 0;
03676
03677 destroying_windows_disallowed += 1;
03678
03679 tmp = copy;
03680 while (tmp != NULL)
03681 {
03682 MetaWindow *window;
03683
03684 window = tmp->data;
03685
03686
03687 meta_window_move_resize_now (window);
03688
03689 tmp = tmp->next;
03690 }
03691
03692 g_slist_free (copy);
03693
03694 destroying_windows_disallowed -= 1;
03695
03696 return FALSE;
03697 }
03698
03699 void
03700 meta_window_get_position (MetaWindow *window,
03701 int *x,
03702 int *y)
03703 {
03704 if (window->frame)
03705 {
03706 if (x)
03707 *x = window->frame->rect.x + window->frame->child_x;
03708 if (y)
03709 *y = window->frame->rect.y + window->frame->child_y;
03710 }
03711 else
03712 {
03713 if (x)
03714 *x = window->rect.x;
03715 if (y)
03716 *y = window->rect.y;
03717 }
03718 }
03719
03720 void
03721 meta_window_get_client_root_coords (MetaWindow *window,
03722 MetaRectangle *rect)
03723 {
03724 meta_window_get_position (window, &rect->x, &rect->y);
03725 rect->width = window->rect.width;
03726 rect->height = window->rect.height;
03727 }
03728
03729 void
03730 meta_window_get_gravity_position (MetaWindow *window,
03731 int gravity,
03732 int *root_x,
03733 int *root_y)
03734 {
03735 MetaRectangle frame_extents;
03736 int w, h;
03737 int x, y;
03738
03739 w = window->rect.width;
03740 h = window->rect.height;
03741
03742 if (gravity == StaticGravity)
03743 {
03744 frame_extents = window->rect;
03745 if (window->frame)
03746 {
03747 frame_extents.x = window->frame->rect.x + window->frame->child_x;
03748 frame_extents.y = window->frame->rect.y + window->frame->child_y;
03749 }
03750 }
03751 else
03752 {
03753 if (window->frame == NULL)
03754 frame_extents = window->rect;
03755 else
03756 frame_extents = window->frame->rect;
03757 }
03758
03759 x = frame_extents.x;
03760 y = frame_extents.y;
03761
03762 switch (gravity)
03763 {
03764 case NorthGravity:
03765 case CenterGravity:
03766 case SouthGravity:
03767
03768 x += frame_extents.width / 2;
03769
03770 x -= w / 2;
03771 break;
03772
03773 case SouthEastGravity:
03774 case EastGravity:
03775 case NorthEastGravity:
03776
03777 x += frame_extents.width;
03778
03779 x -= w;
03780 break;
03781 default:
03782 break;
03783 }
03784
03785 switch (gravity)
03786 {
03787 case WestGravity:
03788 case CenterGravity:
03789 case EastGravity:
03790
03791 y += frame_extents.height / 2;
03792
03793 y -= h / 2;
03794 break;
03795 case SouthWestGravity:
03796 case SouthGravity:
03797 case SouthEastGravity:
03798
03799 y += frame_extents.height;
03800
03801 y -= h;
03802 break;
03803 default:
03804 break;
03805 }
03806
03807 if (root_x)
03808 *root_x = x;
03809 if (root_y)
03810 *root_y = y;
03811 }
03812
03813 void
03814 meta_window_get_geometry (MetaWindow *window,
03815 int *x,
03816 int *y,
03817 int *width,
03818 int *height)
03819 {
03820 meta_window_get_gravity_position (window,
03821 window->size_hints.win_gravity,
03822 x, y);
03823
03824 *width = (window->rect.width - window->size_hints.base_width) /
03825 window->size_hints.width_inc;
03826 *height = (window->rect.height - window->size_hints.base_height) /
03827 window->size_hints.height_inc;
03828 }
03829
03830 void
03831 meta_window_get_outer_rect (const MetaWindow *window,
03832 MetaRectangle *rect)
03833 {
03834 if (window->frame)
03835 *rect = window->frame->rect;
03836 else
03837 *rect = window->rect;
03838 }
03839
03840 void
03841 meta_window_get_xor_rect (MetaWindow *window,
03842 const MetaRectangle *grab_wireframe_rect,
03843 MetaRectangle *xor_rect)
03844 {
03845 if (window->frame)
03846 {
03847 xor_rect->x = grab_wireframe_rect->x - window->frame->child_x;
03848 xor_rect->y = grab_wireframe_rect->y - window->frame->child_y;
03849 xor_rect->width = grab_wireframe_rect->width + window->frame->child_x + window->frame->right_width;
03850
03851 if (window->shaded)
03852 xor_rect->height = window->frame->child_y;
03853 else
03854 xor_rect->height = grab_wireframe_rect->height + window->frame->child_y + window->frame->bottom_height;
03855 }
03856 else
03857 *xor_rect = *grab_wireframe_rect;
03858 }
03859
03860
03861
03862
03863 static void
03864 meta_window_get_wireframe_geometry (MetaWindow *window,
03865 int *width,
03866 int *height)
03867 {
03868 if (!window->display->grab_wireframe_active)
03869 return;
03870
03871 if ((width == NULL) || (height == NULL))
03872 return;
03873
03874 if ((window->display->grab_window->size_hints.width_inc <= 1) ||
03875 (window->display->grab_window->size_hints.height_inc <= 1))
03876 {
03877 *width = -1;
03878 *height = -1;
03879 return;
03880 }
03881
03882 *width = window->display->grab_wireframe_rect.width -
03883 window->display->grab_window->size_hints.base_width;
03884 *width /= window->display->grab_window->size_hints.width_inc;
03885
03886 *height = window->display->grab_wireframe_rect.height -
03887 window->display->grab_window->size_hints.base_height;
03888 *height /= window->display->grab_window->size_hints.height_inc;
03889 }
03890
03891
03892 void
03893 meta_window_begin_wireframe (MetaWindow *window)
03894 {
03895
03896 MetaRectangle new_xor;
03897 int display_width, display_height;
03898
03899 meta_window_get_client_root_coords (window,
03900 &window->display->grab_wireframe_rect);
03901
03902 meta_window_get_xor_rect (window, &window->display->grab_wireframe_rect,
03903 &new_xor);
03904 meta_window_get_wireframe_geometry (window, &display_width, &display_height);
03905
03906 meta_effects_begin_wireframe (window->screen,
03907 &new_xor, display_width, display_height);
03908
03909 window->display->grab_wireframe_last_xor_rect = new_xor;
03910 window->display->grab_wireframe_last_display_width = display_width;
03911 window->display->grab_wireframe_last_display_height = display_height;
03912 }
03913
03914 void
03915 meta_window_update_wireframe (MetaWindow *window,
03916 int x,
03917 int y,
03918 int width,
03919 int height)
03920 {
03921
03922 MetaRectangle new_xor;
03923 int display_width, display_height;
03924
03925 window->display->grab_wireframe_rect.x = x;
03926 window->display->grab_wireframe_rect.y = y;
03927 window->display->grab_wireframe_rect.width = width;
03928 window->display->grab_wireframe_rect.height = height;
03929
03930 meta_window_get_xor_rect (window, &window->display->grab_wireframe_rect,
03931 &new_xor);
03932 meta_window_get_wireframe_geometry (window, &display_width, &display_height);
03933
03934 meta_effects_update_wireframe (window->screen,
03935 &window->display->grab_wireframe_last_xor_rect,
03936 window->display->grab_wireframe_last_display_width,
03937 window->display->grab_wireframe_last_display_height,
03938 &new_xor, display_width, display_height);
03939
03940 window->display->grab_wireframe_last_xor_rect = new_xor;
03941 window->display->grab_wireframe_last_display_width = display_width;
03942 window->display->grab_wireframe_last_display_height = display_height;
03943 }
03944
03945 void
03946 meta_window_end_wireframe (MetaWindow *window)
03947 {
03948 meta_effects_end_wireframe (window->display->grab_window->screen,
03949 &window->display->grab_wireframe_last_xor_rect,
03950 window->display->grab_wireframe_last_display_width,
03951 window->display->grab_wireframe_last_display_height);
03952 }
03953
03954 const char*
03955 meta_window_get_startup_id (MetaWindow *window)
03956 {
03957 if (window->startup_id == NULL)
03958 {
03959 MetaGroup *group;
03960
03961 group = meta_window_get_group (window);
03962
03963 if (group != NULL)
03964 return meta_group_get_startup_id (group);
03965 }
03966
03967 return window->startup_id;
03968 }
03969
03970 static MetaWindow*
03971 get_modal_transient (MetaWindow *window)
03972 {
03973 GSList *windows;
03974 GSList *tmp;
03975 MetaWindow *modal_transient;
03976
03977
03978
03979
03980
03981 modal_transient = window;
03982
03983 windows = meta_display_list_windows (window->display);
03984 tmp = windows;
03985 while (tmp != NULL)
03986 {
03987 MetaWindow *transient = tmp->data;
03988
03989 if (transient->xtransient_for == modal_transient->xwindow &&
03990 transient->wm_state_modal)
03991 {
03992 modal_transient = transient;
03993 tmp = windows;
03994 continue;
03995 }
03996
03997 tmp = tmp->next;
03998 }
03999
04000 g_slist_free (windows);
04001
04002 if (window == modal_transient)
04003 modal_transient = NULL;
04004
04005 return modal_transient;
04006 }
04007
04008
04009 void
04010 meta_window_focus (MetaWindow *window,
04011 guint32 timestamp)
04012 {
04013 MetaWindow *modal_transient;
04014
04015 meta_topic (META_DEBUG_FOCUS,
04016 "Setting input focus to window %s, input: %d take_focus: %d\n",
04017 window->desc, window->input, window->take_focus);
04018
04019 if (window->display->grab_window &&
04020 window->display->grab_window->all_keys_grabbed)
04021 {
04022 meta_topic (META_DEBUG_FOCUS,
04023 "Current focus window %s has global keygrab, not focusing window %s after all\n",
04024 window->display->grab_window->desc, window->desc);
04025 return;
04026 }
04027
04028 modal_transient = get_modal_transient (window);
04029 if (modal_transient != NULL &&
04030 !modal_transient->unmanaging)
04031 {
04032 meta_topic (META_DEBUG_FOCUS,
04033 "%s has %s as a modal transient, so focusing it instead.\n",
04034 window->desc, modal_transient->desc);
04035 if (!modal_transient->on_all_workspaces &&
04036 modal_transient->workspace != window->screen->active_workspace)
04037 meta_window_change_workspace (modal_transient,
04038 window->screen->active_workspace);
04039 window = modal_transient;
04040 }
04041
04042 meta_window_flush_calc_showing (window);
04043
04044 if (!window->mapped && !window->shaded)
04045 {
04046 meta_topic (META_DEBUG_FOCUS,
04047 "Window %s is not showing, not focusing after all\n",
04048 window->desc);
04049 return;
04050 }
04051
04052
04053
04054
04055
04056
04057
04058 if (window->frame &&
04059 (window->shaded ||
04060 !(window->input || window->take_focus)))
04061 {
04062 if (window->frame)
04063 {
04064 meta_topic (META_DEBUG_FOCUS,
04065 "Focusing frame of %s\n", window->desc);
04066 meta_display_set_input_focus_window (window->display,
04067 window,
04068 TRUE,
04069 timestamp);
04070 }
04071 }
04072 else
04073 {
04074 if (window->input)
04075 {
04076 meta_topic (META_DEBUG_FOCUS,
04077 "Setting input focus on %s since input = true\n",
04078 window->desc);
04079 meta_display_set_input_focus_window (window->display,
04080 window,
04081 FALSE,
04082 timestamp);
04083 }
04084
04085 if (window->take_focus)
04086 {
04087 meta_topic (META_DEBUG_FOCUS,
04088 "Sending WM_TAKE_FOCUS to %s since take_focus = true\n",
04089 window->desc);
04090 meta_window_send_icccm_message (window,
04091 window->display->atom_WM_TAKE_FOCUS,
04092 timestamp);
04093 window->display->expected_focus_window = window;
04094 }
04095 }
04096
04097 if (window->wm_state_demands_attention)
04098 meta_window_unset_demands_attention(window);
04099
04100 meta_effect_run_focus(window, NULL, NULL);
04101 }
04102
04103 static void
04104 meta_window_change_workspace_without_transients (MetaWindow *window,
04105 MetaWorkspace *workspace)
04106 {
04107 meta_verbose ("Changing window %s to workspace %d\n",
04108 window->desc, meta_workspace_index (workspace));
04109
04110
04111
04112
04113
04114 if (window->on_all_workspaces)
04115 meta_window_unstick (window);
04116
04117
04118 if (window->workspace != workspace)
04119 {
04120 meta_workspace_remove_window (window->workspace, window);
04121 meta_workspace_add_window (workspace, window);
04122 }
04123 }
04124
04125 static gboolean
04126 change_workspace_foreach (MetaWindow *window,
04127 void *data)
04128 {
04129 meta_window_change_workspace_without_transients (window, data);
04130 return TRUE;
04131 }
04132
04133 void
04134 meta_window_change_workspace (MetaWindow *window,
04135 MetaWorkspace *workspace)
04136 {
04137 meta_window_change_workspace_without_transients (window, workspace);
04138
04139 meta_window_foreach_transient (window, change_workspace_foreach,
04140 workspace);
04141 meta_window_foreach_ancestor (window, change_workspace_foreach,
04142 workspace);
04143 }
04144
04145 static void
04146 window_stick_impl (MetaWindow *window)
04147 {
04148 GList *tmp;
04149 MetaWorkspace *workspace;
04150
04151 meta_verbose ("Sticking window %s current on_all_workspaces = %d\n",
04152 window->desc, window->on_all_workspaces);
04153
04154 if (window->on_all_workspaces)
04155 return;
04156
04157
04158
04159
04160
04161 window->on_all_workspaces = TRUE;
04162
04163
04164
04165 tmp = window->screen->workspaces;
04166 while (tmp)
04167 {
04168 workspace = (MetaWorkspace *) tmp->data;
04169 if (!g_list_find (workspace->mru_list, window))
04170 workspace->mru_list = g_list_prepend (workspace->mru_list, window);
04171
04172 tmp = tmp->next;
04173 }
04174
04175 meta_window_set_current_workspace_hint (window);
04176
04177 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
04178 }
04179
04180 static void
04181 window_unstick_impl (MetaWindow *window)
04182 {
04183 GList *tmp;
04184 MetaWorkspace *workspace;
04185
04186 if (!window->on_all_workspaces)
04187 return;
04188
04189
04190
04191 window->on_all_workspaces = FALSE;
04192
04193
04194 tmp = window->screen->workspaces;
04195 while (tmp)
04196 {
04197 workspace = (MetaWorkspace *) tmp->data;
04198 if (window->workspace != workspace)
04199 workspace->mru_list = g_list_remove (workspace->mru_list, window);
04200 tmp = tmp->next;
04201 }
04202
04203
04204
04205
04206
04207
04208 if (window->screen->active_workspace != window->workspace)
04209 meta_window_change_workspace (window, window->screen->active_workspace);
04210
04211 meta_window_set_current_workspace_hint (window);
04212
04213 meta_window_queue(window, META_QUEUE_CALC_SHOWING);
04214 }
04215
04216 static gboolean
04217 stick_foreach_func (MetaWindow *window,
04218 void *data)
04219 {
04220 gboolean stick;
04221
04222 stick = *(gboolean*)data;
04223 if (stick)
04224 window_stick_impl (window);
04225 else
04226 window_unstick_impl (window);
04227 return TRUE;
04228 }
04229
04230 void
04231 meta_window_stick (MetaWindow *window)
04232 {
04233 gboolean stick = TRUE;
04234 window_stick_impl (window);
04235 meta_window_foreach_transient (window,
04236 stick_foreach_func,
04237 &stick);
04238 }
04239
04240 void
04241 meta_window_unstick (MetaWindow *window)
04242 {
04243 gboolean stick = FALSE;
04244 window_unstick_impl (window);
04245 meta_window_foreach_transient (window,
04246 stick_foreach_func,
04247 &stick);
04248 }
04249
04250 unsigned long
04251 meta_window_get_net_wm_desktop (MetaWindow *window)
04252 {
04253 if (window->on_all_workspaces)
04254 return 0xFFFFFFFF;
04255 else
04256 return meta_workspace_index (window->workspace);
04257 }
04258
04259 static void
04260 update_net_frame_extents (MetaWindow *window)
04261 {
04262 unsigned long data[4] = { 0, 0, 0, 0 };
04263
04264 if (window->frame)
04265 {
04266
04267 data[0] = window->frame->child_x;
04268
04269 data[1] = window->frame->right_width;
04270
04271 data[2] = window->frame->child_y;
04272
04273 data[3] = window->frame->bottom_height;
04274 }
04275
04276 meta_topic (META_DEBUG_GEOMETRY,
04277 "Setting _NET_FRAME_EXTENTS on managed window 0x%lx "
04278 "to left = %lu, right = %lu, top = %lu, bottom = %lu\n",
04279 window->xwindow, data[0], data[1], data[2], data[3]);
04280
04281 meta_error_trap_push (window->display);
04282 XChangeProperty (window->display->xdisplay, window->xwindow,
04283 window->display->atom__NET_FRAME_EXTENTS,
04284 XA_CARDINAL,
04285 32, PropModeReplace, (guchar*) data, 4);
04286 meta_error_trap_pop (window->display, FALSE);
04287 }
04288
04289 void
04290 meta_window_set_current_workspace_hint (MetaWindow *window)
04291 {
04292
04293
04294
04295 unsigned long data[1];
04296
04297 if (window->workspace == NULL)
04298 {
04299
04300 return;
04301 }
04302
04303 data[0] = meta_window_get_net_wm_desktop (window);
04304
04305 meta_verbose ("Setting _NET_WM_DESKTOP of %s to %lu\n",
04306 window->desc, data[0]);
04307
04308 meta_error_trap_push (window->display);
04309 XChangeProperty (window->display->xdisplay, window->xwindow,
04310 window->display->atom__NET_WM_DESKTOP,
04311 XA_CARDINAL,
04312 32, PropModeReplace, (guchar*) data, 1);
04313 meta_error_trap_pop (window->display, FALSE);
04314 }
04315
04316 static gboolean
04317 find_root_ancestor (MetaWindow *window,
04318 void *data)
04319 {
04320 MetaWindow **ancestor = data;
04321
04322
04323 *ancestor = window;
04324
04325
04326
04327
04328 return TRUE;
04329 }
04330
04331 MetaWindow *
04332 meta_window_find_root_ancestor (MetaWindow *window)
04333 {
04334 MetaWindow *ancestor;
04335 ancestor = window;
04336 meta_window_foreach_ancestor (window, find_root_ancestor, &ancestor);
04337 return ancestor;
04338 }
04339
04340 void
04341 meta_window_raise (MetaWindow *window)
04342 {
04343 MetaWindow *ancestor;
04344 ancestor = meta_window_find_root_ancestor (window);
04345
04346 meta_topic (META_DEBUG_WINDOW_OPS,
04347 "Raising window %s, ancestor of %s\n",
04348 ancestor->desc, window->desc);
04349
04350
04351
04352
04353
04354
04355
04356
04357 if (window->screen->stack == ancestor->screen->stack)
04358 meta_stack_raise (window->screen->stack, ancestor);
04359 else
04360 {
04361 meta_warning (
04362 "Either stacks aren't per screen or some window has a weird "
04363 "transient_for hint; window->screen->stack != "
04364 "ancestor->screen->stack. window = %s, ancestor = %s.\n",
04365 window->desc, ancestor->desc);
04366
04367
04368
04369 }
04370
04371
04372
04373
04374
04375
04376 if (window != ancestor)
04377 meta_stack_raise (window->screen->stack, window);
04378 }
04379
04380 void
04381 meta_window_lower (MetaWindow *window)
04382 {
04383 meta_topic (META_DEBUG_WINDOW_OPS,
04384 "Lowering window %s\n", window->desc);
04385
04386 meta_stack_lower (window->screen->stack, window);
04387 }
04388
04389 void
04390 meta_window_send_icccm_message (MetaWindow *window,
04391 Atom atom,
04392 guint32 timestamp)
04393 {
04394
04395
04396
04397
04398
04399
04400
04401
04402
04403
04404
04405
04406
04407
04408
04409
04410 XClientMessageEvent ev;
04411
04412 ev.type = ClientMessage;
04413 ev.window = window->xwindow;
04414 ev.message_type = window->display->atom_WM_PROTOCOLS;
04415 ev.format = 32;
04416 ev.data.l[0] = atom;
04417 ev.data.l[1] = timestamp;
04418
04419 meta_error_trap_push (window->display);
04420 XSendEvent (window->display->xdisplay,
04421 window->xwindow, False, 0, (XEvent*) &ev);
04422 meta_error_trap_pop (window->display, FALSE);
04423 }
04424
04425 void
04426 meta_window_move_resize_request (MetaWindow *window,
04427 guint value_mask,
04428 int gravity,
04429 int new_x,
04430 int new_y,
04431 int new_width,
04432 int new_height)
04433 {
04434 int x, y, width, height;
04435 gboolean allow_position_change;
04436 gboolean in_grab_op;
04437 MetaMoveResizeFlags flags;
04438
04439
04440
04441
04442
04443
04444
04445
04446
04447 in_grab_op = FALSE;
04448 if (window->display->grab_op != META_GRAB_OP_NONE &&
04449 window == window->display->grab_window)
04450 {
04451 switch (window->display->grab_op)
04452 {
04453 case META_GRAB_OP_MOVING:
04454 case META_GRAB_OP_RESIZING_SE:
04455 case META_GRAB_OP_RESIZING_S:
04456 case META_GRAB_OP_RESIZING_SW:
04457 case META_GRAB_OP_RESIZING_N:
04458 case META_GRAB_OP_RESIZING_NE:
04459 case META_GRAB_OP_RESIZING_NW:
04460 case META_GRAB_OP_RESIZING_W:
04461 case META_GRAB_OP_RESIZING_E:
04462 in_grab_op = TRUE;
04463 break;
04464 default:
04465 break;
04466 }
04467 }
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477 meta_window_get_gravity_position (window,
04478 gravity,
04479 &x, &y);
04480
04481 allow_position_change = FALSE;
04482
04483 if (meta_prefs_get_disable_workarounds ())
04484 {
04485 if (window->type == META_WINDOW_DIALOG ||
04486 window->type == META_WINDOW_MODAL_DIALOG ||
04487 window->type == META_WINDOW_SPLASHSCREEN)
04488 ;
04489 else if ((window->size_hints.flags & PPosition) ||
04490
04491
04492
04493 ((window->size_hints.flags & USPosition) &&
04494 !window->placed))
04495 allow_position_change = TRUE;
04496 }
04497 else
04498 {
04499 allow_position_change = TRUE;
04500 }
04501
04502 if (in_grab_op)
04503 allow_position_change = FALSE;
04504
04505 if (allow_position_change)
04506 {
04507 if (value_mask & CWX)
04508 x = new_x;
04509 if (value_mask & CWY)
04510 y = new_y;
04511 if (value_mask & (CWX | CWY))
04512 {
04513
04514
04515
04516 window->placed = TRUE;
04517 }
04518 }
04519 else
04520 {
04521 meta_topic (META_DEBUG_GEOMETRY,
04522 "Not allowing position change for window %s PPosition 0x%lx USPosition 0x%lx type %u\n",
04523 window->desc, window->size_hints.flags & PPosition,
04524 window->size_hints.flags & USPosition,
04525 window->type);
04526 }
04527
04528 width = window->rect.width;
04529 height = window->rect.height;
04530 if (!in_grab_op)
04531 {
04532 if (value_mask & CWWidth)
04533 width = new_width;
04534
04535 if (value_mask & CWHeight)
04536 height = new_height;
04537 }
04538
04539
04540
04541
04542
04543
04544 window->size_hints.x = x;
04545 window->size_hints.y = y;
04546 window->size_hints.width = width;
04547 window->size_hints.height = height;
04548
04549
04550
04551
04552
04553
04554
04555
04556
04557
04558
04559
04560
04561
04562 flags = META_IS_CONFIGURE_REQUEST;
04563 if (value_mask & (CWX | CWY))
04564 flags |= META_IS_MOVE_ACTION;
04565 if (value_mask & (CWWidth | CWHeight))
04566 flags |= META_IS_RESIZE_ACTION;
04567
04568 if (flags & (META_IS_MOVE_ACTION | META_IS_RESIZE_ACTION))
04569 meta_window_move_resize_internal (window,
04570 flags,
04571 gravity,
04572 x,
04573 y,
04574 width,
04575 height);
04576
04577
04578
04579
04580
04581
04582
04583
04584
04585
04586
04587 save_user_window_placement (window);
04588 }
04589
04590 gboolean
04591 meta_window_configure_request (MetaWindow *window,
04592 XEvent *event)
04593 {
04594
04595
04596
04597
04598
04599
04600 if (event->xconfigurerequest.value_mask & CWBorderWidth)
04601 window->border_width = event->xconfigurerequest.border_width;
04602
04603 meta_window_move_resize_request(window,
04604 event->xconfigurerequest.value_mask,
04605 window->size_hints.win_gravity,
04606 event->xconfigurerequest.x,
04607 event->xconfigurerequest.y,
04608 event->xconfigurerequest.width,
04609 event->xconfigurerequest.height);
04610
04611
04612
04613
04614
04615
04616
04617
04618
04619
04620
04621
04622
04623
04624
04625 if (event->xconfigurerequest.value_mask & CWStackMode)
04626 {
04627 MetaWindow *active_window;
04628 active_window = window->display->expected_focus_window;
04629 if (meta_prefs_get_disable_workarounds () ||
04630 !meta_prefs_get_raise_on_click ())
04631 {
04632 meta_topic (META_DEBUG_STACK,
04633 "%s sent an xconfigure stacking request; this is "
04634 "broken behavior and the request is being ignored.\n",
04635 window->desc);
04636 }
04637 else if (active_window &&
04638 !meta_window_same_application (window, active_window) &&
04639 XSERVER_TIME_IS_BEFORE (window->net_wm_user_time,
04640 active_window->net_wm_user_time))
04641 {
04642 meta_topic (META_DEBUG_STACK,
04643 "Ignoring xconfigure stacking request from %s (with "
04644 "user_time %u); currently active application is %s (with "
04645 "user_time %u).\n",
04646 window->desc,
04647 window->net_wm_user_time,
04648 active_window->desc,
04649 active_window->net_wm_user_time);
04650 if (event->xconfigurerequest.detail == Above)
04651 meta_window_set_demands_attention(window);
04652 }
04653 else
04654 {
04655 switch (event->xconfigurerequest.detail)
04656 {
04657 case Above:
04658 meta_window_raise (window);
04659 break;
04660 case Below:
04661 meta_window_lower (window);
04662 break;
04663 case TopIf:
04664 case BottomIf:
04665 case Opposite:
04666 break;
04667 }
04668 }
04669 }
04670
04671 return TRUE;
04672 }
04673
04674 gboolean
04675 meta_window_property_notify (MetaWindow *window,
04676 XEvent *event)
04677 {
04678 return process_property_notify (window, &event->xproperty);
04679 }
04680
04681 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
04682 #define _NET_WM_MOVERESIZE_SIZE_TOP 1
04683 #define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
04684 #define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
04685 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
04686 #define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
04687 #define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
04688 #define _NET_WM_MOVERESIZE_SIZE_LEFT 7
04689 #define _NET_WM_MOVERESIZE_MOVE 8
04690 #define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9
04691 #define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10
04692
04693 gboolean
04694 meta_window_client_message (MetaWindow *window,
04695 XEvent *event)
04696 {
04697 MetaDisplay *display;
04698
04699 display = window->display;
04700
04701 if (event->xclient.message_type ==
04702 display->atom__NET_CLOSE_WINDOW)
04703 {
04704 guint32 timestamp;
04705
04706 if (event->xclient.data.l[0] != 0)
04707 timestamp = event->xclient.data.l[0];
04708 else
04709 {
04710 meta_warning ("Receiving a NET_CLOSE_WINDOW message for %s without "
04711 "a timestamp! This means some buggy (outdated) "
04712 "application is on the loose!\n",
04713 window->desc);
04714 timestamp = meta_display_get_current_time (window->display);
04715 }
04716
04717 meta_window_delete (window, timestamp);
04718
04719 return TRUE;
04720 }
04721 else if (event->xclient.message_type ==
04722 display->atom__NET_WM_DESKTOP)
04723 {
04724 int space;
04725 MetaWorkspace *workspace;
04726
04727 space = event->xclient.data.l[0];
04728
04729 meta_verbose ("Request to move %s to workspace %d\n",
04730 window->desc, space);
04731
04732 workspace =
04733 meta_screen_get_workspace_by_index (window->screen,
04734 space);
04735
04736 if (workspace)
04737 {
04738 if (window->on_all_workspaces)
04739 meta_window_unstick (window);
04740 meta_window_change_workspace (window, workspace);
04741 }
04742 else if (space == (int) 0xFFFFFFFF)
04743 {
04744 meta_window_stick (window);
04745 }
04746 else
04747 {
04748 meta_verbose ("No such workspace %d for screen\n", space);
04749 }
04750
04751 meta_verbose ("Window %s now on_all_workspaces = %d\n",
04752 window->desc, window->on_all_workspaces);
04753
04754 return TRUE;
04755 }
04756 else if (event->xclient.message_type ==
04757 display->atom__NET_WM_STATE)
04758 {
04759 gulong action;
04760 Atom first;
04761 Atom second;
04762
04763 action = event->xclient.data.l[0];
04764 first = event->xclient.data.l[1];
04765 second = event->xclient.data.l[2];
04766
04767 if (meta_is_verbose ())
04768 {
04769 char *str1;
04770 char *str2;
04771
04772 meta_error_trap_push_with_return (display);
04773 str1 = XGetAtomName (display->xdisplay, first);
04774 if (meta_error_trap_pop_with_return (display, TRUE) != Success)
04775 str1 = NULL;
04776
04777 meta_error_trap_push_with_return (display);
04778 str2 = XGetAtomName (display->xdisplay, second);
04779 if (meta_error_trap_pop_with_return (display, TRUE) != Success)
04780 str2 = NULL;
04781
04782 meta_verbose ("Request to change _NET_WM_STATE action %lu atom1: %s atom2: %s\n",
04783 action,
04784 str1 ? str1 : "(unknown)",
04785 str2 ? str2 : "(unknown)");
04786
04787 meta_XFree (str1);
04788 meta_XFree (str2);
04789 }
04790
04791 if (first == display->atom__NET_WM_STATE_SHADED ||
04792 second == display->atom__NET_WM_STATE_SHADED)
04793 {
04794 gboolean shade;
04795 guint32 timestamp;
04796
04797
04798
04799
04800
04801 timestamp = meta_display_get_current_time_roundtrip (window->display);
04802
04803 shade = (action == _NET_WM_STATE_ADD ||
04804 (action == _NET_WM_STATE_TOGGLE && !window->shaded));
04805 if (shade && window->has_shade_func)
04806 meta_window_shade (window, timestamp);
04807 else
04808 meta_window_unshade (window, timestamp);
04809 }
04810
04811 if (first == display->atom__NET_WM_STATE_FULLSCREEN ||
04812 second == display->atom__NET_WM_STATE_FULLSCREEN)
04813 {
04814 gboolean make_fullscreen;
04815
04816 make_fullscreen = (action == _NET_WM_STATE_ADD ||
04817 (action == _NET_WM_STATE_TOGGLE && !window->fullscreen));
04818 if (make_fullscreen && window->has_fullscreen_func)
04819 meta_window_make_fullscreen (window);
04820 else
04821 meta_window_unmake_fullscreen (window);
04822 }
04823
04824 if (first == display->atom__NET_WM_STATE_MAXIMIZED_HORZ ||
04825 second == display->atom__NET_WM_STATE_MAXIMIZED_HORZ)
04826 {
04827 gboolean max;
04828
04829 max = (action == _NET_WM_STATE_ADD ||
04830 (action == _NET_WM_STATE_TOGGLE &&
04831 !window->maximized_horizontally));
04832 if (max && window->has_maximize_func)
04833 {
04834 if (meta_prefs_get_raise_on_click ())
04835 meta_window_raise (window);
04836 meta_window_maximize (window, META_MAXIMIZE_HORIZONTAL);
04837 }
04838 else
04839 {
04840 if (meta_prefs_get_raise_on_click ())
04841 meta_window_raise (window);
04842 meta_window_unmaximize (window, META_MAXIMIZE_HORIZONTAL);
04843 }
04844 }
04845
04846 if (first == display->atom__NET_WM_STATE_MAXIMIZED_VERT ||
04847 second == display->atom__NET_WM_STATE_MAXIMIZED_VERT)
04848 {
04849 gboolean max;
04850
04851 max = (action == _NET_WM_STATE_ADD ||
04852 (action == _NET_WM_STATE_TOGGLE &&
04853 !window->maximized_vertically));
04854 if (max && window->has_maximize_func)
04855 {
04856 if (meta_prefs_get_raise_on_click ())
04857 meta_window_raise (window);
04858 meta_window_maximize (window, META_MAXIMIZE_VERTICAL);
04859 }
04860 else
04861 {
04862 if (meta_prefs_get_raise_on_click ())
04863 meta_window_raise (window);
04864 meta_window_unmaximize (window, META_MAXIMIZE_VERTICAL);
04865 }
04866 }
04867
04868 if (first == display->atom__NET_WM_STATE_MODAL ||
04869 second == display->atom__NET_WM_STATE_MODAL)
04870 {
04871 window->wm_state_modal =
04872 (action == _NET_WM_STATE_ADD) ||
04873 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal);
04874
04875 recalc_window_type (window);
04876 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
04877 }
04878
04879 if (first == display->atom__NET_WM_STATE_SKIP_PAGER ||
04880 second == display->atom__NET_WM_STATE_SKIP_PAGER)
04881 {
04882 window->wm_state_skip_pager =
04883 (action == _NET_WM_STATE_ADD) ||
04884 (action == _NET_WM_STATE_TOGGLE && !window->skip_pager);
04885
04886 recalc_window_features (window);
04887 set_net_wm_state (window);
04888 }
04889
04890 if (first == display->atom__NET_WM_STATE_SKIP_TASKBAR ||
04891 second == display->atom__NET_WM_STATE_SKIP_TASKBAR)
04892 {
04893 window->wm_state_skip_taskbar =
04894 (action == _NET_WM_STATE_ADD) ||
04895 (action == _NET_WM_STATE_TOGGLE && !window->skip_taskbar);
04896
04897 recalc_window_features (window);
04898 set_net_wm_state (window);
04899 }
04900
04901 if (first == display->atom__NET_WM_STATE_ABOVE ||
04902 second == display->atom__NET_WM_STATE_ABOVE)
04903 {
04904 window->wm_state_above =
04905 (action == _NET_WM_STATE_ADD) ||
04906 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_above);
04907
04908 meta_window_update_layer (window);
04909 set_net_wm_state (window);
04910 }
04911
04912 if (first == display->atom__NET_WM_STATE_BELOW ||
04913 second == display->atom__NET_WM_STATE_BELOW)
04914 {
04915 window->wm_state_below =
04916 (action == _NET_WM_STATE_ADD) ||
04917 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_below);
04918
04919 meta_window_update_layer (window);
04920 set_net_wm_state (window);
04921 }
04922
04923 if (first == display->atom__NET_WM_STATE_DEMANDS_ATTENTION ||
04924 second == display->atom__NET_WM_STATE_DEMANDS_ATTENTION)
04925 {
04926 if ((action == _NET_WM_STATE_ADD) ||
04927 (action == _NET_WM_STATE_TOGGLE && !window->wm_state_demands_attention))
04928 meta_window_set_demands_attention(window);
04929 else
04930 meta_window_unset_demands_attention(window);
04931 }
04932
04933 return TRUE;
04934 }
04935 else if (event->xclient.message_type ==
04936 display->atom_WM_CHANGE_STATE)
04937 {
04938 meta_verbose ("WM_CHANGE_STATE client message, state: %ld\n",
04939 event->xclient.data.l[0]);
04940 if (event->xclient.data.l[0] == IconicState &&
04941 window->has_minimize_func)
04942 meta_window_minimize (window);
04943
04944 return TRUE;
04945 }
04946 else if (event->xclient.message_type ==
04947 display->atom__NET_WM_MOVERESIZE)
04948 {
04949 int x_root;
04950 int y_root;
04951 int action;
04952 MetaGrabOp op;
04953 int button;
04954 guint32 timestamp;
04955
04956
04957
04958
04959
04960
04961 gboolean const frame_action = TRUE;
04962
04963 x_root = event->xclient.data.l[0];
04964 y_root = event->xclient.data.l[1];
04965 action = event->xclient.data.l[2];
04966 button = event->xclient.data.l[3];
04967
04968
04969 timestamp = meta_display_get_current_time_roundtrip (display);
04970 meta_warning ("Received a _NET_WM_MOVERESIZE message for %s; these "
04971 "messages lack timestamps and therefore suck.\n",
04972 window->desc);
04973 meta_topic (META_DEBUG_WINDOW_OPS,
04974 "Received _NET_WM_MOVERESIZE message on %s, %d,%d action = %d, button %d\n",
04975 window->desc,
04976 x_root, y_root, action, button);
04977
04978 op = META_GRAB_OP_NONE;
04979 switch (action)
04980 {
04981 case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
04982 op = META_GRAB_OP_RESIZING_NW;
04983 break;
04984 case _NET_WM_MOVERESIZE_SIZE_TOP:
04985 op = META_GRAB_OP_RESIZING_N;
04986 break;
04987 case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
04988 op = META_GRAB_OP_RESIZING_NE;
04989 break;
04990 case _NET_WM_MOVERESIZE_SIZE_RIGHT:
04991 op = META_GRAB_OP_RESIZING_E;
04992 break;
04993 case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
04994 op = META_GRAB_OP_RESIZING_SE;
04995 break;
04996 case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
04997 op = META_GRAB_OP_RESIZING_S;
04998 break;
04999 case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
05000 op = META_GRAB_OP_RESIZING_SW;
05001 break;
05002 case _NET_WM_MOVERESIZE_SIZE_LEFT:
05003 op = META_GRAB_OP_RESIZING_W;
05004 break;
05005 case _NET_WM_MOVERESIZE_MOVE:
05006 op = META_GRAB_OP_MOVING;
05007 break;
05008 case _NET_WM_MOVERESIZE_SIZE_KEYBOARD:
05009 op = META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN;
05010 break;
05011 case _NET_WM_MOVERESIZE_MOVE_KEYBOARD:
05012 op = META_GRAB_OP_KEYBOARD_MOVING;
05013 break;
05014 default:
05015 break;
05016 }
05017
05018 if (op != META_GRAB_OP_NONE &&
05019 ((window->has_move_func && op == META_GRAB_OP_KEYBOARD_MOVING) ||
05020 (window->has_resize_func && op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN)))
05021 {
05022 meta_window_begin_grab_op (window, op, frame_action, timestamp);
05023 }
05024 else if (op != META_GRAB_OP_NONE &&
05025 ((window->has_move_func && op == META_GRAB_OP_MOVING) ||
05026 (window->has_resize_func &&
05027 (op != META_GRAB_OP_MOVING &&
05028 op != META_GRAB_OP_KEYBOARD_MOVING))))
05029 {
05030
05031
05032
05033 if (button == 0)
05034 {
05035 int x, y, query_root_x, query_root_y;
05036 Window root, child;
05037 guint mask;
05038
05039
05040
05041
05042 mask = 0;
05043 meta_error_trap_push (window->display);
05044 XQueryPointer (window->display->xdisplay,
05045 window->xwindow,
05046 &root, &child,
05047 &query_root_x, &query_root_y,
05048 &x, &y,
05049 &mask);
05050 meta_error_trap_pop (window->display, TRUE);
05051
05052 if (mask & Button1Mask)
05053 button = 1;
05054 else if (mask & Button2Mask)
05055 button = 2;
05056 else if (mask & Button3Mask)
05057 button = 3;
05058 else
05059 button = 0;
05060 }
05061
05062 if (button != 0)
05063 {
05064 meta_topic (META_DEBUG_WINDOW_OPS,
05065 "Beginning move/resize with button = %d\n", button);
05066 meta_display_begin_grab_op (window->display,
05067 window->screen,
05068 window,
05069 op,
05070 FALSE,
05071 frame_action,
05072 button, 0,
05073 timestamp,
05074 x_root,
05075 y_root);
05076 }
05077 }
05078
05079 return TRUE;
05080 }
05081 else if (event->xclient.message_type ==
05082 display->atom__NET_MOVERESIZE_WINDOW)
05083 {
05084 int gravity, source;
05085 guint value_mask;
05086
05087 gravity = (event->xclient.data.l[0] & 0xff);
05088 value_mask = (event->xclient.data.l[0] & 0xf00) >> 8;
05089 source = (event->xclient.data.l[0] & 0xf000) >> 12;
05090
05091 if (gravity == 0)
05092 gravity = window->size_hints.win_gravity;
05093
05094 meta_window_move_resize_request(window,
05095 value_mask,
05096 gravity,
05097 event->xclient.data.l[1],
05098 event->xclient.data.l[2],
05099 event->xclient.data.l[3],
05100 event->xclient.data.l[4]);
05101 }
05102 else if (event->xclient.message_type ==
05103 display->atom__NET_ACTIVE_WINDOW)
05104 {
05105 MetaClientType source_indication;
05106 guint32 timestamp;
05107
05108 meta_verbose ("_NET_ACTIVE_WINDOW request for window '%s', activating\n",
05109 window->desc);
05110
05111 source_indication = event->xclient.data.l[0];
05112 timestamp = event->xclient.data.l[1];
05113
05114 if (source_indication > META_CLIENT_TYPE_MAX_RECOGNIZED)
05115 source_indication = META_CLIENT_TYPE_UNKNOWN;
05116
05117 if (timestamp == 0)
05118 {
05119
05120 meta_warning ("Buggy client sent a _NET_ACTIVE_WINDOW message with a "
05121 "timestamp of 0 for %s\n",
05122 window->desc);
05123 timestamp = meta_display_get_current_time (display);
05124 }
05125
05126 window_activate (window, timestamp, source_indication, NULL);
05127 return TRUE;
05128 }
05129
05130 return FALSE;
05131 }
05132
05133 gboolean
05134 meta_window_notify_focus (MetaWindow *window,
05135 XEvent *event)
05136 {
05137
05138
05139
05140
05141
05142
05143
05144
05145
05146
05147
05148
05149
05150
05151
05152
05153
05154
05155 meta_topic (META_DEBUG_FOCUS,
05156 "Focus %s event received on %s 0x%lx (%s) "
05157 "mode %s detail %s\n",
05158 event->type == FocusIn ? "in" :
05159 event->type == FocusOut ? "out" :
05160 event->type == UnmapNotify ? "unmap" :
05161 "???",
05162 window->desc, event->xany.window,
05163 event->xany.window == window->xwindow ?
05164 "client window" :
05165 (window->frame && event->xany.window == window->frame->xwindow) ?
05166 "frame window" :
05167 "unknown window",
05168 event->type != UnmapNotify ?
05169 meta_event_mode_to_string (event->xfocus.mode) : "n/a",
05170 event->type != UnmapNotify ?
05171 meta_event_detail_to_string (event->xfocus.detail) : "n/a");
05172
05173
05174
05175
05176
05177
05178
05179
05180
05181
05182
05183
05184
05185
05186
05187
05188
05189
05190
05191
05192 if ((event->type == FocusIn ||
05193 event->type == FocusOut) &&
05194 (event->xfocus.mode == NotifyGrab ||
05195 event->xfocus.mode == NotifyUngrab ||
05196
05197 event->xfocus.detail > NotifyNonlinearVirtual))
05198 {
05199 meta_topic (META_DEBUG_FOCUS,
05200 "Ignoring focus event generated by a grab or other weirdness\n");
05201 return TRUE;
05202 }
05203
05204 if (event->type == FocusIn)
05205 {
05206 if (window != window->display->focus_window)
05207 {
05208 meta_topic (META_DEBUG_FOCUS,
05209 "* Focus --> %s\n", window->desc);
05210 window->display->focus_window = window;
05211 window->has_focus = TRUE;
05212 meta_compositor_set_active_window (window->display->compositor,
05213 window->screen, window);
05214
05215
05216
05217
05218
05219
05220
05221
05222
05223 if (window->screen->active_workspace &&
05224 meta_window_located_on_workspace (window,
05225 window->screen->active_workspace))
05226 {
05227 GList* link;
05228 link = g_list_find (window->screen->active_workspace->mru_list,
05229 window);
05230 g_assert (link);
05231
05232 window->screen->active_workspace->mru_list =
05233 g_list_remove_link (window->screen->active_workspace->mru_list,
05234 link);
05235 g_list_free (link);
05236
05237 window->screen->active_workspace->mru_list =
05238 g_list_prepend (window->screen->active_workspace->mru_list,
05239 window);
05240 }
05241
05242 if (window->frame)
05243 meta_frame_queue_draw (window->frame);
05244
05245 meta_error_trap_push (window->display);
05246 XInstallColormap (window->display->xdisplay,
05247 window->colormap);
05248 meta_error_trap_pop (window->display, FALSE);
05249
05250
05251 meta_window_update_layer (window);
05252
05253
05254
05255
05256
05257
05258
05259
05260
05261
05262
05263
05264
05265
05266 if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK ||
05267 !meta_prefs_get_raise_on_click())
05268 meta_display_ungrab_focus_window_button (window->display, window);
05269 }
05270 }
05271 else if (event->type == FocusOut ||
05272 event->type == UnmapNotify)
05273 {
05274 if (event->type == FocusOut &&
05275 event->xfocus.detail == NotifyInferior)
05276 {
05277
05278 meta_topic (META_DEBUG_FOCUS,
05279 "Ignoring focus out on %s with NotifyInferior\n",
05280 window->desc);
05281 return TRUE;
05282 }
05283
05284 if (window == window->display->focus_window)
05285 {
05286 meta_topic (META_DEBUG_FOCUS,
05287 "%s is now the previous focus window due to being focused out or unmapped\n",
05288 window->desc);
05289
05290 meta_topic (META_DEBUG_FOCUS,
05291 "* Focus --> NULL (was %s)\n", window->desc);
05292
05293 window->display->focus_window = NULL;
05294 window->has_focus = FALSE;
05295 if (window->frame)
05296 meta_frame_queue_draw (window->frame);
05297
05298 meta_compositor_set_active_window (window->display->compositor,
05299 window->screen, NULL);
05300
05301 meta_error_trap_push (window->display);
05302 XUninstallColormap (window->display->xdisplay,
05303 window->colormap);
05304 meta_error_trap_pop (window->display, FALSE);
05305
05306
05307 meta_window_update_layer (window);
05308
05309
05310 if (meta_prefs_get_focus_mode () == META_FOCUS_MODE_CLICK ||
05311 !meta_prefs_get_raise_on_click ())
05312 meta_display_grab_focus_window_button (window->display, window);
05313 }
05314 }
05315
05316
05317 meta_display_update_active_window_hint (window->display);
05318
05319 return FALSE;
05320 }
05321
05322 static gboolean
05323 process_property_notify (MetaWindow *window,
05324 XPropertyEvent *event)
05325 {
05326
05327
05328
05329 if (event->atom == window->display->atom__NET_WM_STATE)
05330 {
05331 meta_verbose ("Property notify on %s for _NET_WM_STATE, ignoring (we should be the one who set the property in the first place)\n",
05332 window->desc);
05333 return TRUE;
05334 }
05335
05336
05337
05338
05339
05340
05341
05342 if (event->atom == XA_WM_NAME)
05343 {
05344 meta_verbose ("Property notify on %s for WM_NAME\n", window->desc);
05345
05346
05347 if (!window->using_net_wm_name)
05348 meta_window_reload_property (window, XA_WM_NAME);
05349 }
05350 else if (event->atom == window->display->atom__NET_WM_NAME)
05351 {
05352 meta_verbose ("Property notify on %s for NET_WM_NAME\n", window->desc);
05353 meta_window_reload_property (window, window->display->atom__NET_WM_NAME);
05354
05355
05356 if (!window->using_net_wm_name)
05357 meta_window_reload_property (window, XA_WM_NAME);
05358 }
05359 else if (event->atom == XA_WM_ICON_NAME)
05360 {
05361 meta_verbose ("Property notify on %s for WM_ICON_NAME\n", window->desc);
05362
05363
05364 if (!window->using_net_wm_icon_name)
05365 meta_window_reload_property (window, XA_WM_ICON_NAME);
05366 }
05367 else if (event->atom == window->display->atom__NET_WM_ICON_NAME)
05368 {
05369 meta_verbose ("Property notify on %s for NET_WM_ICON_NAME\n", window->desc);
05370 meta_window_reload_property (window, window->display->atom__NET_WM_ICON_NAME);
05371
05372
05373 if (!window->using_net_wm_icon_name)
05374 meta_window_reload_property (window, XA_WM_ICON_NAME);
05375 }
05376 else if (event->atom == XA_WM_NORMAL_HINTS)
05377 {
05378 meta_verbose ("Property notify on %s for WM_NORMAL_HINTS\n", window->desc);
05379
05380 meta_window_reload_property (window, XA_WM_NORMAL_HINTS);
05381
05382
05383 meta_window_queue(window, META_QUEUE_MOVE_RESIZE);
05384 }
05385 else if (event->atom == window->display->atom_WM_PROTOCOLS)
05386 {
05387 meta_verbose ("Property notify on %s for WM_PROTOCOLS\n", window->desc);
05388
05389 meta_window_reload_property (window, window->display->atom_WM_PROTOCOLS);
05390 }
05391 else if (event->atom == XA_WM_HINTS)
05392 {
05393 meta_verbose ("Property notify on %s for WM_HINTS\n", window->desc);
05394
05395 meta_window_reload_property (window, XA_WM_HINTS);
05396 }
05397 else if (event->atom == window->display->atom__MOTIF_WM_HINTS)
05398 {
05399 meta_verbose ("Property notify on %s for MOTIF_WM_HINTS\n", window->desc);
05400
05401 meta_window_reload_property (window,
05402 window->display->atom__MOTIF_WM_HINTS);
05403 }
05404 else if (event->atom == XA_WM_CLASS)
05405 {
05406 meta_verbose ("Property notify on %s for WM_CLASS\n", window->desc);
05407
05408 meta_window_reload_property (window, XA_WM_CLASS);
05409 }
05410 else if (event->atom == XA_WM_TRANSIENT_FOR)
05411 {
05412 meta_verbose ("Property notify on %s for WM_TRANSIENT_FOR\n", window->desc);
05413
05414 meta_window_reload_property (window, XA_WM_TRANSIENT_FOR);
05415 }
05416 else if (event->atom ==
05417 window->display->atom_WM_WINDOW_ROLE)
05418 {
05419 meta_verbose ("Property notify on %s for WM_WINDOW_ROLE\n", window->desc);
05420
05421 update_role (window);
05422 }
05423 else if (event->atom ==
05424 window->display->atom_WM_CLIENT_LEADER ||
05425 event->atom ==
05426 window->display->atom_SM_CLIENT_ID)
05427 {
05428 meta_warning ("Broken client! Window %s changed client leader window or SM client ID\n", window->desc);
05429 }
05430 else if (event->atom ==
05431 window->display->atom__NET_WM_WINDOW_TYPE)
05432 {
05433 meta_verbose ("Property notify on %s for NET_WM_WINDOW_TYPE\n", window->desc);
05434 update_net_wm_type (window);
05435 }
05436 else if (event->atom == window->display->atom__NET_WM_ICON)
05437 {
05438 meta_verbose ("Property notify on %s for NET_WM_ICON\n", window->desc);
05439 meta_icon_cache_property_changed (&window->icon_cache,
05440 window->display,
05441 event->atom);
05442 meta_window_queue(window, META_QUEUE_UPDATE_ICON);
05443 }
05444 else if (event->atom == window->display->atom__KWM_WIN_ICON)
05445 {
05446 meta_verbose ("Property notify on %s for KWM_WIN_ICON\n", window->desc);
05447
05448 meta_icon_cache_property_changed (&window->icon_cache,
05449 window->display,
05450 event->atom);
05451 meta_window_queue(window, META_QUEUE_UPDATE_ICON);
05452 }
05453 else if ((event->atom == window->display->atom__NET_WM_STRUT) ||
05454 (event->atom == window->display->atom__NET_WM_STRUT_PARTIAL))
05455 {
05456 meta_verbose ("Property notify on %s for _NET_WM_STRUT\n", window->desc);
05457 meta_window_update_struts (window);
05458 }
05459 else if (event->atom == window->display->atom__NET_STARTUP_ID)
05460 {
05461 meta_verbose ("Property notify on %s for _NET_STARTUP_ID\n", window->desc);
05462
05463 meta_window_reload_property (window,
05464 window->display->atom__NET_STARTUP_ID);
05465 }
05466 else if (event->atom == window->display->atom__NET_WM_SYNC_REQUEST_COUNTER)
05467 {
05468 meta_verbose ("Property notify on %s for _NET_WM_SYNC_REQUEST_COUNTER\n", window->desc);
05469
05470 meta_window_reload_property (window,
05471 window->display->atom__NET_WM_SYNC_REQUEST_COUNTER);
05472 }
05473 else if (event->atom == window->display->atom__NET_WM_USER_TIME)
05474 {
05475 Window xid;
05476 Atom atom__NET_WM_USER_TIME;
05477
05478 meta_verbose ("Property notify on %s for _NET_WM_USER_TIME\n", window->desc);
05479
05480 atom__NET_WM_USER_TIME = window->display->atom__NET_WM_USER_TIME;
05481 if (window->user_time_window)
05482 xid = window->user_time_window;
05483 else
05484 xid = window->xwindow;
05485 meta_window_reload_property_from_xwindow (window,
05486 xid,
05487 atom__NET_WM_USER_TIME);
05488 }
05489
05490 return TRUE;
05491 }
05492
05493 static void
05494 send_configure_notify (MetaWindow *window)
05495 {
05496 XEvent event;
05497
05498
05499
05500 event.type = ConfigureNotify;
05501 event.xconfigure.display = window->display->xdisplay;
05502 event.xconfigure.event = window->xwindow;
05503 event.xconfigure.window = window->xwindow;
05504 event.xconfigure.x = window->rect.x - window->border_width;
05505 event.xconfigure.y = window->rect.y - window->border_width;
05506 if (window->frame)
05507 {
05508 if (window->withdrawn)
05509 {
05510
05511
05512
05513
05514
05515 }
05516 else
05517 {
05518
05519 event.xconfigure.x += window->frame->rect.x;
05520 event.xconfigure.y += window->frame->rect.y;
05521 }
05522 }
05523 event.xconfigure.width = window->rect.width;
05524 event.xconfigure.height = window->rect.height;
05525 event.xconfigure.border_width = window->border_width;
05526 event.xconfigure.above = None;
05527 event.xconfigure.override_redirect = False;
05528
05529 meta_topic (META_DEBUG_GEOMETRY,
05530 "Sending synthetic configure notify to %s with x: %d y: %d w: %d h: %d\n",
05531 window->desc,
05532 event.xconfigure.x, event.xconfigure.y,
05533 event.xconfigure.width, event.xconfigure.height);
05534
05535 meta_error_trap_push (window->display);
05536 XSendEvent (window->display->xdisplay,
05537 window->xwindow,
05538 False, StructureNotifyMask, &event);
05539 meta_error_trap_pop (window->display, FALSE);
05540 }
05541
05542 gboolean
05543 meta_window_get_icon_geometry (MetaWindow *window,
05544 MetaRectangle *rect)
05545 {
05546 gulong *geometry = NULL;
05547 int nitems;
05548
05549 if (meta_prop_get_cardinal_list (window->display,
05550 window->xwindow,
05551 window->display->atom__NET_WM_ICON_GEOMETRY,
05552 &geometry, &nitems))
05553 {
05554 if (nitems != 4)
05555 {
05556 meta_verbose ("_NET_WM_ICON_GEOMETRY on %s has %d values instead of 4\n",
05557 window->desc, nitems);
05558 meta_XFree (geometry);
05559 return FALSE;
05560 }
05561
05562 if (rect)
05563 {
05564 rect->x = geometry[0];
05565 rect->y = geometry[1];
05566 rect->width = geometry[2];
05567 rect->height = geometry[3];
05568 }
05569
05570 meta_XFree (geometry);
05571
05572 return TRUE;
05573 }
05574
05575 return FALSE;
05576 }
05577
05578 static Window
05579 read_client_leader (MetaDisplay *display,
05580 Window xwindow)
05581 {
05582 Window retval = None;
05583
05584 meta_prop_get_window (display, xwindow,
05585 display->atom_WM_CLIENT_LEADER,
05586 &retval);
05587
05588 return retval;
05589 }
05590
05591 typedef struct
05592 {
05593 Window leader;
05594 } ClientLeaderData;
05595
05596 static gboolean
05597 find_client_leader_func (MetaWindow *ancestor,
05598 void *data)
05599 {
05600 ClientLeaderData *d;
05601
05602 d = data;
05603
05604 d->leader = read_client_leader (ancestor->display,
05605 ancestor->xwindow);
05606
05607
05608 return d->leader == None;
05609 }
05610
05611 static void
05612 update_sm_hints (MetaWindow *window)
05613 {
05614 Window leader;
05615
05616 window->xclient_leader = None;
05617 window->sm_client_id = NULL;
05618
05619
05620
05621
05622
05623 leader = read_client_leader (window->display, window->xwindow);
05624 if (leader == None)
05625 {
05626 ClientLeaderData d;
05627 d.leader = None;
05628 meta_window_foreach_ancestor (window, find_client_leader_func,
05629 &d);
05630 leader = d.leader;
05631 }
05632
05633 if (leader != None)
05634 {
05635 char *str;
05636
05637 window->xclient_leader = leader;
05638
05639 if (meta_prop_get_latin1_string (window->display, leader,
05640 window->display->atom_SM_CLIENT_ID,
05641 &str))
05642 {
05643 window->sm_client_id = g_strdup (str);
05644 meta_XFree (str);
05645 }
05646 }
05647 else
05648 {
05649 meta_verbose ("Didn't find a client leader for %s\n", window->desc);
05650
05651 if (!meta_prefs_get_disable_workarounds ())
05652 {
05653
05654
05655
05656 char *str;
05657
05658 str = NULL;
05659 if (meta_prop_get_latin1_string (window->display, window->xwindow,
05660 window->display->atom_SM_CLIENT_ID,
05661 &str))
05662 {
05663 if (window->sm_client_id == NULL)
05664 meta_warning (_("Window %s sets SM_CLIENT_ID on itself, instead of on the WM_CLIENT_LEADER window as specified in the ICCCM.\n"),
05665 window->desc);
05666
05667 window->sm_client_id = g_strdup (str);
05668 meta_XFree (str);
05669 }
05670 }
05671 }
05672
05673 meta_verbose ("Window %s client leader: 0x%lx SM_CLIENT_ID: '%s'\n",
05674 window->desc, window->xclient_leader,
05675 window->sm_client_id ? window->sm_client_id : "none");
05676 }
05677
05678 static void
05679 update_role (MetaWindow *window)
05680 {
05681 char *str;
05682
05683 if (window->role)
05684 g_free (window->role);
05685 window->role = NULL;
05686
05687 if (meta_prop_get_latin1_string (window->display, window->xwindow,
05688 window->display->atom_WM_WINDOW_ROLE,
05689 &str))
05690 {
05691 window->role = g_strdup (str);
05692 meta_XFree (str);
05693 }
05694
05695 meta_verbose ("Updated role of %s to '%s'\n",
05696 window->desc, window->role ? window->role : "null");
05697 }
05698
05699 static void
05700 update_net_wm_type (MetaWindow *window)
05701 {
05702 int n_atoms;
05703 Atom *atoms;
05704 int i;
05705
05706 window->type_atom = None;
05707 n_atoms = 0;
05708 atoms = NULL;
05709
05710 meta_prop_get_atom_list (window->display, window->xwindow,
05711 window->display->atom__NET_WM_WINDOW_TYPE,
05712 &atoms, &n_atoms);
05713
05714 i = 0;
05715 while (i < n_atoms)
05716 {
05717
05718
05719
05720 if (atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP ||
05721 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DOCK ||
05722 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR ||
05723 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_MENU ||
05724 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG ||
05725 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL ||
05726 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY ||
05727 atoms[i] == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
05728 {
05729 window->type_atom = atoms[i];
05730 break;
05731 }
05732
05733 ++i;
05734 }
05735
05736 meta_XFree (atoms);
05737
05738 if (meta_is_verbose ())
05739 {
05740 char *str;
05741
05742 str = NULL;
05743 if (window->type_atom != None)
05744 {
05745 meta_error_trap_push (window->display);
05746 str = XGetAtomName (window->display->xdisplay, window->type_atom);
05747 meta_error_trap_pop (window->display, TRUE);
05748 }
05749
05750 meta_verbose ("Window %s type atom %s\n", window->desc,
05751 str ? str : "(none)");
05752
05753 if (str)
05754 meta_XFree (str);
05755 }
05756
05757 recalc_window_type (window);
05758 }
05759
05760 static void
05761 redraw_icon (MetaWindow *window)
05762 {
05763
05764
05765
05766 if (window->frame && (window->mapped || window->frame->mapped))
05767 meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow);
05768 }
05769
05770 void
05771 meta_window_update_icon_now (MetaWindow *window)
05772 {
05773 GdkPixbuf *icon;
05774 GdkPixbuf *mini_icon;
05775
05776 icon = NULL;
05777 mini_icon = NULL;
05778
05779 if (meta_read_icons (window->screen,
05780 window->xwindow,
05781 &window->icon_cache,
05782 window->wm_hints_pixmap,
05783 window->wm_hints_mask,
05784 &icon,
05785 META_ICON_WIDTH, META_ICON_HEIGHT,
05786 &mini_icon,
05787 META_MINI_ICON_WIDTH,
05788 META_MINI_ICON_HEIGHT))
05789 {
05790 if (window->icon)
05791 g_object_unref (G_OBJECT (window->icon));
05792
05793 if (window->mini_icon)
05794 g_object_unref (G_OBJECT (window->mini_icon));
05795
05796 window->icon = icon;
05797 window->mini_icon = mini_icon;
05798
05799 redraw_icon (window);
05800 }
05801
05802 g_assert (window->icon);
05803 g_assert (window->mini_icon);
05804 }
05805
05806 static gboolean
05807 idle_update_icon (gpointer data)
05808 {
05809 GSList *tmp;
05810 GSList *copy;
05811 guint queue_index = GPOINTER_TO_INT (data);
05812
05813 meta_topic (META_DEBUG_GEOMETRY, "Clearing the update_icon queue\n");
05814
05815
05816
05817
05818
05819 copy = g_slist_copy (queue_pending[queue_index]);
05820 g_slist_free (queue_pending[queue_index]);
05821 queue_pending[queue_index] = NULL;
05822 queue_idle[queue_index] = 0;
05823
05824 destroying_windows_disallowed += 1;
05825
05826 tmp = copy;
05827 while (tmp != NULL)
05828 {
05829 MetaWindow *window;
05830
05831 window = tmp->data;
05832
05833 meta_window_update_icon_now (window);
05834 window->is_in_queues &= ~META_QUEUE_UPDATE_ICON;
05835
05836 tmp = tmp->next;
05837 }
05838
05839 g_slist_free (copy);
05840
05841 destroying_windows_disallowed -= 1;
05842
05843 return FALSE;
05844 }
05845
05846 GList*
05847 meta_window_get_workspaces (MetaWindow *window)
05848 {
05849 if (window->on_all_workspaces)
05850 return window->screen->workspaces;
05851 else
05852 return window->workspace->list_containing_self;
05853 }
05854
05855 static void
05856 invalidate_work_areas (MetaWindow *window)
05857 {
05858 GList *tmp;
05859
05860 tmp = meta_window_get_workspaces (window);
05861
05862 while (tmp != NULL)
05863 {
05864 meta_workspace_invalidate_work_area (tmp->data);
05865 tmp = tmp->next;
05866 }
05867 }
05868
05869 void
05870 meta_window_update_struts (MetaWindow *window)
05871 {
05872 GSList *old_struts;
05873 GSList *new_struts;
05874 GSList *old_iter, *new_iter;
05875 gulong *struts = NULL;
05876 int nitems;
05877 gboolean changed;
05878
05879 meta_verbose ("Updating struts for %s\n", window->desc);
05880
05881 old_struts = window->struts;
05882 new_struts = NULL;
05883
05884 if (meta_prop_get_cardinal_list (window->display,
05885 window->xwindow,
05886 window->display->atom__NET_WM_STRUT_PARTIAL,
05887 &struts, &nitems))
05888 {
05889 if (nitems != 12)
05890 meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead "
05891 "of 12\n",
05892 window->desc, nitems);
05893 else
05894 {
05895
05896 int i;
05897 for (i=0; i<4; i++)
05898 {
05899 MetaStrut *temp;
05900 int thickness, strut_begin, strut_end;
05901
05902 thickness = struts[i];
05903 if (thickness == 0)
05904 continue;
05905 strut_begin = struts[4+(i*2)];
05906 strut_end = struts[4+(i*2)+1];
05907
05908 temp = g_new (MetaStrut, 1);
05909 temp->side = 1 << i;
05910 temp->rect = window->screen->rect;
05911 switch (temp->side)
05912 {
05913 case META_SIDE_RIGHT:
05914 temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
05915
05916 case META_SIDE_LEFT:
05917 temp->rect.width = thickness;
05918 temp->rect.y = strut_begin;
05919 temp->rect.height = strut_end - strut_begin + 1;
05920 break;
05921 case META_SIDE_BOTTOM:
05922 temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
05923
05924 case META_SIDE_TOP:
05925 temp->rect.height = thickness;
05926 temp->rect.x = strut_begin;
05927 temp->rect.width = strut_end - strut_begin + 1;
05928 break;
05929 default:
05930 g_assert_not_reached ();
05931 }
05932
05933 new_struts = g_slist_prepend (new_struts, temp);
05934 }
05935
05936 meta_verbose ("_NET_WM_STRUT_PARTIAL struts %lu %lu %lu %lu for "
05937 "window %s\n",
05938 struts[0], struts[1], struts[2], struts[3],
05939 window->desc);
05940 }
05941 meta_XFree (struts);
05942 }
05943 else
05944 {
05945 meta_verbose ("No _NET_WM_STRUT property for %s\n",
05946 window->desc);
05947 }
05948
05949 if (!new_struts &&
05950 meta_prop_get_cardinal_list (window->display,
05951 window->xwindow,
05952 window->display->atom__NET_WM_STRUT,
05953 &struts, &nitems))
05954 {
05955 if (nitems != 4)
05956 meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n",
05957 window->desc, nitems);
05958 else
05959 {
05960
05961 int i;
05962 for (i=0; i<4; i++)
05963 {
05964 MetaStrut *temp;
05965 int thickness;
05966
05967 thickness = struts[i];
05968 if (thickness == 0)
05969 continue;
05970
05971 temp = g_new (MetaStrut, 1);
05972 temp->side = 1 << i;
05973 temp->rect = window->screen->rect;
05974 switch (temp->side)
05975 {
05976 case META_SIDE_RIGHT:
05977 temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
05978
05979 case META_SIDE_LEFT:
05980 temp->rect.width = thickness;
05981 break;
05982 case META_SIDE_BOTTOM:
05983 temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
05984
05985 case META_SIDE_TOP:
05986 temp->rect.height = thickness;
05987 break;
05988 default:
05989 g_assert_not_reached ();
05990 }
05991
05992 new_struts = g_slist_prepend (new_struts, temp);
05993 }
05994
05995 meta_verbose ("_NET_WM_STRUT struts %lu %lu %lu %lu for window %s\n",
05996 struts[0], struts[1], struts[2], struts[3],
05997 window->desc);
05998 }
05999 meta_XFree (struts);
06000 }
06001 else if (!new_struts)
06002 {
06003 meta_verbose ("No _NET_WM_STRUT property for %s\n",
06004 window->desc);
06005 }
06006
06007
06008 old_iter = old_struts;
06009 new_iter = new_struts;
06010 while (old_iter && new_iter)
06011 {
06012 MetaStrut *old_strut = (MetaStrut*) old_iter->data;
06013 MetaStrut *new_strut = (MetaStrut*) new_iter->data;
06014
06015 if (old_strut->side != new_strut->side ||
06016 !meta_rectangle_equal (&old_strut->rect, &new_strut->rect))
06017 break;
06018
06019 old_iter = old_iter->next;
06020 new_iter = new_iter->next;
06021 }
06022 changed = (old_iter != NULL || new_iter != NULL);
06023
06024
06025 meta_free_gslist_and_elements (old_struts);
06026 window->struts = new_struts;
06027 if (changed)
06028 {
06029 meta_topic (META_DEBUG_WORKAREA,
06030 "Invalidating work areas of window %s due to struts update\n",
06031 window->desc);
06032 invalidate_work_areas (window);
06033 }
06034 else
06035 {
06036 meta_topic (META_DEBUG_WORKAREA,
06037 "Struts on %s were unchanged\n", window->desc);
06038 }
06039 }
06040
06041 void
06042 meta_window_recalc_window_type (MetaWindow *window)
06043 {
06044 recalc_window_type (window);
06045 }
06046
06047 static void
06048 recalc_window_type (MetaWindow *window)
06049 {
06050 MetaWindowType old_type;
06051
06052 old_type = window->type;
06053
06054 if (window->type_atom != None)
06055 {
06056 if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DESKTOP)
06057 window->type = META_WINDOW_DESKTOP;
06058 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DOCK)
06059 window->type = META_WINDOW_DOCK;
06060 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_TOOLBAR)
06061 window->type = META_WINDOW_TOOLBAR;
06062 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_MENU)
06063 window->type = META_WINDOW_MENU;
06064 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_DIALOG)
06065 window->type = META_WINDOW_DIALOG;
06066 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_NORMAL)
06067 window->type = META_WINDOW_NORMAL;
06068 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_UTILITY)
06069 window->type = META_WINDOW_UTILITY;
06070 else if (window->type_atom == window->display->atom__NET_WM_WINDOW_TYPE_SPLASH)
06071 window->type = META_WINDOW_SPLASHSCREEN;
06072 else
06073 meta_bug ("Set a type atom for %s that wasn't handled in recalc_window_type\n",
06074 window->desc);
06075 }
06076 else if (window->xtransient_for != None)
06077 {
06078 window->type = META_WINDOW_DIALOG;
06079 }
06080 else
06081 {
06082 window->type = META_WINDOW_NORMAL;
06083 }
06084
06085 if (window->type == META_WINDOW_DIALOG &&
06086 window->wm_state_modal)
06087 window->type = META_WINDOW_MODAL_DIALOG;
06088
06089 meta_verbose ("Calculated type %u for %s, old type %u\n",
06090 window->type, window->desc, old_type);
06091
06092 if (old_type != window->type)
06093 {
06094 recalc_window_features (window);
06095
06096 set_net_wm_state (window);
06097
06098
06099 if (window->decorated)
06100 meta_window_ensure_frame (window);
06101 else
06102 meta_window_destroy_frame (window);
06103
06104
06105 meta_window_update_layer (window);
06106
06107 meta_window_grab_keys (window);
06108 }
06109 }
06110
06111 static void
06112 set_allowed_actions_hint (MetaWindow *window)
06113 {
06114 #define MAX_N_ACTIONS 12
06115 unsigned long data[MAX_N_ACTIONS];
06116 int i;
06117
06118 i = 0;
06119 if (window->has_move_func)
06120 {
06121 data[i] = window->display->atom__NET_WM_ACTION_MOVE;
06122 ++i;
06123 }
06124 if (window->has_resize_func)
06125 {
06126 data[i] = window->display->atom__NET_WM_ACTION_RESIZE;
06127 ++i;
06128 }
06129 if (window->has_fullscreen_func)
06130 {
06131 data[i] = window->display->atom__NET_WM_ACTION_FULLSCREEN;
06132 ++i;
06133 }
06134 if (window->has_minimize_func)
06135 {
06136 data[i] = window->display->atom__NET_WM_ACTION_MINIMIZE;
06137 ++i;
06138 }
06139 if (window->has_shade_func)
06140 {
06141 data[i] = window->display->atom__NET_WM_ACTION_SHADE;
06142 ++i;
06143 }
06144
06145
06146
06147 if (window->has_maximize_func)
06148 {
06149 data[i] = window->display->atom__NET_WM_ACTION_MAXIMIZE_HORZ;
06150 ++i;
06151 data[i] = window->display->atom__NET_WM_ACTION_MAXIMIZE_VERT;
06152 ++i;
06153 }
06154
06155 data[i] = window->display->atom__NET_WM_ACTION_CHANGE_DESKTOP;
06156 ++i;
06157 if (window->has_close_func)
06158 {
06159 data[i] = window->display->atom__NET_WM_ACTION_CLOSE;
06160 ++i;
06161 }
06162
06163
06164 data[i] = window->display->atom__NET_WM_ACTION_ABOVE;
06165 ++i;
06166 data[i] = window->display->atom__NET_WM_ACTION_BELOW;
06167 ++i;
06168
06169 g_assert (i <= MAX_N_ACTIONS);
06170
06171 meta_verbose ("Setting _NET_WM_ALLOWED_ACTIONS with %d atoms\n", i);
06172
06173 meta_error_trap_push (window->display);
06174 XChangeProperty (window->display->xdisplay, window->xwindow,
06175 window->display->atom__NET_WM_ALLOWED_ACTIONS,
06176 XA_ATOM,
06177 32, PropModeReplace, (guchar*) data, i);
06178 meta_error_trap_pop (window->display, FALSE);
06179 #undef MAX_N_ACTIONS
06180 }
06181
06182 void
06183 meta_window_recalc_features (MetaWindow *window)
06184 {
06185 recalc_window_features (window);
06186 }
06187
06188 static void
06189 recalc_window_features (MetaWindow *window)
06190 {
06191 gboolean old_has_close_func;
06192 gboolean old_has_minimize_func;
06193 gboolean old_has_move_func;
06194 gboolean old_has_resize_func;
06195 gboolean old_has_shade_func;
06196 gboolean old_always_sticky;
06197
06198 old_has_close_func = window->has_close_func;
06199 old_has_minimize_func = window->has_minimize_func;
06200 old_has_move_func = window->has_move_func;
06201 old_has_resize_func = window->has_resize_func;
06202 old_has_shade_func = window->has_shade_func;
06203 old_always_sticky = window->always_sticky;
06204
06205
06206 window->decorated = window->mwm_decorated;
06207 window->border_only = window->mwm_border_only;
06208 window->has_close_func = window->mwm_has_close_func;
06209 window->has_minimize_func = window->mwm_has_minimize_func;
06210 window->has_maximize_func = window->mwm_has_maximize_func;
06211 window->has_move_func = window->mwm_has_move_func;
06212
06213 window->has_resize_func = TRUE;
06214
06215
06216 if (window->size_hints.min_width == window->size_hints.max_width &&
06217 window->size_hints.min_height == window->size_hints.max_height)
06218 window->has_resize_func = FALSE;
06219 else if (!window->mwm_has_resize_func)
06220 {
06221
06222
06223
06224
06225
06226
06227
06228
06229 meta_warning (_("Window %s sets an MWM hint indicating it isn't resizable, but sets min size %d x %d and max size %d x %d; this doesn't make much sense.\n"),
06230 window->desc,
06231 window->size_hints.min_width,
06232 window->size_hints.min_height,
06233 window->size_hints.max_width,
06234 window->size_hints.max_height);
06235 }
06236
06237 window->has_shade_func = TRUE;
06238 window->has_fullscreen_func = TRUE;
06239
06240 window->always_sticky = FALSE;
06241
06242
06243 if (window->type == META_WINDOW_TOOLBAR)
06244 window->decorated = FALSE;
06245
06246 if (window->type == META_WINDOW_DESKTOP ||
06247 window->type == META_WINDOW_DOCK)
06248 window->always_sticky = TRUE;
06249
06250 if (window->type == META_WINDOW_DESKTOP ||
06251 window->type == META_WINDOW_DOCK ||
06252 window->type == META_WINDOW_SPLASHSCREEN)
06253 {
06254 window->decorated = FALSE;
06255 window->has_close_func = FALSE;
06256 window->has_shade_func = FALSE;
06257
06258
06259
06260
06261
06262
06263
06264
06265
06266 window->has_move_func = FALSE;
06267 window->has_resize_func = FALSE;
06268 }
06269
06270 if (window->type != META_WINDOW_NORMAL)
06271 {
06272 window->has_minimize_func = FALSE;
06273 window->has_maximize_func = FALSE;
06274 window->has_fullscreen_func = FALSE;
06275 }
06276
06277 if (!window->has_resize_func)
06278 {
06279 window->has_maximize_func = FALSE;
06280
06281
06282
06283
06284
06285 if (window->size_hints.min_width == window->screen->rect.width &&
06286 window->size_hints.min_height == window->screen->rect.height)
06287 ;
06288 else
06289 window->has_fullscreen_func = FALSE;
06290 }
06291
06292
06293
06294
06295
06296
06297
06298
06299
06300 if (window->fullscreen)
06301 {
06302 window->has_shade_func = FALSE;
06303 window->has_move_func = FALSE;
06304 window->has_resize_func = FALSE;
06305 window->has_maximize_func = FALSE;
06306 }
06307
06308 meta_topic (META_DEBUG_WINDOW_OPS,
06309 "Window %s fullscreen = %d not resizable, maximizable = %d fullscreenable = %d min size %dx%d max size %dx%d\n",
06310 window->desc,
06311 window->fullscreen,
06312 window->has_maximize_func, window->has_fullscreen_func,
06313 window->size_hints.min_width,
06314 window->size_hints.min_height,
06315 window->size_hints.max_width,
06316 window->size_hints.max_height);
06317
06318
06319 if (!window->decorated || window->border_only)
06320 window->has_shade_func = FALSE;
06321
06322 window->skip_taskbar = FALSE;
06323 window->skip_pager = FALSE;
06324
06325 if (window->wm_state_skip_taskbar)
06326 window->skip_taskbar = TRUE;
06327
06328 if (window->wm_state_skip_pager)
06329 window->skip_pager = TRUE;
06330
06331 switch (window->type)
06332 {
06333
06334 case META_WINDOW_DESKTOP:
06335 case META_WINDOW_DOCK:
06336 case META_WINDOW_TOOLBAR:
06337 case META_WINDOW_MENU:
06338 case META_WINDOW_UTILITY:
06339 case META_WINDOW_SPLASHSCREEN:
06340 window->skip_taskbar = TRUE;
06341 window->skip_pager = TRUE;
06342 break;
06343
06344 case META_WINDOW_DIALOG:
06345 case META_WINDOW_MODAL_DIALOG:
06346
06347 if (window->xtransient_for != None &&
06348 window->xtransient_for != window->screen->xroot)
06349 window->skip_taskbar = TRUE;
06350 break;
06351
06352 case META_WINDOW_NORMAL:
06353 break;
06354 }
06355
06356 meta_topic (META_DEBUG_WINDOW_OPS,
06357 "Window %s decorated = %d border_only = %d has_close = %d has_minimize = %d has_maximize = %d has_move = %d has_shade = %d skip_taskbar = %d skip_pager = %d\n",
06358 window->desc,
06359 window->decorated,
06360 window->border_only,
06361 window->has_close_func,
06362 window->has_minimize_func,
06363 window->has_maximize_func,
06364 window->has_move_func,
06365 window->has_shade_func,
06366 window->skip_taskbar,
06367 window->skip_pager);
06368
06369
06370
06371
06372
06373
06374
06375 if (window->constructing ||
06376 old_has_close_func != window->has_close_func ||
06377 old_has_minimize_func != window->has_minimize_func ||
06378 old_has_move_func != window->has_move_func ||
06379 old_has_resize_func != window->has_resize_func ||
06380 old_has_shade_func != window->has_shade_func ||
06381 old_always_sticky != window->always_sticky)
06382 set_allowed_actions_hint (window);
06383
06384
06385
06386
06387 }
06388
06389 static void
06390 menu_callback (MetaWindowMenu *menu,
06391 Display *xdisplay,
06392 Window client_xwindow,
06393 guint32 timestamp,
06394 MetaMenuOp op,
06395 int workspace_index,
06396 gpointer data)
06397 {
06398 MetaDisplay *display;
06399 MetaWindow *window;
06400 MetaWorkspace *workspace;
06401
06402 display = meta_display_for_x_display (xdisplay);
06403 window = meta_display_lookup_x_window (display, client_xwindow);
06404 workspace = NULL;
06405
06406 if (window != NULL)
06407 {
06408 meta_verbose ("Menu op %u on %s\n", op, window->desc);
06409
06410
06411 switch (op)
06412 {
06413 case META_MENU_OP_DELETE:
06414 meta_window_delete (window, timestamp);
06415 break;
06416
06417 case META_MENU_OP_MINIMIZE:
06418 meta_window_minimize (window);
06419 break;
06420
06421 case META_MENU_OP_UNMAXIMIZE:
06422 meta_window_unmaximize (window,
06423 META_MAXIMIZE_HORIZONTAL |
06424 META_MAXIMIZE_VERTICAL);
06425 break;
06426
06427 case META_MENU_OP_MAXIMIZE:
06428 meta_window_maximize (window,
06429 META_MAXIMIZE_HORIZONTAL |
06430 META_MAXIMIZE_VERTICAL);
06431 break;
06432
06433 case META_MENU_OP_UNSHADE:
06434 meta_window_unshade (window, timestamp);
06435 break;
06436
06437 case META_MENU_OP_SHADE:
06438 meta_window_shade (window, timestamp);
06439 break;
06440
06441 case META_MENU_OP_MOVE_LEFT:
06442 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
06443 META_MOTION_LEFT);
06444 break;
06445
06446 case META_MENU_OP_MOVE_RIGHT:
06447 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
06448 META_MOTION_RIGHT);
06449 break;
06450
06451 case META_MENU_OP_MOVE_UP:
06452 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
06453 META_MOTION_UP);
06454 break;
06455
06456 case META_MENU_OP_MOVE_DOWN:
06457 workspace = meta_workspace_get_neighbor (window->screen->active_workspace,
06458 META_MOTION_DOWN);
06459 break;
06460
06461 case META_MENU_OP_WORKSPACES:
06462 workspace = meta_screen_get_workspace_by_index (window->screen,
06463 workspace_index);
06464 break;
06465
06466 case META_MENU_OP_STICK:
06467 meta_window_stick (window);
06468 break;
06469
06470 case META_MENU_OP_UNSTICK:
06471 meta_window_unstick (window);
06472 break;
06473
06474 case META_MENU_OP_ABOVE:
06475 case META_MENU_OP_UNABOVE:
06476 if (window->wm_state_above == FALSE)
06477 meta_window_make_above (window);
06478 else
06479 meta_window_unmake_above (window);
06480 break;
06481
06482 case META_MENU_OP_MOVE:
06483 meta_window_begin_grab_op (window,
06484 META_GRAB_OP_KEYBOARD_MOVING,
06485 TRUE,
06486 timestamp);
06487 break;
06488
06489 case META_MENU_OP_RESIZE:
06490 meta_window_begin_grab_op (window,
06491 META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN,
06492 TRUE,
06493 timestamp);
06494 break;
06495
06496 case META_MENU_OP_RECOVER:
06497 meta_window_shove_titlebar_onscreen (window);
06498 break;
06499
06500 case 0:
06501
06502 break;
06503
06504 default:
06505 meta_warning (G_STRLOC": Unknown window op\n");
06506 break;
06507 }
06508
06509 if (workspace)
06510 {
06511 meta_window_change_workspace (window,
06512 workspace);
06513 #if 0
06514 meta_workspace_activate (workspace);
06515 meta_window_raise (window);
06516 #endif
06517 }
06518 }
06519 else
06520 {
06521 meta_verbose ("Menu callback on nonexistent window\n");
06522 }
06523
06524 if (display->window_menu == menu)
06525 {
06526 display->window_menu = NULL;
06527 display->window_with_menu = NULL;
06528 }
06529
06530 meta_ui_window_menu_free (menu);
06531 }
06532
06533 void
06534 meta_window_show_menu (MetaWindow *window,
06535 int root_x,
06536 int root_y,
06537 int button,
06538 guint32 timestamp)
06539 {
06540 MetaMenuOp ops;
06541 MetaMenuOp insensitive;
06542 MetaWindowMenu *menu;
06543 MetaWorkspaceLayout layout;
06544 int n_workspaces;
06545 gboolean ltr;
06546
06547 if (window->display->window_menu)
06548 {
06549 meta_ui_window_menu_free (window->display->window_menu);
06550 window->display->window_menu = NULL;
06551 window->display->window_with_menu = NULL;
06552 }
06553
06554 ops = 0;
06555 insensitive = 0;
06556
06557 ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE);
06558
06559 if (!meta_window_titlebar_is_onscreen (window) &&
06560 window->type != META_WINDOW_DOCK &&
06561 window->type != META_WINDOW_DESKTOP)
06562 ops |= META_MENU_OP_RECOVER;
06563
06564 n_workspaces = meta_screen_get_n_workspaces (window->screen);
06565
06566 if (n_workspaces > 1)
06567 ops |= META_MENU_OP_WORKSPACES;
06568
06569 meta_screen_calc_workspace_layout (window->screen,
06570 n_workspaces,
06571 meta_workspace_index ( window->screen->active_workspace),
06572 &layout);
06573
06574 if (!window->on_all_workspaces)
06575 {
06576 ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR;
06577
06578 if (layout.current_col > 0)
06579 ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT;
06580 if ((layout.current_col < layout.cols - 1) &&
06581 (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces))
06582 ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT;
06583 if (layout.current_row > 0)
06584 ops |= META_MENU_OP_MOVE_UP;
06585 if ((layout.current_row < layout.rows - 1) &&
06586 ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces))
06587 ops |= META_MENU_OP_MOVE_DOWN;
06588 }
06589
06590 meta_screen_free_workspace_layout (&layout);
06591
06592 if (META_WINDOW_MAXIMIZED (window))
06593 ops |= META_MENU_OP_UNMAXIMIZE;
06594 else
06595 ops |= META_MENU_OP_MAXIMIZE;
06596
06597 #if 0
06598 if (window->shaded)
06599 ops |= META_MENU_OP_UNSHADE;
06600 else
06601 ops |= META_MENU_OP_SHADE;
06602 #endif
06603
06604 ops |= META_MENU_OP_UNSTICK;
06605 ops |= META_MENU_OP_STICK;
06606
06607 if (window->wm_state_above)
06608 ops |= META_MENU_OP_UNABOVE;
06609 else
06610 ops |= META_MENU_OP_ABOVE;
06611
06612 if (!window->has_maximize_func)
06613 insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE;
06614
06615 if (!window->has_minimize_func)
06616 insensitive |= META_MENU_OP_MINIMIZE;
06617
06618 if (!window->has_close_func)
06619 insensitive |= META_MENU_OP_DELETE;
06620
06621 if (!window->has_shade_func)
06622 insensitive |= META_MENU_OP_SHADE | META_MENU_OP_UNSHADE;
06623
06624 if (!META_WINDOW_ALLOWS_MOVE (window))
06625 insensitive |= META_MENU_OP_MOVE;
06626
06627 if (!META_WINDOW_ALLOWS_RESIZE (window))
06628 insensitive |= META_MENU_OP_RESIZE;
06629
06630 if (window->always_sticky)
06631 insensitive |= META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES;
06632
06633 if ((window->type == META_WINDOW_DESKTOP) ||
06634 (window->type == META_WINDOW_DOCK) ||
06635 (window->type == META_WINDOW_SPLASHSCREEN))
06636 insensitive |= META_MENU_OP_ABOVE | META_MENU_OP_UNABOVE;
06637
06638
06639
06640
06641 if ((ops & ~insensitive) == 0)
06642 return;
06643
06644 menu =
06645 meta_ui_window_menu_new (window->screen->ui,
06646 window->xwindow,
06647 ops,
06648 insensitive,
06649 meta_window_get_net_wm_desktop (window),
06650 meta_screen_get_n_workspaces (window->screen),
06651 menu_callback,
06652 NULL);
06653
06654 window->display->window_menu = menu;
06655 window->display->window_with_menu = window;
06656
06657 meta_verbose ("Popping up window menu for %s\n", window->desc);
06658
06659 meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp);
06660 }
06661
06662 void
06663 meta_window_shove_titlebar_onscreen (MetaWindow *window)
06664 {
06665 MetaRectangle outer_rect;
06666 GList *onscreen_region;
06667 int horiz_amount, vert_amount;
06668 int newx, newy;
06669
06670
06671 if (!window->frame)
06672 return;
06673
06674
06675 meta_window_get_outer_rect (window, &outer_rect);
06676 onscreen_region = window->screen->active_workspace->screen_region;
06677
06678
06679
06680
06681
06682 horiz_amount = outer_rect.width;
06683 vert_amount = outer_rect.height;
06684 meta_rectangle_expand_region (onscreen_region,
06685 horiz_amount,
06686 horiz_amount,
06687 0,
06688 vert_amount);
06689 meta_rectangle_shove_into_region(onscreen_region,
06690 FIXED_DIRECTION_X,
06691 &outer_rect);
06692 meta_rectangle_expand_region (onscreen_region,
06693 -horiz_amount,
06694 -horiz_amount,
06695 0,
06696 -vert_amount);
06697
06698 newx = outer_rect.x + window->frame->child_x;
06699 newy = outer_rect.y + window->frame->child_y;
06700 meta_window_move_resize (window,
06701 FALSE,
06702 newx,
06703 newy,
06704 window->rect.width,
06705 window->rect.height);
06706 }
06707
06708 gboolean
06709 meta_window_titlebar_is_onscreen (MetaWindow *window)
06710 {
06711 MetaRectangle titlebar_rect;
06712 GList *onscreen_region;
06713 int titlebar_size;
06714 gboolean is_onscreen;
06715
06716 const int min_height_needed = 8;
06717 const int min_width_percent = 0.5;
06718 const int min_width_absolute = 50;
06719
06720
06721 if (!window->frame)
06722 return FALSE;
06723
06724
06725 meta_window_get_outer_rect (window, &titlebar_rect);
06726 titlebar_rect.height = window->frame->child_y;
06727 titlebar_size = meta_rectangle_area (&titlebar_rect);
06728
06729
06730
06731
06732 is_onscreen = FALSE;
06733 onscreen_region = window->screen->active_workspace->screen_region;
06734 while (onscreen_region)
06735 {
06736 MetaRectangle *spanning_rect = onscreen_region->data;
06737 MetaRectangle overlap;
06738
06739 meta_rectangle_intersect (&titlebar_rect, spanning_rect, &overlap);
06740 if (overlap.height > MIN (titlebar_rect.height, min_height_needed) &&
06741 overlap.width > MIN (titlebar_rect.width * min_width_percent,
06742 min_width_absolute))
06743 {
06744 is_onscreen = TRUE;
06745 break;
06746 }
06747
06748 onscreen_region = onscreen_region->next;
06749 }
06750
06751 return is_onscreen;
06752 }
06753
06754 static double
06755 timeval_to_ms (const GTimeVal *timeval)
06756 {
06757 return (timeval->tv_sec * G_USEC_PER_SEC + timeval->tv_usec) / 1000.0;
06758 }
06759
06760 static double
06761 time_diff (const GTimeVal *first,
06762 const GTimeVal *second)
06763 {
06764 double first_ms = timeval_to_ms (first);
06765 double second_ms = timeval_to_ms (second);
06766
06767 return first_ms - second_ms;
06768 }
06769
06770 static gboolean
06771 check_moveresize_frequency (MetaWindow *window,
06772 gdouble *remaining)
06773 {
06774 GTimeVal current_time;
06775
06776 g_get_current_time (¤t_time);
06777
06778 #ifdef HAVE_XSYNC
06779 if (!window->disable_sync &&
06780 window->display->grab_sync_request_alarm != None)
06781 {
06782 if (window->sync_request_time.tv_sec != 0 ||
06783 window->sync_request_time.tv_usec != 0)
06784 {
06785 double elapsed =
06786 time_diff (¤t_time, &window->sync_request_time);
06787
06788 if (elapsed < 1000.0)
06789 {
06790
06791
06792
06793
06794 if (remaining)
06795 *remaining = 1000.0 - elapsed + 100;
06796
06797 return FALSE;
06798 }
06799 else
06800 {
06801
06802
06803
06804 window->disable_sync = TRUE;
06805 return TRUE;
06806 }
06807 }
06808 else
06809 {
06810
06811
06812 return TRUE;
06813 }
06814 }
06815 else
06816 #endif
06817 {
06818 const double max_resizes_per_second = 25.0;
06819 const double ms_between_resizes = 1000.0 / max_resizes_per_second;
06820 double elapsed;
06821
06822 elapsed = time_diff (¤t_time, &window->display->grab_last_moveresize_time);
06823
06824 if (elapsed >= 0.0 && elapsed < ms_between_resizes)
06825 {
06826 meta_topic (META_DEBUG_RESIZING,
06827 "Delaying move/resize as only %g of %g ms elapsed\n",
06828 elapsed, ms_between_resizes);
06829
06830 if (remaining)
06831 *remaining = (ms_between_resizes - elapsed);
06832
06833 return FALSE;
06834 }
06835
06836 meta_topic (META_DEBUG_RESIZING,
06837 " Checked moveresize freq, allowing move/resize now (%g of %g seconds elapsed)\n",
06838 elapsed / 1000.0, 1.0 / max_resizes_per_second);
06839
06840 return TRUE;
06841 }
06842 }
06843
06844 static gboolean
06845 update_move_timeout (gpointer data)
06846 {
06847 MetaWindow *window = data;
06848
06849 update_move (window,
06850 window->display->grab_last_user_action_was_snap,
06851 window->display->grab_latest_motion_x,
06852 window->display->grab_latest_motion_y);
06853
06854 return FALSE;
06855 }
06856
06857 static void
06858 update_move (MetaWindow *window,
06859 gboolean snap,
06860 int x,
06861 int y)
06862 {
06863 int dx, dy;
06864 int new_x, new_y;
06865 MetaRectangle old;
06866 int shake_threshold;
06867 MetaDisplay *display = window->display;
06868
06869 display->grab_latest_motion_x = x;
06870 display->grab_latest_motion_y = y;
06871
06872 dx = x - display->grab_anchor_root_x;
06873 dy = y - display->grab_anchor_root_y;
06874
06875 new_x = display->grab_anchor_window_pos.x + dx;
06876 new_y = display->grab_anchor_window_pos.y + dy;
06877
06878 meta_verbose ("x,y = %d,%d anchor ptr %d,%d anchor pos %d,%d dx,dy %d,%d\n",
06879 x, y,
06880 display->grab_anchor_root_x,
06881 display->grab_anchor_root_y,
06882 display->grab_anchor_window_pos.x,
06883 display->grab_anchor_window_pos.y,
06884 dx, dy);
06885
06886
06887
06888
06889
06890 if (dx == 0 && dy == 0)
06891 return;
06892
06893
06894
06895
06896
06897 #define DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR 6
06898 shake_threshold = meta_ui_get_drag_threshold (window->screen->ui) *
06899 DRAG_THRESHOLD_TO_SHAKE_THRESHOLD_FACTOR;
06900
06901 if (META_WINDOW_MAXIMIZED (window) && ABS (dy) >= shake_threshold)
06902 {
06903 double prop;
06904
06905
06906 window->shaken_loose = TRUE;
06907
06908
06909 prop =
06910 ((double)(x - display->grab_initial_window_pos.x)) /
06911 ((double)display->grab_initial_window_pos.width);
06912
06913 display->grab_initial_window_pos.x =
06914 x - window->saved_rect.width * prop;
06915 display->grab_initial_window_pos.y = y;
06916
06917 if (window->frame)
06918 {
06919 display->grab_initial_window_pos.y += window->frame->child_y / 2;
06920 }
06921
06922 window->saved_rect.x = display->grab_initial_window_pos.x;
06923 window->saved_rect.y = display->grab_initial_window_pos.y;
06924 display->grab_anchor_root_x = x;
06925 display->grab_anchor_root_y = y;
06926
06927 meta_window_unmaximize (window,
06928 META_MAXIMIZE_HORIZONTAL |
06929 META_MAXIMIZE_VERTICAL);
06930
06931 return;
06932 }
06933
06934
06935
06936 else if (window->shaken_loose || META_WINDOW_MAXIMIZED (window))
06937 {
06938 const MetaXineramaScreenInfo *wxinerama;
06939 MetaRectangle work_area;
06940 int monitor;
06941
06942 wxinerama = meta_screen_get_xinerama_for_window (window->screen, window);
06943
06944 for (monitor = 0; monitor < window->screen->n_xinerama_infos; monitor++)
06945 {
06946 meta_window_get_work_area_for_xinerama (window, monitor, &work_area);
06947
06948
06949 if (x >= work_area.x &&
06950 x < (work_area.x + work_area.width) &&
06951 y >= work_area.y &&
06952 y < (work_area.y + shake_threshold))
06953 {
06954
06955
06956
06957 if (wxinerama->number != monitor)
06958 {
06959 window->saved_rect.x = work_area.x;
06960 window->saved_rect.y = work_area.y;
06961
06962 if (window->frame)
06963 {
06964 window->saved_rect.x += window->frame->child_x;
06965 window->saved_rect.y += window->frame->child_y;
06966 }
06967
06968 window->user_rect.x = window->saved_rect.x;
06969 window->user_rect.y = window->saved_rect.y;
06970
06971 meta_window_unmaximize (window,
06972 META_MAXIMIZE_HORIZONTAL |
06973 META_MAXIMIZE_VERTICAL);
06974 }
06975
06976 display->grab_initial_window_pos = work_area;
06977 display->grab_anchor_root_x = x;
06978 display->grab_anchor_root_y = y;
06979 window->shaken_loose = FALSE;
06980
06981 meta_window_maximize (window,
06982 META_MAXIMIZE_HORIZONTAL |
06983 META_MAXIMIZE_VERTICAL);
06984
06985 return;
06986 }
06987 }
06988 }
06989
06990 if (display->grab_wireframe_active)
06991 old = display->grab_wireframe_rect;
06992 else
06993 meta_window_get_client_root_coords (window, &old);
06994
06995
06996 if (window->maximized_horizontally)
06997 new_x = old.x;
06998 if (window->maximized_vertically)
06999 new_y = old.y;
07000
07001
07002 meta_window_edge_resistance_for_move (window,
07003 old.x,
07004 old.y,
07005 &new_x,
07006 &new_y,
07007 update_move_timeout,
07008 snap,
07009 FALSE);
07010
07011 if (display->compositor)
07012 {
07013 int root_x = new_x - display->grab_anchor_window_pos.x + display->grab_anchor_root_x;
07014 int root_y = new_y - display->grab_anchor_window_pos.y + display->grab_anchor_root_y;
07015
07016 meta_compositor_update_move (display->compositor,
07017 window, root_x, root_y);
07018 }
07019
07020 if (display->grab_wireframe_active)
07021 meta_window_update_wireframe (window, new_x, new_y,
07022 display->grab_wireframe_rect.width,
07023 display->grab_wireframe_rect.height);
07024 else
07025 meta_window_move (window, TRUE, new_x, new_y);
07026 }
07027
07028 static gboolean
07029 update_resize_timeout (gpointer data)
07030 {
07031 MetaWindow *window = data;
07032
07033 update_resize (window,
07034 window->display->grab_last_user_action_was_snap,
07035 window->display->grab_latest_motion_x,
07036 window->display->grab_latest_motion_y,
07037 TRUE);
07038 return FALSE;
07039 }
07040
07041 static void
07042 update_resize (MetaWindow *window,
07043 gboolean snap,
07044 int x, int y,
07045 gboolean force)
07046 {
07047 int dx, dy;
07048 int new_w, new_h;
07049 int gravity;
07050 MetaRectangle old;
07051 int new_x, new_y;
07052 double remaining;
07053
07054 window->display->grab_latest_motion_x = x;
07055 window->display->grab_latest_motion_y = y;
07056
07057 dx = x - window->display->grab_anchor_root_x;
07058 dy = y - window->display->grab_anchor_root_y;
07059
07060 new_w = window->display->grab_anchor_window_pos.width;
07061 new_h = window->display->grab_anchor_window_pos.height;
07062
07063
07064
07065
07066
07067 if (dx == 0 && dy == 0)
07068 return;
07069
07070
07071 new_x = window->display->grab_anchor_window_pos.x;
07072 new_y = window->display->grab_anchor_window_pos.y;
07073
07074 if (window->display->grab_op == META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN)
07075 {
07076 if ((dx > 0) && (dy > 0))
07077 {
07078 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SE;
07079 meta_window_update_keyboard_resize (window, TRUE);
07080 }
07081 else if ((dx < 0) && (dy > 0))
07082 {
07083 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_SW;
07084 meta_window_update_keyboard_resize (window, TRUE);
07085 }
07086 else if ((dx > 0) && (dy < 0))
07087 {
07088 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NE;
07089 meta_window_update_keyboard_resize (window, TRUE);
07090 }
07091 else if ((dx < 0) && (dy < 0))
07092 {
07093 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_NW;
07094 meta_window_update_keyboard_resize (window, TRUE);
07095 }
07096 else if (dx < 0)
07097 {
07098 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_W;
07099 meta_window_update_keyboard_resize (window, TRUE);
07100 }
07101 else if (dx > 0)
07102 {
07103 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_E;
07104 meta_window_update_keyboard_resize (window, TRUE);
07105 }
07106 else if (dy > 0)
07107 {
07108 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_S;
07109 meta_window_update_keyboard_resize (window, TRUE);
07110 }
07111 else if (dy < 0)
07112 {
07113 window->display->grab_op = META_GRAB_OP_KEYBOARD_RESIZING_N;
07114 meta_window_update_keyboard_resize (window, TRUE);
07115 }
07116 }
07117
07118
07119
07120
07121
07122
07123 switch (window->display->grab_op)
07124 {
07125 case META_GRAB_OP_RESIZING_SE:
07126 case META_GRAB_OP_RESIZING_NE:
07127 case META_GRAB_OP_RESIZING_E:
07128 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
07129 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
07130 case META_GRAB_OP_KEYBOARD_RESIZING_E:
07131 new_w += dx;
07132 break;
07133
07134 case META_GRAB_OP_RESIZING_NW:
07135 case META_GRAB_OP_RESIZING_SW:
07136 case META_GRAB_OP_RESIZING_W:
07137 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
07138 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
07139 case META_GRAB_OP_KEYBOARD_RESIZING_W:
07140 new_w -= dx;
07141 new_x += dx;
07142 break;
07143
07144 default:
07145 break;
07146 }
07147
07148 switch (window->display->grab_op)
07149 {
07150 case META_GRAB_OP_RESIZING_SE:
07151 case META_GRAB_OP_RESIZING_S:
07152 case META_GRAB_OP_RESIZING_SW:
07153 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
07154 case META_GRAB_OP_KEYBOARD_RESIZING_S:
07155 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
07156 new_h += dy;
07157 break;
07158
07159 case META_GRAB_OP_RESIZING_N:
07160 case META_GRAB_OP_RESIZING_NE:
07161 case META_GRAB_OP_RESIZING_NW:
07162 case META_GRAB_OP_KEYBOARD_RESIZING_N:
07163 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
07164 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
07165 new_h -= dy;
07166 new_y += dy;
07167 break;
07168 default:
07169 break;
07170 }
07171
07172 if (!check_moveresize_frequency (window, &remaining) && !force)
07173 {
07174
07175
07176
07177
07178
07179 if (!window->display->grab_resize_timeout_id)
07180 {
07181 window->display->grab_resize_timeout_id =
07182 g_timeout_add ((int)remaining, update_resize_timeout, window);
07183 }
07184
07185 return;
07186 }
07187
07188
07189 if (window->display->compositor)
07190 meta_compositor_set_updates (window->display->compositor, window, TRUE);
07191
07192
07193 if (window->display->grab_resize_timeout_id)
07194 {
07195 g_source_remove (window->display->grab_resize_timeout_id);
07196 window->display->grab_resize_timeout_id = 0;
07197 }
07198
07199 if (window->display->grab_wireframe_active)
07200 old = window->display->grab_wireframe_rect;
07201 else
07202 old = window->rect;
07203
07204
07205
07206
07207
07208 switch (window->display->grab_op)
07209 {
07210 case META_GRAB_OP_RESIZING_S:
07211 case META_GRAB_OP_RESIZING_N:
07212 new_w = old.width;
07213 break;
07214
07215 case META_GRAB_OP_RESIZING_E:
07216 case META_GRAB_OP_RESIZING_W:
07217 new_h = old.height;
07218 break;
07219
07220 default:
07221 break;
07222 }
07223
07224
07225 gravity = meta_resize_gravity_from_grab_op (window->display->grab_op);
07226 g_assert (gravity >= 0);
07227
07228
07229 meta_window_edge_resistance_for_resize (window,
07230 old.width,
07231 old.height,
07232 &new_w,
07233 &new_h,
07234 gravity,
07235 update_resize_timeout,
07236 snap,
07237 FALSE);
07238
07239 if (window->display->grab_wireframe_active)
07240 {
07241 if ((new_x + new_w <= new_x) || (new_y + new_h <= new_y))
07242 return;
07243
07244
07245
07246
07247
07248
07249
07250
07251 meta_window_update_wireframe (window, new_x, new_y, new_w, new_h);
07252 }
07253 else
07254 {
07255
07256
07257
07258 if (old.width != new_w || old.height != new_h)
07259 meta_window_resize_with_gravity (window, TRUE, new_w, new_h, gravity);
07260 }
07261
07262
07263 if (window->rect.width != old.width || window->rect.height != old.height)
07264 g_get_current_time (&window->display->grab_last_moveresize_time);
07265 }
07266
07267 typedef struct
07268 {
07269 const XEvent *current_event;
07270 int count;
07271 guint32 last_time;
07272 } EventScannerData;
07273
07274 static Bool
07275 find_last_time_predicate (Display *display,
07276 XEvent *xevent,
07277 XPointer arg)
07278 {
07279 EventScannerData *esd = (void*) arg;
07280
07281 if (esd->current_event->type == xevent->type &&
07282 esd->current_event->xany.window == xevent->xany.window)
07283 {
07284 esd->count += 1;
07285 esd->last_time = xevent->xmotion.time;
07286 }
07287
07288 return False;
07289 }
07290
07291 static gboolean
07292 check_use_this_motion_notify (MetaWindow *window,
07293 XEvent *event)
07294 {
07295 EventScannerData esd;
07296 XEvent useless;
07297
07298
07299
07300 if (window->display->grab_motion_notify_time != 0)
07301 {
07302
07303 if (window->display->grab_motion_notify_time <=
07304 event->xmotion.time)
07305 {
07306 meta_topic (META_DEBUG_RESIZING,
07307 "Arrived at event with time %u (waiting for %u), using it\n",
07308 (unsigned int)event->xmotion.time,
07309 window->display->grab_motion_notify_time);
07310 window->display->grab_motion_notify_time = 0;
07311 return TRUE;
07312 }
07313 else
07314 return FALSE;
07315 }
07316
07317 esd.current_event = event;
07318 esd.count = 0;
07319 esd.last_time = 0;
07320
07321
07322 XCheckIfEvent (window->display->xdisplay,
07323 &useless,
07324 find_last_time_predicate,
07325 (XPointer) &esd);
07326
07327 if (esd.count > 0)
07328 meta_topic (META_DEBUG_RESIZING,
07329 "Will skip %d motion events and use the event with time %u\n",
07330 esd.count, (unsigned int) esd.last_time);
07331
07332 if (esd.last_time == 0)
07333 return TRUE;
07334 else
07335 {
07336
07337
07338
07339 window->display->grab_motion_notify_time = esd.last_time;
07340 return FALSE;
07341 }
07342 }
07343
07344 void
07345 meta_window_handle_mouse_grab_op_event (MetaWindow *window,
07346 XEvent *event)
07347 {
07348 #ifdef HAVE_XSYNC
07349 if (event->type == (window->display->xsync_event_base + XSyncAlarmNotify))
07350 {
07351 meta_topic (META_DEBUG_RESIZING,
07352 "Alarm event received last motion x = %d y = %d\n",
07353 window->display->grab_latest_motion_x,
07354 window->display->grab_latest_motion_y);
07355
07356
07357
07358
07359
07360 window->disable_sync = FALSE;
07361 window->sync_request_time.tv_sec = 0;
07362 window->sync_request_time.tv_usec = 0;
07363
07364
07365 switch (window->display->grab_op)
07366 {
07367 case META_GRAB_OP_RESIZING_E:
07368 case META_GRAB_OP_RESIZING_W:
07369 case META_GRAB_OP_RESIZING_S:
07370 case META_GRAB_OP_RESIZING_N:
07371 case META_GRAB_OP_RESIZING_SE:
07372 case META_GRAB_OP_RESIZING_SW:
07373 case META_GRAB_OP_RESIZING_NE:
07374 case META_GRAB_OP_RESIZING_NW:
07375 case META_GRAB_OP_KEYBOARD_RESIZING_S:
07376 case META_GRAB_OP_KEYBOARD_RESIZING_N:
07377 case META_GRAB_OP_KEYBOARD_RESIZING_W:
07378 case META_GRAB_OP_KEYBOARD_RESIZING_E:
07379 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
07380 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
07381 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
07382 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
07383
07384 update_resize (window,
07385 window->display->grab_last_user_action_was_snap,
07386 window->display->grab_latest_motion_x,
07387 window->display->grab_latest_motion_y,
07388 TRUE);
07389 break;
07390
07391 default:
07392 break;
07393 }
07394 }
07395 #endif
07396
07397 switch (event->type)
07398 {
07399 case ButtonRelease:
07400 meta_display_check_threshold_reached (window->display,
07401 event->xbutton.x_root,
07402 event->xbutton.y_root);
07403
07404
07405
07406
07407
07408 if (!window->display->grab_last_user_action_was_snap)
07409 {
07410 if (meta_grab_op_is_moving (window->display->grab_op))
07411 {
07412 if (event->xbutton.root == window->screen->xroot)
07413 update_move (window, event->xbutton.state & ShiftMask,
07414 event->xbutton.x_root, event->xbutton.y_root);
07415 }
07416 else if (meta_grab_op_is_resizing (window->display->grab_op))
07417 {
07418 if (event->xbutton.root == window->screen->xroot)
07419 update_resize (window,
07420 event->xbutton.state & ShiftMask,
07421 event->xbutton.x_root,
07422 event->xbutton.y_root,
07423 TRUE);
07424 if (window->display->compositor)
07425 meta_compositor_set_updates (window->display->compositor, window, TRUE);
07426 }
07427 }
07428
07429 meta_display_end_grab_op (window->display, event->xbutton.time);
07430 break;
07431
07432 case MotionNotify:
07433 meta_display_check_threshold_reached (window->display,
07434 event->xmotion.x_root,
07435 event->xmotion.y_root);
07436 if (meta_grab_op_is_moving (window->display->grab_op))
07437 {
07438 if (event->xmotion.root == window->screen->xroot)
07439 {
07440 if (check_use_this_motion_notify (window,
07441 event))
07442 update_move (window,
07443 event->xmotion.state & ShiftMask,
07444 event->xmotion.x_root,
07445 event->xmotion.y_root);
07446 }
07447 }
07448 else if (meta_grab_op_is_resizing (window->display->grab_op))
07449 {
07450 if (event->xmotion.root == window->screen->xroot)
07451 {
07452 if (check_use_this_motion_notify (window,
07453 event))
07454 update_resize (window,
07455 event->xmotion.state & ShiftMask,
07456 event->xmotion.x_root,
07457 event->xmotion.y_root,
07458 FALSE);
07459 }
07460 }
07461 break;
07462
07463 default:
07464 break;
07465 }
07466 }
07467
07468 void
07469 meta_window_set_gravity (MetaWindow *window,
07470 int gravity)
07471 {
07472 XSetWindowAttributes attrs;
07473
07474 meta_verbose ("Setting gravity of %s to %d\n", window->desc, gravity);
07475
07476 attrs.win_gravity = gravity;
07477
07478 meta_error_trap_push (window->display);
07479
07480 XChangeWindowAttributes (window->display->xdisplay,
07481 window->xwindow,
07482 CWWinGravity,
07483 &attrs);
07484
07485 meta_error_trap_pop (window->display, FALSE);
07486 }
07487
07488 static void
07489 get_work_area_xinerama (MetaWindow *window,
07490 MetaRectangle *area,
07491 int which_xinerama)
07492 {
07493 GList *tmp;
07494
07495 g_assert (which_xinerama >= 0);
07496
07497
07498 *area = window->screen->xinerama_infos[which_xinerama].rect;
07499
07500 tmp = meta_window_get_workspaces (window);
07501 while (tmp != NULL)
07502 {
07503 MetaRectangle workspace_work_area;
07504 meta_workspace_get_work_area_for_xinerama (tmp->data,
07505 which_xinerama,
07506 &workspace_work_area);
07507 meta_rectangle_intersect (area,
07508 &workspace_work_area,
07509 area);
07510 tmp = tmp->next;
07511 }
07512
07513 meta_topic (META_DEBUG_WORKAREA,
07514 "Window %s xinerama %d has work area %d,%d %d x %d\n",
07515 window->desc, which_xinerama,
07516 area->x, area->y, area->width, area->height);
07517 }
07518
07519 void
07520 meta_window_get_work_area_current_xinerama (MetaWindow *window,
07521 MetaRectangle *area)
07522 {
07523 const MetaXineramaScreenInfo *xinerama = NULL;
07524 xinerama = meta_screen_get_xinerama_for_window (window->screen,
07525 window);
07526
07527 meta_window_get_work_area_for_xinerama (window,
07528 xinerama->number,
07529 area);
07530 }
07531
07532 void
07533 meta_window_get_work_area_for_xinerama (MetaWindow *window,
07534 int which_xinerama,
07535 MetaRectangle *area)
07536 {
07537 g_return_if_fail (which_xinerama >= 0);
07538
07539 get_work_area_xinerama (window,
07540 area,
07541 which_xinerama);
07542 }
07543
07544 void
07545 meta_window_get_work_area_all_xineramas (MetaWindow *window,
07546 MetaRectangle *area)
07547 {
07548 GList *tmp;
07549
07550
07551 *area = window->screen->rect;
07552
07553 tmp = meta_window_get_workspaces (window);
07554 while (tmp != NULL)
07555 {
07556 MetaRectangle workspace_work_area;
07557 meta_workspace_get_work_area_all_xineramas (tmp->data,
07558 &workspace_work_area);
07559 meta_rectangle_intersect (area,
07560 &workspace_work_area,
07561 area);
07562 tmp = tmp->next;
07563 }
07564
07565 meta_topic (META_DEBUG_WORKAREA,
07566 "Window %s has whole-screen work area %d,%d %d x %d\n",
07567 window->desc, area->x, area->y, area->width, area->height);
07568 }
07569
07570
07571 gboolean
07572 meta_window_same_application (MetaWindow *window,
07573 MetaWindow *other_window)
07574 {
07575 MetaGroup *group = meta_window_get_group (window);
07576 MetaGroup *other_group = meta_window_get_group (other_window);
07577
07578 return
07579 group!=NULL &&
07580 other_group!=NULL &&
07581 group==other_group;
07582 }
07583
07584 void
07585 meta_window_refresh_resize_popup (MetaWindow *window)
07586 {
07587 if (window->display->grab_op == META_GRAB_OP_NONE)
07588 return;
07589
07590 if (window->display->grab_window != window)
07591 return;
07592
07593
07594
07595
07596 if (window->display->grab_wireframe_active)
07597 {
07598 meta_topic (META_DEBUG_WINDOW_OPS,
07599 "refresh_resize_popup called when wireframe active\n");
07600 return;
07601 }
07602
07603 switch (window->display->grab_op)
07604 {
07605 case META_GRAB_OP_RESIZING_SE:
07606 case META_GRAB_OP_RESIZING_S:
07607 case META_GRAB_OP_RESIZING_SW:
07608 case META_GRAB_OP_RESIZING_N:
07609 case META_GRAB_OP_RESIZING_NE:
07610 case META_GRAB_OP_RESIZING_NW:
07611 case META_GRAB_OP_RESIZING_W:
07612 case META_GRAB_OP_RESIZING_E:
07613 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
07614 case META_GRAB_OP_KEYBOARD_RESIZING_S:
07615 case META_GRAB_OP_KEYBOARD_RESIZING_N:
07616 case META_GRAB_OP_KEYBOARD_RESIZING_W:
07617 case META_GRAB_OP_KEYBOARD_RESIZING_E:
07618 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
07619 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
07620 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
07621 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
07622 break;
07623
07624 default:
07625
07626 return;
07627 }
07628
07629 if (window->display->grab_resize_popup == NULL)
07630 {
07631 if (window->size_hints.width_inc > 1 ||
07632 window->size_hints.height_inc > 1)
07633 window->display->grab_resize_popup =
07634 meta_ui_resize_popup_new (window->display->xdisplay,
07635 window->screen->number);
07636 }
07637
07638 if (window->display->grab_resize_popup != NULL)
07639 {
07640 MetaRectangle rect;
07641
07642 if (window->display->grab_wireframe_active)
07643 rect = window->display->grab_wireframe_rect;
07644 else
07645 meta_window_get_client_root_coords (window, &rect);
07646
07647 meta_ui_resize_popup_set (window->display->grab_resize_popup,
07648 rect,
07649 window->size_hints.base_width,
07650 window->size_hints.base_height,
07651 window->size_hints.width_inc,
07652 window->size_hints.height_inc);
07653
07654 meta_ui_resize_popup_set_showing (window->display->grab_resize_popup,
07655 TRUE);
07656 }
07657 }
07658
07659 void
07660 meta_window_foreach_transient (MetaWindow *window,
07661 MetaWindowForeachFunc func,
07662 void *data)
07663 {
07664 GSList *windows;
07665 GSList *tmp;
07666
07667 windows = meta_display_list_windows (window->display);
07668
07669 tmp = windows;
07670 while (tmp != NULL)
07671 {
07672 MetaWindow *transient = tmp->data;
07673
07674 if (meta_window_is_ancestor_of_transient (window, transient))
07675 {
07676 if (!(* func) (transient, data))
07677 break;
07678 }
07679
07680 tmp = tmp->next;
07681 }
07682
07683 g_slist_free (windows);
07684 }
07685
07686 void
07687 meta_window_foreach_ancestor (MetaWindow *window,
07688 MetaWindowForeachFunc func,
07689 void *data)
07690 {
07691 MetaWindow *w;
07692 MetaWindow *tortoise;
07693
07694 w = window;
07695 tortoise = window;
07696 while (TRUE)
07697 {
07698 if (w->xtransient_for == None ||
07699 w->transient_parent_is_root_window)
07700 break;
07701
07702 w = meta_display_lookup_x_window (w->display, w->xtransient_for);
07703
07704 if (w == NULL || w == tortoise)
07705 break;
07706
07707 if (!(* func) (w, data))
07708 break;
07709
07710 if (w->xtransient_for == None ||
07711 w->transient_parent_is_root_window)
07712 break;
07713
07714 w = meta_display_lookup_x_window (w->display, w->xtransient_for);
07715
07716 if (w == NULL || w == tortoise)
07717 break;
07718
07719 if (!(* func) (w, data))
07720 break;
07721
07722 tortoise = meta_display_lookup_x_window (tortoise->display,
07723 tortoise->xtransient_for);
07724
07725
07726
07727
07728 g_assert (tortoise != NULL);
07729 g_assert (tortoise->xtransient_for != None);
07730 g_assert (!tortoise->transient_parent_is_root_window);
07731 }
07732 }
07733
07734 typedef struct
07735 {
07736 MetaWindow *ancestor;
07737 gboolean found;
07738 } FindAncestorData;
07739
07740 static gboolean
07741 find_ancestor_func (MetaWindow *window,
07742 void *data)
07743 {
07744 FindAncestorData *d = data;
07745
07746 if (window == d->ancestor)
07747 {
07748 d->found = TRUE;
07749 return FALSE;
07750 }
07751
07752 return TRUE;
07753 }
07754
07755 gboolean
07756 meta_window_is_ancestor_of_transient (MetaWindow *window,
07757 MetaWindow *transient)
07758 {
07759 FindAncestorData d;
07760
07761 d.ancestor = window;
07762 d.found = FALSE;
07763
07764 meta_window_foreach_ancestor (transient, find_ancestor_func, &d);
07765
07766 return d.found;
07767 }
07768
07769
07770
07771
07772 static gboolean
07773 warp_grab_pointer (MetaWindow *window,
07774 MetaGrabOp grab_op,
07775 int *x,
07776 int *y)
07777 {
07778 MetaRectangle rect;
07779 MetaDisplay *display;
07780
07781 display = window->display;
07782
07783
07784
07785
07786 if (window == display->grab_window && display->grab_wireframe_active)
07787 {
07788 meta_window_get_xor_rect (window, &display->grab_wireframe_rect, &rect);
07789 }
07790 else
07791 {
07792 meta_window_get_outer_rect (window, &rect);
07793 }
07794
07795 switch (grab_op)
07796 {
07797 case META_GRAB_OP_KEYBOARD_MOVING:
07798 case META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN:
07799 *x = rect.width / 2;
07800 *y = rect.height / 2;
07801 break;
07802
07803 case META_GRAB_OP_KEYBOARD_RESIZING_S:
07804 *x = rect.width / 2;
07805 *y = rect.height - 1;
07806 break;
07807
07808 case META_GRAB_OP_KEYBOARD_RESIZING_N:
07809 *x = rect.width / 2;
07810 *y = 0;
07811 break;
07812
07813 case META_GRAB_OP_KEYBOARD_RESIZING_W:
07814 *x = 0;
07815 *y = rect.height / 2;
07816 break;
07817
07818 case META_GRAB_OP_KEYBOARD_RESIZING_E:
07819 *x = rect.width - 1;
07820 *y = rect.height / 2;
07821 break;
07822
07823 case META_GRAB_OP_KEYBOARD_RESIZING_SE:
07824 *x = rect.width - 1;
07825 *y = rect.height - 1;
07826 break;
07827
07828 case META_GRAB_OP_KEYBOARD_RESIZING_NE:
07829 *x = rect.width - 1;
07830 *y = 0;
07831 break;
07832
07833 case META_GRAB_OP_KEYBOARD_RESIZING_SW:
07834 *x = 0;
07835 *y = rect.height - 1;
07836 break;
07837
07838 case META_GRAB_OP_KEYBOARD_RESIZING_NW:
07839 *x = 0;
07840 *y = 0;
07841 break;
07842
07843 default:
07844 return FALSE;
07845 }
07846
07847 *x += rect.x;
07848 *y += rect.y;
07849
07850
07851 *x = CLAMP (*x, 0, window->screen->rect.width-1);
07852 *y = CLAMP (*y, 0, window->screen->rect.height-1);
07853
07854 meta_error_trap_push_with_return (display);
07855
07856 meta_topic (META_DEBUG_WINDOW_OPS,
07857 "Warping pointer to %d,%d with window at %d,%d\n",
07858 *x, *y, rect.x, rect.y);
07859
07860
07861
07862
07863
07864 display->grab_anchor_root_x = *x;
07865 display->grab_anchor_root_y = *y;
07866 display->grab_latest_motion_x = *x;
07867 display->grab_latest_motion_y = *y;
07868 if (display->grab_wireframe_active)
07869 display->grab_anchor_window_pos = display->grab_wireframe_rect;
07870 else
07871 meta_window_get_client_root_coords (window,
07872 &display->grab_anchor_window_pos);
07873
07874 XWarpPointer (display->xdisplay,
07875 None,
07876 window->screen->xroot,
07877 0, 0, 0, 0,
07878 *x, *y);
07879
07880 if (meta_error_trap_pop_with_return (display, FALSE) != Success)
07881 {
07882 meta_verbose ("Failed to warp pointer for window %s\n",
07883 window->desc);
07884 return FALSE;
07885 }
07886
07887 return TRUE;
07888 }
07889
07890 void
07891 meta_window_begin_grab_op (MetaWindow *window,
07892 MetaGrabOp op,
07893 gboolean frame_action,
07894 guint32 timestamp)
07895 {
07896 int x, y;
07897
07898 warp_grab_pointer (window,
07899 op, &x, &y);
07900
07901 meta_display_begin_grab_op (window->display,
07902 window->screen,
07903 window,
07904 op,
07905 FALSE,
07906 frame_action,
07907 0 ,
07908 0,
07909 timestamp,
07910 x, y);
07911 }
07912
07913 void
07914 meta_window_update_keyboard_resize (MetaWindow *window,
07915 gboolean update_cursor)
07916 {
07917 int x, y;
07918
07919 warp_grab_pointer (window,
07920 window->display->grab_op,
07921 &x, &y);
07922
07923 if (update_cursor)
07924 {
07925 guint32 timestamp;
07926
07927 timestamp = CurrentTime;
07928 meta_display_set_grab_op_cursor (window->display,
07929 NULL,
07930 window->display->grab_op,
07931 TRUE,
07932 window->display->grab_xwindow,
07933 timestamp);
07934 }
07935 }
07936
07937 void
07938 meta_window_update_keyboard_move (MetaWindow *window)
07939 {
07940 int x, y;
07941
07942 warp_grab_pointer (window,
07943 window->display->grab_op,
07944 &x, &y);
07945 }
07946
07947 void
07948 meta_window_update_layer (MetaWindow *window)
07949 {
07950 MetaGroup *group;
07951
07952 meta_stack_freeze (window->screen->stack);
07953 group = meta_window_get_group (window);
07954 if (group)
07955 meta_group_update_layers (group);
07956 else
07957 meta_stack_update_layer (window->screen->stack, window);
07958 meta_stack_thaw (window->screen->stack);
07959 }
07960
07961
07962
07963
07964
07965 static void
07966 ensure_mru_position_after (MetaWindow *window,
07967 MetaWindow *after_this_one)
07968 {
07969
07970
07971
07972
07973
07974
07975
07976 GList* active_mru_list;
07977 GList* window_position;
07978 GList* after_this_one_position;
07979
07980 active_mru_list = window->screen->active_workspace->mru_list;
07981 window_position = g_list_find (active_mru_list, window);
07982 after_this_one_position = g_list_find (active_mru_list, after_this_one);
07983
07984
07985
07986
07987
07988 if (after_this_one_position == NULL)
07989 return;
07990
07991 if (g_list_length (window_position) > g_list_length (after_this_one_position))
07992 {
07993 window->screen->active_workspace->mru_list =
07994 g_list_delete_link (window->screen->active_workspace->mru_list,
07995 window_position);
07996
07997 window->screen->active_workspace->mru_list =
07998 g_list_insert_before (window->screen->active_workspace->mru_list,
07999 after_this_one_position->next,
08000 window);
08001 }
08002 }
08003
08004 void
08005 meta_window_stack_just_below (MetaWindow *window,
08006 MetaWindow *below_this_one)
08007 {
08008 g_return_if_fail (window != NULL);
08009 g_return_if_fail (below_this_one != NULL);
08010
08011 if (window->stack_position > below_this_one->stack_position)
08012 {
08013 meta_topic (META_DEBUG_STACK,
08014 "Setting stack position of window %s to %d (making it below window %s).\n",
08015 window->desc,
08016 below_this_one->stack_position,
08017 below_this_one->desc);
08018 meta_window_set_stack_position (window, below_this_one->stack_position);
08019 }
08020 else
08021 {
08022 meta_topic (META_DEBUG_STACK,
08023 "Window %s was already below window %s.\n",
08024 window->desc, below_this_one->desc);
08025 }
08026 }
08027
08028 void
08029 meta_window_set_user_time (MetaWindow *window,
08030 guint32 timestamp)
08031 {
08032
08033
08034
08035
08036
08037
08038 if (window->net_wm_user_time_set &&
08039 XSERVER_TIME_IS_BEFORE (timestamp, window->net_wm_user_time))
08040 {
08041 meta_topic (META_DEBUG_STARTUP,
08042 "Window %s _NET_WM_USER_TIME not updated to %u, because it "
08043 "is less than %u\n",
08044 window->desc, timestamp, window->net_wm_user_time);
08045 }
08046 else
08047 {
08048 meta_topic (META_DEBUG_STARTUP,
08049 "Window %s has _NET_WM_USER_TIME of %u\n",
08050 window->desc, timestamp);
08051 window->net_wm_user_time_set = TRUE;
08052 window->net_wm_user_time = timestamp;
08053 if (XSERVER_TIME_IS_BEFORE (window->display->last_user_time, timestamp))
08054 window->display->last_user_time = timestamp;
08055
08056
08057
08058
08059 if (meta_prefs_get_focus_new_windows () ==
08060 META_FOCUS_NEW_WINDOWS_STRICT &&
08061 __window_is_terminal (window))
08062 window->display->allow_terminal_deactivation = FALSE;
08063 }
08064 }
08065
08066
08067
08068
08069 void
08070 meta_window_set_demands_attention (MetaWindow *window)
08071 {
08072 MetaRectangle candidate_rect, other_rect;
08073 GList *stack = window->screen->stack->sorted;
08074 MetaWindow *other_window;
08075 gboolean obscured = FALSE;
08076
08077 MetaWorkspace *workspace = window->screen->active_workspace;
08078 if (workspace!=window->workspace)
08079 {
08080
08081 obscured = TRUE;
08082 }
08083 else
08084 {
08085 meta_window_get_outer_rect (window, &candidate_rect);
08086
08087
08088
08089 while (stack != NULL && stack->data != window)
08090 {
08091 other_window = stack->data;
08092 stack = stack->next;
08093
08094 if (other_window->on_all_workspaces ||
08095 window->on_all_workspaces ||
08096 other_window->workspace == window->workspace)
08097 {
08098 meta_window_get_outer_rect (other_window, &other_rect);
08099
08100 if (meta_rectangle_overlap (&candidate_rect, &other_rect))
08101 {
08102 obscured = TRUE;
08103 break;
08104 }
08105 }
08106 }
08107
08108
08109 meta_topic (META_DEBUG_WINDOW_OPS,
08110 "Not marking %s as needing attention because it's in full view\n",
08111 window->desc);
08112 return;
08113 }
08114
08115
08116
08117 meta_topic (META_DEBUG_WINDOW_OPS,
08118 "Marking %s as needing attention\n", window->desc);
08119
08120 window->wm_state_demands_attention = TRUE;
08121 set_net_wm_state (window);
08122 }
08123
08124 void
08125 meta_window_unset_demands_attention (MetaWindow *window)
08126 {
08127 meta_topic (META_DEBUG_WINDOW_OPS,
08128 "Marking %s as not needing attention\n", window->desc);
08129
08130 window->wm_state_demands_attention = FALSE;
08131 set_net_wm_state (window);
08132 }
08133
08134 MetaFrame *
08135 meta_window_get_frame (MetaWindow *window)
08136 {
08137 return window->frame;
08138 }
08139
08140 gboolean
08141 meta_window_has_focus (MetaWindow *window)
08142 {
08143 return window->has_focus;
08144 }
08145
08146 gboolean
08147 meta_window_is_shaded (MetaWindow *window)
08148 {
08149 return window->shaded;
08150 }
08151
08152 MetaRectangle *
08153 meta_window_get_rect (MetaWindow *window)
08154 {
08155 return &window->rect;
08156 }
08157
08158 MetaScreen *
08159 meta_window_get_screen (MetaWindow *window)
08160 {
08161 return window->screen;
08162 }
08163
08164 MetaDisplay *
08165 meta_window_get_display (MetaWindow *window)
08166 {
08167 return window->display;
08168 }
08169
08170 Window
08171 meta_window_get_xwindow (MetaWindow *window)
08172 {
08173 return window->xwindow;
08174 }