grim/guifications2

This was compatibility code for Pidgin 1.x.y; because it was written as a check
for "not 2.0.0" this code would be compiled in for 3.0.0. It looks like the
supporting code elsewhere was removed, causing this to leave an unresolved
symbol in guifications.so, thus causing Pidgin to refuse to load. Now we load
in Pidgin 3.0.0. Whether it works or not, I have no clue.
/*
* 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;
}
/* This was yanked from gtk 2.4.x, it's a wrapper to support this function on gtk 2.0 */
static void
gfte_tree_view_expand_to_path(GtkTreeView *tree, GtkTreePath *path) {
#if GTK_CHECK_VERSION(2,2,0)
gtk_tree_view_expand_to_path(tree, path);
#else
gint i, depth;
gint *indices;
GtkTreePath *tmp;
g_return_if_fail(GTK_IS_TREE_VIEW(tree));
g_return_if_fail(path != NULL);
depth = gtk_tree_path_get_depth(path);
indices = gtk_tree_path_get_indices(path);
tmp = gtk_tree_path_new();
g_return_if_fail(tmp != NULL);
for(i = 0; i < depth; i++) {
gtk_tree_path_append_index(tmp, indices[i]);
gtk_tree_view_expand_row(tree, tmp, FALSE);
}
gtk_tree_path_free(tmp);
#endif /* GTK 2.0 */
}
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);
gfte_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) {
GfNotification *notification;
GList *l;
editor.theme = gf_theme_new_from_file(filename);
for(l = gf_theme_get_notifications(editor.theme); l; l = l->next) {
notification = GF_NOTIFICATION(l->data);
}
} 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();
gfte_store_get_row(&iter, &page, &item);
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);
/* 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);
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);
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);
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;
#if !GTK_CHECK_VERSION(2,2,0)
gchar *title;
gint page;
gpointer obj;
#endif /* !GTK_CHECK_VERSION(2,2,0) */
/* 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));
}
#if GTK_CHECK_VERSION(2,2,0)
gtk_tree_store_swap(editor.store, a, b);
#else
/* swap 'em */
title = a_title;
page = a_page;
obj = a_obj;
a_title = b_title;
a_page = b_page;
a_obj = b_obj;
b_title = title;
b_page = page;
b_obj = obj;
/* set 'em */
gtk_tree_store_set(editor.store, a,
GFTE_STORE_OBJECT, a_obj,
GFTE_STORE_PAGE, a_page,
GFTE_STORE_TITLE, a_title,
-1);
gtk_tree_store_set(editor.store, b,
GFTE_STORE_OBJECT, b_obj,
GFTE_STORE_PAGE, b_page,
GFTE_STORE_TITLE, b_title,
-1);
#endif /* GTK_CHECK_VERSION(2,2,0) */
/* 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;
gpointer object;
gchar *title;
gint page;
object = gfte_store_get_row(&child, &page, &title);
if(title)
g_free(title);
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;
gpointer object;
gchar *title;
gint page;
object = gfte_store_get_row(&child, &page, &title);
if(title)
g_free(title);
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, *help;
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);
help = 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;
}