summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--configure.ac9
-rw-r--r--data/Makefile.am1
-rw-r--r--data/ui/Makefile.am7
-rw-r--r--data/ui/theme-viewer-window.ui452
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/Makefile.am14
-rw-r--r--src/ui/preview-widget.c485
-rw-r--r--src/ui/preview-widget.h79
-rw-r--r--src/ui/theme-viewer.c1121
-rw-r--r--theme-viewer/Makefile.am54
-rw-r--r--theme-viewer/theme-viewer-main.c49
-rw-r--r--theme-viewer/theme-viewer-window.c754
-rw-r--r--theme-viewer/theme-viewer-window.h33
-rw-r--r--theme-viewer/theme-viewer.gresource.xml6
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'>&lt;control&gt;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'>&lt;control&gt;u</attribute>"
- "</item>"
- "<item>"
- "<attribute name='label'>Splashscreen</attribute>"
- "<attribute name='action'>theme-viewer.splashscreen</attribute>"
- "<attribute name='accel'>&lt;control&gt;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>