grim/guifications2

Initial support for building the installer
draft default tip
2021-05-19, Gary Kramlich
e60a596742b7
Initial support for building the installer
/*
* Guifications - The end all, be all, toaster popup plugin
* Copyright (C) 2003-2011 Gary Kramlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
*/
#ifdef HAVE_CONFIG_H
# include "../gf_config.h"
#endif
#include <glib.h>
#include <gtk/gtk.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include "gf_internal.h"
#define PURPLE_PLUGINS
#include <debug.h>
#include <pidgin.h>
#include <notify.h>
#include <plugin.h>
#include <request.h>
#include <signals.h>
#include <util.h>
#include <gtkplugin.h>
#include "gf_event.h"
#include "gf_file.h"
#include "gf_item.h"
#include "gf_item_icon.h"
#include "gf_item_image.h"
#include "gf_item_offset.h"
#include "gf_item_text.h"
#include "gf_menu.h"
#include "gf_notification.h"
#include "gf_preferences.h"
#include "gf_theme.h"
#include "gf_theme_editor.h"
#include "gf_theme_info.h"
#include "gf_theme_ops.h"
#include "gf_utils.h"
/* Okay, heres the run down of how all of this works.
*
* The theme is loaded and then converted into a GtkTreeStore. The store holds,
* the title of what to display in the tree view, as well as what page to
* display when it's selected, as well as the object itself.
*
* The getters and setters are added as data to the widget at creation time.
* This way when we hit the callback, we grab the item from the store, and pop
* it into the getter or setter function, update accordingly, and go about our
* business.
*
*/
enum {
GFTE_STORE_TITLE = 0,
GFTE_STORE_PAGE,
GFTE_STORE_OBJECT,
GFTE_STORE_TOTAL
};
enum {
GFTE_PAGE_THEME = 0,
GFTE_PAGE_INFO,
GFTE_PAGE_OPS,
GFTE_PAGE_NOTIFICATION,
GFTE_PAGE_ICON,
GFTE_PAGE_IMAGE,
GFTE_PAGE_TEXT,
GFTE_PAGE_TOTAL
};
enum {
GFTE_FLAGS_OBJECT = 0,
GFTE_FLAGS_SUB_OBJECT,
GFTE_FLAGS_H_OFFSET,
GFTE_FLAGS_V_OFFSET,
GFTE_FLAGS_TOTAL
};
enum {
GFTE_MODIFIED_CLOSE = 0,
GFTE_MODIFIED_NEW,
GFTE_MODIFIED_OPEN,
GFTE_MODIFIED_TOTAL
};
enum {
GFTE_BUTTON_FILE = 0,
GFTE_BUTTON_FONT,
GFTE_BUTTON_COLOR,
GFTE_BUTTON_TOTAL
};
struct GfThemeEditorInfo {
GtkWidget *name;
GtkWidget *version;
GtkWidget *summary;
GtkWidget *description;
GtkWidget *author;
GtkWidget *website;
};
struct GfThemeEditorOps {
GtkWidget *time_format;
GtkWidget *date_format;
GtkWidget *warning;
GtkWidget *ellipsis;
};
struct GfThemeEditorNotification {
GtkWidget *alias;
GtkWidget *use_gtk;
GtkWidget *filename;
GtkWidget *button;
GtkWidget *width;
GtkWidget *height;
};
struct GfThemeEditorItem {
GtkWidget *position;
GtkWidget *h_offset;
GtkWidget *h_offset_p;
GtkWidget *v_offset;
GtkWidget *v_offset_p;
};
struct GfThemeEditorIcon {
struct GfThemeEditorItem item;
GtkWidget *type;
GtkWidget *size;
};
struct GfThemeEditorImage {
struct GfThemeEditorItem item;
GtkWidget *filename;
GtkWidget *button;
};
struct GfThemeEditorText {
struct GfThemeEditorItem item;
GtkWidget *format;
GtkWidget *width;
GtkWidget *clipping;
GtkWidget *font;
GtkWidget *color;
};
struct GfThemeEditor {
GfTheme *theme;
gchar *filename;
gchar *path;
gboolean changed;
/* toolbar stuff */
GtkTooltips *tooltips;
GtkWidget *tool_notification;
GtkWidget *tool_item;
GtkWidget *tool_copy;
GtkWidget *tool_delete;
GtkWidget *tool_up;
GtkWidget *tool_down;
/* main stuff */
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *tree;
GtkWidget *note;
GtkTreeStore *store;
/* everything else */
struct GfThemeEditorInfo info;
struct GfThemeEditorOps ops;
struct GfThemeEditorNotification notification;
struct GfThemeEditorIcon icon;
struct GfThemeEditorImage image;
struct GfThemeEditorText text;
};
struct GfteModified {
GtkWidget *window;
gint type;
gchar *filename;
};
struct GfteDelete {
GtkWidget *window;
};
struct GfteNewNotification {
GtkWidget *window;
GtkWidget *type;
};
struct GfteNewItem {
GtkWidget *window;
GtkWidget *type;
};
typedef void (*GfteSetFunc)(gpointer obj, gconstpointer val);
typedef gconstpointer (*GfteGetFunc)(gpointer obj);
/*******************************************************************************
* Prototypes ICK!
******************************************************************************/
static void gfte_selection_changed_cb(GtkTreeSelection *sel, gpointer data);
/*******************************************************************************
* Globals
******************************************************************************/
PurplePlugin *plugin_handle = NULL;
gpointer image_dialog = NULL;
GtkWidget *opt_dialog = NULL;
struct GfThemeEditor editor;
struct GfteModified modified;
struct GfteDelete del_obj;
struct GfteNewNotification new_notification;
struct GfteNewItem new_item;
/*******************************************************************************
* Toolbar button stuff
******************************************************************************/
static void
gfte_toolbar_buttons_update(gboolean item, gboolean copy, gboolean delete,
gboolean up, gboolean down)
{
gtk_widget_set_sensitive(editor.tool_item, item);
gtk_widget_set_sensitive(editor.tool_copy, copy);
gtk_widget_set_sensitive(editor.tool_delete, delete);
gtk_widget_set_sensitive(editor.tool_up, up);
gtk_widget_set_sensitive(editor.tool_down, down);
}
/*******************************************************************************
* Main stuff thats used all over the place
******************************************************************************/
static void
gfte_remove_temp() {
gchar *name;
if(!editor.path)
return;
name = g_path_get_basename(editor.path);
if(name && name[0] == '.')
gf_file_remove_dir(editor.path);
g_free(name);
}
static void
gfte_save_theme() {
gchar *path, *oldpath, *dir;
gboolean loaded;
loaded = gf_theme_is_loaded(editor.filename);
if(loaded) {
GfTheme *theme = gf_theme_find_theme_by_filename(editor.filename);
if(theme)
gf_theme_unload(theme);
}
gf_theme_save_to_file(editor.theme, editor.filename);
dir = gf_theme_strip_name(editor.theme);
oldpath = g_path_get_dirname(editor.path);
/* ok, because windows is retarded, and everyone can edit everything, we get to take
* the editor's path, remove the last part of it, and then attach the new dir name to
* it.
*/
path = g_build_filename(oldpath, dir, NULL);
g_free(oldpath);
g_free(dir);
/* move the dir */
g_rename(editor.path, path);
/* update the editor's path */
g_free(editor.path);
editor.path = path;
/* update the editor's file */
g_free(editor.filename);
editor.filename = g_build_filename(editor.path, "theme.xml", NULL);
/* reprobe the theme and tell the prefs to refresh it.. */
gf_theme_probe(editor.filename);
if(loaded) {
gf_theme_load(editor.filename);
gf_themes_save_loaded();
}
gf_preferences_refresh_themes_list();
editor.changed = FALSE;
}
static void
gfte_store_add(GtkTreeStore *store, GtkTreeIter *child, GtkTreeIter *parent,
const gchar *title, gint page, gpointer data)
{
gtk_tree_store_append(store, child, parent);
gtk_tree_store_set(store, child,
GFTE_STORE_TITLE, title,
GFTE_STORE_PAGE, page,
GFTE_STORE_OBJECT, data,
-1);
}
static GtkTreeStore *
gfte_store_update() {
GfThemeInfo *info;
GfThemeOptions *ops;
GfEvent *event;
GfNotification *notification;
GfItem *item;
GtkTreeStore *store;
GtkTreeIter parent, child, iter;
GList *n, *i;
store = gtk_tree_store_new(GFTE_STORE_TOTAL, G_TYPE_STRING, G_TYPE_INT,
G_TYPE_POINTER);
/* theme */
gfte_store_add(store, &parent, NULL,
_("Theme"), GFTE_PAGE_THEME, editor.theme);
/* info */
info = gf_theme_get_theme_info(editor.theme);
gfte_store_add(store, &child, &parent,
_("Info"), GFTE_PAGE_INFO, info);
/* options */
ops = gf_theme_get_theme_options(editor.theme);
gfte_store_add(store, &child, &parent,
_("Options"), GFTE_PAGE_OPS, ops);
/* notifications */
for(n = gf_theme_get_notifications(editor.theme); n; n = n->next) {
const gchar *alias = NULL, *name = NULL;
notification = GF_NOTIFICATION(n->data);
if((alias = gf_notification_get_alias(notification)))
name = alias;
else {
const gchar *type;
type = gf_notification_get_type(notification);
event = gf_event_find_for_notification(type);
name = gf_event_get_name(event);
}
gfte_store_add(store, &child, &parent, name,
GFTE_PAGE_NOTIFICATION, notification);
/* items */
for(i = gf_notification_get_items(notification); i; i = i->next) {
GfItemType type;
gint page = -1;
item = GF_ITEM(i->data);
type = gf_item_get_type(item);
switch(type) {
case GF_ITEM_TYPE_ICON:
page = GFTE_PAGE_ICON;
break;
case GF_ITEM_TYPE_IMAGE:
page = GFTE_PAGE_IMAGE;
break;
case GF_ITEM_TYPE_TEXT:
page = GFTE_PAGE_TEXT;
break;
case GF_ITEM_TYPE_UNKNOWN:
default:
break;
}
if(page == -1)
continue;
gfte_store_add(store, &iter, &child,
gf_item_type_to_string(type, TRUE),
page, item);
}
}
return store;
}
static void
gfte_store_select_iter(GtkTreeIter *iter) {
GtkTreeModel *model;
GtkTreeSelection *sel;
GtkTreePath *path;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(editor.tree));
path = gtk_tree_model_get_path(model, iter);
gtk_tree_view_expand_to_path(GTK_TREE_VIEW(editor.tree), path);
gtk_tree_path_free(path);
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(editor.tree));
gtk_tree_selection_select_iter(sel, iter);
}
static gchar *
gfte_make_temp_dir() {
gchar *path, *dir;
dir = g_strdup_printf(".%x", g_random_int());
path = g_build_filename(purple_user_dir(), "guifications", "themes", dir, NULL);
g_free(dir);
g_mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR);
return path;
}
void
gfte_setup(const gchar *filename) {
GfTheme *old = editor.theme;
if(filename) {
editor.theme = gf_theme_new_from_file(filename);
} else {
GfNotification *master = NULL;
editor.theme = gf_theme_new();
gf_theme_set_theme_info(editor.theme, gf_theme_info_new());
gf_theme_set_theme_options(editor.theme, gf_theme_options_new());
master = gf_notification_new(editor.theme);
gf_notification_set_type(master, GF_NOTIFICATION_MASTER);
gf_theme_add_notification(editor.theme, master);
}
if(editor.theme) {
if(old)
gf_theme_unload(old);
old = NULL;
} else {
editor.theme = old;
return;
}
gfte_remove_temp();
if(editor.filename)
g_free(editor.filename);
if(filename) {
editor.filename = g_strdup(filename);
} else {
gchar *path = NULL;
path = gfte_make_temp_dir();
editor.filename = g_build_filename(path, "theme.xml", NULL);
g_free(path);
}
if(editor.path)
g_free(editor.path);
editor.path = g_path_get_dirname(editor.filename);
if(editor.store) {
gtk_tree_view_set_model(GTK_TREE_VIEW(editor.tree), NULL);
g_object_unref(G_OBJECT(editor.store));
}
editor.store = gfte_store_update();
if(editor.window) {
GtkTreeIter iter;
gtk_tree_view_set_model(GTK_TREE_VIEW(editor.tree),
GTK_TREE_MODEL(editor.store));
gtk_tree_view_expand_all(GTK_TREE_VIEW(editor.tree));
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(editor.store), &iter);
gfte_store_select_iter(&iter);
}
editor.changed = FALSE;
}
static void
gfte_dialog_cleanup() {
if(del_obj.window) {
gtk_widget_destroy(del_obj.window);
del_obj.window = NULL;
}
if(new_notification.window) {
gtk_widget_destroy(new_notification.window);
new_notification.window = NULL;
}
if(new_item.window) {
gtk_widget_destroy(new_item.window);
new_item.window = NULL;
}
if(modified.window) {
gtk_widget_destroy(modified.window);
modified.window = NULL;
if(modified.filename)
g_free(modified.filename);
modified.filename = NULL;
}
if(image_dialog) {
purple_request_close(PURPLE_REQUEST_FILE, image_dialog);
image_dialog = NULL;
}
if(opt_dialog) {
gtk_widget_destroy(opt_dialog);
opt_dialog = NULL;
}
}
static void
gfte_cleanup() {
gfte_dialog_cleanup();
editor.window = NULL;
if(editor.theme)
gf_theme_unload(editor.theme);
editor.theme = NULL;
if(editor.filename)
g_free(editor.filename);
editor.filename = NULL;
if(editor.path) {
gchar *dir = NULL;
dir = g_path_get_basename(editor.path);
if(dir && dir[0] == '.') {
gf_file_remove_dir(editor.path);
g_free(dir);
}
g_free(editor.path);
}
editor.path = NULL;
if(editor.store)
g_object_unref(G_OBJECT(editor.store));
editor.store = NULL;
if(editor.tooltips)
g_object_unref(G_OBJECT(editor.tooltips));
editor.tooltips = NULL;
}
/*******************************************************************************
* new/delete helpers
******************************************************************************/
static gpointer
gfte_store_get_row(GtkTreeIter *iter, gint *page, gchar **title) {
GtkTreeModel *model;
GtkTreeSelection *sel;
gpointer object;
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(editor.tree));
if(!gtk_tree_selection_get_selected(sel, &model, iter))
return NULL;
gtk_tree_model_get(model, iter,
GFTE_STORE_OBJECT, &object,
GFTE_STORE_PAGE, page,
GFTE_STORE_TITLE, title,
-1);
return object;
}
/*******************************************************************************
* modified dialog stuff
******************************************************************************/
static gboolean
gfte_modified_deleted_cb(GtkWidget *w, GdkEvent *e, gpointer data) {
modified.window = NULL;
if(modified.filename)
g_free(modified.filename);
modified.filename = NULL;
return FALSE;
}
static void
gfte_modified_cancel_cb(GtkButton *button, gpointer data) {
gtk_widget_destroy(modified.window);
modified.window = NULL;
if(modified.filename)
g_free(modified.filename);
modified.filename = NULL;
}
static void
gfte_modified_no_cb(GtkButton *button, gpointer data) {
gtk_widget_destroy(modified.window);
modified.window = NULL;
gfte_remove_temp();
switch(modified.type) {
case GFTE_MODIFIED_CLOSE:
gtk_widget_destroy(editor.window);
gfte_cleanup();
break;
case GFTE_MODIFIED_NEW:
gfte_setup(NULL);
break;
case GFTE_MODIFIED_OPEN:
if(modified.filename) {
gfte_setup(modified.filename);
g_free(modified.filename);
modified.filename = NULL;
}
break;
case GFTE_MODIFIED_TOTAL:
default:
break;
}
}
static void
gfte_modified_yes_cb(GtkButton *button, gpointer data) {
gtk_widget_destroy(modified.window);
modified.window = NULL;
gfte_save_theme();
switch(modified.type) {
case GFTE_MODIFIED_CLOSE:
gtk_widget_destroy(editor.window);
gfte_cleanup();
break;
case GFTE_MODIFIED_NEW:
gfte_setup(NULL);
break;
case GFTE_MODIFIED_OPEN:
if(modified.filename) {
gfte_setup(modified.filename);
g_free(modified.filename);
modified.filename = NULL;
}
break;
case GFTE_MODIFIED_TOTAL:
default:
break;
}
}
static void
gfte_modified_show(gint type, const gchar *filename) {
GtkWidget *vbox, *hbox, *widget;
gchar *label = NULL;
if(modified.window) {
gtk_widget_show(modified.window);
return;
}
if(type == GFTE_MODIFIED_CLOSE)
label = g_strdup(_("Would you like to save before closing?"));
else if(type == GFTE_MODIFIED_NEW)
label = g_strdup(_("Would you like to save before creating a new theme?"));
else if(type == GFTE_MODIFIED_OPEN)
label = g_strdup_printf(_("Would you like to save before opening %s?"),
filename);
else
return;
gfte_dialog_cleanup();
modified.type = type;
modified.filename = g_strdup(filename);
modified.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(modified.window), _("Confirm"));
gtk_window_set_resizable(GTK_WINDOW(modified.window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(modified.window), 12);
g_signal_connect(G_OBJECT(modified.window), "delete-event",
G_CALLBACK(gfte_modified_deleted_cb), NULL);
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_add(GTK_CONTAINER(modified.window), vbox);
widget = gtk_label_new(label);
g_free(label);
gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
widget = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_YES);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_modified_yes_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_NO);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_modified_no_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_modified_cancel_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
gtk_widget_show_all(modified.window);
}
/*******************************************************************************
* Delete Item Stuff
******************************************************************************/
static gboolean
gfte_delete_deleted_cb(GtkWidget *w, GdkEvent *e, gpointer data) {
del_obj.window = NULL;
return FALSE;
}
static void
gfte_delete_no_cb(GtkButton *button, gpointer data) {
gtk_widget_destroy(del_obj.window);
del_obj.window = NULL;
}
static void
gfte_delete_yes_cb(GtkButton *button, gpointer data) {
GtkTreeIter iter;
gpointer obj = NULL;
gchar *title = NULL;
gint page;
obj = gfte_store_get_row(&iter, &page, &title);
if (title)
g_free(title);
if(!obj) {
gtk_widget_destroy(del_obj.window);
del_obj.window = NULL;
return;
}
if(page == GFTE_PAGE_NOTIFICATION) {
GfTheme *theme = gf_notification_get_theme(GF_NOTIFICATION(obj));
gf_theme_remove_notification(theme, GF_NOTIFICATION(obj));
gf_notification_destroy(GF_NOTIFICATION(obj));
gtk_tree_store_remove(editor.store, &iter);
} else if(page == GFTE_PAGE_ICON ||
page == GFTE_PAGE_IMAGE ||
page == GFTE_PAGE_TEXT)
{
GfNotification *notification = gf_item_get_notification(GF_ITEM(obj));
gf_notification_remove_item(notification, GF_ITEM(obj));
gf_item_destroy(GF_ITEM(obj));
gtk_tree_store_remove(editor.store, &iter);
}
gtk_widget_destroy(del_obj.window);
del_obj.window = NULL;
gfte_toolbar_buttons_update(FALSE, FALSE, FALSE, FALSE, FALSE);
editor.changed = TRUE;
}
static void
gfte_delete_show(GtkButton *button, gpointer data) {
GtkWidget *vbox, *hbox, *widget;
GtkTreeIter iter;
gchar *item, *title, *label;
gint page;
if(del_obj.window) {
gtk_widget_show(del_obj.window);
return;
}
gfte_dialog_cleanup();
if(gfte_store_get_row(&iter, &page, &item) == NULL) {
return;
}
if(page == GFTE_PAGE_NOTIFICATION) {
label = g_strdup_printf(_("Are you sure you want to delete this %s notification?"),
item);
title = g_strdup(_("Confirm delete notification"));
g_free(item);
} else if(page == GFTE_PAGE_ICON ||
page == GFTE_PAGE_IMAGE ||
page == GFTE_PAGE_TEXT)
{
label = g_strdup_printf(_("Are you sure you want to delete this %s item?"),
item);
title = g_strdup(_("Confirm delete item"));
g_free(item);
} else {
g_free(item);
gtk_widget_destroy(del_obj.window);
del_obj.window = NULL;
return;
}
del_obj.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(del_obj.window), title);
g_free(title);
gtk_window_set_resizable(GTK_WINDOW(del_obj.window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(del_obj.window), 12);
g_signal_connect(G_OBJECT(del_obj.window), "delete-event",
G_CALLBACK(gfte_delete_deleted_cb), NULL);
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_add(GTK_CONTAINER(del_obj.window), vbox);
widget = gtk_label_new(label);
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
/* separator */
widget = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
/* buttons */
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_YES);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_delete_yes_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_NO);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_delete_no_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
gtk_widget_show_all(del_obj.window);
}
/*******************************************************************************
* New Notification Stuff
******************************************************************************/
static gboolean
gfte_new_notification_deleted_cb(GtkWidget *w, GdkEvent *e, gpointer data) {
new_notification.window = NULL;
return FALSE;
}
static void
gfte_new_notification_cancel_cb(GtkButton *button, gpointer data) {
gtk_widget_destroy(new_notification.window);
new_notification.window = NULL;
}
static void
gfte_new_notification_ok_cb(GtkButton *button, gpointer data) {
GfNotification *notification, *master;
GtkTreeIter parent, child;
gpointer object;
const gchar *n_type;
gint hist;
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(editor.store), &parent);
gtk_tree_model_get(GTK_TREE_MODEL(editor.store), &parent,
GFTE_STORE_OBJECT, &object,
-1);
if(object == NULL) {
purple_debug_misc("guifications", "ouch, I don't know where to put this, aborting\n");
if(new_notification.window)
gtk_widget_destroy(new_notification.window);
new_notification.window = NULL;
return;
}
/* find the notification type, this really needs to get cleaned up but works for now
*/
hist = gtk_option_menu_get_history(GTK_OPTION_MENU(new_notification.type));
n_type = gf_events_get_nth_notification(hist);
if(!g_utf8_collate(n_type, GF_NOTIFICATION_MASTER))
return;
master = gf_theme_get_master(editor.theme);
if(!master) {
notification = gf_notification_new(GF_THEME(object));
} else {
notification = gf_notification_copy(master);
}
/* create the notification */
gf_notification_set_type(notification, n_type);
/* add it to the theme */
gf_theme_add_notification(GF_THEME(object), notification);
/* add it to the store */
gfte_store_add(editor.store, &child, &parent,
gf_events_get_nth_name(hist),
GFTE_PAGE_NOTIFICATION,
notification);
gfte_store_select_iter(&child);
if(master) {
GtkTreeIter item;
GList *l;
gboolean expand = FALSE;
for(l = gf_notification_get_items(notification); l; l = l->next) {
gint type = gf_item_get_type(GF_ITEM(l->data));
gfte_store_add(editor.store, &item, &child,
gf_item_type_to_string(type, TRUE),
type + GFTE_PAGE_ICON,
l->data);
if(!expand)
expand = TRUE;
}
if(expand) {
GtkTreePath *path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(editor.store), &child);
gtk_tree_view_expand_row(GTK_TREE_VIEW(editor.tree), path, TRUE);
gtk_tree_path_free(path);
}
}
if(new_notification.window)
gtk_widget_destroy(new_notification.window);
new_notification.window = NULL;
editor.changed = TRUE;
}
static void
gfte_new_notification_show(GtkButton *button, gpointer data) {
GtkWidget *vbox, *hbox, *widget, *menu;
if(new_notification.window) {
gtk_widget_show(new_notification.window);
return;
}
gfte_dialog_cleanup();
new_notification.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(new_notification.window), _("New Notification"));
gtk_window_set_resizable(GTK_WINDOW(new_notification.window), FALSE);
gtk_container_set_border_width(GTK_CONTAINER(new_notification.window), 12);
g_signal_connect(G_OBJECT(new_notification.window), "delete-event",
G_CALLBACK(gfte_new_notification_deleted_cb), NULL);
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_add(GTK_CONTAINER(new_notification.window), vbox);
/* option menu */
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
widget = gtk_label_new(_("New notification type:"));
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
menu = gf_menu_build(gf_menu_event, editor.theme);
new_notification.type = gtk_option_menu_new();
gtk_option_menu_set_menu(GTK_OPTION_MENU(new_notification.type), menu);
gtk_box_pack_start(GTK_BOX(hbox), new_notification.type, TRUE, TRUE, 0);
/* separator */
widget = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
/* buttons */
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_OK);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_new_notification_ok_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_new_notification_cancel_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
gtk_widget_show_all(new_notification.window);
}
/*******************************************************************************
* New Item Stuff
******************************************************************************/
static gboolean
gfte_new_item_deleted_cb(GtkWidget *w, GdkEvent *e, gpointer data) {
new_item.window = NULL;
return FALSE;
}
static void
gfte_new_item_cancel_cb(GtkButton *button, gpointer data) {
gtk_widget_destroy(new_item.window);
new_item.window = NULL;
}
static void
gfte_new_item_ok_cb(GtkButton *button, gpointer data) {
GfItem *item;
GfItemType type;
GfItemOffset *offset;
GtkTreeIter parent, child;
gpointer object;
gchar *title = NULL;
gint page;
object = gfte_store_get_row(&parent, &page, &title);
if(object == NULL) {
return;
}
/* we have to grab this early in case the selected node is an item, and we select the
* notification. If we don't grab this, the selection changes kills all the dialogs
* making this and invalid widget.
*/
type = gtk_option_menu_get_history(GTK_OPTION_MENU(new_item.type));
if(page == GFTE_PAGE_ICON || page == GFTE_PAGE_IMAGE ||
page == GFTE_PAGE_TEXT)
{
GtkTreeSelection *sel;
gtk_tree_model_iter_parent(GTK_TREE_MODEL(editor.store), &child, &parent);
if(title) {
g_free(title);
title = NULL;
}
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(editor.tree));
gtk_tree_selection_select_iter(sel, &child);
object = gfte_store_get_row(&parent, &page, &title);
}
if(title) {
g_free(title);
title = NULL;
}
if(!object) {
purple_debug_misc("guifications",
"ouch, I don't know where to put this, aborting\n");
if(new_item.window)
gtk_widget_destroy(new_item.window);
new_item.window = NULL;
return;
}
item = gf_item_new(GF_NOTIFICATION(object));
gf_item_set_type(item, type);
if(type == GF_ITEM_TYPE_ICON) {
GfItemIcon *icon = gf_item_icon_new(item);
gf_item_set_item_icon(item, icon);
} else if(type == GF_ITEM_TYPE_IMAGE) {
GfItemImage *image = gf_item_image_new(item);
gf_item_set_item_image(item, image);
} else if(type == GF_ITEM_TYPE_TEXT) {
GfItemText *text = gf_item_text_new(item);
gf_item_set_item_text(item, text);
}
/* create the offsets for the item */
offset = gf_item_offset_new(item);
gf_item_set_horz_offset(item, offset);
offset = gf_item_offset_new(item);
gf_item_set_vert_offset(item, offset);
/* add the item to the notification */
gf_notification_add_item(GF_NOTIFICATION(object), item);
/* throw it in the tree */
gfte_store_add(editor.store, &child, &parent,
gf_item_type_to_string(type, TRUE),
/* gross dirty hack.. clean me up later */
type + GFTE_PAGE_ICON,
item);
gfte_store_select_iter(&child);
if(new_item.window)
gtk_widget_destroy(new_item.window);
new_item.window = NULL;
editor.changed = TRUE;
}
static void
gfte_new_item_show(GtkButton *button, gpointer data) {
GtkWidget *vbox, *hbox, *widget, *menu;
if(new_item.window) {
gtk_widget_show(new_item.window);
return;
}
gfte_dialog_cleanup();
new_item.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(new_item.window), _("New Item"));
gtk_window_set_resizable(GTK_WINDOW(new_item.window), FALSE);
gtk_widget_set_size_request(new_item.window, 250, -1);
gtk_container_set_border_width(GTK_CONTAINER(new_item.window), 12);
g_signal_connect(G_OBJECT(new_item.window), "delete-event",
G_CALLBACK(gfte_new_item_deleted_cb), NULL);
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_add(GTK_CONTAINER(new_item.window), vbox);
/* option menu */
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
widget = gtk_label_new(_("New item type:"));
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
menu = gf_menu_build(gf_menu_item_type, NULL);
new_item.type = gtk_option_menu_new();
gtk_option_menu_set_menu(GTK_OPTION_MENU(new_item.type), menu);
gtk_box_pack_start(GTK_BOX(hbox), new_item.type, TRUE, TRUE, 0);
/* separator */
widget = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
/* buttons */
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_OK);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_new_item_ok_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
g_signal_connect(G_OBJECT(widget), "clicked",
G_CALLBACK(gfte_new_item_cancel_cb), NULL);
gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
gtk_widget_show_all(new_item.window);
}
/*******************************************************************************
* Duplicate stuff
******************************************************************************/
static void
gfte_duplicate_object(GtkButton *button, gpointer data) {
GtkTreeIter parent, child, sibling;
gchar *title;
gint page;
gpointer object;
object = gfte_store_get_row(&sibling, &page, &title);
if(object == NULL) {
return;
}
gtk_tree_model_iter_parent(GTK_TREE_MODEL(editor.store), &parent, &sibling);
if(page == GFTE_PAGE_NOTIFICATION) {
GfNotification *notification;
GtkTreeIter item;
GList *l;
gboolean expand = FALSE;
notification = gf_notification_copy(GF_NOTIFICATION(object));
gfte_store_add(editor.store, &child, &parent, title, page,
notification);
for(l = gf_notification_get_items(notification); l; l = l->next) {
gint type = gf_item_get_type(GF_ITEM(l->data));
gfte_store_add(editor.store, &item, &child,
gf_item_type_to_string(type, TRUE),
type + GFTE_PAGE_ICON,
l->data);
if(!expand)
expand = TRUE;
}
gf_theme_add_notification(editor.theme, notification);
if(expand) {
GtkTreePath *path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(editor.store), &child);
gtk_tree_view_expand_row(GTK_TREE_VIEW(editor.tree), path, TRUE);
gtk_tree_path_free(path);
}
} else if(page == GFTE_PAGE_ICON || page == GFTE_PAGE_IMAGE ||
page == GFTE_PAGE_TEXT)
{
GfItem *item;
item = gf_item_copy(GF_ITEM(object));
gtk_tree_store_append(editor.store, &child, &parent);
gtk_tree_store_set(editor.store, &child,
GFTE_STORE_OBJECT, item,
GFTE_STORE_PAGE, page,
GFTE_STORE_TITLE, title,
-1);
gf_notification_add_item(gf_item_get_notification(GF_ITEM(object)),
item);
} else {
return;
}
if(title)
g_free(title);
gfte_store_select_iter(&child);
editor.changed = TRUE;
}
/*******************************************************************************
* Moving items
******************************************************************************/
static gboolean
gfte_is_older_notification(GfNotification *notification) {
GfTheme *theme;
GList *l;
theme = gf_notification_get_theme(notification);
if(!theme)
return FALSE;
l = gf_theme_get_notifications(theme);
if(l->data == notification)
return FALSE;
else
return TRUE;
}
static gboolean
gfte_is_younger_notification(GfNotification *notification) {
GfTheme *theme;
GList *l;
theme = gf_notification_get_theme(notification);
if(!theme)
return FALSE;
/* get the last notification */
for(l = gf_theme_get_notifications(theme); l->next; l = l->next);
if(l->data == notification)
return FALSE;
else
return TRUE;
}
static gboolean
gfte_is_older_item(GfItem *item) {
GfNotification *notification;
GList *l;
notification = gf_item_get_notification(item);
if(!notification)
return FALSE;
l = gf_notification_get_items(notification);
if(l->data == item)
return FALSE;
else
return TRUE;
}
static gboolean
gfte_is_younger_item(GfItem *item) {
GfNotification *notification;
GList *l;
notification = gf_item_get_notification(item);
if(!notification)
return FALSE;
/* get the last item */
for(l = gf_notification_get_items(notification); l->next; l = l->next);
if(l->data == item)
return FALSE;
else
return TRUE;
}
static void
gfte_store_swap(GtkTreeIter *a, GtkTreeIter *b) {
GtkTreeSelection *sel;
gchar *a_title, *b_title;
gint a_page, b_page;
gpointer a_obj, b_obj;
/* get 'em */
gtk_tree_model_get(GTK_TREE_MODEL(editor.store), a,
GFTE_STORE_OBJECT, &a_obj,
GFTE_STORE_PAGE, &a_page,
GFTE_STORE_TITLE, &a_title,
-1);
gtk_tree_model_get(GTK_TREE_MODEL(editor.store), b,
GFTE_STORE_OBJECT, &b_obj,
GFTE_STORE_PAGE, &b_page,
GFTE_STORE_TITLE, &b_title,
-1);
if(a_page == GFTE_PAGE_NOTIFICATION)
gf_notifications_swap(GF_NOTIFICATION(a_obj), GF_NOTIFICATION(b_obj));
else {
gf_items_swap(GF_ITEM(a_obj), GF_ITEM(b_obj));
}
gtk_tree_store_swap(editor.store, a, b);
/* clean up */
g_free(a_title);
g_free(b_title);
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(editor.tree));
gfte_selection_changed_cb(sel, NULL);
}
static void
gfte_move_up(GtkButton *button, gpointer data) {
GtkTreeIter child, sibling;
GtkTreePath *path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(editor.store), &child);
if(!path)
return;
if(!gtk_tree_path_prev(path)) {
gtk_tree_path_free(path);
return;
}
if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(editor.store), &sibling, path)) {
gtk_tree_path_free(path);
return;
}
gfte_store_swap(&child, &sibling);
gtk_tree_path_free(path);
}
static void
gfte_move_down(GtkButton *button, gpointer data) {
GtkTreeIter child, sibling;
GtkTreePath *path;
path = gtk_tree_model_get_path(GTK_TREE_MODEL(editor.store), &child);
if(!path)
return;
/* we just assume this works since it returns void I guess.. */
gtk_tree_path_next(path);
if(!gtk_tree_model_get_iter(GTK_TREE_MODEL(editor.store), &sibling, path)) {
gtk_tree_path_free(path);
return;
}
gfte_store_swap(&child, &sibling);
gtk_tree_path_free(path);
}
/*******************************************************************************
* getter/setter helpers
******************************************************************************/
static gpointer
gfte_store_get_object_and_iter(GtkTreeIter *iter) {
GtkTreeModel *model;
GtkTreeSelection *sel;
gpointer object;
g_return_val_if_fail(iter, NULL);
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(editor.tree));
gtk_tree_selection_get_selected(sel, &model, iter);
gtk_tree_model_get(model, iter,
GFTE_STORE_OBJECT, &object,
-1);
return object;
}
static gpointer
gfte_store_get_object() {
GtkTreeIter iter;
return gfte_store_get_object_and_iter(&iter);
}
/*******************************************************************************
* Setters
******************************************************************************/
static void
gfte_set_value(GtkWidget *widget, gint page, gpointer object, gconstpointer value) {
GfteSetFunc setter = g_object_get_data(G_OBJECT(widget), "setter");
gint flags = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "flags"));
switch(page) {
case GFTE_PAGE_THEME:
break;
case GFTE_PAGE_INFO:
setter(GF_THEME_INFO(object), value);
break;
case GFTE_PAGE_OPS:
setter(GF_THEME_OPTIONS(object), value);
break;
case GFTE_PAGE_NOTIFICATION:
setter(GF_NOTIFICATION(object), value);
break;
case GFTE_PAGE_ICON:
switch(flags) {
case GFTE_FLAGS_OBJECT:
setter(GF_ITEM(object), value);
break;
case GFTE_FLAGS_SUB_OBJECT:
setter(gf_item_get_item_icon(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_H_OFFSET:
setter(gf_item_get_horz_offset(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_V_OFFSET:
setter(gf_item_get_vert_offset(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_TOTAL:
default:
break;
}
break;
case GFTE_PAGE_IMAGE:
switch(flags) {
case GFTE_FLAGS_OBJECT:
setter(GF_ITEM(object), value);
break;
case GFTE_FLAGS_SUB_OBJECT:
setter(gf_item_get_item_image(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_H_OFFSET:
setter(gf_item_get_horz_offset(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_V_OFFSET:
setter(gf_item_get_vert_offset(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_TOTAL:
default:
break;
}
break;
case GFTE_PAGE_TEXT:
switch(flags) {
case GFTE_FLAGS_OBJECT:
setter(GF_ITEM(object), value);
break;
case GFTE_FLAGS_SUB_OBJECT:
setter(gf_item_get_item_text(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_H_OFFSET:
setter(gf_item_get_horz_offset(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_V_OFFSET:
setter(gf_item_get_vert_offset(GF_ITEM(object)), value);
break;
case GFTE_FLAGS_TOTAL:
default:
break;
}
break;
case GFTE_PAGE_TOTAL:
default:
break;
}
}
static void
gfte_entry_changed_cb(GtkWidget *widget, gpointer data) {
GtkTreeIter iter;
gpointer object;
const gchar *value;
gint page;
object = gfte_store_get_object_and_iter(&iter);
value = gtk_entry_get_text(GTK_ENTRY(widget));
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
editor.changed = TRUE;
gfte_set_value(widget, page, object, (gpointer)value);
if(page == GFTE_PAGE_NOTIFICATION && widget == editor.notification.alias) {
GfEvent *event;
GfNotification *notification;
const gchar *alias = NULL, *type = NULL;
if(!gf_utils_strcmp(value, "")) {
notification = GF_NOTIFICATION(object);
type = gf_notification_get_type(notification);
event = gf_event_find_for_notification(type);
alias = gf_event_get_name(event);
} else {
alias = value;
}
gtk_tree_store_set(editor.store, &iter,
GFTE_STORE_TITLE, alias,
-1);
}
}
static void
gfte_check_toggled_cb(GtkWidget *widget, gpointer data) {
gpointer object = gfte_store_get_object();
gpointer pvalue;
gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
gboolean value;
value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
pvalue = GINT_TO_POINTER(value);
editor.changed = TRUE;
gfte_set_value(widget, page, object, pvalue);
/* adjust the sensitivity according to the use gtk setting */
if(widget == editor.notification.use_gtk) {
gtk_widget_set_sensitive(editor.notification.button, !value);
gtk_widget_set_sensitive(editor.notification.width, value);
gtk_widget_set_sensitive(editor.notification.height, value);
}
}
static void
gfte_spin_changed_cb(GtkWidget *widget, GtkScrollType arg1, gpointer user_data)
{
gpointer object = gfte_store_get_object();
gpointer value = GINT_TO_POINTER(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
editor.changed = TRUE;
gfte_set_value(widget, page, object, value);
}
static void
gfte_option_menu_changed_cb(GtkWidget *widget, gpointer user_data) {
gpointer object = gfte_store_get_object();
gpointer value = GINT_TO_POINTER(gtk_option_menu_get_history(GTK_OPTION_MENU(widget)));
gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
editor.changed = TRUE;
gfte_set_value(widget, page, object, value);
}
/*******************************************************************************
* Getters
******************************************************************************/
static gpointer
gfte_get_value(GtkWidget *widget, gint page, gpointer object) {
GfteGetFunc getter = g_object_get_data(G_OBJECT(widget), "getter");
/* The flags decide what item we use in our call to the getter function. This could
* be GfTheme, GfThemeInfo, GfThemeOptions, GfNotification, GfItem, GfItemIcon,
* GfItemImage, GfItemOffset, or GfItemText. Everything besides the item gets called
* as is. Thats why we check it only for the item pages. Since the object we need
* to use for the getter could be GfItem, GfItemIcon, GfItemImage, GfItemOffset, or
* GfItemText. Once we know what it is, we can call it correctly.
*/
gint flags = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "flags"));
switch(page) {
case GFTE_PAGE_THEME:
return (gpointer)getter(GF_THEME(object));
break;
case GFTE_PAGE_INFO:
return (gpointer)getter(GF_THEME_INFO(object));
break;
case GFTE_PAGE_OPS:
return (gpointer)getter(GF_THEME_OPTIONS(object));
break;
case GFTE_PAGE_NOTIFICATION:
return (gpointer)getter(GF_NOTIFICATION(object));
break;
case GFTE_PAGE_ICON:
switch(flags) {
case GFTE_FLAGS_OBJECT:
return (gpointer)getter(GF_ITEM(object));
break;
case GFTE_FLAGS_SUB_OBJECT:
return (gpointer)getter(gf_item_get_item_icon(GF_ITEM(object)));
break;
case GFTE_FLAGS_H_OFFSET:
return (gpointer)getter(gf_item_get_horz_offset(GF_ITEM(object)));
break;
case GFTE_FLAGS_V_OFFSET:
return (gpointer)getter(gf_item_get_vert_offset(GF_ITEM(object)));
break;
case GFTE_FLAGS_TOTAL:
default:
return NULL;
}
break;
case GFTE_PAGE_IMAGE:
switch(flags) {
case GFTE_FLAGS_OBJECT:
return (gpointer)getter(GF_ITEM(object));
break;
case GFTE_FLAGS_SUB_OBJECT:
return (gpointer)getter(gf_item_get_item_image(GF_ITEM(object)));
break;
case GFTE_FLAGS_H_OFFSET:
return (gpointer)getter(gf_item_get_horz_offset(GF_ITEM(object)));
break;
case GFTE_FLAGS_V_OFFSET:
return (gpointer)getter(gf_item_get_vert_offset(GF_ITEM(object)));
break;
case GFTE_FLAGS_TOTAL:
default:
return NULL;
}
break;
case GFTE_PAGE_TEXT:
switch(flags) {
case GFTE_FLAGS_OBJECT:
return (gpointer)getter(GF_ITEM(object));
break;
case GFTE_FLAGS_SUB_OBJECT:
return (gpointer)getter(gf_item_get_item_text(GF_ITEM(object)));
break;
case GFTE_FLAGS_H_OFFSET:
return (gpointer)getter(gf_item_get_horz_offset(GF_ITEM(object)));
break;
case GFTE_FLAGS_V_OFFSET:
return (gpointer)getter(gf_item_get_vert_offset(GF_ITEM(object)));
break;
case GFTE_FLAGS_TOTAL:
default:
return NULL;
}
break;
case GFTE_PAGE_TOTAL:
default:
return NULL;
break;
}
}
/*******************************************************************************
* Update Widgets
******************************************************************************/
static void
gfte_update_entry(GtkWidget *entry, gint page, gpointer object) {
gchar *value = (gchar *)gfte_get_value(entry, page, object);
g_signal_handlers_block_by_func(G_OBJECT(entry),
gfte_entry_changed_cb, NULL);
if(value)
gtk_entry_set_text(GTK_ENTRY(entry), value);
else
gtk_entry_set_text(GTK_ENTRY(entry), "");
g_signal_handlers_unblock_by_func(G_OBJECT(entry),
gfte_entry_changed_cb, NULL);
}
static void
gfte_update_option_menu(GtkWidget *opt_menu, gint page, gpointer object) {
gint value = GPOINTER_TO_INT(gfte_get_value(opt_menu, page, object));
g_signal_handlers_block_by_func(G_OBJECT(opt_menu),
gfte_option_menu_changed_cb, NULL);
gtk_option_menu_set_history(GTK_OPTION_MENU(opt_menu), value);
g_signal_handlers_unblock_by_func(G_OBJECT(opt_menu),
gfte_option_menu_changed_cb, NULL);
}
static void
gfte_update_spin_button(GtkWidget *spin, gint page, gpointer object) {
gint value = GPOINTER_TO_INT(gfte_get_value(spin, page, object));
g_signal_handlers_block_by_func(G_OBJECT(spin),
gfte_spin_changed_cb, NULL);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), value);
g_signal_handlers_unblock_by_func(G_OBJECT(spin),
gfte_spin_changed_cb, NULL);
}
static void
gfte_update_check(GtkWidget *check, gint page, gpointer object) {
gboolean value = GPOINTER_TO_INT(gfte_get_value(check, page, object));
g_signal_handlers_block_by_func(G_OBJECT(check),
gfte_check_toggled_cb, NULL);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), value);
g_signal_handlers_unblock_by_func(G_OBJECT(check),
gfte_check_toggled_cb, NULL);
/* adjust the sensitivity according to the use gtk setting */
if(check == editor.notification.use_gtk) {
gtk_widget_set_sensitive(editor.notification.button, !value);
gtk_widget_set_sensitive(editor.notification.width, value);
gtk_widget_set_sensitive(editor.notification.height, value);
}
}
/*******************************************************************************
* Button stuff (requires getters and setters thats why it's here...)
******************************************************************************/
static void
gfte_dialog_file_ok_cb(gpointer data, const gchar *filename) {
GtkWidget *button;
gpointer object;
gchar *relative = NULL, *target = NULL;
gint page;
if(!filename) {
image_dialog = NULL;
return;
}
button = GTK_WIDGET(data);
object = gfte_store_get_object();
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
relative = g_path_get_basename(filename);
target = g_build_filename(editor.path, relative, NULL);
if(!gf_file_copy_file(filename, target)) {
g_free(target);
g_free(relative);
return;
}
g_free(target);
gfte_set_value(button, page, object, relative);
g_free(relative);
if(page == GFTE_PAGE_NOTIFICATION)
gfte_update_entry(editor.notification.filename, page, object);
else if(page == GFTE_PAGE_IMAGE)
gfte_update_entry(editor.image.filename, page, object);
}
static void
gfte_dialog_file_cancel_cb(gpointer data, const gchar *filename) {
image_dialog = NULL;
}
static void
gfte_dialog_font_ok_cb(GtkButton *b, gpointer data) {
GtkWidget *button;
gpointer object;
gchar *font;
gint page;
button = GTK_WIDGET(data);
object = gfte_store_get_object();
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
font = gtk_font_selection_dialog_get_font_name(
GTK_FONT_SELECTION_DIALOG(opt_dialog));
gfte_set_value(button, page, object, font);
if(font)
g_free(font);
gtk_widget_destroy(opt_dialog);
opt_dialog = NULL;
}
static void
gfte_dialog_font_cancel_cb(GtkButton *b, gpointer data) {
gtk_widget_destroy(opt_dialog);
opt_dialog = NULL;
}
static void
gfte_dialog_color_ok_cb(GtkButton *b, gpointer data) {
GtkWidget *button;
GdkColor gcolor;
gpointer object;
gchar ccolor[14];
gint page;
button = GTK_WIDGET(data);
object = gfte_store_get_object();
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(
GTK_COLOR_SELECTION_DIALOG(opt_dialog)->colorsel),
&gcolor);
g_snprintf(ccolor, sizeof(ccolor), "#%04x%04x%04x",
gcolor.red, gcolor.green, gcolor.blue);
gfte_set_value(button, page, object, ccolor);
gtk_widget_destroy(opt_dialog);
opt_dialog = NULL;
}
static void
gfte_dialog_color_cancel_cb(GtkButton *b, gpointer data) {
gtk_widget_destroy(opt_dialog);
opt_dialog = NULL;
}
static void
gfte_button_clicked_cb(GtkWidget *button, gpointer data) {
gpointer object, value;
gint page, type;
gfte_dialog_cleanup();
type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "type"));
object = gfte_store_get_object();
page = gtk_notebook_get_current_page(GTK_NOTEBOOK(editor.note));
value = gfte_get_value(button, page, object);
if(type == GFTE_BUTTON_FILE) {
image_dialog = purple_request_file(plugin_handle, _("Open"), "", FALSE,
G_CALLBACK(gfte_dialog_file_ok_cb),
G_CALLBACK(gfte_dialog_file_cancel_cb),
NULL, NULL, NULL, (gpointer)button);
} else if(type == GFTE_BUTTON_FONT) {
opt_dialog = gtk_font_selection_dialog_new(_("Select font"));
gtk_font_selection_dialog_set_font_name(
GTK_FONT_SELECTION_DIALOG(opt_dialog),
(value) ? (gchar *)value : "Arial 12");
gtk_font_selection_dialog_set_preview_text(
GTK_FONT_SELECTION_DIALOG(opt_dialog),
_("Guifications"));
g_signal_connect(G_OBJECT(GTK_FONT_SELECTION_DIALOG(opt_dialog)->ok_button),
"clicked", G_CALLBACK(gfte_dialog_font_ok_cb),
(gpointer)button);
g_signal_connect(G_OBJECT(GTK_FONT_SELECTION_DIALOG(opt_dialog)->cancel_button),
"clicked", G_CALLBACK(gfte_dialog_font_cancel_cb),
(gpointer)button);
gtk_widget_show_all(opt_dialog);
} else if(type == GFTE_BUTTON_COLOR) {
PangoColor pcolor;
GdkColor gcolor;
if(value) {
pango_color_parse(&pcolor, (gchar *)value);
gcolor.red = pcolor.red;
gcolor.green = pcolor.green;
gcolor.blue = pcolor.blue;
} else {
gcolor.red = gcolor.green = gcolor.blue = 0;
}
opt_dialog = gtk_color_selection_dialog_new(_("Select color"));
gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(
GTK_COLOR_SELECTION_DIALOG(opt_dialog)->colorsel),
&gcolor);
g_signal_connect(G_OBJECT(GTK_COLOR_SELECTION_DIALOG(opt_dialog)->ok_button),
"clicked", G_CALLBACK(gfte_dialog_color_ok_cb),
(gpointer)button);
g_signal_connect(G_OBJECT(GTK_COLOR_SELECTION_DIALOG(opt_dialog)->cancel_button),
"clicked", G_CALLBACK(gfte_dialog_color_cancel_cb),
(gpointer)button);
gtk_widget_show_all(opt_dialog);
}
}
/*******************************************************************************
* Update pages
******************************************************************************/
static void
gfte_update_item(struct GfThemeEditorItem *te_item, gint page, GfItem *item) {
gfte_update_option_menu(te_item->position, page, item);
gfte_update_spin_button(te_item->h_offset, page, item);
gfte_update_check(te_item->h_offset_p, page, item);
gfte_update_spin_button(te_item->v_offset, page, item);
gfte_update_check(te_item->v_offset_p, page, item);
}
static void
gfte_update_info_page() {
GfThemeInfo *info = (GfThemeInfo *)gfte_store_get_object();
gfte_update_entry(editor.info.name, GFTE_PAGE_INFO, info);
gfte_update_entry(editor.info.version, GFTE_PAGE_INFO, info);
gfte_update_entry(editor.info.summary, GFTE_PAGE_INFO, info);
gfte_update_entry(editor.info.description, GFTE_PAGE_INFO, info);
gfte_update_entry(editor.info.author, GFTE_PAGE_INFO, info);
gfte_update_entry(editor.info.website, GFTE_PAGE_INFO, info);
}
static void
gfte_update_ops_page() {
GfThemeOptions *ops = (GfThemeOptions *)gfte_store_get_object();
gfte_update_entry(editor.ops.date_format, GFTE_PAGE_OPS, ops);
gfte_update_entry(editor.ops.time_format, GFTE_PAGE_OPS, ops);
gfte_update_entry(editor.ops.warning, GFTE_PAGE_OPS, ops);
gfte_update_entry(editor.ops.ellipsis, GFTE_PAGE_OPS, ops);
}
static void
gfte_update_notification_page() {
gpointer obj;
GfNotification *notification;
obj = gfte_store_get_object();
notification = GF_NOTIFICATION(obj);
gfte_update_entry(editor.notification.alias, GFTE_PAGE_NOTIFICATION,
notification);
gfte_update_check(editor.notification.use_gtk, GFTE_PAGE_NOTIFICATION,
notification);
gfte_update_entry(editor.notification.filename, GFTE_PAGE_NOTIFICATION,
notification);
gfte_update_spin_button(editor.notification.width, GFTE_PAGE_NOTIFICATION,
notification);
gfte_update_spin_button(editor.notification.height, GFTE_PAGE_NOTIFICATION,
notification);
}
static void
gfte_update_icon_page() {
GfItem *item = GF_ITEM(gfte_store_get_object());
gfte_update_item(&editor.icon.item, GFTE_PAGE_ICON, item);
gfte_update_option_menu(editor.icon.type, GFTE_PAGE_ICON, item);
gfte_update_option_menu(editor.icon.size, GFTE_PAGE_ICON, item);
}
static void
gfte_update_image_page() {
GfItem *item = GF_ITEM(gfte_store_get_object());
gfte_update_item(&editor.image.item, GFTE_PAGE_IMAGE, item);
gfte_update_entry(editor.image.filename, GFTE_PAGE_IMAGE, item);
}
static void
gfte_update_text_page() {
GfItem *item = GF_ITEM(gfte_store_get_object());
gfte_update_item(&editor.text.item, GFTE_PAGE_TEXT, item);
gfte_update_entry(editor.text.format, GFTE_PAGE_TEXT, item);
gfte_update_spin_button(editor.text.width, GFTE_PAGE_TEXT, item);
gfte_update_option_menu(editor.text.clipping, GFTE_PAGE_TEXT, item);
}
/*******************************************************************************
* Callbacks
******************************************************************************/
static void
gfte_selection_changed_cb(GtkTreeSelection *sel, gpointer data) {
GtkTreeModel *model;
GtkTreeIter iter;
gpointer object;
gint page;
gfte_dialog_cleanup();
if(!gtk_tree_selection_get_selected(sel, &model, &iter)) {
gtk_notebook_set_current_page(GTK_NOTEBOOK(editor.note),
GFTE_PAGE_THEME);
return;
}
gtk_tree_model_get(model, &iter,
GFTE_STORE_PAGE, &page,
GFTE_STORE_OBJECT, &object,
-1);
gtk_notebook_set_current_page(GTK_NOTEBOOK(editor.note), page);
switch(page) {
case GFTE_PAGE_THEME:
gfte_toolbar_buttons_update(FALSE, FALSE, FALSE, FALSE, FALSE);
break;
case GFTE_PAGE_INFO:
gfte_toolbar_buttons_update(FALSE, FALSE, FALSE, FALSE, FALSE);
gfte_update_info_page();
break;
case GFTE_PAGE_OPS:
gfte_toolbar_buttons_update(FALSE, FALSE, FALSE, FALSE, FALSE);
gfte_update_ops_page();
break;
case GFTE_PAGE_NOTIFICATION: {
GfNotification *notification = GF_NOTIFICATION(object);
gboolean master;
master = (g_ascii_strcasecmp(GF_NOTIFICATION_MASTER,
gf_notification_get_type(notification)));
gfte_toolbar_buttons_update(TRUE, master, master,
gfte_is_older_notification(object),
gfte_is_younger_notification(object));
gfte_update_notification_page();
break;
}
case GFTE_PAGE_ICON:
gfte_toolbar_buttons_update(TRUE, TRUE, TRUE,
gfte_is_older_item(object),
gfte_is_younger_item(object));
gfte_update_icon_page();
break;
case GFTE_PAGE_IMAGE:
gfte_toolbar_buttons_update(TRUE, TRUE, TRUE,
gfte_is_older_item(object),
gfte_is_younger_item(object));
gfte_update_image_page();
break;
case GFTE_PAGE_TEXT:
gfte_toolbar_buttons_update(TRUE, TRUE, TRUE,
gfte_is_older_item(object),
gfte_is_younger_item(object));
gfte_update_text_page();
break;
case GFTE_PAGE_TOTAL:
default:
break;
}
}
static void
gfte_new_theme_cb(GtkButton *button, gpointer data) {
if(editor.changed)
gfte_modified_show(GFTE_MODIFIED_NEW, NULL);
else
gfte_setup(NULL);
}
static void
gfte_save_theme_cb(GtkButton *button, gpointer data) {
gfte_save_theme();
}
static void
gfte_help(GtkButton *button, gpointer data) {
purple_notify_uri(NULL, GF_WEBSITE "/themes/theme_howto/");
}
/*******************************************************************************
* Helpers
******************************************************************************/
static void
gfte_build_tree() {
GtkWidget *sw;
GtkCellRenderer *renderer;
GtkTreeViewColumn *col;
GtkTreeSelection *sel;
sw = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
gtk_box_pack_start(GTK_BOX(editor.hbox), sw, FALSE, FALSE, 0);
editor.tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(editor.store));
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(editor.tree));
g_signal_connect_after(G_OBJECT(sel), "changed",
G_CALLBACK(gfte_selection_changed_cb), NULL);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(editor.tree), FALSE);
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(editor.tree), FALSE);
gtk_tree_view_expand_all(GTK_TREE_VIEW(editor.tree));
gtk_container_add(GTK_CONTAINER(sw), editor.tree);
renderer = gtk_cell_renderer_text_new();
col = gtk_tree_view_column_new_with_attributes(NULL, renderer,
"text", GFTE_STORE_TITLE,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(editor.tree), col);
}
static GtkWidget *
gfte_make_label(const gchar *text, GtkSizeGroup *sg) {
GtkWidget *label;
label = gtk_label_new_with_mnemonic(text);
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
if(sg)
gtk_size_group_add_widget(sg, label);
return label;
}
static GtkWidget *
gfte_add_label(GtkWidget *widget, const gchar *label, GtkSizeGroup *sg) {
GtkWidget *hbox;
hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(hbox), gfte_make_label(label, sg),
FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
return hbox;
}
static GtkWidget *
gfte_add_entry(GtkWidget *parent, GtkSizeGroup *sg, gint flags,
const gchar *label, gpointer getter, gpointer setter)
{
GtkWidget *entry, *hbox;
entry = gtk_entry_new();
g_object_set_data(G_OBJECT(entry), "getter", getter);
g_object_set_data(G_OBJECT(entry), "setter", setter);
g_object_set_data(G_OBJECT(entry), "flags", GINT_TO_POINTER(flags));
g_signal_connect(G_OBJECT(entry), "changed",
G_CALLBACK(gfte_entry_changed_cb), NULL);
hbox = gfte_add_label(entry, label, sg);
gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
return entry;
}
static GtkWidget *
gfte_add_check(GtkWidget *parent, gint flags, const gchar *label,
gpointer getter, gpointer setter)
{
GtkWidget *check;
check = gtk_check_button_new_with_mnemonic(label);
g_object_set_data(G_OBJECT(check), "getter", getter);
g_object_set_data(G_OBJECT(check), "setter", setter);
g_object_set_data(G_OBJECT(check), "flags", GINT_TO_POINTER(flags));
g_signal_connect(G_OBJECT(check), "toggled",
G_CALLBACK(gfte_check_toggled_cb), NULL);
gtk_box_pack_start(GTK_BOX(parent), check, FALSE, FALSE, 0);
return check;
}
static GtkWidget *
gfte_add_spin_button(GtkWidget *parent, GtkSizeGroup *sg, gint flags,
const gchar *label, gint min, gint max,
gpointer getter, gpointer setter)
{
GtkWidget *spin, *hbox;
spin = gtk_spin_button_new_with_range(min, max, 1);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spin), TRUE);
g_object_set_data(G_OBJECT(spin), "getter", getter);
g_object_set_data(G_OBJECT(spin), "setter", setter);
g_object_set_data(G_OBJECT(spin), "flags", GINT_TO_POINTER(flags));
g_signal_connect(G_OBJECT(spin), "value-changed",
G_CALLBACK(gfte_spin_changed_cb), NULL);
hbox = gfte_add_label(spin, label, sg);
gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
return spin;
}
static GtkWidget *
gfte_add_option_menu(GtkWidget *parent, GtkSizeGroup *sg, gint flags,
const gchar *label, GfMenuItemBuilder builder,
gpointer getter, gpointer setter)
{
GtkWidget *option_menu, *hbox;
option_menu = gtk_option_menu_new();
gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu),
gf_menu_build(builder, NULL));
g_object_set_data(G_OBJECT(option_menu), "getter", getter);
g_object_set_data(G_OBJECT(option_menu), "setter", setter);
g_object_set_data(G_OBJECT(option_menu), "flags", GINT_TO_POINTER(flags));
g_signal_connect(G_OBJECT(option_menu), "changed",
G_CALLBACK(gfte_option_menu_changed_cb), NULL);
hbox = gfte_add_label(option_menu, label, sg);
gtk_box_pack_start(GTK_BOX(parent), hbox, FALSE, FALSE, 0);
return option_menu;
}
static GtkWidget *
gfte_add_button(GtkWidget *parent, gint flags, gint type, const gchar *stock_id,
gpointer getter, gpointer setter)
{
GtkWidget *button;
button = gtk_button_new_from_stock(stock_id);
g_object_set_data(G_OBJECT(button), "getter", getter);
g_object_set_data(G_OBJECT(button), "setter", setter);
g_object_set_data(G_OBJECT(button), "flags", GINT_TO_POINTER(flags));
g_object_set_data(G_OBJECT(button), "type", GINT_TO_POINTER(type));
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(gfte_button_clicked_cb), NULL);
if(parent)
gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0);
return button;
}
/*******************************************************************************
* Pages
******************************************************************************/
static GtkWidget *
gfte_make_theme_page() {
GtkWidget *page;
page = gtk_vbox_new(FALSE, 0);
return page;
}
static GtkWidget *
gfte_make_info_page() {
GtkWidget *page;
GtkSizeGroup *sg;
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
page = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(page), 12);
editor.info.name =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Name:"),
gf_theme_info_get_name,
gf_theme_info_set_name);
editor.info.version =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Version:"),
gf_theme_info_get_version,
gf_theme_info_set_version);
editor.info.summary =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Summary:"),
gf_theme_info_get_summary,
gf_theme_info_set_summary);
editor.info.description =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Description:"),
gf_theme_info_get_description,
gf_theme_info_set_description);
editor.info.author =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Author:"),
gf_theme_info_get_author,
gf_theme_info_set_author);
editor.info.website =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Website:"),
gf_theme_info_get_website,
gf_theme_info_set_website);
return page;
}
static GtkWidget *
gfte_make_ops_page() {
GtkWidget *page;
GtkSizeGroup *sg;
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
page = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(page), 12);
editor.ops.date_format =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Date Format:"),
gf_theme_options_get_date_format,
gf_theme_options_set_date_format);
editor.ops.time_format =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Time Format:"),
gf_theme_options_get_time_format,
gf_theme_options_set_time_format);
editor.ops.warning =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Warning:"),
gf_theme_options_get_warning,
gf_theme_options_set_warning);
editor.ops.ellipsis =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Ellipsis:"),
gf_theme_options_get_ellipsis,
gf_theme_options_set_ellipsis);
return page;
}
static GtkWidget *
gfte_make_notification_page() {
GtkWidget *page;
GtkSizeGroup *sg;
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
page = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(page), 12);
editor.notification.alias =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Alias:"),
gf_notification_get_alias,
gf_notification_set_alias);
editor.notification.use_gtk =
gfte_add_check(page, GFTE_FLAGS_OBJECT,
_("Use Gtk theme background"),
gf_notification_get_use_gtk,
gf_notification_set_use_gtk);
editor.notification.filename =
gfte_add_entry(page, sg, GFTE_FLAGS_OBJECT, _("Background:"),
gf_notification_get_background,
gf_notification_set_background);
gtk_widget_set_sensitive(editor.notification.filename, FALSE);
editor.notification.button =
gfte_add_button(editor.notification.filename->parent,
GFTE_FLAGS_OBJECT, GFTE_BUTTON_FILE,
GTK_STOCK_OPEN,
gf_notification_get_background,
gf_notification_set_background);
editor.notification.width =
gfte_add_spin_button(page, sg, GFTE_FLAGS_OBJECT, _("Width:"),
GF_NOTIFICATION_MIN, GF_NOTIFICATION_MAX,
gf_notification_get_width,
gf_notification_set_width);
editor.notification.height =
gfte_add_spin_button(page, sg, GFTE_FLAGS_OBJECT, _("Height:"),
GF_NOTIFICATION_MIN, GF_NOTIFICATION_MAX,
gf_notification_get_height,
gf_notification_set_height);
return page;
}
static void
gfte_make_item_widgets(GtkWidget *parent, GtkSizeGroup *sg,
struct GfThemeEditorItem *item)
{
item->position = gfte_add_option_menu(parent, sg, GFTE_FLAGS_OBJECT,
_("_Position:"),
gf_menu_item_position,
gf_item_get_position,
gf_item_set_position);
item->h_offset = gfte_add_spin_button(parent, sg, GFTE_FLAGS_H_OFFSET,
_("_Horizontal Offset:"), -1024, 1023,
gf_item_offset_get_value,
gf_item_offset_set_value);
item->h_offset_p = gfte_add_check(item->h_offset->parent,
GFTE_FLAGS_H_OFFSET, _("Percentage"),
gf_item_offset_get_is_percentage,
gf_item_offset_set_is_percentage);
item->v_offset = gfte_add_spin_button(parent, sg, GFTE_FLAGS_V_OFFSET,
_("_Vertical Offset:"), -1024, 1023,
gf_item_offset_get_value,
gf_item_offset_set_value);
item->v_offset_p = gfte_add_check(item->v_offset->parent,
GFTE_FLAGS_V_OFFSET, _("Percentage"),
gf_item_offset_get_is_percentage,
gf_item_offset_set_is_percentage);
}
static GtkWidget *
gfte_make_icon_page() {
GtkWidget *page;
GtkSizeGroup *sg;
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
page = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(page), 12);
gfte_make_item_widgets(page, sg, &editor.icon.item);
editor.icon.type = gfte_add_option_menu(page, sg, GFTE_FLAGS_SUB_OBJECT,
_("_Type:"), gf_menu_item_icon_type,
gf_item_icon_get_type,
gf_item_icon_set_type);
editor.icon.size = gfte_add_option_menu(page, sg, GFTE_FLAGS_SUB_OBJECT,
_("_Size:"), gf_menu_item_icon_size,
gf_item_icon_get_size,
gf_item_icon_set_size);
return page;
}
static GtkWidget *
gfte_make_image_page() {
GtkWidget *page;
GtkSizeGroup *sg;
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
page = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(page), 12);
gfte_make_item_widgets(page, sg, &editor.image.item);
editor.image.filename = gfte_add_entry(page, sg, GFTE_FLAGS_SUB_OBJECT,
_("Image:"),
gf_item_image_get_image,
gf_item_image_set_image);
gtk_widget_set_sensitive(editor.image.filename, FALSE);
editor.image.button = gfte_add_button(editor.image.filename->parent,
GFTE_FLAGS_SUB_OBJECT, GFTE_BUTTON_FILE,
GTK_STOCK_OPEN,
gf_item_image_get_image,
gf_item_image_set_image);
return page;
}
static GtkWidget *
gfte_make_text_page() {
GtkWidget *page, *hbox;
GtkSizeGroup *sg;
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
page = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(page), 12);
gfte_make_item_widgets(page, sg, &editor.text.item);
editor.text.format = gfte_add_entry(page, sg, GFTE_FLAGS_SUB_OBJECT,
_("Format:"),
gf_item_text_get_format,
gf_item_text_set_format);
editor.text.width = gfte_add_spin_button(page, sg, GFTE_FLAGS_SUB_OBJECT,
_("Width:"), 0, 1023,
gf_item_text_get_width,
gf_item_text_set_width);
editor.text.clipping = gfte_add_option_menu(page, sg, GFTE_FLAGS_SUB_OBJECT,
_("Clipping:"),
gf_menu_item_text_clipping,
gf_item_text_get_clipping,
gf_item_text_set_clipping);
editor.text.font = gfte_add_button(NULL, GFTE_FLAGS_SUB_OBJECT,
GFTE_BUTTON_FONT, GTK_STOCK_SELECT_FONT,
gf_item_text_get_font,
gf_item_text_set_font);
hbox = gfte_add_label(editor.text.font, NULL, sg);
gtk_box_pack_start(GTK_BOX(page), hbox, FALSE, FALSE, 0);
editor.text.color = gfte_add_button(NULL, GFTE_FLAGS_SUB_OBJECT,
GFTE_BUTTON_COLOR, GTK_STOCK_SELECT_COLOR,
gf_item_text_get_color,
gf_item_text_set_color);
hbox = gfte_add_label(editor.text.color, NULL, sg);
gtk_box_pack_start(GTK_BOX(page), hbox, FALSE, FALSE, 0);
return page;
}
/*******************************************************************************
* Main stuff
******************************************************************************/
static GtkWidget *
gfte_toolbar_button_new(GtkWidget *parent, const gchar *stock_id,
const gchar *tooltip, GCallback cb, gpointer data)
{
GtkWidget *button, *image;
button = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
if(cb)
g_signal_connect(G_OBJECT(button), "clicked", cb, data);
gtk_tooltips_set_tip(editor.tooltips, button, tooltip, NULL);
image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_container_add(GTK_CONTAINER(button), image);
gtk_box_pack_start(GTK_BOX(parent), button, FALSE, FALSE, 0);
return button;
}
static void
gfte_toolbar_separator_new(GtkWidget *parent) {
GtkWidget *sep;
sep = gtk_vseparator_new();
gtk_box_pack_start(GTK_BOX(parent), sep, FALSE, FALSE, 0);
}
static void
gfte_build_toolbar() {
GtkWidget *frame, *hbox;
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
gtk_box_pack_start(GTK_BOX(editor.vbox), frame, FALSE, FALSE, 0);
hbox = gtk_hbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(frame), hbox);
gfte_toolbar_button_new(hbox, GTK_STOCK_NEW, _("New theme"),
G_CALLBACK(gfte_new_theme_cb), NULL);
gfte_toolbar_button_new(hbox, GTK_STOCK_SAVE, _("Save theme"),
G_CALLBACK(gfte_save_theme_cb), NULL);
gfte_toolbar_separator_new(hbox);
editor.tool_notification =
gfte_toolbar_button_new(hbox, GTK_STOCK_EXECUTE,
_("New notification"),
G_CALLBACK(gfte_new_notification_show),
NULL);
editor.tool_item =
gfte_toolbar_button_new(hbox, GTK_STOCK_PROPERTIES,
_("New item"),
G_CALLBACK(gfte_new_item_show), NULL);
editor.tool_copy =
gfte_toolbar_button_new(hbox, GTK_STOCK_COPY,
_("Duplicate"),
G_CALLBACK(gfte_duplicate_object),
NULL);
editor.tool_delete =
gfte_toolbar_button_new(hbox, GTK_STOCK_DELETE,
_("Delete"),
G_CALLBACK(gfte_delete_show), NULL);
gfte_toolbar_separator_new(hbox);
editor.tool_up =
gfte_toolbar_button_new(hbox, GTK_STOCK_GO_UP, _("Move up"),
G_CALLBACK(gfte_move_up), NULL);
editor.tool_down =
gfte_toolbar_button_new(hbox, GTK_STOCK_GO_DOWN, _("Move down"),
G_CALLBACK(gfte_move_down), NULL);
gfte_toolbar_separator_new(hbox);
gfte_toolbar_button_new(hbox, GTK_STOCK_HELP, _("Help"),
G_CALLBACK(gfte_help), NULL);
gfte_toolbar_buttons_update(FALSE, FALSE, FALSE, FALSE, FALSE);
}
static void
gfte_build_notebook() {
editor.note = gtk_notebook_new();
gtk_notebook_set_show_tabs(GTK_NOTEBOOK(editor.note), FALSE);
gtk_box_pack_start(GTK_BOX(editor.hbox), editor.note, TRUE, TRUE, 4);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_theme_page(),
NULL, GFTE_PAGE_THEME);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_info_page(),
NULL, GFTE_PAGE_INFO);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_ops_page(),
NULL, GFTE_PAGE_OPS);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_notification_page(),
NULL, GFTE_PAGE_NOTIFICATION);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_icon_page(),
NULL, GFTE_PAGE_ICON);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_image_page(),
NULL, GFTE_PAGE_IMAGE);
gtk_notebook_insert_page(GTK_NOTEBOOK(editor.note),
gfte_make_text_page(),
NULL, GFTE_PAGE_TEXT);
}
static gboolean
gfte_window_destroyed_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
if(editor.changed) {
gfte_modified_show(GFTE_MODIFIED_CLOSE, NULL);
return TRUE;
} else {
gfte_cleanup();
return FALSE;
}
}
static void
gfte_build_window() {
editor.tooltips = gtk_tooltips_new();
g_object_ref(G_OBJECT(editor.tooltips));
gtk_object_sink(GTK_OBJECT(editor.tooltips));
editor.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(editor.window), _("Guifications Theme Editor"));
g_signal_connect(G_OBJECT(editor.window), "delete-event",
G_CALLBACK(gfte_window_destroyed_cb), NULL);
editor.vbox = gtk_vbox_new(FALSE, 4);
gtk_container_add(GTK_CONTAINER(editor.window), editor.vbox);
gfte_build_toolbar();
editor.hbox = gtk_hbox_new(FALSE, 4);
gtk_box_pack_start(GTK_BOX(editor.vbox), editor.hbox, TRUE, TRUE, 0);
gfte_build_tree();
gfte_build_notebook();
}
/*******************************************************************************
* Basic helpers
******************************************************************************/
void
gfte_show() {
if(editor.window) {
gtk_window_present(GTK_WINDOW(editor.window));
return;
}
gfte_build_window();
gtk_widget_show_all(editor.window);
}
/*******************************************************************************
* Exports
******************************************************************************/
void
gf_theme_editor_init(PurplePlugin *plugin) {
plugin_handle = plugin;
}
void
gf_theme_editor_uninit() {
if(editor.window)
gtk_widget_destroy(editor.window);
gfte_cleanup();
editor.window = NULL;
}
void
gf_theme_editor_show(const gchar *filename) {
/* if filename is NULL a new theme is being created */
if(!filename) {
gfte_setup(NULL);
gfte_show();
return;
}
/* theme editor isn't showing so we create it */
if(!editor.window) {
gfte_setup(filename);
gfte_show();
return;
}
/* theme editor is showing, so we check the file names, if they match, we just show
* the editor. If they don't, we check if the theme is modified. If it is, then we
* show the modified dialog, and save it if the user wants it saved, and then open
* the other theme.
*/
if(editor.filename) {
if(!g_ascii_strcasecmp(editor.filename, filename)) {
gfte_show();
} else {
if(editor.changed)
gfte_modified_show(GFTE_MODIFIED_OPEN, filename);
else
gfte_setup(filename);
}
}
return;
}