summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHavoc Pennington <hp@pobox.com>2002-01-19 03:50:03 +0000
committerHavoc Pennington <hp@src.gnome.org>2002-01-19 03:50:03 +0000
commit19d2e8c7e1df6fcf12e5e5dcfe36430627eb8cc2 (patch)
tree171f1da8bc2407db50d53475f95241ad0d932021 /src
parent3194faaa9cbe39f37e664470c40054d6621b2fd0 (diff)
downloadmetacity-19d2e8c7e1df6fcf12e5e5dcfe36430627eb8cc2.tar.gz
metacity-19d2e8c7e1df6fcf12e5e5dcfe36430627eb8cc2.tar.bz2
give priority to keeping NW corner onscreen rather than SE, if we need to
2002-01-18 Havoc Pennington <hp@pobox.com> * src/window.c (constrain_position): give priority to keeping NW corner onscreen rather than SE, if we need to shift the window to fit inside constraints * src/frames.c (meta_frames_get_geometry): don't depend on the current window size * src/theme.c: move geometry stuff in here, to be calculated as part of the theme * src/core.c (meta_core_get_client_size): new function to replace meta_core_get_frame_size() so we don't have weird cycles in the geometry calculation
Diffstat (limited to 'src')
-rw-r--r--src/core.c12
-rw-r--r--src/core.h10
-rw-r--r--src/frames.c347
-rw-r--r--src/frames.h4
-rw-r--r--src/theme.c242
-rw-r--r--src/theme.h76
-rw-r--r--src/window.c166
-rw-r--r--src/window.h3
-rw-r--r--src/workspace.c3
9 files changed, 547 insertions, 316 deletions
diff --git a/src/core.c b/src/core.c
index 399fe6d..dddcf68 100644
--- a/src/core.c
+++ b/src/core.c
@@ -24,10 +24,10 @@
#include "workspace.h"
void
-meta_core_get_frame_size (Display *xdisplay,
- Window frame_xwindow,
- int *width,
- int *height)
+meta_core_get_client_size (Display *xdisplay,
+ Window frame_xwindow,
+ int *width,
+ int *height)
{
MetaDisplay *display;
MetaWindow *window;
@@ -39,9 +39,9 @@ meta_core_get_frame_size (Display *xdisplay,
meta_bug ("No such frame window 0x%lx!\n", frame_xwindow);
if (width)
- *width = window->frame->rect.width;
+ *width = window->rect.width;
if (height)
- *height = window->frame->rect.height;
+ *height = window->rect.height;
}
MetaFrameFlags
diff --git a/src/core.h b/src/core.h
index bf8ccd1..b214642 100644
--- a/src/core.h
+++ b/src/core.h
@@ -23,15 +23,13 @@
#define META_CORE_H
/* Don't include core headers here */
-#include <gtk/gtk.h>
#include <gdk/gdkx.h>
-#include "frames.h"
#include "common.h"
-void meta_core_get_frame_size (Display *xdisplay,
- Window frame_xwindow,
- int *width,
- int *height);
+void meta_core_get_client_size (Display *xdisplay,
+ Window frame_xwindow,
+ int *width,
+ int *height);
MetaFrameFlags meta_core_get_frame_flags (Display *xdisplay,
Window frame_xwindow);
diff --git a/src/frames.c b/src/frames.c
index 84eedae..ed18b2e 100644
--- a/src/frames.c
+++ b/src/frames.c
@@ -29,63 +29,6 @@
#define DEFAULT_INNER_BUTTON_BORDER 3
-struct _MetaFrameProperties
-{
- /* Size of left/right/bottom sides */
- int left_width;
- int right_width;
- int bottom_height;
-
- /* Border of blue title region */
- GtkBorder title_border;
-
- /* Border inside title region, around title */
- GtkBorder text_border;
-
- /* padding on either side of spacer */
- int spacer_padding;
-
- /* Size of spacer */
- int spacer_width;
- int spacer_height;
-
- /* indent of buttons from edges of frame */
- int right_inset;
- int left_inset;
-
- /* Size of buttons */
- int button_width;
- int button_height;
-
- /* Space around buttons */
- GtkBorder button_border;
-
- /* Space inside button which is clickable but doesn't draw the
- * button icon
- */
- GtkBorder inner_button_border;
-};
-
-typedef struct _MetaFrameGeometry MetaFrameGeometry;
-
-struct _MetaFrameGeometry
-{
- int left_width;
- int right_width;
- int top_height;
- int bottom_height;
-
- int width;
- int height;
-
- GdkRectangle close_rect;
- GdkRectangle max_rect;
- GdkRectangle min_rect;
- GdkRectangle spacer_rect;
- GdkRectangle menu_rect;
- GdkRectangle title_rect;
-};
-
static void meta_frames_class_init (MetaFramesClass *klass);
static void meta_frames_init (MetaFrames *frames);
static void meta_frames_destroy (GtkObject *object);
@@ -276,7 +219,7 @@ meta_frames_init (MetaFrames *frames)
{
GTK_WINDOW (frames)->type = GTK_WINDOW_POPUP;
- frames->props = g_new0 (MetaFrameProperties, 1);
+ frames->layout = meta_frame_layout_new ();
frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
@@ -337,7 +280,7 @@ meta_frames_finalize (GObject *object)
g_assert (g_hash_table_size (frames->frames) == 0);
g_hash_table_destroy (frames->frames);
- g_free (frames->props);
+ meta_frame_layout_free (frames->layout);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -395,35 +338,35 @@ meta_frames_style_set (GtkWidget *widget,
GtkBorder *text_border;
GtkBorder *button_border;
GtkBorder *inner_button_border;
- MetaFrameProperties props;
+ MetaFrameLayout layout;
frames = META_FRAMES (widget);
gtk_widget_style_get (widget,
"left_width",
- &props.left_width,
+ &layout.left_width,
"right_width",
- &props.right_width,
+ &layout.right_width,
"bottom_height",
- &props.bottom_height,
+ &layout.bottom_height,
"title_border",
&title_border,
"text_border",
&text_border,
"spacer_padding",
- &props.spacer_padding,
+ &layout.spacer_padding,
"spacer_width",
- &props.spacer_width,
+ &layout.spacer_width,
"spacer_height",
- &props.spacer_height,
+ &layout.spacer_height,
"right_inset",
- &props.right_inset,
+ &layout.right_inset,
"left_inset",
- &props.left_inset,
+ &layout.left_inset,
"button_width",
- &props.button_width,
+ &layout.button_width,
"button_height",
- &props.button_height,
+ &layout.button_height,
"button_border",
&button_border,
"inner_button_border",
@@ -431,34 +374,34 @@ meta_frames_style_set (GtkWidget *widget,
NULL);
if (title_border)
- props.title_border = *title_border;
+ layout.title_border = *title_border;
else
- props.title_border = default_title_border;
+ layout.title_border = default_title_border;
g_free (title_border);
if (text_border)
- props.text_border = *text_border;
+ layout.text_border = *text_border;
else
- props.text_border = default_text_border;
+ layout.text_border = default_text_border;
g_free (text_border);
if (button_border)
- props.button_border = *button_border;
+ layout.button_border = *button_border;
else
- props.button_border = default_button_border;
+ layout.button_border = default_button_border;
g_free (button_border);
if (inner_button_border)
- props.inner_button_border = *inner_button_border;
+ layout.inner_button_border = *inner_button_border;
else
- props.inner_button_border = default_inner_button_border;
+ layout.inner_button_border = default_inner_button_border;
g_free (inner_button_border);
- *(frames->props) = props;
+ *(frames->layout) = layout;
{
PangoFontMetrics *metrics;
@@ -486,202 +429,23 @@ meta_frames_style_set (GtkWidget *widget,
static void
meta_frames_calc_geometry (MetaFrames *frames,
- MetaUIFrame *frame,
+ MetaUIFrame *frame,
MetaFrameGeometry *fgeom)
{
- int x;
- int button_y;
- int title_right_edge;
- MetaFrameProperties props;
- int buttons_height, title_height, spacer_height;
int width, height;
MetaFrameFlags flags;
- props = *(frames->props);
-
- /* FIXME this is totally broken - the w/h here are the size of the
- * frame xwindow, which is computed from the size the frame wants to
- * be, which we are currently computing - stuff just happens to work
- * now because we always go through this codepath twice, or don't
- * really use these values, or something.
- */
- meta_core_get_frame_size (gdk_display, frame->xwindow,
- &width, &height);
+ meta_core_get_client_size (gdk_display, frame->xwindow,
+ &width, &height);
flags = meta_core_get_frame_flags (gdk_display, frame->xwindow);
- fgeom->width = width;
- fgeom->height = height;
-
- buttons_height = props.button_height +
- props.button_border.top + props.button_border.bottom;
- title_height = frames->text_height +
- props.text_border.top + props.text_border.bottom +
- props.title_border.top + props.title_border.bottom;
- spacer_height = props.spacer_height;
-
- fgeom->top_height = MAX (buttons_height, title_height);
- fgeom->top_height = MAX (fgeom->top_height, spacer_height);
-
- fgeom->left_width = props.left_width;
- fgeom->right_width = props.right_width;
-
- if (flags & META_FRAME_SHADED)
- fgeom->bottom_height = 0;
- else
- fgeom->bottom_height = props.bottom_height;
-
- x = width - props.right_inset;
-
- /* center buttons */
- button_y = (fgeom->top_height -
- (props.button_height + props.button_border.top + props.button_border.bottom)) / 2 + props.button_border.top;
-
- if ((flags & META_FRAME_ALLOWS_DELETE) &&
- x >= 0)
- {
- fgeom->close_rect.x = x - props.button_border.right - props.button_width;
- fgeom->close_rect.y = button_y;
- fgeom->close_rect.width = props.button_width;
- fgeom->close_rect.height = props.button_height;
-
- x = fgeom->close_rect.x - props.button_border.left;
- }
- else
- {
- fgeom->close_rect.x = 0;
- fgeom->close_rect.y = 0;
- fgeom->close_rect.width = 0;
- fgeom->close_rect.height = 0;
- }
-
- if ((flags & META_FRAME_ALLOWS_MAXIMIZE) &&
- x >= 0)
- {
- fgeom->max_rect.x = x - props.button_border.right - props.button_width;
- fgeom->max_rect.y = button_y;
- fgeom->max_rect.width = props.button_width;
- fgeom->max_rect.height = props.button_height;
-
- x = fgeom->max_rect.x - props.button_border.left;
- }
- else
- {
- fgeom->max_rect.x = 0;
- fgeom->max_rect.y = 0;
- fgeom->max_rect.width = 0;
- fgeom->max_rect.height = 0;
- }
-
- if ((flags & META_FRAME_ALLOWS_MINIMIZE) &&
- x >= 0)
- {
- fgeom->min_rect.x = x - props.button_border.right - props.button_width;
- fgeom->min_rect.y = button_y;
- fgeom->min_rect.width = props.button_width;
- fgeom->min_rect.height = props.button_height;
-
- x = fgeom->min_rect.x - props.button_border.left;
- }
- else
- {
- fgeom->min_rect.x = 0;
- fgeom->min_rect.y = 0;
- fgeom->min_rect.width = 0;
- fgeom->min_rect.height = 0;
- }
-
- if ((fgeom->close_rect.width > 0 ||
- fgeom->max_rect.width > 0 ||
- fgeom->min_rect.width > 0) &&
- x >= 0)
- {
- fgeom->spacer_rect.x = x - props.spacer_padding - props.spacer_width;
- fgeom->spacer_rect.y = (fgeom->top_height - props.spacer_height) / 2;
- fgeom->spacer_rect.width = props.spacer_width;
- fgeom->spacer_rect.height = props.spacer_height;
-
- x = fgeom->spacer_rect.x - props.spacer_padding;
- }
- else
- {
- fgeom->spacer_rect.x = 0;
- fgeom->spacer_rect.y = 0;
- fgeom->spacer_rect.width = 0;
- fgeom->spacer_rect.height = 0;
- }
-
- title_right_edge = x - props.title_border.right;
-
- /* Now x changes to be position from the left */
- x = props.left_inset;
-
- if (flags & META_FRAME_ALLOWS_MENU)
- {
- fgeom->menu_rect.x = x + props.button_border.left;
- fgeom->menu_rect.y = button_y;
- fgeom->menu_rect.width = props.button_width;
- fgeom->menu_rect.height = props.button_height;
-
- x = fgeom->menu_rect.x + fgeom->menu_rect.width + props.button_border.right;
- }
- else
- {
- fgeom->menu_rect.x = 0;
- fgeom->menu_rect.y = 0;
- fgeom->menu_rect.width = 0;
- fgeom->menu_rect.height = 0;
- }
-
- /* If menu overlaps close button, then the menu wins since it
- * lets you perform any operation including close
- */
- if (fgeom->close_rect.width > 0 &&
- fgeom->close_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
- {
- fgeom->close_rect.width = 0;
- fgeom->close_rect.height = 0;
- }
-
- /* Check for maximize overlap */
- if (fgeom->max_rect.width > 0 &&
- fgeom->max_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
- {
- fgeom->max_rect.width = 0;
- fgeom->max_rect.height = 0;
- }
-
- /* Check for minimize overlap */
- if (fgeom->min_rect.width > 0 &&
- fgeom->min_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
- {
- fgeom->min_rect.width = 0;
- fgeom->min_rect.height = 0;
- }
-
- /* Check for spacer overlap */
- if (fgeom->spacer_rect.width > 0 &&
- fgeom->spacer_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
- {
- fgeom->spacer_rect.width = 0;
- fgeom->spacer_rect.height = 0;
- }
-
- /* We always fill as much vertical space as possible with title rect,
- * rather than centering it like the buttons and spacer
- */
- fgeom->title_rect.x = x + props.title_border.left;
- fgeom->title_rect.y = props.title_border.top;
- fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
- fgeom->title_rect.height = fgeom->top_height - props.title_border.top - props.title_border.bottom;
-
- /* Nuke title if it won't fit */
- if (fgeom->title_rect.width < 0 ||
- fgeom->title_rect.height < 0)
- {
- fgeom->title_rect.width = 0;
- fgeom->title_rect.height = 0;
- }
+ meta_frame_layout_calc_geometry (frames->layout,
+ GTK_WIDGET (frames),
+ frames->text_height,
+ flags,
+ width, height,
+ fgeom);
}
MetaFrames*
@@ -789,25 +553,27 @@ meta_frames_get_geometry (MetaFrames *frames,
int *top_height, int *bottom_height,
int *left_width, int *right_width)
{
- MetaFrameGeometry fgeom;
-
+ MetaFrameFlags flags;
MetaUIFrame *frame;
frame = meta_frames_lookup_window (frames, xwindow);
if (frame == NULL)
meta_bug ("No such frame 0x%lx\n", xwindow);
+
+ flags = meta_core_get_frame_flags (gdk_display, frame->xwindow);
- meta_frames_calc_geometry (frames, frame, &fgeom);
-
- if (top_height)
- *top_height = fgeom.top_height;
- if (bottom_height)
- *bottom_height = fgeom.bottom_height;
- if (left_width)
- *left_width = fgeom.left_width;
- if (right_width)
- *right_width = fgeom.right_width;
+ /* We can't get the full geometry, because that depends on
+ * the client window size and probably we're being called
+ * by the core move/resize code to decide on the client
+ * window size
+ */
+ meta_frame_layout_get_borders (frames->layout,
+ GTK_WIDGET (frames),
+ frames->text_height,
+ flags,
+ top_height, bottom_height,
+ left_width, right_width);
}
void
@@ -1704,7 +1470,8 @@ meta_frames_expose_event (GtkWidget *widget,
meta_frames_calc_geometry (frames, frame, &fgeom);
flags = meta_core_get_frame_flags (gdk_display, frame->xwindow);
- meta_core_get_frame_size (gdk_display, frame->xwindow, &width, &height);
+ width = fgeom.width;
+ height = fgeom.height;
/* Black line around outside to give definition */
gdk_draw_rectangle (frame->window,
@@ -1751,9 +1518,9 @@ meta_frames_expose_event (GtkWidget *widget,
GdkGC *layout_gc;
clip = fgeom.title_rect;
- clip.x += frames->props->text_border.left;
- clip.width -= frames->props->text_border.left +
- frames->props->text_border.right;
+ clip.x += frames->layout->text_border.left;
+ clip.width -= frames->layout->text_border.left +
+ frames->layout->text_border.right;
layout_gc = widget->style->fg_gc[GTK_STATE_NORMAL];
if (flags & META_FRAME_HAS_FOCUS)
@@ -1826,16 +1593,16 @@ meta_frames_expose_event (GtkWidget *widget,
&layout_rect);
/* corner of whole title area */
- x = fgeom.title_rect.x + frames->props->text_border.left;
- y = fgeom.title_rect.y + frames->props->text_border.top;
+ x = fgeom.title_rect.x + frames->layout->text_border.left;
+ y = fgeom.title_rect.y + frames->layout->text_border.top;
area_w = fgeom.title_rect.width -
- frames->props->text_border.left -
- frames->props->text_border.right;
+ frames->layout->text_border.left -
+ frames->layout->text_border.right;
area_h = fgeom.title_rect.height -
- frames->props->text_border.top -
- frames->props->text_border.bottom;
+ frames->layout->text_border.top -
+ frames->layout->text_border.bottom;
/* center icon vertically */
icon_y = y + MAX ((area_h - icon_h) / 2, 0);
@@ -1884,7 +1651,7 @@ meta_frames_expose_event (GtkWidget *widget,
}
}
- inner = frames->props->inner_button_border;
+ inner = frames->layout->inner_button_border;
if (fgeom.close_rect.width > 0 && fgeom.close_rect.height > 0)
{
diff --git a/src/frames.h b/src/frames.h
index 8cfa310..5cc70ea 100644
--- a/src/frames.h
+++ b/src/frames.h
@@ -25,6 +25,7 @@
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "common.h"
+#include "theme.h"
typedef enum
{
@@ -61,7 +62,6 @@ typedef struct _MetaFrames MetaFrames;
typedef struct _MetaFramesClass MetaFramesClass;
typedef struct _MetaUIFrame MetaUIFrame;
-typedef struct _MetaFrameProperties MetaFrameProperties;
struct _MetaUIFrame
{
@@ -76,7 +76,7 @@ struct _MetaFrames
GtkWindow parent_instance;
/* If we did a widget per frame, we wouldn't want to cache this. */
- MetaFrameProperties *props;
+ MetaFrameLayout *layout;
int text_height;
diff --git a/src/theme.c b/src/theme.c
index 1629c5c..70a3538 100644
--- a/src/theme.c
+++ b/src/theme.c
@@ -22,8 +22,250 @@
#include "theme.h"
#include "util.h"
#include "gradient.h"
+#include <gtk/gtkwidget.h>
#include <string.h>
+MetaFrameLayout*
+meta_frame_layout_new (void)
+{
+ MetaFrameLayout *layout;
+
+ layout = g_new0 (MetaFrameLayout, 1);
+
+ return layout;
+}
+
+void
+meta_frame_layout_free (MetaFrameLayout *layout)
+{
+ g_return_if_fail (layout != NULL);
+
+ g_free (layout);
+}
+
+void
+meta_frame_layout_get_borders (const MetaFrameLayout *layout,
+ GtkWidget *widget,
+ int text_height,
+ MetaFrameFlags flags,
+ int *top_height,
+ int *bottom_height,
+ int *left_width,
+ int *right_width)
+{
+ int buttons_height, title_height, spacer_height;
+
+ g_return_if_fail (top_height != NULL);
+ g_return_if_fail (bottom_height != NULL);
+ g_return_if_fail (left_width != NULL);
+ g_return_if_fail (right_width != NULL);
+
+ buttons_height = layout->button_height +
+ layout->button_border.top + layout->button_border.bottom;
+ title_height = text_height +
+ layout->text_border.top + layout->text_border.bottom +
+ layout->title_border.top + layout->title_border.bottom;
+ spacer_height = layout->spacer_height;
+
+ if (top_height)
+ {
+ *top_height = MAX (buttons_height, title_height);
+ *top_height = MAX (*top_height, spacer_height);
+ }
+
+ if (left_width)
+ *left_width = layout->left_width;
+ if (right_width)
+ *right_width = layout->right_width;
+
+ if (bottom_height)
+ {
+ if (flags & META_FRAME_SHADED)
+ *bottom_height = 0;
+ else
+ *bottom_height = layout->bottom_height;
+ }
+}
+
+void
+meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
+ GtkWidget *widget,
+ int text_height,
+ MetaFrameFlags flags,
+ int client_width,
+ int client_height,
+ MetaFrameGeometry *fgeom)
+{
+ int x;
+ int button_y;
+ int title_right_edge;
+ int width, height;
+
+ meta_frame_layout_get_borders (layout, widget, text_height,
+ flags,
+ &fgeom->top_height,
+ &fgeom->bottom_height,
+ &fgeom->left_width,
+ &fgeom->right_width);
+
+ width = client_width + fgeom->left_width + fgeom->right_width;
+ height = client_height + fgeom->top_height + fgeom->bottom_height;
+
+ fgeom->width = width;
+ fgeom->height = height;
+
+ x = width - layout->right_inset;
+
+ /* center buttons */
+ button_y = (fgeom->top_height -
+ (layout->button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top;
+
+ if ((flags & META_FRAME_ALLOWS_DELETE) &&
+ x >= 0)
+ {
+ fgeom->close_rect.x = x - layout->button_border.right - layout->button_width;
+ fgeom->close_rect.y = button_y;
+ fgeom->close_rect.width = layout->button_width;
+ fgeom->close_rect.height = layout->button_height;
+
+ x = fgeom->close_rect.x - layout->button_border.left;
+ }
+ else
+ {
+ fgeom->close_rect.x = 0;
+ fgeom->close_rect.y = 0;
+ fgeom->close_rect.width = 0;
+ fgeom->close_rect.height = 0;
+ }
+
+ if ((flags & META_FRAME_ALLOWS_MAXIMIZE) &&
+ x >= 0)
+ {
+ fgeom->max_rect.x = x - layout->button_border.right - layout->button_width;
+ fgeom->max_rect.y = button_y;
+ fgeom->max_rect.width = layout->button_width;
+ fgeom->max_rect.height = layout->button_height;
+
+ x = fgeom->max_rect.x - layout->button_border.left;
+ }
+ else
+ {
+ fgeom->max_rect.x = 0;
+ fgeom->max_rect.y = 0;
+ fgeom->max_rect.width = 0;
+ fgeom->max_rect.height = 0;
+ }
+
+ if ((flags & META_FRAME_ALLOWS_MINIMIZE) &&
+ x >= 0)
+ {
+ fgeom->min_rect.x = x - layout->button_border.right - layout->button_width;
+ fgeom->min_rect.y = button_y;
+ fgeom->min_rect.width = layout->button_width;
+ fgeom->min_rect.height = layout->button_height;
+
+ x = fgeom->min_rect.x - layout->button_border.left;
+ }
+ else
+ {
+ fgeom->min_rect.x = 0;
+ fgeom->min_rect.y = 0;
+ fgeom->min_rect.width = 0;
+ fgeom->min_rect.height = 0;
+ }
+
+ if ((fgeom->close_rect.width > 0 ||
+ fgeom->max_rect.width > 0 ||
+ fgeom->min_rect.width > 0) &&
+ x >= 0)
+ {
+ fgeom->spacer_rect.x = x - layout->spacer_padding - layout->spacer_width;
+ fgeom->spacer_rect.y = (fgeom->top_height - layout->spacer_height) / 2;
+ fgeom->spacer_rect.width = layout->spacer_width;
+ fgeom->spacer_rect.height = layout->spacer_height;
+
+ x = fgeom->spacer_rect.x - layout->spacer_padding;
+ }
+ else
+ {
+ fgeom->spacer_rect.x = 0;
+ fgeom->spacer_rect.y = 0;
+ fgeom->spacer_rect.width = 0;
+ fgeom->spacer_rect.height = 0;
+ }
+
+ title_right_edge = x - layout->title_border.right;
+
+ /* Now x changes to be position from the left */
+ x = layout->left_inset;
+
+ if (flags & META_FRAME_ALLOWS_MENU)
+ {
+ fgeom->menu_rect.x = x + layout->button_border.left;
+ fgeom->menu_rect.y = button_y;
+ fgeom->menu_rect.width = layout->button_width;
+ fgeom->menu_rect.height = layout->button_height;
+
+ x = fgeom->menu_rect.x + fgeom->menu_rect.width + layout->button_border.right;
+ }
+ else
+ {
+ fgeom->menu_rect.x = 0;
+ fgeom->menu_rect.y = 0;
+ fgeom->menu_rect.width = 0;
+ fgeom->menu_rect.height = 0;
+ }
+
+ /* If menu overlaps close button, then the menu wins since it
+ * lets you perform any operation including close
+ */
+ if (fgeom->close_rect.width > 0 &&
+ fgeom->close_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
+ {
+ fgeom->close_rect.width = 0;
+ fgeom->close_rect.height = 0;
+ }
+
+ /* Check for maximize overlap */
+ if (fgeom->max_rect.width > 0 &&
+ fgeom->max_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
+ {
+ fgeom->max_rect.width = 0;
+ fgeom->max_rect.height = 0;
+ }
+
+ /* Check for minimize overlap */
+ if (fgeom->min_rect.width > 0 &&
+ fgeom->min_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
+ {
+ fgeom->min_rect.width = 0;
+ fgeom->min_rect.height = 0;
+ }
+
+ /* Check for spacer overlap */
+ if (fgeom->spacer_rect.width > 0 &&
+ fgeom->spacer_rect.x < (fgeom->menu_rect.x + fgeom->menu_rect.height))
+ {
+ fgeom->spacer_rect.width = 0;
+ fgeom->spacer_rect.height = 0;
+ }
+
+ /* We always fill as much vertical space as possible with title rect,
+ * rather than centering it like the buttons and spacer
+ */
+ fgeom->title_rect.x = x + layout->title_border.left;
+ fgeom->title_rect.y = layout->title_border.top;
+ fgeom->title_rect.width = title_right_edge - fgeom->title_rect.x;
+ fgeom->title_rect.height = fgeom->top_height - layout->title_border.top - layout->title_border.bottom;
+
+ /* Nuke title if it won't fit */
+ if (fgeom->title_rect.width < 0 ||
+ fgeom->title_rect.height < 0)
+ {
+ fgeom->title_rect.width = 0;
+ fgeom->title_rect.height = 0;
+ }
+}
MetaGradientSpec*
meta_gradient_spec_new (MetaGradientType type)
diff --git a/src/theme.h b/src/theme.h
index b14142a..1cb73f0 100644
--- a/src/theme.h
+++ b/src/theme.h
@@ -22,8 +22,8 @@
#ifndef META_THEME_H
#define META_THEME_H
-#include "frames.h"
#include "gradient.h"
+#include "common.h"
#include <gtk/gtkrc.h>
typedef struct _MetaFrameStyle MetaFrameStyle;
@@ -31,6 +31,67 @@ typedef struct _MetaFrameStyleSet MetaFrameStyleSet;
typedef struct _MetaTextureSpec MetaTextureSpec;
typedef struct _MetaGradientSpec MetaGradientSpec;
typedef struct _MetaColorSpec MetaColorSpec;
+typedef struct _MetaFrameLayout MetaFrameLayout;
+typedef struct _MetaFrameGeometry MetaFrameGeometry;
+
+/* Parameters used to calculate the geometry of the frame */
+struct _MetaFrameLayout
+{
+ /* Size of left/right/bottom sides */
+ int left_width;
+ int right_width;
+ int bottom_height;
+
+ /* Border of blue title region */
+ GtkBorder title_border;
+
+ /* Border inside title region, around title */
+ GtkBorder text_border;
+
+ /* padding on either side of spacer */
+ int spacer_padding;
+
+ /* Size of spacer */
+ int spacer_width;
+ int spacer_height;
+
+ /* indent of buttons from edges of frame */
+ int right_inset;
+ int left_inset;
+
+ /* Size of buttons */
+ int button_width;
+ int button_height;
+
+ /* Space around buttons */
+ GtkBorder button_border;
+
+ /* Space inside button which is clickable but doesn't draw the
+ * button icon
+ */
+ GtkBorder inner_button_border;
+};
+
+
+/* Calculated actual geometry of the frame */
+struct _MetaFrameGeometry
+{
+ int left_width;
+ int right_width;
+ int top_height;
+ int bottom_height;
+
+ int width;
+ int height;
+
+ GdkRectangle close_rect;
+ GdkRectangle max_rect;
+ GdkRectangle min_rect;
+ GdkRectangle spacer_rect;
+ GdkRectangle menu_rect;
+ GdkRectangle title_rect;
+};
+
typedef enum
{
@@ -184,7 +245,8 @@ struct _MetaFrameStyle
{
MetaTextureSpec *button_icons[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST];
MetaTextureSpec *button_backgrounds[META_BUTTON_TYPE_LAST][META_BUTTON_STATE_LAST];
- MetaTextureSpec *pieces[META_FRAME_PIECE_LAST];
+ MetaTextureSpec *pieces[META_FRAME_PIECE_LAST];
+ MetaFrameLayout *layout;
};
typedef enum
@@ -195,6 +257,16 @@ typedef enum
META_TEXTURE_DRAW_SCALED_BOTH
} MetaTextureDrawMode;
+MetaFrameLayout* meta_frame_layout_new (void);
+void meta_frame_layout_free (MetaFrameLayout *layout);
+void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
+ GtkWidget *widget,
+ int text_height,
+ MetaFrameFlags flags,
+ int client_width,
+ int client_height,
+ MetaFrameGeometry *fgeom);
+
MetaColorSpec* meta_color_spec_new (MetaColorSpecType type);
void meta_color_spec_free (MetaColorSpec *spec);
void meta_color_spec_render (MetaColorSpec *spec,
diff --git a/src/window.c b/src/window.c
index 712499a..252e533 100644
--- a/src/window.c
+++ b/src/window.c
@@ -53,6 +53,8 @@ typedef enum
WIN_HINTS_DO_NOT_COVER = (1<<5) /* attempt to not cover this window */
} GnomeWinHints;
+static int destroying_windows_disallowed = 0;
+
static void constrain_size (MetaWindow *window,
MetaFrameGeometry *fgeom,
int width,
@@ -127,6 +129,9 @@ static char* get_text_property (MetaDisplay *display,
void meta_window_unqueue_calc_showing (MetaWindow *window);
void meta_window_flush_calc_showing (MetaWindow *window);
+void meta_window_unqueue_move_resize (MetaWindow *window);
+void meta_window_flush_move_resize (MetaWindow *window);
+
static void meta_window_apply_session_info (MetaWindow *window,
const MetaWindowSessionInfo *info);
@@ -316,6 +321,7 @@ meta_window_new (MetaDisplay *display, Window xwindow,
xwindow);
window->unmanaging = FALSE;
window->calc_showing_queued = FALSE;
+ window->move_resize_queued = FALSE;
window->keys_grabbed = FALSE;
window->grab_on_frame = FALSE;
window->all_keys_grabbed = FALSE;
@@ -677,6 +683,10 @@ meta_window_free (MetaWindow *window)
meta_verbose ("Unmanaging 0x%lx\n", window->xwindow);
+ if (destroying_windows_disallowed > 0)
+ meta_bug ("Tried to destroy window %s while destruction was not allowed\n",
+ window->desc);
+
window->unmanaging = TRUE;
/* If we have the focus, focus some other window.
@@ -713,6 +723,7 @@ meta_window_free (MetaWindow *window)
window->display->prev_focus_window = NULL;
meta_window_unqueue_calc_showing (window);
+ meta_window_unqueue_move_resize (window);
tmp = window->workspaces;
while (tmp != NULL)
@@ -969,6 +980,8 @@ idle_calc_showing (gpointer data)
g_slist_free (calc_showing_pending);
calc_showing_pending = NULL;
calc_showing_idle = 0;
+
+ destroying_windows_disallowed += 1;
/* sort them from bottom to top, so we map the
* bottom windows first, so that placement (e.g. cascading)
@@ -984,12 +997,20 @@ idle_calc_showing (gpointer data)
window = tmp->data;
meta_window_calc_showing (window);
+
+ /* important to set this here for reentrancy -
+ * if we queue a window again while it's in "copy",
+ * then queue_calc_showing will just return since
+ * calc_showing_queued = TRUE still
+ */
window->calc_showing_queued = FALSE;
tmp = tmp->next;
}
g_slist_free (copy);
+
+ destroying_windows_disallowed -= 1;
return FALSE;
}
@@ -1003,6 +1024,9 @@ meta_window_unqueue_calc_showing (MetaWindow *window)
meta_verbose ("Removing %s from the calc_showing queue\n",
window->desc);
+ /* Note that window may not actually be in move_resize_pending
+ * because it may have been in "copy" inside the idle handler
+ */
calc_showing_pending = g_slist_remove (calc_showing_pending, window);
window->calc_showing_queued = FALSE;
@@ -1520,6 +1544,9 @@ meta_window_move_resize_internal (MetaWindow *window,
gboolean is_configure_request;
gboolean do_gravity_adjust;
gboolean is_user_action;
+
+ /* We don't need it in the idle queue anymore. */
+ meta_window_unqueue_move_resize (window);
is_configure_request = (flags & META_IS_CONFIGURE_REQUEST) != 0;
do_gravity_adjust = (flags & META_DO_GRAVITY_ADJUST) != 0;
@@ -1801,7 +1828,7 @@ meta_window_move_resize_internal (MetaWindow *window,
{
meta_verbose ("Size/position not modified\n");
}
-
+
/* Update struts for new window size */
if (window->do_not_cover && (need_resize_client || need_move_client))
{
@@ -1809,7 +1836,8 @@ meta_window_move_resize_internal (MetaWindow *window,
/* Does a resize on all windows on entire current workspace,
* would be an infinite loop except for need_resize_client
- * above.
+ * above. We rely on reaching an equilibrium state, which
+ * is somewhat fragile, though.
*/
invalidate_work_areas (window);
@@ -1901,11 +1929,125 @@ meta_window_move_resize_now (MetaWindow *window)
window->user_rect.height : window->rect.height);
}
+
+static guint move_resize_idle = 0;
+static GSList *move_resize_pending = NULL;
+
+/* We want to put windows whose size/pos affects other
+ * windows earlier in the queue, for efficiency.
+ */
+static int
+move_resize_cmp (gconstpointer a, gconstpointer b)
+{
+ MetaWindow *aw = (gpointer) a;
+ MetaWindow *bw = (gpointer) b;
+
+ if (aw->do_not_cover && !bw->do_not_cover)
+ return -1; /* aw before bw */
+ else if (!aw->do_not_cover && bw->do_not_cover)
+ return 1;
+ else
+ return 0;
+}
+
+static gboolean
+idle_move_resize (gpointer data)
+{
+ GSList *tmp;
+ GSList *copy;
+
+ meta_verbose ("Clearing the move_resize queue\n");
+
+ /* Work with a copy, for reentrancy. The allowed reentrancy isn't
+ * complete; destroying a window while we're in here would result in
+ * badness. But it's OK to queue/unqueue move_resizes.
+ */
+ copy = g_slist_copy (move_resize_pending);
+ g_slist_free (move_resize_pending);
+ move_resize_pending = NULL;
+ move_resize_idle = 0;
+
+ destroying_windows_disallowed += 1;
+
+ copy = g_slist_sort (copy, move_resize_cmp);
+
+ tmp = copy;
+ while (tmp != NULL)
+ {
+ MetaWindow *window;
+
+ window = tmp->data;
+
+ /* As a side effect, sets window->move_resize_queued = FALSE */
+ meta_window_move_resize_now (window);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (copy);
+
+ destroying_windows_disallowed -= 1;
+
+ return FALSE;
+}
+
+void
+meta_window_unqueue_move_resize (MetaWindow *window)
+{
+ if (!window->move_resize_queued)
+ return;
+
+ meta_verbose ("Removing %s from the move_resize queue\n",
+ window->desc);
+
+ /* Note that window may not actually be in move_resize_pending
+ * because it may have been in "copy" inside the idle handler
+ */
+ move_resize_pending = g_slist_remove (move_resize_pending, window);
+ window->move_resize_queued = FALSE;
+
+ if (move_resize_pending == NULL &&
+ move_resize_idle != 0)
+ {
+ g_source_remove (move_resize_idle);
+ move_resize_idle = 0;
+ }
+}
+
+void
+meta_window_flush_move_resize (MetaWindow *window)
+{
+ if (window->move_resize_queued)
+ {
+ meta_window_unqueue_move_resize (window);
+ meta_window_move_resize_now (window);
+ }
+}
+
+/* The move/resize queue is only used when we need to
+ * recheck the constraints on the window, e.g. when
+ * maximizing or when changing struts. Configure requests
+ * and such always have to be handled synchronously,
+ * they can't be done via a queue.
+ */
void
meta_window_queue_move_resize (MetaWindow *window)
{
- /* FIXME actually queue, don't do it immediately */
- meta_window_move_resize_now (window);
+ if (window->unmanaging)
+ return;
+
+ if (window->move_resize_queued)
+ return;
+
+ meta_verbose ("Putting %s in the move_resize queue\n",
+ window->desc);
+
+ window->move_resize_queued = TRUE;
+
+ if (move_resize_idle == 0)
+ move_resize_idle = g_idle_add (idle_move_resize, NULL);
+
+ move_resize_pending = g_slist_prepend (move_resize_pending, window);
}
void
@@ -5014,16 +5156,20 @@ constrain_position (MetaWindow *window,
se_y = tmp;
}
- /* Clamp window to the given positions */
- if (x < nw_x)
- x = nw_x;
- if (y < nw_y)
- y = nw_y;
-
+ /* Clamp window to the given positions.
+ * Do the SE clamp first, so that the NW clamp has precedence
+ * and we don't tend to lose the titlebar for too-large
+ * windows.
+ */
if (x > se_x)
x = se_x;
if (y > se_y)
y = se_y;
+
+ if (x < nw_x)
+ x = nw_x;
+ if (y < nw_y)
+ y = nw_y;
/* If maximized, force the exact position */
if (window->maximized)
diff --git a/src/window.h b/src/window.h
index 4fbea57..bd24faf 100644
--- a/src/window.h
+++ b/src/window.h
@@ -169,6 +169,9 @@ struct _MetaWindow
/* Are we in the calc_showing queue? */
guint calc_showing_queued : 1;
+ /* Are we in the move_resize queue? */
+ guint move_resize_queued : 1;
+
/* Used by keybindings.c */
guint keys_grabbed : 1; /* normal keybindings grabbed */
guint grab_on_frame : 1; /* grabs are on the frame */
diff --git a/src/workspace.c b/src/workspace.c
index 77c02e5..70bf080 100644
--- a/src/workspace.c
+++ b/src/workspace.c
@@ -327,6 +327,9 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
if (workspace->work_area_invalid)
return;
+
+ meta_verbose ("Invalidating work area for workspace %d\n",
+ meta_workspace_index (workspace));
workspace->work_area_invalid = TRUE;