1
/* -*- c-basic-offset: 8; indent-tabs-mode: t -*-
4
* Copyright (C) 2003 Frank Worsley <fworsley@shaw.ca>
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22
* Frank Worsley <fworsley@shaw.ca>
25
* Havoc Pennington <hp@pobox.com>
26
* George Lebl <jirka@5z.com>
27
* Mark McLoughlin <mark@skynet.ie>
28
* Tom Tromey (Copyright (C) 1998)
33
#include "panel-run-dialog.h"
38
#include <sys/types.h>
41
#include <glib/gi18n.h>
43
#include <gdk/gdkkeysyms.h>
44
#include <gmenu-tree.h>
46
#include <libpanel-util/panel-error.h>
47
#include <libpanel-util/panel-glib.h>
48
#include <libpanel-util/panel-gtk.h>
49
#include <libpanel-util/panel-keyfile.h>
50
#include <libpanel-util/panel-show.h>
51
#include <libpanel-util/panel-xdg.h>
54
#include "panel-util.h"
55
#include "panel-globals.h"
56
#include "panel-enums.h"
57
#include "panel-stock-icons.h"
58
#include "panel-multiscreen.h"
60
#include "panel-lockdown.h"
61
#include "panel-xutils.h"
62
#include "panel-icon-names.h"
63
#include "panel-schemas.h"
66
GtkWidget *run_dialog;
68
GSettings *run_settings;
74
GtkWidget *run_button;
75
GtkWidget *file_button;
76
GtkWidget *list_expander;
77
GtkWidget *terminal_checkbox;
78
GtkWidget *program_label;
79
GtkWidget *program_list;
83
GtkListStore *program_list_store;
86
GList *possible_executables;
87
GList *completion_items;
88
GCompletion *completion;
90
GSList *add_icon_paths;
91
int add_items_idle_id;
92
int find_command_idle_id;
93
gboolean use_program_list;
94
gboolean completion_started;
111
static PanelRunDialog *static_dialog = NULL;
113
#define PANEL_RUN_MAX_HISTORY 20
115
static GtkTreeModel *
116
_panel_run_get_recent_programs_list (PanelRunDialog *dialog)
122
list = gtk_list_store_new (1, G_TYPE_STRING);
124
commands = g_settings_get_strv (dialog->run_settings,
125
PANEL_RUN_HISTORY_KEY);
127
for (i = 0; commands[i] != NULL; i++) {
129
gtk_list_store_prepend (list, &iter);
130
gtk_list_store_set (list, &iter, 0, commands[i], -1);
133
g_strfreev (commands);
135
return GTK_TREE_MODEL (list);
139
_panel_run_save_recent_programs_list (PanelRunDialog *dialog,
147
commands = g_settings_get_strv (dialog->run_settings,
148
PANEL_RUN_HISTORY_KEY);
150
/* do not save the same command twice in a row */
151
if (g_strcmp0 (commands[0], last_command) == 0)
154
for (i = 0; commands[i] != NULL; i++);
155
size = MIN (i + 1, PANEL_RUN_MAX_HISTORY);
157
new_commands = g_new (char *, size + 1);
159
new_commands[0] = last_command;
160
new_commands[size] = NULL; /* last item */
162
for (i = 1; i < size; i++)
163
new_commands[i] = commands[i-1];
165
g_settings_set_strv (dialog->run_settings,
166
PANEL_RUN_HISTORY_KEY,
167
(const char **) new_commands);
169
g_free (new_commands); /* we don't own the strings */
170
g_strfreev (commands);
174
panel_run_dialog_destroy (PanelRunDialog *dialog)
178
dialog->changed_id = 0;
180
g_object_unref (dialog->list_expander);
182
g_slist_foreach (dialog->add_icon_paths, (GFunc) gtk_tree_path_free, NULL);
183
g_slist_free (dialog->add_icon_paths);
184
dialog->add_icon_paths = NULL;
187
g_object_unref (dialog->gicon);
188
dialog->gicon = NULL;
190
g_free (dialog->desktop_path);
191
dialog->desktop_path = NULL;
192
g_free (dialog->item_name);
193
dialog->item_name = NULL;
195
if (dialog->add_items_idle_id)
196
g_source_remove (dialog->add_items_idle_id);
197
dialog->add_items_idle_id = 0;
199
if (dialog->find_command_idle_id)
200
g_source_remove (dialog->find_command_idle_id);
201
dialog->find_command_idle_id = 0;
203
if (dialog->dir_hash)
204
g_hash_table_destroy (dialog->dir_hash);
205
dialog->dir_hash = NULL;
207
for (l = dialog->possible_executables; l; l = l->next)
209
g_list_free (dialog->possible_executables);
210
dialog->possible_executables = NULL;
212
for (l = dialog->completion_items; l; l = l->next)
214
g_list_free (dialog->completion_items);
215
dialog->completion_items = NULL;
217
if (dialog->completion)
218
g_completion_free (dialog->completion);
219
dialog->completion = NULL;
221
if (dialog->run_settings)
222
g_object_unref (dialog->run_settings);
223
dialog->run_settings = NULL;
229
panel_run_dialog_get_combo_text (PanelRunDialog *dialog)
233
entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
235
return gtk_entry_get_text (GTK_ENTRY (entry));
239
panel_run_dialog_set_default_icon (PanelRunDialog *dialog, gboolean set_drag)
241
gtk_image_set_from_icon_name (GTK_IMAGE (dialog->pixmap),
243
GTK_ICON_SIZE_DIALOG);
246
gtk_drag_source_set_icon_name (dialog->run_dialog,
247
PANEL_ICON_LAUNCHER);
251
panel_run_dialog_set_icon (PanelRunDialog *dialog,
255
if (!force && gicon && dialog->gicon &&
256
gicon == dialog->gicon)
260
g_object_unref (dialog->gicon);
261
dialog->gicon = NULL;
264
dialog->gicon = g_object_ref (gicon);
265
gtk_image_set_from_gicon (GTK_IMAGE (dialog->pixmap),
266
gicon, GTK_ICON_SIZE_DIALOG);
267
gtk_drag_source_set_icon_gicon (dialog->run_dialog, gicon);
269
panel_run_dialog_set_default_icon (dialog, TRUE);
274
command_is_executable (const char *command,
283
result = g_shell_parse_argv (command, &argc, &argv, NULL);
288
path = g_find_program_in_path (argv[0]);
295
/* If we pass an absolute path to g_find_program it just returns
296
* that absolute path without checking if it is executable. Also
297
* make sure its a regular file so we don't try to launch
298
* directories or device nodes.
300
if (!g_file_test (path, G_FILE_TEST_IS_EXECUTABLE) ||
301
!g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
318
* Set the DISPLAY variable, to be use by g_spawn_async.
321
set_environment (gpointer display)
323
g_setenv ("DISPLAY", display, TRUE);
327
dummy_child_watch (GPid pid,
331
/* Nothing, this is just to ensure we don't double fork
333
* https://bugzilla.gnome.org/show_bug.cgi?id=675789
339
* gnome_desktop_prepend_terminal_to_vector:
340
* @argc: a pointer to the vector size
341
* @argv: a pointer to the vector
343
* Description: Prepends a terminal (either the one configured as default in
344
* the user's GNOME setup, or one of the common xterm emulators) to the passed
345
* in vector, modifying it in the process. The vector should be allocated with
346
* #g_malloc, as this will #g_free the original vector. Also all elements must
347
* have been allocated separately. That is the standard glib/GNOME way of
348
* doing vectors however. If the integer that @argc points to is negative, the
349
* size will first be computed. Also note that passing in pointers to a vector
350
* that is empty, will just create a new vector for you.
353
gnome_desktop_prepend_terminal_to_vector (int *argc, char ***argv)
359
char **term_argv = NULL;
363
gchar *terminal = NULL;
367
g_return_if_fail (argc != NULL);
368
g_return_if_fail (argv != NULL);
370
// _gnome_desktop_init_i18n ();
378
/* compute size if not given */
380
for (i = 0; the_argv[i] != NULL; i++)
385
settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
386
terminal = g_settings_get_string (settings, "exec");
392
exec_flag = g_settings_get_string (settings, "exec-arg");
394
if (exec_flag == NULL)
395
command_line = g_strdup (terminal);
397
command_line = g_strdup_printf ("%s %s", terminal,
400
g_shell_parse_argv (command_line,
405
g_free (command_line);
410
g_object_unref (settings);
412
if (term_argv == NULL) {
416
term_argv = g_new0 (char *, 3);
418
check = g_find_program_in_path ("gnome-terminal");
420
term_argv[0] = check;
421
/* Note that gnome-terminal takes -x and
422
* as -e in gnome-terminal is broken we use that. */
423
term_argv[1] = g_strdup ("-x");
426
check = g_find_program_in_path ("nxterm");
428
check = g_find_program_in_path ("color-xterm");
430
check = g_find_program_in_path ("rxvt");
432
check = g_find_program_in_path ("xterm");
434
check = g_find_program_in_path ("dtterm");
436
g_warning (_("Cannot find a terminal, using "
437
"xterm, even if it may not work"));
438
check = g_strdup ("xterm");
440
term_argv[0] = check;
441
term_argv[1] = g_strdup ("-e");
445
real_argc = term_argc + *argc;
446
real_argv = g_new (char *, real_argc + 1);
448
for (i = 0; i < term_argc; i++)
449
real_argv[i] = term_argv[i];
451
for (j = 0; j < *argc; j++, i++)
452
real_argv[i] = (char *)the_argv[j];
460
/* we use g_free here as we sucked all the inner strings
461
* out from it into real_argv */
464
/* FIXME: Implement when needed */
465
g_warning ("gnome_prepend_terminal_to_vector: Not implemented");
470
panel_run_dialog_launch_command (PanelRunDialog *dialog,
472
const char *locale_command)
476
GError *error = NULL;
482
if (!command_is_executable (locale_command, &argc, &argv))
485
screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog));
487
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox)))
488
gnome_desktop_prepend_terminal_to_vector (&argc, &argv);
490
display = gdk_screen_make_display_name (screen);
492
result = g_spawn_async (NULL, /* working directory */
495
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
504
primary = g_markup_printf_escaped (_("Could not run command '%s'"),
506
panel_error_dialog (GTK_WINDOW (dialog->run_dialog), NULL,
507
"cannot_spawn_command", TRUE,
508
primary, error->message);
511
g_error_free (error);
513
g_child_watch_add (pid, dummy_child_watch, NULL);
523
panel_run_dialog_execute (PanelRunDialog *dialog)
531
command = g_strdup (panel_run_dialog_get_combo_text (dialog));
532
command = g_strchug (command);
534
if (!command || !command [0]) {
539
/* evil eggies, do not translate! */
540
if (!strcmp (command, "free the fish")) {
541
start_screen_check ();
544
gtk_widget_destroy (dialog->run_dialog);
549
disk = g_locale_from_utf8 (command, -1, NULL, NULL, &error);
551
if (!disk || error) {
554
primary = g_strdup_printf (_("Could not convert '%s' from UTF-8"),
556
panel_error_dialog (GTK_WINDOW (dialog->run_dialog), NULL,
557
"cannot_convert_command_from_utf8", TRUE,
558
primary, error->message);
561
g_error_free (error);
567
scheme = g_uri_parse_scheme (disk);
568
/* if it's an absolute path or not a URI, it's possibly an executable,
569
* so try it before displaying it */
570
if (g_path_is_absolute (disk) || !scheme)
571
result = panel_run_dialog_launch_command (dialog, command, disk);
578
file = panel_util_get_file_optional_homedir (command);
579
uri = g_file_get_uri (file);
580
g_object_unref (file);
582
screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog));
583
result = panel_show_uri (screen, uri,
584
gtk_get_current_event_time (), NULL);
590
/* only save working commands in history */
591
_panel_run_save_recent_programs_list (dialog, command);
593
/* only close the dialog if we successfully showed or launched
595
gtk_widget_destroy (dialog->run_dialog);
604
panel_run_dialog_response (PanelRunDialog *dialog,
606
GtkWidget *run_dialog)
609
dialog->completion_started = FALSE;
612
case GTK_RESPONSE_OK:
613
panel_run_dialog_execute (dialog);
615
case GTK_RESPONSE_CANCEL:
616
gtk_widget_destroy (dialog->run_dialog);
623
/* only quote the string if really needed */
625
quote_string (const char *s)
629
for (p = s; *p != '\0'; p++) {
630
if ((*p >= 'a' && *p <= 'z') ||
631
(*p >= 'A' && *p <= 'Z') ||
632
(*p >= '0' && *p <= '9') ||
633
strchr ("-_./=:", *p) != NULL)
636
return g_shell_quote (s);
643
panel_run_dialog_append_file_utf8 (PanelRunDialog *dialog,
650
/* Don't allow filenames beginning with '-' */
651
if (!file || !file[0] || file[0] == '-')
654
quoted = quote_string (file);
655
entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
656
text = gtk_entry_get_text (GTK_ENTRY (entry));
657
if (text && text [0]) {
658
temp = g_strconcat (text, " ", quoted, NULL);
659
gtk_entry_set_text (GTK_ENTRY (entry), temp);
662
gtk_entry_set_text (GTK_ENTRY (entry), quoted);
668
panel_run_dialog_append_file (PanelRunDialog *dialog,
676
utf8_file = g_filename_to_utf8 (file, -1, NULL, NULL, NULL);
679
panel_run_dialog_append_file_utf8 (dialog, utf8_file);
685
fuzzy_command_match (const char *cmd1,
692
g_return_val_if_fail (cmd1 && cmd2, TRUE);
696
if (!strcmp (cmd1, cmd2))
699
/* find basename of exec from desktop item.
700
strip of all arguments after the initial command */
701
tokens = g_strsplit (cmd1, " ", -1);
702
if (!tokens || !tokens [0]) {
707
word1 = g_path_get_basename (tokens [0]);
710
/* same for the user command */
711
tokens = g_strsplit (cmd2, " ", -1);
712
word2 = g_path_get_basename (tokens [0]);
713
if (!tokens || !tokens [0]) {
721
if (!strcmp (word1, word2)) {
735
panel_run_dialog_make_all_list_visible (GtkTreeModel *model,
740
gtk_list_store_set (GTK_LIST_STORE (model), iter,
741
COLUMN_VISIBLE, TRUE,
748
panel_run_dialog_find_command_idle (PanelRunDialog *dialog)
758
model = GTK_TREE_MODEL (dialog->program_list_store);
759
path = gtk_tree_path_new_first ();
761
if (!path || !gtk_tree_model_get_iter (model, &iter, path)) {
763
gtk_tree_path_free (path);
765
panel_run_dialog_set_icon (dialog, NULL, FALSE);
767
dialog->find_command_idle_id = 0;
771
text = g_strdup (panel_run_dialog_get_combo_text (dialog));
779
char *comment = NULL;
782
gtk_tree_model_get (model, &iter,
786
COLUMN_COMMENT, &comment,
789
if (!fuzzy && exec && icon &&
790
fuzzy_command_match (text, exec, &fuzzy)) {
792
g_object_unref (found_icon);
795
found_icon = g_object_ref (icon);
796
found_name = g_strdup (name);
798
gtk_list_store_set (dialog->program_list_store,
800
COLUMN_VISIBLE, TRUE,
802
} else if (panel_g_utf8_strstrcase (exec, text) != NULL ||
803
panel_g_utf8_strstrcase (name, text) != NULL ||
804
panel_g_utf8_strstrcase (comment, text) != NULL) {
805
gtk_list_store_set (dialog->program_list_store,
807
COLUMN_VISIBLE, TRUE,
810
gtk_list_store_set (dialog->program_list_store,
812
COLUMN_VISIBLE, FALSE,
817
g_object_unref (icon);
821
} while (gtk_tree_model_iter_next (model, &iter));
823
if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->program_list)),
825
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->program_list),
826
path, NULL, FALSE, 0, 0);
828
gtk_tree_path_free (path);
830
panel_run_dialog_set_icon (dialog, found_icon, FALSE);
831
//FIXME update dialog->program_label
834
g_object_unref (found_icon);
837
g_free (dialog->item_name);
838
dialog->item_name = found_name;
840
dialog->find_command_idle_id = 0;
845
compare_applications (GMenuTreeEntry *a,
848
return g_utf8_collate (g_app_info_get_display_name ((GAppInfo*)(gmenu_tree_entry_get_app_info (a))),
849
g_app_info_get_display_name ((GAppInfo*)(gmenu_tree_entry_get_app_info (b))));
852
static GSList *get_all_applications_from_dir (GMenuTreeDirectory *directory,
856
get_all_applications_from_alias (GMenuTreeAlias *alias,
859
switch (gmenu_tree_alias_get_aliased_item_type (alias)) {
860
case GMENU_TREE_ITEM_ENTRY:
861
/* pass on the reference */
862
list = g_slist_append (list, gmenu_tree_alias_get_aliased_entry (alias));
865
case GMENU_TREE_ITEM_DIRECTORY: {
866
GMenuTreeDirectory *directory = gmenu_tree_alias_get_aliased_directory (alias);
867
list = get_all_applications_from_dir (directory, list);
868
gmenu_tree_item_unref (directory);
880
get_all_applications_from_dir (GMenuTreeDirectory *directory,
884
GMenuTreeItemType next_type;
886
iter = gmenu_tree_directory_iter (directory);
888
while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) {
890
case GMENU_TREE_ITEM_ENTRY:
891
list = g_slist_append (list, gmenu_tree_iter_get_entry (iter));
894
case GMENU_TREE_ITEM_DIRECTORY: {
895
GMenuTreeDirectory *dir = gmenu_tree_iter_get_directory (iter);
896
list = get_all_applications_from_dir (dir, list);
897
gmenu_tree_item_unref (dir);
901
case GMENU_TREE_ITEM_ALIAS: {
902
GMenuTreeAlias *alias = gmenu_tree_iter_get_alias (iter);
903
list = get_all_applications_from_alias (alias, list);
904
gmenu_tree_item_unref (alias);
913
gmenu_tree_iter_unref (iter);
919
get_all_applications (void)
922
GMenuTreeDirectory *root;
925
tree = gmenu_tree_new ("applications.menu", GMENU_TREE_FLAGS_SORT_DISPLAY_NAME);
927
if (!gmenu_tree_load_sync (tree, NULL))
930
root = gmenu_tree_get_root_directory (tree);
932
retval = get_all_applications_from_dir (root, NULL);
934
gmenu_tree_item_unref (root);
935
g_object_unref (tree);
937
retval = g_slist_sort (retval,
938
(GCompareFunc) compare_applications);
944
panel_run_dialog_add_items_idle (PanelRunDialog *dialog)
946
GtkCellRenderer *renderer;
947
GtkTreeViewColumn *column;
948
GtkTreeModel *model_filter;
949
GSList *all_applications;
952
const char *prev_name;
954
/* create list store */
955
dialog->program_list_store = gtk_list_store_new (NUM_COLUMNS,
963
all_applications = get_all_applications ();
965
/* Strip duplicates */
967
for (l = all_applications; l; l = next) {
968
GMenuTreeEntry *entry = l->data;
969
const char *entry_name;
970
GDesktopAppInfo *app_info;
974
app_info = gmenu_tree_entry_get_app_info (entry);
976
entry_name = g_app_info_get_display_name (G_APP_INFO (app_info));
977
if (prev_name && entry_name && strcmp (entry_name, prev_name) == 0) {
978
gmenu_tree_item_unref (entry);
980
all_applications = g_slist_delete_link (all_applications, l);
982
prev_name = entry_name;
986
for (l = all_applications; l; l = l->next) {
987
GMenuTreeEntry *entry = l->data;
992
app_info = G_APP_INFO (gmenu_tree_entry_get_app_info (entry));
994
gtk_list_store_append (dialog->program_list_store, &iter);
995
gtk_list_store_set (dialog->program_list_store, &iter,
996
COLUMN_ICON, g_app_info_get_icon (app_info),
997
COLUMN_NAME, g_app_info_get_display_name (app_info),
998
COLUMN_COMMENT, g_app_info_get_description (app_info),
999
COLUMN_EXEC, g_app_info_get_executable (app_info),
1000
COLUMN_PATH, gmenu_tree_entry_get_desktop_file_path (entry),
1001
COLUMN_VISIBLE, TRUE,
1004
path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->program_list_store), &iter);
1006
dialog->add_icon_paths = g_slist_prepend (dialog->add_icon_paths, path);
1008
gmenu_tree_item_unref (entry);
1010
g_slist_free (all_applications);
1012
model_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->program_list_store),
1014
gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (model_filter),
1017
gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->program_list),
1019
//FIXME use the same search than the fuzzy one?
1020
gtk_tree_view_set_search_column (GTK_TREE_VIEW (dialog->program_list),
1023
renderer = gtk_cell_renderer_pixbuf_new ();
1024
column = gtk_tree_view_column_new ();
1025
gtk_tree_view_column_pack_start (column, renderer, FALSE);
1026
gtk_tree_view_column_set_attributes (column, renderer,
1027
"gicon", COLUMN_ICON,
1030
renderer = gtk_cell_renderer_text_new ();
1031
gtk_tree_view_column_pack_start (column, renderer, TRUE);
1032
gtk_tree_view_column_set_attributes (column, renderer,
1033
"text", COLUMN_NAME,
1036
gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->program_list), column);
1038
dialog->add_icon_paths = g_slist_reverse (dialog->add_icon_paths);
1040
dialog->add_items_idle_id = 0;
1045
remove_parameters (const char *exec)
1050
str = g_string_new (exec);
1052
while ((p = strstr (str->str, "%"))) {
1055
g_string_erase (str, p - str->str, 1);
1070
g_string_erase (str, p - str->str, 2);
1078
g_string_free (str, FALSE);
1084
program_list_selection_changed (GtkTreeSelection *selection,
1085
PanelRunDialog *dialog)
1087
GtkTreeModel *filter_model;
1088
GtkTreeModel *child_model;
1090
GtkTreeIter filter_iter;
1092
char *path, *stripped;
1097
if (!gtk_tree_selection_get_selected (selection, &filter_model,
1101
gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter_model),
1102
&iter, &filter_iter);
1105
child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
1106
gtk_tree_model_get (child_model, &iter,
1113
key_file = g_key_file_new ();
1115
if (!g_key_file_load_from_file (key_file, path,
1116
G_KEY_FILE_NONE, NULL)) {
1117
g_key_file_free (key_file);
1122
dialog->use_program_list = TRUE;
1123
if (dialog->desktop_path)
1124
g_free (dialog->desktop_path);
1125
dialog->desktop_path = g_strdup (path);
1126
if (dialog->item_name)
1127
g_free (dialog->item_name);
1128
dialog->item_name = NULL;
1130
/* Order is important here. We have to set the text first so that the
1131
* drag source is enabled, otherwise the drag icon can't be set by
1132
* panel_run_dialog_set_icon.
1134
entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
1135
temp = panel_key_file_get_string (key_file, "Exec");
1137
stripped = remove_parameters (temp);
1138
gtk_entry_set_text (GTK_ENTRY (entry), stripped);
1141
temp = panel_key_file_get_string (key_file, "URL");
1142
gtk_entry_set_text (GTK_ENTRY (entry), sure_string (temp));
1146
temp = panel_key_file_get_locale_string (key_file, "Icon");
1147
if (!PANEL_GLIB_STR_EMPTY (temp)) {
1150
stripped = panel_xdg_icon_remove_extension (temp);
1151
gicon = g_themed_icon_new (stripped);
1152
panel_run_dialog_set_icon (dialog, gicon, FALSE);
1153
g_object_unref (gicon);
1156
panel_run_dialog_set_icon (dialog, NULL, FALSE);
1160
temp = panel_key_file_get_locale_string (key_file, "Comment");
1161
//FIXME: if sure_string () == "", we should display "Will run..." as in entry_changed()
1162
gtk_label_set_text (GTK_LABEL (dialog->program_label),
1163
sure_string (temp));
1166
terminal = panel_key_file_get_boolean (key_file, "Terminal", FALSE);
1167
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox),
1170
g_key_file_free (key_file);
1176
program_list_selection_activated (GtkTreeView *view,
1178
GtkTreeViewColumn *column,
1179
PanelRunDialog *dialog)
1181
GtkTreeSelection *selection;
1183
/* update the entry with the info from the selection */
1184
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list));
1185
program_list_selection_changed (selection, dialog);
1187
/* now launch the command */
1188
gtk_dialog_response (GTK_DIALOG (dialog->run_dialog), GTK_RESPONSE_OK);
1193
panel_run_dialog_setup_program_list (PanelRunDialog *dialog,
1196
GtkTreeSelection *selection;
1198
dialog->program_list = PANEL_GTK_BUILDER_GET (gui, "program_list");
1199
dialog->program_label = PANEL_GTK_BUILDER_GET (gui, "program_label");
1200
dialog->main_box = PANEL_GTK_BUILDER_GET (gui, "main_box");
1202
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list));
1203
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
1205
g_signal_connect (selection, "changed",
1206
G_CALLBACK (program_list_selection_changed),
1209
g_signal_connect (dialog->program_list, "row-activated",
1210
G_CALLBACK (program_list_selection_activated),
1215
panel_run_dialog_setup_list_expander (PanelRunDialog *dialog,
1218
dialog->list_expander = PANEL_GTK_BUILDER_GET (gui, "list_expander");
1220
/* Ref the expander so it doesn't get destroyed when it is
1221
* removed from the visible area of the dialog box. */
1222
g_object_ref (dialog->list_expander);
1224
g_settings_bind (dialog->run_settings,
1225
PANEL_RUN_SHOW_LIST_KEY,
1226
dialog->list_expander,
1228
G_SETTINGS_BIND_DEFAULT);
1232
panel_run_dialog_update_program_list (GSettings *settings,
1234
PanelRunDialog *dialog)
1240
enabled = g_settings_get_boolean (dialog->run_settings,
1241
PANEL_RUN_ENABLE_LIST_KEY);
1243
parent = gtk_widget_get_parent (dialog->list_expander);
1246
if (dialog->program_list_store == NULL) {
1247
/* start loading the list of applications */
1248
dialog->add_items_idle_id =
1249
g_idle_add_full (G_PRIORITY_LOW,
1250
(GSourceFunc) panel_run_dialog_add_items_idle,
1255
gtk_box_pack_end (GTK_BOX (dialog->main_box),
1256
dialog->list_expander,
1260
gtk_container_remove (GTK_CONTAINER (parent),
1261
dialog->list_expander);
1264
shown = g_settings_get_boolean (dialog->run_settings,
1265
PANEL_RUN_SHOW_LIST_KEY);
1267
if (enabled && shown) {
1268
gtk_window_resize (GTK_WINDOW (dialog->run_dialog), 100, 300);
1269
gtk_window_set_resizable (GTK_WINDOW (dialog->run_dialog), TRUE);
1270
gtk_widget_grab_focus (dialog->program_list);
1272
gtk_window_set_resizable (GTK_WINDOW (dialog->run_dialog), FALSE);
1273
gtk_widget_grab_focus (dialog->combobox);
1278
file_button_browse_response (GtkWidget *chooser,
1280
PanelRunDialog *dialog)
1284
if (response == GTK_RESPONSE_OK) {
1285
file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
1286
panel_run_dialog_append_file (dialog, file);
1290
gtk_widget_destroy (chooser);
1292
gtk_widget_grab_focus (dialog->combobox);
1296
file_button_clicked (GtkButton *button,
1297
PanelRunDialog *dialog)
1301
chooser = gtk_file_chooser_dialog_new (_("Choose a file to append to the command..."),
1302
GTK_WINDOW (dialog->run_dialog),
1303
GTK_FILE_CHOOSER_ACTION_OPEN,
1304
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1305
GTK_STOCK_OK, GTK_RESPONSE_OK,
1308
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
1311
gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
1312
gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE);
1314
g_signal_connect (chooser, "response",
1315
G_CALLBACK (file_button_browse_response), dialog);
1317
gtk_window_present (GTK_WINDOW (chooser));
1321
panel_run_dialog_setup_file_button (PanelRunDialog *dialog,
1324
dialog->file_button = PANEL_GTK_BUILDER_GET (gui, "file_button");
1326
g_signal_connect (dialog->file_button, "clicked",
1327
G_CALLBACK (file_button_clicked),
1332
fill_files_from (const char *dirname,
1333
const char *dirprefix,
1335
GList *existing_items)
1339
struct dirent *dent;
1342
dir = opendir (dirname);
1347
while ((dent = readdir (dir))) {
1352
if (!dent->d_name ||
1353
dent->d_name [0] != prefix)
1356
file = g_build_filename (dirname, dent->d_name, NULL);
1360
#ifdef HAVE_STRUCT_DIRENT_D_TYPE
1361
/* don't use g_file_test at first so we don't stat() */
1362
dent->d_type == DT_DIR ||
1363
(dent->d_type == DT_LNK &&
1364
g_file_test (file, G_FILE_TEST_IS_DIR))
1366
g_file_test (file, G_FILE_TEST_IS_DIR)
1373
item = g_build_filename (dirprefix, dent->d_name, suffix, NULL);
1375
list = g_list_prepend (list, item);
1384
fill_possible_executables (void)
1392
path = g_getenv ("PATH");
1394
if (!path || !path [0])
1397
pathv = g_strsplit (path, ":", 0);
1399
for (i = 0; pathv [i]; i++) {
1404
dir = g_dir_open (pathv [i], 0, NULL);
1409
while ((file = g_dir_read_name (dir))) {
1410
filename = g_build_filename (pathv [i], file, NULL);
1411
list = g_list_prepend (list, filename);
1423
fill_executables (GList *possible_executables,
1424
GList *existing_items,
1432
for (l = possible_executables; l; l = l->next) {
1433
const char *filename;
1437
basename = g_path_get_basename (filename);
1439
if (basename [0] == prefix &&
1440
g_file_test (filename, G_FILE_TEST_IS_REGULAR) &&
1441
g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE)) {
1443
if (g_list_find_custom (existing_items, basename,
1444
(GCompareFunc) strcmp)) {
1449
list = g_list_prepend (list, basename);
1459
panel_run_dialog_update_completion (PanelRunDialog *dialog,
1470
g_assert (text != NULL && *text != '\0' && !g_ascii_isspace (*text));
1475
if (!dialog->completion) {
1476
dialog->completion = g_completion_new (NULL);
1477
dialog->possible_executables = fill_possible_executables ();
1478
dialog->dir_hash = g_hash_table_new_full (g_str_hash,
1483
buf = g_path_get_basename (text);
1486
if (prefix == '/' || prefix == '.')
1489
if (text [0] == '/') {
1490
/* complete against absolute path */
1491
dirname = g_path_get_dirname (text);
1492
dirprefix = g_strdup (dirname);
1494
/* complete against relative path and executable name */
1495
if (!strchr (text, '/')) {
1496
executables = fill_executables (dialog->possible_executables,
1497
dialog->completion_items,
1499
dirprefix = g_strdup ("");
1501
dirprefix = g_path_get_dirname (text);
1504
dirname = g_build_filename (g_get_home_dir (), dirprefix, NULL);
1507
key = g_strdup_printf ("%s%c%c", dirprefix, G_DIR_SEPARATOR, prefix);
1509
if (!g_hash_table_lookup (dialog->dir_hash, key)) {
1510
g_hash_table_insert (dialog->dir_hash, key, dialog);
1512
list = fill_files_from (dirname, dirprefix, prefix,
1513
dialog->completion_items);
1518
list = g_list_concat (list, executables);
1526
g_completion_add_items (dialog->completion, list);
1528
dialog->completion_items = g_list_concat (dialog->completion_items,
1533
entry_event (GtkEditable *entry,
1535
PanelRunDialog *dialog)
1537
GtkTreeSelection *selection;
1539
char *nospace_prefix;
1544
if (event->type != GDK_KEY_PRESS)
1547
/* if user typed something we're not using the list anymore */
1548
dialog->use_program_list = FALSE;
1549
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list));
1550
gtk_tree_selection_unselect_all (selection);
1552
if (!g_settings_get_boolean (dialog->run_settings,
1553
PANEL_RUN_ENABLE_COMPLETION_KEY))
1556
/* tab completion */
1557
if (event->keyval == GDK_KEY_Tab) {
1558
gtk_editable_get_selection_bounds (entry, &pos, &tmp);
1560
if (dialog->completion_started &&
1563
tmp == strlen (gtk_entry_get_text (GTK_ENTRY (entry)))) {
1564
gtk_editable_select_region (entry, 0, 0);
1565
gtk_editable_set_position (entry, -1);
1569
} else if (event->length > 0) {
1571
gtk_editable_get_selection_bounds (entry, &pos, &tmp);
1573
if (dialog->completion_started &&
1576
tmp == strlen (gtk_entry_get_text (GTK_ENTRY (entry)))) {
1577
temp = gtk_editable_get_chars (entry, 0, pos);
1578
prefix = g_strconcat (temp, event->string, NULL);
1580
} else if (pos == tmp &&
1581
tmp == strlen (gtk_entry_get_text (GTK_ENTRY (entry)))) {
1582
prefix = g_strconcat (gtk_entry_get_text (GTK_ENTRY (entry)),
1583
event->string, NULL);
1588
nospace_prefix = prefix;
1589
while (*nospace_prefix != '\0' &&
1590
g_ascii_isspace (*nospace_prefix))
1592
if (*nospace_prefix == '\0')
1595
panel_run_dialog_update_completion (dialog, nospace_prefix);
1597
if (!dialog->completion) {
1602
pos = strlen (prefix);
1605
g_completion_complete_utf8 (dialog->completion, nospace_prefix,
1612
temp = g_strndup (prefix, nospace_prefix - prefix);
1615
prefix = g_strconcat (temp, nprefix, NULL);
1617
g_signal_handler_block (dialog->combobox,
1618
dialog->changed_id);
1619
gtk_editable_delete_text (entry, 0, -1);
1620
g_signal_handler_unblock (dialog->combobox,
1621
dialog->changed_id);
1623
gtk_editable_insert_text (entry,
1624
prefix, strlen (prefix),
1627
gtk_editable_set_position (entry, pos);
1628
gtk_editable_select_region (entry, pos, -1);
1630
dialog->completion_started = TRUE;
1646
combobox_changed (GtkComboBox *combobox,
1647
PanelRunDialog *dialog)
1649
gboolean program_list_enabled;
1654
program_list_enabled = g_settings_get_boolean (dialog->run_settings,
1655
PANEL_RUN_ENABLE_LIST_KEY);
1657
text = g_strdup (panel_run_dialog_get_combo_text (dialog));
1660
while (*start != '\0' && g_ascii_isspace (*start))
1663
/* update item name to use for dnd */
1664
if (!dialog->use_program_list) {
1665
if (dialog->desktop_path) {
1666
g_free (dialog->desktop_path);
1667
dialog->desktop_path = NULL;
1669
if (dialog->item_name) {
1670
g_free (dialog->item_name);
1671
dialog->item_name = NULL;
1675
/* desensitize run button if no text entered */
1676
if (!start || !start [0]) {
1679
gtk_widget_set_sensitive (dialog->run_button, FALSE);
1680
gtk_drag_source_unset (dialog->run_dialog);
1682
if (program_list_enabled)
1683
gtk_label_set_text (GTK_LABEL (dialog->program_label),
1684
_("Select an application to view its description."));
1686
panel_run_dialog_set_default_icon (dialog, FALSE);
1688
if (dialog->find_command_idle_id) {
1689
g_source_remove (dialog->find_command_idle_id);
1690
dialog->find_command_idle_id = 0;
1693
if (program_list_enabled) {
1697
gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->program_list_store),
1698
panel_run_dialog_make_all_list_visible,
1701
path = gtk_tree_path_new_first ();
1702
if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->program_list)),
1704
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->program_list),
1707
gtk_tree_path_free (path);
1713
gtk_widget_set_sensitive (dialog->run_button, TRUE);
1714
gtk_drag_source_set (dialog->run_dialog,
1718
gtk_drag_source_add_uri_targets (dialog->run_dialog);
1720
if (program_list_enabled &&
1721
!dialog->use_program_list) {
1722
msg = g_strdup_printf (_("Will run command: '%s'"),
1724
gtk_label_set_text (GTK_LABEL (dialog->program_label), msg);
1728
/* look up icon for the command */
1729
if (program_list_enabled &&
1730
!dialog->use_program_list &&
1731
!dialog->find_command_idle_id)
1732
dialog->find_command_idle_id =
1733
g_idle_add_full (G_PRIORITY_LOW,
1734
(GSourceFunc) panel_run_dialog_find_command_idle,
1741
entry_drag_data_received (GtkEditable *entry,
1742
GdkDragContext *context,
1745
GtkSelectionData *selection_data,
1748
PanelRunDialog *dialog)
1754
if (gtk_selection_data_get_format (selection_data) != 8 || gtk_selection_data_get_length (selection_data) == 0) {
1755
g_warning (_("URI list dropped on run dialog had wrong format (%d) or length (%d)\n"),
1756
gtk_selection_data_get_format (selection_data),
1757
gtk_selection_data_get_length (selection_data));
1761
uris = g_uri_list_extract_uris ((const char *)gtk_selection_data_get_data (selection_data));
1764
gtk_drag_finish (context, FALSE, FALSE, time);
1768
for (i = 0; uris [i]; i++) {
1769
if (!uris [i] || !uris [i][0])
1772
file = g_filename_from_uri (uris [i], NULL, NULL);
1774
/* FIXME: I assume the file is in utf8 encoding if coming from a URI? */
1776
panel_run_dialog_append_file_utf8 (dialog, file);
1779
panel_run_dialog_append_file_utf8 (dialog, uris [i]);
1783
gtk_drag_finish (context, TRUE, FALSE, time);
1787
panel_run_dialog_setup_entry (PanelRunDialog *dialog,
1794
dialog->combobox = PANEL_GTK_BUILDER_GET (gui, "comboboxentry");
1796
entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
1797
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
1799
gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox),
1800
_panel_run_get_recent_programs_list (dialog));
1801
gtk_combo_box_set_entry_text_column
1802
(GTK_COMBO_BOX (dialog->combobox), 0);
1804
screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog));
1806
/* 1/4 the width of the first monitor should be a good value */
1807
width_request = panel_multiscreen_width (screen, 0) / 4;
1808
g_object_set (G_OBJECT (dialog->combobox),
1809
"width_request", width_request,
1812
g_signal_connect (entry, "key-press-event",
1813
G_CALLBACK (entry_event), dialog);
1815
dialog->changed_id = g_signal_connect (dialog->combobox, "changed",
1816
G_CALLBACK (combobox_changed),
1819
gtk_drag_dest_unset (dialog->combobox);
1821
gtk_drag_dest_set (dialog->combobox,
1822
GTK_DEST_DEFAULT_MOTION|GTK_DEST_DEFAULT_HIGHLIGHT,
1825
gtk_drag_dest_add_uri_targets (dialog->combobox);
1827
g_signal_connect (dialog->combobox, "drag_data_received",
1828
G_CALLBACK (entry_drag_data_received), dialog);
1832
panel_run_dialog_create_desktop_file (PanelRunDialog *dialog)
1835
gboolean exec = FALSE;
1843
text = g_strdup (panel_run_dialog_get_combo_text (dialog));
1845
if (!text || !text [0]) {
1850
key_file = panel_key_file_new_desktop ();
1851
disk = g_locale_from_utf8 (text, -1, NULL, NULL, NULL);
1853
scheme = g_uri_parse_scheme (disk);
1854
/* if it's an absolute path or not a URI, it's possibly an executable */
1855
if (g_path_is_absolute (disk) || !scheme)
1856
exec = command_is_executable (disk, NULL, NULL);
1860
panel_key_file_set_string (key_file, "Type", "Application");
1861
panel_key_file_set_string (key_file, "Exec", text);
1862
name = g_strdup (text);
1867
file = panel_util_get_file_optional_homedir (disk);
1868
uri = g_file_get_uri (file);
1869
g_object_unref (file);
1871
panel_key_file_set_string (key_file, "Type", "Link");
1872
panel_key_file_set_string (key_file, "URL", uri);
1878
panel_key_file_set_locale_string (key_file, "Name",
1879
(dialog->item_name) ?
1880
dialog->item_name : text);
1882
panel_key_file_set_boolean (key_file, "Terminal",
1883
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox)));
1887
icon = panel_util_get_icon_name_from_g_icon (dialog->gicon);
1889
panel_key_file_set_locale_string (key_file, "Icon",
1893
panel_key_file_set_locale_string (key_file, "Icon",
1894
PANEL_ICON_LAUNCHER);
1896
save_uri = panel_make_unique_desktop_uri (g_get_tmp_dir (), name);
1897
disk = g_filename_from_uri (save_uri, NULL, NULL);
1899
if (!disk || !panel_key_file_to_file (key_file, disk, NULL)) {
1904
g_key_file_free (key_file);
1913
pixmap_drag_data_get (GtkWidget *run_dialog,
1914
GdkDragContext *context,
1915
GtkSelectionData *selection_data,
1918
PanelRunDialog *dialog)
1922
if (dialog->use_program_list && dialog->desktop_path)
1923
uri = g_filename_to_uri (dialog->desktop_path, NULL, NULL);
1925
uri = panel_run_dialog_create_desktop_file (dialog);
1928
gtk_selection_data_set (selection_data,
1929
gtk_selection_data_get_target (selection_data), 8,
1930
(unsigned char *) uri, strlen (uri));
1936
panel_run_dialog_setup_pixmap (PanelRunDialog *dialog,
1939
dialog->pixmap = PANEL_GTK_BUILDER_GET (gui, "icon_pixmap");
1941
g_signal_connect (dialog->run_dialog, "drag_data_get",
1942
G_CALLBACK (pixmap_drag_data_get),
1946
static PanelRunDialog *
1947
panel_run_dialog_new (GdkScreen *screen,
1949
guint32 activate_time)
1951
PanelRunDialog *dialog;
1953
dialog = g_new0 (PanelRunDialog, 1);
1955
dialog->run_dialog = PANEL_GTK_BUILDER_GET (gui, "panel_run_dialog");
1957
dialog->run_settings = g_settings_new (PANEL_RUN_SCHEMA);
1959
g_signal_connect_swapped (dialog->run_dialog, "response",
1960
G_CALLBACK (panel_run_dialog_response), dialog);
1962
g_signal_connect_swapped (dialog->run_dialog, "destroy",
1963
G_CALLBACK (panel_run_dialog_destroy), dialog);
1965
dialog->run_button = PANEL_GTK_BUILDER_GET (gui, "run_button");
1966
dialog->terminal_checkbox = PANEL_GTK_BUILDER_GET (gui, "terminal_checkbox");
1968
panel_run_dialog_setup_pixmap (dialog, gui);
1969
panel_run_dialog_setup_entry (dialog, gui);
1970
panel_run_dialog_setup_file_button (dialog, gui);
1971
panel_run_dialog_setup_program_list (dialog, gui);
1972
panel_run_dialog_setup_list_expander (dialog, gui);
1974
gtk_window_set_icon_name (GTK_WINDOW (dialog->run_dialog),
1976
panel_run_dialog_set_default_icon (dialog, FALSE);
1978
g_signal_connect (dialog->run_settings, "changed::"PANEL_RUN_ENABLE_LIST_KEY,
1979
G_CALLBACK (panel_run_dialog_update_program_list), dialog);
1980
g_signal_connect (dialog->run_settings, "changed::"PANEL_RUN_SHOW_LIST_KEY,
1981
G_CALLBACK (panel_run_dialog_update_program_list), dialog);
1983
panel_run_dialog_update_program_list (dialog->run_settings, NULL, dialog);
1985
gtk_widget_set_sensitive (dialog->run_button, FALSE);
1987
gtk_dialog_set_default_response (GTK_DIALOG (dialog->run_dialog),
1990
gtk_window_set_screen (GTK_WINDOW (dialog->run_dialog), screen);
1992
gtk_widget_grab_focus (dialog->combobox);
1993
gtk_widget_realize (dialog->run_dialog);
1994
gdk_x11_window_set_user_time (gtk_widget_get_window (dialog->run_dialog),
1996
gtk_widget_show (dialog->run_dialog);
2002
panel_run_dialog_static_dialog_destroyed (PanelRunDialog *dialog)
2004
/* just reset the static dialog to NULL for next time */
2005
static_dialog = NULL;
2009
panel_run_dialog_present (GdkScreen *screen,
2010
guint32 activate_time)
2014
if (panel_lockdown_get_disable_command_line_s ())
2017
if (static_dialog) {
2018
gtk_window_set_screen (GTK_WINDOW (static_dialog->run_dialog), screen);
2019
gtk_window_present_with_time (GTK_WINDOW (static_dialog->run_dialog),
2021
gtk_widget_grab_focus (static_dialog->combobox);
2025
gui = gtk_builder_new ();
2026
gtk_builder_set_translation_domain (gui, GETTEXT_PACKAGE);
2027
gtk_builder_add_from_resource (gui,
2028
PANEL_RESOURCE_PATH "panel-run-dialog.ui",
2031
static_dialog = panel_run_dialog_new (screen, gui, activate_time);
2033
g_signal_connect_swapped (static_dialog->run_dialog, "destroy",
2034
G_CALLBACK (panel_run_dialog_static_dialog_destroyed),
2037
g_object_unref (gui);