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.
1594 lines
54 KiB
1594 lines
54 KiB
/* $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 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;
|
|
}
|
|
|
|
|
|
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;
|
|
gint position, 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);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
|
|
gtk_container_add (GTK_CONTAINER (button), image);
|
|
|
|
/* working directory field */
|
|
hbox = gtk_hbox_new (FALSE, BORDER);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new_with_mnemonic (_("_Working Directory"));
|
|
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_path = gtk_entry_new ();
|
|
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_path, TRUE, TRUE, 0);
|
|
|
|
gtk_label_set_mnemonic_widget (GTK_LABEL (label), ld->entry_path);
|
|
|
|
g_signal_connect (G_OBJECT (ld->entry_path), "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_folder_chooser), ld);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU);
|
|
gtk_container_add (GTK_CONTAINER (button), image);
|
|
|
|
/* entry terminal toggle button with spacer */
|
|
hbox = gtk_hbox_new (FALSE, BORDER);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
label = gtk_alignment_new (0, 0, 0, 0);
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_size_group_add_widget (sg, label);
|
|
|
|
ld->entry_terminal = gtk_check_button_new_with_mnemonic (_("Run in _terminal"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_terminal, TRUE, TRUE, 0);
|
|
|
|
g_signal_connect (G_OBJECT (ld->entry_terminal), "toggled",
|
|
G_CALLBACK (launcher_dialog_save_button), ld);
|
|
|
|
#ifdef HAVE_LIBSTARTUP_NOTIFICATION
|
|
/* startup notification */
|
|
hbox = gtk_hbox_new (FALSE, BORDER);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
label = gtk_alignment_new (0, 0, 0, 0);
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
|
|
gtk_size_group_add_widget (sg, label);
|
|
|
|
ld->entry_startup = gtk_check_button_new_with_mnemonic (_("Use _startup notification"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), ld->entry_startup, TRUE, TRUE, 0);
|
|
|
|
g_signal_connect (G_OBJECT (ld->entry_startup), "toggled",
|
|
G_CALLBACK (launcher_dialog_save_button), ld);
|
|
#endif
|
|
|
|
/* release size group */
|
|
g_object_unref (G_OBJECT (sg));
|
|
|
|
/* setup dnd in frame */
|
|
gtk_drag_dest_set (frame, GTK_DEST_DEFAULT_ALL,
|
|
drop_targets, G_N_ELEMENTS (drop_targets),
|
|
GDK_ACTION_COPY);
|
|
|
|
g_signal_connect (frame, "drag-data-received",
|
|
G_CALLBACK (launcher_dialog_frame_drag_data_received), ld);
|
|
|
|
return frame;
|
|
}
|
|
|
|
|
|
|
|
|
|
static GtkWidget *
|
|
launcher_dialog_add_tree (LauncherDialog *ld)
|
|
{
|
|
GtkWidget *scroll;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeSelection *selection;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeIter iter;
|
|
GList *li;
|
|
LauncherEntry *entry;
|
|
GdkPixbuf *icon;
|
|
const gchar *name;
|
|
|
|
/* scrolled window */
|
|
scroll = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
|
|
GTK_POLICY_NEVER,
|
|
GTK_POLICY_AUTOMATIC);
|
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
|
|
GTK_SHADOW_IN);
|
|
|
|
/* create new list store */
|
|
ld->store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING);
|
|
|
|
/* create tree view */
|
|
ld->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (ld->store));
|
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ld->treeview), FALSE);
|
|
gtk_tree_view_set_search_column (GTK_TREE_VIEW (ld->treeview), COLUMN_NAME);
|
|
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (ld->treeview), TRUE);
|
|
gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (ld->treeview), TRUE);
|
|
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (ld->treeview), TRUE);
|
|
gtk_container_add (GTK_CONTAINER (scroll), ld->treeview);
|
|
|
|
/* create columns and cell renders */
|
|
column = gtk_tree_view_column_new ();
|
|
gtk_tree_view_column_set_expand (column, TRUE);
|
|
gtk_tree_view_column_set_resizable (column, FALSE);
|
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (ld->treeview), column);
|
|
|
|
renderer = gtk_cell_renderer_pixbuf_new();
|
|
gtk_cell_renderer_set_fixed_size (renderer, LAUNCHER_TREE_ICON_SIZE, LAUNCHER_TREE_ICON_SIZE);
|
|
gtk_tree_view_column_pack_start (column, renderer, FALSE);
|
|
gtk_tree_view_column_set_attributes (column, renderer, "pixbuf", COLUMN_ICON, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
gtk_tree_view_column_pack_start (column, renderer, TRUE);
|
|
gtk_tree_view_column_set_attributes (column, renderer, "text", COLUMN_NAME, NULL);
|
|
g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
|
|
|
/* set selection change signal */
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ld->treeview));
|
|
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
|
|
g_signal_connect_swapped (G_OBJECT (selection), "changed",
|
|
G_CALLBACK (launcher_dialog_tree_selection_changed), ld);
|
|
|
|
/* append current items */
|
|
for (li = ld->launcher->entries; li != NULL; li = li->next)
|
|
{
|
|
entry = li->data;
|
|
|
|
if (G_LIKELY (entry))
|
|
{
|
|
/* load icon */
|
|
icon = launcher_utility_load_pixbuf (gtk_widget_get_screen (ld->treeview), entry->icon, LAUNCHER_TREE_ICON_SIZE);
|
|
|
|
/* build name */
|
|
name = entry->name ? entry->name : _("Unnamed");
|
|
|
|
/* create new row and add the data */
|
|
gtk_list_store_append (ld->store, &iter);
|
|
gtk_list_store_set (ld->store, &iter,
|
|
COLUMN_ICON, icon,
|
|
COLUMN_NAME, name, -1);
|
|
|
|
/* release the pixbuf */
|
|
if (G_LIKELY (icon))
|
|
g_object_unref (G_OBJECT (icon));
|
|
}
|
|
}
|
|
|
|
/* dnd support */
|
|
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (ld->treeview),
|
|
drop_targets, G_N_ELEMENTS (drop_targets),
|
|
GDK_ACTION_COPY);
|
|
|
|
g_signal_connect (G_OBJECT (ld->treeview), "drag-data-received",
|
|
G_CALLBACK (launcher_dialog_tree_drag_data_received), ld);
|
|
|
|
return scroll;
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget *
|
|
launcher_dialog_add_tree_buttons (LauncherDialog *ld)
|
|
{
|
|
GtkWidget *hbox, *button, *align, *image;
|
|
|
|
hbox = gtk_hbox_new (FALSE, BORDER);
|
|
|
|
/* up button */
|
|
ld->up = button = gtk_button_new ();
|
|
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON);
|
|
gtk_container_add (GTK_CONTAINER (button), image);
|
|
|
|
g_signal_connect (G_OBJECT (button), "clicked",
|
|
G_CALLBACK (launcher_dialog_tree_button_clicked), ld);
|
|
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
|
|
/* down button */
|
|
ld->down = button = gtk_button_new ();
|
|
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON);
|
|
gtk_container_add (GTK_CONTAINER (button), image);
|
|
|
|
g_signal_connect (G_OBJECT (button), "clicked",
|
|
G_CALLBACK (launcher_dialog_tree_button_clicked), ld);
|
|
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
|
|
/* free space between buttons */
|
|
align = gtk_alignment_new (0, 0, 0, 0);
|
|
gtk_widget_set_size_request (align, 1, 1);
|
|
gtk_box_pack_start (GTK_BOX (hbox), align, TRUE, TRUE, 0);
|
|
|
|
/* add button */
|
|
ld->add = button = gtk_button_new ();
|
|
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
|
|
gtk_container_add (GTK_CONTAINER (button), image);
|
|
|
|
g_signal_connect (G_OBJECT (button), "clicked",
|
|
G_CALLBACK (launcher_dialog_tree_button_clicked), ld);
|
|
|
|
/* remove button */
|
|
ld->remove = button = gtk_button_new ();
|
|
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
|
|
|
image = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_BUTTON);
|
|
gtk_container_add (GTK_CONTAINER (button), image);
|
|
|
|
g_signal_connect (G_OBJECT (button), "clicked",
|
|
G_CALLBACK (launcher_dialog_tree_button_clicked), ld);
|
|
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
|
|
return hbox;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Dialog functions
|
|
**/
|
|
static void
|
|
launcher_dialog_response (GtkWidget *dialog,
|
|
gint response,
|
|
LauncherDialog *ld)
|
|
{
|
|
LauncherPlugin *launcher = ld->launcher;
|
|
|
|
/* hide the dialog */
|
|
gtk_widget_hide (dialog);
|
|
|
|
/* lock for further updates */
|
|
ld->updating = TRUE;
|
|
ld->entry = NULL;
|
|
|
|
/* cleanup the store */
|
|
gtk_list_store_clear (ld->store);
|
|
g_object_unref (G_OBJECT (ld->store));
|
|
|
|
/* the launcher dialog dataS */
|
|
g_object_set_data (G_OBJECT (launcher->panel_plugin), I_("launcher-dialog"), NULL);
|
|
|
|
/* destroy the dialog */
|
|
gtk_widget_destroy (dialog);
|
|
|
|
/* unlock plugin menu */
|
|
xfce_panel_plugin_unblock_menu (launcher->panel_plugin);
|
|
|
|
/* restore move first */
|
|
launcher->move_first = ld->stored_move_first;
|
|
|
|
/* allow saving again */
|
|
launcher->plugin_can_save = TRUE;
|
|
|
|
if (response == GTK_RESPONSE_OK)
|
|
{
|
|
/* write new settings */
|
|
launcher_plugin_save (launcher);
|
|
}
|
|
else /* revert changes */
|
|
{
|
|
/* remove all the entries */
|
|
g_list_foreach (launcher->entries, (GFunc) launcher_entry_free, launcher);
|
|
|
|
/* read the last saved settings */
|
|
launcher_plugin_read (launcher);
|
|
|
|
/* add new item if there are no entries yet */
|
|
if (G_UNLIKELY (g_list_length (launcher->entries) == 0))
|
|
launcher->entries = g_list_append (launcher->entries, launcher_entry_new ());
|
|
}
|
|
|
|
/* free the panel structure */
|
|
g_slice_free (LauncherDialog, ld);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
launcher_dialog_show (LauncherPlugin *launcher)
|
|
{
|
|
LauncherDialog *ld;
|
|
GtkWidget *dialog;
|
|
GtkWidget *dialog_vbox;
|
|
GtkWidget *paned, *vbox, *hbox;
|
|
GtkWidget *widget, *label, *combo;
|
|
GtkTreePath *path;
|
|
|
|
/* create new structure */
|
|
ld = g_slice_new0 (LauncherDialog);
|
|
|
|
/* init */
|
|
ld->launcher = launcher;
|
|
ld->entry = g_list_first (launcher->entries)->data;
|
|
|
|
/* prevent saving to be able to use the cancel button */
|
|
launcher->plugin_can_save = FALSE;
|
|
|
|
/* lock right-click plugin menu */
|
|
xfce_panel_plugin_block_menu (launcher->panel_plugin);
|
|
|
|
/* disable the auto sort of the list, while working in properties */
|
|
ld->stored_move_first = launcher->move_first;
|
|
launcher->move_first = FALSE;
|
|
|
|
/* create new dialog */
|
|
dialog = xfce_titled_dialog_new_with_buttons (_("Program Launcher"),
|
|
NULL,
|
|
GTK_DIALOG_NO_SEPARATOR,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
|
NULL);
|
|
gtk_window_set_screen (GTK_WINDOW (dialog), gtk_widget_get_screen (GTK_WIDGET (launcher->panel_plugin)));
|
|
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
|
|
gtk_window_set_icon_name (GTK_WINDOW (dialog), "xfce4-settings");
|
|
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
|
|
|
|
/* connect dialog to plugin, so we can destroy it when plugin is closed */
|
|
g_object_set_data (G_OBJECT (ld->launcher->panel_plugin), "dialog", dialog);
|
|
|
|
dialog_vbox = GTK_DIALOG (dialog)->vbox;
|
|
|
|
/* added the horizontal panes */
|
|
paned = gtk_hpaned_new ();
|
|
gtk_box_pack_start (GTK_BOX (dialog_vbox), paned, TRUE, TRUE, 0);
|
|
gtk_container_set_border_width (GTK_CONTAINER (paned), BORDER - 2);
|
|
|
|
vbox = gtk_vbox_new (FALSE, BORDER);
|
|
gtk_paned_pack1 (GTK_PANED (paned), vbox, FALSE, FALSE);
|
|
|
|
/* arrow button position */
|
|
hbox = gtk_hbox_new (FALSE, BORDER);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
|
|
|
label = gtk_label_new_with_mnemonic (_("A_rrow:"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
|
|
|
ld->arrow_position = combo = gtk_combo_box_new_text ();
|
|
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
|
|
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Default"));
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Left"));
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Right"));
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Top"));
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Bottom"));
|
|
gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Inside Button"));
|
|
gtk_widget_set_sensitive (combo, g_list_length (launcher->entries) > 1);
|
|
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), launcher->arrow_position);
|
|
g_signal_connect (G_OBJECT (combo), "changed", G_CALLBACK (launcher_dialog_arrow_position_changed), ld);
|
|
gtk_widget_show (combo);
|
|
|
|
/* add the entries list */
|
|
widget = launcher_dialog_add_tree (ld);
|
|
gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
|
|
|
|
/* add the tree navigation buttons */
|
|
widget = launcher_dialog_add_tree_buttons (ld);
|
|
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
|
|
|
|
/* add the entry widgets */
|
|
widget = launcher_dialog_add_properties (ld);
|
|
gtk_paned_pack2 (GTK_PANED (paned), widget, TRUE, FALSE);
|
|
|
|
/* show all widgets inside dialog */
|
|
gtk_widget_show_all (dialog_vbox);
|
|
|
|
/* focus the title entry */
|
|
gtk_widget_grab_focus (ld->entry_name);
|
|
|
|
/* select first item in the tree (this also updates the fields) */
|
|
path = gtk_tree_path_new_first ();
|
|
gtk_tree_view_set_cursor (GTK_TREE_VIEW (ld->treeview), path, NULL, FALSE);
|
|
gtk_tree_path_free (path);
|
|
|
|
/* connect response signal */
|
|
g_signal_connect (G_OBJECT (dialog), "response",
|
|
G_CALLBACK (launcher_dialog_response), ld);
|
|
|
|
/* show the dialog */
|
|
gtk_widget_show (dialog);
|
|
}
|
|
|