diff --git a/src/display.c b/src/display.c index 1d56840a4..ec14ee3b4 100644 --- a/src/display.c +++ b/src/display.c @@ -370,6 +370,8 @@ meta_display_grab (MetaDisplay *display) } XSync (display->xdisplay, False); display->server_grab_count += 1; + meta_verbose ("Grabbing display, grab count now %d\n", + display->server_grab_count); } void @@ -384,10 +386,13 @@ meta_display_ungrab (MetaDisplay *display) /* FIXME we want to purge all pending "queued" stuff * at this point, such as window hide/show */ - + XSync (display->xdisplay, False); XUngrabServer (display->xdisplay); } XSync (display->xdisplay, False); + + meta_verbose ("Ungrabbing display, grab count now %d\n", + display->server_grab_count); } MetaDisplay* @@ -532,16 +537,23 @@ event_queue_callback (MetaEventQueue *queue, meta_window_free (window); /* Unmanage destroyed window */ break; case UnmapNotify: - if (window && window->mapped) + if (window) { - meta_verbose ("Window %s withdrawn\n", - window->desc); - meta_window_free (window); /* Unmanage withdrawn window */ + if (window->unmaps_pending == 0) + { + meta_verbose ("Window %s withdrawn\n", + window->desc); + meta_window_free (window); /* Unmanage withdrawn window */ + } + else + { + window->unmaps_pending -= 1; + meta_verbose ("Received pending unmap, %d now pending\n", + window->unmaps_pending); + } } break; case MapNotify: - if (window) - window->mapped = TRUE; break; case MapRequest: if (window == NULL) @@ -809,7 +821,7 @@ meta_spew_event (MetaDisplay *display, break; case EnterNotify: name = "EnterNotify"; - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %d detail: %d\n", + extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %d detail: %d", event->xcrossing.window, event->xcrossing.root, event->xcrossing.subwindow, @@ -818,7 +830,7 @@ meta_spew_event (MetaDisplay *display, break; case LeaveNotify: name = "LeaveNotify"; - extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %d detail: %d\n", + extra = g_strdup_printf ("win: 0x%lx root: 0x%lx subwindow: 0x%lx mode: %d detail: %d", event->xcrossing.window, event->xcrossing.root, event->xcrossing.subwindow, @@ -903,7 +915,29 @@ meta_spew_event (MetaDisplay *display, name = "CirculateRequest"; break; case PropertyNotify: - name = "PropertyNotify"; + { + char *str; + const char *state; + + name = "PropertyNotify"; + + meta_error_trap_push (display); + str = XGetAtomName (display->xdisplay, + event->xproperty.atom); + meta_error_trap_pop (display); + + if (event->xproperty.state == PropertyNewValue) + state = "PropertyNewValue"; + else if (event->xproperty.state == PropertyDelete) + state = "PropertyDelete"; + else + state = "(????)"; + + extra = g_strdup_printf ("atom: %s state: %s", + str ? str : "(unknown atom)", + state); + XFree (str); + } break; case SelectionClear: name = "SelectionClear"; diff --git a/src/frame.c b/src/frame.c index 4e9d0bb3a..fc424aeea 100644 --- a/src/frame.c +++ b/src/frame.c @@ -84,74 +84,24 @@ meta_frame_init_info (MetaFrame *frame, info->current_control_state = META_STATE_PRELIGHT; } - -/* returns values suitable for meta_window_move */ -void -meta_frame_adjust_for_gravity (int win_gravity, - int frame_width, - int frame_height, - MetaFrameGeometry *fgeom, - int child_root_x, - int child_root_y, - int *win_root_x, - int *win_root_y) +static void +pango_hack_start (MetaDisplay *display) { - int x, y; - - /* NW coordinate of the frame. We should just - * compute NW coordinate to return from the start, - * but I wrote it this way first and am now lazy - */ - x = 0; - y = 0; - - switch (win_gravity) + if (display->server_grab_count > 0) { - case NorthWestGravity: - x = child_root_x; - y = child_root_y; - break; - case NorthGravity: - x = child_root_x - frame_width / 2; - y = child_root_y; - break; - case NorthEastGravity: - x = child_root_x - frame_width; - y = child_root_y; - break; - case WestGravity: - x = child_root_x; - y = child_root_y - frame_height / 2; - break; - case CenterGravity: - x = child_root_x - frame_width / 2; - y = child_root_y - frame_height / 2; - break; - case EastGravity: - x = child_root_x - frame_width; - y = child_root_y - frame_height / 2; - break; - case SouthWestGravity: - x = child_root_x; - y = child_root_y - frame_height; - break; - case SouthGravity: - x = child_root_x - frame_width / 2; - y = child_root_y - frame_height; - break; - case SouthEastGravity: - x = child_root_x - frame_width; - y = child_root_y - frame_height; - break; - case StaticGravity: - default: - x = child_root_x - fgeom->left_width; - y = child_root_y - fgeom->top_height; - break; + meta_verbose ("Pango workaround, ungrabbing server\n"); + XUngrabServer (display->xdisplay); } +} - *win_root_x = x + fgeom->left_width; - *win_root_y = y + fgeom->top_height; +static void +pango_hack_end (MetaDisplay *display) +{ + if (display->server_grab_count > 0) + { + meta_verbose ("Pango workaround, regrabbing server\n"); + XGrabServer (display->xdisplay); + } } void @@ -193,8 +143,10 @@ meta_frame_calc_geometry (MetaFrame *frame, geom.shape_mask = None; + pango_hack_start (frame->window->display); window->screen->engine->fill_frame_geometry (&info, &geom, frame->theme_data); + pango_hack_end (frame->window->display); *geomp = geom; } @@ -242,6 +194,8 @@ meta_window_ensure_frame (MetaWindow *window) { MetaFrame *frame; XSetWindowAttributes attrs; + + g_return_if_fail (window->display->server_grab_count > 0); if (window->frame) return; @@ -286,16 +240,16 @@ meta_window_ensure_frame (MetaWindow *window) /* Reparent the client window; it may be destroyed, * thus the error trap. We'll get a destroy notify later * and free everything. Comment in FVWM source code says - * we need the server grab or the child can get its MapNotify + * we need a server grab or the child can get its MapNotify * before we've finished reparenting and getting the decoration - * window onscreen. + * window onscreen, so ensure_frame must be called with + * a grab. */ - meta_display_grab (window->display); - meta_error_trap_push (window->display); window->mapped = FALSE; /* the reparent will unmap the window, * we don't want to take that as a withdraw */ + window->unmaps_pending += 1; XReparentWindow (window->display->xdisplay, window->xwindow, frame->xwindow, @@ -304,11 +258,6 @@ meta_window_ensure_frame (MetaWindow *window) /* stick frame to the window */ window->frame = frame; - - /* Ungrab server (FIXME after fixing Pango not to lock us up, - * we need to recalc geometry before ungrabbing) - */ - meta_display_ungrab (window->display); } void @@ -339,6 +288,7 @@ meta_window_destroy_frame (MetaWindow *window) * can identify a withdraw initiated * by the client. */ + window->unmaps_pending += 1; XReparentWindow (window->display->xdisplay, window->xwindow, window->screen->xroot, @@ -366,9 +316,11 @@ meta_frame_sync_to_window (MetaFrame *frame, gboolean need_move, gboolean need_resize) { - meta_verbose ("Syncing frame geometry %d,%d %dx%d pixel %ld\n", + meta_verbose ("Syncing frame geometry %d,%d %dx%d (SE: %d,%d) pixel %ld\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height, + frame->rect.x + frame->rect.width, + frame->rect.y + frame->rect.height, frame->bg_pixel); /* set bg to none to avoid flicker */ @@ -439,10 +391,12 @@ meta_frame_draw_now (MetaFrame *frame, info.drawable = p; info.xoffset = - x; info.yoffset = - y; + pango_hack_start (frame->window->display); frame->window->screen->engine->expose_frame (&info, 0, 0, width, height, frame->theme_data); - + pango_hack_end (frame->window->display); + XCopyArea (frame->window->display->xdisplay, p, frame->xwindow, @@ -609,7 +563,8 @@ update_move (MetaFrame *frame, dx = x - frame->grab->start_root_x; dy = y - frame->grab->start_root_y; - + + frame->window->user_has_moved = TRUE; meta_window_move (frame->window, frame->grab->start_window_x + dx, frame->grab->start_window_y + dy); @@ -623,7 +578,8 @@ update_resize_se (MetaFrame *frame, dx = x - frame->grab->start_root_x; dy = y - frame->grab->start_root_y; - + + frame->window->user_has_resized = TRUE; meta_window_resize (frame->window, frame->grab->start_window_x + dx, frame->grab->start_window_y + dy); diff --git a/src/frame.h b/src/frame.h index 4947142ef..83cfda341 100644 --- a/src/frame.h +++ b/src/frame.h @@ -76,15 +76,6 @@ void meta_frame_calc_geometry (MetaFrame *frame, int child_width, int child_height, MetaFrameGeometry *geomp); -/* returns values suitable for meta_window_move */ -void meta_frame_adjust_for_gravity (int win_gravity, - int frame_width, - int frame_height, - MetaFrameGeometry *fgeom, - int x, - int y, - int *win_root_x, - int *win_root_y); void meta_frame_sync_to_window (MetaFrame *frame, gboolean need_move, gboolean need_resize); diff --git a/src/run-metacity.sh b/src/run-metacity.sh index 24e0489f5..9f150c46f 100755 --- a/src/run-metacity.sh +++ b/src/run-metacity.sh @@ -9,7 +9,19 @@ elif test -z "$DEBUG"; then DEBUG=gdb fi +if test -z "$CLIENTS"; then + CLIENTS=0 +fi + Xnest :1 -scrns $SCREENS -geometry 640x480 -bw 15 & usleep 50000 + +if test $CLIENTS != 0; then + for I in `seq 1 $CLIENTS`; do + DISPLAY=:1 xterm -geometry 25x15 & + done +fi + +DISPLAY=:1 xsetroot -solid royalblue3 METACITY_UISLAVE_DIR=./uislave DISPLAY=:1 unst libtool --mode=execute $DEBUG ./metacity killall Xnest diff --git a/src/screen.c b/src/screen.c index a13f9a3ee..90f75d276 100644 --- a/src/screen.c +++ b/src/screen.c @@ -239,7 +239,8 @@ meta_screen_manage_all_windows (MetaScreen *screen) meta_display_ungrab (screen->display); return; } - + + meta_stack_freeze (screen->stack); i = 0; while (i < n_children) { @@ -247,6 +248,7 @@ meta_screen_manage_all_windows (MetaScreen *screen) ++i; } + meta_stack_thaw (screen->stack); meta_display_ungrab (screen->display); diff --git a/src/theme.c b/src/theme.c index 11f911e32..c80c2a3fb 100644 --- a/src/theme.c +++ b/src/theme.c @@ -309,7 +309,7 @@ calc_geometry (MetaFrameInfo *info, if (fgeom->title_rect.width < 0) fgeom->title_rect.width = 0; } - + static void default_fill_frame_geometry (MetaFrameInfo *info, MetaFrameGeometry *geom, diff --git a/src/window.c b/src/window.c index 809bce75c..a63b2ec20 100644 --- a/src/window.c +++ b/src/window.c @@ -29,6 +29,7 @@ #include static void constrain_size (MetaWindow *window, + MetaFrameGeometry *fgeom, int width, int height, int *new_width, @@ -82,19 +83,32 @@ meta_window_new (MetaDisplay *display, Window xwindow) GSList *tmp; meta_verbose ("Attempting to manage 0x%lx\n", xwindow); + + /* Grab server */ + meta_display_grab (display); - /* round trip */ meta_error_trap_push (display); - if (XGetWindowAttributes (display->xdisplay, - xwindow, &attrs) == Success && - attrs.override_redirect) + XGetWindowAttributes (display->xdisplay, + xwindow, &attrs); + + if (meta_error_trap_pop (display)) { - meta_verbose ("Deciding not to manage override_redirect window 0x%lx\n", xwindow); - meta_error_trap_pop (display); + meta_verbose ("Failed to get attributes for window 0x%lx\n", + xwindow); + meta_display_ungrab (display); return NULL; } + if (attrs.override_redirect) + { + meta_verbose ("Deciding not to manage override_redirect window 0x%lx\n", xwindow); + meta_display_ungrab (display); + return NULL; + } + + meta_error_trap_push (display); + XAddToSaveSet (display->xdisplay, xwindow); XSelectInput (display->xdisplay, xwindow, @@ -110,9 +124,11 @@ meta_window_new (MetaDisplay *display, Window xwindow) { meta_verbose ("Window 0x%lx disappeared just as we tried to manage it\n", xwindow); - + meta_display_ungrab (display); return NULL; } + + g_assert (!attrs.override_redirect); window = g_new (MetaWindow, 1); @@ -139,6 +155,9 @@ meta_window_new (MetaDisplay *display, Window xwindow) g_assert (window->screen); + /* avoid tons of stack updates */ + meta_stack_freeze (window->screen->stack); + /* Remember this rect is the actual window size */ window->rect.x = attrs.x; window->rect.y = attrs.y; @@ -165,6 +184,9 @@ meta_window_new (MetaDisplay *display, Window xwindow) window->frame = NULL; window->has_focus = FALSE; + window->user_has_resized = FALSE; + window->user_has_moved = FALSE; + window->maximized = FALSE; window->on_all_workspaces = FALSE; window->shaded = FALSE; @@ -173,6 +195,8 @@ meta_window_new (MetaDisplay *display, Window xwindow) window->iconic = FALSE; window->mapped = FALSE; + window->unmaps_pending = 0; + window->decorated = TRUE; window->has_close_func = TRUE; window->has_minimize_func = TRUE; @@ -220,7 +244,8 @@ meta_window_new (MetaDisplay *display, Window xwindow) * change it again. */ set_wm_state (window, window->iconic ? IconicState : NormalState); - + set_net_wm_state (window); + if (window->decorated) meta_window_ensure_frame (window); @@ -238,8 +263,13 @@ meta_window_new (MetaDisplay *display, Window xwindow) meta_stack_add (window->screen->stack, window); - + + /* Sync stack changes */ + meta_stack_thaw (window->screen->stack); + meta_window_queue_calc_showing (window); + + meta_display_ungrab (display); return window; } @@ -294,18 +324,54 @@ static int set_wm_state (MetaWindow *window, int state) { - unsigned long data[1]; + unsigned long data[2]; /* twm sets the icon window as data[1], I couldn't find that in * ICCCM. */ data[0] = state; + data[1] = None; meta_error_trap_push (window->display); XChangeProperty (window->display->xdisplay, window->xwindow, window->display->atom_wm_state, window->display->atom_wm_state, - 32, PropModeReplace, (guchar*) data, 1); + 32, PropModeReplace, (guchar*) data, 2); + return meta_error_trap_pop (window->display); +} + +static int +set_net_wm_state (MetaWindow *window) +{ + int i; + unsigned long data[10]; + + i = 0; + if (window->shaded) + { + data[i] = window->display->atom_net_wm_state_shaded; + ++i; + } + if (window->wm_state_modal) + { + data[i] = window->display->atom_net_wm_state_modal; + ++i; + } + if (window->maximized) + { + data[i] = window->display->atom_net_wm_state_maximized_horz; + ++i; + data[i] = window->display->atom_net_wm_state_maximized_vert; + ++i; + } + + meta_verbose ("Setting _NET_WM_STATE with %d atoms\n", i); + + meta_error_trap_push (window->display); + XChangeProperty (window->display->xdisplay, window->xwindow, + window->display->atom_net_wm_state, + XA_ATOM, + 32, PropModeReplace, (guchar*) data, i); return meta_error_trap_pop (window->display); } @@ -370,6 +436,7 @@ meta_window_show (MetaWindow *window) { meta_verbose ("%s actually needs unmap\n", window->desc); window->mapped = FALSE; + window->unmaps_pending += 1; meta_error_trap_push (window->display); XUnmapWindow (window->display->xdisplay, window->xwindow); meta_error_trap_pop (window->display); @@ -416,6 +483,7 @@ meta_window_hide (MetaWindow *window) { meta_verbose ("%s actually needs unmap\n", window->desc); window->mapped = FALSE; + window->unmaps_pending += 1; XUnmapWindow (window->display->xdisplay, window->xwindow); } @@ -464,6 +532,8 @@ meta_window_maximize (MetaWindow *window) /* move_resize with new maximization constraints */ meta_window_queue_move_resize (window); + + set_net_wm_state (window); } } @@ -479,6 +549,8 @@ meta_window_unmaximize (MetaWindow *window) window->saved_rect.y, window->saved_rect.width, window->saved_rect.height); + + set_net_wm_state (window); } } @@ -490,6 +562,8 @@ meta_window_shade (MetaWindow *window) window->shaded = TRUE; meta_window_queue_move_resize (window); meta_window_queue_calc_showing (window); + + set_net_wm_state (window); } } @@ -504,6 +578,142 @@ meta_window_unshade (MetaWindow *window) /* focus the window */ /* FIXME CurrentTime is bogus */ meta_window_focus (window, CurrentTime); + + set_net_wm_state (window); + } +} + + +/* returns values suitable for meta_window_move */ +void +adjust_for_gravity (MetaWindow *window, + MetaFrameGeometry *fgeom, + gboolean coords_assume_border, + int x, + int y, + int *xp, + int *yp) +{ + int ref_x, ref_y; + int bw; + int child_x, child_y; + int frame_width, frame_height; + + if (coords_assume_border) + bw = window->border_width; + else + bw = 0; + + if (fgeom) + { + child_x = fgeom->left_width; + child_y = fgeom->top_height; + frame_width = child_x + window->rect.width + fgeom->right_width; + frame_height = child_y + window->rect.height + fgeom->bottom_height; + } + else + { + child_x = 0; + child_y = 0; + frame_width = window->rect.width; + frame_height = window->rect.height; + } + + /* We're computing position to pass to window_move, which is + * the position of the client window (StaticGravity basically) + * + * (see WM spec description of gravity computation, but note that + * their formulas assume we're honoring the border width, rather + * than compensating for having turned it off) + */ + switch (window->size_hints.win_gravity) + { + case NorthWestGravity: + ref_x = x; + ref_y = y; + break; + case NorthGravity: + ref_x = x + window->rect.width / 2 + bw; + ref_y = y; + break; + case NorthEastGravity: + ref_x = x + window->rect.width + bw * 2; + ref_y = y; + break; + case WestGravity: + ref_x = x; + ref_y = y + window->rect.height / 2 + bw; + break; + case CenterGravity: + ref_x = x + window->rect.width / 2 + bw; + ref_y = y + window->rect.height / 2 + bw; + break; + case EastGravity: + ref_x = x + window->rect.width + bw * 2; + ref_y = y + window->rect.height / 2 + bw; + break; + case SouthWestGravity: + ref_x = x; + ref_y = y + window->rect.height + bw * 2; + break; + case SouthGravity: + ref_x = x + window->rect.width / 2 + bw; + ref_y = y + window->rect.height + bw * 2; + break; + case SouthEastGravity: + ref_x = x + window->rect.width + bw * 2; + ref_y = y + window->rect.height + bw * 2; + break; + case StaticGravity: + default: + ref_x = x; + ref_y = y; + break; + } + + switch (window->size_hints.win_gravity) + { + case NorthWestGravity: + *xp = ref_x + child_x; + *yp = ref_y + child_y; + break; + case NorthGravity: + *xp = ref_x - frame_width / 2 + child_x; + *yp = ref_y + child_y; + break; + case NorthEastGravity: + *xp = ref_x - frame_width + child_x; + *yp = ref_y + child_y; + break; + case WestGravity: + *xp = ref_x + child_x; + *yp = ref_y - frame_height / 2 + child_y; + break; + case CenterGravity: + *xp = ref_x - frame_width / 2 + child_x; + *yp = ref_y - frame_height / 2 + child_y; + break; + case EastGravity: + *xp = ref_x - frame_width + child_x; + *yp = ref_y - frame_height / 2 + child_y; + break; + case SouthWestGravity: + *xp = ref_x + child_x; + *yp = ref_y - frame_height + child_y; + break; + case SouthGravity: + *xp = ref_x - frame_width / 2 + child_x; + *yp = ref_y - frame_height + child_y; + break; + case SouthEastGravity: + *xp = ref_x - frame_width + child_x; + *yp = ref_y - frame_height + child_y; + break; + case StaticGravity: + default: + *xp = ref_x; + *yp = ref_y; + break; } } @@ -524,10 +734,22 @@ meta_window_move_resize_internal (MetaWindow *window, gboolean need_resize_client = FALSE; gboolean need_resize_frame = FALSE; - meta_verbose ("Move/resize %s to %d,%d %dx%d\n", - window->desc, root_x_nw, root_y_nw, w, h); + meta_verbose ("Move/resize %s to %d,%d %dx%d%s\n", + window->desc, root_x_nw, root_y_nw, w, h, + is_configure_request ? " (configure request)" : ""); - constrain_size (window, w, h, &w, &h); + /* FIXME we're passing old window size to calc_geometry, + * I believe the right fix is to remove window size + * args from calc_geometry and remove any dependency + * on that in frame code. + */ + if (window->frame) + meta_frame_calc_geometry (window->frame, + window->rect.width, + window->rect.height, + &fgeom); + + constrain_size (window, &fgeom, w, h, &w, &h); meta_verbose ("Constrained resize of %s to %d x %d\n", window->desc, w, h); if (w != window->rect.width || @@ -540,11 +762,6 @@ meta_window_move_resize_internal (MetaWindow *window, if (window->frame) { int new_w, new_h; - - meta_frame_calc_geometry (window->frame, - window->rect.width, - window->rect.height, - &fgeom); new_w = window->rect.width + fgeom.left_width + fgeom.right_width; @@ -563,23 +780,25 @@ meta_window_move_resize_internal (MetaWindow *window, meta_verbose ("Calculated frame size %dx%d\n", window->frame->rect.width, window->frame->rect.height); - - if (is_configure_request) - { - meta_frame_adjust_for_gravity (window->size_hints.win_gravity, - window->frame->rect.width, - window->frame->rect.height, - &fgeom, - root_x_nw, - root_y_nw, - &root_x_nw, - &root_y_nw); - - meta_verbose ("Compensated position for gravity, new pos %d,%d\n", - root_x_nw, root_y_nw); - } } + + if (is_configure_request) + { + adjust_for_gravity (window, + window->frame ? &fgeom : NULL, + /* configure request coords assume + * the border width existed + */ + is_configure_request, + root_x_nw, + root_y_nw, + &root_x_nw, + &root_y_nw); + meta_verbose ("Compensated position for gravity, new pos %d,%d\n", + root_x_nw, root_y_nw); + } + constrain_position (window, window->frame ? &fgeom : NULL, root_x_nw, root_y_nw, @@ -1079,6 +1298,18 @@ meta_window_client_message (MetaWindow *window, meta_window_unmaximize (window); } + if (first == display->atom_net_wm_state_modal || + second == display->atom_net_wm_state_modal) + { + window->wm_state_modal = + (action == _NET_WM_STATE_ADD) || + (action == _NET_WM_STATE_TOGGLE && !window->wm_state_modal); + + recalc_window_type (window); + meta_window_queue_move_resize (window); + set_net_wm_state (window); + } + return TRUE; } else if (event->xclient.message_type == @@ -1244,6 +1475,9 @@ static int update_size_hints (MetaWindow *window) { int x, y, w, h; + gulong supplied; + + meta_verbose ("Updating WM_NORMAL_HINTS\n"); /* Save the last ConfigureRequest, which we put here. * Values here set in the hints are supposed to @@ -1255,11 +1489,19 @@ update_size_hints (MetaWindow *window) h = window->size_hints.height; window->size_hints.flags = 0; + supplied = 0; meta_error_trap_push (window->display); - XGetNormalHints (window->display->xdisplay, - window->xwindow, - &window->size_hints); + XGetWMNormalHints (window->display->xdisplay, + window->xwindow, + &window->size_hints, + &supplied); + + /* as far as I can tell, "supplied" is just + * to check whether we had old-style normal hints + * without gravity, base size as returned by + * XGetNormalHints() + */ /* Put it back. */ window->size_hints.x = x; @@ -1375,6 +1617,8 @@ update_size_hints (MetaWindow *window) } else { + meta_verbose ("Window %s doesn't set gravity, using NW\n", + window->desc); window->size_hints.win_gravity = NorthWestGravity; window->size_hints.flags |= PWinGravity; } @@ -1885,7 +2129,6 @@ update_transient_for (MetaWindow *window) /* update stacking constraints */ meta_stack_update_transient (window->screen->stack, window); - meta_stack_update_layer (window->screen->stack, window); return meta_error_trap_pop (window->display); } @@ -2004,6 +2247,7 @@ recalc_window_type (MetaWindow *window) static void constrain_size (MetaWindow *window, + MetaFrameGeometry *fgeom, int width, int height, int *new_width, int *new_height) { @@ -2023,19 +2267,25 @@ constrain_size (MetaWindow *window, /* frame member variables should NEVER be used in here */ #define FLOOR(value, base) ( ((gint) ((value) / (base))) * (base) ) - + /* Get the allowed size ranges, considering maximized, etc. */ fullw = window->screen->active_workspace->workarea.width; fullh = window->screen->active_workspace->workarea.height; if (window->frame) { - fullw -= window->frame->child_x + window->frame->right_width; - fullh -= window->frame->child_y + window->frame->bottom_height; + fullw -= fgeom->left_width + fgeom->right_width; + fullh -= fgeom->top_height + fgeom->bottom_height; } maxw = window->size_hints.max_width; maxh = window->size_hints.max_height; - if (window->maximized) + + /* If user hasn't resized or moved, then try to shrink the window to + * fit onscreen, while not violating the min size, just as + * we do for maximize + */ + if (window->maximized || + !(window->user_has_resized || window->user_has_moved)) { maxw = MIN (maxw, fullw); maxh = MIN (maxh, fullh); @@ -2043,12 +2293,21 @@ constrain_size (MetaWindow *window, minw = window->size_hints.min_width; minh = window->size_hints.min_height; + + /* Check that fullscreen doesn't go under app-specified min size, if + * so snap back to min size + */ + if (maxw < minw) + maxw = minw; + if (maxh < minh) + maxh = minh; + if (window->maximized) { minw = MAX (minw, fullw); minh = MAX (minh, fullh); } - + /* Check that fullscreen doesn't exceed max width hint, * if so then snap back to max width hint */ diff --git a/src/window.h b/src/window.h index cd44a960a..c2146741d 100644 --- a/src/window.h +++ b/src/window.h @@ -77,17 +77,15 @@ struct _MetaWindow * have no stupid viewports) */ guint on_all_workspaces : 1; - - /* Mapped is what we think the mapped state should be; - * so if we get UnmapNotify and mapped == TRUE then - * it's a withdraw, if mapped == FALSE the UnmapNotify - * is caused by us. - */ - guint mapped : 1 ; /* Minimize is the state controlled by the minimize button */ guint minimized : 1; + /* Whether the window is mapped; actual server-side state + * see also unmaps_pending + */ + guint mapped : 1; + /* Iconic is the state in WM_STATE; happens for workspaces/shading * in addition to minimize */ @@ -116,7 +114,20 @@ struct _MetaWindow * determines whether we draw the focus */ guint has_focus : 1; - + + /* Track whether the user has ever manually modified + * the window; if so, we remove some constraints + * that exist on program modifications. + */ + guint user_has_resized : 1; + guint user_has_moved : 1; + + /* Number of UnmapNotify that are caused by us, if + * we get UnmapNotify with none pending then the client + * is withdrawing the window. + */ + int unmaps_pending; + /* The size we set the window to last (i.e. what we believe * to be its actual size on the server). The x, y are * the actual server-side x,y so are relative to the frame