You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1598 lines
54 KiB

13 years ago
/* $Id: launcher-dialog.c 26139 2007-10-17 09:21:10Z nick $
*
* Copyright (c) 2005-2007 Jasper Huijsmans <jasper@xfce.org>
* Copyright (c) 2006-2007 Nick Schermer <nick@xfce.org>
* Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
*
* 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 Library 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-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <libxfce4ui/libxfce4ui.h>
#include <libxfce4panel/libxfce4panel.h>
#include "launcher.h"
#include "launcher-dialog.h"
enum
{
COLUMN_ICON = 0,
COLUMN_NAME
};
typedef struct _LauncherDialog LauncherDialog;
struct _LauncherDialog
{
LauncherPlugin *launcher;
/* stored setting */
guint stored_move_first : 1;
/* arrow position */
GtkWidget *arrow_position;
/* entries list */
GtkWidget *treeview;
GtkListStore *store;
/* tree buttons */
GtkWidget *up;
GtkWidget *down;
GtkWidget *add;
GtkWidget *remove;
/* lock */
guint updating : 1;
/* active entry */
LauncherEntry *entry;
/* entry widgets */
GtkWidget *entry_name;
GtkWidget *entry_comment;
GtkWidget *entry_icon;
GtkWidget *entry_exec;
GtkWidget *entry_path;
GtkWidget *entry_terminal;
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
GtkWidget *entry_startup;
#endif
};
/**
* Prototypes
**/
static void launcher_dialog_g_list_swap (GList *li_a,
GList *li_b);
static gboolean launcher_dialog_read_desktop_file (const gchar *file,
LauncherEntry *entry);
static void launcher_dialog_tree_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
LauncherDialog *ld);
static void launcher_dialog_frame_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
LauncherDialog *ld);
static void launcher_dialog_save_entry (GtkWidget *entry,
LauncherDialog *ld);
static void launcher_dialog_save_button (GtkWidget *button,
LauncherDialog *ld);
static void launcher_dialog_update_entries (LauncherDialog *ld);
static void launcher_dialog_update_icon (LauncherDialog *ld);
static void launcher_dialog_folder_chooser (LauncherDialog *ld);
static void launcher_dialog_command_chooser (LauncherDialog *ld);
static void launcher_dialog_icon_chooser (LauncherDialog *ld);
static void launcher_dialog_tree_update_row (LauncherDialog *ld,
gint column);
static void launcher_dialog_tree_selection_changed (LauncherDialog *ld,
GtkTreeSelection *selection);
static void launcher_dialog_tree_button_clicked (GtkWidget *button,
LauncherDialog *ld);
static GtkWidget *launcher_dialog_add_properties (LauncherDialog *ld) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
static GtkWidget *launcher_dialog_add_tree (LauncherDialog *ld) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
static GtkWidget *launcher_dialog_add_tree_buttons (LauncherDialog *ld) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
static void launcher_dialog_response (GtkWidget *dialog,
gint response,
LauncherDialog *ld);
/**
* .Desktop entry
**/
static void
launcher_dialog_g_list_swap (GList *li_a,
GList *li_b)
{
gpointer data;
/* swap the data pointers */
data = li_a->data;
li_a->data = li_b->data;
li_b->data = data;
}
static gboolean
launcher_dialog_read_desktop_file (const gchar *path,
LauncherEntry *entry)
{
XfceRc *rc = NULL;
const gchar *value = NULL;
const gchar *p;
/* we only support .desktop files */
if (G_UNLIKELY (g_str_has_suffix (path, ".desktop") == FALSE ||
g_path_is_absolute (path) == FALSE))
return FALSE;
/* open de .desktop file */
rc = xfce_rc_simple_open (path, TRUE);
if (G_UNLIKELY (rc == NULL))
return FALSE;
/* set the desktop entry group */
xfce_rc_set_group (rc, "Desktop Entry");
/* name */
value = xfce_rc_read_entry (rc, "Name", NULL);
if (G_LIKELY (value != NULL))
{
g_free (entry->name);
entry->name = g_strdup (value);
}
/* comment */
value = xfce_rc_read_entry (rc, "Comment", NULL);
if (G_LIKELY (value != NULL))
{
g_free (entry->comment);
entry->comment = g_strdup (value);
}
/* icon */
value = xfce_rc_read_entry_untranslated (rc, "Icon", NULL);
if (G_LIKELY (value != NULL))
{
g_free (entry->icon);
/* get rid of extensions in non-absolute names */
if (G_UNLIKELY (g_path_is_absolute (value) == FALSE) &&
((p = g_strrstr (value, ".")) && strlen (p) < 6))
entry->icon = g_strndup (value, p-value);
else
entry->icon = g_strdup (value);
}
/* exec */
value = xfce_rc_read_entry_untranslated (rc, "Exec", NULL);
if (G_LIKELY (value != NULL))
{
g_free (entry->exec);
/* expand variables and store */
entry->exec = value ? xfce_expand_variables (value, NULL) : NULL;
}
/* working directory */
value = xfce_rc_read_entry_untranslated (rc, "Path", NULL);
if (G_UNLIKELY (value != NULL))
{
g_free (entry->path);
/* expand variables and store */
entry->path = value ? xfce_expand_variables (value, NULL) : NULL;
}
/* terminal */
entry->terminal = xfce_rc_read_bool_entry (rc, "Terminal", FALSE);
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
/* startup notification */
entry->startup = xfce_rc_read_bool_entry (rc, "StartupNotify", FALSE);
#endif
/* release rc file */
xfce_rc_close (rc);
return TRUE;
}
static void
launcher_dialog_tree_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
LauncherDialog *ld)
{
GtkTreePath *path = NULL;
GtkTreeViewDropPosition position;
GtkTreeModel *model;
GtkTreeIter iter_a;
GtkTreeIter iter_b;
GSList *filenames = NULL;
GSList *li;
const gchar *file;
gboolean insert_before = FALSE;
gboolean update_icon = FALSE;
gint i = 0;
LauncherEntry *entry;
GdkPixbuf *pixbuf;
/* get drop position in the tree */
if (gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (ld->treeview),
x, y, &path, &position) == FALSE)
{
/* probably droped in empty tree space, drop after last item */
path = gtk_tree_path_new_from_indices (g_list_length (ld->launcher->entries) -1 , -1);
position = GTK_TREE_VIEW_DROP_AFTER;
}
if (G_LIKELY (path != NULL))
{
/* get the iter we're going to drop after */
model = gtk_tree_view_get_model (GTK_TREE_VIEW (ld->treeview));
gtk_tree_model_get_iter (model, &iter_a, path);
/* array position or current item */
i = gtk_tree_path_get_indices (path)[0];
/* insert position, array correction and the path we select afterwards */
switch (position)
{
case GTK_TREE_VIEW_DROP_BEFORE:
case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
insert_before = TRUE;
break;
case GTK_TREE_VIEW_DROP_AFTER:
case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
gtk_tree_path_next (path);
++i;
insert_before = FALSE;
break;
}
/* we need to update the button icon afterwards */
if (i == 0)
update_icon = TRUE;
/* create list from selection data */
filenames = launcher_utility_filenames_from_selection_data (selection_data);
}
if (G_LIKELY (filenames != NULL))
{
for (li = filenames; li != NULL; li = li->next)
{
file = li->data;
/* create new entry */
entry = launcher_entry_new ();
/* try to parse desktop file */
if (G_LIKELY (launcher_dialog_read_desktop_file (file, entry) == TRUE))
{
/* insert new row in store */
if (insert_before)
gtk_list_store_insert_before (ld->store, &iter_b, &iter_a);
else
gtk_list_store_insert_after (ld->store, &iter_b, &iter_a);
/* try to load the pixbuf */
pixbuf = launcher_utility_load_pixbuf (gtk_widget_get_screen (ld->treeview), entry->icon, LAUNCHER_TREE_ICON_SIZE);
/* set tree data */
gtk_list_store_set (ld->store, &iter_b,
COLUMN_ICON, pixbuf,
COLUMN_NAME, entry->name,
-1);
/* release pixbuf */
if (G_LIKELY (pixbuf != NULL))
g_object_unref (G_OBJECT (pixbuf));
/* insert in list */
ld->launcher->entries = g_list_insert (ld->launcher->entries, entry, i);
/* copy iter, so we add after last item */
iter_a = iter_b;
/* raise position counter */
++i;
/* 1st item is inserted before existing item, after
* that we insert after the 1st item */
insert_before = FALSE;
}
else
{
/* desktop file pasring failed, free new entry */
launcher_entry_free (entry, NULL);
}
}
/* select the new item (also updates treeview buttons) */
gtk_tree_view_set_cursor (GTK_TREE_VIEW (ld->treeview), path, NULL, FALSE);
/* update the panel */
launcher_plugin_rebuild (ld->launcher, update_icon);
/* cleanup */
launcher_free_filenames (filenames);
}
/* free path */
if (G_LIKELY (path != NULL))
gtk_tree_path_free (path);
/* finish drag */
gtk_drag_finish (context, TRUE, FALSE, time);
}
static void
launcher_dialog_frame_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint time,
LauncherDialog *ld)
{
GSList *filenames, *li;
gchar *file;
gboolean update_icon = FALSE;
/* create list from all the uri list */
filenames = launcher_utility_filenames_from_selection_data (selection_data);
if (G_LIKELY (filenames != NULL))
{
for (li = filenames; li != NULL; li = li->next)
{
file = (gchar *) li->data;
/* try to update the current entry settings */
if (G_LIKELY (launcher_dialog_read_desktop_file (file, ld->entry) == TRUE))
{
/* update the widgets */
launcher_dialog_update_entries (ld);
/* update the tree */
launcher_dialog_tree_update_row (ld, COLUMN_NAME);
launcher_dialog_tree_update_row (ld, COLUMN_ICON);
/* also update the panel button icon */
if (g_list_index (ld->launcher->entries, ld->entry) == 0)
update_icon = TRUE;
/* update the panel */
launcher_plugin_rebuild (ld->launcher, update_icon);
/* stop trying */
break;
}
}
/* cleanup */
launcher_free_filenames (filenames);
}
/* finish drag */
gtk_drag_finish (context, TRUE, FALSE, time);
}
/**
* Properties update and save functions
**/
static void
launcher_dialog_save_entry (GtkWidget *entry,
LauncherDialog *ld)
{
const gchar *text;
/* quit if locked or no active entry set */
if (G_UNLIKELY (ld->updating == TRUE || ld->entry == NULL))
return;
/* get entry text */
text = gtk_entry_get_text (GTK_ENTRY (entry));
/* set text to null, if there is no valid text */
if (G_UNLIKELY (text == NULL || *text == '\0'))
text = NULL;
/* save new value */
if (entry == ld->entry_name)
{
g_free (ld->entry->name);
ld->entry->name = g_strdup (text);
/* update tree, when triggered by widget */
launcher_dialog_tree_update_row (ld, COLUMN_NAME);
}
else if (entry == ld->entry_comment)
{
g_free (ld->entry->comment);
ld->entry->comment = g_strdup (text);
}
else if (entry == ld->entry_exec)
{
g_free (ld->entry->exec);
ld->entry->exec = text ? xfce_expand_variables (text, NULL) : NULL;
}
else if (entry == ld->entry_path)
{
g_free (ld->entry->path);
ld->entry->path = text ? xfce_expand_variables (text, NULL) : NULL;
}
/* update panel */
launcher_plugin_rebuild (ld->launcher, FALSE);
}
static void
launcher_dialog_save_button (GtkWidget *button,
LauncherDialog *ld)
{
gboolean active;
/* quit if locked or no active entry set */
if (G_UNLIKELY (ld->updating == TRUE || ld->entry == NULL))
return;
/* get toggle button state */
active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
/* update entry or global setting */
if (button == ld->entry_terminal)
{
ld->entry->terminal = active;
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
gtk_widget_set_sensitive (ld->entry_startup, !active);
#endif
}
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
else if (button == ld->entry_startup)
ld->entry->startup = active;
#endif
}
static void
launcher_dialog_update_entries (LauncherDialog *ld)
{
/* quit if locked or no active entry set */
if (G_UNLIKELY (ld->updating == TRUE || ld->entry == NULL))
return;
/* lock the save functions */
ld->updating = TRUE;
/* set new entry values */
gtk_entry_set_text (GTK_ENTRY (ld->entry_name),
(ld->entry->name != NULL) ? ld->entry->name : "");
gtk_entry_set_text (GTK_ENTRY (ld->entry_comment),
(ld->entry->comment != NULL) ? ld->entry->comment : "");
gtk_entry_set_text (GTK_ENTRY (ld->entry_exec),
(ld->entry->exec != NULL) ? ld->entry->exec : "");
gtk_entry_set_text (GTK_ENTRY (ld->entry_path),
(ld->entry->path != NULL) ? ld->entry->path : "");
/* set toggle buttons */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ld->entry_terminal),
ld->entry->terminal);
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ld->entry_startup),
ld->entry->startup);
gtk_widget_set_sensitive (ld->entry_startup, !ld->entry->terminal);
#endif
/* update icon button */
launcher_dialog_update_icon (ld);
/* unlock */
ld->updating = FALSE;
}
static void
launcher_dialog_update_icon (LauncherDialog *ld)
{
GdkPixbuf *icon = NULL;
GtkWidget *child;
/* drop the previous button child */
if (GTK_BIN (ld->entry_icon)->child != NULL)
gtk_widget_destroy (GTK_BIN (ld->entry_icon)->child);
if (G_LIKELY (ld->entry->icon))
icon = launcher_utility_load_pixbuf (gtk_widget_get_screen (ld->entry_icon), ld->entry->icon, LAUNCHER_CHOOSER_ICON_SIZE);
/* create icon button */
if (G_LIKELY (icon != NULL))
{
/* create image from pixbuf */
child = gtk_image_new_from_pixbuf (icon);
/* release icon */
g_object_unref (G_OBJECT (icon));
gtk_widget_set_size_request (child, LAUNCHER_CHOOSER_ICON_SIZE, LAUNCHER_CHOOSER_ICON_SIZE);
}
else
{
child = gtk_label_new (_("No icon"));
gtk_widget_set_size_request (child, -1, LAUNCHER_CHOOSER_ICON_SIZE);
}
gtk_container_add (GTK_CONTAINER (ld->entry_icon), child);
gtk_widget_show (child);
}
/**
* Icon and command search dialogs
**/
static void
launcher_dialog_folder_chooser (LauncherDialog *ld)
{
GtkWidget *chooser;
gchar *path;
chooser = gtk_file_chooser_dialog_new (_("Select a Directory"),
NULL,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
/* only here */
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
/* use the bindir as default folder */
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), BINDIR);
/* select folder from field */
if (G_LIKELY (ld->entry->path != NULL))
{
if (G_LIKELY (g_path_is_absolute (ld->entry->path)))
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), ld->entry->path);
}
/* run the chooser dialog */
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
{
path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
/* set the new entry text */
gtk_entry_set_text (GTK_ENTRY (ld->entry_path), path);
/* cleanup */
g_free (path);
}
/* destroy dialog */
gtk_widget_destroy (chooser);
}
static void
launcher_dialog_command_chooser (LauncherDialog *ld)
{
GtkFileFilter *filter;
GtkWidget *chooser;
gchar *filename;
gchar *s;
chooser = gtk_file_chooser_dialog_new (_("Select an Application"),
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
/* add file chooser filters */
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All Files"));
gtk_file_filter_add_pattern (filter, "*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Executable Files"));
gtk_file_filter_add_mime_type (filter, "application/x-csh");
gtk_file_filter_add_mime_type (filter, "application/x-executable");
gtk_file_filter_add_mime_type (filter, "application/x-perl");
gtk_file_filter_add_mime_type (filter, "application/x-python");
gtk_file_filter_add_mime_type (filter, "application/x-ruby");
gtk_file_filter_add_mime_type (filter, "application/x-shellscript");
gtk_file_filter_add_pattern (filter, "*.pl");
gtk_file_filter_add_pattern (filter, "*.py");
gtk_file_filter_add_pattern (filter, "*.rb");
gtk_file_filter_add_pattern (filter, "*.sh");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Perl Scripts"));
gtk_file_filter_add_mime_type (filter, "application/x-perl");
gtk_file_filter_add_pattern (filter, "*.pl");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Python Scripts"));
gtk_file_filter_add_mime_type (filter, "application/x-python");
gtk_file_filter_add_pattern (filter, "*.py");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Ruby Scripts"));
gtk_file_filter_add_mime_type (filter, "application/x-ruby");
gtk_file_filter_add_pattern (filter, "*.rb");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("Shell Scripts"));
gtk_file_filter_add_mime_type (filter, "application/x-csh");
gtk_file_filter_add_mime_type (filter, "application/x-shellscript");
gtk_file_filter_add_pattern (filter, "*.sh");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
/* use the bindir as default folder */
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), BINDIR);
/* get the current command */
filename = gtk_editable_get_chars (GTK_EDITABLE (ld->entry_exec), 0, -1);
if (G_LIKELY (filename != NULL))
{
/* use only the first argument */
s = strchr (filename, ' ');
if (G_UNLIKELY (s != NULL))
*s = '\0';
/* check if we have a file name */
if (G_LIKELY (*filename != '\0'))
{
/* check if the filename is not an absolute path */
if (G_LIKELY (!g_path_is_absolute (filename)))
{
/* try to lookup the filename in $PATH */
s = g_find_program_in_path (filename);
if (G_LIKELY (s != NULL))
{
/* use the absolute path instead */
g_free (filename);
filename = s;
}
}
/* check if we have an absolute path now */
if (G_LIKELY (g_path_is_absolute (filename)))
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), filename);
}
/* release the filename */
g_free (filename);
}
/* run the chooser dialog */
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
{
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
/* set the new entry text */
gtk_entry_set_text (GTK_ENTRY (ld->entry_exec), filename);
/* cleanup */
g_free (filename);
}
/* destroy dialog */
gtk_widget_destroy (chooser);
}
static void
launcher_dialog_icon_chooser (LauncherDialog *ld)
{
const gchar *name;
GtkWidget *chooser;
gchar *title;
gboolean update_icon = FALSE;
/* determine the name of the entry being edited */
name = gtk_entry_get_text (GTK_ENTRY (ld->entry_name));
if (G_UNLIKELY (name == NULL || *name == '\0'))
name = _("Unknown");
/* allocate the chooser dialog */
title = g_strdup_printf (_("Select an Icon for \"%s\""), name);
chooser = exo_icon_chooser_dialog_new (title, NULL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT, GTK_RESPONSE_CANCEL, -1);
gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT);
g_free (title);
/* set the current icon, if there is any */
if (G_LIKELY (ld->entry->icon))
exo_icon_chooser_dialog_set_icon (EXO_ICON_CHOOSER_DIALOG (chooser), ld->entry->icon);
/* run the icon chooser dialog */
if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
{
/* free the old icon name */
if (G_LIKELY (ld->entry->icon))
g_free (ld->entry->icon);
/* set new icon */
ld->entry->icon = exo_icon_chooser_dialog_get_icon (EXO_ICON_CHOOSER_DIALOG (chooser));
/* update the icon button */
launcher_dialog_update_icon (ld);
/* update the icon column in the tree */
launcher_dialog_tree_update_row (ld, COLUMN_ICON);
/* check if we need to update the icon button image */
if (g_list_index (ld->launcher->entries, ld->entry) == 0)
update_icon = TRUE;
/* update the panel widgets */
launcher_plugin_rebuild (ld->launcher, update_icon);
}
/* destroy the chooser */
gtk_widget_destroy (chooser);
}
/**
* Tree functions
**/
static void
launcher_dialog_tree_update_row (LauncherDialog *ld,
gint column)
{
GtkTreeSelection *selection;
GtkTreeIter iter;
GdkPixbuf *icon = NULL;
const gchar *name;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ld->treeview));
if (G_LIKELY (gtk_tree_selection_get_selected (selection, NULL, &iter)))
{
switch (column)
{
case COLUMN_ICON:
/* load entry icon */
icon = launcher_utility_load_pixbuf (gtk_widget_get_screen (ld->treeview), ld->entry->icon, LAUNCHER_TREE_ICON_SIZE);
/* set new icon */
gtk_list_store_set (ld->store, &iter,
COLUMN_ICON, icon,
-1);
/* release icon */
if (G_LIKELY (icon != NULL))
g_object_unref (G_OBJECT (icon));
break;
case COLUMN_NAME:
/* build name */
name = ld->entry->name ? ld->entry->name : _("Unnamed");
/* set new name */
gtk_list_store_set (ld->store, &iter,
COLUMN_NAME, name,
-1);
break;
}
}
}
static void
launcher_dialog_tree_selection_changed (LauncherDialog *ld,
GtkTreeSelection *selection)
{
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
gboolean selected;
gint position = 0;
gint items;
if (G_UNLIKELY (ld->updating == TRUE))
return;
g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
/* check if we have currently selected an item */
selected = gtk_tree_selection_get_selected (selection, &model, &iter);
if (G_LIKELY (selected))
{
/* determine the path for the selected iter */
path = gtk_tree_model_get_path (model, &iter);
/* get position */
position = gtk_tree_path_get_indices (path)[0];
/* set new active entry */
ld->entry = (LauncherEntry *) g_list_nth (ld->launcher->entries, position)->data;
/* update fields */
launcher_dialog_update_entries (ld);
/* scroll new item to center of window */
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (ld->treeview), path, NULL,
TRUE, 0.5, 0.0);
/* release path */
gtk_tree_path_free (path);
}
/* items in the list */
items = gtk_tree_model_iter_n_children (model, NULL);
/* change sensitivity of buttons */
gtk_widget_set_sensitive (ld->up, selected && (position > 0));
gtk_widget_set_sensitive (ld->down, selected && (position < items - 1));
gtk_widget_set_sensitive (ld->remove, selected && (items > 1));
}
static void
launcher_dialog_tree_button_clicked (GtkWidget *button,
LauncherDialog *ld)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter_a;
GtkTreeIter iter_b;
guint position;
gint list_length;
GList *li;
GdkPixbuf *icon = NULL;
LauncherEntry *entry;
gboolean update_icon = FALSE;
/* get the selected items in the treeview */
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ld->treeview));
/* get selected iter, quit if no iter found */
if (G_UNLIKELY (gtk_tree_selection_get_selected (selection, &model, &iter_a) == FALSE))
return;
/* run the requested button action */
if (button == ld->up)
{
/* get path */
path = gtk_tree_model_get_path (model, &iter_a);
/* position of the item in the list */
position = gtk_tree_path_get_indices (path)[0];
/* check if we need to update the icon button image */
if (position == 1)
update_icon = TRUE;
/* get previous path */
if (G_LIKELY (gtk_tree_path_prev (path)))
{
/* get iter for previous item */
gtk_tree_model_get_iter (model, &iter_b, path);
/* swap the entries */
gtk_list_store_swap (ld->store, &iter_a, &iter_b);
/* swap items in the list */
li = g_list_nth (ld->launcher->entries, position);
launcher_dialog_g_list_swap (li, li->prev);
}
/* release the path */
gtk_tree_path_free (path);
/* update tree view */
launcher_dialog_tree_selection_changed (ld, selection);
}
else if (button == ld->down)
{
/* get path of selected item */
path = gtk_tree_model_get_path (model, &iter_a);
/* get position of item we're going to move */
position = gtk_tree_path_get_indices (path)[0];
/* check if we need to update the icon button image*/
if (position == 0)
update_icon = TRUE;
/* get next item in the list */
gtk_tree_path_next (path);
/* get next iter */
if (G_LIKELY (gtk_tree_model_get_iter (model, &iter_b, path)))
{
/* swap the entries */
gtk_list_store_swap (ld->store, &iter_a, &iter_b);
/* swap items in the list */
li = g_list_nth (ld->launcher->entries, position);
launcher_dialog_g_list_swap (li, li->next);
}
/* release the path */
gtk_tree_path_free (path);
/* update tree view */
launcher_dialog_tree_selection_changed (ld, selection);
}
else if (button == ld->add)
{
/* create new entry */
entry = launcher_entry_new ();
/* load new launcher icon */
icon = launcher_utility_load_pixbuf (gtk_widget_get_screen (ld->treeview), entry->icon, LAUNCHER_TREE_ICON_SIZE);
/* append new entry */
gtk_list_store_insert_after (ld->store, &iter_b, &iter_a);
gtk_list_store_set (ld->store, &iter_b,
COLUMN_ICON, icon,
COLUMN_NAME, entry->name,
-1);
/* release the pixbuf */
if (G_LIKELY (icon != NULL))
g_object_unref (G_OBJECT (icon));
/* get path of new item */
path = gtk_tree_model_get_path (model, &iter_b);
/* position in the list */
position = gtk_tree_path_get_indices (path)[0];
/* insert in list */
ld->launcher->entries = g_list_insert (ld->launcher->entries,
entry, position);
/* select the new item (also updates treeview buttons) */
gtk_tree_view_set_cursor (GTK_TREE_VIEW (ld->treeview), path, NULL, FALSE);
/* cleanup */
gtk_tree_path_free (path);
/* allow to set the arrow position */
gtk_widget_set_sensitive (ld->arrow_position, TRUE);
}
else if (button == ld->remove)
{
/* path from row to remove */
path = gtk_tree_model_get_path (model, &iter_a);
/* get position of the item to remove */
position = gtk_tree_path_get_indices (path)[0];
/* check if we need to update the icon button image*/
if (position == 0)
update_icon = TRUE;
/* lock */
ld->updating = TRUE;
/* remove active entry */
launcher_entry_free (ld->entry, ld->launcher);
ld->entry = NULL;
/* remove row from store */
gtk_list_store_remove (ld->store, &iter_a);
/* unlock */
ld->updating = FALSE;
/* list length */
list_length = g_list_length (ld->launcher->entries);
/* select previous item, if last item was removed */
if (position >= list_length)
gtk_tree_path_prev (path);
/* select the new item (also updates treeview buttons) */
gtk_tree_view_set_cursor (GTK_TREE_VIEW (ld->treeview), path, NULL, FALSE);
/* cleanup */
gtk_tree_path_free (path);
/* allow to set the arrow position */
gtk_widget_set_sensitive (ld->arrow_position, list_length > 1);
/* don't allow menu arrows */
if (list_length == 1 && ld->launcher->arrow_position == LAUNCHER_ARROW_INSIDE_BUTTON)
gtk_combo_box_set_active (GTK_COMBO_BOX (ld->arrow_position), LAUNCHER_ARROW_DEFAULT);
}
/* update panel */
launcher_plugin_rebuild (ld->launcher, update_icon);
}
static void
launcher_dialog_arrow_position_changed (GtkComboBox *combo,
LauncherDialog *ld)
{
ld->launcher->arrow_position = gtk_combo_box_get_active (combo);
launcher_plugin_rebuild (ld->launcher, TRUE);
}
/**
* Launcher dialog widgets
**/
static GtkWidget *
launcher_dialog_add_properties (LauncherDialog *ld)
{
GtkWidget *frame, *vbox, *hbox;
GtkWidget *label, *button, *image;
GtkSizeGroup *sg;
frame = gtk_frame_new (NULL);
vbox = gtk_vbox_new (FALSE, BORDER);
gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
gtk_container_add (GTK_CONTAINER (frame), vbox);
sg = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
/* entry name field */
hbox = gtk_hbox_new (FALSE, BORDER);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new_with_mnemonic (_("_Name"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_size_group_add_widget (sg, label);
ld->entry_name = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_name, TRUE, TRUE, 0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), ld->entry_name);
g_signal_connect (G_OBJECT (ld->entry_name), "changed",
G_CALLBACK (launcher_dialog_save_entry), ld);
/* entry comment field */
hbox = gtk_hbox_new (FALSE, BORDER);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new_with_mnemonic (_("_Description"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_size_group_add_widget (sg, label);
ld->entry_comment = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_comment, TRUE, TRUE, 0);
gtk_widget_set_size_request (ld->entry_comment, 300, -1);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), ld->entry_comment);
g_signal_connect (G_OBJECT (ld->entry_comment), "changed",
G_CALLBACK (launcher_dialog_save_entry), ld);
/* entry icon chooser button */
hbox = gtk_hbox_new (FALSE, BORDER);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new_with_mnemonic (_("_Icon"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_size_group_add_widget (sg, label);
ld->entry_icon = gtk_button_new ();
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_icon, FALSE, FALSE, 0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), ld->entry_icon);
g_signal_connect_swapped (G_OBJECT (ld->entry_icon), "clicked",
G_CALLBACK (launcher_dialog_icon_chooser), ld);
/* entry command field and button */
hbox = gtk_hbox_new (FALSE, BORDER);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
label = gtk_label_new_with_mnemonic (_("Co_mmand"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_size_group_add_widget (sg, label);
ld->entry_exec = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_exec, TRUE, TRUE, 0);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), ld->entry_exec);
g_signal_connect (G_OBJECT (ld->entry_exec), "changed",
G_CALLBACK (launcher_dialog_save_entry), ld);
button = gtk_button_new ();
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect_swapped (G_OBJECT (button), "clicked",
G_CALLBACK (launcher_dialog_command_chooser), ld);