Button-reordering patch. Has all the code except actually installing a

2002-10-03  Havoc Pennington  <hp@pobox.com>

        Button-reordering patch. Has all the code except actually
	installing a gconf schema and reading the gconf key in prefs.c.
	metacity-theme-viewer displays the button layouts for testing
	themes.

	* src/preview-widget.c (meta_preview_size_request): make up a
	width/height if no child widget

	* src/prefs.c (meta_prefs_get_button_layout): new function

	* src/frames.c: get the button layout from prefs and
	use it when drawing

	* src/theme.c (meta_frame_layout_calc_geometry): enhance to be
	able to lay out buttons in different arrangements
	(button_rect): draw the new button background rectangles
	(meta_theme_draw_frame): require a button layout argument
	(meta_theme_calc_geometry): pass in the button layout

	* src/preview-widget.h: mod to handle button layouts

	* src/theme-viewer.c: mod to handle button layouts
This commit is contained in:
Havoc Pennington 2002-10-04 02:28:57 +00:00 committed by Havoc Pennington
parent 261c9a74ef
commit 7641c6f952
10 changed files with 772 additions and 190 deletions

View File

@ -1,3 +1,28 @@
2002-10-03 Havoc Pennington <hp@pobox.com>
Button-reordering patch. Has all the code except actually
installing a gconf schema and reading the gconf key in prefs.c.
metacity-theme-viewer displays the button layouts for testing
themes.
* src/preview-widget.c (meta_preview_size_request): make up a
width/height if no child widget
* src/prefs.c (meta_prefs_get_button_layout): new function
* src/frames.c: get the button layout from prefs and
use it when drawing
* src/theme.c (meta_frame_layout_calc_geometry): enhance to be
able to lay out buttons in different arrangements
(button_rect): draw the new button background rectangles
(meta_theme_draw_frame): require a button layout argument
(meta_theme_calc_geometry): pass in the button layout
* src/preview-widget.h: mod to handle button layouts
* src/theme-viewer.c: mod to handle button layouts
2002-10-03 Havoc Pennington <hp@redhat.com> 2002-10-03 Havoc Pennington <hp@redhat.com>
* configure.in: 2.4.2 * configure.in: 2.4.2

View File

@ -117,7 +117,6 @@ typedef enum
META_GRAB_OP_CLICKING_MENU META_GRAB_OP_CLICKING_MENU
} MetaGrabOp; } MetaGrabOp;
typedef enum typedef enum
{ {
META_CURSOR_DEFAULT, META_CURSOR_DEFAULT,
@ -169,6 +168,32 @@ typedef enum
META_VIRTUAL_MOD5_MASK = 1 << 14 META_VIRTUAL_MOD5_MASK = 1 << 14
} MetaVirtualModifier; } MetaVirtualModifier;
/* Function a window button can have. Note, you can't add stuff here
* without extending the theme format to draw a new function and
* breaking all existing themes.
*/
typedef enum
{
META_BUTTON_FUNCTION_MENU,
META_BUTTON_FUNCTION_MINIMIZE,
META_BUTTON_FUNCTION_MAXIMIZE,
META_BUTTON_FUNCTION_CLOSE,
META_BUTTON_FUNCTION_LAST
} MetaButtonFunction;
#define MAX_BUTTONS_PER_CORNER META_BUTTON_FUNCTION_LAST
typedef struct _MetaButtonLayout MetaButtonLayout;
struct _MetaButtonLayout
{
/* buttons in the group on the left side */
MetaButtonFunction left_buttons[MAX_BUTTONS_PER_CORNER];
/* buttons in the group on the right side */
MetaButtonFunction right_buttons[MAX_BUTTONS_PER_CORNER];
};
/* should investigate changing these to whatever most apps use */ /* should investigate changing these to whatever most apps use */
#define META_ICON_WIDTH 32 #define META_ICON_WIDTH 32
#define META_ICON_HEIGHT 32 #define META_ICON_HEIGHT 32

View File

@ -73,7 +73,9 @@ static void meta_frames_ensure_layout (MetaFrames *frames,
static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames, static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
Window xwindow); Window xwindow);
static void meta_frames_font_changed (MetaFrames *frames); static void meta_frames_font_changed (MetaFrames *frames);
static void meta_frames_button_layout_changed (MetaFrames *frames);
static GdkRectangle* control_rect (MetaFrameControl control, static GdkRectangle* control_rect (MetaFrameControl control,
MetaFrameGeometry *fgeom); MetaFrameGeometry *fgeom);
@ -161,12 +163,19 @@ unsigned_long_hash (gconstpointer v)
} }
static void static void
font_changed_callback (MetaPreference pref, prefs_changed_callback (MetaPreference pref,
void *data) void *data)
{ {
if (pref == META_PREF_TITLEBAR_FONT) switch (pref)
{ {
case META_PREF_TITLEBAR_FONT:
meta_frames_font_changed (META_FRAMES (data)); meta_frames_font_changed (META_FRAMES (data));
break;
case META_PREF_BUTTON_LAYOUT:
meta_frames_button_layout_changed (META_FRAMES (data));
break;
default:
break;
} }
} }
@ -185,7 +194,7 @@ meta_frames_init (MetaFrames *frames)
gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE); gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE);
meta_prefs_add_listener (font_changed_callback, frames); meta_prefs_add_listener (prefs_changed_callback, frames);
} }
static void static void
@ -237,7 +246,7 @@ meta_frames_finalize (GObject *object)
frames = META_FRAMES (object); frames = META_FRAMES (object);
meta_prefs_remove_listener (font_changed_callback, frames); meta_prefs_remove_listener (prefs_changed_callback, frames);
g_hash_table_destroy (frames->text_heights); g_hash_table_destroy (frames->text_heights);
@ -292,6 +301,31 @@ meta_frames_font_changed (MetaFrames *frames)
} }
static void
queue_draw_func (gpointer key, gpointer value, gpointer data)
{
MetaUIFrame *frame;
MetaFrames *frames;
frames = META_FRAMES (data);
frame = value;
/* If a resize occurs it will cause a redraw, but the
* resize may not actually be needed so we always redraw
* in case of color change.
*/
gtk_style_set_background (GTK_WIDGET (frames)->style,
frame->window, GTK_STATE_NORMAL);
gdk_window_invalidate_rect (frame->window, NULL, FALSE);
}
static void
meta_frames_button_layout_changed (MetaFrames *frames)
{
g_hash_table_foreach (frames->frames,
queue_draw_func, frames);
}
static void static void
meta_frames_style_set (GtkWidget *widget, meta_frames_style_set (GtkWidget *widget,
GtkStyle *prev_style) GtkStyle *prev_style)
@ -394,6 +428,7 @@ meta_frames_calc_geometry (MetaFrames *frames,
int width, height; int width, height;
MetaFrameFlags flags; MetaFrameFlags flags;
MetaFrameType type; MetaFrameType type;
MetaButtonLayout button_layout;
meta_core_get_client_size (gdk_display, frame->xwindow, meta_core_get_client_size (gdk_display, frame->xwindow,
&width, &height); &width, &height);
@ -402,12 +437,15 @@ meta_frames_calc_geometry (MetaFrames *frames,
type = meta_core_get_frame_type (gdk_display, frame->xwindow); type = meta_core_get_frame_type (gdk_display, frame->xwindow);
meta_frames_ensure_layout (frames, frame); meta_frames_ensure_layout (frames, frame);
meta_prefs_get_button_layout (&button_layout);
meta_theme_calc_geometry (meta_theme_get_current (), meta_theme_calc_geometry (meta_theme_get_current (),
type, type,
frame->text_height, frame->text_height,
flags, flags,
width, height, width, height,
&button_layout,
fgeom); fgeom);
} }
@ -1524,6 +1562,7 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
GdkRectangle *areas; GdkRectangle *areas;
int n_areas; int n_areas;
int screen_width, screen_height; int screen_width, screen_height;
MetaButtonLayout button_layout;
widget = GTK_WIDGET (frames); widget = GTK_WIDGET (frames);
@ -1656,10 +1695,12 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
/* Now draw remaining portion of region */ /* Now draw remaining portion of region */
gdk_region_get_rectangles (edges, &areas, &n_areas); gdk_region_get_rectangles (edges, &areas, &n_areas);
meta_prefs_get_button_layout (&button_layout);
i = 0; i = 0;
while (i < n_areas) while (i < n_areas)
{ {
if (GDK_IS_WINDOW (drawable)) if (GDK_IS_WINDOW (drawable))
gdk_window_begin_paint_rect (drawable, &areas[i]); gdk_window_begin_paint_rect (drawable, &areas[i]);
@ -1673,6 +1714,7 @@ meta_frames_paint_to_drawable (MetaFrames *frames,
w, h, w, h,
frame->layout, frame->layout,
frame->text_height, frame->text_height,
&button_layout,
button_states, button_states,
mini_icon, icon); mini_icon, icon);

View File

@ -799,6 +799,10 @@ meta_preference_to_string (MetaPreference pref)
case META_PREF_COMMANDS: case META_PREF_COMMANDS:
return "COMMANDS"; return "COMMANDS";
case META_PREF_BUTTON_LAYOUT:
return "BUTTON_LAYOUT";
break;
} }
return "(unknown)"; return "(unknown)";
@ -1142,6 +1146,27 @@ meta_prefs_get_gconf_key_for_command (int i)
return key; return key;
} }
void
meta_prefs_get_button_layout (MetaButtonLayout *button_layout)
{
/* FIXME */
int i;
i = 0;
while (i < MAX_BUTTONS_PER_CORNER)
{
button_layout->left_buttons[i] = META_BUTTON_FUNCTION_LAST;
button_layout->right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++i;
}
button_layout->left_buttons[0] = META_BUTTON_FUNCTION_MENU;
button_layout->right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
button_layout->right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
button_layout->right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
}
void void
meta_prefs_get_screen_bindings (const MetaKeyPref **bindings, meta_prefs_get_screen_bindings (const MetaKeyPref **bindings,
int *n_bindings) int *n_bindings)

View File

@ -38,7 +38,8 @@ typedef enum
META_PREF_WINDOW_KEYBINDINGS, META_PREF_WINDOW_KEYBINDINGS,
META_PREF_SCREEN_KEYBINDINGS, META_PREF_SCREEN_KEYBINDINGS,
META_PREF_DISABLE_WORKAROUNDS, META_PREF_DISABLE_WORKAROUNDS,
META_PREF_COMMANDS META_PREF_COMMANDS,
META_PREF_BUTTON_LAYOUT
} MetaPreference; } MetaPreference;
typedef void (* MetaPrefsChangedFunc) (MetaPreference pref, typedef void (* MetaPrefsChangedFunc) (MetaPreference pref,
@ -66,6 +67,8 @@ const char* meta_prefs_get_command (int i);
char* meta_prefs_get_gconf_key_for_command (int i); char* meta_prefs_get_gconf_key_for_command (int i);
void meta_prefs_get_button_layout (MetaButtonLayout *button_layout);
void meta_prefs_set_num_workspaces (int n_workspaces); void meta_prefs_set_num_workspaces (int n_workspaces);
/* Screen bindings */ /* Screen bindings */

View File

@ -79,8 +79,24 @@ meta_preview_class_init (MetaPreviewClass *class)
static void static void
meta_preview_init (MetaPreview *preview) meta_preview_init (MetaPreview *preview)
{ {
int i;
GTK_WIDGET_SET_FLAGS (preview, GTK_NO_WINDOW); GTK_WIDGET_SET_FLAGS (preview, GTK_NO_WINDOW);
i = 0;
while (i < MAX_BUTTONS_PER_CORNER)
{
preview->button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
preview->button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++i;
}
preview->button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
preview->button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
preview->button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
preview->button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
preview->type = META_FRAME_TYPE_NORMAL; preview->type = META_FRAME_TYPE_NORMAL;
preview->flags = preview->flags =
META_FRAME_ALLOWS_DELETE | META_FRAME_ALLOWS_DELETE |
@ -218,7 +234,7 @@ meta_preview_expose (GtkWidget *widget,
if (client_width < 0) if (client_width < 0)
client_width = 1; client_width = 1;
if (client_height < 0) if (client_height < 0)
client_height = 1; client_height = 1;
if (preview->theme) if (preview->theme)
{ {
@ -235,6 +251,7 @@ meta_preview_expose (GtkWidget *widget,
client_width, client_height, client_width, client_height,
preview->layout, preview->layout,
preview->text_height, preview->text_height,
&preview->button_layout,
button_states, button_states,
meta_preview_get_mini_icon (), meta_preview_get_mini_icon (),
meta_preview_get_icon ()); meta_preview_get_icon ());
@ -267,6 +284,13 @@ meta_preview_size_request (GtkWidget *widget,
req->width += child_requisition.width; req->width += child_requisition.width;
req->height += child_requisition.height; req->height += child_requisition.height;
} }
else
{
#define NO_CHILD_WIDTH 80
#define NO_CHILD_HEIGHT 20
req->width += NO_CHILD_WIDTH;
req->height += NO_CHILD_HEIGHT;
}
req->width += GTK_CONTAINER (widget)->border_width * 2; req->width += GTK_CONTAINER (widget)->border_width * 2;
req->height += GTK_CONTAINER (widget)->border_width * 2; req->height += GTK_CONTAINER (widget)->border_width * 2;
@ -369,6 +393,17 @@ meta_preview_set_frame_flags (MetaPreview *preview,
gtk_widget_queue_resize (GTK_WIDGET (preview)); gtk_widget_queue_resize (GTK_WIDGET (preview));
} }
void
meta_preview_set_button_layout (MetaPreview *preview,
const MetaButtonLayout *button_layout)
{
g_return_if_fail (META_IS_PREVIEW (preview));
preview->button_layout = *button_layout;
gtk_widget_queue_draw (GTK_WIDGET (preview));
}
#include "inlinepixbufs.h" #include "inlinepixbufs.h"
GdkPixbuf* GdkPixbuf*

View File

@ -52,6 +52,7 @@ struct _MetaPreview
int top_height; int top_height;
int bottom_height; int bottom_height;
MetaButtonLayout button_layout;
}; };
struct _MetaPreviewClass struct _MetaPreviewClass
@ -63,14 +64,17 @@ struct _MetaPreviewClass
GtkType meta_preview_get_type (void) G_GNUC_CONST; GtkType meta_preview_get_type (void) G_GNUC_CONST;
GtkWidget* meta_preview_new (void); GtkWidget* meta_preview_new (void);
void meta_preview_set_theme (MetaPreview *preview, void meta_preview_set_theme (MetaPreview *preview,
MetaTheme *theme); MetaTheme *theme);
void meta_preview_set_title (MetaPreview *preview, void meta_preview_set_title (MetaPreview *preview,
const char *title); const char *title);
void meta_preview_set_frame_type (MetaPreview *preview, void meta_preview_set_frame_type (MetaPreview *preview,
MetaFrameType type); MetaFrameType type);
void meta_preview_set_frame_flags (MetaPreview *preview, void meta_preview_set_frame_flags (MetaPreview *preview,
MetaFrameFlags flags); MetaFrameFlags flags);
void meta_preview_set_button_layout (MetaPreview *preview,
const MetaButtonLayout *button_layout);
GdkPixbuf* meta_preview_get_icon (void); GdkPixbuf* meta_preview_get_icon (void);
GdkPixbuf* meta_preview_get_mini_icon (void); GdkPixbuf* meta_preview_get_mini_icon (void);

View File

@ -28,6 +28,22 @@
#include <time.h> #include <time.h>
#include <stdlib.h> #include <stdlib.h>
/* We need to compute all different button arrangements
* in terms of button location. We don't care about
* different arrangements in terms of button function.
*
* So if dups are allowed, from 0-4 buttons on the left, from 0-4 on
* the right, 5x5=25 combinations.
*
* If no dups, 0-4 on left determines the number on the right plus
* we have a special case for the "no buttons on either side" case.
*/
#ifndef ALLOW_DUPLICATE_BUTTONS
#define BUTTON_LAYOUT_COMBINATIONS (MAX_BUTTONS_PER_CORNER + 1 + 1)
#else
#define BUTTON_LAYOUT_COMBINATIONS ((MAX_BUTTONS_PER_CORNER+1)*(MAX_BUTTONS_PER_CORNER+1))
#endif
#define CLIENT_WIDTH 200 #define CLIENT_WIDTH 200
#define CLIENT_HEIGHT 200 #define CLIENT_HEIGHT 200
@ -40,7 +56,7 @@ enum
}; };
static MetaTheme *global_theme = NULL; static MetaTheme *global_theme = NULL;
static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST] = { NULL, }; static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + BUTTON_LAYOUT_COMBINATIONS] = { NULL, };
static void run_position_expression_tests (void); static void run_position_expression_tests (void);
static void run_position_expression_timings (void); static void run_position_expression_timings (void);
@ -547,6 +563,190 @@ preview_collection (int font_size,
return sw; return sw;
} }
static MetaButtonLayout different_layouts[BUTTON_LAYOUT_COMBINATIONS];
static void
init_layouts (void)
{
int i;
/* Blank out all the layouts */
i = 0;
while (i < (int) G_N_ELEMENTS (different_layouts))
{
int j;
j = 0;
while (j < MAX_BUTTONS_PER_CORNER)
{
different_layouts[i].left_buttons[j] = META_BUTTON_FUNCTION_LAST;
different_layouts[i].right_buttons[j] = META_BUTTON_FUNCTION_LAST;
++j;
}
++i;
}
#ifndef ALLOW_DUPLICATE_BUTTONS
i = 0;
while (i <= MAX_BUTTONS_PER_CORNER)
{
int j;
j = 0;
while (j < i)
{
different_layouts[i].right_buttons[j] = (MetaButtonFunction) j;
++j;
}
while (j < MAX_BUTTONS_PER_CORNER)
{
different_layouts[i].left_buttons[j-i] = (MetaButtonFunction) j;
++j;
}
++i;
}
/* Special extra case for no buttons on either side */
different_layouts[i].left_buttons[0] = META_BUTTON_FUNCTION_LAST;
different_layouts[i].right_buttons[0] = META_BUTTON_FUNCTION_LAST;
#else
/* FIXME this code is if we allow duplicate buttons,
* which we currently do not
*/
int left;
int i;
left = 0;
i = 0;
while (left < MAX_BUTTONS_PER_CORNER)
{
int right;
right = 0;
while (right < MAX_BUTTONS_PER_CORNER)
{
int j;
static MetaButtonFunction left_functions[MAX_BUTTONS_PER_CORNER] = {
META_BUTTON_FUNCTION_MENU,
META_BUTTON_FUNCTION_MINIMIZE,
META_BUTTON_FUNCTION_MAXIMIZE,
META_BUTTON_FUNCTION_CLOSE
};
static MetaButtonFunction right_functions[MAX_BUTTONS_PER_CORNER] = {
META_BUTTON_FUNCTION_MINIMIZE,
META_BUTTON_FUNCTION_MAXIMIZE,
META_BUTTON_FUNCTION_CLOSE,
META_BUTTON_FUNCTION_MENU
};
g_assert (i < BUTTON_LAYOUT_COMBINATIONS);
j = 0;
while (j <= left)
{
different_layouts[i].left_buttons[j] = left_functions[j];
++j;
}
j = 0;
while (j <= right)
{
different_layouts[i].right_buttons[j] = right_functions[j];
++j;
}
++i;
++right;
}
++left;
}
#endif
}
static GtkWidget*
previews_of_button_layouts (void)
{
static gboolean initted = FALSE;
GtkWidget *box;
GtkWidget *sw;
GdkColor desktop_color;
int i;
GtkWidget *eventbox;
if (!initted)
{
init_layouts ();
initted = TRUE;
}
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
box = gtk_vbox_new (FALSE, 0);
gtk_box_set_spacing (GTK_BOX (box), 20);
gtk_container_set_border_width (GTK_CONTAINER (box), 20);
eventbox = gtk_event_box_new ();
gtk_container_add (GTK_CONTAINER (eventbox), box);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), eventbox);
desktop_color.red = 0x5144;
desktop_color.green = 0x75D6;
desktop_color.blue = 0xA699;
gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL, &desktop_color);
i = 0;
while (i < BUTTON_LAYOUT_COMBINATIONS)
{
GtkWidget *align;
double xalign, yalign;
GtkWidget *eventbox2;
GtkWidget *preview;
char *title;
eventbox2 = gtk_event_box_new ();
preview = meta_preview_new ();
gtk_container_add (GTK_CONTAINER (eventbox2), preview);
meta_preview_set_theme (META_PREVIEW (preview), global_theme);
title = g_strdup_printf ("Button layout test %d", i+1);
meta_preview_set_title (META_PREVIEW (preview), title);
g_free (title);
meta_preview_set_button_layout (META_PREVIEW (preview),
&different_layouts[i]);
xalign = 0.5;
yalign = 0.5;
align = gtk_alignment_new (0.0, 0.0, xalign, yalign);
gtk_container_add (GTK_CONTAINER (align), eventbox2);
gtk_box_pack_start (GTK_BOX (box), align, TRUE, TRUE, 0);
previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + i] = preview;
++i;
}
return sw;
}
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {
@ -630,6 +830,11 @@ main (int argc, char **argv)
collection, collection,
gtk_label_new ("Large Title Font")); gtk_label_new ("Large Title Font"));
collection = previews_of_button_layouts ();
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
collection,
gtk_label_new ("Button Layouts"));
i = 0; i = 0;
while (i < (int) G_N_ELEMENTS (previews)) while (i < (int) G_N_ELEMENTS (previews))
{ {
@ -698,6 +903,7 @@ run_theme_benchmark (int client_width,
clock_t start; clock_t start;
clock_t end; clock_t end;
int i; int i;
MetaButtonLayout button_layout;
#define ITERATIONS 100 #define ITERATIONS 100
widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); widget = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@ -718,7 +924,21 @@ run_theme_benchmark (int client_width,
-1); -1);
layout = create_title_layout (widget); layout = create_title_layout (widget);
i = 0;
while (i < MAX_BUTTONS_PER_CORNER)
{
button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST;
button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST;
++i;
}
button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
start = clock (); start = clock ();
i = 0; i = 0;
@ -734,6 +954,7 @@ run_theme_benchmark (int client_width,
client_width, client_height, client_width, client_height,
layout, layout,
get_text_height (widget), get_text_height (widget),
&button_layout,
button_states, button_states,
meta_preview_get_mini_icon (), meta_preview_get_mini_icon (),
meta_preview_get_icon ()); meta_preview_get_icon ());

View File

@ -390,14 +390,86 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout,
} }
} }
void static GdkRectangle*
meta_frame_layout_calc_geometry (const MetaFrameLayout *layout, rect_for_function (MetaFrameGeometry *fgeom,
int text_height, MetaFrameFlags flags,
MetaFrameFlags flags, MetaButtonFunction function)
int client_width,
int client_height,
MetaFrameGeometry *fgeom)
{ {
switch (function)
{
case META_BUTTON_FUNCTION_MENU:
if (flags & META_FRAME_ALLOWS_MENU)
return &fgeom->menu_rect;
else
return NULL;
case META_BUTTON_FUNCTION_MINIMIZE:
if (flags & META_FRAME_ALLOWS_MINIMIZE)
return &fgeom->min_rect;
else
return NULL;
case META_BUTTON_FUNCTION_MAXIMIZE:
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
return &fgeom->max_rect;
else
return NULL;
case META_BUTTON_FUNCTION_CLOSE:
if (flags & META_FRAME_ALLOWS_DELETE)
return &fgeom->close_rect;
else
return NULL;
case META_BUTTON_FUNCTION_LAST:
return NULL;
}
return NULL;
}
static gboolean
strip_button (GdkRectangle *func_rects[MAX_BUTTONS_PER_CORNER],
GdkRectangle *bg_rects[MAX_BUTTONS_PER_CORNER],
int *n_rects,
GdkRectangle *to_strip)
{
int i;
i = 0;
while (i < *n_rects)
{
if (func_rects[i] == to_strip)
{
*n_rects -= 1;
/* shift the other rects back in the array */
while (i < *n_rects)
{
func_rects[i] = func_rects[i+1];
bg_rects[i] = bg_rects[i+1];
++i;
}
func_rects[i] = NULL;
bg_rects[i] = NULL;
return TRUE;
}
++i;
}
return FALSE; /* did not strip anything */
}
void
meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
int text_height,
MetaFrameFlags flags,
int client_width,
int client_height,
const MetaButtonLayout *button_layout,
MetaFrameGeometry *fgeom)
{
int i, n_left, n_right;
int x; int x;
int button_y; int button_y;
int title_right_edge; int title_right_edge;
@ -405,6 +477,14 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
int button_width, button_height; int button_width, button_height;
int min_size_for_rounding; int min_size_for_rounding;
/* the left/right rects in order; the max # of rects
* is the number of button functions
*/
GdkRectangle *left_func_rects[MAX_BUTTONS_PER_CORNER];
GdkRectangle *right_func_rects[MAX_BUTTONS_PER_CORNER];
GdkRectangle *left_bg_rects[MAX_BUTTONS_PER_CORNER];
GdkRectangle *right_bg_rects[MAX_BUTTONS_PER_CORNER];
meta_frame_layout_get_borders (layout, text_height, meta_frame_layout_get_borders (layout, text_height,
flags, flags,
&fgeom->top_height, &fgeom->top_height,
@ -425,8 +505,6 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
fgeom->left_titlebar_edge = layout->left_titlebar_edge; fgeom->left_titlebar_edge = layout->left_titlebar_edge;
fgeom->right_titlebar_edge = layout->right_titlebar_edge; fgeom->right_titlebar_edge = layout->right_titlebar_edge;
x = width - layout->right_titlebar_edge;
/* gcc warnings */ /* gcc warnings */
button_width = -1; button_width = -1;
button_height = -1; button_height = -1;
@ -446,110 +524,202 @@ meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
break; break;
} }
/* FIXME all this code sort of pretends that duplicate buttons
* with the same function are allowed, but that breaks the
* code in frames.c, so isn't really allowed right now.
* Would need left_close_rect, right_close_rect, etc.
*/
/* Init all button rects to 0, lame hack */
memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
LENGTH_OF_BUTTON_RECTS);
n_left = 0;
n_right = 0;
i = 0;
while (i < MAX_BUTTONS_PER_CORNER)
{
/* NULL all unused */
left_func_rects[i] = NULL;
right_func_rects[i] = NULL;
/* Try to fill in rects */
if (button_layout->left_buttons[i] != META_BUTTON_FUNCTION_LAST)
{
left_func_rects[n_left] = rect_for_function (fgeom, flags,
button_layout->left_buttons[i]);
if (left_func_rects[n_left] != NULL)
++n_left;
}
if (button_layout->right_buttons[i] != META_BUTTON_FUNCTION_LAST)
{
right_func_rects[n_right] = rect_for_function (fgeom, flags,
button_layout->right_buttons[i]);
if (right_func_rects[n_right] != NULL)
++n_right;
}
++i;
}
i = 0;
while (i < MAX_BUTTONS_PER_CORNER)
{
left_bg_rects[i] = NULL;
right_bg_rects[i] = NULL;
++i;
}
i = 0;
while (i < n_left)
{
if (i == 0)
left_bg_rects[i] = &fgeom->left_left_background;
else if (i == (n_left - 1))
left_bg_rects[i] = &fgeom->left_right_background;
else
left_bg_rects[i] = &fgeom->left_middle_backgrounds[i-1];
++i;
}
i = 0;
while (i < n_right)
{
if (i == 0)
right_bg_rects[i] = &fgeom->right_left_background;
else if (i == (n_right - 1))
right_bg_rects[i] = &fgeom->right_right_background;
else
right_bg_rects[i] = &fgeom->right_middle_backgrounds[i-1];
++i;
}
/* Be sure buttons fit */
while (n_left > 0 || n_right > 0)
{
int space_used_by_buttons;
int space_available;
space_available = fgeom->width - layout->left_titlebar_edge - layout->right_titlebar_edge;
space_used_by_buttons = 0;
i = 0;
while (i < n_left)
{
space_used_by_buttons += button_width;
if (i != n_left)
space_used_by_buttons += layout->button_border.left + layout->button_border.right;
++i;
}
i = 0;
while (i < n_right)
{
space_used_by_buttons += button_width;
if (i != n_right)
space_used_by_buttons += layout->button_border.left + layout->button_border.right;
++i;
}
if (space_used_by_buttons <= space_available)
break; /* Everything fits, bail out */
/* Otherwise we need to shave out a button. Shave
* min, max, close, then menu (menu is most useful);
* prefer the default button locations.
*/
if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->min_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->min_rect))
continue;
else if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->max_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->max_rect))
continue;
else if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->close_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->close_rect))
continue;
else if (strip_button (right_func_rects, right_bg_rects,
&n_right, &fgeom->menu_rect))
continue;
else if (strip_button (left_func_rects, left_bg_rects,
&n_left, &fgeom->menu_rect))
continue;
else
{
meta_bug ("Could not find a button to strip. n_left = %d n_right = %d\n",
n_left, n_right);
}
}
/* center buttons vertically */ /* center buttons vertically */
button_y = (fgeom->top_height - button_y = (fgeom->top_height -
(button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top; (button_height + layout->button_border.top + layout->button_border.bottom)) / 2 + layout->button_border.top;
/* right edge of farthest-right button */
x = width - layout->right_titlebar_edge;
if ((flags & META_FRAME_ALLOWS_DELETE) && i = n_right - 1;
x >= 0) while (i >= 0)
{ {
fgeom->close_rect.x = x - layout->button_border.right - button_width; GdkRectangle *rect;
fgeom->close_rect.y = button_y;
fgeom->close_rect.width = button_width;
fgeom->close_rect.height = button_height;
x = fgeom->close_rect.x - layout->button_border.left; if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
} break;
else
{ rect = right_func_rects[i];
fgeom->close_rect.x = 0;
fgeom->close_rect.y = 0; rect->x = x - layout->button_border.right - button_width;
fgeom->close_rect.width = 0; rect->y = button_y;
fgeom->close_rect.height = 0; rect->width = button_width;
} rect->height = button_height;
if ((flags & META_FRAME_ALLOWS_MAXIMIZE) && *(right_bg_rects[i]) = *rect;
x >= 0)
{ x = rect->x - layout->button_border.left;
fgeom->max_rect.x = x - layout->button_border.right - button_width;
fgeom->max_rect.y = button_y; --i;
fgeom->max_rect.width = button_width;
fgeom->max_rect.height = 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 - button_width;
fgeom->min_rect.y = button_y;
fgeom->min_rect.width = button_width;
fgeom->min_rect.height = 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;
} }
/* save right edge of titlebar for later use */
title_right_edge = x - layout->title_border.right; title_right_edge = x - layout->title_border.right;
/* Now x changes to be position from the left */ /* Now x changes to be position from the left and we go through
* the left-side buttons
*/
x = layout->left_titlebar_edge; x = layout->left_titlebar_edge;
if (flags & META_FRAME_ALLOWS_MENU) i = 0;
while (i < n_left)
{ {
fgeom->menu_rect.x = x + layout->button_border.left; GdkRectangle *rect;
fgeom->menu_rect.y = button_y;
fgeom->menu_rect.width = button_width; rect = left_func_rects[i];
fgeom->menu_rect.height = button_height;
rect->x = x + layout->button_border.left;
x = fgeom->menu_rect.x + fgeom->menu_rect.width + layout->button_border.right; rect->y = button_y;
} rect->width = button_width;
else rect->height = button_height;
{
fgeom->menu_rect.x = 0; x = rect->x + rect->width + layout->button_border.right;
fgeom->menu_rect.y = 0;
fgeom->menu_rect.width = 0; ++i;
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;
} }
/* We always fill as much vertical space as possible with title rect, /* We always fill as much vertical space as possible with title rect,
@ -3594,39 +3764,51 @@ meta_frame_style_validate (MetaFrameStyle *style,
} }
static void static void
button_rect (MetaButtonType type, button_rect (MetaButtonType type,
const MetaFrameGeometry *fgeom, const MetaFrameGeometry *fgeom,
GdkRectangle *rect) GdkRectangle *rect)
{ {
switch (type) switch (type)
{ {
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
*rect = fgeom->left_left_background;
break;
case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
/* FIXME */
break;
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
*rect = fgeom->left_right_background;
break;
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
*rect = fgeom->right_left_background;
break;
case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
/* FIXME */
break;
case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND: case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
*rect = fgeom->right_right_background;
break;
case META_BUTTON_TYPE_CLOSE: case META_BUTTON_TYPE_CLOSE:
*rect = fgeom->close_rect; *rect = fgeom->close_rect;
break; break;
case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
case META_BUTTON_TYPE_MAXIMIZE: case META_BUTTON_TYPE_MAXIMIZE:
*rect = fgeom->max_rect; *rect = fgeom->max_rect;
break; break;
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
case META_BUTTON_TYPE_MINIMIZE: case META_BUTTON_TYPE_MINIMIZE:
*rect = fgeom->min_rect; *rect = fgeom->min_rect;
break; break;
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
case META_BUTTON_TYPE_MENU: case META_BUTTON_TYPE_MENU:
*rect = fgeom->menu_rect; *rect = fgeom->menu_rect;
break; break;
case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
rect->x = 0;
rect->y = 0;
rect->width = 0;
rect->height = 0;
break;
case META_BUTTON_TYPE_LAST: case META_BUTTON_TYPE_LAST:
g_assert_not_reached (); g_assert_not_reached ();
@ -4445,21 +4627,22 @@ meta_theme_get_title_scale (MetaTheme *theme,
} }
void void
meta_theme_draw_frame (MetaTheme *theme, meta_theme_draw_frame (MetaTheme *theme,
GtkWidget *widget, GtkWidget *widget,
GdkDrawable *drawable, GdkDrawable *drawable,
const GdkRectangle *clip, const GdkRectangle *clip,
int x_offset, int x_offset,
int y_offset, int y_offset,
MetaFrameType type, MetaFrameType type,
MetaFrameFlags flags, MetaFrameFlags flags,
int client_width, int client_width,
int client_height, int client_height,
PangoLayout *title_layout, PangoLayout *title_layout,
int text_height, int text_height,
MetaButtonState button_states[META_BUTTON_TYPE_LAST], const MetaButtonLayout *button_layout,
GdkPixbuf *mini_icon, MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *icon) GdkPixbuf *mini_icon,
GdkPixbuf *icon)
{ {
MetaFrameGeometry fgeom; MetaFrameGeometry fgeom;
MetaFrameStyle *style; MetaFrameStyle *style;
@ -4476,6 +4659,7 @@ meta_theme_draw_frame (MetaTheme *theme,
text_height, text_height,
flags, flags,
client_width, client_height, client_width, client_height,
button_layout,
&fgeom); &fgeom);
meta_frame_style_draw (style, meta_frame_style_draw (style,
@ -4562,13 +4746,14 @@ meta_theme_get_frame_borders (MetaTheme *theme,
} }
void void
meta_theme_calc_geometry (MetaTheme *theme, meta_theme_calc_geometry (MetaTheme *theme,
MetaFrameType type, MetaFrameType type,
int text_height, int text_height,
MetaFrameFlags flags, MetaFrameFlags flags,
int client_width, int client_width,
int client_height, int client_height,
MetaFrameGeometry *fgeom) const MetaButtonLayout *button_layout,
MetaFrameGeometry *fgeom)
{ {
MetaFrameStyle *style; MetaFrameStyle *style;
@ -4584,6 +4769,7 @@ meta_theme_calc_geometry (MetaTheme *theme,
text_height, text_height,
flags, flags,
client_width, client_height, client_width, client_height,
button_layout,
fgeom); fgeom);
} }

View File

@ -103,7 +103,6 @@ struct _MetaFrameLayout
guint bottom_right_corner_rounded : 1; guint bottom_right_corner_rounded : 1;
}; };
/* Calculated actual geometry of the frame */ /* Calculated actual geometry of the frame */
struct _MetaFrameGeometry struct _MetaFrameGeometry
{ {
@ -113,12 +112,8 @@ struct _MetaFrameGeometry
int bottom_height; int bottom_height;
int width; int width;
int height; int height;
GdkRectangle close_rect;
GdkRectangle max_rect;
GdkRectangle min_rect;
GdkRectangle menu_rect;
GdkRectangle title_rect; GdkRectangle title_rect;
int left_titlebar_edge; int left_titlebar_edge;
@ -126,6 +121,25 @@ struct _MetaFrameGeometry
int top_titlebar_edge; int top_titlebar_edge;
int bottom_titlebar_edge; int bottom_titlebar_edge;
/* used for a memset hack */
#define ADDRESS_OF_BUTTON_RECTS(fgeom) (((char*)(fgeom)) + G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
#define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, right_right_background) + sizeof (GdkRectangle) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
/* The button rects (if changed adjust memset hack) */
GdkRectangle close_rect;
GdkRectangle max_rect;
GdkRectangle min_rect;
GdkRectangle menu_rect;
#define MAX_MIDDLE_BACKGROUNDS (MAX_BUTTONS_PER_CORNER - 2)
GdkRectangle left_left_background;
GdkRectangle left_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS];
GdkRectangle left_right_background;
GdkRectangle right_left_background;
GdkRectangle right_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS];
GdkRectangle right_right_background;
/* End of button rects (if changed adjust memset hack) */
/* Round corners */ /* Round corners */
guint top_left_corner_rounded : 1; guint top_left_corner_rounded : 1;
guint top_right_corner_rounded : 1; guint top_right_corner_rounded : 1;
@ -582,12 +596,13 @@ void meta_frame_layout_get_borders (const MetaFrameLayout *layout,
int *bottom_height, int *bottom_height,
int *left_width, int *left_width,
int *right_width); int *right_width);
void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout, void meta_frame_layout_calc_geometry (const MetaFrameLayout *layout,
int text_height, int text_height,
MetaFrameFlags flags, MetaFrameFlags flags,
int client_width, int client_width,
int client_height, int client_height,
MetaFrameGeometry *fgeom); const MetaButtonLayout *button_layout,
MetaFrameGeometry *fgeom);
gboolean meta_frame_layout_validate (const MetaFrameLayout *layout, gboolean meta_frame_layout_validate (const MetaFrameLayout *layout,
GError **error); GError **error);
@ -710,21 +725,22 @@ double meta_theme_get_title_scale (MetaTheme *theme,
MetaFrameType type, MetaFrameType type,
MetaFrameFlags flags); MetaFrameFlags flags);
void meta_theme_draw_frame (MetaTheme *theme, void meta_theme_draw_frame (MetaTheme *theme,
GtkWidget *widget, GtkWidget *widget,
GdkDrawable *drawable, GdkDrawable *drawable,
const GdkRectangle *clip, const GdkRectangle *clip,
int x_offset, int x_offset,
int y_offset, int y_offset,
MetaFrameType type, MetaFrameType type,
MetaFrameFlags flags, MetaFrameFlags flags,
int client_width, int client_width,
int client_height, int client_height,
PangoLayout *title_layout, PangoLayout *title_layout,
int text_height, int text_height,
MetaButtonState button_states[META_BUTTON_TYPE_LAST], const MetaButtonLayout *button_layout,
GdkPixbuf *mini_icon, MetaButtonState button_states[META_BUTTON_TYPE_LAST],
GdkPixbuf *icon); GdkPixbuf *mini_icon,
GdkPixbuf *icon);
void meta_theme_draw_menu_icon (MetaTheme *theme, void meta_theme_draw_menu_icon (MetaTheme *theme,
GtkWidget *widget, GtkWidget *widget,
@ -744,14 +760,14 @@ void meta_theme_get_frame_borders (MetaTheme *theme,
int *bottom_height, int *bottom_height,
int *left_width, int *left_width,
int *right_width); int *right_width);
void meta_theme_calc_geometry (MetaTheme *theme, void meta_theme_calc_geometry (MetaTheme *theme,
MetaFrameType type, MetaFrameType type,
int text_height, int text_height,
MetaFrameFlags flags, MetaFrameFlags flags,
int client_width, int client_width,
int client_height, int client_height,
MetaFrameGeometry *fgeom); const MetaButtonLayout *button_layout,
MetaFrameGeometry *fgeom);
MetaFrameLayout* meta_theme_lookup_layout (MetaTheme *theme, MetaFrameLayout* meta_theme_lookup_layout (MetaTheme *theme,
const char *name); const char *name);