/* * themebrowser.c: Theme browser * * Written by: Ullrich Hafner * * Copyright (C) 2000 Ullrich Hafner * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. */ /* * $Date: 2001/03/16 16:52:28 $ * $Author: hafner $ * $Revision: 1.4 $ * $State: Exp $ */ #include "config.h" #include #include "proplist_t.h" #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */ #if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION) # include # define NLENGTH(dirent) (strlen ((dirent)->d_name)) #else # define dirent direct # define NLENGTH(dirent) ((dirent)->d_namlen) # ifdef HAVE_SYS_NDIR_H # include # endif /* HAVE_SYS_NDIR_H */ # ifdef HAVE_SYS_DIR_H # include # endif /* HAVE_SYS_DIR_H */ # ifdef HAVE_NDIR_H # include # endif /* HAVE_NDIR_H */ #endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ #include #include #include #include #include #include "themebrowser.h" #include "dndtree.h" #include "rimage.h" #include "previews.h" #include "window.h" #include "path.h" #include "icons.h" #include "dialog.h" #include "misc.h" #include "error.h" /***************************************************************************** global variables *****************************************************************************/ extern proplist_t windowmaker; extern proplist_t wmconfig; extern GtkTooltips *tooltips; extern bool_t changed; extern GtkWidget *main_window; typedef struct themeinfo { bool_t istheme; GtkCTreeNode *parent; char *fullname; char *name; char *suffix; } themeinfo_t; typedef struct themerename { char *oldname; char *newname; } themerename_t; GtkCTree *tree = NULL; static GtkWidget *workspaceback = NULL; static GtkWidget *titlebarback = NULL; static GtkWidget *unfocus_titlebarback = NULL; static GtkWidget *parent_titlebarback = NULL; static GtkWidget *menutitleback = NULL; static GtkWidget *menuitemback = NULL; static GtkWidget *iconback = NULL; static proplist_t theme_keys = NULL; static bool_t previews_active = NO; static GtkWidget *preview_update_menu = NULL; /***************************************************************************** prototypes *****************************************************************************/ static void update_themes_timeout (char *filename); static void toggle_selection_mode (GtkWidget *widget, gpointer ptr); static void update_selection (GtkCList *themelist, gint row, gint column, GdkEvent *event, gpointer data); static void insert_dnd_elements (GtkCList *clist, const char *start); static void drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time); static void init_dnd (GtkWidget *widget); static gint insert_theme_files (GtkWidget *widget, gpointer ptr); static void cancel_installation (GtkWidget *widget, gpointer ptr); static void install_themes (GtkWidget *widget, gpointer ptr); static void open_theme_browser (GtkWidget *button, gpointer data); static void install_theme_dialog (GtkWidget *widget, gpointer ptr); static void remove_theme_dialog (GtkWidget *button, gpointer ptr); static void remove_theme (GtkWidget *widget, gpointer ptr); static void remove_file (gpointer data, gpointer user_data); static proplist_t get_color (proplist_t texture); static void compute_preview (GtkWidget *progress_bar, GtkWidget *progress_label, unsigned n, unsigned nelem, const char *name, unsigned width, unsigned height); static void free_memory (gpointer data, gpointer user_data); static void preview_dialog (GtkWidget *button, gpointer ptr); static void leave_preview (GtkWidget *button, gpointer ptr); static void set_theme (GtkWidget *button, gpointer ptr); static void load_theme (GtkWidget *button, gpointer ptr); static bool_t getstyle_call (const char *themename); static GList * remove_file_from_list (GList *list, const char *file); static GList * get_theme_files (const char *themename); static void save_theme_frontend (GtkWidget *widget, gpointer ptr); static void save_theme_backend (GtkWidget *widget, gpointer ptr); static void activate_themename (GtkWidget *widget, gpointer ptr); static void set_themename (GtkWidget *widget, gpointer ptr); static gint hide_window (GtkWidget *widget, gpointer ptr); static void save_theme_dialog (GtkWidget *widget, gpointer ptr); static GtkWidget * theme_preview (void); static char * theme_image_filename (const char *name, const char *attribute, bool_t combined); static void theme_gradient (const char *name, const char *attribute, GtkWidget *preview); static void select_theme (GtkCTree *tree, const char *text); static gint compare_themename (gconstpointer a, gconstpointer b); static void new_directory_dialog (GtkWidget *widget, gpointer ptr); static void new_directory_backend (GtkWidget *widget, gpointer ptr); static void select_directory_dialog (GtkWidget *button, gpointer data); static void info_destructor (gpointer data); static void set_node_text (GtkCTree *tree, GtkCTreeNode *node, const char *text); static void activate_button (GtkWidget *widget, gpointer ptr); static void rename_theme (GtkWidget *widget, gpointer ptr); static void rename_theme_backend (themerename_t *renameinfo); static void rename_theme_delete (GtkWidget *widget, gpointer ptr); GtkCTreeNode * get_selected_node (GtkCTree *tree); static void rename_theme_dialog (GtkWidget *widget, gpointer ptr); static gint context_menu (GtkCTree *ctree, GdkEventButton *event, gpointer ptr); static void selection_made (GtkCTree *ctree, GtkCTreeNode *node, gint column, gpointer data); static GtkCTreeNode * append_directory (const char *dirname, GtkCTree *tree, GtkCTreeNode *parent, GtkCTreeNode *sibling); static GtkCTreeNode * append_node (char *dirname, GtkCTree *tree, GtkCTreeNode *parent, GtkCTreeNode *sibling, bool_t theme); static gboolean node_drag_compare (GtkCTree *ctree, GtkCTreeNode *source_node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling); static void tree_moved (GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling); static void expand_recursive (GtkWidget *widget, gpointer ptr); static void collapse_recursive (GtkWidget *widget, gpointer ptr); /***************************************************************************** public code *****************************************************************************/ void generate_theme_menu (GtkMenu *themes_menu) { GtkWidget *item; item = gtk_menu_item_new_with_label (_("Install...")); gtk_menu_append (themes_menu, item); gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (install_theme_dialog), NULL); #ifdef GETSTYLE item = gtk_menu_item_new_with_label (_("Save...")); gtk_menu_append (themes_menu, item); gtk_signal_connect (GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC (save_theme_dialog), NULL); #endif /* GETSTYLE */ item = gtk_menu_item_new_with_label (_("Directory list...")); gtk_menu_append (themes_menu, item); gtk_widget_show (item); gtk_signal_connect (GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC (select_directory_dialog), NULL); item = gtk_menu_item_new_with_label (_("Update previews")); gtk_menu_append (themes_menu, item); gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (generate_previews), NULL); } GtkWidget * theme_browser (GtkWidget *box, bool_t section) /* * Generate theme dialog window: scrolled theme list, theme path list, * and action button box */ { GtkWidget *scrolled; GtkWidget *hbox; GtkWidget *vbox; /* * Scrolled window for ctree */ scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_container_set_border_width (GTK_CONTAINER (scrolled), 5); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); /* * Ctree to show the menu structure */ tree = gtk_dndtree_new (1, 0); gtk_object_set_user_data (GTK_OBJECT (tree), tree); gtk_clist_set_row_height (GTK_CLIST (tree), 18); gtk_clist_set_selection_mode (GTK_CLIST (tree), GTK_SELECTION_BROWSE); gtk_clist_set_column_auto_resize (GTK_CLIST (tree), 0, TRUE); gtk_ctree_set_line_style (GTK_CTREE (tree), GTK_CTREE_LINES_DOTTED); gtk_ctree_set_drag_compare_func (GTK_CTREE (tree), node_drag_compare); gtk_signal_connect (GTK_OBJECT (tree), "tree_move", GTK_SIGNAL_FUNC (tree_moved), NULL); gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (tree)); build_theme_list (); gtk_signal_connect (GTK_OBJECT(tree), "tree_select_row", GTK_SIGNAL_FUNC (selection_made), NULL); gtk_signal_connect (GTK_OBJECT (tree), "button_press_event", GTK_SIGNAL_FUNC (context_menu), NULL); /* * Horizontal container (tree, theme info) */ hbox = gtk_hbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0); { GtkWidget *button; button = gtk_check_button_new_with_label (_("Single selection with " "drag and drop")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (toggle_selection_mode), tree); gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); } gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); vbox = gtk_vbox_new (TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), theme_preview (), FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, TRUE, TRUE, 0); gtk_widget_show_all (hbox); return hbox; } void build_theme_list (void) /* * Build theme list by scanning the directories of ThemePath. * * No return value. * * Side effects: * Old tree is discarded and new tree elements are added. */ { proplist_t pltheme = WMCreatePLString ("ThemePath"); proplist_t dirlist = WMGetFromPLDictionary (windowmaker, pltheme); GtkCTreeNode *sibling = NULL; unsigned n; WMReleasePropList (pltheme); gtk_clist_freeze (GTK_CLIST (tree)); gtk_clist_clear (GTK_CLIST (tree)); for (n = 0; n < WMGetPropListItemCount (dirlist); n++) { proplist_t pldir = WMGetFromPLArray (dirlist, n); char *dirname = expand_tilde (WMGetFromPLString (pldir)); sibling = append_directory (dirname, GTK_CTREE (tree), NULL, sibling); gtk_ctree_sort_recursive (GTK_CTREE (tree), sibling); } gtk_clist_thaw (GTK_CLIST (tree)); gtk_ctree_select (tree, gtk_ctree_node_nth (tree, 0)); } /***************************************************************************** preview generation *****************************************************************************/ void generate_previews (GtkWidget *button, gpointer ptr) { GList *background_list = NULL; GList *titlebar_list = NULL; GList *icons_list = NULL; unsigned row; previews_active = YES; if (preview_update_menu) gtk_widget_set_sensitive (preview_update_menu, FALSE); /* * Append image filenames in lists one for icons, titlebars and background */ for (row = 0; row < (unsigned) GTK_CLIST (tree)->rows; row++) { GtkCTreeNode *theme = gtk_ctree_node_nth (tree, row); themeinfo_t *info = gtk_ctree_node_get_row_data (tree, theme); if (info->istheme) { char *filename; filename = theme_image_filename (info->fullname, "WorkspaceBack", NO); if (filename) background_list = g_list_append (background_list, filename); filename = theme_image_filename (info->fullname, "IconBack", NO); if (filename) titlebar_list = g_list_append (titlebar_list, filename); filename = theme_image_filename (info->fullname, "FTitleBack", NO); if (filename) icons_list = g_list_append (icons_list, filename); filename = theme_image_filename (info->fullname, "UTitleBack", NO); if (filename) icons_list = g_list_append (icons_list, filename); filename = theme_image_filename (info->fullname, "PTitleBack", NO); if (filename) icons_list = g_list_append (icons_list, filename); filename = theme_image_filename (info->fullname, "MenuTitleBack", NO); if (filename) icons_list = g_list_append (icons_list, filename); filename = theme_image_filename (info->fullname, "MenuTextBack", NO); if (filename) icons_list = g_list_append (icons_list, filename); } } /* * Update each of the images */ { GtkWidget *progress_window; GtkWidget *progress_label; GtkWidget *progress_bar; GtkWidget *vbox; /* * Generate a progressbar and window */ progress_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_position (GTK_WINDOW (progress_window), GTK_WIN_POS_MOUSE); gtk_window_set_title (GTK_WINDOW (progress_window), _("Update previews")); gtk_signal_connect (GTK_OBJECT (progress_window), "delete_event", GTK_SIGNAL_FUNC (gtk_true), NULL); gtk_widget_set_usize (progress_window, 250, -1); vbox = gtk_vbox_new (FALSE, 5); gtk_container_add (GTK_CONTAINER (progress_window), vbox); gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); progress_label = gtk_label_new (_("Update previews")); gtk_box_pack_start (GTK_BOX (vbox), progress_label, FALSE, TRUE, 0); { GtkAdjustment *adj; adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 300, 0, 0, 0); progress_bar = gtk_progress_bar_new_with_adjustment (adj); } gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 5); gtk_widget_show_all (progress_window); { GList **listptr = (GList **) ptr; int n; int m = g_list_length (background_list) + g_list_length (titlebar_list) + g_list_length (icons_list); if (listptr && *listptr) m += g_list_length (*listptr); for (n = 0; n < (int) g_list_length (background_list); n++) compute_preview (progress_bar, progress_label, n, m, g_list_nth_data (background_list, n), 160, 120); for (n = 0; n < (int) g_list_length (titlebar_list); n++) compute_preview (progress_bar, progress_label, n + g_list_length (background_list), m, g_list_nth_data (titlebar_list, n), 64, 64); for (n = 0; n < (int) g_list_length (icons_list); n++) compute_preview (progress_bar, progress_label, n + g_list_length (background_list) + g_list_length (titlebar_list), m, g_list_nth_data (icons_list, n), 234, 22); if (listptr && *listptr) { GList *list = *listptr; for (n = 0; n < (int) g_list_length (list); n++) { previewdata_t *pd = g_list_nth_data (list, n); char *pname = preview_name (pd->name); char *path = get_pixmap_path (pname); if (!path) { compute_preview (progress_bar, progress_label, n + g_list_length (background_list) + g_list_length (titlebar_list) + g_list_length (icons_list), m, pd->name, 64, 64); path = get_pixmap_path (pname); } if (path) { GtkWidget *pixmap; pixmap = gtk_object_get_user_data (GTK_OBJECT (pd->button)); make_pixmap (path, 64, 64, pixmap); Free (path); } Free (pname); } } } gtk_widget_destroy (progress_window); } g_list_foreach (background_list, free_memory, NULL); g_list_free (background_list); g_list_foreach (titlebar_list, free_memory, NULL); g_list_free (titlebar_list); g_list_foreach (icons_list, free_memory, NULL); g_list_free (icons_list); previews_active = NO; if (preview_update_menu) gtk_widget_set_sensitive (preview_update_menu, TRUE); } bool_t load_attributes (const char *filename, const char *path) /* * Load attributes from a file 'filename' in directory 'path'. * * Return value: * true on success */ { static char * deprecated_keys[] = { "DisplayFont" }; proplist_t theme = read_proplist (filename); if (theme) { unsigned n; proplist_t keys; proplist_t plupdate = WMCreatePLString ("Update"); proplist_t plupdateptr = WMCreatePLString ("UpdatePtr"); /* * Remove deprecated keys from style */ for (n = 0; n < sizeof (deprecated_keys) / sizeof (char *); n++) { proplist_t depkeypl = WMCreatePLString (deprecated_keys[n]); if (WMGetFromPLDictionary (theme, depkeypl)) WMRemoveFromPLDictionary (theme, depkeypl); WMReleasePropList (depkeypl); } /* * Modify style file that doesn't contain resizebarback */ { proplist_t rsbpl = WMCreatePLString ("ResizebarBack"); proplist_t resizebar = WMGetFromPLDictionary (theme, rsbpl); if (!resizebar) { proplist_t utitle = WMCreatePLString ("UTitleBack"); proplist_t tmp = WMGetFromPLDictionary (theme, utitle); WMReleasePropList (utitle); if (tmp) { proplist_t color = get_color (tmp); if (color) { proplist_t array; array = WMCreatePLArray (WMCreatePLString ("solid"), WMRetainPropList (color), NULL); WMPutInPLDictionary (theme, rsbpl, array); WMReleasePropList (array); } } } WMReleasePropList (rsbpl); } /* * Modify style file that doesn't contain iconbarback */ { proplist_t icontitle = WMCreatePLString ("IconTitleColor"); proplist_t iconback = WMCreatePLString ("IconTitleBack"); proplist_t iconpl = WMGetFromPLDictionary (theme, icontitle); if (!iconpl) iconpl = WMGetFromPLDictionary (theme, iconback); if (!iconpl) { proplist_t ftitle = WMCreatePLString ("FTitleColor"); proplist_t fback = WMCreatePLString ("FTitleBack"); proplist_t tmp = WMGetFromPLDictionary (theme, ftitle); WMReleasePropList (ftitle); if (tmp) WMPutInPLDictionary (theme, icontitle, tmp); tmp = WMGetFromPLDictionary (theme, fback); WMReleasePropList (fback); if (tmp) { proplist_t color = get_color (tmp); if (color) WMPutInPLDictionary (theme, iconback, color); } } WMReleasePropList (icontitle); WMReleasePropList (iconback); } keys = WMGetPLDictionaryKeys (theme) ; for (n = 0; n < WMGetPropListItemCount (keys); n++) { proplist_t key = WMGetFromPLArray (keys, n); proplist_t value = WMGetFromPLDictionary (theme, key); proplist_t keydef = WMGetFromPLDictionary (wmconfig, key); if (keydef) { proplist_t keydata; proplist_t keyupdate; keydata = WMGetFromPLDictionary (keydef, plupdateptr); keyupdate = WMGetFromPLDictionary (keydef, plupdate); if (keyupdate && keydata) { gpointer data; update_fct update; data = * (gpointer *) WMGetPLDataBytes (keydata); update = * (update_fct *) WMGetPLDataBytes (keyupdate); update (key, data, value, path); } else warning (_("Attribute %s not yet supported."), WMGetFromPLString (key)); } else warning (_("Attribute %s not yet supported."), WMGetFromPLString (key)); } WMReleasePropList (plupdateptr); WMReleasePropList (plupdate); WMReleasePropList (keys); WMReleasePropList (theme); return TRUE; } else return FALSE; } void connect_update_function (proplist_t key, gpointer ptr, update_fct update) /* * Connect an 'update' function with the current 'key' and * generic datapointer 'ptr'. * * Side effects: * wmconfig dictionary Update and UpdatePtr are set */ { proplist_t plupdate = WMCreatePLString ("Update"); proplist_t plupdateptr = WMCreatePLString ("UpdatePtr"); proplist_t keydef = WMGetFromPLDictionary (wmconfig, key); proplist_t data; data = WMCreatePLDataWithBytes ((unsigned char *) &ptr, sizeof (gpointer)); WMPutInPLDictionary (keydef, plupdateptr, data); WMReleasePropList (data); data = WMCreatePLDataWithBytes ((unsigned char *) &update, sizeof (update_fct)); WMPutInPLDictionary (keydef, plupdate, data); WMReleasePropList (data); WMReleasePropList (plupdateptr); WMReleasePropList (plupdate); } /***************************************************************************** private code *****************************************************************************/ static void toggle_selection_mode (GtkWidget *widget, gpointer ptr) /* * Toggle confirm panel when using the EXIT or SHUTDOWN command. */ { GtkCTree *tree = GTK_CTREE (ptr); if (GTK_TOGGLE_BUTTON (widget)->active) { gtk_clist_set_selection_mode (GTK_CLIST (tree), GTK_SELECTION_BROWSE); gtk_clist_set_reorderable (GTK_CLIST (tree), TRUE); } else { gtk_clist_set_selection_mode (GTK_CLIST (tree), GTK_SELECTION_EXTENDED); gtk_clist_set_reorderable (GTK_CLIST (tree), FALSE); } } static gint context_menu (GtkCTree *ctree, GdkEventButton *event, gpointer ptr) /* * Popup context menu (right click) * * Return value: * TRUE show popup menu * FALSE don't show popup menu */ { gint row; gint column; GtkCTreeNode *selection; bool_t single_selection = NO; bool_t istheme = NO; bool_t toplevel = NO; if (!gtk_clist_get_selection_info (GTK_CLIST (ctree), event->x, event->y, &row, &column) || event->button != 3) return FALSE; selection = get_selected_node (tree); single_selection = selection != NULL; if (single_selection) { themeinfo_t *info = gtk_ctree_node_get_row_data (tree, selection); istheme = info->istheme; toplevel = !info->parent; } else istheme = NO; { static GtkWidget *menu = NULL; GtkWidget *menu_item; if (menu) gtk_widget_destroy (menu); menu = gtk_menu_new (); #ifdef GETSTYLE if (istheme) { menu_item = gtk_menu_item_new_with_label (_("Open")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (load_theme), NULL); } #endif /* GETSTYLE */ if (single_selection && !toplevel) { menu_item = gtk_menu_item_new_with_label (_("Rename...")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (rename_theme_dialog), ctree); } #ifdef GETSTYLE if (single_selection) { menu_item = gtk_menu_item_new_with_label (_("Save...")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (save_theme_dialog), NULL); } #endif /* GETSTYLE */ if (!toplevel) { menu_item = gtk_menu_item_new_with_label (_("Remove...")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (remove_theme_dialog), NULL); } if (single_selection && !toplevel) { menu_item = gtk_menu_item_new_with_label (_("New directory...")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (new_directory_dialog), ctree); } #ifdef GETSTYLE # ifdef SETSTYLE if (!single_selection || istheme) { menu_item = gtk_menu_item_new (); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); menu_item = gtk_menu_item_new_with_label (_("Preview")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (preview_dialog), NULL); } # endif /* SETSTYLE */ #endif /* GETSTYLE */ #ifdef GETSTYLE if (istheme) { menu_item = gtk_menu_item_new_with_label (_("Set")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (set_theme), NULL); } #endif /* GETSTYLE */ menu_item = gtk_menu_item_new (); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); menu_item = gtk_menu_item_new_with_label (_("Install...")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (install_theme_dialog), NULL); menu_item = gtk_menu_item_new_with_label (_("Directory list...")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (select_directory_dialog), NULL); menu_item = gtk_menu_item_new_with_label (_("Expand directory tree")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (expand_recursive), NULL); menu_item = gtk_menu_item_new_with_label (_("Collapse directory tree")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (collapse_recursive), NULL); #ifdef PREVIEWS preview_update_menu = menu_item = gtk_menu_item_new_with_label (_("Update previews")); gtk_menu_append (GTK_MENU (menu), menu_item); gtk_widget_show (menu_item); gtk_signal_connect (GTK_OBJECT(menu_item), "activate", GTK_SIGNAL_FUNC (generate_previews), NULL); gtk_widget_set_sensitive (preview_update_menu, !previews_active); #endif /* PREVIEWS */ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time); } return TRUE; } /***************************************************************************** build theme tree *****************************************************************************/ static GtkCTreeNode * append_directory (const char *dirname, GtkCTree *tree, GtkCTreeNode *parent, GtkCTreeNode *sibling) /* * Append a new theme directory 'dirname' in theme 'tree'. * Position of entry is given by 'parent' and 'sibling'. * * Return Value: * new tree node */ { DIR *dir = opendir (dirname); if (!dir) return NULL; else { GtkCTreeNode *root; GtkCTreeNode *rootsibling = NULL; if (parent) root = append_node ((char *) g_basename (dirname), tree, parent, sibling, NO); else root = append_node ((char *) dirname, tree, parent, sibling, NO); /* * Insert themes and subdirs */ { struct dirent *file; while ((file = readdir (dir))) { if (streq (file->d_name, ".") || streq (file->d_name, "..")) continue; /* * Check whether filename is .themed directory */ { char *path = g_strconcat (dirname, "/", file->d_name, NULL); DIR *subdir = opendir (path); char *ext; if (subdir) /* .themed or subdir */ { if (!strstr (path, ".themed")) { sibling = append_directory (path, tree, root, sibling); Free (path); continue; } closedir (subdir); } ext = strrchr (path, '.'); if (ext && (streq (ext, ".tar") || streq (ext, ".gz") || streq (ext, ".tgz") || streq (ext, ".bz2"))) { Free (path); continue; } sibling = append_node (file->d_name, tree, root, rootsibling, YES); Free (path); } } } closedir (dir); return root; } } static GtkCTreeNode * append_node (char *dirname, GtkCTree *tree, GtkCTreeNode *parent, GtkCTreeNode *sibling, bool_t theme) /* * Append a new tree node with text 'dirname' in theme 'tree'. * Position of entry is given by 'parent' and 'sibling'. * 'theme' defines whether the file is a theme (YES) or dir (NO). * * Return Value: * new tree node */ { char *old; guint8 spacing; GdkPixmap *closed, *opened; GdkBitmap *mask_closed, *mask_opened; gboolean is_leaf, expanded; GtkCTreeNode *root; themeinfo_t *info = Calloc (1, sizeof (themeinfo_t)); if (parent) { themeinfo_t *pinfo = gtk_ctree_node_get_row_data (tree, parent); info->fullname = g_strconcat (pinfo->fullname, "/", dirname, NULL); } else info->fullname = g_strdup (dirname); info->istheme = theme; info->parent = parent; info->suffix = NULL; root = gtk_ctree_insert_node (tree, parent, sibling, &dirname, 8, NULL, NULL, NULL, NULL, FALSE, theme ? FALSE : TRUE); gtk_ctree_get_node_info (tree, root, &old, &spacing, &closed, &mask_closed, &opened, &mask_opened, &is_leaf, &expanded); if (theme) { char *new = g_strdup (dirname); if (strlen (new) > strlen (".themed") && streq (new + strlen (new) - strlen (".themed"), ".themed")) { info->suffix = g_strdup (".themed"); *(new + strlen (new) - strlen (".themed")) = 0; } if (strlen (new) > strlen (".style") && streq (new + strlen (new) - strlen (".style"), ".style")) { info->suffix = g_strdup (".style"); *(new + strlen (new) - strlen (".style")) = 0; } info->name = g_strdup (new); gtk_ctree_set_node_info (tree, root, new, 8, p_array [P_GNUSTEP].pixmap, p_array [P_GNUSTEP].mask, NULL, NULL, FALSE, expanded); g_free (new); } else { info->name = g_strdup (dirname); gtk_ctree_set_node_info (tree, root, dirname, 8, p_array [P_BOOK_CLOSE].pixmap, p_array [P_BOOK_CLOSE].mask, p_array [P_BOOK_OPEN].pixmap, p_array [P_BOOK_OPEN].mask, FALSE, expanded); } gtk_ctree_node_set_row_data_full (tree, root, info, info_destructor); return root; } static void info_destructor (gpointer data) /* * Cleanup memory of theme information structure. */ { themeinfo_t *info = (themeinfo_t *) data; if (info->name) Free (info->name); if (info->suffix) Free (info->suffix); Free (info); } /***************************************************************************** miscellaneous operations *****************************************************************************/ static void expand_recursive (GtkWidget *widget, gpointer ptr) { gtk_ctree_expand_recursive (tree, NULL); } static void collapse_recursive (GtkWidget *widget, gpointer ptr) { gtk_ctree_collapse_recursive (tree, NULL); } static gboolean node_drag_compare (GtkCTree *tree, GtkCTreeNode *source_node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling) /* * Check whether dragged theme or directory can be dragged at current * position. * * Return Value: * TRUE if drag is allowed, FALSE otherwise */ { if (!new_parent) return FALSE; else { themeinfo_t *info = gtk_ctree_node_get_row_data (tree, source_node); themeinfo_t *pinfo = gtk_ctree_node_get_row_data (tree, new_parent); if (!info->parent) return FALSE; if (pinfo->istheme) return FALSE; if (info->parent != new_parent) return TRUE; else return FALSE; } } GtkCTreeNode * get_selected_node (GtkCTree *tree) /* * Get selected tree node. * * Return value: * selected node on success * NULL otherwise */ { GList *selection = GTK_CLIST (tree)->selection; if (!GTK_CLIST (tree)->selection || g_list_length (selection) != 1) return NULL; else return g_list_nth_data (selection, 0); } static void select_theme (GtkCTree *tree, const char *text) /* * Select a theme given by the specified filename (position: middle of screen) * * No return value. */ { GtkCTreeNode *current; current = gtk_ctree_find_by_row_data_custom (tree, NULL, (gpointer) text, compare_themename); if (current) { gtk_ctree_select (tree, current); gtk_ctree_node_moveto (tree, current, 0, 0.5, 0); } } static gint compare_themename (gconstpointer a, gconstpointer b) /* * Check whether the theme date pointer filename is equal to string 'b'. * * Return value: * 0 strings are equal * otherwise continue search */ { themeinfo_t *info = (themeinfo_t *) a; const char *text = (const char *) b; return !streq (info->fullname, text); } static void activate_button (GtkWidget *widget, gpointer ptr) /* * Simulate a button click. * * No return value. */ { gtk_signal_emit_by_name (GTK_OBJECT (ptr), "clicked"); } static void set_node_text (GtkCTree *tree, GtkCTreeNode *node, const char *text) /* * Set text of theme (tree node). */ { char *old; guint8 spacing; GdkPixmap *closed, *opened; GdkBitmap *mask_closed, *mask_opened; gboolean is_leaf, expanded; gtk_ctree_get_node_info (tree, node, &old, &spacing, &closed, &mask_closed, &opened, &mask_opened, &is_leaf, &expanded); gtk_ctree_set_node_info (tree, node, text, spacing, closed, mask_closed, opened, mask_opened, is_leaf, expanded); } /***************************************************************************** rename theme operation *****************************************************************************/ static void rename_theme_dialog (GtkWidget *widget, gpointer ptr) /* * Dialog window to rename theme file or directory. * * No return value. */ { GtkCTree *tree = (GtkCTree *) ptr; GtkCTreeNode *selection = get_selected_node (tree); themeinfo_t *info; if (!selection) return; info = gtk_ctree_node_get_row_data (tree, selection); /* * Dialog window */ { GtkWidget *window = gtk_dialog_new (); GtkWidget *vbox = gtk_vbox_new (FALSE, 0); GtkWidget *entry = gtk_entry_new (); char *text; gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0); /* * Window */ gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); gtk_window_set_title (GTK_WINDOW (window), _("Rename theme")); gtk_signal_connect_object (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); /* * Label and entry */ if (info->suffix && streq (info->suffix, ".themed")) text = g_strdup_printf (_("Rename theme directory `%s' to:"), info->name); else { if (info->istheme) text = g_strdup_printf (_("Rename theme file `%s' to:"), info->name); else text = g_strdup_printf (_("Rename directory `%s' to:"), info->name); } gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (text), TRUE, TRUE, 0); g_free (text); gtk_entry_set_text (GTK_ENTRY (entry), info->name); gtk_entry_select_region (GTK_ENTRY (entry), 0, -1); gtk_object_set_user_data (GTK_OBJECT (entry), info); gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); gtk_widget_grab_focus (entry); /* * Cancel and OK buttons */ { GtkWidget *hbox = gtk_hbutton_box_new (); GtkWidget *button; gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbox), 5); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, FALSE, TRUE, 5); button = gtk_button_new_with_label (_("OK")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 5); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (rename_theme), entry); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); gtk_signal_connect (GTK_OBJECT (entry), "activate", GTK_SIGNAL_FUNC (activate_button), button); button = gtk_button_new_with_label (_("Cancel")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 5); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); } gtk_grab_add (window); gtk_widget_show_all (window); } } static void rename_theme (GtkWidget *widget, gpointer ptr) /* * Rename selected theme. * Computes old and new filename and checks whether file already exists. * * No return value. */ { GtkEntry *entry = (GtkEntry *) ptr; themeinfo_t *info = gtk_object_get_user_data (GTK_OBJECT (entry)); GtkCTreeNode *parent = info->parent; themeinfo_t *parentinfo = gtk_ctree_node_get_row_data (tree, parent); char *oldname = g_strconcat (parentinfo->name, "/", info->name, info->suffix, NULL); char *newname = g_strconcat (parentinfo->name, "/", gtk_entry_get_text (entry), info->suffix, NULL); themerename_t *renameinfo = Calloc (1, sizeof (themerename_t)); renameinfo->oldname = oldname; renameinfo->newname = newname; if (!streq (oldname, newname)) { if (file_exists (newname)) dialog_popup (DIALOG_QUESTION, rename_theme_delete, renameinfo, _("Overwrite existing theme\n`%s'"), newname); else rename_theme_backend (renameinfo); } else { Free (renameinfo->newname); Free (renameinfo->oldname); Free (renameinfo); } } static void rename_theme_backend (themerename_t *renameinfo) /* * Actually performs the rename operation. If successful, the tree * list is computed again. */ { if (!rename_file_or_dir (renameinfo->oldname, renameinfo->newname)) { build_theme_list (); select_theme (tree, renameinfo->newname); } Free (renameinfo->newname); Free (renameinfo->oldname); Free (renameinfo); } static void rename_theme_delete (GtkWidget *widget, gpointer ptr) /* * Overwrite old theme. */ { themerename_t *renameinfo = (themerename_t *) ptr; if (!remove_directory (renameinfo->newname)) rename_theme_backend (renameinfo); else { Free (renameinfo->newname); Free (renameinfo->oldname); Free (renameinfo); } } /***************************************************************************** remove themes (files and dirs) *****************************************************************************/ static void remove_theme_dialog (GtkWidget *button, gpointer ptr) { GList *selection = GTK_CLIST (tree)->selection; if (!GTK_CLIST (tree)->selection || g_list_length (selection) < 1) return; else { GtkWidget *window; GtkBox *vbox; window = gtk_dialog_new (); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); vbox = GTK_BOX (GTK_DIALOG (window)->vbox); gtk_window_set_title (GTK_WINDOW (window), _("Remove themes")); gtk_signal_connect_object (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); { gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (""), FALSE, TRUE, 0); { GList *selection = GTK_CLIST (tree)->selection; unsigned n; if (g_list_length (selection) > 1 && g_list_length (selection) < 8) { gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (_("Remove files and directories of themes")), FALSE, TRUE, 0); for (n = 0; n < g_list_length (selection); n++) { GtkCTreeNode *theme = g_list_nth_data (selection, n); themeinfo_t *info = gtk_ctree_node_get_row_data (tree, theme); if (info->parent) gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (info->name), FALSE, TRUE, 0); } } else if (g_list_length (selection) == 1) { GtkCTreeNode *theme = g_list_nth_data (selection, 0); themeinfo_t *info = gtk_ctree_node_get_row_data (tree, theme); char *text; text = g_strdup_printf (_("Remove files and directories " "of theme `%s'"), info->name); gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (text), FALSE, TRUE, 0); Free (text); } else { gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (_("Remove files and directories of selected themes")), FALSE, TRUE, 0); } } gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (""), FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (_("Select individual files and directories:")), FALSE, TRUE, 0); } { GtkWidget *filelist = gtk_clist_new (1); gtk_clist_set_auto_sort (GTK_CLIST (filelist), YES); gtk_clist_set_column_auto_resize (GTK_CLIST (filelist), 0, YES); gtk_clist_column_titles_passive (GTK_CLIST (filelist)); gtk_clist_set_selection_mode (GTK_CLIST (filelist), GTK_SELECTION_EXTENDED); { GtkWidget *scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_container_set_border_width (GTK_CONTAINER (scrolled), 5); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (scrolled), filelist); gtk_box_pack_start (vbox, scrolled, TRUE, TRUE, 0); gtk_widget_set_usize (scrolled, 550, 350); } /* * Buttons */ { GtkWidget *hbox = gtk_hbutton_box_new (); GtkWidget *button; gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, TRUE, TRUE, 0); gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbox), 5); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); button = gtk_button_new_with_label (_("Remove")); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (remove_theme), filelist); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); button = gtk_button_new_with_label (_("Cancel")); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); } /* * List of Files */ { unsigned n; GList *selection = GTK_CLIST (tree)->selection; for (n = 0; n < g_list_length (selection); n++) { GtkCTreeNode *theme = g_list_nth_data (selection, n); themeinfo_t *info = gtk_ctree_node_get_row_data (tree, theme); if (!info->parent) continue; gtk_clist_insert (GTK_CLIST (filelist), -1, &info->fullname); if (info->suffix && streq (info->suffix, ".themed")) { DIR *themedir = opendir (info->fullname); if (themedir) { struct dirent *file; while ((file = readdir (themedir))) { if (!streq (file->d_name, ".") && !streq (file->d_name, "..")) { char *tmp = g_strconcat (info->fullname, "/", file->d_name, NULL); gtk_clist_insert (GTK_CLIST (filelist), -1, &tmp); Free (tmp); } } closedir (themedir); } } else { const char *attr[] = {"WorkspaceBack", "IconBack", "FTitleBack", "UTitleBack", "PTitleBack", "MenuTitleBack", "MenuTextBack"}; unsigned n; for (n = 0; n < sizeof (attr) / sizeof (attr [0]); n++) { char *name = theme_image_filename (info->fullname, attr [n], NO); if (name) { char *pname = preview_name (name); char *path = get_pixmap_path (pname); gtk_clist_insert (GTK_CLIST (filelist), -1, &name); if (path) { gtk_clist_insert (GTK_CLIST (filelist), -1, &path); Free (path); } Free (pname); Free (name); } } } } } gtk_clist_select_all (GTK_CLIST (filelist)); gtk_widget_show_all (window); } } } static void remove_theme (GtkWidget *widget, gpointer ptr) /* * Actually remove theme files */ { GtkCList *filelist = GTK_CLIST (ptr); GList *list = g_list_reverse (filelist->selection); g_list_foreach (list, remove_file, filelist); build_theme_list (); } static void remove_file (gpointer data, gpointer user_data) /* * Remove a file */ { GtkCList *filelist = GTK_CLIST (user_data); gint row = GPOINTER_TO_INT (data); char *path; gtk_clist_get_text (filelist, row, 0, &path); delete_file_or_dir (path); } /***************************************************************************** new directory operation *****************************************************************************/ static void new_directory_dialog (GtkWidget *widget, gpointer ptr) { GtkCTree *tree = (GtkCTree *) ptr; GtkCTreeNode *selection = get_selected_node (tree); themeinfo_t *info; themeinfo_t *pinfo; if (!selection) return; info = gtk_ctree_node_get_row_data (tree, selection); assert (info->parent); pinfo = gtk_ctree_node_get_row_data (tree, info->parent); /* * Dialog window */ { GtkWidget *window = gtk_dialog_new (); GtkWidget *vbox = gtk_vbox_new (FALSE, 0); GtkWidget *entry = gtk_entry_new (); char *text; gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0); /* * Window */ gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); gtk_window_set_title (GTK_WINDOW (window), _("New directory")); gtk_signal_connect_object (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); text = g_strdup_printf (_("Make new subdirectory in\n`%s':"), pinfo->fullname); gtk_object_set_user_data (GTK_OBJECT (entry), pinfo); gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (text), TRUE, TRUE, 0); g_free (text); gtk_entry_select_region (GTK_ENTRY (entry), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0); gtk_widget_grab_focus (entry); /* * Cancel and OK buttons */ { GtkWidget *hbox = gtk_hbutton_box_new (); GtkWidget *button; gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbox), 5); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, FALSE, TRUE, 5); button = gtk_button_new_with_label (_("OK")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 5); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (new_directory_backend), entry); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); gtk_signal_connect (GTK_OBJECT (entry), "activate", GTK_SIGNAL_FUNC (activate_button), button); button = gtk_button_new_with_label (_("Cancel")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 5); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); } gtk_grab_add (window); gtk_widget_show_all (window); } } static void new_directory_backend (GtkWidget *widget, gpointer ptr) /* * Actually performs the mkdir operation. If successful, the tree * list is computed again. */ { GtkEntry *entry = (GtkEntry *) ptr; themeinfo_t *info = gtk_object_get_user_data (GTK_OBJECT (entry)); char *directory = g_strdup(gtk_entry_get_text (entry)); if (info) directory = g_strconcat (info->fullname, "/", directory, NULL); if (!make_directory (directory)) { build_theme_list (); select_theme (tree, directory); } if (info) Free (directory); } static void select_directory_dialog (GtkWidget *button, gpointer data) /* * Dialog window to add a new toplevel directory. * * No return value. */ { GtkWidget *window = gtk_dialog_new (); GtkWidget *vbox = gtk_vbox_new (FALSE, 0); proplist_t pltheme = WMCreatePLString ("ThemePath"); proplist_t plinfo = WMCreatePLString ("Info"); proplist_t keydef = WMGetFromPLDictionary (wmconfig, pltheme); proplist_t array = WMGetFromPLDictionary (windowmaker, pltheme); proplist_t info = WMGetFromPLDictionary (keydef, plinfo); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0); /* * Window */ gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); gtk_widget_set_usize (window, 550, -1); gtk_window_set_title (GTK_WINDOW (window), _("Toplevel theme directory list")); gtk_signal_connect_object (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); path_dialog (vbox, pltheme, array, tooltips, info); /* * Close button */ { GtkWidget *hbox = gtk_hbutton_box_new (); GtkWidget *button; gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbox), 5); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, FALSE, TRUE, 5); button = gtk_button_new_with_label (_("Close")); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 5); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_widget_grab_default (button); } gtk_widget_show_all (window); } /***************************************************************************** theme preview window *****************************************************************************/ static GtkWidget * theme_preview (void) { GtkWidget *frame = gtk_frame_new (_("Preview")); GtkWidget *hbox = gtk_hbox_new (FALSE, 0); GtkWidget *vbox = gtk_vbox_new (FALSE, 0); GtkWidget *ibox; gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); ibox = gtk_vbox_new (FALSE, 0); workspaceback = make_pixmap (PKGDATADIR "/black.xpm", 160, 120, NULL); gtk_box_pack_start (GTK_BOX (hbox), ibox, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (ibox), workspaceback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 5); ibox = gtk_vbox_new (FALSE, 0); iconback = make_pixmap (PKGDATADIR "/black.xpm", 64, 64, NULL); gtk_box_pack_start (GTK_BOX (hbox), ibox, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (ibox), iconback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 5); ibox = gtk_vbox_new (FALSE, 0); titlebarback = make_pixmap (PKGDATADIR "/black.xpm", 234, 22, NULL); gtk_box_pack_start (GTK_BOX (ibox), gtk_label_new (_("Focused titlebar")), FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), ibox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (ibox), titlebarback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 0); ibox = gtk_vbox_new (FALSE, 0); unfocus_titlebarback = make_pixmap (PKGDATADIR "/black.xpm", 234, 22, NULL); gtk_box_pack_start (GTK_BOX (ibox), gtk_label_new (_("Unfocused titlebar")), FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), ibox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (ibox), unfocus_titlebarback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 0); ibox = gtk_vbox_new (FALSE, 0); parent_titlebarback = make_pixmap (PKGDATADIR "/black.xpm", 234, 22, NULL); gtk_box_pack_start (GTK_BOX (ibox), gtk_label_new (_("Parent titlebar")), FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), ibox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (ibox), parent_titlebarback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 0); ibox = gtk_vbox_new (FALSE, 0); menutitleback = make_pixmap (PKGDATADIR "/black.xpm", 234, 22, NULL); gtk_box_pack_start (GTK_BOX (ibox), gtk_label_new (_("Menutitle")), FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), ibox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (ibox), menutitleback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 0); ibox = gtk_vbox_new (FALSE, 0); menuitemback = make_pixmap (PKGDATADIR "/black.xpm", 234, 22, NULL); gtk_box_pack_start (GTK_BOX (ibox), gtk_label_new (_("Menuitem")), FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), ibox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (ibox), menuitemback, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (ibox), 0); gtk_widget_show_all (frame); return frame; } static void selection_made (GtkCTree *tree, GtkCTreeNode *selection, gint column, gpointer data) /* * Update preview after new tree item has been selected. * * No return value. */ { themeinfo_t *info = gtk_ctree_node_get_row_data (tree, selection); if (!info) return; if (!get_selected_node (tree)) return; if (info->istheme) { char *filename; filename = theme_image_filename (info->fullname, "WorkspaceBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 160, 120, workspaceback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "WorkspaceBack", workspaceback); filename = theme_image_filename (info->fullname, "IconBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 64, 64, iconback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "IconBack", iconback); filename = theme_image_filename (info->fullname, "FTitleBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 234, 22, titlebarback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "FTitleBack", titlebarback); filename = theme_image_filename (info->fullname, "UTitleBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 234, 22, unfocus_titlebarback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "UTitleBack", unfocus_titlebarback); filename = theme_image_filename (info->fullname, "PTitleBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 234, 22, parent_titlebarback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "PTitleBack", parent_titlebarback); filename = theme_image_filename (info->fullname, "MenuTitleBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 234, 22, menutitleback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "MenuTitleBack", menutitleback); filename = theme_image_filename (info->fullname, "MenuTextBack", NO); if (filename) { char *pname = preview_name (filename); char *name = get_pixmap_path (pname); make_pixmap (name ? name : filename, 234, 22, menuitemback); Free (pname); Free (filename); if (name) Free (name); } else theme_gradient (info->fullname, "MenuTextBack", menuitemback); } } static proplist_t cache_theme = NULL; static char *cache_name = NULL; static char * theme_image_filename (const char *name, const char *attribute, bool_t combined) { proplist_t theme; /* theme file */ /* * Use cached theme file or replace cache with selected theme */ if (cache_theme && streq (name, cache_name)) theme = cache_theme; else { if (cache_name && streq (name, cache_name)) /* theme was invalid */ return NULL; theme = read_proplist (name); if (!theme) { char *fname2 = g_strconcat (name, "/style", NULL); theme = read_proplist (fname2); Free (fname2); } if (cache_theme) WMReleasePropList (cache_theme); if (cache_name) Free (cache_name); cache_name = g_strdup (name); cache_theme = theme; if (!theme || !WMIsPLDictionary (theme)) /* invalid theme */ { if (theme) WMReleasePropList (theme); cache_theme = NULL; return NULL; } } /* * Extract theme images */ { proplist_t plattribute = WMCreatePLString ((char *) attribute); proplist_t value; char *path = NULL; value = WMGetFromPLDictionary (theme, plattribute); if (value && WMIsPLArray (value) && WMGetPropListItemCount (value) > 2) { proplist_t type = WMGetFromPLArray (value, 0); proplist_t file = WMGetFromPLArray (value, 1); char *ttype = WMGetFromPLString (type); if ((!combined && strcaseeq (ttype + 1, "pixmap")) || (combined && strcaseeq (ttype + 2, "gradient") && *ttype == 't')) { path = get_pixmap_path (WMGetFromPLString (file)); if (!path) { char *tmp = g_strconcat (name, "/", WMGetFromPLString (file), NULL); path = get_pixmap_path (tmp); Free (tmp); } } } WMReleasePropList (plattribute); return path; } } static void theme_gradient (const char *name, const char *attribute, GtkWidget *preview) { proplist_t theme; int width, height; width = GTK_WIDGET (preview)->requisition.width; height = GTK_WIDGET (preview)->requisition.height; /* * Use cached theme file or replace cache with selected theme */ if (cache_theme && streq (name, cache_name)) theme = cache_theme; else { if (cache_name && streq (name, cache_name)) { make_pixmap (PKGDATADIR "/black.xpm", width, height, preview); return; } theme = read_proplist (name); if (!theme) { char *fname2 = g_strconcat (name, "/style", NULL); theme = read_proplist (fname2); Free (fname2); } if (cache_theme) WMReleasePropList (cache_theme); if (cache_name) Free (cache_name); cache_name = g_strdup (name); cache_theme = theme; if (!theme || !WMIsPLDictionary (theme)) { cache_theme = NULL; if (theme) WMReleasePropList (theme); make_pixmap (PKGDATADIR "/black.xpm", width, height, preview); return; } } /* * Extract theme gradients */ { proplist_t plattribute = WMCreatePLString ((char *) attribute); proplist_t value = WMGetFromPLDictionary (theme, plattribute); bool_t done = NO; #if defined(PREVIEWS) && !defined(CONVERT) if (value && WMIsPLArray (value) && WMGetPropListItemCount (value) > 1) { proplist_t type = WMGetFromPLArray (value, 0); char *ttype = WMGetFromPLString (type); if (strcaseeq (ttype + 1, "gradient") || strcaseeq (ttype + 2, "gradient")) { gtype_e gtype; unsigned offset = strcaseeq (ttype + 2, "gradient") ? 1 : 0; if (*(ttype + offset) == 'h') gtype = HGRADIENT; else if (*(ttype + offset) == 'v') gtype = VGRADIENT; else gtype = DGRADIENT; if (offset && *ttype == 't') make_textured_gradient (theme_image_filename (name, attribute, YES), value, width, height, gtype, preview); else make_gradient (value, width, height, gtype, preview); done = YES; } else if (strcaseeq (ttype, "solid")) { make_solid (WMGetFromPLString (WMGetFromPLArray (value, 1)), width, height, preview); done = YES; } } #endif /* defined(PREVIEWS) && !defined(CONVERT) */ WMReleasePropList (plattribute); if (!done) make_pixmap (PKGDATADIR "/black.xpm", width, height, preview); } } /***************************************************************************** load or set theme *****************************************************************************/ #ifdef GETSTYLE static void load_theme (GtkWidget *button, gpointer ptr) { GtkCTreeNode *selection = get_selected_node (tree); themeinfo_t *info; if (!selection) return; info = gtk_ctree_node_get_row_data (tree, selection); if (!load_attributes (info->fullname, NULL)) /* try new style theme */ { char *path = g_strdup (info->fullname); char *fname2 = g_strconcat (info->fullname, "/style", NULL); if (!load_attributes (fname2, path)) dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't open selected theme.")); Free (path); Free (fname2); } } static void set_theme (GtkWidget *button, gpointer ptr) { load_theme (button, ptr); save_config_file (button, ptr); } #endif /* GETSTYLE */ /***************************************************************************** theme preview dialog *****************************************************************************/ #ifdef GETSTYLE # ifdef SETSTYLE static void preview_dialog (GtkWidget *button, gpointer ptr) /* * Preview selected theme and hide main window. */ { GList *selection = GTK_CLIST (tree)->selection; if (!GTK_CLIST (tree)->selection || g_list_length (selection) < 1) return; else { char *tmpthemename = get_temporary_file_name (); if (!getstyle_call (tmpthemename)) dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't write temporary theme file.\n" "Please check `stderr' for more details.")); else { GList *previewlist = NULL; unsigned n; for (n = 0; n < g_list_length (selection); n++) { GtkCTreeNode *theme = g_list_nth_data (selection, n); themeinfo_t *info = gtk_ctree_node_get_row_data (tree, theme); if (info->istheme) previewlist = g_list_append (previewlist, info->fullname); } previewlist = g_list_append (previewlist, g_strdup (tmpthemename)); leave_preview (button, previewlist); } } } static void leave_preview (GtkWidget *button, gpointer ptr) /* * Show new theme or restore old theme */ { GList *list = (GList *) ptr; char *name = list->data; char *quotedname = protect_quotes (g_strdup (name)); char *cmdline = g_strconcat (SETSTYLE, " \"", quotedname, "\"", NULL); char *text; if (g_list_length (list) > 1) text = g_strdup_printf (_("Can't show preview of theme `%s'.\n" "Please check `stderr' for more details."), name); else text = g_strdup_printf (_("Can't revert to old theme.\n" "Please check `stderr' for more details.")); gtk_widget_hide (main_window); shell_command (cmdline, text); Free (text); Free (cmdline); Free (quotedname); if (g_list_length (list) == 1) /* revert */ { delete_file_or_dir (name); gtk_widget_show (main_window); Free (name); g_list_free (list); } else { list = g_list_remove (list, list->data); dialog (DIALOG_INFO, g_list_length (list) > 1 ? _("Show next preview") : _("Leave preview mode"), NULL, leave_preview, list, _("Preview of `%s'"), g_basename (name)); } } # endif /* SETSTYLE */ #endif /* GETSTYLE */ /***************************************************************************** save theme *****************************************************************************/ #ifdef GETSTYLE static void save_theme_dialog (GtkWidget *widget, gpointer ptr) /* * Save theme dialog window */ { GtkCTreeNode *selection = get_selected_node (tree); themeinfo_t *info; char *dirname; if (!selection) return; info = gtk_ctree_node_get_row_data (tree, selection); if (!info->parent) dirname = info->fullname; else { themeinfo_t *pinfo = gtk_ctree_node_get_row_data (tree, info->parent); dirname = pinfo->fullname; } { GtkWidget *window = gtk_dialog_new (); GtkWidget *entry = gtk_entry_new (); GtkWidget *vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); gtk_window_set_title (GTK_WINDOW (window), _("Save a theme")); gtk_signal_connect_object (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); /* * Theme name */ { GtkWidget *box = gtk_vbox_new (FALSE, 0); GtkWidget *frame = gtk_frame_new (_("Theme name")); char *text = g_strdup_printf (_("Save current settings to new" " theme in\n`%s':"), dirname); gtk_container_set_border_width (GTK_CONTAINER (box), 5); gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); gtk_container_add (GTK_CONTAINER (frame), box); gtk_box_pack_start (GTK_BOX (box), gtk_label_new (text), FALSE, TRUE, 0); Free (text); gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0); } /* * Theme format */ #ifdef TAR { GSList *group = NULL; GtkWidget *fvbox = gtk_vbox_new (FALSE, 0); GtkWidget *frame = gtk_frame_new (_("Output format")); GtkWidget *button; gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); gtk_container_add (GTK_CONTAINER (frame), fvbox); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (fvbox), 5); button = gtk_radio_button_new_with_label (group, _("Window Maker theme folder (.themed)")); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); group = gtk_radio_button_group (GTK_RADIO_BUTTON (button)); gtk_box_pack_start (GTK_BOX (fvbox), button, TRUE, TRUE, 0); #ifdef GZIP button = gtk_radio_button_new_with_label (group, _("http://wm.themes.org theme archive (.tar.gz)")); #else /* not GZIP */ button = gtk_radio_button_new_with_label (group, _("http://wm.themes.org theme archive (.tar)")); #endif /* not GZIP */ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); group = gtk_radio_button_group (GTK_RADIO_BUTTON (button)); gtk_box_pack_start (GTK_BOX (fvbox), button, TRUE, TRUE, 0); gtk_object_set_user_data (GTK_OBJECT (entry), button); } #else /* not TAR */ gtk_object_set_user_data (GTK_OBJECT (entry), NULL); #endif /* not TAR */ gtk_object_set_data (GTK_OBJECT (entry), "path", dirname); /* * Buttons */ { GtkWidget *hbox = gtk_hbutton_box_new (); GtkWidget *button1, *button2; gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, TRUE, TRUE, 5); gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbox), 5); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); button1 = gtk_button_new_with_label (_("Save")); gtk_box_pack_start (GTK_BOX (hbox), button1, TRUE, TRUE, 5); gtk_widget_set_sensitive (button1, FALSE); gtk_signal_connect (GTK_OBJECT (button1), "clicked", GTK_SIGNAL_FUNC (save_theme_frontend), entry); gtk_signal_connect_object (GTK_OBJECT (button1), "clicked", GTK_SIGNAL_FUNC (gtk_widget_hide), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT); gtk_signal_connect (GTK_OBJECT (entry), "changed", GTK_SIGNAL_FUNC (set_themename), button1); gtk_signal_connect (GTK_OBJECT (entry), "activate", GTK_SIGNAL_FUNC (activate_themename), button1); button2 = gtk_button_new_with_label (_("Cancel")); gtk_box_pack_start (GTK_BOX (hbox), button2, TRUE, TRUE, 5); gtk_signal_connect_object (GTK_OBJECT (button2), "clicked", GTK_SIGNAL_FUNC (gtk_widget_hide), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); gtk_object_set_user_data (GTK_OBJECT (button1), button2); gtk_widget_grab_default (button2); } gtk_widget_show_all (window); gtk_widget_grab_focus (entry); gtk_entry_select_region (GTK_ENTRY (entry), 0, -1); } } static gint hide_window (GtkWidget *widget, gpointer ptr) /* * Hide the specified window, don't destroy it. */ { gtk_widget_hide (widget); return TRUE; } static void set_themename (GtkWidget *widget, gpointer ptr) /* * Toggle sensitivity of 'Save' button. */ { if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) > 0) { gtk_widget_set_sensitive (GTK_WIDGET (ptr), YES); gtk_widget_grab_default (GTK_WIDGET (ptr)); } else { gtk_widget_set_sensitive (GTK_WIDGET (ptr), NO); gtk_widget_grab_default (GTK_WIDGET (gtk_object_get_user_data (GTK_OBJECT (ptr)))); } } static void activate_themename (GtkWidget *widget, gpointer ptr) { if (strlen (gtk_entry_get_text (GTK_ENTRY (widget))) > 0) gtk_signal_emit_by_name (GTK_OBJECT (ptr), "clicked"); else gtk_signal_emit_by_name (GTK_OBJECT (gtk_object_get_user_data (GTK_OBJECT (ptr))), "clicked"); } static void save_theme_frontend (GtkWidget *widget, gpointer ptr) /* * Checks whether the theme file or directory already exists. */ { GtkEntry *name = GTK_ENTRY (ptr); GtkWidget *button = gtk_object_get_user_data (GTK_OBJECT (ptr)); const char *themename = gtk_entry_get_text (name); const char *pathname = gtk_object_get_data (GTK_OBJECT (ptr), "path"); #ifdef TAR if (button && GTK_TOGGLE_BUTTON (button)->active) { char *filename1; bool_t exists1 = NO; char *filename2; bool_t exists2 = NO; filename1 = g_strconcat (pathname, "/", themename, ".tar", NULL); exists1 = file_exists (filename1); #ifdef GZIP filename2 = g_strconcat (pathname, "/", themename, ".tar.gz", NULL); exists2 = file_exists (filename2); #endif /* GZIP */ if (exists1 && exists2) { dialog_popup (DIALOG_QUESTION, save_theme_backend, ptr, _("Overwrite existing files\n`%s'\n`%s'"), filename1, filename2); Free (filename1); Free (filename2); return; } else if (exists1) { dialog_popup (DIALOG_QUESTION, save_theme_backend, ptr, _("Overwrite existing file\n`%s'"), filename1); Free (filename1); #ifdef GZIP Free (filename2); #endif /* GZIP */ return; } else if (exists2) { dialog_popup (DIALOG_QUESTION, save_theme_backend, ptr, _("Overwrite existing file\n`%s'"), filename2); Free (filename1); Free (filename2); return; } Free (filename1); #ifdef GZIP Free (filename2); #endif /* GZIP */ } else #endif { char *filename = g_strconcat (pathname, "/", themename, ".themed", NULL); if (file_exists (filename)) { dialog_popup (DIALOG_QUESTION, save_theme_backend, ptr, _("Overwrite existing theme\n`%s'"), filename); Free (filename); return; } Free (filename); } save_theme_backend (widget, ptr); } static void save_theme_backend (GtkWidget *widget, gpointer ptr) /* * Actually writes a theme to disk. * Two formats are supported: * Either a .tar.gz file or a .themed directory are written. */ { GtkEntry *name = GTK_ENTRY (ptr); char *pathname = expand_tilde (gtk_object_get_data (GTK_OBJECT (ptr), "path")); GtkWidget *button = gtk_object_get_user_data (GTK_OBJECT (name)); const char *themename = gtk_entry_get_text (name); bool_t archive = FALSE; char *tmpdir = NULL; char *filename; GList *oldfiles = NULL; #ifdef TAR archive = button && GTK_TOGGLE_BUTTON (button)->active; /* * If archive is set, then generate temporary theme * /tmpfile/Themes/'themename'.themed */ if (archive) { char *subdir; tmpdir = make_temporary_directory (); subdir = g_strconcat (tmpdir, "/Themes", NULL); if (make_directory (subdir)) /* create temporary Themes directory */ { Free (subdir); return; } Free (subdir); filename = g_strconcat (tmpdir, "/Themes/", themename, ".themed", NULL); if (make_directory (filename)) /* create new theme directory */ { Free (filename); return; } } else #endif { filename = g_strconcat (pathname, "/", themename, ".themed", NULL); if (file_exists (filename)) oldfiles = get_theme_files (filename); else if (make_directory (filename)) /* create new theme directory */ { Free (filename); return; } } /* * Write style file to directory 'themename'.themed * Copy all image files to this directory */ { unsigned n; proplist_t pltype = WMCreatePLString ("Type"); char *stylename = g_strconcat (filename, "/style", NULL); proplist_t theme = WMCreatePLDictionary (NULL, NULL, NULL); oldfiles = remove_file_from_list (oldfiles, stylename); for (n = 0; n < WMGetPropListItemCount (theme_keys); n++) { proplist_t key = WMGetFromPLArray (theme_keys, n); proplist_t entry = WMGetFromPLDictionary (wmconfig, key); if (entry && WMIsPLDictionary (entry)) { proplist_t value = WMGetFromPLDictionary (windowmaker, key); proplist_t type = WMGetFromPLDictionary (entry, pltype); if (strcaseeq (WMGetFromPLString (type), "Texture") && value && WMIsPLArray (value) && WMGetPropListItemCount (value) >= 2) { char *ttype = WMGetFromPLString (WMGetFromPLArray (value, 0)); if (strcaseeq (ttype + 1, "pixmap") || (strcaseeq (ttype + 2, "gradient") && *ttype == 't')) { char *name; char *path; name = g_strdup (WMGetFromPLString (WMGetFromPLArray (value, 1))); path = get_pixmap_path (name); if (path) { if (copy_file (filename, path)) { Free (filename); Free (path); WMReleasePropList (pltype); WMReleasePropList (theme); Free (name); Free (stylename); return; } else { char *file; proplist_t plfile; oldfiles = remove_file_from_list (oldfiles, path); value = WMDeepCopyPropList (value); file = strrchr (path, '/'); if (!file) plfile = WMRetainPropList (WMCreatePLString (path)); else plfile = WMRetainPropList (WMCreatePLString (file + 1)); WMDeleteFromPLArray (value, 1); WMInsertInPLArray (value, 1, plfile); Free (path); } } else { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't open input file\n'%s'"), name); Free (filename); WMReleasePropList (pltype); WMReleasePropList (theme); Free (name); Free (stylename); return; } Free (name); } } WMPutInPLDictionary (theme, key, value); } } while (oldfiles) { char *tmp = oldfiles->data; delete_file_or_dir (tmp); oldfiles = g_list_remove (oldfiles, tmp); Free (tmp); } if (!WMWritePropListToFile (theme, stylename, YES)) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't save theme file\n`%s'\n" "Please check `stderr' for more details."), stylename); Free (filename); WMReleasePropList (pltype); WMReleasePropList (theme); Free (stylename); return; } WMReleasePropList (theme); WMReleasePropList (pltype); Free (stylename); } #ifdef TAR if (archive) { char *cdname = g_strdup (filename); char *tmp; char *cmd; char *tarname; char *quotedtar; char *quotedcd; tmp = strrchr (cdname, '/'); *tmp = 0; tmp = strrchr (cdname, '/'); *tmp = 0; tarname = g_strconcat (pathname, "/", themename, ".tar", NULL); quotedtar = protect_quotes (g_strdup (tarname)); quotedcd = protect_quotes (g_strdup (cdname)); cmd = g_strconcat ("cd ", " \"", quotedcd, "\" && ", TAR, " -c -f \"", quotedtar,"\" * ", NULL); if (shell_command (cmd, NULL)) /* create tar archive */ { remove_directory (tmpdir); Free (tarname); Free (quotedtar); Free (cdname); Free (quotedcd); Free (filename); return; } if (remove_directory (tmpdir)) /* delete tmp directory */ { Free (tarname); Free (quotedtar); Free (cdname); Free (quotedcd); Free (filename); return; } #ifdef GZIP { char *text = g_strdup_printf (_("Can't pack theme file\n`%s'"), tarname); cmd = g_strconcat (GZIP, " -f \"", quotedtar,"\"", NULL); if (shell_command (cmd, text)) /* compress archive */ { Free (tarname); Free (quotedtar); Free (cdname); Free (quotedcd); Free (filename); Free (text); return; } Free (text); } #endif /* not GZIP */ Free (tarname); Free (quotedtar); Free (cdname); Free (quotedcd); } #endif /* TAR */ Free (pathname); Free (filename); build_theme_list (); } static GList * get_theme_files (const char *themename) /* * Generate list of files that are part of the given theme */ { GList *list = NULL; DIR *themedir = opendir (themename); if (themedir) { struct dirent *file; while ((file = readdir (themedir))) { if (!streq (file->d_name, ".") && !streq (file->d_name, "..")) list = g_list_append (list, g_strconcat (themename, "/", file->d_name, NULL)); } closedir (themedir); } return list; } static GList * remove_file_from_list (GList *list, const char *file) /* * Remove list element 'file' from 'list'. */ { if (list && g_list_length (list) > 0) { unsigned n; for (n = 0; n < g_list_length (list); n++) { char *tmp = g_list_nth_data (list, n) ; if (streq (tmp, file)) { list = g_list_remove (list, tmp); Free (tmp); break; } } } return list; } void get_theme_attributes (void) /* * Generate list of attributes that define a Window Maker theme * * Side effects: * fills global property array of attributes: 'theme_keys' */ { char *tmpthemename = get_temporary_file_name (); proplist_t theme; if (!getstyle_call (tmpthemename)) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't write temporary theme file.\n" "Please check `stderr' for more details.")); return; } theme = read_proplist (tmpthemename); if (!theme) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't open temporary theme file.\n" "Please check `stderr' for more details.")); delete_file_or_dir (tmpthemename); return; } theme_keys = WMGetPLDictionaryKeys (theme); WMReleasePropList (theme); delete_file_or_dir (tmpthemename); } void cleanup_themes (void) { WMReleasePropList (theme_keys); } static void free_memory (gpointer data, gpointer user_data) { Free (data); } static bool_t getstyle_call (const char *themename) /* * Start wmaker's getstyle program */ { char *quotedname = protect_quotes (g_strdup (themename)); char *cmdline = g_strconcat (GETSTYLE, " -t \"", quotedname, "\"", NULL); bool_t success = !system (cmdline); Free (cmdline); Free (quotedname); return success; } #endif /* GETSTYLE */ /***************************************************************************** theme installation *****************************************************************************/ static void install_theme_dialog (GtkWidget *widget, gpointer ptr) /* * Install theme dialog window */ { GtkWidget *install_button; GtkWidget *filelist; GtkWidget *window; GtkCTreeNode *selection = get_selected_node (tree); themeinfo_t *info; char *dirname; if (!selection) return; info = gtk_ctree_node_get_row_data (tree, selection); if (!info->parent) dirname = info->fullname; else { themeinfo_t *pinfo = gtk_ctree_node_get_row_data (tree, info->parent); dirname = pinfo->fullname; } #if 0 if (strlen (dirname) > strlen ("/Themes") && streq (dirname + strlen (dirname) - strlen ("/Themes"), "/Themes")) *(dirname + strlen (dirname) - strlen ("/Themes")) = 0; #endif { GtkBox *vbox; GtkWidget *box = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (box), 5); filelist = gtk_clist_new (1); window = gtk_dialog_new (); vbox = GTK_BOX (GTK_DIALOG (window)->vbox); gtk_object_set_data (GTK_OBJECT (filelist), "path", dirname); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE); gtk_object_set_user_data (GTK_OBJECT (window), filelist); gtk_window_set_title (GTK_WINDOW (window), _("Install themes")); gtk_signal_connect_object (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, TRUE, 0); { char *text = g_strdup_printf (_("Install themes in\n`%s':"), dirname); gtk_box_pack_start (GTK_BOX (box), gtk_label_new (text), FALSE, TRUE, 0); Free (text); } /* * List of themes */ { GtkWidget *hbox = gtk_vbox_new (FALSE, 0); GtkWidget *button = gtk_button_new_with_label (_("Browse...")); GtkWidget *bbox = gtk_hbutton_box_new (); GtkWidget *frame = gtk_frame_new (_("List of themes")); gtk_frame_set_label_align (GTK_FRAME (frame), 0.5, 0.5); gtk_container_set_border_width (GTK_CONTAINER (frame), 5); gtk_container_add (GTK_CONTAINER (frame), hbox); gtk_box_pack_start (vbox, frame, FALSE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); init_dnd (filelist); gtk_clist_set_column_auto_resize (GTK_CLIST (filelist), 0, YES); gtk_clist_column_titles_passive (GTK_CLIST (filelist)); gtk_clist_set_selection_mode (GTK_CLIST (filelist), GTK_SELECTION_EXTENDED); { GtkWidget *scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_container_set_border_width (GTK_CONTAINER (scrolled), 5); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_container_add (GTK_CONTAINER (scrolled), filelist); gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0); gtk_widget_set_usize (scrolled, 550, 150); } gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 5); gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (open_theme_browser), filelist); gtk_tooltips_set_tip (tooltips, button, _("Select themes with a file selection dialog " "(or use drag and drop with your " "file manager and WWW browser)."), NULL); } /* * Buttons */ { GtkWidget *hbox = gtk_hbutton_box_new (); GtkWidget *button2; gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbox), 5); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, FALSE, TRUE, 5); install_button = gtk_button_new_with_label (_("Install")); gtk_widget_set_sensitive (install_button, FALSE); gtk_box_pack_start (GTK_BOX (hbox), install_button, FALSE, TRUE, 5); gtk_signal_connect (GTK_OBJECT (install_button), "clicked", GTK_SIGNAL_FUNC (install_themes), filelist); gtk_signal_connect_object (GTK_OBJECT (install_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); gtk_signal_connect (GTK_OBJECT (filelist), "select_row", GTK_SIGNAL_FUNC (update_selection), install_button); gtk_signal_connect (GTK_OBJECT (filelist), "unselect_row", GTK_SIGNAL_FUNC (update_selection), install_button); GTK_WIDGET_SET_FLAGS (install_button, GTK_CAN_DEFAULT); button2 = gtk_button_new_with_label (_("Cancel")); gtk_box_pack_start (GTK_BOX (hbox), button2, FALSE, TRUE, 5); gtk_signal_connect_object (GTK_OBJECT (button2), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window)); GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT); gtk_widget_grab_default (button2); gtk_object_set_user_data (GTK_OBJECT (install_button), button2); } } if (g_list_length (GTK_CLIST(filelist)->selection) > 0) { gtk_widget_set_sensitive (GTK_WIDGET (install_button), TRUE); gtk_widget_grab_default (GTK_WIDGET (install_button)); } else { gtk_widget_set_sensitive (GTK_WIDGET (install_button), FALSE); gtk_widget_grab_default (GTK_WIDGET (gtk_object_get_user_data (GTK_OBJECT (install_button)))); } gtk_widget_show_all (window); if (ptr) insert_dnd_elements (GTK_CLIST (filelist), ptr); } static void open_theme_browser (GtkWidget *button, gpointer data) /* * Open file browser to select themes. */ { static GtkWidget *filesel = NULL; if (!filesel) { GtkFileSelection *fs; GtkWidget *clist = (GtkWidget *) data; filesel = gtk_file_selection_new (_("Choose themes to install")); fs = GTK_FILE_SELECTION (filesel); gtk_file_selection_set_select_multiple (fs, TRUE); gtk_file_selection_hide_fileop_buttons (fs); gtk_window_set_position (GTK_WINDOW (fs), GTK_WIN_POS_MOUSE); gtk_signal_connect_object (GTK_OBJECT (fs), "destroy", GTK_SIGNAL_FUNC (hide_window), GTK_OBJECT (filesel)); gtk_signal_connect (GTK_OBJECT (fs->ok_button), "clicked", GTK_SIGNAL_FUNC (insert_theme_files), clist); gtk_object_set_user_data (GTK_OBJECT (fs->ok_button), filesel); gtk_signal_connect_object (GTK_OBJECT (fs->cancel_button), "clicked", GTK_SIGNAL_FUNC (hide_window), GTK_OBJECT (filesel)); gtk_signal_connect_object (GTK_OBJECT (fs->ok_button), "clicked", GTK_SIGNAL_FUNC (hide_window), GTK_OBJECT (filesel)); gtk_file_selection_set_filename (fs, "~/"); } if (GTK_WIDGET_VISIBLE (filesel)) gtk_widget_hide (filesel); else gtk_widget_show_all (filesel); } static void install_themes (GtkWidget *widget, gpointer ptr) /* * Install selected list of themes */ { GtkWidget *vbox; GtkWidget *progress_window; GtkWidget *progress_label; GtkWidget *progress_bar; GtkCList *install_list = GTK_CLIST (ptr); GList *files = install_list->selection; unsigned n; char *themedir = gtk_object_get_data (GTK_OBJECT (ptr), "path"); char *qthemedir; gint timer; pid_t pid; gtk_widget_hide (gtk_widget_get_toplevel (widget)); if (strlen (themedir) == 0) { dialog_popup (DIALOG_ERROR, NULL, NULL, _("No installation prefix given.")); return; } themedir = expand_tilde (themedir); qthemedir = protect_quotes (g_strdup (themedir)); /* * Generate a progressbar and window */ progress_window = gtk_dialog_new (); gtk_window_set_position (GTK_WINDOW (progress_window), GTK_WIN_POS_MOUSE); gtk_window_set_title (GTK_WINDOW (progress_window), _("Install themes")); gtk_widget_set_usize (progress_window, 250, -1); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (progress_window)->vbox), vbox, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); progress_label = gtk_label_new (""); gtk_box_pack_start (GTK_BOX (vbox), progress_label, FALSE, TRUE, 0); { GtkAdjustment *adj; adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 300, 0, 0, 0); progress_bar = gtk_progress_bar_new_with_adjustment (adj); gtk_progress_set_activity_mode (GTK_PROGRESS (progress_bar), TRUE); gtk_progress_bar_set_activity_step (GTK_PROGRESS_BAR (progress_bar), 5); gtk_progress_bar_set_activity_blocks (GTK_PROGRESS_BAR (progress_bar), 4); timer = gtk_timeout_add (100, progress_timer, progress_bar); } gtk_box_pack_start (GTK_BOX (vbox), progress_bar, FALSE, TRUE, 5); { GtkWidget *bbox = gtk_hbutton_box_new (); GtkWidget *cancel = gtk_button_new_with_label (_("Skip")); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (progress_window)->action_area), bbox, FALSE, TRUE, 5); gtk_box_pack_start (GTK_BOX (bbox), cancel, FALSE, TRUE, 0); gtk_signal_connect (GTK_OBJECT (cancel), "clicked", GTK_SIGNAL_FUNC (cancel_installation), &pid); gtk_signal_connect (GTK_OBJECT (progress_window), "delete_event", GTK_SIGNAL_FUNC (delete_button), cancel); } gtk_widget_show_all (progress_window); for (n = 0; n < g_list_length (files); n++) { char *orig_filename = NULL; char *install_filename = NULL; char *qinstall_filename = NULL; char *unpacked_filename = NULL; char *qunpacked_filename = NULL; char *tmp_filename = NULL; gtk_clist_get_text (install_list, GPOINTER_TO_INT (g_list_nth_data (files, n)), 0, &orig_filename); { char *basename = strrchr (orig_filename, '='); if (!basename) basename = strrchr (orig_filename, '/'); gtk_label_set_text (GTK_LABEL (progress_label), basename ? basename + 1: orig_filename); gtk_label_set_text (GTK_LABEL (progress_label), basename ? basename + 1: orig_filename); } while (gtk_events_pending()) gtk_main_iteration(); /* * Get theme via WWW */ if (!strneq (orig_filename, "file:/", strlen ("file:/"))) #ifdef WWWREQUEST { char *tmpthemename = get_temporary_file_name (); pid = fork (); if (pid) /* parent */ { int status; while (waitpid (pid, &status, WNOHANG) == 0) gtk_main_iteration (); if (WIFSIGNALED (status)) continue; } else /* child */ { execl (PERL, PERL, PKGDATADIR "/getfile.pl", orig_filename, tmpthemename, NULL); #ifdef HAVE__EXIT _exit (1); #else /* HAVE__EXIT */ exit (1); #endif /* HAVE__EXIT */ } tmp_filename = install_filename = g_strdup (tmpthemename); } #else /* not WWWREQUEST */ continue; /* skip this file */ #endif /* not WWWREQUEST */ else install_filename = g_strdup (orig_filename + strlen ("file:")); /* * Now lets install the new theme file */ qinstall_filename = protect_quotes (g_strdup (install_filename)); { bool_t gzip = NO; #ifdef GUNZIP { char *tmp = g_strdup_printf ("%s -t \"%s\"", GUNZIP, qinstall_filename); if (!system (tmp)) { Free (tmp); gzip = YES; qunpacked_filename = g_strconcat (qinstall_filename, ".tar", NULL); tmp = g_strdup_printf ("%s -c < \"%s\" > \"%s\"", GUNZIP, qinstall_filename, qunpacked_filename); if (system (tmp)) /* no success ? */ { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't unpack GNU zipped theme file\n`%s'\n" "to destiation file\n`%s'\n" "Please check `stderr' for more details."), qinstall_filename, qunpacked_filename); Free (qunpacked_filename); Free (tmp); continue; } unpacked_filename = g_strconcat (install_filename, ".tar", NULL); } Free (tmp); } #endif /* GUNZIP */ #ifdef BUNZIP2 if (!gzip) { char *tmp = g_strdup_printf ("%s -t \"%s\"", BUNZIP2, qinstall_filename); if (!system (tmp)) { Free (tmp); qunpacked_filename = g_strconcat (qinstall_filename, ".tar", NULL); tmp = g_strdup_printf ("%s < \"%s\" > \"%s\"", BUNZIP2, qinstall_filename, qunpacked_filename); if (system (tmp)) /* no success ? */ { dialog_popup (DIALOG_ERROR, NULL, NULL, _("Can't unpack BZIP2 compressed theme file\n" "`%s'\nto destiation file\n`%s'\n" "Please check `stderr' for more details."), qinstall_filename, qunpacked_filename); Free (qunpacked_filename); Free (tmp); continue; } unpacked_filename = g_strconcat (install_filename, ".tar", NULL); } Free (tmp); } #endif /* BUNZIP2 */ if (unpacked_filename) /* unpacked file has been created ? */ { if (tmp_filename) delete_file_or_dir (tmp_filename); tmp_filename = unpacked_filename; } else /* still the same */ { unpacked_filename = g_strdup (install_filename); qunpacked_filename = g_strdup (qinstall_filename); } { #ifdef TAR char *tmp = g_strdup_printf ("%s -t -f \"%s\"", TAR, qunpacked_filename); if (!system (tmp)) { char *text = g_strdup_printf (_("Can't unpack theme\n`%s'"), unpacked_filename); Free (tmp); tmp = g_strdup_printf ("cd \"%s\"; %s -x -f \"%s\"", qthemedir, TAR, qunpacked_filename); if (shell_command (tmp, text)) { Free (tmp); Free (text); continue; } Free (text); Free (tmp); } else #endif /* TAR */ { if (copy_file (themedir, unpacked_filename)) { continue; } } } if (tmp_filename) delete_file_or_dir (tmp_filename); Free (unpacked_filename); Free (install_filename); Free (qunpacked_filename); Free (qinstall_filename); } } gtk_timeout_remove (timer); gtk_widget_destroy (progress_window); build_theme_list (); Free (themedir); Free (qthemedir); gtk_clist_clear (GTK_CLIST (install_list)); } static void cancel_installation (GtkWidget *widget, gpointer ptr) { pid_t pid = * (pid_t *) ptr; kill (pid, 15); } static gint insert_theme_files (GtkWidget *widget, gpointer ptr) { GtkFileSelection *fs; GtkCList *themelist; gchar **list; int i; fs = GTK_FILE_SELECTION (gtk_object_get_user_data (GTK_OBJECT (widget))); list = gtk_file_selection_get_selections (fs); themelist = GTK_CLIST (ptr); for (i = 0; list[i]; i++) { char *tmp = g_strconcat ("file:", list[i], NULL); gtk_clist_insert (themelist, -1, &tmp); gtk_clist_select_row (themelist, themelist->rows - 1, 0); Free (tmp); } g_strfreev (list); return TRUE; } static void update_selection (GtkCList *themelist, gint row, gint column, GdkEvent *event, gpointer data) { if (g_list_length (themelist->selection) > 0) { gtk_widget_set_sensitive (GTK_WIDGET (data), TRUE); gtk_widget_grab_default (GTK_WIDGET (data)); } else { gtk_widget_set_sensitive (GTK_WIDGET (data), FALSE); gtk_widget_grab_default (GTK_WIDGET (gtk_object_get_user_data (GTK_OBJECT (data)))); } } enum { TARGET_STRING, TARGET_ROOTWIN, TARGET_URL }; static GtkTargetEntry target_table[] = { { "STRING", 0, TARGET_STRING }, { "text/plain", 0, TARGET_STRING }, { "text/uri-list", 0, TARGET_URL } }; static guint n_targets = sizeof (target_table) / sizeof (target_table [0]); static void init_dnd (GtkWidget *widget) { gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, target_table, n_targets, GDK_ACTION_COPY | GDK_ACTION_MOVE); gtk_signal_connect (GTK_OBJECT (widget), "drag_data_received", GTK_SIGNAL_FUNC (drag_data_received), NULL); } static void drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, guint time) { if (data->length >= 0 && data->format == 8) { char *text = (char *) data->data; if (widget == GTK_WIDGET (tree)) install_theme_dialog (widget, text); else insert_dnd_elements (GTK_CLIST (widget), text); gtk_drag_finish (context, TRUE, FALSE, time); } else gtk_drag_finish (context, FALSE, FALSE, time); } static void insert_dnd_elements (GtkCList *clist, const char *start) { while (strneq (start, "http://", strlen ("http://")) || strneq (start, "ftp://", strlen ("ftp://")) || strneq (start, "file:/", strlen ("file:/"))) { char *end; if ((end = strstr (start + 1, "file:/")) || (end = strstr (start + 1, "http://")) || (end = strstr (start + 1, "ftp://"))) { char *tmp; const char *last = end; while (isspace (*--last)) ; tmp = g_strndup (start, last - start + 1); gtk_clist_insert (clist, -1, &tmp); Free (tmp); start = end; } else { char *tmp; const char *last = start + strlen (start); while (isspace (*--last)) ; tmp = g_strndup (start, last - start + 1); gtk_clist_insert (clist, -1, &tmp); Free (tmp); start++; } gtk_clist_select_row (clist, clist->rows - 1, 0); } } /***************************************************************************** theme preview computation *****************************************************************************/ static void compute_preview (GtkWidget *progress_bar, GtkWidget *progress_label, unsigned n, unsigned nelem, const char *name, unsigned width, unsigned height) { char *pname; char *path; char *filename; if (!name) return; else filename = g_strdup (name); pname = preview_name (name); path = get_pixmap_path (pname); gtk_progress_bar_update (GTK_PROGRESS_BAR (progress_bar), n / (double) nelem); gtk_label_set_text (GTK_LABEL (progress_label), g_basename (name)); while (gtk_events_pending ()) gtk_main_iteration (); if (!path) { DIR *dir = opendir (g_dirname (pname)); if (!dir) /* Make ~/.wmakerconf directory */ { if (make_directory (g_dirname (pname))) { Free (pname); return; } } else closedir (dir); filename = protect_quotes (filename); pname = protect_quotes (pname); { #ifdef CONVERT char *cmd = g_strdup_printf ("%s -comment \"\" -geometry %dx%d " "\"%s\" ppm:\"%s\"", CONVERT, width, height, filename, pname); #else /* not CONVERT */ char *cmd = g_strdup_printf ("%s \"%s\" \"%s\" %d %d", BINDIR "/mkpreview", filename, pname, width, height); #endif /* not CONVERT */ if (system (cmd)) /* Write failure */ { warning (_("Can't generate preview `%s'.\n" "Please check `stderr' for more details."), pname); } Free (cmd); } } else Free (path); Free (pname); Free (filename); } static proplist_t get_color (proplist_t texture) /* setstyle.c from Window Maker utils directory */ { char *str; proplist_t type = WMGetFromPLArray (texture, 0); proplist_t value = 0; if (!type) return NULL; str = WMGetFromPLString (type); if (streq (str, "solid")) value = WMGetFromPLArray (texture, 1); else if (streq (str + 1, "gradient")) { if (WMGetPropListItemCount (texture) == 3) { GdkColor color1, color2; char *c1name = WMGetFromPLString (WMGetFromPLArray (texture, 1)); char *c2name = WMGetFromPLString (WMGetFromPLArray (texture, 2)); /* * Compute default color = (color1 + color2) / 2 */ if (!make_color (c1name, &color1)) color1.red = color1.green = color1.blue = 65535; /* white */ if (!make_color (c2name, &color2)) color2.red = color2.green = color2.blue = 65535; /* white */ color1.red = (color1.red + color2.red) >> 1; color1.green = (color1.green + color2.green) >> 1; color1.blue = (color1.blue + color2.blue) >> 1; { char colstr [MAXSTRLEN]; sprintf (colstr, "#%02x%02x%02x", /* new color */ (unsigned) (color1.red / 256 + 0.5), (unsigned) (color1.green / 256 + 0.5), (unsigned) (color1.blue / 256 + 0.5)); value = WMCreatePLString (colstr); } } } else if (streq (str + 2, "gradient")) value = WMGetFromPLArray (texture, 1); else if (streq (str + 1, "pixmap")) value = WMGetFromPLArray (texture, 2); return value; } static gint timer_index = 0; static void tree_moved (GtkCTree *ctree, GtkCTreeNode *node, GtkCTreeNode *new_parent, GtkCTreeNode *new_sibling) { if (node && new_parent) { themeinfo_t *info = gtk_ctree_node_get_row_data (tree, node); themeinfo_t *pinfo = gtk_ctree_node_get_row_data (tree, new_parent); char *fullname = g_strconcat (pinfo->fullname, "/", info->name, info->suffix, NULL); info->parent = new_parent; rename_file_or_dir (info->fullname, fullname); timer_index = gtk_timeout_add (20, (GtkFunction) update_themes_timeout, fullname); } } static void update_themes_timeout (char *filename) { build_theme_list (); select_theme (tree, filename); Free (filename); gtk_timeout_remove (timer_index); }