summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2002-05-05 05:41:13 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-05-05 05:41:13 +0000
commit41120f2a7931821391115c69da0239c08f022f60 (patch)
treeabfc25b03939cb1c7fb6299a6151883c9c5eb256
parent6f8a7f18702beb2fb8128eea25b532cb0b15ebbb (diff)
downloadmetacity-41120f2a7931821391115c69da0239c08f022f60.tar.gz
on unminimize, queue calc_showing on all transients
2002-05-05 Havoc Pennington <hp@pobox.com> * 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
-rw-r--r--ChangeLog43
-rw-r--r--src/common.h3
-rw-r--r--src/place.c75
-rw-r--r--src/prefs.c2
-rw-r--r--src/screen.c13
-rw-r--r--src/screen.h4
-rw-r--r--src/window.c156
-rw-r--r--src/window.h8
-rw-r--r--src/workspace.c80
9 files changed, 340 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index a8a047c8..b61a9ffb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,46 @@
+2002-05-05 Havoc Pennington <hp@pobox.com>
+
+ * 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 <hp@pobox.com>
* src/frames.c (meta_frames_paint_to_drawable): chop out the
diff --git a/src/common.h b/src/common.h
index 238608f8..82985d0d 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 ade971bc..62337818 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 58946c4c..c9f753c6 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 14c71b8a..cc4015e2 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 12915e7b..bc85d873 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 ebef3fee..7b5737c5 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 873d97ed..d13d3f61 100644
--- a/src/window.h
+++ b/src/window.h
@@ -29,6 +29,8 @@
#include <X11/Xutil.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+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 44ba51b3..33d4cbbd 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)
@@ -315,15 +315,32 @@ set_number_of_spaces_hint (MetaScreen *screen)
}
static int
-set_workarea_hint (MetaScreen *screen)
+set_active_space_hint (MetaScreen *screen)
+{
+ unsigned long data[1];
+
+ data[0] = meta_workspace_screen_index (screen->active_workspace);
+
+ meta_verbose ("Setting _NET_CURRENT_DESKTOP to %ld\n", data[0]);
+
+ meta_error_trap_push (screen->display);
+ XChangeProperty (screen->display->xdisplay, screen->xroot,
+ screen->display->atom_net_current_desktop,
+ XA_CARDINAL,
+ 32, PropModeReplace, (guchar*) data, 1);
+ 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 = g_list_length (screen->display->workspaces);
- data = g_new (unsigned long, num_workspaces);
+ num_workspaces = meta_screen_get_n_workspaces (screen);
+ data = g_new (unsigned long, num_workspaces * 4);
tmp_list = screen->display->workspaces;
tmp = data;
@@ -331,41 +348,44 @@ set_workarea_hint (MetaScreen *screen)
{
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;
+ 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);
+ (guchar*) data, num_workspaces*4);
g_free (data);
return meta_error_trap_pop (screen->display);
}
-static int
-set_active_space_hint (MetaScreen *screen)
+static gboolean
+set_work_area_idle_func (void *data)
{
- unsigned long data[1];
+ MetaScreen *screen;
+
+ meta_topic (META_DEBUG_WORKAREA,
+ "Running work area idle function\n");
- data[0] = meta_workspace_screen_index (screen->active_workspace);
+ screen = data;
- meta_verbose ("Setting _NET_CURRENT_DESKTOP to %ld\n", data[0]);
+ screen->work_area_idle = 0;
- meta_error_trap_push (screen->display);
- XChangeProperty (screen->display->xdisplay, screen->xroot,
- screen->display->atom_net_current_desktop,
- XA_CARDINAL,
- 32, PropModeReplace, (guchar*) data, 1);
- return meta_error_trap_pop (screen->display);
+ set_work_area_hint (screen);
+
+ return FALSE;
}
void
@@ -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