From 2ff2a2722907f2ede849fe9df8febc0bd81c25d5 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Tue, 23 Apr 2013 12:53:24 -0400 Subject: [PATCH] use gtk+ theme impl --- src/Makefile.am | 20 +- src/compositor/meta-window-actor.c | 89 +- src/core/frame.c | 159 +- src/core/frame.h | 3 - src/core/keybindings.c | 4 - src/core/main.c | 42 - src/core/prefs.c | 44 - src/core/stack-tracker.c | 4 +- src/core/stack.c | 5 +- src/core/window.c | 283 +- src/gtk-decorator/gtk-decorator.c | 143 + src/meta/gradient.h | 71 - src/meta/meta-background-actor.h | 1 - src/meta/meta-background.h | 1 - src/meta/prefs.h | 3 - src/meta/util.h | 1 - src/ui/frames.c | 2412 ---------- src/ui/frames.h | 160 - src/ui/gradient.c | 873 ---- src/ui/menu.c | 518 --- src/ui/menu.h | 55 - src/ui/testgradient.c | 315 -- src/ui/theme-parser.c | 4344 ------------------ src/ui/theme-private.h | 1156 ----- src/ui/theme.c | 6802 ---------------------------- src/ui/ui.c | 446 +- src/ui/ui.h | 57 - 27 files changed, 221 insertions(+), 17790 deletions(-) create mode 100644 src/gtk-decorator/gtk-decorator.c delete mode 100644 src/meta/gradient.h delete mode 100644 src/ui/frames.c delete mode 100644 src/ui/frames.h delete mode 100644 src/ui/gradient.c delete mode 100644 src/ui/menu.c delete mode 100644 src/ui/menu.h delete mode 100644 src/ui/testgradient.c delete mode 100644 src/ui/theme-parser.c delete mode 100644 src/ui/theme-private.h delete mode 100644 src/ui/theme.c diff --git a/src/Makefile.am b/src/Makefile.am index dc1cac73a..75ae6eae4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -102,8 +102,6 @@ libmutter_la_SOURCES = \ meta/errors.h \ core/frame.c \ core/frame.h \ - ui/gradient.c \ - meta/gradient.h \ core/group-private.h \ core/group-props.c \ core/group-props.h \ @@ -152,20 +150,12 @@ libmutter_la_SOURCES = \ core/xprops.h \ meta/common.h \ core/core.h \ + ui/ui.c \ ui/ui.h \ - ui/frames.c \ - ui/frames.h \ - ui/menu.c \ - ui/menu.h \ ui/metaaccellabel.c \ ui/metaaccellabel.h \ ui/resizepopup.c \ - ui/resizepopup.h \ - ui/theme-parser.c \ - ui/theme.c \ - meta/theme.h \ - ui/theme-private.h \ - ui/ui.c + ui/resizepopup.h nodist_libmutter_la_SOURCES = \ $(mutter_built_sources) @@ -183,7 +173,6 @@ libmutterinclude_base_headers = \ meta/compositor.h \ meta/display.h \ meta/errors.h \ - meta/gradient.h \ meta/group.h \ meta/keybindings.h \ meta/main.h \ @@ -198,7 +187,6 @@ libmutterinclude_base_headers = \ meta/meta-window-actor.h \ meta/prefs.h \ meta/screen.h \ - meta/theme.h \ meta/types.h \ meta/util.h \ meta/window.h \ @@ -254,13 +242,11 @@ Meta-$(api_version).gir: libmutter.la endif testboxes_SOURCES = core/testboxes.c -testgradient_SOURCES = ui/testgradient.c testasyncgetprop_SOURCES = core/testasyncgetprop.c -noinst_PROGRAMS=testboxes testgradient testasyncgetprop +noinst_PROGRAMS=testboxes testasyncgetprop testboxes_LDADD = $(MUTTER_LIBS) libmutter.la -testgradient_LDADD = $(MUTTER_LIBS) libmutter.la testasyncgetprop_LDADD = $(MUTTER_LIBS) libmutter.la @INTLTOOL_DESKTOP_RULE@ diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 11606bb27..70214ff31 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -361,6 +361,7 @@ meta_window_actor_dispose (GObject *object) xdisplay = meta_display_get_xdisplay (display); info = meta_screen_get_compositor_data (screen); + meta_window_actor_set_redirected (self, FALSE); meta_window_actor_detach (self); if (priv->send_frame_messages_timer != 0) @@ -484,6 +485,36 @@ meta_window_actor_get_property (GObject *object, } } +static const char* +meta_frame_type_to_string (MetaFrameType type) +{ + switch (type) + { + case META_FRAME_TYPE_NORMAL: + return "normal"; + case META_FRAME_TYPE_DIALOG: + return "dialog"; + case META_FRAME_TYPE_MODAL_DIALOG: + return "modal_dialog"; + case META_FRAME_TYPE_UTILITY: + return "utility"; + case META_FRAME_TYPE_MENU: + return "menu"; + case META_FRAME_TYPE_BORDER: + return "border"; + case META_FRAME_TYPE_ATTACHED: + return "attached"; +#if 0 + case META_FRAME_TYPE_TOOLBAR: + return "toolbar"; +#endif + case META_FRAME_TYPE_LAST: + break; + } + + return ""; +} + static const char * meta_window_actor_get_shadow_class (MetaWindowActor *self) { @@ -1842,43 +1873,6 @@ meta_window_actor_sync_visibility (MetaWindowActor *self) } } -static cairo_region_t * -scan_visible_region (guchar *mask_data, - int stride, - cairo_region_t *scan_area) -{ - int i, n_rects = cairo_region_num_rectangles (scan_area); - MetaRegionBuilder builder; - - meta_region_builder_init (&builder); - - for (i = 0; i < n_rects; i++) - { - int x, y; - cairo_rectangle_int_t rect; - - cairo_region_get_rectangle (scan_area, i, &rect); - - for (y = rect.y; y < (rect.y + rect.height); y++) - { - for (x = rect.x; x < (rect.x + rect.width); x++) - { - int x2 = x; - while (mask_data[y * stride + x2] == 255 && x2 < (rect.x + rect.width)) - x2++; - - if (x2 > x) - { - meta_region_builder_add_rectangle (&builder, x, y, x2 - x, 1); - x = x2; - } - } - } - } - - return meta_region_builder_finish (&builder); -} - static void build_and_scan_frame_mask (MetaWindowActor *self, cairo_rectangle_int_t *client_area, @@ -1914,27 +1908,6 @@ build_and_scan_frame_mask (MetaWindowActor *self, gdk_cairo_region (cr, shape_region); cairo_fill (cr); - if (priv->window->frame != NULL) - { - cairo_region_t *frame_paint_region, *scanned_region; - cairo_rectangle_int_t rect = { 0, 0, tex_width, tex_height }; - - /* Make sure we don't paint the frame over the client window. */ - frame_paint_region = cairo_region_create_rectangle (&rect); - cairo_region_subtract_rectangle (frame_paint_region, client_area); - - gdk_cairo_region (cr, frame_paint_region); - cairo_clip (cr); - - meta_frame_get_mask (priv->window->frame, cr); - - cairo_surface_flush (surface); - scanned_region = scan_visible_region (mask_data, stride, frame_paint_region); - cairo_region_union (shape_region, scanned_region); - cairo_region_destroy (scanned_region); - cairo_region_destroy (frame_paint_region); - } - cairo_destroy (cr); cairo_surface_destroy (surface); diff --git a/src/core/frame.c b/src/core/frame.c index ed7e3cb59..086160291 100644 --- a/src/core/frame.c +++ b/src/core/frame.c @@ -43,7 +43,6 @@ meta_window_ensure_frame (MetaWindow *window) { MetaFrame *frame; XSetWindowAttributes attrs; - Visual *visual; gulong create_serial; if (window->frame) @@ -62,53 +61,34 @@ meta_window_ensure_frame (MetaWindow *window) frame->current_cursor = 0; frame->is_flashing = FALSE; - frame->borders_cached = FALSE; - - meta_verbose ("Framing window %s: visual %s default, depth %d default depth %d\n", - window->desc, - XVisualIDFromVisual (window->xvisual) == - XVisualIDFromVisual (window->screen->default_xvisual) ? - "is" : "is not", - window->depth, window->screen->default_depth); + meta_verbose ("Frame geometry %d,%d %dx%d\n", frame->rect.x, frame->rect.y, frame->rect.width, frame->rect.height); - - /* Default depth/visual handles clients with weird visuals; they can - * always be children of the root depth/visual obviously, but - * e.g. DRI games can't be children of a parent that has the same - * visual as the client. NULL means default visual. - * - * We look for an ARGB visual if we can find one, otherwise use - * the default of NULL. - */ - - /* Special case for depth 32 windows (assumed to be ARGB), - * we use the window's visual. Otherwise we just use the system visual. - */ - if (window->depth == 32) - visual = window->xvisual; - else - visual = NULL; - - frame->xwindow = meta_ui_create_frame_window (window->screen->ui, - window->display->xdisplay, - visual, - frame->rect.x, - frame->rect.y, - frame->rect.width, - frame->rect.height, - frame->window->screen->number, - &create_serial); + + attrs.event_mask = EVENT_MASK; + XChangeWindowAttributes (window->display->xdisplay, + frame->xwindow, CWEventMask, &attrs); + + create_serial = XNextRequest (window->display->xdisplay); + + frame->xwindow = XCreateWindow (window->display->xdisplay, + DefaultRootWindow (window->display->xdisplay), + frame->rect.x, frame->rect.y, + frame->rect.width, frame->rect.height, + 0, + CopyFromParent, + InputOnly, + CopyFromParent, + CWEventMask, + &attrs); + meta_stack_tracker_record_add (window->screen->stack_tracker, frame->xwindow, create_serial); meta_verbose ("Frame for %s is 0x%lx\n", frame->window->desc, frame->xwindow); - attrs.event_mask = EVENT_MASK; - XChangeWindowAttributes (window->display->xdisplay, - frame->xwindow, CWEventMask, &attrs); - + meta_display_register_x_window (window->display, &frame->xwindow, window); meta_error_trap_push (window->display); @@ -128,28 +108,12 @@ meta_window_ensure_frame (MetaWindow *window) meta_stack_tracker_record_remove (window->screen->stack_tracker, window->xwindow, XNextRequest (window->display->xdisplay)); - XReparentWindow (window->display->xdisplay, - window->xwindow, - frame->xwindow, - window->rect.x, - window->rect.y); /* FIXME handle this error */ meta_error_trap_pop (window->display); /* stick frame to the window */ window->frame = frame; - /* Now that frame->xwindow is registered with window, we can set its - * style and background. - */ - meta_ui_update_frame_style (window->screen->ui, frame->xwindow); - meta_ui_reset_frame_bg (window->screen->ui, frame->xwindow); - - if (window->title) - meta_ui_set_frame_title (window->screen->ui, - window->frame->xwindow, - window->title); - /* Move keybindings to frame instead of window */ meta_window_grab_keys (window); @@ -190,18 +154,9 @@ meta_window_destroy_frame (MetaWindow *window) meta_stack_tracker_record_add (window->screen->stack_tracker, window->xwindow, XNextRequest (window->display->xdisplay)); - XReparentWindow (window->display->xdisplay, - window->xwindow, - window->screen->xroot, - /* Using anything other than meta_window_get_position() - * coordinates here means we'll need to ensure a configure - * notify event is sent; see bug 399552. - */ - window->frame->rect.x + borders.invisible.left, - window->frame->rect.y + borders.invisible.top); meta_error_trap_pop (window->display); - meta_ui_destroy_frame_window (window->screen->ui, frame->xwindow); + XDestroyWindow (window->display->xdisplay, frame->xwindow); meta_display_unregister_x_window (window->display, frame->xwindow); @@ -309,22 +264,7 @@ void meta_frame_calc_borders (MetaFrame *frame, MetaFrameBorders *borders) { - /* Save on if statements and potential uninitialized values - * in callers -- if there's no frame, then zero the borders. */ - if (frame == NULL) - meta_frame_borders_clear (borders); - else - { - if (!frame->borders_cached) - { - meta_ui_get_frame_borders (frame->window->screen->ui, - frame->xwindow, - &frame->cached_borders); - frame->borders_cached = TRUE; - } - - *borders = frame->cached_borders; - } + meta_frame_borders_clear (borders); } void @@ -346,35 +286,12 @@ meta_frame_sync_to_window (MetaFrame *frame, frame->rect.x + frame->rect.width, frame->rect.y + frame->rect.height); - /* set bg to none to avoid flicker */ - if (need_resize) - { - meta_ui_unflicker_frame_bg (frame->window->screen->ui, - frame->xwindow, - frame->rect.width, - frame->rect.height); - } - - meta_ui_move_resize_frame (frame->window->screen->ui, - frame->xwindow, - frame->rect.x, - frame->rect.y, - frame->rect.width, - frame->rect.height); - - if (need_resize) - { - meta_ui_reset_frame_bg (frame->window->screen->ui, - frame->xwindow); - - /* If we're interactively resizing the frame, repaint - * it immediately so we don't start to lag. - */ - if (frame->window->display->grab_window == - frame->window) - meta_ui_repaint_frame (frame->window->screen->ui, - frame->xwindow); - } + XMoveResizeWindow (frame->window->display->xdisplay, + frame->xwindow, + frame->rect.x, + frame->rect.y, + frame->rect.width, + frame->rect.height); return need_resize; } @@ -382,25 +299,19 @@ meta_frame_sync_to_window (MetaFrame *frame, cairo_region_t * meta_frame_get_frame_bounds (MetaFrame *frame) { - return meta_ui_get_frame_bounds (frame->window->screen->ui, - frame->xwindow, - frame->rect.width, - frame->rect.height); -} + cairo_rectangle_int_t rect; -void -meta_frame_get_mask (MetaFrame *frame, - cairo_t *cr) -{ - meta_ui_get_frame_mask (frame->window->screen->ui, frame->xwindow, - frame->rect.width, frame->rect.height, cr); + rect.x = frame->window->rect.x; + rect.y = frame->window->rect.y; + rect.width = frame->window->rect.width; + rect.height = frame->window->rect.height; + + return cairo_region_create_rectangles (&rect, 1); } void meta_frame_queue_draw (MetaFrame *frame) { - meta_ui_queue_frame_draw (frame->window->screen->ui, - frame->xwindow); } void diff --git a/src/core/frame.h b/src/core/frame.h index 8ac1c261e..e22348df4 100644 --- a/src/core/frame.h +++ b/src/core/frame.h @@ -72,9 +72,6 @@ void meta_frame_clear_cached_borders (MetaFrame *frame); cairo_region_t *meta_frame_get_frame_bounds (MetaFrame *frame); -void meta_frame_get_mask (MetaFrame *frame, - cairo_t *cr); - void meta_frame_set_screen_cursor (MetaFrame *frame, MetaCursor cursor); diff --git a/src/core/keybindings.c b/src/core/keybindings.c index c43afd1ac..6038948d5 100644 --- a/src/core/keybindings.c +++ b/src/core/keybindings.c @@ -1983,10 +1983,6 @@ meta_display_process_key_event (MetaDisplay *display, if (screen == NULL) return FALSE; /* event window is destroyed */ - /* ignore key events on popup menus and such. */ - if (meta_ui_window_is_widget (screen->ui, event->event)) - return FALSE; - /* window may be NULL */ keysym = XKeycodeToKeysym (display->xdisplay, event->detail, 0); diff --git a/src/core/main.c b/src/core/main.c index b2eb4cdbb..63d750b33 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -523,42 +523,6 @@ meta_run (void) if (g_getenv ("MUTTER_G_FATAL_WARNINGS") != NULL) g_log_set_always_fatal (G_LOG_LEVEL_MASK); - - meta_ui_set_current_theme (meta_prefs_get_theme ()); - - /* Try to find some theme that'll work if the theme preference - * doesn't exist. First try Simple (the default theme) then just - * try anything in the themes directory. - */ - if (!meta_ui_have_a_theme ()) - meta_ui_set_current_theme ("Simple"); - - if (!meta_ui_have_a_theme ()) - { - const char *dir_entry = NULL; - GError *err = NULL; - GDir *themes_dir = NULL; - - if (!(themes_dir = g_dir_open (MUTTER_DATADIR"/themes", 0, &err))) - { - meta_fatal (_("Failed to scan themes directory: %s\n"), err->message); - g_error_free (err); - } - else - { - while (((dir_entry = g_dir_read_name (themes_dir)) != NULL) && - (!meta_ui_have_a_theme ())) - { - meta_ui_set_current_theme (dir_entry); - } - - g_dir_close (themes_dir); - } - } - - if (!meta_ui_have_a_theme ()) - meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n"), - MUTTER_DATADIR"/themes"); if (!meta_display_open ()) meta_exit (META_EXIT_ERROR); @@ -606,12 +570,6 @@ prefs_changed_callback (MetaPreference pref, { switch (pref) { - case META_PREF_THEME: - case META_PREF_DRAGGABLE_BORDER_WIDTH: - meta_ui_set_current_theme (meta_prefs_get_theme ()); - meta_display_retheme_all (); - break; - case META_PREF_CURSOR_THEME: case META_PREF_CURSOR_SIZE: meta_display_set_cursor_theme (meta_prefs_get_cursor_theme (), diff --git a/src/core/prefs.c b/src/core/prefs.c index d9f0f28d9..cc9c6ead3 100644 --- a/src/core/prefs.c +++ b/src/core/prefs.c @@ -80,7 +80,6 @@ static GDesktopFocusMode focus_mode = G_DESKTOP_FOCUS_MODE_CLICK; static GDesktopFocusNewWindows focus_new_windows = G_DESKTOP_FOCUS_NEW_WINDOWS_SMART; static gboolean raise_on_click = TRUE; static gboolean attach_modal_dialogs = FALSE; -static char* current_theme = NULL; static int num_workspaces = 4; static GDesktopTitlebarAction action_double_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE; static GDesktopTitlebarAction action_middle_click_titlebar = G_DESKTOP_TITLEBAR_ACTION_LOWER; @@ -132,7 +131,6 @@ static void queue_changed (MetaPreference pref); static void maybe_give_disable_workarounds_warning (void); static gboolean titlebar_handler (GVariant*, gpointer*, gpointer); -static gboolean theme_name_handler (GVariant*, gpointer*, gpointer); static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer); static gboolean button_layout_handler (GVariant*, gpointer*, gpointer); static gboolean overlay_key_handler (GVariant*, gpointer*, gpointer); @@ -382,14 +380,6 @@ static MetaStringPreference preferences_string[] = mouse_button_mods_handler, NULL, }, - { - { "theme", - SCHEMA_GENERAL, - META_PREF_THEME, - }, - theme_name_handler, - NULL, - }, { { KEY_TITLEBAR_FONT, SCHEMA_GENERAL, @@ -1225,12 +1215,6 @@ meta_prefs_get_raise_on_click (void) return raise_on_click || focus_mode == G_DESKTOP_FOCUS_MODE_CLICK; } -const char* -meta_prefs_get_theme (void) -{ - return current_theme; -} - const char* meta_prefs_get_cursor_theme (void) { @@ -1287,31 +1271,6 @@ titlebar_handler (GVariant *value, return TRUE; } -static gboolean -theme_name_handler (GVariant *value, - gpointer *result, - gpointer data) -{ - const gchar *string_value; - - *result = NULL; /* ignored */ - string_value = g_variant_get_string (value, NULL); - - if (!string_value || !*string_value) - return FALSE; - - if (g_strcmp0 (current_theme, string_value) != 0) - { - if (current_theme) - g_free (current_theme); - - current_theme = g_strdup (string_value); - queue_changed (META_PREF_THEME); - } - - return TRUE; -} - static gboolean mouse_button_mods_handler (GVariant *value, gpointer *result, @@ -1731,9 +1690,6 @@ meta_preference_to_string (MetaPreference pref) case META_PREF_RAISE_ON_CLICK: return "RAISE_ON_CLICK"; - case META_PREF_THEME: - return "THEME"; - case META_PREF_TITLEBAR_FONT: return "TITLEBAR_FONT"; diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c index 17979e38a..1aaf7801e 100644 --- a/src/core/stack-tracker.c +++ b/src/core/stack-tracker.c @@ -711,9 +711,7 @@ meta_stack_tracker_sync_stack (MetaStackTracker *tracker) * XID => window table. (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; * see window-prop.c:reload_net_wm_user_time_window() for registration.) */ - if (meta_window && - (windows[i] == meta_window->xwindow || - (meta_window->frame && windows[i] == meta_window->frame->xwindow))) + if (meta_window && windows[i] == meta_window->xwindow) meta_windows = g_list_prepend (meta_windows, meta_window); } diff --git a/src/core/stack.c b/src/core/stack.c index 18f1d7e56..f51e6bb9d 100644 --- a/src/core/stack.c +++ b/src/core/stack.c @@ -1189,10 +1189,7 @@ stack_sync_to_server (MetaStack *stack) else g_array_prepend_val (stacked, w->xwindow); - if (w->frame) - top_level_window = w->frame->xwindow; - else - top_level_window = w->xwindow; + top_level_window = w->xwindow; /* We don't restack hidden windows along with the rest, though they are * reflected in the _NET hints. Hidden windows all get pushed below diff --git a/src/core/window.c b/src/core/window.c index 6405b2370..7a5cd91ec 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -1705,13 +1705,6 @@ meta_window_unmanage (MetaWindow *window, meta_compositor_remove_window (window->display->compositor, window); } - if (window->display->window_with_menu == window) - { - meta_ui_window_menu_free (window->display->window_menu); - window->display->window_menu = NULL; - window->display->window_with_menu = NULL; - } - if (destroying_windows_disallowed > 0) meta_bug ("Tried to destroy window %s while destruction was not allowed\n", window->desc); @@ -3697,10 +3690,6 @@ meta_window_tile (MetaWindow *window) window, &old_rect, &new_rect); - - if (window->frame) - meta_ui_queue_frame_draw (window->screen->ui, - window->frame->xwindow); } else { @@ -7888,11 +7877,6 @@ meta_window_update_shape_region_x11 (MetaWindow *window) static void redraw_icon (MetaWindow *window) { - /* We could probably be smart and just redraw the icon here, - * instead of the whole frame. - */ - if (window->frame) - meta_ui_queue_frame_draw (window->screen->ui, window->frame->xwindow); } void @@ -8644,145 +8628,6 @@ recalc_window_features (MetaWindow *window) */ } -static void -menu_callback (MetaWindowMenu *menu, - Display *xdisplay, - Window client_xwindow, - guint32 timestamp, - MetaMenuOp op, - int workspace_index, - gpointer data) -{ - MetaDisplay *display; - MetaWindow *window; - MetaWorkspace *workspace; - - display = meta_display_for_x_display (xdisplay); - window = meta_display_lookup_x_window (display, client_xwindow); - workspace = NULL; - - if (window != NULL) /* window can be NULL */ - { - meta_verbose ("Menu op %u on %s\n", op, window->desc); - - switch (op) - { - case META_MENU_OP_NONE: - /* nothing */ - break; - - case META_MENU_OP_DELETE: - meta_window_delete (window, timestamp); - break; - - case META_MENU_OP_MINIMIZE: - meta_window_minimize (window); - break; - - case META_MENU_OP_UNMAXIMIZE: - meta_window_unmaximize (window, - META_MAXIMIZE_HORIZONTAL | - META_MAXIMIZE_VERTICAL); - break; - - case META_MENU_OP_MAXIMIZE: - meta_window_maximize (window, - META_MAXIMIZE_HORIZONTAL | - META_MAXIMIZE_VERTICAL); - break; - - case META_MENU_OP_UNSHADE: - meta_window_unshade (window, timestamp); - break; - - case META_MENU_OP_SHADE: - meta_window_shade (window, timestamp); - break; - - case META_MENU_OP_MOVE_LEFT: - workspace = meta_workspace_get_neighbor (window->screen->active_workspace, - META_MOTION_LEFT); - break; - - case META_MENU_OP_MOVE_RIGHT: - workspace = meta_workspace_get_neighbor (window->screen->active_workspace, - META_MOTION_RIGHT); - break; - - case META_MENU_OP_MOVE_UP: - workspace = meta_workspace_get_neighbor (window->screen->active_workspace, - META_MOTION_UP); - break; - - case META_MENU_OP_MOVE_DOWN: - workspace = meta_workspace_get_neighbor (window->screen->active_workspace, - META_MOTION_DOWN); - break; - - case META_MENU_OP_WORKSPACES: - workspace = meta_screen_get_workspace_by_index (window->screen, - workspace_index); - break; - - case META_MENU_OP_STICK: - meta_window_stick (window); - break; - - case META_MENU_OP_UNSTICK: - meta_window_unstick (window); - break; - - case META_MENU_OP_ABOVE: - case META_MENU_OP_UNABOVE: - if (window->wm_state_above == FALSE) - meta_window_make_above (window); - else - meta_window_unmake_above (window); - break; - - case META_MENU_OP_MOVE: - meta_window_begin_grab_op (window, - META_GRAB_OP_KEYBOARD_MOVING, - TRUE, - timestamp); - break; - - case META_MENU_OP_RESIZE: - meta_window_begin_grab_op (window, - META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN, - TRUE, - timestamp); - break; - - case META_MENU_OP_RECOVER: - meta_window_shove_titlebar_onscreen (window); - break; - - default: - meta_warning (G_STRLOC": Unknown window op\n"); - break; - } - - if (workspace) - { - meta_window_change_workspace (window, - workspace); - } - } - else - { - meta_verbose ("Menu callback on nonexistent window\n"); - } - - if (display->window_menu == menu) - { - display->window_menu = NULL; - display->window_with_menu = NULL; - } - - meta_ui_window_menu_free (menu); -} - void meta_window_show_menu (MetaWindow *window, int root_x, @@ -8790,126 +8635,6 @@ meta_window_show_menu (MetaWindow *window, int button, guint32 timestamp) { - MetaMenuOp ops; - MetaMenuOp insensitive; - MetaWindowMenu *menu; - MetaWorkspaceLayout layout; - int n_workspaces; - gboolean ltr; - - g_return_if_fail (!window->override_redirect); - - if (window->display->window_menu) - { - meta_ui_window_menu_free (window->display->window_menu); - window->display->window_menu = NULL; - window->display->window_with_menu = NULL; - } - - ops = META_MENU_OP_NONE; - insensitive = META_MENU_OP_NONE; - - ops |= (META_MENU_OP_DELETE | META_MENU_OP_MINIMIZE | META_MENU_OP_MOVE | META_MENU_OP_RESIZE); - - if (!meta_window_titlebar_is_onscreen (window) && - window->type != META_WINDOW_DOCK && - window->type != META_WINDOW_DESKTOP) - ops |= META_MENU_OP_RECOVER; - - if (!meta_prefs_get_workspaces_only_on_primary () || - meta_window_is_on_primary_monitor (window)) - { - n_workspaces = meta_screen_get_n_workspaces (window->screen); - - if (n_workspaces > 1) - ops |= META_MENU_OP_WORKSPACES; - - meta_screen_calc_workspace_layout (window->screen, - n_workspaces, - meta_workspace_index ( window->screen->active_workspace), - &layout); - - if (!window->on_all_workspaces) - { - ltr = meta_ui_get_direction() == META_UI_DIRECTION_LTR; - - if (layout.current_col > 0) - ops |= ltr ? META_MENU_OP_MOVE_LEFT : META_MENU_OP_MOVE_RIGHT; - if ((layout.current_col < layout.cols - 1) && - (layout.current_row * layout.cols + (layout.current_col + 1) < n_workspaces)) - ops |= ltr ? META_MENU_OP_MOVE_RIGHT : META_MENU_OP_MOVE_LEFT; - if (layout.current_row > 0) - ops |= META_MENU_OP_MOVE_UP; - if ((layout.current_row < layout.rows - 1) && - ((layout.current_row + 1) * layout.cols + layout.current_col < n_workspaces)) - ops |= META_MENU_OP_MOVE_DOWN; - } - - meta_screen_free_workspace_layout (&layout); - - ops |= META_MENU_OP_UNSTICK; - ops |= META_MENU_OP_STICK; - } - - if (META_WINDOW_MAXIMIZED (window)) - ops |= META_MENU_OP_UNMAXIMIZE; - else - ops |= META_MENU_OP_MAXIMIZE; - - if (window->wm_state_above) - ops |= META_MENU_OP_UNABOVE; - else - ops |= META_MENU_OP_ABOVE; - - if (!window->has_maximize_func) - insensitive |= META_MENU_OP_UNMAXIMIZE | META_MENU_OP_MAXIMIZE; - - if (!window->has_minimize_func) - insensitive |= META_MENU_OP_MINIMIZE; - - if (!window->has_close_func) - insensitive |= META_MENU_OP_DELETE; - - if (!window->has_shade_func) - insensitive |= META_MENU_OP_SHADE | META_MENU_OP_UNSHADE; - - if (!META_WINDOW_ALLOWS_MOVE (window)) - insensitive |= META_MENU_OP_MOVE; - - if (!META_WINDOW_ALLOWS_RESIZE (window)) - insensitive |= META_MENU_OP_RESIZE; - - if (window->always_sticky) - insensitive |= META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES; - - if ((window->type == META_WINDOW_DESKTOP) || - (window->type == META_WINDOW_DOCK) || - (window->type == META_WINDOW_SPLASHSCREEN || - META_WINDOW_MAXIMIZED (window))) - insensitive |= META_MENU_OP_ABOVE | META_MENU_OP_UNABOVE; - - /* If all operations are disabled, just quit without showing the menu. - * This is the case, for example, with META_WINDOW_DESKTOP windows. - */ - if ((ops & ~insensitive) == 0) - return; - - menu = - meta_ui_window_menu_new (window->screen->ui, - window->xwindow, - ops, - insensitive, - meta_window_get_net_wm_desktop (window), - meta_screen_get_n_workspaces (window->screen), - menu_callback, - NULL); - - window->display->window_menu = menu; - window->display->window_with_menu = window; - - meta_verbose ("Popping up window menu for %s\n", window->desc); - - meta_ui_window_menu_popup (menu, root_x, root_y, button, timestamp); } void @@ -11245,13 +10970,7 @@ meta_window_get_frame_type (MetaWindow *window) cairo_region_t * meta_window_get_frame_bounds (MetaWindow *window) { - if (!window->frame_bounds) - { - if (window->frame) - window->frame_bounds = meta_frame_get_frame_bounds (window->frame); - } - - return window->frame_bounds; + return NULL; } /** diff --git a/src/gtk-decorator/gtk-decorator.c b/src/gtk-decorator/gtk-decorator.c new file mode 100644 index 000000000..b76034069 --- /dev/null +++ b/src/gtk-decorator/gtk-decorator.c @@ -0,0 +1,143 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * Copyright (C) 2013 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: + * Jasper St. Pierre + */ + +#include +#include + +#include + +typedef struct { + Display *xdisplay; +} Decorator; + +typedef struct { + Decorator decorator; + Window child_window; + + GtkWidget *window; + GtkWidget *socket; +} WindowFrame; + +static void +socket_size_allocate (GtkWidget *widget, + GtkAllocation *allocation, + gpointer user_data) +{ + WindowFrame *frame = user_data; + + XMoveResizeWindow (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)), + frame->child_window, + allocation->x, allocation->y, + allocation->width, allocation->height); +} + +static WindowFrame * +frame_window (Decorator *decorator, + Window child_window) +{ + WindowFrame *frame; + XWindowAttributes attrs; + GtkWidget *window, *socket; + + XGetWindowAttributes (decorator->xdisplay, child_window, &attrs); + + frame = g_slice_new0 (WindowFrame); + frame->child_window = child_window; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + frame->window = window; + gtk_window_move (GTK_WINDOW (window), attrs.x, attrs.y); + + socket = gtk_frame_new (NULL); + frame->socket = socket; + gtk_widget_set_size_request (socket, attrs.width, attrs.height); + g_signal_connect (socket, "size-allocate", + G_CALLBACK (socket_size_allocate), frame); + gtk_container_add (GTK_CONTAINER (window), socket); + + gtk_widget_show (socket); + gtk_widget_show (window); + + XReparentWindow (decorator->xdisplay, + child_window, + GDK_WINDOW_XID (gtk_widget_get_window (window)), + /* these will be positioned correctly at the + * next size-allocate pass... */ + 0, 0); + + return frame; +} + +static Window +find_test_window (Display *dpy) +{ + Window root, parent; + Window *children; + Window ret = None; + unsigned int i, n_children; + + XQueryTree (dpy, DefaultRootWindow (dpy), + &root, &parent, + &children, &n_children); + + for (i = 0; i < n_children; i++) + { + Window child = children[i]; + char *name; + + XFetchName (dpy, child, &name); + if (g_strcmp0 (name, "this is a test window") == 0) + ret = child; + + g_free (name); + + if (ret) + break; + } + + return ret; +} + +static void +decorator_init (Decorator *decorator) +{ + decorator->xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); +} + +int +main (int argc, + char **argv) +{ + Decorator decorator; + Window window; + + gtk_init (&argc, &argv); + + decorator_init (&decorator); + + window = find_test_window (decorator.xdisplay); + frame_window (&decorator, window); + + gtk_main (); + return 0; +} diff --git a/src/meta/gradient.h b/src/meta/gradient.h deleted file mode 100644 index 1c9ac242f..000000000 --- a/src/meta/gradient.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Mutter gradient rendering */ - -/* - * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in - * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . */ - -#ifndef META_GRADIENT_H -#define META_GRADIENT_H - -#include -#include - -/** - * MetaGradientType: - * @META_GRADIENT_VERTICAL: Vertical gradient - * @META_GRADIENT_HORIZONTAL: Horizontal gradient - * @META_GRADIENT_DIAGONAL: Diagonal gradient - * @META_GRADIENT_LAST: Marks the end of the #MetaGradientType enumeration - * - */ -typedef enum -{ - META_GRADIENT_VERTICAL, - META_GRADIENT_HORIZONTAL, - META_GRADIENT_DIAGONAL, - META_GRADIENT_LAST -} MetaGradientType; - -GdkPixbuf* meta_gradient_create_simple (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to, - MetaGradientType style); -GdkPixbuf* meta_gradient_create_multi (int width, - int height, - const GdkRGBA *colors, - int n_colors, - MetaGradientType style); -GdkPixbuf* meta_gradient_create_interwoven (int width, - int height, - const GdkRGBA colors1[2], - int thickness1, - const GdkRGBA colors2[2], - int thickness2); - - -/* Generate an alpha gradient and multiply it with the existing alpha - * channel of the given pixbuf - */ -void meta_gradient_add_alpha (GdkPixbuf *pixbuf, - const guchar *alphas, - int n_alphas, - MetaGradientType type); - - -#endif diff --git a/src/meta/meta-background-actor.h b/src/meta/meta-background-actor.h index 56e97688f..4904a7abd 100644 --- a/src/meta/meta-background-actor.h +++ b/src/meta/meta-background-actor.h @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/src/meta/meta-background.h b/src/meta/meta-background.h index c171df326..3028d8aac 100644 --- a/src/meta/meta-background.h +++ b/src/meta/meta-background.h @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/src/meta/prefs.h b/src/meta/prefs.h index a5a3ab2c3..b2ba0f614 100644 --- a/src/meta/prefs.h +++ b/src/meta/prefs.h @@ -43,7 +43,6 @@ * @META_PREF_AUTO_RAISE: auto-raise * @META_PREF_AUTO_RAISE_DELAY: auto-raise delay * @META_PREF_FOCUS_CHANGE_ON_POINTER_REST: focus change on pointer rest - * @META_PREF_THEME: theme * @META_PREF_TITLEBAR_FONT: title-bar font * @META_PREF_NUM_WORKSPACES: number of workspaces * @META_PREF_DYNAMIC_WORKSPACES: dynamic workspaces @@ -80,7 +79,6 @@ typedef enum META_PREF_AUTO_RAISE, META_PREF_AUTO_RAISE_DELAY, META_PREF_FOCUS_CHANGE_ON_POINTER_REST, - META_PREF_THEME, META_PREF_TITLEBAR_FONT, META_PREF_NUM_WORKSPACES, META_PREF_DYNAMIC_WORKSPACES, @@ -125,7 +123,6 @@ GDesktopFocusMode meta_prefs_get_focus_mode (void); GDesktopFocusNewWindows meta_prefs_get_focus_new_windows (void); gboolean meta_prefs_get_attach_modal_dialogs (void); gboolean meta_prefs_get_raise_on_click (void); -const char* meta_prefs_get_theme (void); /* returns NULL if GTK default should be used */ const PangoFontDescription* meta_prefs_get_titlebar_font (void); int meta_prefs_get_num_workspaces (void); diff --git a/src/meta/util.h b/src/meta/util.h index 9328a26b9..1b85271fc 100644 --- a/src/meta/util.h +++ b/src/meta/util.h @@ -111,7 +111,6 @@ gint meta_unsigned_long_equal (gconstpointer v1, gconstpointer v2); guint meta_unsigned_long_hash (gconstpointer v); -const char* meta_frame_type_to_string (MetaFrameType type); const char* meta_gravity_to_string (int gravity); char* meta_external_binding_name_for_action (guint keybinding_action); diff --git a/src/ui/frames.c b/src/ui/frames.c deleted file mode 100644 index d69224ece..000000000 --- a/src/ui/frames.c +++ /dev/null @@ -1,2412 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity window frame manager widget */ - -/* - * Copyright (C) 2001 Havoc Pennington - * Copyright (C) 2003 Red Hat, Inc. - * Copyright (C) 2005, 2006 Elijah Newren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include -#include -#include -#include -#include "frames.h" -#include -#include "core.h" -#include "menu.h" -#include -#include -#include "ui.h" - -#include - -#ifdef HAVE_SHAPE -#include -#endif - -#define DEFAULT_INNER_BUTTON_BORDER 3 - -static void meta_frames_destroy (GtkWidget *object); -static void meta_frames_finalize (GObject *object); -static void meta_frames_style_updated (GtkWidget *widget); -static void meta_frames_map (GtkWidget *widget); -static void meta_frames_unmap (GtkWidget *widget); - -static void meta_frames_update_prelit_control (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameControl control); -static gboolean meta_frames_button_press_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean meta_frames_button_release_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean meta_frames_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event); -static gboolean meta_frames_destroy_event (GtkWidget *widget, - GdkEventAny *event); -static gboolean meta_frames_draw (GtkWidget *widget, - cairo_t *cr); -static gboolean meta_frames_enter_notify_event (GtkWidget *widget, - GdkEventCrossing *event); -static gboolean meta_frames_leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event); - -static void meta_frames_attach_style (MetaFrames *frames, - MetaUIFrame *frame); - -static void meta_frames_paint (MetaFrames *frames, - MetaUIFrame *frame, - cairo_t *cr); - -static void meta_frames_set_window_background (MetaFrames *frames, - MetaUIFrame *frame); - -static void meta_frames_calc_geometry (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameGeometry *fgeom); - -static void meta_frames_ensure_layout (MetaFrames *frames, - MetaUIFrame *frame); - -static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames, - Window xwindow); - -static void meta_frames_font_changed (MetaFrames *frames); -static void meta_frames_button_layout_changed (MetaFrames *frames); - - -static GdkRectangle* control_rect (MetaFrameControl control, - MetaFrameGeometry *fgeom); -static MetaFrameControl get_control (MetaFrames *frames, - MetaUIFrame *frame, - int x, - int y); -static void invalidate_whole_window (MetaFrames *frames, - MetaUIFrame *frame); - -G_DEFINE_TYPE (MetaFrames, meta_frames, GTK_TYPE_WINDOW); - -static GObject * -meta_frames_constructor (GType gtype, - guint n_properties, - GObjectConstructParam *properties) -{ - GObject *object; - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (meta_frames_parent_class); - object = gobject_class->constructor (gtype, n_properties, properties); - - g_object_set (object, - "type", GTK_WINDOW_POPUP, - NULL); - - return object; -} - -static void -meta_frames_class_init (MetaFramesClass *class) -{ - GObjectClass *gobject_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS (class); - widget_class = (GtkWidgetClass*) class; - - gobject_class->constructor = meta_frames_constructor; - gobject_class->finalize = meta_frames_finalize; - - widget_class->destroy = meta_frames_destroy; - - widget_class->style_updated = meta_frames_style_updated; - - widget_class->map = meta_frames_map; - widget_class->unmap = meta_frames_unmap; - - widget_class->draw = meta_frames_draw; - widget_class->destroy_event = meta_frames_destroy_event; - widget_class->button_press_event = meta_frames_button_press_event; - widget_class->button_release_event = meta_frames_button_release_event; - widget_class->motion_notify_event = meta_frames_motion_notify_event; - widget_class->enter_notify_event = meta_frames_enter_notify_event; - widget_class->leave_notify_event = meta_frames_leave_notify_event; -} - -static gint -unsigned_long_equal (gconstpointer v1, - gconstpointer v2) -{ - return *((const gulong*) v1) == *((const gulong*) v2); -} - -static guint -unsigned_long_hash (gconstpointer v) -{ - gulong val = * (const gulong *) v; - - /* I'm not sure this works so well. */ -#if GLIB_SIZEOF_LONG > 4 - return (guint) (val ^ (val >> 32)); -#else - return val; -#endif -} - -static void -prefs_changed_callback (MetaPreference pref, - void *data) -{ - switch (pref) - { - case META_PREF_TITLEBAR_FONT: - meta_frames_font_changed (META_FRAMES (data)); - break; - case META_PREF_BUTTON_LAYOUT: - meta_frames_button_layout_changed (META_FRAMES (data)); - break; - default: - break; - } -} - -static GtkStyleContext * -meta_frames_get_theme_variant (MetaFrames *frames, - const gchar *variant) -{ - GtkStyleContext *style; - - style = g_hash_table_lookup (frames->style_variants, variant); - if (style == NULL) - { - style = meta_theme_create_style_context (gtk_widget_get_screen (GTK_WIDGET (frames)), variant); - g_hash_table_insert (frames->style_variants, g_strdup (variant), style); - } - - return style; -} - -static void -update_style_contexts (MetaFrames *frames) -{ - GtkStyleContext *style; - GList *variants, *variant; - GdkScreen *screen; - - screen = gtk_widget_get_screen (GTK_WIDGET (frames)); - - if (frames->normal_style) - g_object_unref (frames->normal_style); - frames->normal_style = meta_theme_create_style_context (screen, NULL); - - variants = g_hash_table_get_keys (frames->style_variants); - for (variant = variants; variant; variant = variants->next) - { - style = meta_theme_create_style_context (screen, (char *)variant->data); - g_hash_table_insert (frames->style_variants, - g_strdup (variant->data), style); - } - g_list_free (variants); -} - -static void -meta_frames_init (MetaFrames *frames) -{ - frames->text_heights = g_hash_table_new (NULL, NULL); - - frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal); - - frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - update_style_contexts (frames); - - gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE); - - meta_prefs_add_listener (prefs_changed_callback, frames); -} - -static void -listify_func (gpointer key, gpointer value, gpointer data) -{ - GSList **listp; - - listp = data; - *listp = g_slist_prepend (*listp, value); -} - -static void -meta_frames_destroy (GtkWidget *object) -{ - GSList *winlist; - GSList *tmp; - MetaFrames *frames; - - frames = META_FRAMES (object); - - winlist = NULL; - g_hash_table_foreach (frames->frames, listify_func, &winlist); - - /* Unmanage all frames */ - for (tmp = winlist; tmp != NULL; tmp = tmp->next) - { - MetaUIFrame *frame; - - frame = tmp->data; - - meta_frames_unmanage_window (frames, frame->xwindow); - } - g_slist_free (winlist); - - if (frames->normal_style) - { - g_object_unref (frames->normal_style); - frames->normal_style = NULL; - } - - if (frames->style_variants) - { - g_hash_table_destroy (frames->style_variants); - frames->style_variants = NULL; - } - - GTK_WIDGET_CLASS (meta_frames_parent_class)->destroy (object); -} - -static void -meta_frames_finalize (GObject *object) -{ - MetaFrames *frames; - - frames = META_FRAMES (object); - - meta_prefs_remove_listener (prefs_changed_callback, frames); - - g_hash_table_destroy (frames->text_heights); - - g_assert (g_hash_table_size (frames->frames) == 0); - g_hash_table_destroy (frames->frames); - - G_OBJECT_CLASS (meta_frames_parent_class)->finalize (object); -} - -static void -queue_recalc_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. - */ - meta_frames_set_window_background (frames, frame); - - invalidate_whole_window (frames, frame); - meta_core_queue_frame_resize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - frame->xwindow); - if (frame->layout) - { - /* save title to recreate layout */ - g_free (frame->title); - - frame->title = g_strdup (pango_layout_get_text (frame->layout)); - - g_object_unref (G_OBJECT (frame->layout)); - frame->layout = NULL; - } -} - -static void -meta_frames_font_changed (MetaFrames *frames) -{ - if (g_hash_table_size (frames->text_heights) > 0) - { - g_hash_table_destroy (frames->text_heights); - frames->text_heights = g_hash_table_new (NULL, NULL); - } - - /* Queue a draw/resize on all frames */ - g_hash_table_foreach (frames->frames, - queue_recalc_func, 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. - */ - meta_frames_set_window_background (frames, frame); - - invalidate_whole_window (frames, frame); -} - -static void -meta_frames_button_layout_changed (MetaFrames *frames) -{ - g_hash_table_foreach (frames->frames, - queue_draw_func, frames); -} - -static void -reattach_style_func (gpointer key, gpointer value, gpointer data) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (data); - frame = value; - - meta_frames_attach_style (frames, frame); -} - -static void -meta_frames_style_updated (GtkWidget *widget) -{ - MetaFrames *frames; - - frames = META_FRAMES (widget); - - meta_frames_font_changed (frames); - - update_style_contexts (frames); - - g_hash_table_foreach (frames->frames, - reattach_style_func, frames); - - GTK_WIDGET_CLASS (meta_frames_parent_class)->style_updated (widget); -} - -static void -meta_frames_ensure_layout (MetaFrames *frames, - MetaUIFrame *frame) -{ - GtkWidget *widget; - MetaFrameFlags flags; - MetaFrameType type; - MetaFrameStyle *style; - - widget = GTK_WIDGET (frames); - - g_return_if_fail (gtk_widget_get_realized (widget)); - - meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - style = meta_theme_get_frame_style (meta_theme_get_current (), - type, flags); - - if (style != frame->cache_style) - { - if (frame->layout) - { - /* save title to recreate layout */ - g_free (frame->title); - - frame->title = g_strdup (pango_layout_get_text (frame->layout)); - - g_object_unref (G_OBJECT (frame->layout)); - frame->layout = NULL; - } - } - - frame->cache_style = style; - - if (frame->layout == NULL) - { - gpointer key, value; - PangoFontDescription *font_desc; - double scale; - int size; - - scale = meta_theme_get_title_scale (meta_theme_get_current (), - type, - flags); - - frame->layout = gtk_widget_create_pango_layout (widget, frame->title); - - pango_layout_set_ellipsize (frame->layout, PANGO_ELLIPSIZE_END); - pango_layout_set_auto_dir (frame->layout, FALSE); - pango_layout_set_single_paragraph_mode (frame->layout, TRUE); - - font_desc = meta_gtk_widget_get_font_desc (widget, scale, - meta_prefs_get_titlebar_font ()); - - size = pango_font_description_get_size (font_desc); - - if (g_hash_table_lookup_extended (frames->text_heights, - GINT_TO_POINTER (size), - &key, &value)) - { - frame->text_height = GPOINTER_TO_INT (value); - } - else - { - frame->text_height = - meta_pango_font_desc_get_text_height (font_desc, - gtk_widget_get_pango_context (widget)); - - g_hash_table_replace (frames->text_heights, - GINT_TO_POINTER (size), - GINT_TO_POINTER (frame->text_height)); - } - - pango_layout_set_font_description (frame->layout, - font_desc); - - pango_font_description_free (font_desc); - - /* Save some RAM */ - g_free (frame->title); - frame->title = NULL; - } -} - -static void -meta_frames_calc_geometry (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameGeometry *fgeom) -{ - int width, height; - MetaFrameFlags flags; - MetaFrameType type; - MetaButtonLayout button_layout; - - meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, - META_CORE_GET_CLIENT_WIDTH, &width, - META_CORE_GET_CLIENT_HEIGHT, &height, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - meta_frames_ensure_layout (frames, frame); - - meta_prefs_get_button_layout (&button_layout); - - meta_theme_calc_geometry (meta_theme_get_current (), - type, - frame->text_height, - flags, - width, height, - &button_layout, - fgeom); -} - -MetaFrames* -meta_frames_new (int screen_number) -{ - GdkScreen *screen; - - screen = gdk_display_get_screen (gdk_display_get_default (), - screen_number); - - return g_object_new (META_TYPE_FRAMES, - "screen", screen, - NULL); -} - -/* In order to use a style with a window it has to be attached to that - * window. Actually, the colormaps just have to match, but since GTK+ - * already takes care of making sure that its cheap to attach a style - * to multiple windows with the same colormap, we can just go ahead - * and attach separately for each window. - */ -static void -meta_frames_attach_style (MetaFrames *frames, - MetaUIFrame *frame) -{ - gboolean has_frame; - char *variant = NULL; - - if (frame->style != NULL) - g_object_unref (frame->style); - - meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - frame->xwindow, - META_CORE_WINDOW_HAS_FRAME, &has_frame, - META_CORE_GET_THEME_VARIANT, &variant, - META_CORE_GET_END); - - if (variant == NULL || strcmp(variant, "normal") == 0) - frame->style = g_object_ref (frames->normal_style); - else - frame->style = g_object_ref (meta_frames_get_theme_variant (frames, - variant)); -} - -void -meta_frames_manage_window (MetaFrames *frames, - Window xwindow, - GdkWindow *window) -{ - MetaUIFrame *frame; - - g_assert (window); - - frame = g_new (MetaUIFrame, 1); - - frame->window = window; - - gdk_window_set_user_data (frame->window, frames); - - frame->style = NULL; - - /* Don't set event mask here, it's in frame.c */ - - frame->xwindow = xwindow; - frame->cache_style = NULL; - frame->layout = NULL; - frame->text_height = -1; - frame->title = NULL; - frame->shape_applied = FALSE; - frame->prelit_control = META_FRAME_CONTROL_NONE; - - /* Don't set the window background yet; we need frame->xwindow to be - * registered with its MetaWindow, which happens after this function - * and meta_ui_create_frame_window() return to meta_window_ensure_frame(). - */ - - meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow); - - g_hash_table_replace (frames->frames, &frame->xwindow, frame); -} - -void -meta_frames_unmanage_window (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = g_hash_table_lookup (frames->frames, &xwindow); - - if (frame) - { - /* restore the cursor */ - meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - frame->xwindow, - META_CURSOR_DEFAULT); - - gdk_window_set_user_data (frame->window, NULL); - - if (frames->last_motion_frame == frame) - frames->last_motion_frame = NULL; - - g_hash_table_remove (frames->frames, &frame->xwindow); - - g_object_unref (frame->style); - - gdk_window_destroy (frame->window); - - if (frame->layout) - g_object_unref (G_OBJECT (frame->layout)); - - if (frame->title) - g_free (frame->title); - - g_free (frame); - } - else - meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow); -} - -static void -meta_frames_map (GtkWidget *widget) -{ - /* We override the parent map function to a no-op because we don't - * want to actually show the GDK window. But GTK needs to think that - * the widget is mapped or it won't deliver the events we care about. - */ - gtk_widget_set_mapped (widget, TRUE); -} - -static void -meta_frames_unmap (GtkWidget *widget) -{ - gtk_widget_set_mapped (widget, FALSE); -} - -static MetaUIFrame* -meta_frames_lookup_window (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = g_hash_table_lookup (frames->frames, &xwindow); - - return frame; -} - -static void -meta_ui_frame_get_borders (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameBorders *borders) -{ - MetaFrameFlags flags; - MetaFrameType type; - - meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - g_return_if_fail (type < META_FRAME_TYPE_LAST); - - meta_frames_ensure_layout (frames, frame); - - /* 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_theme_get_frame_borders (meta_theme_get_current (), - type, - frame->text_height, - flags, - borders); -} - -void -meta_frames_get_borders (MetaFrames *frames, - Window xwindow, - MetaFrameBorders *borders) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - if (frame == NULL) - meta_bug ("No such frame 0x%lx\n", xwindow); - - meta_ui_frame_get_borders (frames, frame, borders); -} - -static void -meta_ui_frame_get_corner_radiuses (MetaFrames *frames, - MetaUIFrame *frame, - float *top_left, - float *top_right, - float *bottom_left, - float *bottom_right) -{ - MetaFrameGeometry fgeom; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - /* For compatibility with the code in get_visible_rect(), there's - * a mysterious sqrt() added to the corner radiuses: - * - * const float radius = sqrt(corner) + corner; - * - * It's unclear why the radius is calculated like this, but we - * need to be consistent with it. - */ - - if (top_left) - *top_left = fgeom.top_left_corner_rounded_radius + sqrt(fgeom.top_left_corner_rounded_radius); - if (top_right) - *top_right = fgeom.top_right_corner_rounded_radius + sqrt(fgeom.top_right_corner_rounded_radius); - if (bottom_left) - *bottom_left = fgeom.bottom_left_corner_rounded_radius + sqrt(fgeom.bottom_left_corner_rounded_radius); - if (bottom_right) - *bottom_right = fgeom.bottom_right_corner_rounded_radius + sqrt(fgeom.bottom_right_corner_rounded_radius); -} - -void -meta_frames_reset_bg (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - meta_frames_set_window_background (frames, frame); -} - -static void -set_background_none (Display *xdisplay, - Window xwindow) -{ - XSetWindowAttributes attrs; - - attrs.background_pixmap = None; - XChangeWindowAttributes (xdisplay, xwindow, - CWBackPixmap, &attrs); -} - -void -meta_frames_unflicker_bg (MetaFrames *frames, - Window xwindow, - int target_width, - int target_height) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - g_return_if_fail (frame != NULL); - - set_background_none (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow); -} - -/* The client rectangle surrounds client window; it subtracts both - * the visible and invisible borders from the frame window's size. - */ -static void -get_client_rect (MetaFrameGeometry *fgeom, - int window_width, - int window_height, - cairo_rectangle_int_t *rect) -{ - rect->x = fgeom->borders.total.left; - rect->y = fgeom->borders.total.top; - rect->width = window_width - fgeom->borders.total.right - rect->x; - rect->height = window_height - fgeom->borders.total.bottom - rect->y; -} - -/* The visible frame rectangle surrounds the visible portion of the - * frame window; it subtracts only the invisible borders from the frame - * window's size. - */ -static void -get_visible_frame_rect (MetaFrameGeometry *fgeom, - int window_width, - int window_height, - cairo_rectangle_int_t *rect) -{ - rect->x = fgeom->borders.invisible.left; - rect->y = fgeom->borders.invisible.top; - rect->width = window_width - fgeom->borders.invisible.right - rect->x; - rect->height = window_height - fgeom->borders.invisible.bottom - rect->y; -} - -static cairo_region_t * -get_visible_region (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameGeometry *fgeom, - int window_width, - int window_height) -{ - cairo_region_t *corners_region; - cairo_region_t *visible_region; - cairo_rectangle_int_t rect; - cairo_rectangle_int_t frame_rect; - - corners_region = cairo_region_create (); - get_visible_frame_rect (fgeom, window_width, window_height, &frame_rect); - - if (fgeom->top_left_corner_rounded_radius != 0) - { - const int corner = fgeom->top_left_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; itop_right_corner_rounded_radius != 0) - { - const int corner = fgeom->top_right_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; ibottom_left_corner_rounded_radius != 0) - { - const int corner = fgeom->bottom_left_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; ibottom_right_corner_rounded_radius != 0) - { - const int corner = fgeom->bottom_right_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; iwindow); - old_height = gdk_window_get_height (frame->window); - - gdk_window_move_resize (frame->window, x, y, width, height); - - if (old_width != width || old_height != height) - invalidate_whole_window (frames, frame); -} - -void -meta_frames_queue_draw (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - invalidate_whole_window (frames, frame); -} - -void -meta_frames_set_title (MetaFrames *frames, - Window xwindow, - const char *title) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - g_assert (frame); - - g_free (frame->title); - frame->title = g_strdup (title); - - if (frame->layout) - { - g_object_unref (frame->layout); - frame->layout = NULL; - } - - invalidate_whole_window (frames, frame); -} - -void -meta_frames_update_frame_style (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - g_assert (frame); - - meta_frames_attach_style (frames, frame); - invalidate_whole_window (frames, frame); -} - -void -meta_frames_repaint_frame (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - g_assert (frame); - - /* repaint everything, so the other frame don't - * lag behind if they are exposed - */ - gdk_window_process_all_updates (); -} - -static void -redraw_control (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameControl control) -{ - MetaFrameGeometry fgeom; - GdkRectangle *rect; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - rect = control_rect (control, &fgeom); - - gdk_window_invalidate_rect (frame->window, rect, FALSE); -} - -static gboolean -meta_frame_titlebar_event (MetaUIFrame *frame, - GdkEventButton *event, - int action) -{ - MetaFrameFlags flags; - Display *display; - - display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - switch (action) - { - case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_SHADE: - { - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_SHADE) - { - if (flags & META_FRAME_SHADED) - meta_core_unshade (display, - frame->xwindow, - event->time); - else - meta_core_shade (display, - frame->xwindow, - event->time); - } - } - break; - - case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE: - { - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MAXIMIZE) - { - meta_core_toggle_maximize (display, frame->xwindow); - } - } - break; - - case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_HORIZONTALLY: - { - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MAXIMIZE) - { - meta_core_toggle_maximize_horizontally (display, frame->xwindow); - } - } - break; - - case G_DESKTOP_TITLEBAR_ACTION_TOGGLE_MAXIMIZE_VERTICALLY: - { - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MAXIMIZE) - { - meta_core_toggle_maximize_vertically (display, frame->xwindow); - } - } - break; - - case G_DESKTOP_TITLEBAR_ACTION_MINIMIZE: - { - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MINIMIZE) - { - meta_core_minimize (display, frame->xwindow); - } - } - break; - - case G_DESKTOP_TITLEBAR_ACTION_NONE: - /* Yaay, a sane user that doesn't use that other weird crap! */ - break; - - case G_DESKTOP_TITLEBAR_ACTION_LOWER: - meta_core_user_lower_and_unfocus (display, - frame->xwindow, - event->time); - break; - - case G_DESKTOP_TITLEBAR_ACTION_MENU: - meta_core_show_window_menu (display, - frame->xwindow, - event->x_root, - event->y_root, - event->button, - event->time); - break; - } - - return TRUE; -} - -static gboolean -meta_frame_double_click_event (MetaUIFrame *frame, - GdkEventButton *event) -{ - int action = meta_prefs_get_action_double_click_titlebar (); - - return meta_frame_titlebar_event (frame, event, action); -} - -static gboolean -meta_frame_middle_click_event (MetaUIFrame *frame, - GdkEventButton *event) -{ - int action = meta_prefs_get_action_middle_click_titlebar(); - - return meta_frame_titlebar_event (frame, event, action); -} - -static gboolean -meta_frame_right_click_event(MetaUIFrame *frame, - GdkEventButton *event) -{ - int action = meta_prefs_get_action_right_click_titlebar(); - - return meta_frame_titlebar_event (frame, event, action); -} - -static gboolean -meta_frames_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaFrameControl control; - Display *display; - - frames = META_FRAMES (widget); - display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - /* Remember that the display may have already done something with this event. - * If so there's probably a GrabOp in effect. - */ - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - control = get_control (frames, frame, event->x, event->y); - - /* focus on click, even if click was on client area */ - if (event->button == 1 && - !(control == META_FRAME_CONTROL_MINIMIZE || - control == META_FRAME_CONTROL_DELETE || - control == META_FRAME_CONTROL_MAXIMIZE)) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing window with frame 0x%lx due to button 1 press\n", - frame->xwindow); - meta_core_user_focus (display, - frame->xwindow, - event->time); - } - - /* don't do the rest of this if on client area */ - if (control == META_FRAME_CONTROL_CLIENT_AREA) - return FALSE; /* not on the frame, just passed through from client */ - - /* We want to shade even if we have a GrabOp, since we'll have a move grab - * if we double click the titlebar. - */ - if (control == META_FRAME_CONTROL_TITLE && - event->button == 1 && - event->type == GDK_2BUTTON_PRESS) - { - meta_core_end_grab_op (display, event->time); - return meta_frame_double_click_event (frame, event); - } - - if (meta_core_get_grab_op (display) != - META_GRAB_OP_NONE) - return FALSE; /* already up to something */ - - if (event->button == 1 && - (control == META_FRAME_CONTROL_MAXIMIZE || - control == META_FRAME_CONTROL_UNMAXIMIZE || - control == META_FRAME_CONTROL_MINIMIZE || - control == META_FRAME_CONTROL_DELETE || - control == META_FRAME_CONTROL_SHADE || - control == META_FRAME_CONTROL_UNSHADE || - control == META_FRAME_CONTROL_ABOVE || - control == META_FRAME_CONTROL_UNABOVE || - control == META_FRAME_CONTROL_STICK || - control == META_FRAME_CONTROL_UNSTICK || - control == META_FRAME_CONTROL_MENU)) - { - MetaGrabOp op = META_GRAB_OP_NONE; - - switch (control) - { - case META_FRAME_CONTROL_MINIMIZE: - op = META_GRAB_OP_CLICKING_MINIMIZE; - break; - case META_FRAME_CONTROL_MAXIMIZE: - op = META_GRAB_OP_CLICKING_MAXIMIZE; - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - op = META_GRAB_OP_CLICKING_UNMAXIMIZE; - break; - case META_FRAME_CONTROL_DELETE: - op = META_GRAB_OP_CLICKING_DELETE; - break; - case META_FRAME_CONTROL_MENU: - op = META_GRAB_OP_CLICKING_MENU; - break; - case META_FRAME_CONTROL_SHADE: - op = META_GRAB_OP_CLICKING_SHADE; - break; - case META_FRAME_CONTROL_UNSHADE: - op = META_GRAB_OP_CLICKING_UNSHADE; - break; - case META_FRAME_CONTROL_ABOVE: - op = META_GRAB_OP_CLICKING_ABOVE; - break; - case META_FRAME_CONTROL_UNABOVE: - op = META_GRAB_OP_CLICKING_UNABOVE; - break; - case META_FRAME_CONTROL_STICK: - op = META_GRAB_OP_CLICKING_STICK; - break; - case META_FRAME_CONTROL_UNSTICK: - op = META_GRAB_OP_CLICKING_UNSTICK; - break; - default: - g_assert_not_reached (); - break; - } - - meta_core_begin_grab_op (display, - frame->xwindow, - op, - TRUE, - TRUE, - event->button, - 0, - event->time, - event->x_root, - event->y_root); - - frame->prelit_control = control; - redraw_control (frames, frame, control); - - if (op == META_GRAB_OP_CLICKING_MENU) - { - MetaFrameGeometry fgeom; - GdkRectangle *rect; - int dx, dy; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom); - - /* get delta to convert to root coords */ - dx = event->x_root - event->x; - dy = event->y_root - event->y; - - /* Align to the right end of the menu rectangle if RTL */ - if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) - dx += rect->width; - - meta_core_show_window_menu (display, - frame->xwindow, - rect->x + dx, - rect->y + rect->height + dy, - event->button, - event->time); - } - } - else if (event->button == 1 && - (control == META_FRAME_CONTROL_RESIZE_SE || - control == META_FRAME_CONTROL_RESIZE_S || - control == META_FRAME_CONTROL_RESIZE_SW || - control == META_FRAME_CONTROL_RESIZE_NE || - control == META_FRAME_CONTROL_RESIZE_N || - control == META_FRAME_CONTROL_RESIZE_NW || - control == META_FRAME_CONTROL_RESIZE_E || - control == META_FRAME_CONTROL_RESIZE_W)) - { - MetaGrabOp op; - - op = META_GRAB_OP_NONE; - - switch (control) - { - case META_FRAME_CONTROL_RESIZE_SE: - op = META_GRAB_OP_RESIZING_SE; - break; - case META_FRAME_CONTROL_RESIZE_S: - op = META_GRAB_OP_RESIZING_S; - break; - case META_FRAME_CONTROL_RESIZE_SW: - op = META_GRAB_OP_RESIZING_SW; - break; - case META_FRAME_CONTROL_RESIZE_NE: - op = META_GRAB_OP_RESIZING_NE; - break; - case META_FRAME_CONTROL_RESIZE_N: - op = META_GRAB_OP_RESIZING_N; - break; - case META_FRAME_CONTROL_RESIZE_NW: - op = META_GRAB_OP_RESIZING_NW; - break; - case META_FRAME_CONTROL_RESIZE_E: - op = META_GRAB_OP_RESIZING_E; - break; - case META_FRAME_CONTROL_RESIZE_W: - op = META_GRAB_OP_RESIZING_W; - break; - default: - g_assert_not_reached (); - break; - } - - meta_core_begin_grab_op (display, - frame->xwindow, - op, - TRUE, - TRUE, - event->button, - 0, - event->time, - event->x_root, - event->y_root); - } - else if (control == META_FRAME_CONTROL_TITLE && - event->button == 1) - { - MetaFrameFlags flags; - - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MOVE) - { - meta_core_begin_grab_op (display, - frame->xwindow, - META_GRAB_OP_MOVING, - TRUE, - TRUE, - event->button, - 0, - event->time, - event->x_root, - event->y_root); - } - } - else if (event->button == 2) - { - return meta_frame_middle_click_event (frame, event); - } - else if (event->button == 3) - { - return meta_frame_right_click_event (frame, event); - } - - return TRUE; -} - -void -meta_frames_notify_menu_hide (MetaFrames *frames) -{ - Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - if (meta_core_get_grab_op (display) == - META_GRAB_OP_CLICKING_MENU) - { - Window grab_frame; - - grab_frame = meta_core_get_grab_frame (display); - - if (grab_frame != None) - { - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, grab_frame); - - if (frame) - { - redraw_control (frames, frame, - META_FRAME_CONTROL_MENU); - meta_core_end_grab_op (display, CurrentTime); - } - } - } -} - -static gboolean -meta_frames_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaGrabOp op; - Display *display; - - frames = META_FRAMES (widget); - display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - op = meta_core_get_grab_op (display); - - if (op == META_GRAB_OP_NONE) - return FALSE; - - /* We only handle the releases we handled the presses for (things - * involving frame controls). Window ops that don't require a - * frame are handled in the Xlib part of the code, display.c/window.c - */ - if (frame->xwindow == meta_core_get_grab_frame (display) && - ((int) event->button) == meta_core_get_grab_button (display)) - { - MetaFrameControl control; - - control = get_control (frames, frame, event->x, event->y); - - switch (op) - { - case META_GRAB_OP_CLICKING_MINIMIZE: - if (control == META_FRAME_CONTROL_MINIMIZE) - meta_core_minimize (display, frame->xwindow); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_MAXIMIZE: - if (control == META_FRAME_CONTROL_MAXIMIZE) - { - /* Focus the window on the maximize */ - meta_core_user_focus (display, - frame->xwindow, - event->time); - meta_core_maximize (display, frame->xwindow); - } - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNMAXIMIZE: - if (control == META_FRAME_CONTROL_UNMAXIMIZE) - meta_core_unmaximize (display, frame->xwindow); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_DELETE: - if (control == META_FRAME_CONTROL_DELETE) - meta_core_delete (display, frame->xwindow, event->time); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_MENU: - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_SHADE: - if (control == META_FRAME_CONTROL_SHADE) - meta_core_shade (display, frame->xwindow, event->time); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNSHADE: - if (control == META_FRAME_CONTROL_UNSHADE) - meta_core_unshade (display, frame->xwindow, event->time); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_ABOVE: - if (control == META_FRAME_CONTROL_ABOVE) - meta_core_make_above (display, frame->xwindow); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNABOVE: - if (control == META_FRAME_CONTROL_UNABOVE) - meta_core_unmake_above (display, frame->xwindow); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_STICK: - if (control == META_FRAME_CONTROL_STICK) - meta_core_stick (display, frame->xwindow); - - meta_core_end_grab_op (display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNSTICK: - if (control == META_FRAME_CONTROL_UNSTICK) - meta_core_unstick (display, frame->xwindow); - - meta_core_end_grab_op (display, event->time); - break; - - default: - break; - } - - /* Update the prelit control regardless of what button the mouse - * was released over; needed so that the new button can become - * prelit so to let the user know that it can now be pressed. - * :) - */ - meta_frames_update_prelit_control (frames, frame, control); - } - - return TRUE; -} - -static void -meta_frames_update_prelit_control (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameControl control) -{ - MetaFrameControl old_control; - MetaCursor cursor; - - - meta_verbose ("Updating prelit control from %u to %u\n", - frame->prelit_control, control); - - cursor = META_CURSOR_DEFAULT; - - switch (control) - { - case META_FRAME_CONTROL_CLIENT_AREA: - break; - case META_FRAME_CONTROL_NONE: - break; - case META_FRAME_CONTROL_TITLE: - break; - case META_FRAME_CONTROL_DELETE: - break; - case META_FRAME_CONTROL_MENU: - break; - case META_FRAME_CONTROL_MINIMIZE: - break; - case META_FRAME_CONTROL_MAXIMIZE: - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - break; - case META_FRAME_CONTROL_SHADE: - break; - case META_FRAME_CONTROL_UNSHADE: - break; - case META_FRAME_CONTROL_ABOVE: - break; - case META_FRAME_CONTROL_UNABOVE: - break; - case META_FRAME_CONTROL_STICK: - break; - case META_FRAME_CONTROL_UNSTICK: - break; - case META_FRAME_CONTROL_RESIZE_SE: - cursor = META_CURSOR_SE_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_S: - cursor = META_CURSOR_SOUTH_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_SW: - cursor = META_CURSOR_SW_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_N: - cursor = META_CURSOR_NORTH_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_NE: - cursor = META_CURSOR_NE_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_NW: - cursor = META_CURSOR_NW_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_W: - cursor = META_CURSOR_WEST_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_E: - cursor = META_CURSOR_EAST_RESIZE; - break; - } - - /* set/unset the prelight cursor */ - meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - frame->xwindow, - cursor); - - switch (control) - { - case META_FRAME_CONTROL_MENU: - case META_FRAME_CONTROL_MINIMIZE: - case META_FRAME_CONTROL_MAXIMIZE: - case META_FRAME_CONTROL_DELETE: - case META_FRAME_CONTROL_SHADE: - case META_FRAME_CONTROL_UNSHADE: - case META_FRAME_CONTROL_ABOVE: - case META_FRAME_CONTROL_UNABOVE: - case META_FRAME_CONTROL_STICK: - case META_FRAME_CONTROL_UNSTICK: - case META_FRAME_CONTROL_UNMAXIMIZE: - /* leave control set */ - break; - default: - /* Only prelight buttons */ - control = META_FRAME_CONTROL_NONE; - break; - } - - if (control == frame->prelit_control) - return; - - /* Save the old control so we can unprelight it */ - old_control = frame->prelit_control; - - frame->prelit_control = control; - - redraw_control (frames, frame, old_control); - redraw_control (frames, frame, control); -} - -static gboolean -meta_frames_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaGrabOp grab_op; - Display *display; - - frames = META_FRAMES (widget); - display = GDK_DISPLAY_XDISPLAY (gdk_window_get_display (event->window)); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - frames->last_motion_frame = frame; - - grab_op = meta_core_get_grab_op (display); - - switch (grab_op) - { - case META_GRAB_OP_CLICKING_MENU: - case META_GRAB_OP_CLICKING_DELETE: - case META_GRAB_OP_CLICKING_MINIMIZE: - case META_GRAB_OP_CLICKING_MAXIMIZE: - case META_GRAB_OP_CLICKING_UNMAXIMIZE: - case META_GRAB_OP_CLICKING_SHADE: - case META_GRAB_OP_CLICKING_UNSHADE: - case META_GRAB_OP_CLICKING_ABOVE: - case META_GRAB_OP_CLICKING_UNABOVE: - case META_GRAB_OP_CLICKING_STICK: - case META_GRAB_OP_CLICKING_UNSTICK: - { - MetaFrameControl control; - int x, y; - - gdk_window_get_device_position (frame->window, event->device, - &x, &y, NULL); - - /* Control is set to none unless it matches - * the current grab - */ - control = get_control (frames, frame, x, y); - if (! ((control == META_FRAME_CONTROL_MENU && - grab_op == META_GRAB_OP_CLICKING_MENU) || - (control == META_FRAME_CONTROL_DELETE && - grab_op == META_GRAB_OP_CLICKING_DELETE) || - (control == META_FRAME_CONTROL_MINIMIZE && - grab_op == META_GRAB_OP_CLICKING_MINIMIZE) || - ((control == META_FRAME_CONTROL_MAXIMIZE || - control == META_FRAME_CONTROL_UNMAXIMIZE) && - (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || - grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) || - (control == META_FRAME_CONTROL_SHADE && - grab_op == META_GRAB_OP_CLICKING_SHADE) || - (control == META_FRAME_CONTROL_UNSHADE && - grab_op == META_GRAB_OP_CLICKING_UNSHADE) || - (control == META_FRAME_CONTROL_ABOVE && - grab_op == META_GRAB_OP_CLICKING_ABOVE) || - (control == META_FRAME_CONTROL_UNABOVE && - grab_op == META_GRAB_OP_CLICKING_UNABOVE) || - (control == META_FRAME_CONTROL_STICK && - grab_op == META_GRAB_OP_CLICKING_STICK) || - (control == META_FRAME_CONTROL_UNSTICK && - grab_op == META_GRAB_OP_CLICKING_UNSTICK))) - control = META_FRAME_CONTROL_NONE; - - /* Update prelit control and cursor */ - meta_frames_update_prelit_control (frames, frame, control); - } - break; - case META_GRAB_OP_NONE: - { - MetaFrameControl control; - int x, y; - - gdk_window_get_device_position (frame->window, event->device, - &x, &y, NULL); - - control = get_control (frames, frame, x, y); - - /* Update prelit control and cursor */ - meta_frames_update_prelit_control (frames, frame, control); - } - break; - - default: - break; - } - - return TRUE; -} - -static gboolean -meta_frames_destroy_event (GtkWidget *widget, - GdkEventAny *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - return TRUE; -} - - -static void -setup_bg_cr (cairo_t *cr, GdkWindow *window, int x_offset, int y_offset) -{ - GdkWindow *parent = gdk_window_get_parent (window); - cairo_pattern_t *bg_pattern; - - bg_pattern = gdk_window_get_background_pattern (window); - if (bg_pattern == NULL && parent) - { - gint window_x, window_y; - - gdk_window_get_position (window, &window_x, &window_y); - setup_bg_cr (cr, parent, x_offset + window_x, y_offset + window_y); - } - else if (bg_pattern) - { - cairo_translate (cr, - x_offset, - y_offset); - cairo_set_source (cr, bg_pattern); - cairo_translate (cr, x_offset, y_offset); - } -} - -static void -clip_region_to_visible_frame_border (cairo_region_t *region, - MetaUIFrame *frame) -{ - cairo_rectangle_int_t area; - cairo_region_t *frame_border; - MetaFrameFlags flags; - MetaFrameType type; - MetaFrameBorders borders; - Display *display; - int frame_width, frame_height; - - display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_FRAME_WIDTH, &frame_width, - META_CORE_GET_FRAME_HEIGHT, &frame_height, - META_CORE_GET_END); - - meta_theme_get_frame_borders (meta_theme_get_current (), - type, frame->text_height, flags, - &borders); - - /* Visible frame rect */ - area.x = borders.invisible.left; - area.y = borders.invisible.top; - area.width = frame_width - borders.invisible.left - borders.invisible.right; - area.height = frame_height - borders.invisible.top - borders.invisible.bottom; - - frame_border = cairo_region_create_rectangle (&area); - - /* Client rect */ - area.x += borders.visible.left; - area.y += borders.visible.top; - area.width -= borders.visible.left + borders.visible.right; - area.height -= borders.visible.top + borders.visible.bottom; - - /* Visible frame border */ - cairo_region_subtract_rectangle (frame_border, &area); - cairo_region_intersect (region, frame_border); - - cairo_region_destroy (frame_border); -} - -#define TAU (2*M_PI) - -/* - * Draw the opaque and semi-opaque pixels of this frame into a mask. - * - * (0,0) in Cairo coordinates is assumed to be the top left corner of the - * invisible border. - * - * The parts of @cr's surface in the clip region are assumed to be - * initialized to fully-transparent, and the clip region is assumed to - * contain the invisible border and the visible parts of the frame, but - * not the client area. - * - * This function uses @cr to draw pixels of arbitrary color (it will - * typically be drawing in a %CAIRO_FORMAT_A8 surface, so the color is - * discarded anyway) with appropriate alpha values to reproduce this - * frame's alpha channel, as a mask to be applied to an opaque pixmap. - * - * @frame: This frame - * @xwindow: The X window for the frame, which has the client window as a child - * @width: The width of the framed window including any invisible borders - * @height: The height of the framed window including any invisible borders - * @cr: Used to draw the resulting mask - */ -void -meta_frames_get_mask (MetaFrames *frames, - Window xwindow, - guint width, - guint height, - cairo_t *cr) -{ - MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow); - float top_left, top_right, bottom_left, bottom_right; - int x, y; - MetaFrameBorders borders; - - if (frame == NULL) - meta_bug ("No such frame 0x%lx\n", xwindow); - - cairo_save (cr); - - meta_ui_frame_get_borders (frames, frame, &borders); - meta_ui_frame_get_corner_radiuses (frames, frame, - &top_left, &top_right, - &bottom_left, &bottom_right); - - /* top left */ - x = borders.invisible.left; - y = borders.invisible.top; - - cairo_arc (cr, - x + top_left, - y + top_left, - top_left, - 2 * TAU / 4, - 3 * TAU / 4); - - /* top right */ - x = width - borders.invisible.right - top_right; - y = borders.invisible.top; - - cairo_arc (cr, - x, - y + top_right, - top_right, - 3 * TAU / 4, - 4 * TAU / 4); - - /* bottom right */ - x = width - borders.invisible.right - bottom_right; - y = height - borders.invisible.bottom - bottom_right; - - cairo_arc (cr, - x, - y, - bottom_right, - 0 * TAU / 4, - 1 * TAU / 4); - - /* bottom left */ - x = borders.invisible.left; - y = height - borders.invisible.bottom - bottom_left; - - cairo_arc (cr, - x + bottom_left, - y, - bottom_left, - 1 * TAU / 4, - 2 * TAU / 4); - - cairo_set_source_rgba (cr, 1, 1, 1, 1); - cairo_fill (cr); - - cairo_restore (cr); -} - -static gboolean -meta_frames_draw (GtkWidget *widget, - cairo_t *cr) -{ - MetaUIFrame *frame; - MetaFrames *frames; - cairo_rectangle_int_t clip; - cairo_region_t *region; - cairo_surface_t *target; - - frames = META_FRAMES (widget); - target = cairo_get_target (cr); - gdk_cairo_get_clip_rectangle (cr, &clip); - - g_assert (cairo_surface_get_type (target) == CAIRO_SURFACE_TYPE_XLIB); - frame = meta_frames_lookup_window (frames, cairo_xlib_surface_get_drawable (target)); - if (frame == NULL) - return FALSE; - - region = cairo_region_create_rectangle (&clip); - clip_region_to_visible_frame_border (region, frame); - - if (cairo_region_is_empty (region)) - goto out; - - gdk_cairo_region (cr, region); - cairo_clip (cr); - - cairo_save (cr); - setup_bg_cr (cr, frame->window, 0, 0); - cairo_paint (cr); - cairo_restore (cr); - - meta_frames_paint (frames, frame, cr); - - out: - cairo_region_destroy (region); - - return TRUE; -} - -static void -meta_frames_paint (MetaFrames *frames, - MetaUIFrame *frame, - cairo_t *cr) -{ - MetaFrameFlags flags; - MetaFrameType type; - GdkPixbuf *mini_icon; - GdkPixbuf *icon; - int w, h; - MetaButtonState button_states[META_BUTTON_TYPE_LAST]; - Window grab_frame; - int i; - MetaButtonLayout button_layout; - MetaGrabOp grab_op; - Display *display; - - display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()); - - for (i = 0; i < META_BUTTON_TYPE_LAST; i++) - button_states[i] = META_BUTTON_STATE_NORMAL; - - grab_frame = meta_core_get_grab_frame (display); - grab_op = meta_core_get_grab_op (display); - if (grab_frame != frame->xwindow) - grab_op = META_GRAB_OP_NONE; - - /* Set prelight state */ - switch (frame->prelit_control) - { - case META_FRAME_CONTROL_MENU: - if (grab_op == META_GRAB_OP_CLICKING_MENU) - button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_MINIMIZE: - if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE) - button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_MAXIMIZE: - if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE) - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE) - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_SHADE: - if (grab_op == META_GRAB_OP_CLICKING_SHADE) - button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNSHADE: - if (grab_op == META_GRAB_OP_CLICKING_UNSHADE) - button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_ABOVE: - if (grab_op == META_GRAB_OP_CLICKING_ABOVE) - button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNABOVE: - if (grab_op == META_GRAB_OP_CLICKING_UNABOVE) - button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_STICK: - if (grab_op == META_GRAB_OP_CLICKING_STICK) - button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNSTICK: - if (grab_op == META_GRAB_OP_CLICKING_UNSTICK) - button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_DELETE: - if (grab_op == META_GRAB_OP_CLICKING_DELETE) - button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT; - break; - default: - break; - } - - meta_core_get (display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_MINI_ICON, &mini_icon, - META_CORE_GET_ICON, &icon, - META_CORE_GET_CLIENT_WIDTH, &w, - META_CORE_GET_CLIENT_HEIGHT, &h, - META_CORE_GET_END); - - meta_frames_ensure_layout (frames, frame); - - meta_prefs_get_button_layout (&button_layout); - - meta_theme_draw_frame (meta_theme_get_current (), - frame->style, - cr, - type, - flags, - w, h, - frame->layout, - frame->text_height, - &button_layout, - button_states, - mini_icon, icon); -} - -static void -meta_frames_set_window_background (MetaFrames *frames, - MetaUIFrame *frame) -{ - MetaFrameFlags flags; - MetaFrameType type; - MetaFrameStyle *style = NULL; - gboolean frame_exists; - - meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, - META_CORE_WINDOW_HAS_FRAME, &frame_exists, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - if (frame_exists) - { - style = meta_theme_get_frame_style (meta_theme_get_current (), - type, flags); - } - - if (frame_exists && style->window_background_color != NULL) - { - GdkRGBA color; - GdkVisual *visual; - - meta_color_spec_render (style->window_background_color, - frame->style, - &color); - - /* Set A in ARGB to window_background_alpha, if we have ARGB */ - - visual = gtk_widget_get_visual (GTK_WIDGET (frames)); - if (gdk_visual_get_depth (visual) == 32) /* we have ARGB */ - { - color.alpha = style->window_background_alpha / 255.0; - } - - gdk_window_set_background_rgba (frame->window, &color); - } - else - { - gtk_style_context_set_background (frame->style, frame->window); - } - } - -static gboolean -meta_frames_enter_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaFrameControl control; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - control = get_control (frames, frame, event->x, event->y); - meta_frames_update_prelit_control (frames, frame, control); - - return TRUE; -} - -static gboolean -meta_frames_leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE); - - return TRUE; -} - -static GdkRectangle* -control_rect (MetaFrameControl control, - MetaFrameGeometry *fgeom) -{ - GdkRectangle *rect; - - rect = NULL; - switch (control) - { - case META_FRAME_CONTROL_TITLE: - rect = &fgeom->title_rect; - break; - case META_FRAME_CONTROL_DELETE: - rect = &fgeom->close_rect.visible; - break; - case META_FRAME_CONTROL_MENU: - rect = &fgeom->menu_rect.visible; - break; - case META_FRAME_CONTROL_MINIMIZE: - rect = &fgeom->min_rect.visible; - break; - case META_FRAME_CONTROL_MAXIMIZE: - case META_FRAME_CONTROL_UNMAXIMIZE: - rect = &fgeom->max_rect.visible; - break; - case META_FRAME_CONTROL_SHADE: - rect = &fgeom->shade_rect.visible; - break; - case META_FRAME_CONTROL_UNSHADE: - rect = &fgeom->unshade_rect.visible; - break; - case META_FRAME_CONTROL_ABOVE: - rect = &fgeom->above_rect.visible; - break; - case META_FRAME_CONTROL_UNABOVE: - rect = &fgeom->unabove_rect.visible; - break; - case META_FRAME_CONTROL_STICK: - rect = &fgeom->stick_rect.visible; - break; - case META_FRAME_CONTROL_UNSTICK: - rect = &fgeom->unstick_rect.visible; - break; - case META_FRAME_CONTROL_RESIZE_SE: - break; - case META_FRAME_CONTROL_RESIZE_S: - break; - case META_FRAME_CONTROL_RESIZE_SW: - break; - case META_FRAME_CONTROL_RESIZE_N: - break; - case META_FRAME_CONTROL_RESIZE_NE: - break; - case META_FRAME_CONTROL_RESIZE_NW: - break; - case META_FRAME_CONTROL_RESIZE_W: - break; - case META_FRAME_CONTROL_RESIZE_E: - break; - case META_FRAME_CONTROL_NONE: - break; - case META_FRAME_CONTROL_CLIENT_AREA: - break; - } - - return rect; -} - -#define TOP_RESIZE_HEIGHT 4 -#define CORNER_SIZE_MULT 2 -static MetaFrameControl -get_control (MetaFrames *frames, - MetaUIFrame *frame, - int x, int y) -{ - MetaFrameGeometry fgeom; - MetaFrameFlags flags; - MetaFrameType type; - gboolean has_vert, has_horiz; - gboolean has_north_resize; - cairo_rectangle_int_t client; - - meta_frames_calc_geometry (frames, frame, &fgeom); - get_client_rect (&fgeom, fgeom.width, fgeom.height, &client); - - if (POINT_IN_RECT (x, y, client)) - return META_FRAME_CONTROL_CLIENT_AREA; - - if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable)) - return META_FRAME_CONTROL_DELETE; - - if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable)) - return META_FRAME_CONTROL_MINIMIZE; - - if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable)) - return META_FRAME_CONTROL_MENU; - - meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - has_north_resize = (type != META_FRAME_TYPE_ATTACHED); - has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0; - has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0; - - if (POINT_IN_RECT (x, y, fgeom.title_rect)) - { - if (has_vert && y <= TOP_RESIZE_HEIGHT && has_north_resize) - return META_FRAME_CONTROL_RESIZE_N; - else - return META_FRAME_CONTROL_TITLE; - } - - if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable)) - { - if (flags & META_FRAME_MAXIMIZED) - return META_FRAME_CONTROL_UNMAXIMIZE; - else - return META_FRAME_CONTROL_MAXIMIZE; - } - - if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable)) - { - return META_FRAME_CONTROL_SHADE; - } - - if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable)) - { - return META_FRAME_CONTROL_UNSHADE; - } - - if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable)) - { - return META_FRAME_CONTROL_ABOVE; - } - - if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable)) - { - return META_FRAME_CONTROL_UNABOVE; - } - - if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable)) - { - return META_FRAME_CONTROL_STICK; - } - - if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable)) - { - return META_FRAME_CONTROL_UNSTICK; - } - - /* South resize always has priority over north resize, - * in case of overlap. - */ - - if (y >= (fgeom.height - fgeom.borders.total.bottom * CORNER_SIZE_MULT) && - x >= (fgeom.width - fgeom.borders.total.right * CORNER_SIZE_MULT)) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_SE; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_S; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_E; - } - else if (y >= (fgeom.height - fgeom.borders.total.bottom * CORNER_SIZE_MULT) && - x <= fgeom.borders.total.left * CORNER_SIZE_MULT) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_SW; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_S; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_W; - } - else if (y < (fgeom.borders.invisible.top * CORNER_SIZE_MULT) && - x <= (fgeom.borders.total.left * CORNER_SIZE_MULT) && has_north_resize) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_NW; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_N; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_W; - } - else if (y < (fgeom.borders.invisible.top * CORNER_SIZE_MULT) && - x >= (fgeom.width - fgeom.borders.total.right * CORNER_SIZE_MULT) && has_north_resize) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_NE; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_N; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_E; - } - else if (y < (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT)) - { - if (has_vert && has_north_resize) - return META_FRAME_CONTROL_RESIZE_N; - } - else if (y >= (fgeom.height - fgeom.borders.total.bottom)) - { - if (has_vert) - return META_FRAME_CONTROL_RESIZE_S; - } - else if (x <= fgeom.borders.total.left) - { - if (has_horiz) - return META_FRAME_CONTROL_RESIZE_W; - } - else if (x >= (fgeom.width - fgeom.borders.total.right)) - { - if (has_horiz) - return META_FRAME_CONTROL_RESIZE_E; - } - - if (y >= fgeom.borders.total.top) - return META_FRAME_CONTROL_NONE; - else - return META_FRAME_CONTROL_TITLE; -} - -static void -invalidate_whole_window (MetaFrames *frames, - MetaUIFrame *frame) -{ - gdk_window_invalidate_rect (frame->window, NULL, FALSE); -} diff --git a/src/ui/frames.h b/src/ui/frames.h deleted file mode 100644 index c0618f399..000000000 --- a/src/ui/frames.h +++ /dev/null @@ -1,160 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity window frame manager widget */ - -/* - * Copyright (C) 2001 Havoc Pennington - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#ifndef META_FRAMES_H -#define META_FRAMES_H - -#include -#include -#include -#include "theme-private.h" - -typedef enum -{ - META_FRAME_CONTROL_NONE, - META_FRAME_CONTROL_TITLE, - META_FRAME_CONTROL_DELETE, - META_FRAME_CONTROL_MENU, - META_FRAME_CONTROL_MINIMIZE, - META_FRAME_CONTROL_MAXIMIZE, - META_FRAME_CONTROL_UNMAXIMIZE, - META_FRAME_CONTROL_SHADE, - META_FRAME_CONTROL_UNSHADE, - META_FRAME_CONTROL_ABOVE, - META_FRAME_CONTROL_UNABOVE, - META_FRAME_CONTROL_STICK, - META_FRAME_CONTROL_UNSTICK, - META_FRAME_CONTROL_RESIZE_SE, - META_FRAME_CONTROL_RESIZE_S, - META_FRAME_CONTROL_RESIZE_SW, - META_FRAME_CONTROL_RESIZE_N, - META_FRAME_CONTROL_RESIZE_NE, - META_FRAME_CONTROL_RESIZE_NW, - META_FRAME_CONTROL_RESIZE_W, - META_FRAME_CONTROL_RESIZE_E, - META_FRAME_CONTROL_CLIENT_AREA -} MetaFrameControl; - -/* This is one widget that manages all the window frames - * as subwindows. - */ - -#define META_TYPE_FRAMES (meta_frames_get_type ()) -#define META_FRAMES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_FRAMES, MetaFrames)) -#define META_FRAMES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_FRAMES, MetaFramesClass)) -#define META_IS_FRAMES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_FRAMES)) -#define META_IS_FRAMES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_FRAMES)) -#define META_FRAMES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_FRAMES, MetaFramesClass)) - -typedef struct _MetaFrames MetaFrames; -typedef struct _MetaFramesClass MetaFramesClass; - -typedef struct _MetaUIFrame MetaUIFrame; - -struct _MetaUIFrame -{ - Window xwindow; - GdkWindow *window; - GtkStyleContext *style; - MetaFrameStyle *cache_style; - PangoLayout *layout; - int text_height; - char *title; /* NULL once we have a layout */ - guint shape_applied : 1; - - /* FIXME get rid of this, it can just be in the MetaFrames struct */ - MetaFrameControl prelit_control; -}; - -struct _MetaFrames -{ - GtkWindow parent_instance; - - GHashTable *text_heights; - - GHashTable *frames; - MetaUIFrame *last_motion_frame; - - GtkStyleContext *normal_style; - GHashTable *style_variants; -}; - -struct _MetaFramesClass -{ - GtkWindowClass parent_class; - -}; - -GType meta_frames_get_type (void) G_GNUC_CONST; - -MetaFrames *meta_frames_new (int screen_number); - -void meta_frames_manage_window (MetaFrames *frames, - Window xwindow, - GdkWindow *window); -void meta_frames_unmanage_window (MetaFrames *frames, - Window xwindow); -void meta_frames_set_title (MetaFrames *frames, - Window xwindow, - const char *title); - -void meta_frames_update_frame_style (MetaFrames *frames, - Window xwindow); - -void meta_frames_repaint_frame (MetaFrames *frames, - Window xwindow); - -void meta_frames_get_borders (MetaFrames *frames, - Window xwindow, - MetaFrameBorders *borders); - -void meta_frames_reset_bg (MetaFrames *frames, - Window xwindow); -void meta_frames_unflicker_bg (MetaFrames *frames, - Window xwindow, - int target_width, - int target_height); - -cairo_region_t *meta_frames_get_frame_bounds (MetaFrames *frames, - Window xwindow, - int window_width, - int window_height); - -void meta_frames_get_mask (MetaFrames *frames, - Window xwindow, - guint width, - guint height, - cairo_t *cr); - -void meta_frames_move_resize_frame (MetaFrames *frames, - Window xwindow, - int x, - int y, - int width, - int height); -void meta_frames_queue_draw (MetaFrames *frames, - Window xwindow); - -void meta_frames_notify_menu_hide (MetaFrames *frames); - -Window meta_frames_get_moving_frame (MetaFrames *frames); - -#endif diff --git a/src/ui/gradient.c b/src/ui/gradient.c deleted file mode 100644 index e3ce60bb5..000000000 --- a/src/ui/gradient.c +++ /dev/null @@ -1,873 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* - * Copyright (C) 2001 Havoc Pennington, 99% copied from wrlib in - * WindowMaker, Copyright (C) 1997-2000 Dan Pascu and Alfredo Kojima - * Copyright (C) 2005 Elijah Newren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . */ - -/** - * SECTION:gradient - * @title: Gradients - * @short_description: Metacity gradient rendering - */ - -#include -#include -#include - -/* This is all Alfredo's and Dan's usual very nice WindowMaker code, - * slightly GTK-ized - */ -static GdkPixbuf* meta_gradient_create_horizontal (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to); -static GdkPixbuf* meta_gradient_create_vertical (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to); -static GdkPixbuf* meta_gradient_create_diagonal (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to); -static GdkPixbuf* meta_gradient_create_multi_horizontal (int width, - int height, - const GdkRGBA *colors, - int count); -static GdkPixbuf* meta_gradient_create_multi_vertical (int width, - int height, - const GdkRGBA *colors, - int count); -static GdkPixbuf* meta_gradient_create_multi_diagonal (int width, - int height, - const GdkRGBA *colors, - int count); - - -/* Used as the destroy notification function for gdk_pixbuf_new() */ -static void -free_buffer (guchar *pixels, gpointer data) -{ - g_free (pixels); -} - -static GdkPixbuf* -blank_pixbuf (int width, int height, gboolean no_padding) -{ - guchar *buf; - int rowstride; - - g_return_val_if_fail (width > 0, NULL); - g_return_val_if_fail (height > 0, NULL); - - if (no_padding) - rowstride = width * 3; - else - /* Always align rows to 32-bit boundaries */ - rowstride = 4 * ((3 * width + 3) / 4); - - buf = g_try_malloc (height * rowstride); - if (!buf) - return NULL; - - return gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB, - FALSE, 8, - width, height, rowstride, - free_buffer, NULL); -} - -/** - * meta_gradient_create_simple: - * @width: Width in pixels - * @height: Height in pixels - * @from: Starting color - * @to: Ending color - * @style: Gradient style - * - * Returns: (transfer full): A new linear gradient - */ -GdkPixbuf* -meta_gradient_create_simple (int width, - int height, - const GdkRGBA *from, - const GdkRGBA *to, - MetaGradientType style) -{ - switch (style) - { - case META_GRADIENT_HORIZONTAL: - return meta_gradient_create_horizontal (width, height, - from, to); - case META_GRADIENT_VERTICAL: - return meta_gradient_create_vertical (width, height, - from, to); - - case META_GRADIENT_DIAGONAL: - return meta_gradient_create_diagonal (width, height, - from, to); - case META_GRADIENT_LAST: - break; - } - g_assert_not_reached (); - return NULL; -} - -/** - * meta_gradient_create_multi: - * @width: Width in pixels - * @height: Height in pixels - * @colors: (array length=n_colors): Array of colors - * @n_colors: Number of colors - * @style: Gradient style - * - * Returns: (transfer full): A new multi-step linear gradient - */ -GdkPixbuf* -meta_gradient_create_multi (int width, - int height, - const GdkRGBA *colors, - int n_colors, - MetaGradientType style) -{ - - if (n_colors > 2) - { - switch (style) - { - case META_GRADIENT_HORIZONTAL: - return meta_gradient_create_multi_horizontal (width, height, colors, n_colors); - case META_GRADIENT_VERTICAL: - return meta_gradient_create_multi_vertical (width, height, colors, n_colors); - case META_GRADIENT_DIAGONAL: - return meta_gradient_create_multi_diagonal (width, height, colors, n_colors); - case META_GRADIENT_LAST: - g_assert_not_reached (); - break; - } - } - else if (n_colors > 1) - { - return meta_gradient_create_simple (width, height, &colors[0], &colors[1], - style); - } - else if (n_colors > 0) - { - return meta_gradient_create_simple (width, height, &colors[0], &colors[0], - style); - } - g_assert_not_reached (); - return NULL; -} - -/** - * meta_gradient_create_interwoven: (skip) - * @width: Width in pixels - * @height: Height in pixels - * @colors1: Array of colors - * @thickness1: Thickness - * @colors2: Array of colors - * @thickness2: Thickness - * - * Interwoven essentially means we have two vertical gradients, - * cut into horizontal strips of the given thickness, and then the strips - * are alternated. I'm not sure what it's good for, just copied since - * WindowMaker had it. - */ -GdkPixbuf* -meta_gradient_create_interwoven (int width, - int height, - const GdkRGBA colors1[2], - int thickness1, - const GdkRGBA colors2[2], - int thickness2) -{ - - int i, j, k, l, ll; - long r1, g1, b1, dr1, dg1, db1; - long r2, g2, b2, dr2, dg2, db2; - GdkPixbuf *pixbuf; - unsigned char *ptr; - unsigned char *pixels; - int rowstride; - - pixbuf = blank_pixbuf (width, height, FALSE); - if (pixbuf == NULL) - return NULL; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - - r1 = (long)(colors1[0].red*0xffffff); - g1 = (long)(colors1[0].green*0xffffff); - b1 = (long)(colors1[0].blue*0xffffff); - - r2 = (long)(colors2[0].red*0xffffff); - g2 = (long)(colors2[0].green*0xffffff); - b2 = (long)(colors2[0].blue*0xffffff); - - dr1 = ((colors1[1].red-colors1[0].red)*0xffffff)/(int)height; - dg1 = ((colors1[1].green-colors1[0].green)*0xffffff)/(int)height; - db1 = ((colors1[1].blue-colors1[0].blue)*0xffffff)/(int)height; - - dr2 = ((colors2[1].red-colors2[0].red)*0xffffff)/(int)height; - dg2 = ((colors2[1].green-colors2[0].green)*0xffffff)/(int)height; - db2 = ((colors2[1].blue-colors2[0].blue)*0xffffff)/(int)height; - - for (i=0,k=0,l=0,ll=thickness1; i>16); - ptr[1] = (unsigned char) (g1>>16); - ptr[2] = (unsigned char) (b1>>16); - } - else - { - ptr[0] = (unsigned char) (r2>>16); - ptr[1] = (unsigned char) (g2>>16); - ptr[2] = (unsigned char) (b2>>16); - } - - for (j=1; j <= width/2; j *= 2) - memcpy (&(ptr[j*3]), ptr, j*3); - memcpy (&(ptr[j*3]), ptr, (width - j)*3); - - if (++l == ll) - { - if (k == 0) - { - k = 1; - ll = thickness2; - } - else - { - k = 0; - ll = thickness1; - } - l = 0; - } - r1+=dr1; - g1+=dg1; - b1+=db1; - - r2+=dr2; - g2+=dg2; - b2+=db2; - } - - return pixbuf; -} - -/* - *---------------------------------------------------------------------- - * meta_gradient_create_horizontal-- - * Renders a horizontal linear gradient of the specified size in the - * GdkPixbuf format with a border of the specified type. - * - * Returns: - * A 24bit GdkPixbuf with the gradient (no alpha channel). - * - * Side effects: - * None - *---------------------------------------------------------------------- - */ -static GdkPixbuf* -meta_gradient_create_horizontal (int width, int height, - const GdkRGBA *from, - const GdkRGBA *to) -{ - int i; - long r, g, b, dr, dg, db; - GdkPixbuf *pixbuf; - unsigned char *ptr; - unsigned char *pixels; - int r0, g0, b0; - int rf, gf, bf; - int rowstride; - - pixbuf = blank_pixbuf (width, height, FALSE); - if (pixbuf == NULL) - return NULL; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - ptr = pixels; - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - - r0 = (guchar) (from->red * 0xff); - g0 = (guchar) (from->green * 0xff); - b0 = (guchar) (from->blue * 0xff); - rf = (guchar) (to->red * 0xff); - gf = (guchar) (to->green * 0xff); - bf = (guchar) (to->blue * 0xff); - - r = r0 << 16; - g = g0 << 16; - b = b0 << 16; - - dr = ((rf-r0)<<16)/(int)width; - dg = ((gf-g0)<<16)/(int)width; - db = ((bf-b0)<<16)/(int)width; - /* render the first line */ - for (i=0; i>16); - *(ptr++) = (unsigned char)(g>>16); - *(ptr++) = (unsigned char)(b>>16); - r += dr; - g += dg; - b += db; - } - - /* copy the first line to the other lines */ - for (i=1; ired * 0xff); - g0 = (guchar) (from->green * 0xff); - b0 = (guchar) (from->blue * 0xff); - rf = (guchar) (to->red * 0xff); - gf = (guchar) (to->green * 0xff); - bf = (guchar) (to->blue * 0xff); - - r = r0<<16; - g = g0<<16; - b = b0<<16; - - dr = ((rf-r0)<<16)/(int)height; - dg = ((gf-g0)<<16)/(int)height; - db = ((bf-b0)<<16)/(int)height; - - for (i=0; i>16); - ptr[1] = (unsigned char)(g>>16); - ptr[2] = (unsigned char)(b>>16); - - for (j=1; j <= width/2; j *= 2) - memcpy (&(ptr[j*3]), ptr, j*3); - memcpy (&(ptr[j*3]), ptr, (width - j)*3); - - r+=dr; - g+=dg; - b+=db; - } - return pixbuf; -} - - -/* - *---------------------------------------------------------------------- - * meta_gradient_create_diagonal-- - * Renders a diagonal linear gradient of the specified size in the - * GdkPixbuf format with a border of the specified type. - * - * Returns: - * A 24bit GdkPixbuf with the gradient (no alpha channel). - * - * Side effects: - * None - *---------------------------------------------------------------------- - */ - - -static GdkPixbuf* -meta_gradient_create_diagonal (int width, int height, - const GdkRGBA *from, - const GdkRGBA *to) -{ - GdkPixbuf *pixbuf, *tmp; - int j; - float a, offset; - unsigned char *ptr; - unsigned char *pixels; - int rowstride; - - if (width == 1) - return meta_gradient_create_vertical (width, height, from, to); - else if (height == 1) - return meta_gradient_create_horizontal (width, height, from, to); - - pixbuf = blank_pixbuf (width, height, FALSE); - if (pixbuf == NULL) - return NULL; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - - tmp = meta_gradient_create_horizontal (2*width-1, 1, from, to); - if (!tmp) - { - g_object_unref (G_OBJECT (pixbuf)); - return NULL; - } - - ptr = gdk_pixbuf_get_pixels (tmp); - - a = ((float)(width - 1))/((float)(height - 1)); - width = width * 3; - - /* copy the first line to the other lines with corresponding offset */ - for (j=0, offset=0.0; j 2, NULL); - - pixbuf = blank_pixbuf (width, height, FALSE); - if (pixbuf == NULL) - return NULL; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - ptr = pixels; - - if (count > width) - count = width; - - if (count > 1) - width2 = width/(count-1); - else - width2 = width; - - k = 0; - - r = (long)(colors[0].red * 0xffffff); - g = (long)(colors[0].green * 0xffffff); - b = (long)(colors[0].blue * 0xffffff); - - /* render the first line */ - for (i=1; i>16); - *ptr++ = (unsigned char)(g>>16); - *ptr++ = (unsigned char)(b>>16); - r += dr; - g += dg; - b += db; - k++; - } - r = (long)(colors[i].red * 0xffffff); - g = (long)(colors[i].green * 0xffffff); - b = (long)(colors[i].blue * 0xffffff); - } - for (j=k; j>16); - *ptr++ = (unsigned char)(g>>16); - *ptr++ = (unsigned char)(b>>16); - } - - /* copy the first line to the other lines */ - for (i=1; i 2, NULL); - - pixbuf = blank_pixbuf (width, height, FALSE); - if (pixbuf == NULL) - return NULL; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - ptr = pixels; - - if (count > height) - count = height; - - if (count > 1) - height2 = height/(count-1); - else - height2 = height; - - k = 0; - - r = (long)(colors[0].red * 0xffffff); - g = (long)(colors[0].green * 0xffffff); - b = (long)(colors[0].blue * 0xffffff); - - for (i=1; i>16); - ptr[1] = (unsigned char)(g>>16); - ptr[2] = (unsigned char)(b>>16); - - for (x=1; x <= width/2; x *= 2) - memcpy (&(ptr[x*3]), ptr, x*3); - memcpy (&(ptr[x*3]), ptr, (width - x)*3); - - ptr += rowstride; - - r += dr; - g += dg; - b += db; - k++; - } - r = (long)(colors[i].red * 0xffffff); - g = (long)(colors[i].green * 0xffffff); - b = (long)(colors[i].blue * 0xffffff); - } - - if (k>16); - ptr[1] = (unsigned char) (g>>16); - ptr[2] = (unsigned char) (b>>16); - - for (x=1; x <= width/2; x *= 2) - memcpy (&(ptr[x*3]), ptr, x*3); - memcpy (&(ptr[x*3]), ptr, (width - x)*3); - - ptr += rowstride; - - for (j=k+1; j 2, NULL); - - if (width == 1) - return meta_gradient_create_multi_vertical (width, height, colors, count); - else if (height == 1) - return meta_gradient_create_multi_horizontal (width, height, colors, count); - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, - width, height); - if (pixbuf == NULL) - return NULL; - - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - - if (count > width) - count = width; - if (count > height) - count = height; - - if (count > 2) - tmp = meta_gradient_create_multi_horizontal (2*width-1, 1, colors, count); - else - /* wrlib multiplies these colors by 256 before passing them in, but - * I think it's a bug in wrlib, so changed here. I could be wrong - * though, if we notice two-color multi diagonals not working. - */ - tmp = meta_gradient_create_horizontal (2*width-1, 1, - &colors[0], &colors[1]); - - if (!tmp) - { - g_object_unref (G_OBJECT (pixbuf)); - return NULL; - } - ptr = gdk_pixbuf_get_pixels (tmp); - - a = ((float)(width - 1))/((float)(height - 1)); - width = width * 3; - - /* copy the first line to the other lines with corresponding offset */ - for (j=0, offset=0; j 0); - - if (n_alphas == 1) - { - /* Optimize this */ - simple_multiply_alpha (pixbuf, alphas[0]); - return; - } - - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - - gradient = g_new (unsigned char, width); - gradient_end = gradient + width; - - if (n_alphas > width) - n_alphas = width; - - if (n_alphas > 1) - width2 = width / (n_alphas - 1); - else - width2 = width; - - a = alphas[0] << 8; - gradient_p = gradient; - - /* render the gradient into an array */ - for (i = 1; i < n_alphas; i++) - { - da = (((int)(alphas[i] - (int) alphas[i-1])) << 8) / (int) width2; - - for (j = 0; j < width2; j++) - { - *gradient_p++ = (a >> 8); - - a += da; - } - - a = alphas[i] << 8; - } - - /* get leftover pixels */ - while (gradient_p != gradient_end) - { - *gradient_p++ = a >> 8; - } - - /* Now for each line of the pixbuf, fill in with the gradient */ - pixels = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - - p = pixels; - i = 0; - while (i < height) - { - unsigned char *row_end = p + rowstride; - gradient_p = gradient; - - p += 3; - while (gradient_p != gradient_end) - { - /* multiply the two alpha channels. not sure this is right. - * but some end cases are that if the pixbuf contains 255, - * then it should be modified to contain "alpha"; if the - * pixbuf contains 0, it should remain 0. - */ - /* ((*p / 255.0) * (alpha / 255.0)) * 255; */ - *p = (guchar) (((int) *p * (int) *gradient_p) / (int) 255); - - p += 4; - ++gradient_p; - } - - p = row_end; - ++i; - } - - g_free (gradient); -} - -void -meta_gradient_add_alpha (GdkPixbuf *pixbuf, - const guchar *alphas, - int n_alphas, - MetaGradientType type) -{ - g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); - g_return_if_fail (gdk_pixbuf_get_has_alpha (pixbuf)); - g_return_if_fail (n_alphas > 0); - - switch (type) - { - case META_GRADIENT_HORIZONTAL: - meta_gradient_add_alpha_horizontal (pixbuf, alphas, n_alphas); - break; - - case META_GRADIENT_VERTICAL: - g_printerr ("metacity: vertical alpha channel gradient not implemented yet\n"); - break; - - case META_GRADIENT_DIAGONAL: - g_printerr ("metacity: diagonal alpha channel gradient not implemented yet\n"); - break; - - case META_GRADIENT_LAST: - g_assert_not_reached (); - break; - } -} diff --git a/src/ui/menu.c b/src/ui/menu.c deleted file mode 100644 index d59e24211..000000000 --- a/src/ui/menu.c +++ /dev/null @@ -1,518 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Mutter window menu */ - -/* - * Copyright (C) 2001 Havoc Pennington - * Copyright (C) 2004 Rob Adams - * Copyright (C) 2005 Elijah Newren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include -#include -#include -#include "menu.h" -#include -#include "util-private.h" -#include "core.h" -#include "metaaccellabel.h" -#include "ui.h" - -typedef struct _MenuItem MenuItem; -typedef struct _MenuData MenuData; - -typedef enum -{ - MENU_ITEM_SEPARATOR = 0, - MENU_ITEM_NORMAL, - MENU_ITEM_CHECKBOX, - MENU_ITEM_RADIOBUTTON, - MENU_ITEM_WORKSPACE_LIST, -} MetaMenuItemType; - -struct _MenuItem -{ - MetaMenuOp op; - MetaMenuItemType type; - const gboolean checked; - const char *label; -}; - - -struct _MenuData -{ - MetaWindowMenu *menu; - MetaMenuOp op; -}; - -static void activate_cb (GtkWidget *menuitem, gpointer data); - -static MenuItem menuitems[] = { - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MINIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Mi_nimize") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Ma_ximize") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_UNMAXIMIZE, MENU_ITEM_NORMAL, FALSE, N_("Unma_ximize") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_SHADE, MENU_ITEM_NORMAL, FALSE, N_("Roll _Up") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_UNSHADE, MENU_ITEM_NORMAL, FALSE, N_("_Unroll") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MOVE, MENU_ITEM_NORMAL, FALSE, N_("_Move") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_RESIZE, MENU_ITEM_NORMAL, FALSE, N_("_Resize") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_RECOVER, MENU_ITEM_NORMAL, FALSE, N_("Move Titlebar On_screen") }, - { META_MENU_OP_WORKSPACES, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */ - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_ABOVE, MENU_ITEM_CHECKBOX, FALSE, N_("Always on _Top") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_UNABOVE, MENU_ITEM_CHECKBOX, TRUE, N_("Always on _Top") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_STICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Always on Visible Workspace") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_UNSTICK, MENU_ITEM_RADIOBUTTON, FALSE, N_("_Only on This Workspace") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MOVE_LEFT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Left") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MOVE_RIGHT, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace R_ight") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MOVE_UP, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Up") }, - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_MOVE_DOWN, MENU_ITEM_NORMAL, FALSE, N_("Move to Workspace _Down") }, - { 0, MENU_ITEM_WORKSPACE_LIST, FALSE, NULL }, - { 0, MENU_ITEM_SEPARATOR, FALSE, NULL }, /* separator */ - /* Translators: Translate this string the same way as you do in libwnck! */ - { META_MENU_OP_DELETE, MENU_ITEM_NORMAL, FALSE, N_("_Close") } -}; - -static void -popup_position_func (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) -{ - GtkRequisition req; - GdkPoint *pos; - - pos = user_data; - - gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL); - - *x = pos->x; - *y = pos->y; - - if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) - *x = MAX (0, *x - req.width); - - /* Ensure onscreen */ - *x = CLAMP (*x, 0, MAX (0, gdk_screen_width () - req.width)); - *y = CLAMP (*y, 0, MAX (0, gdk_screen_height () - req.height)); -} - -static void -menu_closed (GtkMenu *widget, - gpointer data) -{ - MetaWindowMenu *menu; - - menu = data; - - meta_frames_notify_menu_hide (menu->frames); - (* menu->func) (menu, - GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - menu->client_xwindow, - gtk_get_current_event_time (), - 0, 0, - menu->data); - - /* menu may now be freed */ -} - -static void -activate_cb (GtkWidget *menuitem, gpointer data) -{ - MenuData *md; - - g_return_if_fail (GTK_IS_WIDGET (menuitem)); - - md = data; - - meta_frames_notify_menu_hide (md->menu->frames); - (* md->menu->func) (md->menu, - GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), - md->menu->client_xwindow, - gtk_get_current_event_time (), - md->op, - GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), - "workspace")), - md->menu->data); - - /* menu may now be freed */ -} - -/* - * Given a Display and an index, get the workspace name and add any - * accelerators. At the moment this means adding a _ if the name is of - * the form "Workspace n" where n is less than 10, and escaping any - * other '_'s so they do not create inadvertant accelerators. - * - * The calling code owns the string, and is reponsible to free the - * memory after use. - * - * See also http://mail.gnome.org/archives/gnome-i18n/2008-March/msg00380.html - * which discusses possible i18n concerns. - */ -static char* -get_workspace_name_with_accel (Display *display, - Window xroot, - int index) -{ - const char *name; - int number; - int charcount=0; - - name = meta_core_get_workspace_name_with_index (display, xroot, index); - - g_assert (name != NULL); - - /* - * If the name is of the form "Workspace x" where x is an unsigned - * integer, insert a '_' before the number if it is less than 10 and - * return it - */ - number = 0; - if (sscanf (name, _("Workspace %d%n"), &number, &charcount) != 0 && - *(name + charcount)=='\0') - { - char *new_name; - - /* - * Above name is a pointer into the Workspace struct. Here we make - * a copy copy so we can have our wicked way with it. - */ - if (number == 10) - new_name = g_strdup_printf (_("Workspace 1_0")); - else - new_name = g_strdup_printf (_("Workspace %s%d"), - number < 10 ? "_" : "", - number); - return new_name; - } - else - { - /* - * Otherwise this is just a normal name. Escape any _ characters so that - * the user's workspace names do not get mangled. If the number is less - * than 10 we provide an accelerator. - */ - char *new_name; - const char *source; - char *dest; - - /* - * Assume the worst case, that every character is a _. We also - * provide memory for " (_#)" - */ - new_name = g_malloc0 (strlen (name) * 2 + 6 + 1); - - /* - * Now iterate down the strings, adding '_' to escape as we go - */ - dest = new_name; - source = name; - while (*source != '\0') - { - if (*source == '_') - *dest++ = '_'; - *dest++ = *source++; - } - - /* People don't start at workspace 0, but workspace 1 */ - if (index < 9) - { - g_snprintf (dest, 6, " (_%d)", index + 1); - } - else if (index == 9) - { - g_snprintf (dest, 6, " (_0)"); - } - - return new_name; - } -} - -static GtkWidget * -menu_item_new (MenuItem *menuitem, int workspace_id) -{ - unsigned int key; - MetaVirtualModifier mods; - const char *i18n_label; - GtkWidget *mi; - GtkWidget *accel_label; - - if (menuitem->type == MENU_ITEM_NORMAL) - { - mi = gtk_menu_item_new (); - } - else if (menuitem->type == MENU_ITEM_CHECKBOX) - { - mi = gtk_check_menu_item_new (); - - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), - menuitem->checked); - } - else if (menuitem->type == MENU_ITEM_RADIOBUTTON) - { - mi = gtk_check_menu_item_new (); - - gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (mi), - TRUE); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), - menuitem->checked); - } - else if (menuitem->type == MENU_ITEM_WORKSPACE_LIST) - return NULL; - else - return gtk_separator_menu_item_new (); - - i18n_label = _(menuitem->label); - meta_core_get_menu_accelerator (menuitem->op, workspace_id, &key, &mods); - - accel_label = meta_accel_label_new_with_mnemonic (i18n_label); - gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5); - - gtk_container_add (GTK_CONTAINER (mi), accel_label); - gtk_widget_show (accel_label); - - meta_accel_label_set_accelerator (META_ACCEL_LABEL (accel_label), - key, mods); - - return mi; -} - -MetaWindowMenu* -meta_window_menu_new (MetaFrames *frames, - MetaMenuOp ops, - MetaMenuOp insensitive, - Window client_xwindow, - unsigned long active_workspace, - int n_workspaces, - MetaWindowMenuFunc func, - gpointer data) -{ - int i; - MetaWindowMenu *menu; - - /* FIXME: Modifications to 'ops' should happen in meta_window_show_menu */ - if (n_workspaces < 2) - ops &= ~(META_MENU_OP_STICK | META_MENU_OP_UNSTICK | META_MENU_OP_WORKSPACES); - else if (n_workspaces == 2) - /* #151183: If we only have two workspaces, disable the menu listing them. */ - ops &= ~(META_MENU_OP_WORKSPACES); - - menu = g_new (MetaWindowMenu, 1); - menu->frames = frames; - menu->client_xwindow = client_xwindow; - menu->func = func; - menu->data = data; - menu->ops = ops; - menu->insensitive = insensitive; - - menu->menu = gtk_menu_new (); - - gtk_menu_set_screen (GTK_MENU (menu->menu), - gtk_widget_get_screen (GTK_WIDGET (frames))); - - for (i = 0; i < (int) G_N_ELEMENTS (menuitems); i++) - { - MenuItem menuitem = menuitems[i]; - if (ops & menuitem.op || menuitem.op == 0) - { - GtkWidget *mi; - MenuData *md; - unsigned int key; - MetaVirtualModifier mods; - - mi = menu_item_new (&menuitem, -1); - - /* Set the activeness of radiobuttons. */ - switch (menuitem.op) - { - case META_MENU_OP_STICK: - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), - active_workspace == 0xFFFFFFFF); - break; - case META_MENU_OP_UNSTICK: - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (mi), - active_workspace != 0xFFFFFFFF); - break; - default: - break; - } - - if (menuitem.type == MENU_ITEM_WORKSPACE_LIST) - { - if (ops & META_MENU_OP_WORKSPACES) - { - Display *display; - Window xroot; - GdkScreen *screen; - GdkWindow *window; - GtkWidget *submenu; - int j; - - MenuItem to_another_workspace = { - 0, MENU_ITEM_NORMAL, FALSE, - N_("Move to Another _Workspace") - }; - - meta_verbose ("Creating %d-workspace menu current space %lu\n", - n_workspaces, active_workspace); - - window = gtk_widget_get_window (GTK_WIDGET (frames)); - display = GDK_WINDOW_XDISPLAY (window); - - screen = gdk_window_get_screen (window); - xroot = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); - - submenu = gtk_menu_new (); - - g_assert (mi==NULL); - mi = menu_item_new (&to_another_workspace, -1); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), submenu); - - for (j = 0; j < n_workspaces; j++) - { - char *label; - MenuData *md; - unsigned int key; - MetaVirtualModifier mods; - MenuItem moveitem; - GtkWidget *submi; - - meta_core_get_menu_accelerator (META_MENU_OP_WORKSPACES, - j + 1, - &key, &mods); - - label = get_workspace_name_with_accel (display, xroot, j); - - moveitem.type = MENU_ITEM_NORMAL; - moveitem.op = META_MENU_OP_WORKSPACES; - moveitem.label = label; - submi = menu_item_new (&moveitem, j + 1); - - g_free (label); - - if ((active_workspace == (unsigned)j) && (ops & META_MENU_OP_UNSTICK)) - gtk_widget_set_sensitive (submi, FALSE); - - md = g_new (MenuData, 1); - - md->menu = menu; - md->op = META_MENU_OP_WORKSPACES; - - g_object_set_data (G_OBJECT (submi), - "workspace", - GINT_TO_POINTER (j)); - - g_signal_connect_data (G_OBJECT (submi), - "activate", - G_CALLBACK (activate_cb), - md, - (GClosureNotify) g_free, 0); - - gtk_menu_shell_append (GTK_MENU_SHELL (submenu), submi); - - gtk_widget_show (submi); - } - } - else - meta_verbose ("not creating workspace menu\n"); - } - else if (menuitem.type != MENU_ITEM_SEPARATOR) - { - meta_core_get_menu_accelerator (menuitems[i].op, -1, - &key, &mods); - - if (insensitive & menuitem.op) - gtk_widget_set_sensitive (mi, FALSE); - - md = g_new (MenuData, 1); - - md->menu = menu; - md->op = menuitem.op; - - g_signal_connect_data (G_OBJECT (mi), - "activate", - G_CALLBACK (activate_cb), - md, - (GClosureNotify) g_free, 0); - } - - if (mi) - { - gtk_menu_shell_append (GTK_MENU_SHELL (menu->menu), mi); - - gtk_widget_show (mi); - } - } - } - - - g_signal_connect (menu->menu, "selection_done", - G_CALLBACK (menu_closed), menu); - - return menu; -} - -void -meta_window_menu_popup (MetaWindowMenu *menu, - int root_x, - int root_y, - int button, - guint32 timestamp) -{ - GdkPoint *pt; - - pt = g_new (GdkPoint, 1); - - g_object_set_data_full (G_OBJECT (menu->menu), - "destroy-point", - pt, - g_free); - - pt->x = root_x; - pt->y = root_y; - - gtk_menu_popup (GTK_MENU (menu->menu), - NULL, NULL, - popup_position_func, pt, - button, - timestamp); - - if (!gtk_widget_get_visible (menu->menu)) - meta_warning ("GtkMenu failed to grab the pointer\n"); -} - -void -meta_window_menu_free (MetaWindowMenu *menu) -{ - gtk_widget_destroy (menu->menu); - g_free (menu); -} diff --git a/src/ui/menu.h b/src/ui/menu.h deleted file mode 100644 index ab42a8ba9..000000000 --- a/src/ui/menu.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Mutter window menu */ - -/* - * Copyright (C) 2001 Havoc Pennington - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#ifndef META_MENU_H -#define META_MENU_H - -#include -#include "frames.h" - -struct _MetaWindowMenu -{ - MetaFrames *frames; - Window client_xwindow; - GtkWidget *menu; - MetaWindowMenuFunc func; - gpointer data; - MetaMenuOp ops; - MetaMenuOp insensitive; -}; - -MetaWindowMenu* meta_window_menu_new (MetaFrames *frames, - MetaMenuOp ops, - MetaMenuOp insensitive, - Window client_xwindow, - unsigned long active_workspace, - int n_workspaces, - MetaWindowMenuFunc func, - gpointer data); -void meta_window_menu_popup (MetaWindowMenu *menu, - int root_x, - int root_y, - int button, - guint32 timestamp); -void meta_window_menu_free (MetaWindowMenu *menu); - - -#endif diff --git a/src/ui/testgradient.c b/src/ui/testgradient.c deleted file mode 100644 index fdc9576f9..000000000 --- a/src/ui/testgradient.c +++ /dev/null @@ -1,315 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Mutter gradient test program */ - -/* - * Copyright (C) 2002 Havoc Pennington - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . */ - -#include -#include - -typedef void (* RenderGradientFunc) (cairo_t *cr, - int width, - int height); - -static void -draw_checkerboard (cairo_t *cr, - int width, - int height) -{ - gint i, j, xcount, ycount; - GdkRGBA color1, color2; - -#define CHECK_SIZE 10 -#define SPACING 2 - - color1.red = 30000. / 65535.; - color1.green = 30000. / 65535.; - color1.blue = 30000. / 65535.; - color1.alpha = 1.0; - - color2.red = 50000. / 65535.; - color2.green = 50000. / 65535.; - color2.blue = 50000. / 65535.; - color2.alpha = 1.0; - - xcount = 0; - i = SPACING; - while (i < width) - { - j = SPACING; - ycount = xcount % 2; /* start with even/odd depending on row */ - while (j < height) - { - if (ycount % 2) - gdk_cairo_set_source_rgba (cr, &color1); - else - gdk_cairo_set_source_rgba (cr, &color2); - - /* If we're outside event->area, this will do nothing. - * It might be mildly more efficient if we handled - * the clipping ourselves, but again we're feeling lazy. - */ - cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE); - cairo_fill (cr); - - j += CHECK_SIZE + SPACING; - ++ycount; - } - - i += CHECK_SIZE + SPACING; - ++xcount; - } -} - -static void -render_simple (cairo_t *cr, - int width, int height, - MetaGradientType type, - gboolean with_alpha) -{ - GdkPixbuf *pixbuf; - GdkRGBA from, to; - - gdk_rgba_parse (&from, "blue"); - gdk_rgba_parse (&to, "green"); - - pixbuf = meta_gradient_create_simple (width, height, - &from, &to, - type); - - if (with_alpha) - { - const unsigned char alphas[] = { 0xff, 0xaa, 0x2f, 0x0, 0xcc, 0xff, 0xff }; - - if (!gdk_pixbuf_get_has_alpha (pixbuf)) - { - GdkPixbuf *new_pixbuf; - - new_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); - g_object_unref (G_OBJECT (pixbuf)); - pixbuf = new_pixbuf; - } - - meta_gradient_add_alpha (pixbuf, - alphas, G_N_ELEMENTS (alphas), - META_GRADIENT_HORIZONTAL); - - draw_checkerboard (cr , width, height); - } - - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - - g_object_unref (G_OBJECT (pixbuf)); -} - -static void -render_vertical_func (cairo_t *cr, - int width, int height) -{ - render_simple (cr, width, height, META_GRADIENT_VERTICAL, FALSE); -} - -static void -render_horizontal_func (cairo_t *cr, - int width, int height) -{ - render_simple (cr, width, height, META_GRADIENT_HORIZONTAL, FALSE); -} - -static void -render_diagonal_func (cairo_t *cr, - int width, int height) -{ - render_simple (cr, width, height, META_GRADIENT_DIAGONAL, FALSE); -} - -static void -render_diagonal_alpha_func (cairo_t *cr, - int width, int height) -{ - render_simple (cr, width, height, META_GRADIENT_DIAGONAL, TRUE); -} - -static void -render_multi (cairo_t *cr, - int width, int height, - MetaGradientType type) -{ - GdkPixbuf *pixbuf; -#define N_COLORS 5 - GdkRGBA colors[N_COLORS]; - - gdk_rgba_parse (&colors[0], "red"); - gdk_rgba_parse (&colors[1], "blue"); - gdk_rgba_parse (&colors[2], "orange"); - gdk_rgba_parse (&colors[3], "pink"); - gdk_rgba_parse (&colors[4], "green"); - - pixbuf = meta_gradient_create_multi (width, height, - colors, N_COLORS, - type); - - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - - g_object_unref (G_OBJECT (pixbuf)); -#undef N_COLORS -} - -static void -render_vertical_multi_func (cairo_t *cr, - int width, int height) -{ - render_multi (cr, width, height, META_GRADIENT_VERTICAL); -} - -static void -render_horizontal_multi_func (cairo_t *cr, - int width, int height) -{ - render_multi (cr, width, height, META_GRADIENT_HORIZONTAL); -} - -static void -render_diagonal_multi_func (cairo_t *cr, - int width, int height) -{ - render_multi (cr, width, height, META_GRADIENT_DIAGONAL); -} - -static void -render_interwoven_func (cairo_t *cr, - int width, int height) -{ - GdkPixbuf *pixbuf; -#define N_COLORS 4 - GdkRGBA colors[N_COLORS]; - - gdk_rgba_parse (&colors[0], "red"); - gdk_rgba_parse (&colors[1], "blue"); - gdk_rgba_parse (&colors[2], "pink"); - gdk_rgba_parse (&colors[3], "green"); - - pixbuf = meta_gradient_create_interwoven (width, height, - colors, height / 10, - colors + 2, height / 14); - - gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); - cairo_rectangle (cr, 0, 0, width, height); - cairo_fill (cr); - - g_object_unref (G_OBJECT (pixbuf)); -} - -static gboolean -draw_callback (GtkWidget *widget, - cairo_t *cr, - gpointer data) -{ - RenderGradientFunc func = data; - GtkStyleContext *style; - GdkRGBA color; - - style = gtk_widget_get_style_context (widget); - - gtk_style_context_save (style); - gtk_style_context_set_state (style, gtk_widget_get_state_flags (widget)); - gtk_style_context_lookup_color (style, "foreground-color", &color); - gtk_style_context_restore (style); - - gdk_cairo_set_source_rgba (cr, &color); - - (* func) (cr, - gtk_widget_get_allocated_width (widget), - gtk_widget_get_allocated_height (widget)); - - return FALSE; -} - -static GtkWidget* -create_gradient_window (const char *title, - RenderGradientFunc func) -{ - GtkWidget *window; - GtkWidget *drawing_area; - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_window_set_title (GTK_WINDOW (window), title); - - drawing_area = gtk_drawing_area_new (); - - gtk_widget_set_size_request (drawing_area, 1, 1); - - gtk_window_set_default_size (GTK_WINDOW (window), 175, 175); - - g_signal_connect (G_OBJECT (drawing_area), - "draw", - G_CALLBACK (draw_callback), - func); - - gtk_container_add (GTK_CONTAINER (window), drawing_area); - - gtk_widget_show_all (window); - - return window; -} - -static void -meta_gradient_test (void) -{ - create_gradient_window ("Simple vertical", - render_vertical_func); - - create_gradient_window ("Simple horizontal", - render_horizontal_func); - - create_gradient_window ("Simple diagonal", - render_diagonal_func); - - create_gradient_window ("Multi vertical", - render_vertical_multi_func); - - create_gradient_window ("Multi horizontal", - render_horizontal_multi_func); - - create_gradient_window ("Multi diagonal", - render_diagonal_multi_func); - - create_gradient_window ("Interwoven", - render_interwoven_func); - - create_gradient_window ("Simple diagonal with horizontal multi alpha", - render_diagonal_alpha_func); - -} - -int -main (int argc, char **argv) -{ - gtk_init (&argc, &argv); - - meta_gradient_test (); - - gtk_main (); - - return 0; -} - diff --git a/src/ui/theme-parser.c b/src/ui/theme-parser.c deleted file mode 100644 index e9ce02827..000000000 --- a/src/ui/theme-parser.c +++ /dev/null @@ -1,4344 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity theme parsing */ - -/* - * Copyright (C) 2001 Havoc Pennington - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include -#include "theme-private.h" -#include "util-private.h" -#include -#include - -/* We were intending to put the version number - * in the subdirectory name, but we ended up - * using the filename instead. The "-1" survives - * as a fossil. - */ -#define THEME_SUBDIR "metacity-1" - -/* Highest version of the theme format to - * look out for. - */ -#define THEME_MAJOR_VERSION 3 -#define THEME_MINOR_VERSION 4 -#define THEME_VERSION (1000 * THEME_MAJOR_VERSION + THEME_MINOR_VERSION) - -#define METACITY_THEME_FILENAME_FORMAT "metacity-theme-%d.xml" - -typedef enum -{ - STATE_START, - STATE_THEME, - /* info section */ - STATE_INFO, - STATE_NAME, - STATE_AUTHOR, - STATE_COPYRIGHT, - STATE_DATE, - STATE_DESCRIPTION, - /* constants */ - STATE_CONSTANT, - /* geometry */ - STATE_FRAME_GEOMETRY, - STATE_DISTANCE, - STATE_BORDER, - STATE_ASPECT_RATIO, - /* draw ops */ - STATE_DRAW_OPS, - STATE_LINE, - STATE_RECTANGLE, - STATE_ARC, - STATE_CLIP, - STATE_TINT, - STATE_GRADIENT, - STATE_IMAGE, - STATE_GTK_ARROW, - STATE_GTK_BOX, - STATE_GTK_VLINE, - STATE_ICON, - STATE_TITLE, - STATE_INCLUDE, /* include another draw op list */ - STATE_TILE, /* tile another draw op list */ - /* sub-parts of gradient */ - STATE_COLOR, - /* frame style */ - STATE_FRAME_STYLE, - STATE_PIECE, - STATE_BUTTON, - /* style set */ - STATE_FRAME_STYLE_SET, - STATE_FRAME, - /* assigning style sets to windows */ - STATE_WINDOW, - /* things we don't use any more but we can still parse: */ - STATE_MENU_ICON, - STATE_FALLBACK -} ParseState; - -typedef struct -{ - /* This two lists contain stacks of state and required version - * (cast to pointers.) There is one list item for each currently - * open element. */ - GSList *states; - GSList *required_versions; - - const char *theme_name; /* name of theme (directory it's in) */ - const char *theme_file; /* theme filename */ - const char *theme_dir; /* dir the theme is inside */ - MetaTheme *theme; /* theme being parsed */ - guint format_version; /* version of format of theme file */ - char *name; /* name of named thing being parsed */ - MetaFrameLayout *layout; /* layout being parsed if any */ - MetaDrawOpList *op_list; /* op list being parsed if any */ - MetaDrawOp *op; /* op being parsed if any */ - MetaFrameStyle *style; /* frame style being parsed if any */ - MetaFrameStyleSet *style_set; /* frame style set being parsed if any */ - MetaFramePiece piece; /* position of piece being parsed */ - MetaButtonType button_type; /* type of button/menuitem being parsed */ - MetaButtonState button_state; /* state of button being parsed */ - int skip_level; /* depth of elements that we're ignoring */ -} ParseInfo; - -typedef enum { - THEME_PARSE_ERROR_TOO_OLD, - THEME_PARSE_ERROR_TOO_FAILED -} ThemeParseError; - -static GQuark -theme_parse_error_quark (void) -{ - return g_quark_from_static_string ("theme-parse-error-quark"); -} - -#define THEME_PARSE_ERROR (theme_parse_error_quark ()) - -static void set_error (GError **err, - GMarkupParseContext *context, - int error_domain, - int error_code, - const char *format, - ...) G_GNUC_PRINTF (5, 6); - -static void add_context_to_error (GError **err, - GMarkupParseContext *context); - -static void parse_info_init (ParseInfo *info); -static void parse_info_free (ParseInfo *info); - -static void push_state (ParseInfo *info, - ParseState state); -static void pop_state (ParseInfo *info); -static ParseState peek_state (ParseInfo *info); - - -static void parse_toplevel_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); -static void parse_info_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); -static void parse_geometry_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); -static void parse_draw_op_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); -static void parse_gradient_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); -static void parse_style_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); -static void parse_style_set_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); - -static void parse_piece_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); - -static void parse_button_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); - -static void parse_menu_icon_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error); - -static void start_element_handler (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error); -static void end_element_handler (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error); -static void text_handler (GMarkupParseContext *context, - const gchar *text, - gsize text_len, - gpointer user_data, - GError **error); - -/* Translators: This means that an attribute which should have been found - * on an XML element was not in fact found. - */ -#define ATTRIBUTE_NOT_FOUND _("No \"%s\" attribute on element <%s>") - -static GMarkupParser metacity_theme_parser = { - start_element_handler, - end_element_handler, - text_handler, - NULL, - NULL -}; - -static void -set_error (GError **err, - GMarkupParseContext *context, - int error_domain, - int error_code, - const char *format, - ...) -{ - int line, ch; - va_list args; - char *str; - - g_markup_parse_context_get_position (context, &line, &ch); - - va_start (args, format); - str = g_strdup_vprintf (format, args); - va_end (args); - - g_set_error (err, error_domain, error_code, - _("Line %d character %d: %s"), - line, ch, str); - - g_free (str); -} - -static void -add_context_to_error (GError **err, - GMarkupParseContext *context) -{ - int line, ch; - char *str; - - if (err == NULL || *err == NULL) - return; - - g_markup_parse_context_get_position (context, &line, &ch); - - str = g_strdup_printf (_("Line %d character %d: %s"), - line, ch, (*err)->message); - g_free ((*err)->message); - (*err)->message = str; -} - -static void -parse_info_init (ParseInfo *info) -{ - info->theme_file = NULL; - info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START)); - info->required_versions = NULL; - info->theme = NULL; - info->name = NULL; - info->layout = NULL; - info->op_list = NULL; - info->op = NULL; - info->style = NULL; - info->style_set = NULL; - info->piece = META_FRAME_PIECE_LAST; - info->button_type = META_BUTTON_TYPE_LAST; - info->button_state = META_BUTTON_STATE_LAST; - info->skip_level = 0; -} - -static void -parse_info_free (ParseInfo *info) -{ - g_slist_free (info->states); - g_slist_free (info->required_versions); - - if (info->theme) - meta_theme_free (info->theme); - - if (info->layout) - meta_frame_layout_unref (info->layout); - - if (info->op_list) - meta_draw_op_list_unref (info->op_list); - - if (info->op) - meta_draw_op_free (info->op); - - if (info->style) - meta_frame_style_unref (info->style); - - if (info->style_set) - meta_frame_style_set_unref (info->style_set); -} - -static void -push_state (ParseInfo *info, - ParseState state) -{ - info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state)); -} - -static void -pop_state (ParseInfo *info) -{ - g_return_if_fail (info->states != NULL); - - info->states = g_slist_remove (info->states, info->states->data); -} - -static ParseState -peek_state (ParseInfo *info) -{ - g_return_val_if_fail (info->states != NULL, STATE_START); - - return GPOINTER_TO_INT (info->states->data); -} - -static void -push_required_version (ParseInfo *info, - int version) -{ - info->required_versions = g_slist_prepend (info->required_versions, - GINT_TO_POINTER (version)); -} - -static void -pop_required_version (ParseInfo *info) -{ - g_return_if_fail (info->required_versions != NULL); - - info->required_versions = g_slist_delete_link (info->required_versions, info->required_versions); -} - -static int -peek_required_version (ParseInfo *info) -{ - if (info->required_versions) - return GPOINTER_TO_INT (info->required_versions->data); - else - return info->format_version; -} - -#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) - -typedef struct -{ - const char *name; - const char **retloc; - gboolean required; -} LocateAttr; - -/* Attribute names can have a leading '!' to indicate that they are - * required. - */ -static gboolean -locate_attributes (GMarkupParseContext *context, - const char *element_name, - const char **attribute_names, - const char **attribute_values, - GError **error, - const char *first_attribute_name, - const char **first_attribute_retloc, - ...) -{ - va_list args; - const char *name; - const char **retloc; - int n_attrs; -#define MAX_ATTRS 24 - LocateAttr attrs[MAX_ATTRS]; - gboolean retval; - int i; - - g_return_val_if_fail (first_attribute_name != NULL, FALSE); - g_return_val_if_fail (first_attribute_retloc != NULL, FALSE); - - retval = TRUE; - - /* FIXME: duplicated code; refactor loop */ - n_attrs = 1; - attrs[0].name = first_attribute_name; - attrs[0].retloc = first_attribute_retloc; - attrs[0].required = attrs[0].name[0]=='!'; - if (attrs[0].required) - attrs[0].name++; /* skip past it */ - *first_attribute_retloc = NULL; - - va_start (args, first_attribute_retloc); - - name = va_arg (args, const char*); - retloc = va_arg (args, const char**); - - while (name != NULL) - { - if (retloc == NULL) - { - retval = FALSE; - goto out; - } - - g_assert (n_attrs < MAX_ATTRS); - - attrs[n_attrs].name = name; - attrs[n_attrs].retloc = retloc; - attrs[n_attrs].required = attrs[n_attrs].name[0]=='!'; - if (attrs[n_attrs].required) - attrs[n_attrs].name++; /* skip past it */ - - n_attrs += 1; - *retloc = NULL; - - name = va_arg (args, const char*); - retloc = va_arg (args, const char**); - } - - va_end (args); - - i = 0; - while (attribute_names[i]) - { - int j; - gboolean found; - - /* Can be present anywhere */ - if (strcmp (attribute_names[i], "version") == 0) - { - ++i; - continue; - } - - found = FALSE; - j = 0; - while (j < n_attrs) - { - if (strcmp (attrs[j].name, attribute_names[i]) == 0) - { - retloc = attrs[j].retloc; - - if (*retloc != NULL) - { - - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Attribute \"%s\" repeated twice on the same <%s> element"), - attrs[j].name, element_name); - retval = FALSE; - goto out; - } - - *retloc = attribute_values[i]; - found = TRUE; - } - - ++j; - } - - if (!found) - { - j = 0; - while (j < n_attrs) - { - g_warning ("It could have been %s.\n", attrs[j++].name); - } - - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Attribute \"%s\" is invalid on <%s> element in this context"), - attribute_names[i], element_name); - retval = FALSE; - goto out; - } - - ++i; - } - - /* Did we catch them all? */ - i = 0; - while (i < n_attrs) - { - if (attrs[i].required && *(attrs[i].retloc)==NULL) - { - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - ATTRIBUTE_NOT_FOUND, - attrs[i].name, element_name); - retval = FALSE; - goto out; - } - - ++i; - } - - out: - return retval; -} - -static gboolean -check_no_attributes (GMarkupParseContext *context, - const char *element_name, - const char **attribute_names, - const char **attribute_values, - GError **error) -{ - int i = 0; - - /* Can be present anywhere */ - if (attribute_names[0] && strcmp (attribute_names[i], "version") == 0) - i++; - - if (attribute_names[i] != NULL) - { - set_error (error, context, - G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Attribute \"%s\" is invalid on <%s> element in this context"), - attribute_names[0], element_name); - return FALSE; - } - - return TRUE; -} - -#define MAX_REASONABLE 4096 -static gboolean -parse_positive_integer (const char *str, - int *val, - GMarkupParseContext *context, - MetaTheme *theme, - GError **error) -{ - char *end; - long l; - int j; - - *val = 0; - - end = NULL; - - /* Is str a constant? */ - - if (META_THEME_ALLOWS (theme, META_THEME_UBIQUITOUS_CONSTANTS) && - meta_theme_lookup_int_constant (theme, str, &j)) - { - /* Yes. */ - l = j; - } - else - { - /* No. Let's try parsing it instead. */ - - l = strtol (str, &end, 10); - - if (end == NULL || end == str) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Could not parse \"%s\" as an integer"), - str); - return FALSE; - } - - if (*end != '\0') - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand trailing characters \"%s\" in string \"%s\""), - end, str); - return FALSE; - } - } - - if (l < 0) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Integer %ld must be positive"), l); - return FALSE; - } - - if (l > MAX_REASONABLE) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Integer %ld is too large, current max is %d"), - l, MAX_REASONABLE); - return FALSE; - } - - *val = (int) l; - - return TRUE; -} - -static gboolean -parse_double (const char *str, - double *val, - GMarkupParseContext *context, - GError **error) -{ - char *end; - - *val = 0; - - end = NULL; - - *val = g_ascii_strtod (str, &end); - - if (end == NULL || end == str) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Could not parse \"%s\" as a floating point number"), - str); - return FALSE; - } - - if (*end != '\0') - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand trailing characters \"%s\" in string \"%s\""), - end, str); - return FALSE; - } - - return TRUE; -} - -static gboolean -parse_boolean (const char *str, - gboolean *val, - GMarkupParseContext *context, - GError **error) -{ - if (strcmp ("true", str) == 0) - *val = TRUE; - else if (strcmp ("false", str) == 0) - *val = FALSE; - else - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Boolean values must be \"true\" or \"false\" not \"%s\""), - str); - return FALSE; - } - - return TRUE; -} - -static gboolean -parse_rounding (const char *str, - guint *val, - GMarkupParseContext *context, - MetaTheme *theme, - GError **error) -{ - if (strcmp ("true", str) == 0) - *val = 5; /* historical "true" value */ - else if (strcmp ("false", str) == 0) - *val = 0; - else - { - int tmp; - gboolean result; - if (!META_THEME_ALLOWS (theme, META_THEME_VARIED_ROUND_CORNERS)) - { - /* Not known in this version, so bail. */ - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Boolean values must be \"true\" or \"false\" not \"%s\""), - str); - return FALSE; - } - - result = parse_positive_integer (str, &tmp, context, theme, error); - - *val = tmp; - - return result; - } - - return TRUE; -} - -static gboolean -parse_angle (const char *str, - double *val, - GMarkupParseContext *context, - GError **error) -{ - if (!parse_double (str, val, context, error)) - return FALSE; - - if (*val < (0.0 - 1e6) || *val > (360.0 + 1e6)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Angle must be between 0.0 and 360.0, was %g\n"), - *val); - return FALSE; - } - - return TRUE; -} - -static gboolean -parse_alpha (const char *str, - MetaAlphaGradientSpec **spec_ret, - GMarkupParseContext *context, - GError **error) -{ - char **split; - int i; - int n_alphas; - MetaAlphaGradientSpec *spec; - - *spec_ret = NULL; - - split = g_strsplit (str, ":", -1); - - i = 0; - while (split[i]) - ++i; - - if (i == 0) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Could not parse \"%s\" as a floating point number"), - str); - - g_strfreev (split); - - return FALSE; - } - - n_alphas = i; - - /* FIXME allow specifying horizontal/vertical/diagonal in theme format, - * once we implement vertical/diagonal in gradient.c - */ - spec = meta_alpha_gradient_spec_new (META_GRADIENT_HORIZONTAL, - n_alphas); - - i = 0; - while (i < n_alphas) - { - double v; - - if (!parse_double (split[i], &v, context, error)) - { - /* clear up, but don't set error: it was set by parse_double */ - g_strfreev (split); - meta_alpha_gradient_spec_free (spec); - - return FALSE; - } - - if (v < (0.0 - 1e-6) || v > (1.0 + 1e-6)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Alpha must be between 0.0 (invisible) and 1.0 (fully opaque), was %g\n"), - v); - - g_strfreev (split); - meta_alpha_gradient_spec_free (spec); - - return FALSE; - } - - spec->alphas[i] = (unsigned char) (v * 255); - - ++i; - } - - g_strfreev (split); - - *spec_ret = spec; - - return TRUE; -} - -static MetaColorSpec* -parse_color (MetaTheme *theme, - const char *str, - GError **err) -{ - char* referent; - - if (META_THEME_ALLOWS (theme, META_THEME_COLOR_CONSTANTS) && - meta_theme_lookup_color_constant (theme, str, &referent)) - { - if (referent) - return meta_color_spec_new_from_string (referent, err); - - /* no need to free referent: it's a pointer into the actual hash table */ - } - - return meta_color_spec_new_from_string (str, err); -} - -static gboolean -parse_title_scale (const char *str, - double *val, - GMarkupParseContext *context, - GError **error) -{ - double factor; - - if (strcmp (str, "xx-small") == 0) - factor = PANGO_SCALE_XX_SMALL; - else if (strcmp (str, "x-small") == 0) - factor = PANGO_SCALE_X_SMALL; - else if (strcmp (str, "small") == 0) - factor = PANGO_SCALE_SMALL; - else if (strcmp (str, "medium") == 0) - factor = PANGO_SCALE_MEDIUM; - else if (strcmp (str, "large") == 0) - factor = PANGO_SCALE_LARGE; - else if (strcmp (str, "x-large") == 0) - factor = PANGO_SCALE_X_LARGE; - else if (strcmp (str, "xx-large") == 0) - factor = PANGO_SCALE_XX_LARGE; - else - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Invalid title scale \"%s\" (must be one of xx-small,x-small,small,medium,large,x-large,xx-large)\n"), - str); - return FALSE; - } - - *val = factor; - - return TRUE; -} - -static void -parse_toplevel_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_THEME); - - if (ELEMENT_IS ("info")) - { - if (!check_no_attributes (context, element_name, - attribute_names, attribute_values, - error)) - return; - - push_state (info, STATE_INFO); - } - else if (ELEMENT_IS ("constant")) - { - const char *name; - const char *value; - int ival = 0; - double dval = 0.0; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, "!value", &value, - NULL)) - return; - - /* We don't know how a a constant is going to be used, so we have guess its - * type from its contents: - * - * - Starts like a number and contains a '.': float constant - * - Starts like a number and doesn't contain a '.': int constant - * - Starts with anything else: a color constant. - * (colors always start with # or a letter) - */ - if (value[0] == '.' || value[0] == '+' || value[0] == '-' || (value[0] >= '0' && value[0] <= '9')) - { - if (strchr (value, '.')) - { - if (!parse_double (value, &dval, context, error)) - return; - - if (!meta_theme_define_float_constant (info->theme, - name, - dval, - error)) - { - add_context_to_error (error, context); - return; - } - } - else - { - if (!parse_positive_integer (value, &ival, context, info->theme, error)) - return; - - if (!meta_theme_define_int_constant (info->theme, - name, - ival, - error)) - { - add_context_to_error (error, context); - return; - } - } - } - else - { - if (!meta_theme_define_color_constant (info->theme, - name, - value, - error)) - { - add_context_to_error (error, context); - return; - } - } - - push_state (info, STATE_CONSTANT); - } - else if (ELEMENT_IS ("frame_geometry")) - { - const char *name = NULL; - const char *parent = NULL; - const char *has_title = NULL; - const char *title_scale = NULL; - const char *rounded_top_left = NULL; - const char *rounded_top_right = NULL; - const char *rounded_bottom_left = NULL; - const char *rounded_bottom_right = NULL; - const char *hide_buttons = NULL; - gboolean has_title_val; - guint rounded_top_left_val; - guint rounded_top_right_val; - guint rounded_bottom_left_val; - guint rounded_bottom_right_val; - gboolean hide_buttons_val; - double title_scale_val; - MetaFrameLayout *parent_layout; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, "parent", &parent, - "has_title", &has_title, "title_scale", &title_scale, - "rounded_top_left", &rounded_top_left, - "rounded_top_right", &rounded_top_right, - "rounded_bottom_left", &rounded_bottom_left, - "rounded_bottom_right", &rounded_bottom_right, - "hide_buttons", &hide_buttons, - NULL)) - return; - - has_title_val = TRUE; - if (has_title && !parse_boolean (has_title, &has_title_val, context, error)) - return; - - hide_buttons_val = FALSE; - if (hide_buttons && !parse_boolean (hide_buttons, &hide_buttons_val, context, error)) - return; - - rounded_top_left_val = 0; - rounded_top_right_val = 0; - rounded_bottom_left_val = 0; - rounded_bottom_right_val = 0; - - if (rounded_top_left && !parse_rounding (rounded_top_left, &rounded_top_left_val, context, info->theme, error)) - return; - if (rounded_top_right && !parse_rounding (rounded_top_right, &rounded_top_right_val, context, info->theme, error)) - return; - if (rounded_bottom_left && !parse_rounding (rounded_bottom_left, &rounded_bottom_left_val, context, info->theme, error)) - return; - if (rounded_bottom_right && !parse_rounding (rounded_bottom_right, &rounded_bottom_right_val, context, info->theme, error)) - return; - - title_scale_val = 1.0; - if (title_scale && !parse_title_scale (title_scale, &title_scale_val, context, error)) - return; - - if (meta_theme_lookup_layout (info->theme, name)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> name \"%s\" used a second time"), - element_name, name); - return; - } - - parent_layout = NULL; - if (parent) - { - parent_layout = meta_theme_lookup_layout (info->theme, parent); - if (parent_layout == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> parent \"%s\" has not been defined"), - element_name, parent); - return; - } - } - - g_assert (info->layout == NULL); - - if (parent_layout) - info->layout = meta_frame_layout_copy (parent_layout); - else - info->layout = meta_frame_layout_new (); - - if (has_title) /* only if explicit, otherwise inherit */ - info->layout->has_title = has_title_val; - - if (META_THEME_ALLOWS (info->theme, META_THEME_HIDDEN_BUTTONS) && hide_buttons_val) - info->layout->hide_buttons = hide_buttons_val; - - if (title_scale) - info->layout->title_scale = title_scale_val; - - if (rounded_top_left) - info->layout->top_left_corner_rounded_radius = rounded_top_left_val; - - if (rounded_top_right) - info->layout->top_right_corner_rounded_radius = rounded_top_right_val; - - if (rounded_bottom_left) - info->layout->bottom_left_corner_rounded_radius = rounded_bottom_left_val; - - if (rounded_bottom_right) - info->layout->bottom_right_corner_rounded_radius = rounded_bottom_right_val; - - meta_theme_insert_layout (info->theme, name, info->layout); - - push_state (info, STATE_FRAME_GEOMETRY); - } - else if (ELEMENT_IS ("draw_ops")) - { - const char *name = NULL; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, - NULL)) - return; - - if (meta_theme_lookup_draw_op_list (info->theme, name)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> name \"%s\" used a second time"), - element_name, name); - return; - } - - g_assert (info->op_list == NULL); - info->op_list = meta_draw_op_list_new (2); - - meta_theme_insert_draw_op_list (info->theme, name, info->op_list); - - push_state (info, STATE_DRAW_OPS); - } - else if (ELEMENT_IS ("frame_style")) - { - const char *name = NULL; - const char *parent = NULL; - const char *geometry = NULL; - const char *background = NULL; - const char *alpha = NULL; - MetaFrameStyle *parent_style; - MetaFrameLayout *layout; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, "parent", &parent, - "geometry", &geometry, - "background", &background, - "alpha", &alpha, - NULL)) - return; - - if (meta_theme_lookup_style (info->theme, name)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> name \"%s\" used a second time"), - element_name, name); - return; - } - - parent_style = NULL; - if (parent) - { - parent_style = meta_theme_lookup_style (info->theme, parent); - if (parent_style == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> parent \"%s\" has not been defined"), - element_name, parent); - return; - } - } - - layout = NULL; - if (geometry) - { - layout = meta_theme_lookup_layout (info->theme, geometry); - if (layout == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> geometry \"%s\" has not been defined"), - element_name, geometry); - return; - } - } - else if (parent_style) - { - layout = parent_style->layout; - } - - if (layout == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> must specify either a geometry or a parent that has a geometry"), - element_name); - return; - } - - g_assert (info->style == NULL); - - info->style = meta_frame_style_new (parent_style); - g_assert (info->style->layout == NULL); - meta_frame_layout_ref (layout); - info->style->layout = layout; - - if (background != NULL && META_THEME_ALLOWS (info->theme, META_THEME_FRAME_BACKGROUNDS)) - { - info->style->window_background_color = meta_color_spec_new_from_string (background, error); - if (!info->style->window_background_color) - return; - - if (alpha != NULL) - { - - gboolean success; - MetaAlphaGradientSpec *alpha_vector; - - g_clear_error (error); - /* fortunately, we already have a routine to parse alpha values, - * though it produces a vector of them, which is a superset of - * what we want. - */ - success = parse_alpha (alpha, &alpha_vector, context, error); - if (!success) - return; - - /* alpha_vector->alphas must contain at least one element */ - info->style->window_background_alpha = alpha_vector->alphas[0]; - - meta_alpha_gradient_spec_free (alpha_vector); - } - } - else if (alpha != NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("You must specify a background for an alpha value to be meaningful")); - return; - } - - meta_theme_insert_style (info->theme, name, info->style); - - push_state (info, STATE_FRAME_STYLE); - } - else if (ELEMENT_IS ("frame_style_set")) - { - const char *name = NULL; - const char *parent = NULL; - MetaFrameStyleSet *parent_set; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, "parent", &parent, - NULL)) - return; - - if (meta_theme_lookup_style_set (info->theme, name)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> name \"%s\" used a second time"), - element_name, name); - return; - } - - parent_set = NULL; - if (parent) - { - parent_set = meta_theme_lookup_style_set (info->theme, parent); - if (parent_set == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("<%s> parent \"%s\" has not been defined"), - element_name, parent); - return; - } - } - - g_assert (info->style_set == NULL); - - info->style_set = meta_frame_style_set_new (parent_set); - - meta_theme_insert_style_set (info->theme, name, info->style_set); - - push_state (info, STATE_FRAME_STYLE_SET); - } - else if (ELEMENT_IS ("window")) - { - const char *type_name = NULL; - const char *style_set_name = NULL; - MetaFrameStyleSet *style_set; - MetaFrameType type; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!type", &type_name, "!style_set", &style_set_name, - NULL)) - return; - - type = meta_frame_type_from_string (type_name); - - if (type == META_FRAME_TYPE_LAST || - (type == META_FRAME_TYPE_ATTACHED && peek_required_version (info) < 3002)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Unknown type \"%s\" on <%s> element"), - type_name, element_name); - return; - } - - style_set = meta_theme_lookup_style_set (info->theme, - style_set_name); - - if (style_set == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Unknown style_set \"%s\" on <%s> element"), - style_set_name, element_name); - return; - } - - if (info->theme->style_sets_by_type[type] != NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Window type \"%s\" has already been assigned a style set"), - type_name); - return; - } - - meta_frame_style_set_ref (style_set); - info->theme->style_sets_by_type[type] = style_set; - - push_state (info, STATE_WINDOW); - } - else if (ELEMENT_IS ("menu_icon")) - { - /* Not supported any more, but we have to parse it if they include it, - * for backwards compatibility. - */ - g_assert (info->op_list == NULL); - - push_state (info, STATE_MENU_ICON); - } - else if (ELEMENT_IS ("fallback")) - { - /* Not supported any more, but we have to parse it if they include it, - * for backwards compatibility. - */ - push_state (info, STATE_FALLBACK); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "metacity_theme"); - } -} - -static void -parse_info_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_INFO); - - if (ELEMENT_IS ("name")) - { - if (!check_no_attributes (context, element_name, - attribute_names, attribute_values, - error)) - return; - - push_state (info, STATE_NAME); - } - else if (ELEMENT_IS ("author")) - { - if (!check_no_attributes (context, element_name, - attribute_names, attribute_values, - error)) - return; - - push_state (info, STATE_AUTHOR); - } - else if (ELEMENT_IS ("copyright")) - { - if (!check_no_attributes (context, element_name, - attribute_names, attribute_values, - error)) - return; - - push_state (info, STATE_COPYRIGHT); - } - else if (ELEMENT_IS ("description")) - { - if (!check_no_attributes (context, element_name, - attribute_names, attribute_values, - error)) - return; - - push_state (info, STATE_DESCRIPTION); - } - else if (ELEMENT_IS ("date")) - { - if (!check_no_attributes (context, element_name, - attribute_names, attribute_values, - error)) - return; - - push_state (info, STATE_DATE); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "info"); - } -} - -static void -parse_distance (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - const char *name; - const char *value; - int val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, "!value", &value, - NULL)) - return; - - val = 0; - if (!parse_positive_integer (value, &val, context, info->theme, error)) - return; - - g_assert (val >= 0); /* yeah, "non-negative" not "positive" get over it */ - g_assert (info->layout); - - if (strcmp (name, "left_width") == 0) - info->layout->left_width = val; - else if (strcmp (name, "right_width") == 0) - info->layout->right_width = val; - else if (strcmp (name, "bottom_height") == 0) - info->layout->bottom_height = val; - else if (strcmp (name, "title_vertical_pad") == 0) - info->layout->title_vertical_pad = val; - else if (strcmp (name, "right_titlebar_edge") == 0) - info->layout->right_titlebar_edge = val; - else if (strcmp (name, "left_titlebar_edge") == 0) - info->layout->left_titlebar_edge = val; - else if (strcmp (name, "button_width") == 0) - { - info->layout->button_width = val; - - if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST || - info->layout->button_sizing == META_BUTTON_SIZING_FIXED)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons")); - return; - } - - info->layout->button_sizing = META_BUTTON_SIZING_FIXED; - } - else if (strcmp (name, "button_height") == 0) - { - info->layout->button_height = val; - - if (!(info->layout->button_sizing == META_BUTTON_SIZING_LAST || - info->layout->button_sizing == META_BUTTON_SIZING_FIXED)) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons")); - return; - } - - info->layout->button_sizing = META_BUTTON_SIZING_FIXED; - } - else - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Distance \"%s\" is unknown"), name); - return; - } -} - -static void -parse_aspect_ratio (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - const char *name; - const char *value; - double val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, "!value", &value, - NULL)) - return; - - val = 0; - if (!parse_double (value, &val, context, error)) - return; - - g_assert (info->layout); - - if (strcmp (name, "button") == 0) - { - info->layout->button_aspect = val; - - if (info->layout->button_sizing != META_BUTTON_SIZING_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Cannot specify both \"button_width\"/\"button_height\" and \"aspect_ratio\" for buttons")); - return; - } - - info->layout->button_sizing = META_BUTTON_SIZING_ASPECT; - } - else - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Aspect ratio \"%s\" is unknown"), name); - return; - } -} - -static void -parse_border (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - const char *name; - const char *top; - const char *bottom; - const char *left; - const char *right; - int top_val; - int bottom_val; - int left_val; - int right_val; - GtkBorder *border; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!name", &name, - "!top", &top, - "!bottom", &bottom, - "!left", &left, - "!right", &right, - NULL)) - return; - - top_val = 0; - if (!parse_positive_integer (top, &top_val, context, info->theme, error)) - return; - - bottom_val = 0; - if (!parse_positive_integer (bottom, &bottom_val, context, info->theme, error)) - return; - - left_val = 0; - if (!parse_positive_integer (left, &left_val, context, info->theme, error)) - return; - - right_val = 0; - if (!parse_positive_integer (right, &right_val, context, info->theme, error)) - return; - - g_assert (info->layout); - - border = NULL; - - if (strcmp (name, "title_border") == 0) - border = &info->layout->title_border; - else if (strcmp (name, "button_border") == 0) - border = &info->layout->button_border; - - if (border == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Border \"%s\" is unknown"), name); - return; - } - - border->top = top_val; - border->bottom = bottom_val; - border->left = left_val; - border->right = right_val; -} - -static void -parse_geometry_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_FRAME_GEOMETRY); - - if (ELEMENT_IS ("distance")) - { - parse_distance (context, element_name, - attribute_names, attribute_values, - info, error); - push_state (info, STATE_DISTANCE); - } - else if (ELEMENT_IS ("border")) - { - parse_border (context, element_name, - attribute_names, attribute_values, - info, error); - push_state (info, STATE_BORDER); - } - else if (ELEMENT_IS ("aspect_ratio")) - { - parse_aspect_ratio (context, element_name, - attribute_names, attribute_values, - info, error); - - push_state (info, STATE_ASPECT_RATIO); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "frame_geometry"); - } -} - -#if 0 -static gboolean -check_expression (PosToken *tokens, - int n_tokens, - gboolean has_object, - MetaTheme *theme, - GMarkupParseContext *context, - GError **error) -{ - MetaPositionExprEnv env; - int x, y; - - /* We set it all to 0 to try and catch divide-by-zero screwups. - * it's possible we should instead guarantee that widths and heights - * are at least 1. - */ - - env.rect = meta_rect (0, 0, 0, 0); - if (has_object) - { - env.object_width = 0; - env.object_height = 0; - } - else - { - env.object_width = -1; - env.object_height = -1; - } - - env.left_width = 0; - env.right_width = 0; - env.top_height = 0; - env.bottom_height = 0; - env.title_width = 0; - env.title_height = 0; - - env.icon_width = 0; - env.icon_height = 0; - env.mini_icon_width = 0; - env.mini_icon_height = 0; - env.theme = theme; - - if (!meta_parse_position_expression (tokens, n_tokens, - &env, - &x, &y, - error)) - { - add_context_to_error (error, context); - return FALSE; - } - - return TRUE; -} -#endif - -static void -parse_draw_op_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_DRAW_OPS); - - if (ELEMENT_IS ("line")) - { - MetaDrawOp *op; - const char *color; - const char *x1; - const char *y1; - const char *x2; - const char *y2; - const char *dash_on_length; - const char *dash_off_length; - const char *width; - MetaColorSpec *color_spec; - int dash_on_val; - int dash_off_val; - int width_val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!color", &color, - "!x1", &x1, "!y1", &y1, - "!x2", &x2, "!y2", &y2, - "dash_on_length", &dash_on_length, - "dash_off_length", &dash_off_length, - "width", &width, - NULL)) - return; - -#if 0 - if (!check_expression (x1, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y1, FALSE, info->theme, context, error)) - return; - - if (!check_expression (x2, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y2, FALSE, info->theme, context, error)) - return; -#endif - - dash_on_val = 0; - if (dash_on_length && - !parse_positive_integer (dash_on_length, &dash_on_val, context, info->theme, error)) - return; - - dash_off_val = 0; - if (dash_off_length && - !parse_positive_integer (dash_off_length, &dash_off_val, context, info->theme, error)) - return; - - width_val = 0; - if (width && - !parse_positive_integer (width, &width_val, context, info->theme, error)) - return; - - /* Check last so we don't have to free it when other - * stuff fails - */ - color_spec = parse_color (info->theme, color, error); - if (color_spec == NULL) - { - add_context_to_error (error, context); - return; - } - - op = meta_draw_op_new (META_DRAW_LINE); - - op->data.line.color_spec = color_spec; - - op->data.line.x1 = meta_draw_spec_new (info->theme, x1, NULL); - op->data.line.y1 = meta_draw_spec_new (info->theme, y1, NULL); - - if (strcmp(x1, x2)==0) - op->data.line.x2 = NULL; - else - op->data.line.x2 = meta_draw_spec_new (info->theme, x2, NULL); - - if (strcmp(y1, y2)==0) - op->data.line.y2 = NULL; - else - op->data.line.y2 = meta_draw_spec_new (info->theme, y2, NULL); - - op->data.line.width = width_val; - op->data.line.dash_on_length = dash_on_val; - op->data.line.dash_off_length = dash_off_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_LINE); - } - else if (ELEMENT_IS ("rectangle")) - { - MetaDrawOp *op; - const char *color; - const char *x; - const char *y; - const char *width; - const char *height; - const char *filled; - gboolean filled_val; - MetaColorSpec *color_spec; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!color", &color, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "filled", &filled, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - - filled_val = FALSE; - if (filled && !parse_boolean (filled, &filled_val, context, error)) - return; - - /* Check last so we don't have to free it when other - * stuff fails - */ - color_spec = parse_color (info->theme, color, error); - if (color_spec == NULL) - { - add_context_to_error (error, context); - return; - } - - op = meta_draw_op_new (META_DRAW_RECTANGLE); - - op->data.rectangle.color_spec = color_spec; - op->data.rectangle.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.rectangle.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.rectangle.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.rectangle.height = meta_draw_spec_new (info->theme, - height, NULL); - - op->data.rectangle.filled = filled_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_RECTANGLE); - } - else if (ELEMENT_IS ("arc")) - { - MetaDrawOp *op; - const char *color; - const char *x; - const char *y; - const char *width; - const char *height; - const char *filled; - const char *start_angle; - const char *extent_angle; - const char *from; - const char *to; - gboolean filled_val; - double start_angle_val; - double extent_angle_val; - MetaColorSpec *color_spec; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!color", &color, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "filled", &filled, - "start_angle", &start_angle, - "extent_angle", &extent_angle, - "from", &from, - "to", &to, - NULL)) - return; - - if (META_THEME_ALLOWS (info->theme, META_THEME_DEGREES_IN_ARCS) ) - { - if (start_angle == NULL && from == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("No \"start_angle\" or \"from\" attribute on element <%s>"), element_name); - return; - } - - if (extent_angle == NULL && to == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("No \"extent_angle\" or \"to\" attribute on element <%s>"), element_name); - return; - } - } - else - { - if (start_angle == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - ATTRIBUTE_NOT_FOUND, "start_angle", element_name); - return; - } - - if (extent_angle == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - ATTRIBUTE_NOT_FOUND, "extent_angle", element_name); - return; - } - } - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - - if (start_angle == NULL) - { - if (!parse_angle (from, &start_angle_val, context, error)) - return; - - start_angle_val = (180-start_angle_val)/360.0; - } - else - { - if (!parse_angle (start_angle, &start_angle_val, context, error)) - return; - } - - if (extent_angle == NULL) - { - if (!parse_angle (to, &extent_angle_val, context, error)) - return; - - extent_angle_val = ((180-extent_angle_val)/360.0) - start_angle_val; - } - else - { - if (!parse_angle (extent_angle, &extent_angle_val, context, error)) - return; - } - - filled_val = FALSE; - if (filled && !parse_boolean (filled, &filled_val, context, error)) - return; - - /* Check last so we don't have to free it when other - * stuff fails - */ - color_spec = parse_color (info->theme, color, error); - if (color_spec == NULL) - { - add_context_to_error (error, context); - return; - } - - op = meta_draw_op_new (META_DRAW_ARC); - - op->data.arc.color_spec = color_spec; - - op->data.arc.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.arc.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.arc.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.arc.height = meta_draw_spec_new (info->theme, height, NULL); - - op->data.arc.filled = filled_val; - op->data.arc.start_angle = start_angle_val; - op->data.arc.extent_angle = extent_angle_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_ARC); - } - else if (ELEMENT_IS ("clip")) - { - MetaDrawOp *op; - const char *x; - const char *y; - const char *width; - const char *height; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - op = meta_draw_op_new (META_DRAW_CLIP); - - op->data.clip.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.clip.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.clip.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.clip.height = meta_draw_spec_new (info->theme, height, NULL); - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_CLIP); - } - else if (ELEMENT_IS ("tint")) - { - MetaDrawOp *op; - const char *color; - const char *x; - const char *y; - const char *width; - const char *height; - const char *alpha; - MetaAlphaGradientSpec *alpha_spec; - MetaColorSpec *color_spec; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!color", &color, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "!alpha", &alpha, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - alpha_spec = NULL; - if (!parse_alpha (alpha, &alpha_spec, context, error)) - return; - - /* Check last so we don't have to free it when other - * stuff fails - */ - color_spec = parse_color (info->theme, color, error); - if (color_spec == NULL) - { - if (alpha_spec) - meta_alpha_gradient_spec_free (alpha_spec); - - add_context_to_error (error, context); - return; - } - - op = meta_draw_op_new (META_DRAW_TINT); - - op->data.tint.color_spec = color_spec; - op->data.tint.alpha_spec = alpha_spec; - - op->data.tint.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.tint.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.tint.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.tint.height = meta_draw_spec_new (info->theme, height, NULL); - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_TINT); - } - else if (ELEMENT_IS ("gradient")) - { - const char *x; - const char *y; - const char *width; - const char *height; - const char *type; - const char *alpha; - MetaAlphaGradientSpec *alpha_spec; - MetaGradientType type_val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!type", &type, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "alpha", &alpha, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - - type_val = meta_gradient_type_from_string (type); - if (type_val == META_GRADIENT_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Did not understand value \"%s\" for type of gradient"), - type); - return; - } - - alpha_spec = NULL; - if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) - return; - - g_assert (info->op == NULL); - info->op = meta_draw_op_new (META_DRAW_GRADIENT); - - info->op->data.gradient.x = meta_draw_spec_new (info->theme, x, NULL); - info->op->data.gradient.y = meta_draw_spec_new (info->theme, y, NULL); - info->op->data.gradient.width = meta_draw_spec_new (info->theme, - width, NULL); - info->op->data.gradient.height = meta_draw_spec_new (info->theme, - height, NULL); - - info->op->data.gradient.gradient_spec = meta_gradient_spec_new (type_val); - - info->op->data.gradient.alpha_spec = alpha_spec; - - push_state (info, STATE_GRADIENT); - - /* op gets appended on close tag */ - } - else if (ELEMENT_IS ("image")) - { - MetaDrawOp *op; - const char *filename; - const char *x; - const char *y; - const char *width; - const char *height; - const char *alpha; - const char *colorize; - const char *fill_type; - MetaAlphaGradientSpec *alpha_spec; - GdkPixbuf *pixbuf; - MetaColorSpec *colorize_spec = NULL; - MetaImageFillType fill_type_val; - int h, w, c; - int pixbuf_width, pixbuf_height, pixbuf_n_channels, pixbuf_rowstride; - guchar *pixbuf_pixels; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "alpha", &alpha, "!filename", &filename, - "colorize", &colorize, - "fill_type", &fill_type, - NULL)) - return; - -#if 0 - if (!check_expression (x, TRUE, info->theme, context, error)) - return; - - if (!check_expression (y, TRUE, info->theme, context, error)) - return; - - if (!check_expression (width, TRUE, info->theme, context, error)) - return; - - if (!check_expression (height, TRUE, info->theme, context, error)) - return; -#endif - fill_type_val = META_IMAGE_FILL_SCALE; - if (fill_type) - { - fill_type_val = meta_image_fill_type_from_string (fill_type); - - if (((int) fill_type_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand fill type \"%s\" for <%s> element"), - fill_type, element_name); - } - } - - /* Check last so we don't have to free it when other - * stuff fails. - * - * If it's a theme image, ask for it at 64px, which is - * the largest possible. We scale it anyway. - */ - pixbuf = meta_theme_load_image (info->theme, filename, 64, error); - - if (pixbuf == NULL) - { - add_context_to_error (error, context); - return; - } - - if (colorize) - { - colorize_spec = parse_color (info->theme, colorize, error); - - if (colorize_spec == NULL) - { - add_context_to_error (error, context); - g_object_unref (G_OBJECT (pixbuf)); - return; - } - } - - alpha_spec = NULL; - if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) - { - g_object_unref (G_OBJECT (pixbuf)); - return; - } - - op = meta_draw_op_new (META_DRAW_IMAGE); - - op->data.image.pixbuf = pixbuf; - op->data.image.colorize_spec = colorize_spec; - - op->data.image.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.image.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.image.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.image.height = meta_draw_spec_new (info->theme, height, NULL); - - op->data.image.alpha_spec = alpha_spec; - op->data.image.fill_type = fill_type_val; - - /* Check for vertical & horizontal stripes */ - pixbuf_n_channels = gdk_pixbuf_get_n_channels(pixbuf); - pixbuf_width = gdk_pixbuf_get_width(pixbuf); - pixbuf_height = gdk_pixbuf_get_height(pixbuf); - pixbuf_rowstride = gdk_pixbuf_get_rowstride(pixbuf); - pixbuf_pixels = gdk_pixbuf_get_pixels(pixbuf); - - /* Check for horizontal stripes */ - for (h = 0; h < pixbuf_height; h++) - { - for (w = 1; w < pixbuf_width; w++) - { - for (c = 0; c < pixbuf_n_channels; c++) - { - if (pixbuf_pixels[(h * pixbuf_rowstride) + c] != - pixbuf_pixels[(h * pixbuf_rowstride) + w + c]) - break; - } - if (c < pixbuf_n_channels) - break; - } - if (w < pixbuf_width) - break; - } - - if (h >= pixbuf_height) - { - op->data.image.horizontal_stripes = TRUE; - } - else - { - op->data.image.horizontal_stripes = FALSE; - } - - /* Check for vertical stripes */ - for (w = 0; w < pixbuf_width; w++) - { - for (h = 1; h < pixbuf_height; h++) - { - for (c = 0; c < pixbuf_n_channels; c++) - { - if (pixbuf_pixels[w + c] != - pixbuf_pixels[(h * pixbuf_rowstride) + w + c]) - break; - } - if (c < pixbuf_n_channels) - break; - } - if (h < pixbuf_height) - break; - } - - if (w >= pixbuf_width) - { - op->data.image.vertical_stripes = TRUE; - } - else - { - op->data.image.vertical_stripes = FALSE; - } - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_IMAGE); - } - else if (ELEMENT_IS ("gtk_arrow")) - { - MetaDrawOp *op; - const char *state; - const char *shadow; - const char *arrow; - const char *x; - const char *y; - const char *width; - const char *height; - const char *filled; - gboolean filled_val; - GtkStateFlags state_val; - GtkShadowType shadow_val; - GtkArrowType arrow_val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!state", &state, - "!shadow", &shadow, - "!arrow", &arrow, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "filled", &filled, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - filled_val = TRUE; - if (filled && !parse_boolean (filled, &filled_val, context, error)) - return; - - state_val = meta_gtk_state_from_string (state); - if (((int) state_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand state \"%s\" for <%s> element"), - state, element_name); - return; - } - - shadow_val = meta_gtk_shadow_from_string (shadow); - if (((int) shadow_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand shadow \"%s\" for <%s> element"), - shadow, element_name); - return; - } - - arrow_val = meta_gtk_arrow_from_string (arrow); - if (((int) arrow_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand arrow \"%s\" for <%s> element"), - arrow, element_name); - return; - } - - op = meta_draw_op_new (META_DRAW_GTK_ARROW); - - op->data.gtk_arrow.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.gtk_arrow.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.gtk_arrow.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.gtk_arrow.height = meta_draw_spec_new (info->theme, - height, NULL); - - op->data.gtk_arrow.filled = filled_val; - op->data.gtk_arrow.state = state_val; - op->data.gtk_arrow.shadow = shadow_val; - op->data.gtk_arrow.arrow = arrow_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_GTK_ARROW); - } - else if (ELEMENT_IS ("gtk_box")) - { - MetaDrawOp *op; - const char *state; - const char *shadow; - const char *x; - const char *y; - const char *width; - const char *height; - GtkStateFlags state_val; - GtkShadowType shadow_val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!state", &state, - "!shadow", &shadow, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - state_val = meta_gtk_state_from_string (state); - if (((int) state_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand state \"%s\" for <%s> element"), - state, element_name); - return; - } - - shadow_val = meta_gtk_shadow_from_string (shadow); - if (((int) shadow_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand shadow \"%s\" for <%s> element"), - shadow, element_name); - return; - } - - op = meta_draw_op_new (META_DRAW_GTK_BOX); - - op->data.gtk_box.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.gtk_box.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.gtk_box.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.gtk_box.height = meta_draw_spec_new (info->theme, height, NULL); - - op->data.gtk_box.state = state_val; - op->data.gtk_box.shadow = shadow_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_GTK_BOX); - } - else if (ELEMENT_IS ("gtk_vline")) - { - MetaDrawOp *op; - const char *state; - const char *x; - const char *y1; - const char *y2; - GtkStateFlags state_val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!state", &state, - "!x", &x, "!y1", &y1, "!y2", &y2, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y1, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y2, FALSE, info->theme, context, error)) - return; -#endif - - state_val = meta_gtk_state_from_string (state); - if (((int) state_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand state \"%s\" for <%s> element"), - state, element_name); - return; - } - - op = meta_draw_op_new (META_DRAW_GTK_VLINE); - - op->data.gtk_vline.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.gtk_vline.y1 = meta_draw_spec_new (info->theme, y1, NULL); - op->data.gtk_vline.y2 = meta_draw_spec_new (info->theme, y2, NULL); - - op->data.gtk_vline.state = state_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_GTK_VLINE); - } - else if (ELEMENT_IS ("icon")) - { - MetaDrawOp *op; - const char *x; - const char *y; - const char *width; - const char *height; - const char *alpha; - const char *fill_type; - MetaAlphaGradientSpec *alpha_spec; - MetaImageFillType fill_type_val; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!x", &x, "!y", &y, - "!width", &width, "!height", &height, - "alpha", &alpha, - "fill_type", &fill_type, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - fill_type_val = META_IMAGE_FILL_SCALE; - if (fill_type) - { - fill_type_val = meta_image_fill_type_from_string (fill_type); - - if (((int) fill_type_val) == -1) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Did not understand fill type \"%s\" for <%s> element"), - fill_type, element_name); - } - } - - alpha_spec = NULL; - if (alpha && !parse_alpha (alpha, &alpha_spec, context, error)) - return; - - op = meta_draw_op_new (META_DRAW_ICON); - - op->data.icon.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.icon.y = meta_draw_spec_new (info->theme, y, NULL); - op->data.icon.width = meta_draw_spec_new (info->theme, width, NULL); - op->data.icon.height = meta_draw_spec_new (info->theme, height, NULL); - - op->data.icon.alpha_spec = alpha_spec; - op->data.icon.fill_type = fill_type_val; - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_ICON); - } - else if (ELEMENT_IS ("title")) - { - MetaDrawOp *op; - const char *color; - const char *x; - const char *y; - const char *ellipsize_width; - MetaColorSpec *color_spec; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!color", &color, - "!x", &x, "!y", &y, - "ellipsize_width", &ellipsize_width, - NULL)) - return; - -#if 0 - if (!check_expression (x, FALSE, info->theme, context, error)) - return; - - if (!check_expression (y, FALSE, info->theme, context, error)) - return; - - if (!check_expression (ellipsize_width, FALSE, info->theme, context, error)) - return; -#endif - - if (ellipsize_width && peek_required_version (info) < 3001) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - ATTRIBUTE_NOT_FOUND, "ellipsize_width", element_name); - return; - } - - /* Check last so we don't have to free it when other - * stuff fails - */ - color_spec = parse_color (info->theme, color, error); - if (color_spec == NULL) - { - add_context_to_error (error, context); - return; - } - - op = meta_draw_op_new (META_DRAW_TITLE); - - op->data.title.color_spec = color_spec; - - op->data.title.x = meta_draw_spec_new (info->theme, x, NULL); - op->data.title.y = meta_draw_spec_new (info->theme, y, NULL); - if (ellipsize_width) - op->data.title.ellipsize_width = meta_draw_spec_new (info->theme, ellipsize_width, NULL); - - g_assert (info->op_list); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_TITLE); - } - else if (ELEMENT_IS ("include")) - { - MetaDrawOp *op; - const char *name; - const char *x; - const char *y; - const char *width; - const char *height; - MetaDrawOpList *op_list; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "x", &x, "y", &y, - "width", &width, "height", &height, - "!name", &name, - NULL)) - return; - - /* x/y/width/height default to 0,0,width,height - should - * probably do this for all the draw ops - */ -#if 0 - if (x && !check_expression (x, FALSE, info->theme, context, error)) - return; - - if (y && !check_expression (y, FALSE, info->theme, context, error)) - return; - - if (width && !check_expression (width, FALSE, info->theme, context, error)) - return; - - if (height && !check_expression (height, FALSE, info->theme, context, error)) - return; -#endif - - op_list = meta_theme_lookup_draw_op_list (info->theme, - name); - if (op_list == NULL) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("No called \"%s\" has been defined"), - name); - return; - } - - g_assert (info->op_list); - - if (op_list == info->op_list || - meta_draw_op_list_contains (op_list, info->op_list)) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Including draw_ops \"%s\" here would create a circular reference"), - name); - return; - } - - op = meta_draw_op_new (META_DRAW_OP_LIST); - - meta_draw_op_list_ref (op_list); - op->data.op_list.op_list = op_list; - - op->data.op_list.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL); - op->data.op_list.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL); - op->data.op_list.width = meta_draw_spec_new (info->theme, - width ? width : "width", - NULL); - op->data.op_list.height = meta_draw_spec_new (info->theme, - height ? height : "height", - NULL); - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_INCLUDE); - } - else if (ELEMENT_IS ("tile")) - { - MetaDrawOp *op; - const char *name; - const char *x; - const char *y; - const char *width; - const char *height; - const char *tile_xoffset; - const char *tile_yoffset; - const char *tile_width; - const char *tile_height; - MetaDrawOpList *op_list; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "x", &x, "y", &y, - "width", &width, "height", &height, - "!name", &name, - "tile_xoffset", &tile_xoffset, - "tile_yoffset", &tile_yoffset, - "!tile_width", &tile_width, - "!tile_height", &tile_height, - NULL)) - return; - - /* These default to 0 */ -#if 0 - if (tile_xoffset && !check_expression (tile_xoffset, FALSE, info->theme, context, error)) - return; - - if (tile_yoffset && !check_expression (tile_yoffset, FALSE, info->theme, context, error)) - return; - - /* x/y/width/height default to 0,0,width,height - should - * probably do this for all the draw ops - */ - if (x && !check_expression (x, FALSE, info->theme, context, error)) - return; - - if (y && !check_expression (y, FALSE, info->theme, context, error)) - return; - - if (width && !check_expression (width, FALSE, info->theme, context, error)) - return; - - if (height && !check_expression (height, FALSE, info->theme, context, error)) - return; - - if (!check_expression (tile_width, FALSE, info->theme, context, error)) - return; - - if (!check_expression (tile_height, FALSE, info->theme, context, error)) - return; -#endif - op_list = meta_theme_lookup_draw_op_list (info->theme, - name); - if (op_list == NULL) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("No called \"%s\" has been defined"), - name); - return; - } - - g_assert (info->op_list); - - if (op_list == info->op_list || - meta_draw_op_list_contains (op_list, info->op_list)) - { - set_error (error, context, G_MARKUP_ERROR, - G_MARKUP_ERROR_PARSE, - _("Including draw_ops \"%s\" here would create a circular reference"), - name); - return; - } - - op = meta_draw_op_new (META_DRAW_TILE); - - meta_draw_op_list_ref (op_list); - - op->data.tile.x = meta_draw_spec_new (info->theme, x ? x : "0", NULL); - op->data.tile.y = meta_draw_spec_new (info->theme, y ? y : "0", NULL); - op->data.tile.width = meta_draw_spec_new (info->theme, - width ? width : "width", - NULL); - op->data.tile.height = meta_draw_spec_new (info->theme, - height ? height : "height", - NULL); - op->data.tile.tile_xoffset = meta_draw_spec_new (info->theme, - tile_xoffset ? tile_xoffset : "0", - NULL); - op->data.tile.tile_yoffset = meta_draw_spec_new (info->theme, - tile_yoffset ? tile_yoffset : "0", - NULL); - op->data.tile.tile_width = meta_draw_spec_new (info->theme, tile_width, NULL); - op->data.tile.tile_height = meta_draw_spec_new (info->theme, tile_height, NULL); - - op->data.tile.op_list = op_list; - - meta_draw_op_list_append (info->op_list, op); - - push_state (info, STATE_TILE); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "draw_ops"); - } -} - -static void -parse_gradient_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_GRADIENT); - - if (ELEMENT_IS ("color")) - { - const char *value = NULL; - MetaColorSpec *color_spec; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!value", &value, - NULL)) - return; - - color_spec = parse_color (info->theme, value, error); - if (color_spec == NULL) - { - add_context_to_error (error, context); - return; - } - - g_assert (info->op); - g_assert (info->op->type == META_DRAW_GRADIENT); - g_assert (info->op->data.gradient.gradient_spec != NULL); - info->op->data.gradient.gradient_spec->color_specs = - g_slist_append (info->op->data.gradient.gradient_spec->color_specs, - color_spec); - - push_state (info, STATE_COLOR); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "gradient"); - } -} - -static void -parse_style_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE); - - g_assert (info->style); - - if (ELEMENT_IS ("piece")) - { - const char *position = NULL; - const char *draw_ops = NULL; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!position", &position, - "draw_ops", &draw_ops, - NULL)) - return; - - info->piece = meta_frame_piece_from_string (position); - if (info->piece == META_FRAME_PIECE_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Unknown position \"%s\" for frame piece"), - position); - return; - } - - if (info->style->pieces[info->piece] != NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Frame style already has a piece at position %s"), - position); - return; - } - - g_assert (info->op_list == NULL); - - if (draw_ops) - { - MetaDrawOpList *op_list; - - op_list = meta_theme_lookup_draw_op_list (info->theme, - draw_ops); - - if (op_list == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("No with the name \"%s\" has been defined"), - draw_ops); - return; - } - - meta_draw_op_list_ref (op_list); - info->op_list = op_list; - } - - push_state (info, STATE_PIECE); - } - else if (ELEMENT_IS ("button")) - { - const char *function = NULL; - const char *state = NULL; - const char *draw_ops = NULL; - gint required_version; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!function", &function, - "!state", &state, - "draw_ops", &draw_ops, - NULL)) - return; - - info->button_type = meta_button_type_from_string (function, info->theme); - if (info->button_type == META_BUTTON_TYPE_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Unknown function \"%s\" for button"), - function); - return; - } - - required_version = peek_required_version (info); - if (meta_theme_earliest_version_with_button (info->button_type) > - (guint)required_version) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Button function \"%s\" does not exist in this version (%d, need %d)"), - function, - required_version, - meta_theme_earliest_version_with_button (info->button_type) - ); - return; - } - - info->button_state = meta_button_state_from_string (state); - if (info->button_state == META_BUTTON_STATE_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Unknown state \"%s\" for button"), - state); - return; - } - - if (info->style->buttons[info->button_type][info->button_state] != NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Frame style already has a button for function %s state %s"), - function, state); - return; - } - - g_assert (info->op_list == NULL); - - if (draw_ops) - { - MetaDrawOpList *op_list; - - op_list = meta_theme_lookup_draw_op_list (info->theme, - draw_ops); - - if (op_list == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("No with the name \"%s\" has been defined"), - draw_ops); - return; - } - - meta_draw_op_list_ref (op_list); - info->op_list = op_list; - } - - push_state (info, STATE_BUTTON); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "frame_style"); - } -} - -static void -parse_style_set_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_FRAME_STYLE_SET); - - if (ELEMENT_IS ("frame")) - { - const char *focus = NULL; - const char *state = NULL; - const char *resize = NULL; - const char *style = NULL; - MetaFrameFocus frame_focus; - MetaFrameState frame_state; - MetaFrameResize frame_resize; - MetaFrameStyle *frame_style; - - if (!locate_attributes (context, element_name, attribute_names, attribute_values, - error, - "!focus", &focus, - "!state", &state, - "resize", &resize, - "!style", &style, - NULL)) - return; - - frame_focus = meta_frame_focus_from_string (focus); - if (frame_focus == META_FRAME_FOCUS_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("\"%s\" is not a valid value for focus attribute"), - focus); - return; - } - - frame_state = meta_frame_state_from_string (state); - if (frame_state == META_FRAME_STATE_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("\"%s\" is not a valid value for state attribute"), - focus); - return; - } - - frame_style = meta_theme_lookup_style (info->theme, style); - - if (frame_style == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("A style called \"%s\" has not been defined"), - style); - return; - } - - switch (frame_state) - { - case META_FRAME_STATE_NORMAL: - if (resize == NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - ATTRIBUTE_NOT_FOUND, - "resize", element_name); - return; - } - - - frame_resize = meta_frame_resize_from_string (resize); - if (frame_resize == META_FRAME_RESIZE_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("\"%s\" is not a valid value for resize attribute"), - focus); - return; - } - - break; - - case META_FRAME_STATE_SHADED: - if (META_THEME_ALLOWS (info->theme, META_THEME_UNRESIZABLE_SHADED_STYLES)) - { - if (resize == NULL) - /* In state="normal" we would complain here. But instead we accept - * not having a resize attribute and default to resize="both", since - * that most closely mimics what we did in v1, and thus people can - * upgrade a theme to v2 without as much hassle. - */ - frame_resize = META_FRAME_RESIZE_BOTH; - else - { - frame_resize = meta_frame_resize_from_string (resize); - if (frame_resize == META_FRAME_RESIZE_LAST) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("\"%s\" is not a valid value for resize attribute"), - focus); - return; - } - } - } - else /* v1 theme */ - { - if (resize != NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Should not have \"resize\" attribute on <%s> element for maximized/shaded states"), - element_name); - return; - } - - /* resize="both" is equivalent to the old behaviour */ - frame_resize = META_FRAME_RESIZE_BOTH; - } - break; - - default: - if (resize != NULL) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Should not have \"resize\" attribute on <%s> element for maximized states"), - element_name); - return; - } - - frame_resize = META_FRAME_RESIZE_LAST; - } - - switch (frame_state) - { - case META_FRAME_STATE_NORMAL: - if (info->style_set->normal_styles[frame_resize][frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s resize %s focus %s"), - state, resize, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->normal_styles[frame_resize][frame_focus] = frame_style; - break; - case META_FRAME_STATE_MAXIMIZED: - if (info->style_set->maximized_styles[frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s focus %s"), - state, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->maximized_styles[frame_focus] = frame_style; - break; - case META_FRAME_STATE_TILED_LEFT: - if (info->style_set->tiled_left_styles[frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s focus %s"), - state, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->tiled_left_styles[frame_focus] = frame_style; - break; - case META_FRAME_STATE_TILED_RIGHT: - if (info->style_set->tiled_right_styles[frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s focus %s"), - state, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->tiled_right_styles[frame_focus] = frame_style; - break; - case META_FRAME_STATE_SHADED: - if (info->style_set->shaded_styles[frame_resize][frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s resize %s focus %s"), - state, resize, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->shaded_styles[frame_resize][frame_focus] = frame_style; - break; - case META_FRAME_STATE_MAXIMIZED_AND_SHADED: - if (info->style_set->maximized_and_shaded_styles[frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s focus %s"), - state, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->maximized_and_shaded_styles[frame_focus] = frame_style; - break; - case META_FRAME_STATE_TILED_LEFT_AND_SHADED: - if (info->style_set->tiled_left_and_shaded_styles[frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s focus %s"), - state, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->tiled_left_and_shaded_styles[frame_focus] = frame_style; - break; - case META_FRAME_STATE_TILED_RIGHT_AND_SHADED: - if (info->style_set->tiled_right_and_shaded_styles[frame_focus]) - { - set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Style has already been specified for state %s focus %s"), - state, focus); - return; - } - meta_frame_style_ref (frame_style); - info->style_set->tiled_right_and_shaded_styles[frame_focus] = frame_style; - break; - case META_FRAME_STATE_LAST: - g_assert_not_reached (); - break; - } - - push_state (info, STATE_FRAME); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "frame_style_set"); - } -} - -static void -parse_piece_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_PIECE); - - if (ELEMENT_IS ("draw_ops")) - { - if (info->op_list) - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Can't have a two draw_ops for a element (theme specified a draw_ops attribute and also a element, or specified two elements)")); - return; - } - - if (!check_no_attributes (context, element_name, attribute_names, attribute_values, - error)) - return; - - g_assert (info->op_list == NULL); - info->op_list = meta_draw_op_list_new (2); - - push_state (info, STATE_DRAW_OPS); - } - else - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Element <%s> is not allowed below <%s>"), - element_name, "piece"); - } -} - -static void -parse_button_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - ParseInfo *info, - GError **error) -{ - g_return_if_fail (peek_state (info) == STATE_BUTTON); - - if (ELEMENT_IS ("draw_ops")) - { - if (info->op_list) - { - set_error (error, context, - G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, - _("Can't have a two draw_ops for a