diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | data/Makefile.am | 1 | ||||
-rw-r--r-- | data/ui/Makefile.am | 7 | ||||
-rw-r--r-- | data/ui/theme-viewer-window.ui | 452 | ||||
-rw-r--r-- | po/POTFILES.in | 3 | ||||
-rw-r--r-- | src/Makefile.am | 14 | ||||
-rw-r--r-- | src/ui/preview-widget.c | 485 | ||||
-rw-r--r-- | src/ui/preview-widget.h | 79 | ||||
-rw-r--r-- | src/ui/theme-viewer.c | 1121 | ||||
-rw-r--r-- | theme-viewer/Makefile.am | 54 | ||||
-rw-r--r-- | theme-viewer/theme-viewer-main.c | 49 | ||||
-rw-r--r-- | theme-viewer/theme-viewer-window.c | 754 | ||||
-rw-r--r-- | theme-viewer/theme-viewer-window.h | 33 | ||||
-rw-r--r-- | theme-viewer/theme-viewer.gresource.xml | 6 |
15 files changed, 1369 insertions, 1699 deletions
diff --git a/Makefile.am b/Makefile.am index 4903767f..84d29cb0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,6 +3,7 @@ NULL = SUBDIRS = \ data \ libmetacity \ + theme-viewer \ doc \ src \ po \ diff --git a/configure.ac b/configure.ac index 25cff473..73cca30c 100644 --- a/configure.ac +++ b/configure.ac @@ -62,6 +62,7 @@ dnl Check for required programs dnl ************************************************************************** AC_PATH_PROG([GLIB_MKENUMS], [glib-mkenums]) +AC_PATH_PROG([GLIB_COMPILE_RESOURCES], [glib-compile-resources]) dnl ************************************************************************** dnl Check for required packages @@ -75,6 +76,11 @@ PKG_CHECK_MODULES([LIBMETACITY], [ gtk+-3.0 >= $GTK_REQUIRED_VERSION ]) +PKG_CHECK_MODULES([METACITY_THEME_VIEWER], [ + glib-2.0 >= $GLIB_REQUIRED_VERSION + gtk+-3.0 >= $GTK_REQUIRED_VERSION +]) + dnl ************************************************************************** # Honor aclocal flags @@ -431,6 +437,7 @@ AC_CONFIG_FILES([ data/Makefile data/pkgconfig/Makefile data/pkgconfig/libmetacity.pc + data/ui/Makefile doc/Makefile doc/creating_themes/Makefile @@ -442,6 +449,8 @@ AC_CONFIG_FILES([ src/tools/Makefile src/themes/Makefile + theme-viewer/Makefile + po/Makefile.in ]) diff --git a/data/Makefile.am b/data/Makefile.am index fa95971e..38625224 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -2,6 +2,7 @@ NULL = SUBDIRS = \ pkgconfig \ + ui \ $(NULL) -include $(top_srcdir)/git.mk diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am new file mode 100644 index 00000000..25e1cd9e --- /dev/null +++ b/data/ui/Makefile.am @@ -0,0 +1,7 @@ +NULL = + +EXTRA_DIST = \ + theme-viewer-window.ui \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/data/ui/theme-viewer-window.ui b/data/ui/theme-viewer-window.ui new file mode 100644 index 00000000..f7ba2006 --- /dev/null +++ b/data/ui/theme-viewer-window.ui @@ -0,0 +1,452 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.19.0 --> +<interface domain="metacity"> + <requires lib="gtk+" version="3.18"/> + <template class="ThemeViewerWindow" parent="GtkWindow"> + <property name="can_focus">False</property> + <property name="default_width">1024</property> + <property name="default_height">600</property> + <child> + <object class="GtkPaned"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">12</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">3</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Dark Theme:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSwitch" id="dark_theme"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">start</property> + <signal name="state-set" handler="dark_theme_state_set_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">3</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Frame Type:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="frame_type_combo_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">0</property> + <items> + <item translatable="yes">Normal</item> + <item translatable="yes">Dialog</item> + <item translatable="yes">Modal Dialog</item> + <item translatable="yes">Utility</item> + <item translatable="yes">Menu</item> + <item translatable="yes">Border</item> + <item translatable="yes">Attached</item> + </items> + <signal name="changed" handler="frame_type_combo_box_changed_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">3</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Frame Flags:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="column_spacing">6</property> + <child> + <object class="GtkCheckButton" id="has_focus"> + <property name="label" translatable="yes">Has Focus</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="flags_toggled_cb" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="shaded"> + <property name="label" translatable="yes">Shaded</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="flags_toggled_cb" swapped="no"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="maximized"> + <property name="label" translatable="yes">Maximized</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="flags_toggled_cb" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="fullscreen"> + <property name="label" translatable="yes">Fullscreen</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="flags_toggled_cb" swapped="no"/> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="tiled"> + <property name="label" translatable="yes">Tiled</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="flags_toggled_cb" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">3</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Button Layout:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="button_layout_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="text">:minimize,maximize,close</property> + <signal name="changed" handler="button_layout_entry_changed_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">3</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">start</property> + <property name="label" translatable="yes">Composited:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSwitch" id="composited"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="halign">start</property> + <property name="active">True</property> + <signal name="state-set" handler="composited_state_set_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="resize">False</property> + <property name="shrink">False</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkBox" id="choose_theme"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Choose Theme</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEventBox" id="theme_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <signal name="button-press-event" handler="theme_box_button_press_event_cb" swapped="no"/> + <signal name="button-release-event" handler="theme_box_button_release_event_cb" swapped="no"/> + <signal name="draw" handler="theme_box_draw_cb" swapped="no"/> + <signal name="motion-notify-event" handler="theme_box_motion_notify_event_cb" swapped="no"/> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + </object> + </child> + <child type="titlebar"> + <placeholder/> + </child> + </template> + <object class="GtkHeaderBar" id="header_bar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="show_close_button">True</property> + <child type="title"> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">10</property> + <child> + <object class="GtkComboBoxText" id="type_combo_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="active">0</property> + <items> + <item>GTK+</item> + <item>Metacity</item> + </items> + <signal name="changed" handler="type_combo_box_changed_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="theme_combo_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <signal name="changed" handler="theme_combo_box_changed_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="reload_button"> + <property name="label" translatable="yes">Reload</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <signal name="clicked" handler="reload_button_clicked_cb" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/po/POTFILES.in b/po/POTFILES.in index 0ed2ad9b..36aa9c76 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,5 +1,6 @@ # List of source files containing translatable strings. # Please keep this file sorted alphabetically. +[type: gettext/glade]data/ui/theme-viewer-window.ui libmetacity/meta-color-spec.c libmetacity/meta-draw-op.c libmetacity/meta-draw-spec.c @@ -34,4 +35,4 @@ src/ui/frames.c src/ui/menu.c src/ui/metaaccellabel.c src/ui/resizepopup.c -src/ui/theme-viewer.c +theme-viewer/theme-viewer-window.c diff --git a/src/Makefile.am b/src/Makefile.am index adae947f..401be92c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -110,17 +110,6 @@ metacity_SOURCES= \ ui/ui.c \ $(NULL) -metacity_theme_viewer_SOURCES= \ - core/boxes.c \ - include/boxes.h \ - core/util.c \ - include/util.h \ - include/common.h \ - ui/preview-widget.c \ - ui/preview-widget.h \ - ui/theme-viewer.c \ - $(NULL) - gsettings_SCHEMAS = org.gnome.metacity.gschema.xml @INTLTOOL_XML_NOMERGE_RULE@ @GSETTINGS_RULES@ @@ -128,10 +117,9 @@ gsettings_SCHEMAS = org.gnome.metacity.gschema.xml convertdir = $(datadir)/GConf/gsettings/ convert_DATA = metacity-schemas.convert -bin_PROGRAMS=metacity metacity-theme-viewer +bin_PROGRAMS=metacity metacity_LDADD=@METACITY_LIBS@ $(top_builddir)/libmetacity/libmetacity.la -metacity_theme_viewer_LDADD= @METACITY_LIBS@ $(top_builddir)/libmetacity/libmetacity.la testboxes_SOURCES=include/util.h core/util.c include/boxes.h core/boxes.c core/testboxes.c testgradient_SOURCES=../libmetacity/meta-gradient.h ../libmetacity/meta-gradient.c ui/testgradient.c diff --git a/src/ui/preview-widget.c b/src/ui/preview-widget.c deleted file mode 100644 index bf377b44..00000000 --- a/src/ui/preview-widget.c +++ /dev/null @@ -1,485 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity theme preview widget */ - -/* - * 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 <http://www.gnu.org/licenses/>. - */ - -#define _GNU_SOURCE -#define _XOPEN_SOURCE 600 /* for the maths routines over floats */ - -#include <math.h> -#include <gtk/gtk.h> -#include "common.h" /* for META_MINI_ICON_WIDTH */ -#include "preview-widget.h" - -static void meta_preview_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural); -static void meta_preview_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural); -static void meta_preview_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gboolean meta_preview_draw (GtkWidget *widget, - cairo_t *cr); -static void meta_preview_finalize (GObject *object); - -G_DEFINE_TYPE (MetaPreview, meta_preview, GTK_TYPE_BIN); - -static void -meta_preview_class_init (MetaPreviewClass *class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (class); - GtkWidgetClass *widget_class; - - widget_class = (GtkWidgetClass*) class; - - gobject_class->finalize = meta_preview_finalize; - - widget_class->draw = meta_preview_draw; - widget_class->get_preferred_width = meta_preview_get_preferred_width; - widget_class->get_preferred_height = meta_preview_get_preferred_height; - widget_class->size_allocate = meta_preview_size_allocate; - - gtk_container_class_handle_border_width (GTK_CONTAINER_CLASS (class)); -} - -static void -meta_preview_init (MetaPreview *preview) -{ - int i; - - gtk_widget_set_has_window (GTK_WIDGET (preview), FALSE); - - i = 0; - while (i < META_BUTTON_FUNCTION_LAST) - { - preview->button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; - preview->button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; - ++i; - } - - preview->button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU; - - preview->button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE; - preview->button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE; - preview->button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE; - - preview->type = META_FRAME_TYPE_NORMAL; - preview->flags = - META_FRAME_ALLOWS_DELETE | - META_FRAME_ALLOWS_MENU | - META_FRAME_ALLOWS_MINIMIZE | - META_FRAME_ALLOWS_MAXIMIZE | - META_FRAME_ALLOWS_VERTICAL_RESIZE | - META_FRAME_ALLOWS_HORIZONTAL_RESIZE | - META_FRAME_HAS_FOCUS | - META_FRAME_ALLOWS_SHADE | - META_FRAME_ALLOWS_MOVE; - - preview->borders_cached = FALSE; -} - -GtkWidget* -meta_preview_new (void) -{ - MetaPreview *preview; - - preview = g_object_new (META_TYPE_PREVIEW, NULL); - - return GTK_WIDGET (preview); -} - -static void -meta_preview_finalize (GObject *object) -{ - MetaPreview *preview; - - preview = META_PREVIEW (object); - - g_free (preview->title); - preview->title = NULL; - - G_OBJECT_CLASS (meta_preview_parent_class)->finalize (object); -} - -static void -ensure_info (MetaPreview *preview) -{ - GtkWidget *widget; - - widget = GTK_WIDGET (preview); - - if (preview->layout == NULL) - { - MetaStyleInfo *style_info; - PangoFontDescription *font_desc; - MetaFrameStyle *style; - PangoAttrList *attrs; - PangoAttribute *attr; - - preview->layout = gtk_widget_create_pango_layout (widget, - preview->title); - - style_info = meta_theme_get_style_info (preview->theme, NULL); - font_desc = meta_style_info_create_font_desc (preview->theme, style_info); - style = meta_theme_get_frame_style (preview->theme, preview->type, preview->flags); - meta_frame_style_apply_scale (style, font_desc); - - preview->text_height = - meta_pango_font_desc_get_text_height (font_desc, - gtk_widget_get_pango_context (widget)); - - attrs = pango_attr_list_new (); - - attr = pango_attr_size_new (pango_font_description_get_size (font_desc)); - attr->start_index = 0; - attr->end_index = G_MAXINT; - - pango_attr_list_insert (attrs, attr); - - pango_layout_set_attributes (preview->layout, attrs); - - pango_attr_list_unref (attrs); - - pango_font_description_free (font_desc); - } - - if (!preview->borders_cached) - { - if (preview->theme) - meta_theme_get_frame_borders (preview->theme, - NULL, /* theme variant */ - preview->type, - preview->text_height, - preview->flags, - &preview->borders); - else - meta_frame_borders_clear (&preview->borders); - preview->borders_cached = TRUE; - } -} - -static gboolean -meta_preview_draw (GtkWidget *widget, - cairo_t *cr) -{ - MetaPreview *preview; - GtkAllocation allocation; - int border_width; - int client_width; - int client_height; - MetaButtonState button_states[META_BUTTON_TYPE_LAST] = - { - META_BUTTON_STATE_NORMAL, - META_BUTTON_STATE_NORMAL, - META_BUTTON_STATE_NORMAL, - META_BUTTON_STATE_NORMAL - }; - - g_return_val_if_fail (META_IS_PREVIEW (widget), FALSE); - - preview = META_PREVIEW (widget); - - ensure_info (preview); - - cairo_save (cr); - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - gtk_widget_get_allocation (widget, &allocation); - client_width = allocation.width - preview->borders.total.left - preview->borders.total.right - border_width * 2; - client_height = allocation.height - preview->borders.total.top - preview->borders.total.bottom - border_width * 2; - - if (client_width < 0) - client_width = 1; - if (client_height < 0) - client_height = 1; - - if (preview->theme) - { - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - meta_theme_draw_frame (preview->theme, - NULL, /* theme variant... */ - cr, - preview->type, - preview->flags, - client_width, client_height, - preview->layout, - preview->text_height, - &preview->button_layout, - button_states, - meta_preview_get_mini_icon (), - meta_preview_get_icon ()); - } - - cairo_restore (cr); - - /* draw child */ - return GTK_WIDGET_CLASS (meta_preview_parent_class)->draw (widget, cr); -} - -#define NO_CHILD_WIDTH 80 -#define NO_CHILD_HEIGHT 20 - -static void -meta_preview_get_preferred_width (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - MetaPreview *preview; - int border_width; - GtkWidget *child; - - preview = META_PREVIEW (widget); - - ensure_info (preview); - - *minimum = *natural = preview->borders.total.left + preview->borders.total.right; - - child = gtk_bin_get_child (GTK_BIN (preview)); - if (child && gtk_widget_get_visible (child)) - { - gint child_min, child_nat; - - gtk_widget_get_preferred_width (child, &child_min, &child_nat); - - *minimum += child_min; - *natural += child_nat; - } - else - { - *minimum += NO_CHILD_WIDTH; - *natural += NO_CHILD_WIDTH; - } - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - *minimum += border_width * 2; - *natural += border_width * 2; -} - -static void -meta_preview_get_preferred_height (GtkWidget *widget, - gint *minimum, - gint *natural) -{ - MetaPreview *preview; - int border_width; - GtkWidget *child; - - preview = META_PREVIEW (widget); - - ensure_info (preview); - - *minimum = *natural = preview->borders.total.top + preview->borders.total.bottom; - - child = gtk_bin_get_child (GTK_BIN (preview)); - if (child && gtk_widget_get_visible (child)) - { - gint child_min, child_nat; - - gtk_widget_get_preferred_height (child, &child_min, &child_nat); - - *minimum += child_min; - *natural += child_nat; - } - else - { - *minimum += NO_CHILD_HEIGHT; - *natural += NO_CHILD_HEIGHT; - } - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - *minimum += border_width * 2; - *natural += border_width * 2; -} - -static void -meta_preview_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - MetaPreview *preview; - int border_width; - GtkAllocation widget_allocation, child_allocation; - GtkWidget *child; - - preview = META_PREVIEW (widget); - - ensure_info (preview); - - gtk_widget_set_allocation (widget, allocation); - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - child = gtk_bin_get_child (GTK_BIN (widget)); - if (child && - gtk_widget_get_visible (child)) - { - gtk_widget_get_allocation (widget, &widget_allocation); - child_allocation.x = widget_allocation.x + border_width + preview->borders.total.left; - child_allocation.y = widget_allocation.y + border_width + preview->borders.total.top; - - child_allocation.width = MAX (1, widget_allocation.width - border_width * 2 - preview->borders.total.left - preview->borders.total.right); - child_allocation.height = MAX (1, widget_allocation.height - border_width * 2 - preview->borders.total.top - preview->borders.total.bottom); - - gtk_widget_size_allocate (gtk_bin_get_child (GTK_BIN (widget)), &child_allocation); - } -} - -static void -clear_cache (MetaPreview *preview) -{ - if (preview->layout) - { - g_object_unref (G_OBJECT (preview->layout)); - preview->layout = NULL; - } - - preview->borders_cached = FALSE; -} - -void -meta_preview_set_theme (MetaPreview *preview, - MetaTheme *theme) -{ - g_return_if_fail (META_IS_PREVIEW (preview)); - - preview->theme = theme; - - clear_cache (preview); - - gtk_widget_queue_resize (GTK_WIDGET (preview)); -} - -void -meta_preview_set_title (MetaPreview *preview, - const char *title) -{ - g_return_if_fail (META_IS_PREVIEW (preview)); - - g_free (preview->title); - preview->title = g_strdup (title); - - clear_cache (preview); - - gtk_widget_queue_resize (GTK_WIDGET (preview)); -} - -void -meta_preview_set_frame_type (MetaPreview *preview, - MetaFrameType type) -{ - g_return_if_fail (META_IS_PREVIEW (preview)); - - preview->type = type; - - clear_cache (preview); - - gtk_widget_queue_resize (GTK_WIDGET (preview)); -} - -void -meta_preview_set_frame_flags (MetaPreview *preview, - MetaFrameFlags flags) -{ - g_return_if_fail (META_IS_PREVIEW (preview)); - - preview->flags = flags; - - clear_cache (preview); - - gtk_widget_queue_resize (GTK_WIDGET (preview)); -} - -void -meta_preview_set_button_layout (MetaPreview *preview, - const MetaButtonLayout *button_layout) -{ - g_return_if_fail (META_IS_PREVIEW (preview)); - - preview->button_layout = *button_layout; - - gtk_widget_queue_draw (GTK_WIDGET (preview)); -} - -GdkPixbuf* -meta_preview_get_icon (void) -{ - static GdkPixbuf *default_icon = NULL; - - if (default_icon == NULL) - { - GtkIconTheme *theme; - gboolean icon_exists; - - theme = gtk_icon_theme_get_default (); - - icon_exists = gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME); - - if (icon_exists) - default_icon = gtk_icon_theme_load_icon (theme, - META_DEFAULT_ICON_NAME, - META_ICON_WIDTH, - 0, - NULL); - else - default_icon = gtk_icon_theme_load_icon (theme, - "image-missing", - META_ICON_WIDTH, - 0, - NULL); - - g_assert (default_icon); - } - - return default_icon; -} - -GdkPixbuf* -meta_preview_get_mini_icon (void) -{ - static GdkPixbuf *default_icon = NULL; - - if (default_icon == NULL) - { - GtkIconTheme *theme; - gboolean icon_exists; - - theme = gtk_icon_theme_get_default (); - - icon_exists = gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME); - - if (icon_exists) - default_icon = gtk_icon_theme_load_icon (theme, - META_DEFAULT_ICON_NAME, - META_MINI_ICON_WIDTH, - 0, - NULL); - else - default_icon = gtk_icon_theme_load_icon (theme, - "image-missing", - META_MINI_ICON_WIDTH, - 0, - NULL); - - g_assert (default_icon); - } - - return default_icon; -} diff --git a/src/ui/preview-widget.h b/src/ui/preview-widget.h deleted file mode 100644 index c81aee76..00000000 --- a/src/ui/preview-widget.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity theme preview widget */ - -/* - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <gtk/gtk.h> -#include <libmetacity/meta-theme.h> - -#ifndef META_PREVIEW_WIDGET_H -#define META_PREVIEW_WIDGET_H - -#define META_TYPE_PREVIEW (meta_preview_get_type ()) -#define META_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_PREVIEW, MetaPreview)) -#define META_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_PREVIEW, MetaPreviewClass)) -#define META_IS_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_PREVIEW)) -#define META_IS_PREVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_PREVIEW)) -#define META_PREVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_PREVIEW, MetaPreviewClass)) - -typedef struct _MetaPreview MetaPreview; -typedef struct _MetaPreviewClass MetaPreviewClass; - -struct _MetaPreview -{ - GtkBin bin; - - MetaTheme *theme; - char *title; - MetaFrameType type; - MetaFrameFlags flags; - - PangoLayout *layout; - int text_height; - - MetaFrameBorders borders; - guint borders_cached : 1; - - MetaButtonLayout button_layout; -}; - -struct _MetaPreviewClass -{ - GtkBinClass parent_class; -}; - - -GType meta_preview_get_type (void) G_GNUC_CONST; -GtkWidget* meta_preview_new (void); - -void meta_preview_set_theme (MetaPreview *preview, - MetaTheme *theme); -void meta_preview_set_title (MetaPreview *preview, - const char *title); -void meta_preview_set_frame_type (MetaPreview *preview, - MetaFrameType type); -void meta_preview_set_frame_flags (MetaPreview *preview, - MetaFrameFlags flags); -void meta_preview_set_button_layout (MetaPreview *preview, - const MetaButtonLayout *button_layout); - -GdkPixbuf* meta_preview_get_icon (void); -GdkPixbuf* meta_preview_get_mini_icon (void); - -#endif diff --git a/src/ui/theme-viewer.c b/src/ui/theme-viewer.c deleted file mode 100644 index 8db9aef5..00000000 --- a/src/ui/theme-viewer.c +++ /dev/null @@ -1,1121 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity theme viewer and test app main() */ - -/* - * 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 <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include "util.h" -#include "preview-widget.h" -#include <gtk/gtk.h> -#include <time.h> -#include <stdlib.h> -#include <string.h> - -#include <libintl.h> -#define _(x) dgettext (GETTEXT_PACKAGE, x) -#define N_(x) x - -/* We need to compute all different button arrangements - * in terms of button location. We don't care about - * different arrangements in terms of button function. - * - * So if dups are allowed, from 0-4 buttons on the left, from 0-4 on - * the right, 5x5=25 combinations. - * - * If no dups, 0-4 on left determines the number on the right plus - * we have a special case for the "no buttons on either side" case. - */ -#ifndef ALLOW_DUPLICATE_BUTTONS -#define BUTTON_LAYOUT_COMBINATIONS (META_BUTTON_FUNCTION_LAST + 1 + 1) -#else -#define BUTTON_LAYOUT_COMBINATIONS ((META_BUTTON_FUNCTION_LAST+1)*(META_BUTTON_FUNCTION_LAST+1)) -#endif - -enum -{ - FONT_SIZE_SMALL, - FONT_SIZE_NORMAL, - FONT_SIZE_LARGE, - FONT_SIZE_LAST -}; - -static MetaTheme *global_theme = NULL; -static GtkWidget *previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + BUTTON_LAYOUT_COMBINATIONS] = { NULL, }; -static double milliseconds_to_draw_frame = 0.0; - -static void run_theme_benchmark (void); - -static const gchar *xml = - "<interface>" - "<menu id='menubar'>" - "<submenu>" - "<attribute name='label'>Windows</attribute>" - "<section>" - "<item>" - "<attribute name='label'>Dialog</attribute>" - "<attribute name='action'>theme-viewer.dialog1</attribute>" - "<attribute name='accel'><control>d</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Modal dialog</attribute>" - "<attribute name='action'>theme-viewer.dialog2</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Utility</attribute>" - "<attribute name='action'>theme-viewer.utility</attribute>" - "<attribute name='accel'><control>u</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Splashscreen</attribute>" - "<attribute name='action'>theme-viewer.splashscreen</attribute>" - "<attribute name='accel'><control>s</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Top dock</attribute>" - "<attribute name='action'>theme-viewer.top-dock</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Bottom dock</attribute>" - "<attribute name='action'>theme-viewer.bottom-dock</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Left dock</attribute>" - "<attribute name='action'>theme-viewer.left-dock</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Right dock</attribute>" - "<attribute name='action'>theme-viewer.right-dock</attribute>" - "</item>" - "<item>" - "<attribute name='label'>All docks</attribute>" - "<attribute name='action'>theme-viewer.all-docks</attribute>" - "</item>" - "<item>" - "<attribute name='label'>Desktop</attribute>" - "<attribute name='action'>theme-viewer.desktop</attribute>" - "</item>" - "</section>" - "</submenu>" - "</menu>" - "</interface>"; - -static GActionEntry theme_viewer_entries[] = -{ - /* menubar */ - { "dialog1", NULL, NULL, NULL, NULL, {} }, - { "dialog2", NULL, NULL, NULL, NULL, {} }, - { "utility", NULL, NULL, NULL, NULL, {} }, - { "splashscreen", NULL, NULL, NULL, NULL, {} }, - { "top-dock", NULL, NULL, NULL, NULL, {} }, - { "bottom-dock", NULL, NULL, NULL, NULL, {} }, - { "left-dock", NULL, NULL, NULL, NULL, {} }, - { "right-dock", NULL, NULL, NULL, NULL, {} }, - { "all-docks", NULL, NULL, NULL, NULL, {} }, - { "desktop", NULL, NULL, NULL, NULL, {} }, - /* toolbar */ - { "new", NULL, NULL, NULL, NULL, {} }, - { "open", NULL, NULL, NULL, NULL, {} }, - { "quit", NULL, NULL, NULL, NULL, {} } -}; - -static GtkWidget * -create_toolbar (void) -{ - GtkWidget *toolbar; - GtkToolItem *item; - - toolbar = gtk_toolbar_new (); - - item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-new", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL); - gtk_tool_item_set_tooltip_markup (item, "Open another one of these windows"); - gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "theme-viewer.new"); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1); - - item = gtk_tool_button_new (gtk_image_new_from_icon_name ("document-open", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL); - gtk_tool_item_set_tooltip_markup (item, "This is a demo button with an 'open' icon"); - gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "theme-viewer.open"); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1); - - item = gtk_tool_button_new (gtk_image_new_from_icon_name ("application-exit", GTK_ICON_SIZE_SMALL_TOOLBAR), NULL); - gtk_tool_item_set_tooltip_markup (item, "This is a demo button with a 'quit' icon"); - gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "theme-viewer.quit"); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1); - - return toolbar; -} - -static GtkWidget * -normal_contents (void) -{ - GtkWidget *grid; - GtkWidget *statusbar; - GtkWidget *contents; - GtkWidget *sw; - GtkBuilder *builder; - GMenuModel *model; - GtkWidget *menubar; - GtkWidget *toolbar; - - grid = gtk_grid_new (); - builder = gtk_builder_new_from_string (xml, -1); - - /* create menu items */ - model = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")); - menubar = gtk_menu_bar_new_from_model (model); - gtk_grid_attach (GTK_GRID (grid), menubar, 0, 0, 1, 1); - gtk_widget_set_hexpand (menubar, TRUE); - - /* Create the toolbar */ - toolbar = create_toolbar (); - gtk_grid_attach (GTK_GRID (grid), toolbar, 0, 1, 1, 1); - gtk_widget_set_hexpand (toolbar, TRUE); - - /* Create document - */ - - sw = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), - GTK_SHADOW_IN); - - gtk_grid_attach (GTK_GRID (grid), sw, 0, 2, 1, 1); - - gtk_widget_set_hexpand (sw, TRUE); - gtk_widget_set_vexpand (sw, TRUE); - - contents = gtk_text_view_new (); - gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (contents), - PANGO_WRAP_WORD); - - gtk_container_add (GTK_CONTAINER (sw), - contents); - - /* Create statusbar */ - - statusbar = gtk_statusbar_new (); - gtk_grid_attach (GTK_GRID (grid), statusbar, 0, 3, 1, 1); - gtk_widget_set_hexpand (statusbar, TRUE); - - gtk_widget_show_all (grid); - - g_object_unref (builder); - - return grid; -} - -static void -update_spacings (GtkWidget *vbox, - GtkWidget *action_area) -{ - gtk_container_set_border_width (GTK_CONTAINER (vbox), 2); - gtk_box_set_spacing (GTK_BOX (action_area), 10); - gtk_container_set_border_width (GTK_CONTAINER (action_area), 5); -} - -static GtkWidget* -dialog_contents (void) -{ - GtkWidget *vbox; - GtkWidget *hbox; - GtkWidget *action_area; - GtkWidget *label; - GtkWidget *image; - GtkWidget *button; - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - - action_area = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); - - gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), - GTK_BUTTONBOX_END); - - button = gtk_button_new_with_label (_("OK")); - gtk_box_pack_end (GTK_BOX (action_area), - button, - FALSE, TRUE, 0); - - gtk_box_pack_end (GTK_BOX (vbox), action_area, - FALSE, TRUE, 0); - - update_spacings (vbox, action_area); - - label = gtk_label_new (_("This is a sample message in a sample dialog")); - image = gtk_image_new_from_icon_name ("dialog-information", GTK_ICON_SIZE_DIALOG); - gtk_widget_set_halign (image, GTK_ALIGN_CENTER); - gtk_widget_set_valign (image, GTK_ALIGN_START); - - gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); - gtk_label_set_selectable (GTK_LABEL (label), TRUE); - - hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - - gtk_box_pack_start (GTK_BOX (hbox), image, - FALSE, FALSE, 0); - - gtk_box_pack_start (GTK_BOX (hbox), label, - TRUE, TRUE, 0); - - gtk_box_pack_start (GTK_BOX (vbox), - hbox, - FALSE, FALSE, 0); - - gtk_widget_show_all (vbox); - - return vbox; -} - -static GtkWidget* -utility_contents (void) -{ - GtkWidget *grid; - GtkWidget *button; - int i, j; - - grid = gtk_grid_new (); - - i = 0; - while (i < 3) - { - j = 0; - while (j < 4) - { - char *str; - - str = g_strdup_printf ("_%c", (char) ('A' + 4*i + j)); - - button = gtk_button_new_with_mnemonic (str); - - g_free (str); - - gtk_grid_attach (GTK_GRID (grid), button, i, j, 1, 1); - - ++j; - } - - ++i; - } - - gtk_widget_show_all (grid); - - return grid; -} - -static GtkWidget* -menu_contents (void) -{ - GtkWidget *vbox; - GtkWidget *mi; - int i; - GtkWidget *frame; - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME (frame), - GTK_SHADOW_OUT); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - - i = 0; - while (i < 10) - { - char *str = g_strdup_printf (_("Fake menu item %d\n"), i + 1); - mi = gtk_label_new (str); - gtk_widget_set_halign (mi, GTK_ALIGN_START); - gtk_widget_set_valign (mi, GTK_ALIGN_CENTER); - g_free (str); - gtk_box_pack_start (GTK_BOX (vbox), mi, FALSE, FALSE, 0); - - ++i; - } - - gtk_container_add (GTK_CONTAINER (frame), vbox); - - gtk_widget_show_all (frame); - - return frame; -} - -static void -override_background_color (GtkWidget *widget, - GdkRGBA *rgba) -{ - gchar *css; - GtkCssProvider *provider; - - provider = gtk_css_provider_new (); - - css = g_strdup_printf ("* { background-color: %s; }", - gdk_rgba_to_string (rgba)); - gtk_css_provider_load_from_data (provider, css, -1, NULL); - g_free (css); - - gtk_style_context_add_provider (gtk_widget_get_style_context (widget), - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - g_object_unref (provider); -} - -static GtkWidget* -border_only_contents (void) -{ - GtkWidget *event_box; - GtkWidget *vbox; - GtkWidget *w; - GdkRGBA color; - - event_box = gtk_event_box_new (); - - color.red = 0.6; - color.green = 0; - color.blue = 0.6; - color.alpha = 1.0; - override_background_color (event_box, &color); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 3); - - w = gtk_label_new (_("Border-only window")); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); - w = gtk_button_new_with_label (_("Bar")); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); - - gtk_container_add (GTK_CONTAINER (event_box), vbox); - - gtk_widget_show_all (event_box); - - return event_box; -} - -static GtkWidget* -get_window_contents (MetaFrameType type, - const char **title) -{ - switch (type) - { - case META_FRAME_TYPE_NORMAL: - *title = _("Normal Application Window"); - return normal_contents (); - - case META_FRAME_TYPE_DIALOG: - *title = _("Dialog Box"); - return dialog_contents (); - - case META_FRAME_TYPE_MODAL_DIALOG: - *title = _("Modal Dialog Box"); - return dialog_contents (); - - case META_FRAME_TYPE_UTILITY: - *title = _("Utility Palette"); - return utility_contents (); - - case META_FRAME_TYPE_MENU: - *title = _("Torn-off Menu"); - return menu_contents (); - - case META_FRAME_TYPE_BORDER: - *title = _("Border"); - return border_only_contents (); - - case META_FRAME_TYPE_ATTACHED: - *title = _("Attached Modal Dialog"); - return dialog_contents (); - - case META_FRAME_TYPE_LAST: - g_assert_not_reached (); - break; - - default: - g_assert_not_reached (); - break; - } - - return NULL; -} - -static MetaFrameFlags -get_window_flags (MetaFrameType type) -{ - MetaFrameFlags flags; - - flags = META_FRAME_ALLOWS_DELETE | - META_FRAME_ALLOWS_MENU | - META_FRAME_ALLOWS_MINIMIZE | - META_FRAME_ALLOWS_MAXIMIZE | - META_FRAME_ALLOWS_VERTICAL_RESIZE | - META_FRAME_ALLOWS_HORIZONTAL_RESIZE | - META_FRAME_HAS_FOCUS | - META_FRAME_ALLOWS_SHADE | - META_FRAME_ALLOWS_MOVE; - - switch (type) - { - case META_FRAME_TYPE_NORMAL: - break; - - case META_FRAME_TYPE_DIALOG: - case META_FRAME_TYPE_MODAL_DIALOG: - flags &= ~(META_FRAME_ALLOWS_MINIMIZE | - META_FRAME_ALLOWS_MAXIMIZE); - break; - - case META_FRAME_TYPE_UTILITY: - flags &= ~(META_FRAME_ALLOWS_MINIMIZE | - META_FRAME_ALLOWS_MAXIMIZE); - break; - - case META_FRAME_TYPE_MENU: - flags &= ~(META_FRAME_ALLOWS_MINIMIZE | - META_FRAME_ALLOWS_MAXIMIZE); - break; - - case META_FRAME_TYPE_BORDER: - break; - - case META_FRAME_TYPE_ATTACHED: - break; - - case META_FRAME_TYPE_LAST: - g_assert_not_reached (); - break; - - default: - g_assert_not_reached (); - break; - } - - return flags; -} - -static void -override_font (GtkWidget *widget, - const gchar *font) -{ - gchar *css; - GtkCssProvider *provider; - - provider = gtk_css_provider_new (); - - css = g_strdup_printf ("* { font: %s; }", font); - gtk_css_provider_load_from_data (provider, css, -1, NULL); - g_free (css); - - gtk_style_context_add_provider (gtk_widget_get_style_context (widget), - GTK_STYLE_PROVIDER (provider), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - g_object_unref (provider); -} - -static GtkWidget* -preview_collection (int font_size, - const PangoFontDescription *base_desc) -{ - GtkWidget *box; - GtkWidget *sw; - GdkRGBA desktop_color; - int i; - GtkWidget *eventbox; - GSimpleActionGroup *action_group; - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_box_set_spacing (GTK_BOX (box), 20); - gtk_container_set_border_width (GTK_CONTAINER (box), 20); - - eventbox = gtk_event_box_new (); - gtk_container_add (GTK_CONTAINER (eventbox), box); - - gtk_container_add (GTK_CONTAINER (sw), eventbox); - - action_group = g_simple_action_group_new (); - g_action_map_add_action_entries (G_ACTION_MAP (action_group), - theme_viewer_entries, - G_N_ELEMENTS (theme_viewer_entries), - NULL); - gtk_widget_insert_action_group (sw, "theme-viewer", G_ACTION_GROUP (action_group)); - g_object_unref (action_group); - - desktop_color.red = 0.32; - desktop_color.green = 0.46; - desktop_color.blue = 0.65; - desktop_color.alpha = 1.0; - - override_background_color (eventbox, &desktop_color); - - i = 0; - while (i < META_FRAME_TYPE_LAST) - { - const char *title = NULL; - GtkWidget *contents; - GtkAlign xalign, yalign; - GtkWidget *eventbox2; - GtkWidget *preview; - PangoFontDescription *font_desc; - gchar *font_string; - double scale; - - eventbox2 = gtk_event_box_new (); - - preview = meta_preview_new (); - - gtk_container_add (GTK_CONTAINER (eventbox2), preview); - - meta_preview_set_frame_type (META_PREVIEW (preview), i); - meta_preview_set_frame_flags (META_PREVIEW (preview), - get_window_flags (i)); - - meta_preview_set_theme (META_PREVIEW (preview), global_theme); - - contents = get_window_contents (i, &title); - - meta_preview_set_title (META_PREVIEW (preview), title); - - gtk_container_add (GTK_CONTAINER (preview), contents); - - if (i == META_FRAME_TYPE_MENU) - { - xalign = GTK_ALIGN_START; - yalign = GTK_ALIGN_START; - } - else - { - xalign = GTK_ALIGN_FILL; - yalign = GTK_ALIGN_FILL; - } - - gtk_widget_set_halign (eventbox2, xalign); - gtk_widget_set_valign (eventbox2, yalign); - - gtk_box_pack_start (GTK_BOX (box), eventbox2, TRUE, TRUE, 0); - - switch (font_size) - { - case FONT_SIZE_SMALL: - scale = PANGO_SCALE_XX_SMALL; - break; - case FONT_SIZE_LARGE: - scale = PANGO_SCALE_XX_LARGE; - break; - default: - scale = 1.0; - break; - } - - if (scale != 1.0) - { - font_desc = pango_font_description_new (); - - pango_font_description_set_size (font_desc, - MAX (pango_font_description_get_size (base_desc) * scale, 1)); - - font_string = pango_font_description_to_string (font_desc); - override_font (preview, font_string); - g_free (font_string); - - pango_font_description_free (font_desc); - } - - previews[font_size*META_FRAME_TYPE_LAST + i] = preview; - - ++i; - } - - return sw; -} - -static MetaButtonLayout different_layouts[BUTTON_LAYOUT_COMBINATIONS]; - -static void -init_layouts (void) -{ - int i; - - /* Blank out all the layouts */ - i = 0; - while (i < (int) G_N_ELEMENTS (different_layouts)) - { - int j; - - j = 0; - while (j < META_BUTTON_FUNCTION_LAST) - { - different_layouts[i].left_buttons[j] = META_BUTTON_FUNCTION_LAST; - different_layouts[i].right_buttons[j] = META_BUTTON_FUNCTION_LAST; - ++j; - } - ++i; - } - -#ifndef ALLOW_DUPLICATE_BUTTONS - i = 0; - while (i <= META_BUTTON_FUNCTION_LAST) - { - int j; - - j = 0; - while (j < i) - { - different_layouts[i].right_buttons[j] = (MetaButtonFunction) j; - ++j; - } - while (j < META_BUTTON_FUNCTION_LAST) - { - different_layouts[i].left_buttons[j-i] = (MetaButtonFunction) j; - ++j; - } - - ++i; - } - - /* Special extra case for no buttons on either side */ - different_layouts[i].left_buttons[0] = META_BUTTON_FUNCTION_LAST; - different_layouts[i].right_buttons[0] = META_BUTTON_FUNCTION_LAST; - -#else - /* FIXME this code is if we allow duplicate buttons, - * which we currently do not - */ - int left; - int i; - - left = 0; - i = 0; - - while (left < META_BUTTON_FUNCTION_LAST) - { - int right; - - right = 0; - - while (right < META_BUTTON_FUNCTION_LAST) - { - int j; - - static MetaButtonFunction left_functions[META_BUTTON_FUNCTION_LAST] = { - META_BUTTON_FUNCTION_MENU, - META_BUTTON_FUNCTION_MINIMIZE, - META_BUTTON_FUNCTION_MAXIMIZE, - META_BUTTON_FUNCTION_CLOSE - }; - static MetaButtonFunction right_functions[META_BUTTON_FUNCTION_LAST] = { - META_BUTTON_FUNCTION_MINIMIZE, - META_BUTTON_FUNCTION_MAXIMIZE, - META_BUTTON_FUNCTION_CLOSE, - META_BUTTON_FUNCTION_MENU - }; - - g_assert (i < BUTTON_LAYOUT_COMBINATIONS); - - j = 0; - while (j <= left) - { - different_layouts[i].left_buttons[j] = left_functions[j]; - ++j; - } - - j = 0; - while (j <= right) - { - different_layouts[i].right_buttons[j] = right_functions[j]; - ++j; - } - - ++i; - - ++right; - } - - ++left; - } -#endif -} - - -static GtkWidget* -previews_of_button_layouts (void) -{ - static gboolean initted = FALSE; - GtkWidget *box; - GtkWidget *sw; - GdkRGBA desktop_color; - int i; - GtkWidget *eventbox; - - if (!initted) - { - init_layouts (); - initted = TRUE; - } - - sw = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_box_set_spacing (GTK_BOX (box), 20); - gtk_container_set_border_width (GTK_CONTAINER (box), 20); - - eventbox = gtk_event_box_new (); - gtk_container_add (GTK_CONTAINER (eventbox), box); - - gtk_container_add (GTK_CONTAINER (sw), eventbox); - - desktop_color.red = 0.32; - desktop_color.green = 0.46; - desktop_color.blue = 0.65; - desktop_color.alpha = 1.0; - - override_background_color (eventbox, &desktop_color); - - i = 0; - while (i < BUTTON_LAYOUT_COMBINATIONS) - { - GtkWidget *eventbox2; - GtkWidget *preview; - char *title; - - eventbox2 = gtk_event_box_new (); - - preview = meta_preview_new (); - - gtk_container_add (GTK_CONTAINER (eventbox2), preview); - - meta_preview_set_theme (META_PREVIEW (preview), global_theme); - - title = g_strdup_printf (_("Button layout test %d"), i+1); - meta_preview_set_title (META_PREVIEW (preview), title); - g_free (title); - - meta_preview_set_button_layout (META_PREVIEW (preview), - &different_layouts[i]); - - gtk_widget_set_halign (eventbox2, GTK_ALIGN_FILL); - - gtk_box_pack_start (GTK_BOX (box), eventbox2, TRUE, TRUE, 0); - - previews[META_FRAME_TYPE_LAST*FONT_SIZE_LAST + i] = preview; - - ++i; - } - - return sw; -} - -static GtkWidget* -benchmark_summary (void) -{ - char *msg; - GtkWidget *label; - - msg = g_strdup_printf (_("%g milliseconds to draw one window frame"), - milliseconds_to_draw_frame); - label = gtk_label_new (msg); - g_free (msg); - - return label; -} - -int -main (int argc, char **argv) -{ - gboolean loaded; - GtkWidget *window; - GtkWidget *collection; - MetaStyleInfo *style_info; - PangoFontDescription *font_desc; - GError *err; - clock_t start, end; - GtkWidget *notebook; - int i; - gchar *theme_name; - - bindtextdomain (GETTEXT_PACKAGE, METACITY_LOCALEDIR); - textdomain(GETTEXT_PACKAGE); - bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); - - gtk_init (&argc, &argv); - - if (g_getenv ("METACITY_DEBUG") != NULL) - { - meta_set_debugging (TRUE); - meta_set_verbose (TRUE); - } - - start = clock (); - global_theme = meta_theme_new (META_THEME_TYPE_METACITY); - - err = NULL; - loaded = FALSE; - - if (argc == 1) - loaded = meta_theme_load (global_theme, "Atlanta", &err); - else if (argc == 2) - loaded = meta_theme_load (global_theme, argv[1], &err); - else - { - g_printerr (_("Usage: metacity-theme-viewer [THEMENAME]\n")); - - g_object_unref (global_theme); - exit (1); - } - - end = clock (); - - if (loaded == FALSE) - { - g_printerr (_("Error loading theme: %s\n"), err->message); - g_error_free (err); - - g_object_unref (global_theme); - exit (1); - } - - theme_name = meta_theme_get_name (global_theme); - - g_print (_("Loaded theme '%s' in %g seconds\n"), theme_name, - (end - start) / (double) CLOCKS_PER_SEC); - - run_theme_benchmark (); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size (GTK_WINDOW (window), 350, 350); - - gtk_window_set_title (GTK_WINDOW (window), theme_name); - g_free (theme_name); - - g_signal_connect (G_OBJECT (window), "destroy", - G_CALLBACK (gtk_main_quit), NULL); - - gtk_widget_realize (window); - - style_info = meta_theme_get_style_info (global_theme, NULL); - font_desc = meta_style_info_create_font_desc (global_theme, style_info); - g_assert (font_desc); - - notebook = gtk_notebook_new (); - gtk_container_add (GTK_CONTAINER (window), notebook); - - collection = preview_collection (FONT_SIZE_NORMAL, - font_desc); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), - collection, - gtk_label_new (_("Normal Title Font"))); - - collection = preview_collection (FONT_SIZE_SMALL, - font_desc); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), - collection, - gtk_label_new (_("Small Title Font"))); - - collection = preview_collection (FONT_SIZE_LARGE, - font_desc); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), - collection, - gtk_label_new (_("Large Title Font"))); - - collection = previews_of_button_layouts (); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), - collection, - gtk_label_new (_("Button Layouts"))); - - collection = benchmark_summary (); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), - collection, - gtk_label_new (_("Benchmark"))); - - pango_font_description_free (font_desc); - - i = 0; - while (i < (int) G_N_ELEMENTS (previews)) - { - /* preview widget likes to be realized before its size request. - * it's lame that way. - */ - gtk_widget_realize (previews[i]); - - ++i; - } - - gtk_widget_show_all (window); - - gtk_main (); - - return 0; -} - - -static MetaFrameFlags -get_flags (GtkWidget *widget) -{ - return META_FRAME_ALLOWS_DELETE | - META_FRAME_ALLOWS_MENU | - META_FRAME_ALLOWS_MINIMIZE | - META_FRAME_ALLOWS_MAXIMIZE | - META_FRAME_ALLOWS_VERTICAL_RESIZE | - META_FRAME_ALLOWS_HORIZONTAL_RESIZE | - META_FRAME_HAS_FOCUS | - META_FRAME_ALLOWS_SHADE | - META_FRAME_ALLOWS_MOVE; -} - -static int -get_text_height (GtkWidget *widget, - MetaStyleInfo *style_info) -{ - PangoFontDescription *font_desc; - int text_height; - - font_desc = meta_style_info_create_font_desc (global_theme, style_info); - text_height = meta_pango_font_desc_get_text_height (font_desc, gtk_widget_get_pango_context (widget)); - pango_font_description_free (font_desc); - - return text_height; -} - -static PangoLayout* -create_title_layout (GtkWidget *widget) -{ - PangoLayout *layout; - - layout = gtk_widget_create_pango_layout (widget, _("Window Title Goes Here")); - - return layout; -} - -static void -run_theme_benchmark (void) -{ - GtkWidget* widget; - MetaStyleInfo *style_info; - cairo_surface_t *pixmap; - MetaFrameBorders borders; - MetaButtonState button_states[META_BUTTON_TYPE_LAST] = - { - META_BUTTON_STATE_NORMAL, - META_BUTTON_STATE_NORMAL, - META_BUTTON_STATE_NORMAL, - META_BUTTON_STATE_NORMAL - }; - PangoLayout *layout; - clock_t start; - clock_t end; - GTimer *timer; - int i; - MetaButtonLayout button_layout; -#define ITERATIONS 100 - int client_width; - int client_height; - cairo_t *cr; - int inc; - - widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_widget_realize (widget); - - style_info = meta_theme_get_style_info (global_theme, NULL); - - meta_theme_get_frame_borders (global_theme, - NULL, - META_FRAME_TYPE_NORMAL, - get_text_height (widget, style_info), - get_flags (widget), - &borders); - - layout = create_title_layout (widget); - - i = 0; - while (i < META_BUTTON_FUNCTION_LAST) - { - button_layout.left_buttons[i] = META_BUTTON_FUNCTION_LAST; - button_layout.right_buttons[i] = META_BUTTON_FUNCTION_LAST; - ++i; - } - - button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU; - - button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE; - button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE; - button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE; - - timer = g_timer_new (); - start = clock (); - - client_width = 50; - client_height = 50; - inc = 1000 / ITERATIONS; /* Increment to grow width/height, - * eliminates caching effects. - */ - - i = 0; - while (i < ITERATIONS) - { - /* Creating the pixmap in the loop is right, since - * GDK does the same with its double buffering. - */ - pixmap = gdk_window_create_similar_surface (gtk_widget_get_window (widget), - CAIRO_CONTENT_COLOR, - client_width + borders.total.left + borders.total.right, - client_height + borders.total.top + borders.total.bottom); - cr = cairo_create (pixmap); - - meta_theme_draw_frame (global_theme, - NULL, /* theme variant */ - cr, - META_FRAME_TYPE_NORMAL, - get_flags (widget), - client_width, client_height, - layout, - get_text_height (widget, style_info), - &button_layout, - button_states, - meta_preview_get_mini_icon (), - meta_preview_get_icon ()); - - cairo_destroy (cr); - cairo_surface_destroy (pixmap); - - ++i; - client_width += inc; - client_height += inc; - } - - end = clock (); - g_timer_stop (timer); - - milliseconds_to_draw_frame = (g_timer_elapsed (timer, NULL) / (double) ITERATIONS) * 1000; - - g_print (_("Drew %d frames in %g client-side seconds (%g milliseconds per frame) and %g seconds wall clock time including X server resources (%g milliseconds per frame)\n"), - ITERATIONS, - ((double)end - (double)start) / CLOCKS_PER_SEC, - (((double)end - (double)start) / CLOCKS_PER_SEC / (double) ITERATIONS) * 1000, - g_timer_elapsed (timer, NULL), - milliseconds_to_draw_frame); - - g_timer_destroy (timer); - g_object_unref (G_OBJECT (layout)); - gtk_widget_destroy (widget); - -#undef ITERATIONS -} diff --git a/theme-viewer/Makefile.am b/theme-viewer/Makefile.am new file mode 100644 index 00000000..cc1975dc --- /dev/null +++ b/theme-viewer/Makefile.am @@ -0,0 +1,54 @@ +NULL = + +bin_PROGRAMS = metacity-theme-viewer + +metacity_theme_viewer_SOURCES = \ + theme-viewer-main.c \ + theme-viewer-window.c \ + theme-viewer-window.h \ + $(BUILT_SOURCES) \ + $(NULL) + +metacity_theme_viewer_CPPFLAGS = \ + -DDATADIR=\""$(datadir)"\" \ + -DLOCALEDIR=\""$(localedir)"\" \ + -I$(top_srcdir) \ + $(AM_CPPFLAGS) \ + $(NULL) + +metacity_theme_viewer_CFLAGS = \ + $(METACITY_THEME_VIEWER_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) \ + $(NULL) + +metacity_theme_viewer_LDFLAGS = \ + $(WARN_LDFLAGS) \ + $(AM_LDFLAGS) \ + $(NULL) + +metacity_theme_viewer_LDADD = \ + $(top_builddir)/libmetacity/libmetacity.la \ + $(METACITY_THEME_VIEWER_LIBS) \ + $(NULL) + +theme-viewer-resources.c: theme-viewer.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/theme-viewer.gresource.xml) + $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate --c-name theme_viewer $< + +theme-viewer-resources.h: theme-viewer.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/theme-viewer.gresource.xml) + $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate --c-name theme_viewer $< + +BUILT_SOURCES = \ + theme-viewer-resources.c \ + theme-viewer-resources.h \ + $(NULL) + +EXTRA_DIST = \ + theme-viewer.gresource.xml \ + $(NULL) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/theme-viewer/theme-viewer-main.c b/theme-viewer/theme-viewer-main.c new file mode 100644 index 00000000..08b55f84 --- /dev/null +++ b/theme-viewer/theme-viewer-main.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Alberts Muktupāvels + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <glib/gi18n.h> + +#include "theme-viewer-window.h" + +static void +destroy_cb (GtkWidget *widget) +{ + gtk_main_quit (); +} + +int +main (int argc, char **argv) +{ + GtkWidget *window; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); + + gtk_init (&argc, &argv); + + window = theme_viewer_window_new (); + gtk_window_present (GTK_WINDOW (window)); + + g_signal_connect (window, "destroy", G_CALLBACK (destroy_cb), NULL); + + gtk_main (); + + return 0; +} diff --git a/theme-viewer/theme-viewer-window.c b/theme-viewer/theme-viewer-window.c new file mode 100644 index 00000000..16a0fbe0 --- /dev/null +++ b/theme-viewer/theme-viewer-window.c @@ -0,0 +1,754 @@ +/* + * Copyright (C) 2016 Alberts Muktupāvels + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <glib/gi18n.h> +#include <libmetacity/meta-theme.h> + +#include "theme-viewer-window.h" + +#define PADDING 60 +#define MINI_ICON_SIZE 16 +#define ICON_SIZE 96 + +struct _ThemeViewerWindow +{ + GtkWindow parent; + + GtkWidget *header_bar; + GtkWidget *type_combo_box; + GtkWidget *theme_combo_box; + GtkWidget *reload_button; + + GtkWidget *choose_theme; + GtkWidget *theme_box; + + GtkWidget *has_focus; + GtkWidget *shaded; + GtkWidget *maximized; + GtkWidget *fullscreen; + GtkWidget *tiled; + + GtkWidget *button_layout_entry; + + MetaTheme *theme; + + const gchar *theme_variant; + gboolean composited; + + MetaFrameType frame_type; + MetaFrameFlags frame_flags; + + PangoLayout *title_layout; + gint title_height; + + MetaFrameBorders borders; + + MetaButtonLayout button_layout; + MetaButtonState button_states[META_BUTTON_TYPE_LAST]; + + gboolean button_pressed; + + GdkPixbuf *mini_icon; + GdkPixbuf *icon; +}; + +G_DEFINE_TYPE (ThemeViewerWindow, theme_viewer_window, GTK_TYPE_WINDOW) + +static GdkPixbuf * +get_icon (gint size) +{ + GtkIconTheme *theme; + const gchar *icon; + + theme = gtk_icon_theme_get_default (); + + if (gtk_icon_theme_has_icon (theme, "start-here-symbolic")) + icon = "start-here-symbolic"; + else + icon = "image-missing"; + + return gtk_icon_theme_load_icon (theme, icon, size, 0, NULL);; +} + +static gboolean +point_in_rect (gint x, + gint y, + GdkRectangle rect) +{ + if (x >= rect.x && x < (rect.x + rect.width) && + y >= rect.y && y < (rect.y + rect.height)) + return TRUE; + + return FALSE; +} + +static void +get_client_width_and_height (GtkWidget *widget, + ThemeViewerWindow *window, + gint *width, + gint *height) +{ + *width = gtk_widget_get_allocated_width (widget) - PADDING * 2; + *height = gtk_widget_get_allocated_height (widget) - PADDING * 2; + + *width -= window->borders.total.left + window->borders.total.right; + *height -= window->borders.total.top + window->borders.total.bottom; +} + +static void +update_button_state (GtkWidget *widget, + GdkDevice *device, + ThemeViewerWindow *window) +{ + gint x; + gint y; + gint width; + gint height; + MetaFrameGeometry fgeom; + MetaButtonType type; + guint i; + + gdk_window_get_device_position (gtk_widget_get_window (widget), + device, &x, &y, NULL); + + get_client_width_and_height (widget, window, &width, &height); + + meta_theme_calc_geometry (window->theme, window->theme_variant, + window->frame_type, window->title_height, + window->frame_flags, width, height, + &window->button_layout, &fgeom); + + x -= PADDING; + y -= PADDING; + + if (point_in_rect (x, y, fgeom.menu_rect.clickable)) + type = META_BUTTON_TYPE_MENU; + + if (point_in_rect (x, y, fgeom.appmenu_rect.clickable)) + type = META_BUTTON_TYPE_APPMENU; + + if (point_in_rect (x, y, fgeom.min_rect.clickable)) + type = META_BUTTON_TYPE_MINIMIZE; + + if (point_in_rect (x, y, fgeom.max_rect.clickable)) + type = META_BUTTON_TYPE_MAXIMIZE; + + if (point_in_rect (x, y, fgeom.close_rect.clickable)) + type = META_BUTTON_TYPE_CLOSE; + + if (point_in_rect (x, y, fgeom.shade_rect.clickable)) + type = META_BUTTON_TYPE_SHADE; + + if (point_in_rect (x, y, fgeom.unshade_rect.clickable)) + type = META_BUTTON_TYPE_UNSHADE; + + if (point_in_rect (x, y, fgeom.above_rect.clickable)) + type = META_BUTTON_TYPE_ABOVE; + + if (point_in_rect (x, y, fgeom.unabove_rect.clickable)) + type = META_BUTTON_TYPE_UNABOVE; + + if (point_in_rect (x, y, fgeom.stick_rect.clickable)) + type = META_BUTTON_TYPE_STICK; + + if (point_in_rect (x, y, fgeom.unstick_rect.clickable)) + type = META_BUTTON_TYPE_UNSTICK; + + for (i = 0; i < META_BUTTON_TYPE_LAST; i++) + { + if (i == type) + { + if (window->button_pressed) + window->button_states[i] = META_BUTTON_STATE_PRESSED; + else + window->button_states[i] = META_BUTTON_STATE_PRELIGHT; + } + else + window->button_states[i] = META_BUTTON_STATE_NORMAL; + } + + gtk_widget_queue_draw (window->theme_box); +} + +static void +update_button_layout (ThemeViewerWindow *window) +{ + const gchar *text; + gint i; + + text = gtk_entry_get_text (GTK_ENTRY (window->button_layout_entry)); + window->button_layout = meta_button_layout_new (text, FALSE); + + for (i = 0; i < META_BUTTON_TYPE_LAST; i++) + window->button_states[i] = META_BUTTON_STATE_NORMAL; +} + +static void +update_title_layout (ThemeViewerWindow *window) +{ + GtkWidget *widget; + PangoLayout *layout; + MetaStyleInfo *style_info; + PangoFontDescription *font_desc; + MetaFrameType type; + MetaFrameFlags flags; + MetaFrameStyle *style; + PangoContext *context; + gint height; + + widget = GTK_WIDGET (window); + + layout = gtk_widget_create_pango_layout (widget, "Metacity Theme Viewer"); + + style_info = meta_theme_get_style_info (window->theme, window->theme_variant); + font_desc = meta_style_info_create_font_desc (window->theme, style_info); + + type = window->frame_type; + flags = window->frame_flags; + + style = meta_theme_get_frame_style (window->theme, type, flags); + meta_frame_style_apply_scale (style, font_desc); + + context = gtk_widget_get_pango_context (widget); + height = meta_pango_font_desc_get_text_height (font_desc, context); + + pango_layout_set_auto_dir (layout, FALSE); + pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END); + pango_layout_set_font_description (layout, font_desc); + pango_layout_set_single_paragraph_mode (layout, TRUE); + + if (window->title_layout) + g_object_unref (window->title_layout); + + window->title_layout = layout; + window->title_height = height; + + pango_font_description_free (font_desc); +} + +static void +update_frame_borders (ThemeViewerWindow *window) +{ + meta_theme_get_frame_borders (window->theme, window->theme_variant, + window->frame_type, window->title_height, + window->frame_flags, &window->borders); +} + +static void +update_frame_flags (ThemeViewerWindow *window) +{ + MetaFrameFlags flags; + GtkToggleButton *button; + + flags = META_FRAME_ALLOWS_DELETE | META_FRAME_ALLOWS_MENU | + META_FRAME_ALLOWS_APPMENU | META_FRAME_ALLOWS_MINIMIZE | + META_FRAME_ALLOWS_MAXIMIZE | META_FRAME_ALLOWS_VERTICAL_RESIZE | + META_FRAME_ALLOWS_HORIZONTAL_RESIZE | META_FRAME_ALLOWS_SHADE | + META_FRAME_ALLOWS_MOVE; + + button = GTK_TOGGLE_BUTTON (window->has_focus); + if (gtk_toggle_button_get_active (button)) + flags |= META_FRAME_HAS_FOCUS; + + button = GTK_TOGGLE_BUTTON (window->shaded); + if (gtk_toggle_button_get_active (button)) + flags |= META_FRAME_SHADED; + + button = GTK_TOGGLE_BUTTON (window->maximized); + if (gtk_toggle_button_get_active (button)) + flags |= META_FRAME_MAXIMIZED; + + button = GTK_TOGGLE_BUTTON (window->fullscreen); + if (gtk_toggle_button_get_active (button)) + flags |= META_FRAME_FULLSCREEN; + + button = GTK_TOGGLE_BUTTON (window->tiled); + if (gtk_toggle_button_get_active (button)) + flags |= META_FRAME_TILED_LEFT; + + window->frame_flags = flags; + + update_title_layout (window); + update_frame_borders (window); +} + +static void +theme_box_draw_grid (GtkWidget *widget, + cairo_t *cr) +{ + PangoContext *context; + PangoLayout *layout; + gint width; + gint height; + GdkRectangle clip; + gint x; + gint y; + + context = gtk_widget_get_pango_context (widget); + layout = pango_layout_new (context); + + pango_layout_set_text (layout, "X", 1); + + pango_layout_get_pixel_size (layout, &width, &height); + g_object_unref (layout); + + height /= 2; + + cairo_save (cr); + + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.2); + + gdk_cairo_get_clip_rectangle (cr, &clip); + + for (x = 0; x <= clip.x + clip.width; x += width) + { + cairo_move_to (cr, x + .5, clip.y - .5); + cairo_line_to (cr, x + .5, clip.y + clip.height - .5); + } + + for (y = 0; y <= clip.y + clip.height; y += height) + { + cairo_move_to (cr, clip.x + .5, y - .5); + cairo_line_to (cr, clip.x + clip.width + .5, y - .5); + } + + cairo_stroke (cr); + + cairo_restore (cr); +} + +static void +clear_theme (ThemeViewerWindow *window) +{ + gtk_widget_show (window->choose_theme); + gtk_widget_hide (window->theme_box); + + g_clear_object (&window->theme); +} + +static gboolean +is_valid_theme (const gchar *themes_dir, + const gchar *theme, + MetaThemeType type) +{ + gchar *path; + GDir *dir; + const gchar *name; + + path = g_build_filename (themes_dir, theme, NULL); + dir = g_dir_open (path, 0, NULL); + g_free (path); + + if (dir == NULL) + return FALSE; + + while ((name = g_dir_read_name (dir)) != NULL) + { + gchar *filename; + + if (type == META_THEME_TYPE_METACITY && + g_strcmp0 (name, "metacity-1") == 0) + { + gint i; + + for (i = 1; i <=3; i++) + { + gchar *theme_format; + + theme_format = g_strdup_printf ("metacity-theme-%d.xml", i); + filename = g_build_filename (themes_dir, theme, name, + theme_format, NULL); + + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + { + g_free (filename); + g_free (theme_format); + g_dir_close (dir); + + return TRUE; + } + + g_free (filename); + g_free (theme_format); + } + } + else if (type == META_THEME_TYPE_GTK && + g_strcmp0 (name, "gtk-3.0") == 0) + { + filename = g_build_filename (themes_dir, theme, name, + "gtk.css", NULL); + + if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) + { + g_free (filename); + g_dir_close (dir); + + return TRUE; + } + + g_free (filename); + } + } + + g_dir_close (dir); + + return FALSE; +} + +static void +get_valid_themes (ThemeViewerWindow *window, + const gchar *themes_dir, + MetaThemeType type, + GSList **themes) +{ + GDir *dir; + const gchar *theme; + + dir = g_dir_open (themes_dir, 0, NULL); + + if (dir == NULL) + return; + + while ((theme = g_dir_read_name (dir)) != NULL) + { + if (!is_valid_theme (themes_dir, theme, type)) + continue; + + if (g_slist_find_custom (*themes, theme, (GCompareFunc) g_strcmp0)) + continue; + + *themes = g_slist_prepend (*themes, g_strdup (theme)); + } + + g_dir_close (dir); +} + +static void +theme_viewer_window_dispose (GObject *object) +{ + ThemeViewerWindow *window; + + window = THEME_VIEWER_WINDOW (object); + + g_clear_object (&window->theme); + g_clear_object (&window->title_layout); + g_clear_object (&window->mini_icon); + g_clear_object (&window->icon); + + G_OBJECT_CLASS (theme_viewer_window_parent_class)->dispose (object); +} + +static void +type_combo_box_changed_cb (GtkComboBox *combo_box, + ThemeViewerWindow *window) +{ + GtkComboBoxText *theme_combo_box_text; + MetaThemeType type; + GSList *themes; + gchar *themes_dir; + GSList *theme; + + theme_combo_box_text = GTK_COMBO_BOX_TEXT (window->theme_combo_box); + + gtk_combo_box_text_remove_all (theme_combo_box_text); + gtk_widget_set_sensitive (window->reload_button, FALSE); + + clear_theme (window); + + type = gtk_combo_box_get_active (combo_box); + themes = NULL; + + themes_dir = g_build_filename (DATADIR, "themes", NULL); + get_valid_themes (window, themes_dir, type, &themes); + g_free (themes_dir); + + themes_dir = g_build_filename (g_get_user_data_dir (), "themes", NULL); + get_valid_themes (window, themes_dir, type, &themes); + g_free (themes_dir); + + themes_dir = g_build_filename (g_get_home_dir (), ".themes", NULL); + get_valid_themes (window, themes_dir, type, &themes); + g_free (themes_dir); + + gtk_combo_box_text_insert (theme_combo_box_text, 0, NULL, _("Choose Theme")); + gtk_combo_box_set_active (GTK_COMBO_BOX (window->theme_combo_box), 0); + + themes = g_slist_sort (themes, (GCompareFunc) g_strcmp0); + for (theme = themes; theme != NULL; theme = g_slist_next (theme)) + { + const gchar *name; + + name = (const gchar *) theme->data; + + gtk_combo_box_text_append (theme_combo_box_text, name, name); + } + + g_slist_free_full (themes, g_free); +} + +static void +theme_combo_box_changed_cb (GtkComboBox *combo_box, + ThemeViewerWindow *window) +{ + const gchar *theme; + MetaThemeType type; + + theme = gtk_combo_box_get_active_id (combo_box); + + gtk_widget_set_sensitive (window->reload_button, FALSE); + + if (theme == NULL) + { + clear_theme (window); + + return; + } + + type = gtk_combo_box_get_active (GTK_COMBO_BOX (window->type_combo_box)); + + window->theme = meta_theme_new (type); + + meta_theme_load (window->theme, theme, NULL); + meta_theme_set_composited (window->theme, window->composited); + + update_frame_flags (window); + update_button_layout (window); + + gtk_widget_hide (window->choose_theme); + gtk_widget_show (window->theme_box); + + if (type == META_THEME_TYPE_METACITY) + gtk_widget_set_sensitive (window->reload_button, TRUE); +} + +static void +reload_button_clicked_cb (GtkButton *button, + ThemeViewerWindow *window) +{ + GtkComboBox *combo_box; + const gchar *theme; + + combo_box = GTK_COMBO_BOX (window->theme_combo_box); + theme = gtk_combo_box_get_active_id (combo_box); + + meta_theme_load (window->theme, theme, NULL); + + update_frame_borders (window); + + gtk_widget_queue_draw (window->theme_box); +} + +static gboolean +theme_box_draw_cb (GtkWidget *widget, + cairo_t *cr, + ThemeViewerWindow *window) +{ + gint client_width; + gint client_height; + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + theme_box_draw_grid (widget, cr); + + get_client_width_and_height (widget, window, &client_width, &client_height); + + if (!window->mini_icon) + window->mini_icon = get_icon (MINI_ICON_SIZE); + + if (!window->mini_icon) + window->icon = get_icon (ICON_SIZE); + + cairo_translate (cr, PADDING, PADDING); + meta_theme_draw_frame (window->theme, window->theme_variant, cr, + window->frame_type, window->frame_flags, + client_width, client_height, + window->title_layout, window->title_height, + &window->button_layout, window->button_states, + window->mini_icon, window->icon); + + return TRUE; +} + +static gboolean +theme_box_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + ThemeViewerWindow *window) +{ + window->button_pressed = TRUE; + + update_button_state (widget, event->device, window); + + return TRUE; +} + +static gboolean +theme_box_button_release_event_cb (GtkWidget *widget, + GdkEventButton *event, + ThemeViewerWindow *window) +{ + window->button_pressed = FALSE; + + update_button_state (widget, event->device, window); + + return TRUE; +} + +static gboolean +theme_box_motion_notify_event_cb (GtkWidget *widget, + GdkEventMotion *event, + ThemeViewerWindow *window) +{ + update_button_state (widget, event->device, window); + + return TRUE; +} + +static void +flags_toggled_cb (GtkToggleButton *togglebutton, + ThemeViewerWindow *window) +{ + update_frame_flags (window); + + gtk_widget_queue_draw (window->theme_box); +} + +static void +button_layout_entry_changed_cb (GtkEditable *editable, + ThemeViewerWindow *window) +{ + update_button_layout (window); + + gtk_widget_queue_draw (window->theme_box); +} + +static void +dark_theme_state_set_cb (GtkSwitch *widget, + gboolean state, + ThemeViewerWindow *window) +{ + gboolean active; + + active = gtk_switch_get_active (GTK_SWITCH (widget)); + window->theme_variant = active ? "dark" : NULL; + + update_frame_borders (window); + + gtk_widget_queue_draw (window->theme_box); +} + +static void +frame_type_combo_box_changed_cb (GtkComboBox *combo_box, + ThemeViewerWindow *window) +{ + window->frame_type = gtk_combo_box_get_active (combo_box); + + update_frame_flags (window); +} + +static void +composited_state_set_cb (GtkSwitch *widget, + gboolean state, + ThemeViewerWindow *window) +{ + gboolean active; + + active = gtk_switch_get_active (GTK_SWITCH (widget)); + window->composited = active; + + if (!window->theme) + return; + + meta_theme_set_composited (window->theme, active); + + gtk_widget_queue_draw (window->theme_box); +} + +static void +theme_viewer_window_class_init (ThemeViewerWindowClass *window_class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + const gchar *resource; + + object_class = G_OBJECT_CLASS (window_class); + widget_class = GTK_WIDGET_CLASS (window_class); + + object_class->dispose = theme_viewer_window_dispose; + + resource = "/org/gnome/metacity/ui/theme-viewer-window.ui"; + gtk_widget_class_set_template_from_resource (widget_class, resource); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, header_bar); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, type_combo_box); + gtk_widget_class_bind_template_callback (widget_class, type_combo_box_changed_cb); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, theme_combo_box); + gtk_widget_class_bind_template_callback (widget_class, theme_combo_box_changed_cb); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, reload_button); + gtk_widget_class_bind_template_callback (widget_class, reload_button_clicked_cb); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, choose_theme); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, theme_box); + gtk_widget_class_bind_template_callback (widget_class, theme_box_draw_cb); + gtk_widget_class_bind_template_callback (widget_class, theme_box_button_press_event_cb); + gtk_widget_class_bind_template_callback (widget_class, theme_box_button_release_event_cb); + gtk_widget_class_bind_template_callback (widget_class, theme_box_motion_notify_event_cb); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, has_focus); + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, shaded); + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, maximized); + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, fullscreen); + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, tiled); + gtk_widget_class_bind_template_callback (widget_class, flags_toggled_cb); + + gtk_widget_class_bind_template_child (widget_class, ThemeViewerWindow, button_layout_entry); + gtk_widget_class_bind_template_callback (widget_class, button_layout_entry_changed_cb); + + gtk_widget_class_bind_template_callback (widget_class, dark_theme_state_set_cb); + gtk_widget_class_bind_template_callback (widget_class, frame_type_combo_box_changed_cb); + gtk_widget_class_bind_template_callback (widget_class, composited_state_set_cb); +} + +static void +theme_viewer_window_init (ThemeViewerWindow *window) +{ + window->composited = TRUE; + + gtk_widget_init_template (GTK_WIDGET (window)); + gtk_window_set_titlebar (GTK_WINDOW (window), window->header_bar); + + gtk_widget_add_events (window->theme_box, GDK_POINTER_MOTION_MASK); + + type_combo_box_changed_cb (GTK_COMBO_BOX (window->type_combo_box), window); +} + +GtkWidget * +theme_viewer_window_new (void) +{ + return g_object_new (THEME_VIEWER_TYPE_WINDOW, + "title", _("Metacity Theme Viewer"), + NULL); +} diff --git a/theme-viewer/theme-viewer-window.h b/theme-viewer/theme-viewer-window.h new file mode 100644 index 00000000..0912b441 --- /dev/null +++ b/theme-viewer/theme-viewer-window.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Alberts Muktupāvels + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef THEME_VIEWER_WINDOW_H +#define THEME_VIEWER_WINDOW_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define THEME_VIEWER_TYPE_WINDOW theme_viewer_window_get_type () +G_DECLARE_FINAL_TYPE (ThemeViewerWindow, theme_viewer_window, + THEME_VIEWER, WINDOW, GtkWindow) + +GtkWidget *theme_viewer_window_new (void); + +G_END_DECLS + +#endif diff --git a/theme-viewer/theme-viewer.gresource.xml b/theme-viewer/theme-viewer.gresource.xml new file mode 100644 index 00000000..6cee870f --- /dev/null +++ b/theme-viewer/theme-viewer.gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gnome/metacity/ui"> + <file alias="theme-viewer-window.ui">../data/ui/theme-viewer-window.ui</file> + </gresource> +</gresources> |