From 41120f2a7931821391115c69da0239c08f022f60 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 5 May 2002 05:41:13 +0000 Subject: [PATCH] on unminimize, queue calc_showing on all transients 2002-05-05 Havoc Pennington * src/window.c (meta_window_unminimize): on unminimize, queue calc_showing on all transients (meta_window_activate): on activate, unminimize all a window's ancestors, not just the window itself. * src/workspace.c (set_work_area_hint): don't increment "tmp" by 16 unsigned long, increment by 4 * src/window.c (meta_window_free): if a window isn't minimized, restore its WM_STATE to NormalState instead of IconicState, since IconicState on initial window map means that the window should be minimized. * src/workspace.c (meta_workspace_invalidate_work_area): queue an idle to recompute the work area hint. (set_work_area_hint): we need 4*num_workspaces ints, not just num_workspaces. * src/screen.c (meta_screen_new): add work_area_idle field, handle it on screen shutdown * src/common.h (META_PRIORITY_PREFS_NOTIFY, META_PRIORITY_WORK_AREA_HINT): define some idle priorities * src/window.c (meta_window_calc_showing): hide windows if their parent window is minimized (meta_window_minimize): also queue_calc_showing on all transients of the window being minimized * src/place.c (constrain_placement): function to apply placement-time-only constraints, such as "not off the left of the screen" (meta_window_place): put dialogs down a bit over their parent, not right at the top. (meta_window_place): when centering a dialog, center it on the current xinerama screen, rather than the entire screen. * src/screen.c (meta_screen_get_current_xinerama): new function, but not implemented --- ChangeLog | 43 +++++++++++++ src/common.h | 3 + src/place.c | 75 +++++++++++++++++++---- src/prefs.c | 2 +- src/screen.c | 13 ++++ src/screen.h | 4 ++ src/window.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++-- src/window.h | 8 +++ src/workspace.c | 108 +++++++++++++++++++++------------ 9 files changed, 354 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index a8a047c83..b61a9ffb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2002-05-05 Havoc Pennington + + * src/window.c (meta_window_unminimize): on unminimize, queue + calc_showing on all transients + (meta_window_activate): on activate, unminimize all a window's + ancestors, not just the window itself. + + * src/workspace.c (set_work_area_hint): don't increment "tmp" by + 16 unsigned long, increment by 4 + + * src/window.c (meta_window_free): if a window isn't minimized, + restore its WM_STATE to NormalState instead of IconicState, + since IconicState on initial window map means that the window + should be minimized. + + * src/workspace.c (meta_workspace_invalidate_work_area): queue an + idle to recompute the work area hint. + (set_work_area_hint): we need 4*num_workspaces ints, not just + num_workspaces. + + * src/screen.c (meta_screen_new): add work_area_idle field, + handle it on screen shutdown + + * src/common.h (META_PRIORITY_PREFS_NOTIFY, + META_PRIORITY_WORK_AREA_HINT): define some idle priorities + + * src/window.c (meta_window_calc_showing): hide windows if + their parent window is minimized + (meta_window_minimize): also queue_calc_showing on all + transients of the window being minimized + + * src/place.c (constrain_placement): function to apply + placement-time-only constraints, such as "not off the left of the + screen" + (meta_window_place): put dialogs down a bit over their parent, + not right at the top. + (meta_window_place): when centering a dialog, center it + on the current xinerama screen, rather than the entire + screen. + + * src/screen.c (meta_screen_get_current_xinerama): new function, + but not implemented + 2002-05-04 Havoc Pennington * src/frames.c (meta_frames_paint_to_drawable): chop out the diff --git a/src/common.h b/src/common.h index 238608f89..82985d0d4 100644 --- a/src/common.h +++ b/src/common.h @@ -148,6 +148,9 @@ typedef enum #define META_MINI_ICON_WIDTH 16 #define META_MINI_ICON_HEIGHT 16 +#define META_PRIORITY_PREFS_NOTIFY (G_PRIORITY_DEFAULT_IDLE + 10) +#define META_PRIORITY_WORK_AREA_HINT (G_PRIORITY_DEFAULT_IDLE + 15) + #endif diff --git a/src/place.c b/src/place.c index ade971bc0..62337818b 100644 --- a/src/place.c +++ b/src/place.c @@ -197,13 +197,50 @@ find_first_fit (MetaWindow *window, /* FIXME */ } +static void +constrain_placement (MetaWindow *window, + MetaFrameGeometry *fgeom, + int x, + int y, + int *new_x, + int *new_y) +{ + /* The purpose of this function is to apply constraints that are not + * covered by window.c:constrain_position(), but should apply + * whenever we are _placing_ a window regardless of placement algorithm. + */ + MetaRectangle work_area; + int nw_x, nw_y; + + meta_window_get_work_area (window, &work_area); + + nw_x = work_area.x; + nw_y = work_area.y; + if (window->frame) + { + nw_x += fgeom->left_width; + nw_y += fgeom->top_height; + } + + /* Keep window from going off left edge, though we don't have + * this constraint once the window has been placed. + */ + if (x < nw_x) + x = nw_x; + if (y < nw_y) + y = nw_y; + + *new_x = x; + *new_y = y; +} + void -meta_window_place (MetaWindow *window, +meta_window_place (MetaWindow *window, MetaFrameGeometry *fgeom, - int x, - int y, - int *new_x, - int *new_y) + int x, + int y, + int *new_x, + int *new_y) { GList *windows; @@ -215,10 +252,6 @@ meta_window_place (MetaWindow *window, */ meta_topic (META_DEBUG_PLACEMENT, "Placing window %s\n", window->desc); - - /* FIXME copying Mac, when placing a dialog - * put it at 1/5 down and horizontally centered - */ if ((window->type == META_WINDOW_DIALOG || window->type == META_WINDOW_MODAL_DIALOG) && @@ -244,6 +277,14 @@ meta_window_place (MetaWindow *window, /* center of child over center of parent */ x -= window->rect.width / 2; + /* put child down 1/5 or so from the top of parent, unless + * it makes us have more of parent showing above child than + * below + */ + if (window->rect.height <= (parent->rect.height - (parent->rect.height / 5) * 2)) + y += parent->rect.height / 5; + + /* put top of child's frame, not top of child's client */ if (fgeom) y += fgeom->top_height; @@ -264,16 +305,22 @@ meta_window_place (MetaWindow *window, { /* Center on screen */ int w, h; + const MetaXineramaScreenInfo *xi; /* I think whole screen will look nicer than workarea */ - w = window->screen->width; - h = window->screen->height; + xi = meta_screen_get_current_xinerama (window->screen); + + w = xi->width; + h = xi->height; x = (w - window->rect.width) / 2; y = (h - window->rect.height) / 2; - meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen\n", - window->desc); + x += xi->x_origin; + y += xi->y_origin; + + meta_topic (META_DEBUG_PLACEMENT, "Centered window %s on screen %d xinerama %d\n", + window->desc, window->screen->number, xi->number); goto done; } @@ -313,6 +360,8 @@ meta_window_place (MetaWindow *window, g_list_free (windows); done: + constrain_placement (window, fgeom, x, y, &x, &y); + *new_x = x; *new_y = y; } diff --git a/src/prefs.c b/src/prefs.c index 58946c4cd..c9f753c6d 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -190,7 +190,7 @@ queue_changed (MetaPreference pref) /* add idle at priority below the gconf notify idle */ if (changed_idle == 0) - changed_idle = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 10, + changed_idle = g_idle_add_full (META_PRIORITY_PREFS_NOTIFY, changed_idle_handler, NULL, NULL); } diff --git a/src/screen.c b/src/screen.c index 14c71b8a2..cc4015e27 100644 --- a/src/screen.c +++ b/src/screen.c @@ -217,6 +217,8 @@ meta_screen_new (MetaDisplay *display, screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen); screen->default_depth = DefaultDepthOfScreen (screen->xscreen); + screen->work_area_idle = 0; + screen->xinerama_infos = NULL; screen->n_xinerama_infos = 0; @@ -351,6 +353,9 @@ meta_screen_free (MetaScreen *screen) if (meta_error_trap_pop (screen->display) != Success) meta_warning (_("Could not release screen %d on display '%s'\n"), screen->number, screen->display->name); + + if (screen->work_area_idle != 0) + g_source_remove (screen->work_area_idle); g_free (screen->screen_name); g_free (screen); @@ -778,3 +783,11 @@ meta_screen_focus_top_window (MetaScreen *screen, meta_topic (META_DEBUG_FOCUS, "No top window to focus found\n"); } } + +const MetaXineramaScreenInfo* +meta_screen_get_current_xinerama (MetaScreen *screen) +{ + /* FIXME how do we decide which is current? */ + + return &screen->xinerama_infos[0]; +} diff --git a/src/screen.h b/src/screen.h index 12915e7b3..bc85d873f 100644 --- a/src/screen.h +++ b/src/screen.h @@ -63,6 +63,8 @@ struct _MetaScreen MetaXineramaScreenInfo *xinerama_infos; int n_xinerama_infos; + guint work_area_idle; + guint keys_grabbed : 1; }; @@ -88,6 +90,8 @@ void meta_screen_ensure_tab_popup (MetaScreen *scree void meta_screen_focus_top_window (MetaScreen *screen, MetaWindow *not_this_one); +const MetaXineramaScreenInfo* meta_screen_get_current_xinerama (MetaScreen *screen); + #endif diff --git a/src/window.c b/src/window.c index ebef3fee2..7b5737c51 100644 --- a/src/window.c +++ b/src/window.c @@ -866,6 +866,18 @@ meta_window_free (MetaWindow *window) set_wm_state (window, WithdrawnState); meta_error_trap_pop (window->display); } + else + { + /* We need to put WM_STATE so that others will understand it on + * restart. + */ + if (!window->minimized) + { + meta_error_trap_push (window->display); + set_wm_state (window, NormalState); + meta_error_trap_pop (window->display); + } + } if (window->frame) meta_window_destroy_frame (window); @@ -1004,13 +1016,17 @@ meta_window_visible_on_workspace (MetaWindow *window, void meta_window_calc_showing (MetaWindow *window) { - gboolean on_workspace; + gboolean showing, on_workspace; meta_verbose ("Calc showing for window %s\n", window->desc); + + /* 1. See if we're on the workspace */ on_workspace = meta_window_visible_on_workspace (window, window->screen->active_workspace); + showing = on_workspace; + if (!on_workspace) meta_verbose ("Window %s is not on workspace %d\n", window->desc, @@ -1023,17 +1039,55 @@ meta_window_calc_showing (MetaWindow *window) if (window->on_all_workspaces) meta_verbose ("Window %s is on all workspaces\n", window->desc); - if (on_workspace && + /* 2. See if we're minimized */ + if (window->minimized) + showing = FALSE; + + /* 3. See if we're in "show desktop" mode */ + + if (showing && window->display->showing_desktop && window->type != META_WINDOW_DESKTOP && window->type != META_WINDOW_DOCK) { meta_verbose ("Window %s is on current workspace, but we're showing the desktop\n", window->desc); - on_workspace = FALSE; + showing = FALSE; } + + /* 4. See if an ancestor is minimized (note that + * ancestor's "mapped" field may not be up to date + * since it's being computed in this same idle queue) + */ - if (window->minimized || !on_workspace) + if (showing) + { + MetaWindow *w; + + w = window; + while (w != NULL) + { + if (w->minimized) + { + showing = FALSE; + break; + } + + if (w->xtransient_for == None) + break; + + w = meta_display_lookup_x_window (w->display, w->xtransient_for); + + if (w == window) + break; /* Cute, someone thought they'd make a transient_for cycle */ + + /* w may be null... */ + } + } + + /* Actually show/hide the window */ + + if (!showing) { /* Really this effects code should probably * be in meta_window_hide so the window->mapped @@ -1385,6 +1439,13 @@ meta_window_hide (MetaWindow *window) } } +static void +queue_calc_showing_func (MetaWindow *window, + void *data) +{ + meta_window_queue_calc_showing (window); +} + void meta_window_minimize (MetaWindow *window) { @@ -1392,6 +1453,11 @@ meta_window_minimize (MetaWindow *window) { window->minimized = TRUE; meta_window_queue_calc_showing (window); + + meta_window_foreach_transient (window, + queue_calc_showing_func, + NULL); + if (window->has_focus) { meta_topic (META_DEBUG_FOCUS, @@ -1418,6 +1484,10 @@ meta_window_unminimize (MetaWindow *window) { window->minimized = FALSE; meta_window_queue_calc_showing (window); + + meta_window_foreach_transient (window, + queue_calc_showing_func, + NULL); } } @@ -1590,6 +1660,28 @@ meta_window_unshade (MetaWindow *window) } } +static void +unminimize_window_and_all_transient_parents (MetaWindow *window) +{ + MetaWindow *w; + + w = window; + while (w != NULL) + { + meta_window_unminimize (w); + + if (w->xtransient_for == None) + break; + + w = meta_display_lookup_x_window (w->display, w->xtransient_for); + + if (w == window) + break; /* Cute, someone thought they'd make a transient_for cycle */ + + /* w may be null... */ + } +} + void meta_window_activate (MetaWindow *window, guint32 timestamp) @@ -1609,8 +1701,7 @@ meta_window_activate (MetaWindow *window, if (window->shaded) meta_window_unshade (window); - if (window->minimized) - meta_window_unminimize (window); + unminimize_window_and_all_transient_parents (window); meta_window_raise (window); meta_topic (META_DEBUG_FOCUS, @@ -5578,3 +5669,56 @@ meta_window_refresh_resize_popup (MetaWindow *window) TRUE); } } + +void +meta_window_foreach_transient (MetaWindow *window, + MetaWindowForeachFunc func, + void *data) +{ + GSList *windows; + GSList *tmp; + + windows = meta_display_list_windows (window->display); + + tmp = windows; + while (tmp != NULL) + { + MetaWindow *transient = tmp->data; + + if (meta_window_is_ancestor_of_transient (window, transient)) + (* func) (transient, data); + + tmp = tmp->next; + } + + g_slist_free (windows); +} + +gboolean +meta_window_is_ancestor_of_transient (MetaWindow *window, + MetaWindow *transient) +{ + MetaWindow *w; + + if (window == transient) + return FALSE; + + w = transient; + while (w != NULL) + { + if (w->xtransient_for == None) + return FALSE; + + if (w->xtransient_for == window->xwindow) + return TRUE; + + w = meta_display_lookup_x_window (w->display, w->xtransient_for); + + if (w == transient) + return FALSE; /* Cycle */ + + /* w may be null... */ + } + + return FALSE; +} diff --git a/src/window.h b/src/window.h index 873d97ed5..d13d3f614 100644 --- a/src/window.h +++ b/src/window.h @@ -29,6 +29,8 @@ #include #include +typedef void (*MetaWindowForeachFunc) (MetaWindow *window, + void *data); typedef enum { @@ -383,4 +385,10 @@ void meta_window_refresh_resize_popup (MetaWindow *window); void meta_window_free_delete_dialog (MetaWindow *window); +void meta_window_foreach_transient (MetaWindow *window, + MetaWindowForeachFunc func, + void *data); +gboolean meta_window_is_ancestor_of_transient (MetaWindow *window, + MetaWindow *transient); + #endif diff --git a/src/workspace.c b/src/workspace.c index 44ba51b3d..33d4cbbd9 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -27,7 +27,7 @@ void meta_workspace_queue_calc_showing (MetaWorkspace *workspace); static int set_number_of_spaces_hint (MetaScreen *screen); static int set_active_space_hint (MetaScreen *screen); -static int set_workarea_hint (MetaScreen *screen); +static int set_work_area_hint (MetaScreen *screen); MetaWorkspace* meta_workspace_new (MetaScreen *screen) @@ -314,43 +314,6 @@ set_number_of_spaces_hint (MetaScreen *screen) return meta_error_trap_pop (screen->display); } -static int -set_workarea_hint (MetaScreen *screen) -{ - int num_workspaces; - GList *tmp_list; - unsigned long *data, *tmp; - MetaRectangle area; - - num_workspaces = g_list_length (screen->display->workspaces); - data = g_new (unsigned long, num_workspaces); - tmp_list = screen->display->workspaces; - tmp = data; - - while (tmp_list != NULL) - { - MetaWorkspace *workspace = tmp_list->data; - - meta_workspace_get_work_area (workspace, &area); - tmp[0] = area.x; - tmp[1] = area.y; - tmp[2] = area.width; - tmp[3] = area.height; - - tmp += sizeof (unsigned long) * 4; - - tmp_list = tmp_list->next; - } - - meta_error_trap_push (screen->display); - XChangeProperty (screen->display->xdisplay, screen->xroot, - screen->display->atom_net_wm_workarea, - XA_CARDINAL, 32, PropModeReplace, - (guchar*) data, num_workspaces * 4); - g_free (data); - return meta_error_trap_pop (screen->display); -} - static int set_active_space_hint (MetaScreen *screen) { @@ -368,6 +331,63 @@ set_active_space_hint (MetaScreen *screen) return meta_error_trap_pop (screen->display); } +static int +set_work_area_hint (MetaScreen *screen) +{ + int num_workspaces; + GList *tmp_list; + unsigned long *data, *tmp; + MetaRectangle area; + + num_workspaces = meta_screen_get_n_workspaces (screen); + data = g_new (unsigned long, num_workspaces * 4); + tmp_list = screen->display->workspaces; + tmp = data; + + while (tmp_list != NULL) + { + MetaWorkspace *workspace = tmp_list->data; + + if (workspace->screen == screen) + { + meta_workspace_get_work_area (workspace, &area); + tmp[0] = area.x; + tmp[1] = area.y; + tmp[2] = area.width; + tmp[3] = area.height; + } + + tmp += 4; + + tmp_list = tmp_list->next; + } + + meta_error_trap_push (screen->display); + XChangeProperty (screen->display->xdisplay, screen->xroot, + screen->display->atom_net_wm_workarea, + XA_CARDINAL, 32, PropModeReplace, + (guchar*) data, num_workspaces*4); + g_free (data); + return meta_error_trap_pop (screen->display); +} + +static gboolean +set_work_area_idle_func (void *data) +{ + MetaScreen *screen; + + meta_topic (META_DEBUG_WORKAREA, + "Running work area idle function\n"); + + screen = data; + + screen->work_area_idle = 0; + + set_work_area_hint (screen); + + return FALSE; +} + void meta_workspace_invalidate_work_area (MetaWorkspace *workspace) { @@ -401,6 +421,18 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace) } g_list_free (windows); + + /* Recompute work area in an idle */ + if (workspace->screen->work_area_idle == 0) + { + meta_topic (META_DEBUG_WORKAREA, + "Adding work area hint idle function\n"); + workspace->screen->work_area_idle = + g_idle_add_full (META_PRIORITY_WORK_AREA_HINT, + set_work_area_idle_func, + workspace->screen, + NULL); + } } void