~ubuntu-branches/ubuntu/trusty/gnome-panel/trusty

« back to all changes in this revision

Viewing changes to .pc/clock_applet_needs_terminal.patch/gnome-panel/panel-run-dialog.c

  • Committer: Package Import Robot
  • Author(s): Tim Lunn, Tim Lunn, Jeremy Bicha
  • Date: 2013-05-28 11:55:23 UTC
  • Revision ID: package-import@ubuntu.com-20130528115523-5xjvb98au715s7zn
Tags: 1:3.6.2-0ubuntu4
[ Tim Lunn ]
* Rebuild for gnome-desktop 3.8 transition (LP: #1184812)
  - debian/patches/git_panel_run_dialog_resurrect_terminal.patch 
    clock_applet_needs_terminal.patch

[ Jeremy Bicha ]
* git-build-with-gweather38.patch:
  - Backport patch to build with gweather 3.8 (LP: #1184168) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- c-basic-offset: 8; indent-tabs-mode: t -*-
 
2
 * panel-run-dialog.c:
 
3
 *
 
4
 * Copyright (C) 2003 Frank Worsley <fworsley@shaw.ca>
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 * 02111-1307, USA.
 
20
 
 
21
 * Authors:
 
22
 *      Frank Worsley <fworsley@shaw.ca>
 
23
 *
 
24
 * Based on code by:
 
25
 *      Havoc Pennington <hp@pobox.com>
 
26
 *      George Lebl <jirka@5z.com>
 
27
 *      Mark McLoughlin <mark@skynet.ie>
 
28
 *      Tom Tromey (Copyright (C) 1998)
 
29
 */
 
30
 
 
31
#include <config.h>
 
32
 
 
33
#include "panel-run-dialog.h"
 
34
 
 
35
#include <string.h>
 
36
#include <dirent.h>
 
37
#include <errno.h>
 
38
#include <sys/types.h>
 
39
#include <unistd.h>
 
40
 
 
41
#include <glib/gi18n.h>
 
42
#include <gio/gio.h>
 
43
#include <gdk/gdkkeysyms.h>
 
44
#include <gmenu-tree.h>
 
45
 
 
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>
 
52
 
 
53
#include "nothing.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"
 
59
#include "menu.h"
 
60
#include "panel-lockdown.h"
 
61
#include "panel-xutils.h"
 
62
#include "panel-icon-names.h"
 
63
#include "panel-schemas.h"
 
64
 
 
65
typedef struct {
 
66
        GtkWidget        *run_dialog;
 
67
 
 
68
        GSettings        *run_settings;
 
69
 
 
70
        GtkWidget        *main_box;
 
71
 
 
72
        GtkWidget        *combobox;
 
73
        GtkWidget        *pixmap;
 
74
        GtkWidget        *run_button;
 
75
        GtkWidget        *file_button;
 
76
        GtkWidget        *list_expander;
 
77
        GtkWidget        *terminal_checkbox;
 
78
        GtkWidget        *program_label;
 
79
        GtkWidget        *program_list;
 
80
        
 
81
        long              changed_id;
 
82
 
 
83
        GtkListStore     *program_list_store;
 
84
 
 
85
        GHashTable       *dir_hash;
 
86
        GList            *possible_executables;
 
87
        GList            *completion_items;
 
88
        GCompletion      *completion;
 
89
        
 
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;
 
95
        
 
96
        GIcon            *gicon;
 
97
        char             *desktop_path;
 
98
        char             *item_name;    
 
99
} PanelRunDialog;
 
100
 
 
101
enum {
 
102
        COLUMN_ICON,
 
103
        COLUMN_NAME,
 
104
        COLUMN_COMMENT,
 
105
        COLUMN_PATH,
 
106
        COLUMN_EXEC,
 
107
        COLUMN_VISIBLE,
 
108
        NUM_COLUMNS
 
109
};
 
110
 
 
111
static PanelRunDialog *static_dialog = NULL;
 
112
 
 
113
#define PANEL_RUN_MAX_HISTORY 20
 
114
 
 
115
static GtkTreeModel *
 
116
_panel_run_get_recent_programs_list (PanelRunDialog *dialog)
 
117
{
 
118
        GtkListStore  *list;
 
119
        char         **commands;
 
120
        int            i;
 
121
 
 
122
        list = gtk_list_store_new (1, G_TYPE_STRING);
 
123
 
 
124
        commands = g_settings_get_strv (dialog->run_settings,
 
125
                                        PANEL_RUN_HISTORY_KEY);
 
126
 
 
127
        for (i = 0; commands[i] != NULL; i++) {
 
128
                GtkTreeIter iter;
 
129
                gtk_list_store_prepend (list, &iter);
 
130
                gtk_list_store_set (list, &iter, 0, commands[i], -1);
 
131
        }
 
132
 
 
133
        g_strfreev (commands);
 
134
 
 
135
        return GTK_TREE_MODEL (list);
 
136
}
 
137
 
 
138
static void
 
139
_panel_run_save_recent_programs_list (PanelRunDialog *dialog,
 
140
                                      char           *last_command)
 
141
{
 
142
        char **commands;
 
143
        char **new_commands;
 
144
        int    i;
 
145
        int    size;
 
146
 
 
147
        commands = g_settings_get_strv (dialog->run_settings,
 
148
                                        PANEL_RUN_HISTORY_KEY);
 
149
 
 
150
        /* do not save the same command twice in a row */
 
151
        if (g_strcmp0 (commands[0], last_command) == 0)
 
152
                return;
 
153
 
 
154
        for (i = 0; commands[i] != NULL; i++);
 
155
        size = MIN (i + 1, PANEL_RUN_MAX_HISTORY);
 
156
 
 
157
        new_commands = g_new (char *, size + 1);
 
158
 
 
159
        new_commands[0] = last_command;
 
160
        new_commands[size] = NULL; /* last item */
 
161
 
 
162
        for (i = 1; i < size; i++)
 
163
                new_commands[i] = commands[i-1];
 
164
 
 
165
        g_settings_set_strv (dialog->run_settings,
 
166
                             PANEL_RUN_HISTORY_KEY,
 
167
                             (const char **) new_commands);
 
168
 
 
169
        g_free (new_commands); /* we don't own the strings */
 
170
        g_strfreev (commands);
 
171
}
 
172
 
 
173
static void
 
174
panel_run_dialog_destroy (PanelRunDialog *dialog)
 
175
{
 
176
        GList *l;
 
177
        
 
178
        dialog->changed_id = 0;
 
179
 
 
180
        g_object_unref (dialog->list_expander);
 
181
        
 
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;
 
185
 
 
186
        if (dialog->gicon)
 
187
                g_object_unref (dialog->gicon);
 
188
        dialog->gicon = NULL;
 
189
 
 
190
        g_free (dialog->desktop_path);
 
191
        dialog->desktop_path = NULL;
 
192
        g_free (dialog->item_name);
 
193
        dialog->item_name = NULL;
 
194
 
 
195
        if (dialog->add_items_idle_id)
 
196
                g_source_remove (dialog->add_items_idle_id);
 
197
        dialog->add_items_idle_id = 0;
 
198
 
 
199
        if (dialog->find_command_idle_id)
 
200
                g_source_remove (dialog->find_command_idle_id);
 
201
        dialog->find_command_idle_id = 0;
 
202
 
 
203
        if (dialog->dir_hash)
 
204
                g_hash_table_destroy (dialog->dir_hash);
 
205
        dialog->dir_hash = NULL;
 
206
 
 
207
        for (l = dialog->possible_executables; l; l = l->next)
 
208
                g_free (l->data);
 
209
        g_list_free (dialog->possible_executables);
 
210
        dialog->possible_executables = NULL;
 
211
        
 
212
        for (l = dialog->completion_items; l; l = l->next)
 
213
                g_free (l->data);
 
214
        g_list_free (dialog->completion_items);
 
215
        dialog->completion_items = NULL;
 
216
        
 
217
        if (dialog->completion)
 
218
                g_completion_free (dialog->completion);
 
219
        dialog->completion = NULL;
 
220
 
 
221
        if (dialog->run_settings)
 
222
                g_object_unref (dialog->run_settings);
 
223
        dialog->run_settings = NULL;
 
224
 
 
225
        g_free (dialog);
 
226
}
 
227
 
 
228
static const char *
 
229
panel_run_dialog_get_combo_text (PanelRunDialog *dialog)
 
230
{
 
231
        GtkWidget *entry;
 
232
 
 
233
        entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
 
234
 
 
235
        return gtk_entry_get_text (GTK_ENTRY (entry));
 
236
}
 
237
 
 
238
static void
 
239
panel_run_dialog_set_default_icon (PanelRunDialog *dialog, gboolean set_drag)
 
240
{
 
241
        gtk_image_set_from_icon_name (GTK_IMAGE (dialog->pixmap),
 
242
                                      PANEL_ICON_RUN,
 
243
                                      GTK_ICON_SIZE_DIALOG);
 
244
        
 
245
        if (set_drag)
 
246
                gtk_drag_source_set_icon_name (dialog->run_dialog,
 
247
                                               PANEL_ICON_LAUNCHER);
 
248
}
 
249
 
 
250
static void
 
251
panel_run_dialog_set_icon (PanelRunDialog *dialog,
 
252
                           GIcon          *gicon,
 
253
                           gboolean        force)
 
254
{
 
255
        if (!force && gicon && dialog->gicon &&
 
256
            gicon == dialog->gicon)
 
257
                return;
 
258
 
 
259
        if (dialog->gicon)
 
260
                g_object_unref (dialog->gicon);
 
261
        dialog->gicon = NULL;
 
262
                
 
263
        if (gicon) {
 
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);
 
268
        } else {
 
269
                panel_run_dialog_set_default_icon (dialog, TRUE);
 
270
        }
 
271
}
 
272
 
 
273
static gboolean
 
274
command_is_executable (const char   *command,
 
275
                       int          *argcp,
 
276
                       char       ***argvp)
 
277
{
 
278
        gboolean   result;
 
279
        char     **argv;
 
280
        char      *path;
 
281
        int        argc;
 
282
 
 
283
        result = g_shell_parse_argv (command, &argc, &argv, NULL);
 
284
 
 
285
        if (!result)
 
286
                return FALSE;
 
287
 
 
288
        path = g_find_program_in_path (argv[0]);
 
289
 
 
290
        if (!path) {
 
291
                g_strfreev (argv);
 
292
                return FALSE;
 
293
        }
 
294
 
 
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.
 
299
         */
 
300
        if (!g_file_test (path, G_FILE_TEST_IS_EXECUTABLE) ||
 
301
            !g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
 
302
                g_free (path);
 
303
                g_strfreev (argv);
 
304
                return FALSE;
 
305
        }
 
306
 
 
307
        g_free (path);
 
308
 
 
309
        if (argcp)
 
310
                *argcp = argc;
 
311
        if (argvp)
 
312
                *argvp = argv;
 
313
 
 
314
        return TRUE;
 
315
}
 
316
 
 
317
/*
 
318
 * Set the DISPLAY variable, to be use by g_spawn_async.
 
319
 */
 
320
static void
 
321
set_environment (gpointer display)
 
322
{
 
323
  g_setenv ("DISPLAY", display, TRUE);
 
324
}
 
325
 
 
326
static void
 
327
dummy_child_watch (GPid         pid,
 
328
                   gint         status,
 
329
                   gpointer user_data)
 
330
{
 
331
        /* Nothing, this is just to ensure we don't double fork
 
332
         * and break pkexec:
 
333
         * https://bugzilla.gnome.org/show_bug.cgi?id=675789
 
334
         */
 
335
}
 
336
 
 
337
 
 
338
/**
 
339
 * gnome_desktop_prepend_terminal_to_vector:
 
340
 * @argc: a pointer to the vector size
 
341
 * @argv: a pointer to the vector
 
342
 *
 
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.
 
351
 **/
 
352
static void
 
353
gnome_desktop_prepend_terminal_to_vector (int *argc, char ***argv)
 
354
{
 
355
#ifndef G_OS_WIN32
 
356
        char **real_argv;
 
357
        int real_argc;
 
358
        int i, j;
 
359
        char **term_argv = NULL;
 
360
        int term_argc = 0;
 
361
        GSettings *settings;
 
362
 
 
363
        gchar *terminal = NULL;
 
364
 
 
365
        char **the_argv;
 
366
 
 
367
        g_return_if_fail (argc != NULL);
 
368
        g_return_if_fail (argv != NULL);
 
369
 
 
370
        // _gnome_desktop_init_i18n ();
 
371
 
 
372
        /* sanity */
 
373
        if(*argv == NULL)
 
374
                *argc = 0;
 
375
 
 
376
        the_argv = *argv;
 
377
 
 
378
        /* compute size if not given */
 
379
        if (*argc < 0) {
 
380
                for (i = 0; the_argv[i] != NULL; i++)
 
381
                        ;
 
382
                *argc = i;
 
383
        }
 
384
 
 
385
        settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
 
386
        terminal = g_settings_get_string (settings, "exec");
 
387
 
 
388
        if (terminal) {
 
389
                gchar *command_line;
 
390
                gchar *exec_flag;
 
391
 
 
392
                exec_flag = g_settings_get_string (settings, "exec-arg");
 
393
 
 
394
                if (exec_flag == NULL)
 
395
                        command_line = g_strdup (terminal);
 
396
                else
 
397
                        command_line = g_strdup_printf ("%s %s", terminal,
 
398
                                                        exec_flag);
 
399
 
 
400
                g_shell_parse_argv (command_line,
 
401
                                    &term_argc,
 
402
                                    &term_argv,
 
403
                                    NULL /* error */);
 
404
 
 
405
                g_free (command_line);
 
406
                g_free (exec_flag);
 
407
                g_free (terminal);
 
408
        }
 
409
 
 
410
        g_object_unref (settings);
 
411
 
 
412
        if (term_argv == NULL) {
 
413
                char *check;
 
414
 
 
415
                term_argc = 2;
 
416
                term_argv = g_new0 (char *, 3);
 
417
 
 
418
                check = g_find_program_in_path ("gnome-terminal");
 
419
                if (check != NULL) {
 
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");
 
424
                } else {
 
425
                        if (check == NULL)
 
426
                                check = g_find_program_in_path ("nxterm");
 
427
                        if (check == NULL)
 
428
                                check = g_find_program_in_path ("color-xterm");
 
429
                        if (check == NULL)
 
430
                                check = g_find_program_in_path ("rxvt");
 
431
                        if (check == NULL)
 
432
                                check = g_find_program_in_path ("xterm");
 
433
                        if (check == NULL)
 
434
                                check = g_find_program_in_path ("dtterm");
 
435
                        if (check == NULL) {
 
436
                                g_warning (_("Cannot find a terminal, using "
 
437
                                             "xterm, even if it may not work"));
 
438
                                check = g_strdup ("xterm");
 
439
                        }
 
440
                        term_argv[0] = check;
 
441
                        term_argv[1] = g_strdup ("-e");
 
442
                }
 
443
        }
 
444
 
 
445
        real_argc = term_argc + *argc;
 
446
        real_argv = g_new (char *, real_argc + 1);
 
447
 
 
448
        for (i = 0; i < term_argc; i++)
 
449
                real_argv[i] = term_argv[i];
 
450
 
 
451
        for (j = 0; j < *argc; j++, i++)
 
452
                real_argv[i] = (char *)the_argv[j];
 
453
 
 
454
        real_argv[i] = NULL;
 
455
 
 
456
        g_free (*argv);
 
457
        *argv = real_argv;
 
458
        *argc = real_argc;
 
459
 
 
460
        /* we use g_free here as we sucked all the inner strings
 
461
         * out from it into real_argv */
 
462
        g_free (term_argv);
 
463
#else
 
464
        /* FIXME: Implement when needed */
 
465
        g_warning ("gnome_prepend_terminal_to_vector: Not implemented");
 
466
#endif
 
467
}
 
468
 
 
469
static gboolean
 
470
panel_run_dialog_launch_command (PanelRunDialog *dialog,
 
471
                                 const char     *command,
 
472
                                 const char     *locale_command)
 
473
{
 
474
        GdkScreen  *screen;
 
475
        gboolean    result;
 
476
        GError     *error = NULL;
 
477
        char      **argv;
 
478
        int         argc;
 
479
        char       *display;
 
480
        GPid        pid;
 
481
 
 
482
        if (!command_is_executable (locale_command, &argc, &argv))
 
483
                return FALSE;
 
484
 
 
485
        screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog));
 
486
 
 
487
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox)))
 
488
                gnome_desktop_prepend_terminal_to_vector (&argc, &argv);
 
489
 
 
490
        display = gdk_screen_make_display_name (screen);
 
491
 
 
492
        result = g_spawn_async (NULL, /* working directory */
 
493
                                argv,
 
494
                                NULL, /* envp */
 
495
                                G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
 
496
                                set_environment,
 
497
                                display,
 
498
                                &pid,
 
499
                                &error);
 
500
 
 
501
        if (!result) {
 
502
                char *primary;
 
503
 
 
504
                primary = g_markup_printf_escaped (_("Could not run command '%s'"),
 
505
                                                   command);
 
506
                panel_error_dialog (GTK_WINDOW (dialog->run_dialog), NULL,
 
507
                                    "cannot_spawn_command", TRUE,
 
508
                                    primary, error->message);
 
509
                g_free (primary);
 
510
 
 
511
                g_error_free (error);
 
512
        } else {
 
513
                g_child_watch_add (pid, dummy_child_watch, NULL);
 
514
        }
 
515
 
 
516
        g_free (display);
 
517
        g_strfreev (argv);
 
518
 
 
519
        return result;
 
520
}
 
521
 
 
522
static void
 
523
panel_run_dialog_execute (PanelRunDialog *dialog)
 
524
{
 
525
        GError   *error;
 
526
        gboolean  result;
 
527
        char     *command;
 
528
        char     *disk;
 
529
        char     *scheme;       
 
530
        
 
531
        command = g_strdup (panel_run_dialog_get_combo_text (dialog));
 
532
        command = g_strchug (command);
 
533
 
 
534
        if (!command || !command [0]) {
 
535
                g_free (command);
 
536
                return;
 
537
        }
 
538
        
 
539
        /* evil eggies, do not translate! */
 
540
        if (!strcmp (command, "free the fish")) {
 
541
                start_screen_check ();
 
542
 
 
543
                g_free (command);
 
544
                gtk_widget_destroy (dialog->run_dialog);
 
545
                return;
 
546
        }
 
547
                
 
548
        error = NULL;
 
549
        disk = g_locale_from_utf8 (command, -1, NULL, NULL, &error);
 
550
 
 
551
        if (!disk || error) {
 
552
                char *primary;
 
553
 
 
554
                primary = g_strdup_printf (_("Could not convert '%s' from UTF-8"),
 
555
                                           command);
 
556
                panel_error_dialog (GTK_WINDOW (dialog->run_dialog), NULL,
 
557
                                    "cannot_convert_command_from_utf8", TRUE,
 
558
                                    primary, error->message);
 
559
                g_free (primary);
 
560
 
 
561
                g_error_free (error);
 
562
                return;
 
563
        }
 
564
 
 
565
        result = FALSE;
 
566
        
 
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);
 
572
        
 
573
        if (!result) {
 
574
                GFile     *file;
 
575
                char      *uri;
 
576
                GdkScreen *screen;
 
577
                
 
578
                file = panel_util_get_file_optional_homedir (command);
 
579
                uri = g_file_get_uri (file);
 
580
                g_object_unref (file);
 
581
 
 
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);
 
585
 
 
586
                g_free (uri);
 
587
        }
 
588
                
 
589
        if (result) {
 
590
                /* only save working commands in history */
 
591
                _panel_run_save_recent_programs_list (dialog, command);
 
592
                
 
593
                /* only close the dialog if we successfully showed or launched
 
594
                 * something */
 
595
                gtk_widget_destroy (dialog->run_dialog);
 
596
        }
 
597
 
 
598
        g_free (command);
 
599
        g_free (disk);
 
600
        g_free (scheme);
 
601
}
 
602
 
 
603
static void
 
604
panel_run_dialog_response (PanelRunDialog *dialog,
 
605
                           int             response,
 
606
                           GtkWidget      *run_dialog)
 
607
{
 
608
 
 
609
        dialog->completion_started = FALSE;
 
610
 
 
611
        switch (response) {
 
612
        case GTK_RESPONSE_OK:
 
613
                panel_run_dialog_execute (dialog);
 
614
                break;
 
615
        case GTK_RESPONSE_CANCEL:
 
616
                gtk_widget_destroy (dialog->run_dialog);
 
617
                break;
 
618
        default:
 
619
                break;
 
620
        }
 
621
}
 
622
 
 
623
/* only quote the string if really needed */
 
624
static char *
 
625
quote_string (const char *s)
 
626
{
 
627
        const char *p;
 
628
        
 
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)
 
634
                        ;
 
635
                else
 
636
                        return g_shell_quote (s);
 
637
        }
 
638
        
 
639
        return g_strdup (s);
 
640
}
 
641
 
 
642
static void
 
643
panel_run_dialog_append_file_utf8 (PanelRunDialog *dialog,
 
644
                                   const char     *file)
 
645
{
 
646
        const char *text;
 
647
        char       *quoted, *temp;
 
648
        GtkWidget  *entry;
 
649
        
 
650
        /* Don't allow filenames beginning with '-' */
 
651
        if (!file || !file[0] || file[0] == '-')
 
652
                return;
 
653
        
 
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);
 
660
                g_free (temp);
 
661
        } else
 
662
                gtk_entry_set_text (GTK_ENTRY (entry), quoted);
 
663
        
 
664
        g_free (quoted);
 
665
}
 
666
 
 
667
static void
 
668
panel_run_dialog_append_file (PanelRunDialog *dialog,
 
669
                              const char *file)
 
670
{
 
671
        char *utf8_file;
 
672
        
 
673
        if (!file)
 
674
                return;
 
675
        
 
676
        utf8_file = g_filename_to_utf8 (file, -1, NULL, NULL, NULL);
 
677
        
 
678
        if (utf8_file)
 
679
                panel_run_dialog_append_file_utf8 (dialog, utf8_file);
 
680
        
 
681
        g_free (utf8_file);
 
682
}
 
683
 
 
684
static gboolean
 
685
fuzzy_command_match (const char *cmd1,
 
686
                     const char *cmd2,
 
687
                     gboolean   *fuzzy)
 
688
{
 
689
        char **tokens;
 
690
        char  *word1, *word2;
 
691
 
 
692
        g_return_val_if_fail (cmd1 && cmd2, TRUE);
 
693
 
 
694
        *fuzzy = FALSE;
 
695
 
 
696
        if (!strcmp (cmd1, cmd2))
 
697
                return TRUE;
 
698
 
 
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]) {
 
703
                g_strfreev (tokens);
 
704
                return FALSE;
 
705
        }
 
706
 
 
707
        word1 = g_path_get_basename (tokens [0]);
 
708
        g_strfreev (tokens);
 
709
 
 
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]) {
 
714
                g_free (word1);
 
715
                g_strfreev (tokens);
 
716
                return FALSE;
 
717
        }
 
718
 
 
719
        g_strfreev (tokens);
 
720
 
 
721
        if (!strcmp (word1, word2)) {
 
722
                g_free (word1);
 
723
                g_free (word2);
 
724
                *fuzzy = TRUE;
 
725
                return TRUE;
 
726
        }
 
727
 
 
728
        g_free (word1);
 
729
        g_free (word2);
 
730
 
 
731
        return FALSE;
 
732
}
 
733
 
 
734
static gboolean
 
735
panel_run_dialog_make_all_list_visible (GtkTreeModel *model,
 
736
                                        GtkTreePath  *path,
 
737
                                        GtkTreeIter  *iter,
 
738
                                        gpointer      data)
 
739
{
 
740
        gtk_list_store_set (GTK_LIST_STORE (model), iter,
 
741
                            COLUMN_VISIBLE, TRUE,
 
742
                            -1);
 
743
 
 
744
        return FALSE;
 
745
}
 
746
 
 
747
static gboolean
 
748
panel_run_dialog_find_command_idle (PanelRunDialog *dialog)
 
749
{
 
750
        GtkTreeIter   iter;
 
751
        GtkTreeModel *model;
 
752
        GtkTreePath  *path;
 
753
        char         *text;
 
754
        GIcon        *found_icon;
 
755
        char         *found_name;
 
756
        gboolean      fuzzy;
 
757
        
 
758
        model = GTK_TREE_MODEL (dialog->program_list_store);
 
759
        path = gtk_tree_path_new_first ();
 
760
        
 
761
        if (!path || !gtk_tree_model_get_iter (model, &iter, path)) {
 
762
                if (path)
 
763
                        gtk_tree_path_free (path);
 
764
                
 
765
                panel_run_dialog_set_icon (dialog, NULL, FALSE);
 
766
        
 
767
                dialog->find_command_idle_id = 0;
 
768
                return FALSE;
 
769
        }
 
770
 
 
771
        text = g_strdup (panel_run_dialog_get_combo_text (dialog));
 
772
        found_icon = NULL;
 
773
        found_name = NULL;
 
774
        fuzzy = FALSE;
 
775
 
 
776
        do {
 
777
                char *exec = NULL;
 
778
                char *name = NULL;
 
779
                char *comment = NULL;
 
780
                GIcon *icon = NULL;
 
781
 
 
782
                gtk_tree_model_get (model, &iter,
 
783
                                    COLUMN_EXEC,    &exec,
 
784
                                    COLUMN_ICON,    &icon,
 
785
                                    COLUMN_NAME,    &name,
 
786
                                    COLUMN_COMMENT, &comment,
 
787
                                    -1);
 
788
 
 
789
                if (!fuzzy && exec && icon &&
 
790
                    fuzzy_command_match (text, exec, &fuzzy)) {
 
791
                        if (found_icon)
 
792
                                g_object_unref (found_icon);
 
793
                        g_free (found_name);
 
794
                        
 
795
                        found_icon = g_object_ref (icon);
 
796
                        found_name = g_strdup (name);
 
797
                        
 
798
                        gtk_list_store_set (dialog->program_list_store,
 
799
                                            &iter,
 
800
                                            COLUMN_VISIBLE, TRUE,
 
801
                                            -1);
 
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,
 
806
                                            &iter,
 
807
                                            COLUMN_VISIBLE, TRUE,
 
808
                                            -1);
 
809
                } else {
 
810
                        gtk_list_store_set (dialog->program_list_store,
 
811
                                            &iter,
 
812
                                            COLUMN_VISIBLE, FALSE,
 
813
                                            -1);
 
814
                }
 
815
 
 
816
                g_free (exec);
 
817
                g_object_unref (icon);
 
818
                g_free (name);
 
819
                g_free (comment);
 
820
        
 
821
        } while (gtk_tree_model_iter_next (model, &iter));
 
822
 
 
823
        if (gtk_tree_model_get_iter (gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->program_list)),
 
824
                                     &iter, path))
 
825
                gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->program_list),
 
826
                                              path, NULL, FALSE, 0, 0);
 
827
 
 
828
        gtk_tree_path_free (path);
 
829
 
 
830
        panel_run_dialog_set_icon (dialog, found_icon, FALSE);
 
831
        //FIXME update dialog->program_label
 
832
 
 
833
        if (found_icon)
 
834
                g_object_unref (found_icon);
 
835
        g_free (text);
 
836
        
 
837
        g_free (dialog->item_name);
 
838
        dialog->item_name = found_name;
 
839
        
 
840
        dialog->find_command_idle_id = 0;
 
841
        return FALSE;
 
842
}
 
843
 
 
844
static int
 
845
compare_applications (GMenuTreeEntry *a,
 
846
                      GMenuTreeEntry *b)
 
847
{
 
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))));
 
850
}
 
851
 
 
852
static GSList *get_all_applications_from_dir (GMenuTreeDirectory *directory,
 
853
                                              GSList            *list);
 
854
 
 
855
static GSList *
 
856
get_all_applications_from_alias (GMenuTreeAlias *alias,
 
857
                                 GSList         *list)
 
858
{
 
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));
 
863
                break;
 
864
 
 
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);
 
869
                break;
 
870
        }
 
871
 
 
872
        default:
 
873
                break;
 
874
        }
 
875
 
 
876
        return list;
 
877
}
 
878
 
 
879
static GSList *
 
880
get_all_applications_from_dir (GMenuTreeDirectory *directory,
 
881
                               GSList             *list)
 
882
{
 
883
        GMenuTreeIter *iter;
 
884
        GMenuTreeItemType next_type;
 
885
 
 
886
        iter = gmenu_tree_directory_iter (directory);
 
887
 
 
888
        while ((next_type = gmenu_tree_iter_next (iter)) != GMENU_TREE_ITEM_INVALID) {
 
889
                switch (next_type) {
 
890
                case GMENU_TREE_ITEM_ENTRY:
 
891
                        list = g_slist_append (list, gmenu_tree_iter_get_entry (iter));
 
892
                        break;
 
893
 
 
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);
 
898
                        break;
 
899
                }
 
900
 
 
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);
 
905
                        break;
 
906
                }
 
907
 
 
908
                default:
 
909
                        break;
 
910
                }
 
911
        }
 
912
 
 
913
        gmenu_tree_iter_unref (iter);
 
914
 
 
915
        return list;
 
916
}
 
917
 
 
918
static GSList *
 
919
get_all_applications (void)
 
920
{
 
921
        GMenuTree          *tree;
 
922
        GMenuTreeDirectory *root;
 
923
        GSList             *retval;
 
924
 
 
925
        tree = gmenu_tree_new ("applications.menu", GMENU_TREE_FLAGS_SORT_DISPLAY_NAME);
 
926
 
 
927
        if (!gmenu_tree_load_sync (tree, NULL))
 
928
                return NULL;
 
929
 
 
930
        root = gmenu_tree_get_root_directory (tree);
 
931
 
 
932
        retval = get_all_applications_from_dir (root, NULL);
 
933
 
 
934
        gmenu_tree_item_unref (root);
 
935
        g_object_unref (tree);
 
936
 
 
937
        retval = g_slist_sort (retval,
 
938
                               (GCompareFunc) compare_applications);
 
939
 
 
940
        return retval;
 
941
}
 
942
 
 
943
static gboolean
 
944
panel_run_dialog_add_items_idle (PanelRunDialog *dialog)
 
945
{
 
946
        GtkCellRenderer   *renderer;
 
947
        GtkTreeViewColumn *column;
 
948
        GtkTreeModel      *model_filter;
 
949
        GSList            *all_applications;
 
950
        GSList            *l;
 
951
        GSList            *next;
 
952
        const char        *prev_name;
 
953
 
 
954
        /* create list store */
 
955
        dialog->program_list_store = gtk_list_store_new (NUM_COLUMNS,
 
956
                                                         G_TYPE_ICON,
 
957
                                                         G_TYPE_STRING,
 
958
                                                         G_TYPE_STRING,
 
959
                                                         G_TYPE_STRING,
 
960
                                                         G_TYPE_STRING,
 
961
                                                         G_TYPE_BOOLEAN);
 
962
 
 
963
        all_applications = get_all_applications ();
 
964
        
 
965
        /* Strip duplicates */
 
966
        prev_name = NULL;
 
967
        for (l = all_applications; l; l = next) {
 
968
                GMenuTreeEntry  *entry = l->data;
 
969
                const char      *entry_name;
 
970
                GDesktopAppInfo *app_info;
 
971
 
 
972
 
 
973
                next = l->next;
 
974
                app_info = gmenu_tree_entry_get_app_info (entry);
 
975
 
 
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);
 
979
 
 
980
                        all_applications = g_slist_delete_link (all_applications, l);
 
981
                } else {
 
982
                        prev_name = entry_name;
 
983
                }
 
984
        }
 
985
 
 
986
        for (l = all_applications; l; l = l->next) {
 
987
                GMenuTreeEntry *entry = l->data;
 
988
                GtkTreeIter     iter;
 
989
                GtkTreePath    *path;
 
990
                GAppInfo       *app_info;
 
991
 
 
992
                app_info = G_APP_INFO (gmenu_tree_entry_get_app_info (entry));
 
993
 
 
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,
 
1002
                                    -1);
 
1003
 
 
1004
                path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->program_list_store), &iter);
 
1005
                if (path != NULL)
 
1006
                        dialog->add_icon_paths = g_slist_prepend (dialog->add_icon_paths, path);
 
1007
 
 
1008
                gmenu_tree_item_unref (entry);
 
1009
        }
 
1010
        g_slist_free (all_applications);
 
1011
 
 
1012
        model_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (dialog->program_list_store),
 
1013
                                                  NULL);
 
1014
        gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (model_filter),
 
1015
                                                  COLUMN_VISIBLE);
 
1016
 
 
1017
        gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->program_list), 
 
1018
                                 model_filter);
 
1019
        //FIXME use the same search than the fuzzy one?
 
1020
        gtk_tree_view_set_search_column (GTK_TREE_VIEW (dialog->program_list),
 
1021
                                         COLUMN_NAME);
 
1022
 
 
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,
 
1028
                                             NULL);
 
1029
        
 
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,
 
1034
                                             NULL);
 
1035
                                                  
 
1036
        gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->program_list), column);
 
1037
 
 
1038
        dialog->add_icon_paths = g_slist_reverse (dialog->add_icon_paths);
 
1039
 
 
1040
        dialog->add_items_idle_id = 0;                                   
 
1041
        return FALSE;
 
1042
}
 
1043
 
 
1044
static char *
 
1045
remove_parameters (const char *exec)
 
1046
{
 
1047
        GString *str;
 
1048
        char    *retval, *p;
 
1049
 
 
1050
        str = g_string_new (exec);
 
1051
 
 
1052
        while ((p = strstr (str->str, "%"))) {
 
1053
                switch (p [1]) {
 
1054
                case '%':
 
1055
                        g_string_erase (str, p - str->str, 1);
 
1056
                        break;
 
1057
                case 'U':
 
1058
                case 'F':
 
1059
                case 'N':
 
1060
                case 'D':
 
1061
                case 'f':
 
1062
                case 'u':
 
1063
                case 'd':
 
1064
                case 'n':
 
1065
                case 'm':
 
1066
                case 'i':
 
1067
                case 'c':
 
1068
                case 'k':
 
1069
                case 'v':
 
1070
                        g_string_erase (str, p - str->str, 2);
 
1071
                        break;
 
1072
                default:
 
1073
                        break;
 
1074
                }
 
1075
        }
 
1076
 
 
1077
        retval = str->str;
 
1078
        g_string_free (str, FALSE);
 
1079
 
 
1080
        return retval;
 
1081
}
 
1082
 
 
1083
static void
 
1084
program_list_selection_changed (GtkTreeSelection *selection,
 
1085
                                PanelRunDialog   *dialog)
 
1086
{
 
1087
        GtkTreeModel *filter_model;
 
1088
        GtkTreeModel *child_model;
 
1089
        GtkTreeIter   iter;
 
1090
        GtkTreeIter   filter_iter;
 
1091
        char         *temp;
 
1092
        char         *path, *stripped;
 
1093
        gboolean      terminal;
 
1094
        GKeyFile     *key_file;
 
1095
        GtkWidget    *entry;
 
1096
 
 
1097
        if (!gtk_tree_selection_get_selected (selection, &filter_model,
 
1098
                                              &filter_iter))
 
1099
                return;
 
1100
 
 
1101
        gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (filter_model),
 
1102
                                                          &iter, &filter_iter);
 
1103
 
 
1104
        path = NULL;
 
1105
        child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
 
1106
        gtk_tree_model_get (child_model, &iter,
 
1107
                            COLUMN_PATH, &path,
 
1108
                            -1);
 
1109
                                  
 
1110
        if (!path)
 
1111
                return;
 
1112
 
 
1113
        key_file = g_key_file_new ();
 
1114
 
 
1115
        if (!g_key_file_load_from_file (key_file, path,
 
1116
                                        G_KEY_FILE_NONE, NULL)) {
 
1117
                g_key_file_free (key_file);
 
1118
                g_free (path);
 
1119
                return;
 
1120
        }
 
1121
 
 
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;
 
1129
 
 
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.
 
1133
         */
 
1134
        entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
 
1135
        temp = panel_key_file_get_string (key_file, "Exec");
 
1136
        if (temp) {
 
1137
                stripped = remove_parameters (temp);
 
1138
                gtk_entry_set_text (GTK_ENTRY (entry), stripped);
 
1139
                g_free (stripped);
 
1140
        } else {
 
1141
                temp = panel_key_file_get_string (key_file, "URL");
 
1142
                gtk_entry_set_text (GTK_ENTRY (entry), sure_string (temp));
 
1143
        }
 
1144
        g_free (temp);
 
1145
 
 
1146
        temp = panel_key_file_get_locale_string (key_file, "Icon");
 
1147
        if (!PANEL_GLIB_STR_EMPTY (temp)) {
 
1148
                GIcon *gicon;
 
1149
 
 
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);
 
1154
                g_free (stripped);
 
1155
        } else {
 
1156
                panel_run_dialog_set_icon (dialog, NULL, FALSE);
 
1157
        }
 
1158
        g_free (temp);
 
1159
        
 
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));
 
1164
        g_free (temp);
 
1165
 
 
1166
        terminal = panel_key_file_get_boolean (key_file, "Terminal", FALSE);
 
1167
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox),
 
1168
                                      terminal);
 
1169
 
 
1170
        g_key_file_free (key_file);
 
1171
 
 
1172
        g_free (path);
 
1173
}
 
1174
 
 
1175
static void
 
1176
program_list_selection_activated (GtkTreeView       *view,
 
1177
                                  GtkTreePath       *path,
 
1178
                                  GtkTreeViewColumn *column,
 
1179
                                  PanelRunDialog    *dialog)
 
1180
{
 
1181
        GtkTreeSelection *selection;
 
1182
 
 
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);
 
1186
        
 
1187
        /* now launch the command */
 
1188
        gtk_dialog_response (GTK_DIALOG (dialog->run_dialog), GTK_RESPONSE_OK);
 
1189
}
 
1190
 
 
1191
 
 
1192
static void
 
1193
panel_run_dialog_setup_program_list (PanelRunDialog *dialog,
 
1194
                                     GtkBuilder     *gui)
 
1195
{
 
1196
        GtkTreeSelection *selection;
 
1197
        
 
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");
 
1201
        
 
1202
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->program_list));
 
1203
        gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
1204
 
 
1205
        g_signal_connect (selection, "changed",
 
1206
                          G_CALLBACK (program_list_selection_changed),
 
1207
                          dialog);
 
1208
 
 
1209
        g_signal_connect (dialog->program_list, "row-activated",
 
1210
                          G_CALLBACK (program_list_selection_activated),
 
1211
                          dialog);
 
1212
}
 
1213
 
 
1214
static void
 
1215
panel_run_dialog_setup_list_expander (PanelRunDialog *dialog,
 
1216
                                      GtkBuilder     *gui)
 
1217
{
 
1218
        dialog->list_expander = PANEL_GTK_BUILDER_GET (gui, "list_expander");
 
1219
 
 
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);
 
1223
 
 
1224
        g_settings_bind (dialog->run_settings,
 
1225
                         PANEL_RUN_SHOW_LIST_KEY,
 
1226
                         dialog->list_expander,
 
1227
                         "expanded",
 
1228
                         G_SETTINGS_BIND_DEFAULT);
 
1229
}
 
1230
 
 
1231
static void
 
1232
panel_run_dialog_update_program_list (GSettings      *settings,
 
1233
                                      char           *key,
 
1234
                                      PanelRunDialog *dialog)
 
1235
{
 
1236
        gboolean   enabled;
 
1237
        gboolean   shown;
 
1238
        GtkWidget *parent;
 
1239
 
 
1240
        enabled = g_settings_get_boolean (dialog->run_settings,
 
1241
                                          PANEL_RUN_ENABLE_LIST_KEY);
 
1242
 
 
1243
        parent = gtk_widget_get_parent (dialog->list_expander);
 
1244
 
 
1245
        if (enabled) {
 
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,
 
1251
                                                 dialog, NULL);
 
1252
                }
 
1253
 
 
1254
                if (!parent)
 
1255
                        gtk_box_pack_end (GTK_BOX (dialog->main_box),
 
1256
                                          dialog->list_expander,
 
1257
                                          TRUE, TRUE, 0);
 
1258
        } else {
 
1259
                if (parent)
 
1260
                        gtk_container_remove (GTK_CONTAINER (parent),
 
1261
                                              dialog->list_expander);
 
1262
        }
 
1263
 
 
1264
        shown = g_settings_get_boolean (dialog->run_settings,
 
1265
                                        PANEL_RUN_SHOW_LIST_KEY);
 
1266
 
 
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);
 
1271
        } else {
 
1272
                gtk_window_set_resizable (GTK_WINDOW (dialog->run_dialog), FALSE);
 
1273
                gtk_widget_grab_focus (dialog->combobox);
 
1274
        }
 
1275
}
 
1276
 
 
1277
static void
 
1278
file_button_browse_response (GtkWidget      *chooser,
 
1279
                             gint            response,
 
1280
                             PanelRunDialog *dialog)
 
1281
{
 
1282
        char *file;
 
1283
        
 
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);
 
1287
                g_free (file);
 
1288
        }
 
1289
 
 
1290
        gtk_widget_destroy (chooser);
 
1291
 
 
1292
        gtk_widget_grab_focus (dialog->combobox);
 
1293
}
 
1294
 
 
1295
static void
 
1296
file_button_clicked (GtkButton      *button,
 
1297
                     PanelRunDialog *dialog)
 
1298
{
 
1299
        GtkWidget *chooser;
 
1300
 
 
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,
 
1306
                                               NULL);
 
1307
        
 
1308
        gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
 
1309
                                             g_get_home_dir ());
 
1310
        
 
1311
        gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
 
1312
        gtk_window_set_destroy_with_parent (GTK_WINDOW (chooser), TRUE);
 
1313
 
 
1314
        g_signal_connect (chooser, "response",
 
1315
                          G_CALLBACK (file_button_browse_response), dialog);
 
1316
 
 
1317
        gtk_window_present (GTK_WINDOW (chooser));
 
1318
}
 
1319
 
 
1320
static void
 
1321
panel_run_dialog_setup_file_button (PanelRunDialog *dialog,
 
1322
                                    GtkBuilder     *gui)
 
1323
{
 
1324
        dialog->file_button = PANEL_GTK_BUILDER_GET (gui, "file_button");
 
1325
                
 
1326
        g_signal_connect (dialog->file_button, "clicked",
 
1327
                          G_CALLBACK (file_button_clicked),
 
1328
                          dialog);
 
1329
}
 
1330
 
 
1331
static GList *
 
1332
fill_files_from (const char *dirname,
 
1333
                 const char *dirprefix,
 
1334
                 char        prefix,
 
1335
                 GList      *existing_items)
 
1336
{
 
1337
        GList         *list;
 
1338
        DIR           *dir;
 
1339
        struct dirent *dent;
 
1340
        
 
1341
        list = NULL;
 
1342
        dir = opendir (dirname);
 
1343
        
 
1344
        if (!dir)
 
1345
                return list;
 
1346
        
 
1347
        while ((dent = readdir (dir))) {
 
1348
                char       *file;
 
1349
                char       *item;
 
1350
                const char *suffix;
 
1351
                
 
1352
                if (!dent->d_name ||
 
1353
                    dent->d_name [0] != prefix)
 
1354
                        continue;
 
1355
 
 
1356
                file = g_build_filename (dirname, dent->d_name, NULL);
 
1357
                
 
1358
                suffix = NULL;
 
1359
                if (
 
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))
 
1365
#else
 
1366
                    g_file_test (file, G_FILE_TEST_IS_DIR)
 
1367
#endif
 
1368
                   )
 
1369
                        suffix = "/";
 
1370
                
 
1371
                g_free (file);
 
1372
                
 
1373
                item = g_build_filename (dirprefix, dent->d_name, suffix, NULL);
 
1374
                
 
1375
                list = g_list_prepend (list, item);
 
1376
        }
 
1377
 
 
1378
        closedir (dir);
 
1379
        
 
1380
        return list;
 
1381
}       
 
1382
 
 
1383
static GList *
 
1384
fill_possible_executables (void)
 
1385
{
 
1386
        GList         *list;
 
1387
        const char    *path;
 
1388
        char         **pathv;
 
1389
        int            i;
 
1390
        
 
1391
        list = NULL;
 
1392
        path = g_getenv ("PATH");
 
1393
 
 
1394
        if (!path || !path [0])
 
1395
                return list;
 
1396
 
 
1397
        pathv = g_strsplit (path, ":", 0);
 
1398
        
 
1399
        for (i = 0; pathv [i]; i++) {
 
1400
                const char *file;
 
1401
                char       *filename;
 
1402
                GDir       *dir;
 
1403
 
 
1404
                dir = g_dir_open (pathv [i], 0, NULL);
 
1405
 
 
1406
                if (!dir)
 
1407
                        continue;
 
1408
 
 
1409
                while ((file = g_dir_read_name (dir))) {
 
1410
                        filename = g_build_filename (pathv [i], file, NULL);
 
1411
                        list = g_list_prepend (list, filename);
 
1412
                }
 
1413
 
 
1414
                g_dir_close (dir);
 
1415
        }
 
1416
        
 
1417
        g_strfreev (pathv);
 
1418
        
 
1419
        return list;
 
1420
}
 
1421
 
 
1422
static GList *
 
1423
fill_executables (GList *possible_executables,
 
1424
                  GList *existing_items,
 
1425
                  char   prefix)
 
1426
{
 
1427
        GList *list;
 
1428
        GList *l;
 
1429
        
 
1430
        list = NULL;    
 
1431
        
 
1432
        for (l = possible_executables; l; l = l->next) {
 
1433
                const char *filename;
 
1434
                char       *basename;
 
1435
                        
 
1436
                filename = l->data;
 
1437
                basename = g_path_get_basename (filename);
 
1438
                        
 
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)) {
 
1442
                            
 
1443
                        if (g_list_find_custom (existing_items, basename,
 
1444
                                                (GCompareFunc) strcmp)) {
 
1445
                                g_free (basename);
 
1446
                                return NULL;
 
1447
                        }
 
1448
 
 
1449
                        list = g_list_prepend (list, basename);
 
1450
                 } else {
 
1451
                        g_free (basename);
 
1452
                 }
 
1453
        }
 
1454
        
 
1455
        return list;
 
1456
}
 
1457
 
 
1458
static void
 
1459
panel_run_dialog_update_completion (PanelRunDialog *dialog,
 
1460
                                    const char     *text)
 
1461
{
 
1462
        GList *list;
 
1463
        GList *executables;
 
1464
        char   prefix;
 
1465
        char  *buf;
 
1466
        char  *dirname;
 
1467
        char  *dirprefix;
 
1468
        char  *key;
 
1469
 
 
1470
        g_assert (text != NULL && *text != '\0' && !g_ascii_isspace (*text));
 
1471
 
 
1472
        list = NULL;
 
1473
        executables = NULL;
 
1474
 
 
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,
 
1479
                                                          g_str_equal,
 
1480
                                                          g_free, NULL);
 
1481
        }
 
1482
        
 
1483
        buf = g_path_get_basename (text);
 
1484
        prefix = buf[0];
 
1485
        g_free (buf);
 
1486
        if (prefix == '/' || prefix == '.')
 
1487
                return;
 
1488
 
 
1489
        if (text [0] == '/') {
 
1490
                /* complete against absolute path */
 
1491
                dirname = g_path_get_dirname (text);
 
1492
                dirprefix = g_strdup (dirname);
 
1493
        } else {
 
1494
                /* complete against relative path and executable name */
 
1495
                if (!strchr (text, '/')) {
 
1496
                        executables = fill_executables (dialog->possible_executables,
 
1497
                                                        dialog->completion_items,
 
1498
                                                        text [0]);
 
1499
                        dirprefix = g_strdup ("");
 
1500
                } else {
 
1501
                        dirprefix = g_path_get_dirname (text);
 
1502
                }
 
1503
 
 
1504
                dirname = g_build_filename (g_get_home_dir (), dirprefix, NULL);
 
1505
        }
 
1506
 
 
1507
        key = g_strdup_printf ("%s%c%c", dirprefix, G_DIR_SEPARATOR, prefix);
 
1508
 
 
1509
        if (!g_hash_table_lookup (dialog->dir_hash, key)) {
 
1510
                g_hash_table_insert (dialog->dir_hash, key, dialog);
 
1511
 
 
1512
                list = fill_files_from (dirname, dirprefix, prefix,
 
1513
                                        dialog->completion_items);
 
1514
        } else {
 
1515
                g_free (key);
 
1516
        }
 
1517
 
 
1518
        list = g_list_concat (list, executables);
 
1519
 
 
1520
        g_free (dirname);
 
1521
        g_free (dirprefix);
 
1522
 
 
1523
        if (list == NULL)
 
1524
                return;
 
1525
                
 
1526
        g_completion_add_items (dialog->completion, list);
 
1527
                
 
1528
        dialog->completion_items = g_list_concat (dialog->completion_items,
 
1529
                                                  list);        
 
1530
}
 
1531
 
 
1532
static gboolean
 
1533
entry_event (GtkEditable    *entry,
 
1534
             GdkEventKey    *event,
 
1535
             PanelRunDialog *dialog)
 
1536
{
 
1537
        GtkTreeSelection *selection;
 
1538
        char             *prefix;
 
1539
        char             *nospace_prefix;
 
1540
        char             *nprefix;
 
1541
        char             *temp;
 
1542
        int               pos, tmp;
 
1543
 
 
1544
        if (event->type != GDK_KEY_PRESS)
 
1545
                return FALSE;
 
1546
 
 
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);
 
1551
 
 
1552
        if (!g_settings_get_boolean (dialog->run_settings,
 
1553
                                     PANEL_RUN_ENABLE_COMPLETION_KEY))
 
1554
                return FALSE;
 
1555
 
 
1556
        /* tab completion */
 
1557
        if (event->keyval == GDK_KEY_Tab) {
 
1558
                gtk_editable_get_selection_bounds (entry, &pos, &tmp);
 
1559
 
 
1560
                if (dialog->completion_started &&
 
1561
                    pos != tmp &&
 
1562
                    pos != 1 &&
 
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);
 
1566
                        
 
1567
                        return TRUE;
 
1568
                }
 
1569
        } else if (event->length > 0) {
 
1570
                           
 
1571
                gtk_editable_get_selection_bounds (entry, &pos, &tmp);
 
1572
 
 
1573
                if (dialog->completion_started &&
 
1574
                    pos != tmp &&
 
1575
                    pos != 0 &&
 
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);
 
1579
                        g_free (temp);
 
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);
 
1584
                } else {
 
1585
                        return FALSE;
 
1586
                }
 
1587
                
 
1588
                nospace_prefix = prefix;
 
1589
                while (*nospace_prefix != '\0' &&
 
1590
                       g_ascii_isspace (*nospace_prefix))
 
1591
                        nospace_prefix++;
 
1592
                if (*nospace_prefix == '\0')
 
1593
                        return FALSE;
 
1594
 
 
1595
                panel_run_dialog_update_completion (dialog, nospace_prefix);
 
1596
                
 
1597
                if (!dialog->completion) {
 
1598
                        g_free (prefix);
 
1599
                        return FALSE;
 
1600
                }
 
1601
                
 
1602
                pos = strlen (prefix);
 
1603
                nprefix = NULL;
 
1604
 
 
1605
                g_completion_complete_utf8 (dialog->completion, nospace_prefix,
 
1606
                                            &nprefix);
 
1607
 
 
1608
                if (nprefix) {
 
1609
                        int insertpos;
 
1610
                        insertpos = 0;
 
1611
 
 
1612
                        temp = g_strndup (prefix, nospace_prefix - prefix);
 
1613
                        g_free (prefix);
 
1614
 
 
1615
                        prefix = g_strconcat (temp, nprefix, NULL);
 
1616
 
 
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);
 
1622
 
 
1623
                        gtk_editable_insert_text (entry,
 
1624
                                                  prefix, strlen (prefix),
 
1625
                                                  &insertpos);
 
1626
 
 
1627
                        gtk_editable_set_position (entry, pos);
 
1628
                        gtk_editable_select_region (entry, pos, -1);
 
1629
                        
 
1630
                        dialog->completion_started = TRUE;
 
1631
 
 
1632
                        g_free (temp);
 
1633
                        g_free (nprefix);
 
1634
                        g_free (prefix);
 
1635
                        
 
1636
                        return TRUE;
 
1637
                }
 
1638
                
 
1639
                g_free (prefix);
 
1640
        }
 
1641
        
 
1642
        return FALSE;
 
1643
}
 
1644
 
 
1645
static void
 
1646
combobox_changed (GtkComboBox    *combobox,
 
1647
                  PanelRunDialog *dialog)
 
1648
{
 
1649
        gboolean  program_list_enabled;
 
1650
        char     *text;
 
1651
        char     *start;
 
1652
        char     *msg;
 
1653
 
 
1654
        program_list_enabled = g_settings_get_boolean (dialog->run_settings,
 
1655
                                                       PANEL_RUN_ENABLE_LIST_KEY);
 
1656
 
 
1657
        text = g_strdup (panel_run_dialog_get_combo_text (dialog));
 
1658
 
 
1659
        start = text;
 
1660
        while (*start != '\0' && g_ascii_isspace (*start))
 
1661
                start++;
 
1662
 
 
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;
 
1668
                }
 
1669
                if (dialog->item_name) {
 
1670
                        g_free (dialog->item_name);
 
1671
                        dialog->item_name = NULL;
 
1672
                }
 
1673
        }
 
1674
 
 
1675
        /* desensitize run button if no text entered */
 
1676
        if (!start || !start [0]) {
 
1677
                g_free (text);
 
1678
 
 
1679
                gtk_widget_set_sensitive (dialog->run_button, FALSE);
 
1680
                gtk_drag_source_unset (dialog->run_dialog);
 
1681
 
 
1682
                if (program_list_enabled)
 
1683
                        gtk_label_set_text (GTK_LABEL (dialog->program_label),
 
1684
                                            _("Select an application to view its description."));
 
1685
 
 
1686
                panel_run_dialog_set_default_icon (dialog, FALSE);
 
1687
 
 
1688
                if (dialog->find_command_idle_id) {
 
1689
                        g_source_remove (dialog->find_command_idle_id);
 
1690
                        dialog->find_command_idle_id = 0;
 
1691
                }
 
1692
 
 
1693
                if (program_list_enabled) {
 
1694
                        GtkTreeIter  iter;
 
1695
                        GtkTreePath *path;
 
1696
 
 
1697
                        gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->program_list_store),
 
1698
                                                panel_run_dialog_make_all_list_visible,
 
1699
                                                NULL);
 
1700
 
 
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)),
 
1703
                                                     &iter, path))
 
1704
                                gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->program_list),
 
1705
                                                              path, NULL,
 
1706
                                                              FALSE, 0, 0);
 
1707
                        gtk_tree_path_free (path);
 
1708
                }
 
1709
 
 
1710
                return;
 
1711
        }
 
1712
 
 
1713
        gtk_widget_set_sensitive (dialog->run_button, TRUE);
 
1714
        gtk_drag_source_set (dialog->run_dialog,
 
1715
                             GDK_BUTTON1_MASK,
 
1716
                             NULL, 0,
 
1717
                             GDK_ACTION_COPY);
 
1718
        gtk_drag_source_add_uri_targets (dialog->run_dialog);
 
1719
 
 
1720
        if (program_list_enabled &&
 
1721
            !dialog->use_program_list) {
 
1722
                msg = g_strdup_printf (_("Will run command: '%s'"),
 
1723
                                       start);
 
1724
                gtk_label_set_text (GTK_LABEL (dialog->program_label), msg);
 
1725
                g_free (msg);
 
1726
        }
 
1727
        
 
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,
 
1735
                                         dialog, NULL);
 
1736
 
 
1737
        g_free (text);
 
1738
}
 
1739
 
 
1740
static void
 
1741
entry_drag_data_received (GtkEditable      *entry,
 
1742
                          GdkDragContext   *context,
 
1743
                          gint              x,
 
1744
                          gint              y,
 
1745
                          GtkSelectionData *selection_data,
 
1746
                          guint             info,
 
1747
                          guint32           time,
 
1748
                          PanelRunDialog   *dialog)
 
1749
{
 
1750
        char **uris;
 
1751
        char  *file;
 
1752
        int    i;
 
1753
 
 
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));
 
1758
                return;
 
1759
        }
 
1760
 
 
1761
        uris = g_uri_list_extract_uris ((const char *)gtk_selection_data_get_data (selection_data));
 
1762
 
 
1763
        if (!uris) {
 
1764
                gtk_drag_finish (context, FALSE, FALSE, time);
 
1765
                return;
 
1766
        }
 
1767
 
 
1768
        for (i = 0; uris [i]; i++) {
 
1769
                if (!uris [i] || !uris [i][0])
 
1770
                        continue;
 
1771
                
 
1772
                file = g_filename_from_uri (uris [i], NULL, NULL);
 
1773
 
 
1774
                /* FIXME: I assume the file is in utf8 encoding if coming from a URI? */
 
1775
                if (file) {
 
1776
                        panel_run_dialog_append_file_utf8 (dialog, file);
 
1777
                        g_free (file);
 
1778
                } else
 
1779
                        panel_run_dialog_append_file_utf8 (dialog, uris [i]);
 
1780
        }
 
1781
 
 
1782
        g_strfreev (uris);
 
1783
        gtk_drag_finish (context, TRUE, FALSE, time);
 
1784
}
 
1785
 
 
1786
static void
 
1787
panel_run_dialog_setup_entry (PanelRunDialog *dialog,
 
1788
                              GtkBuilder     *gui)
 
1789
{
 
1790
        GdkScreen             *screen;
 
1791
        int                    width_request;
 
1792
        GtkWidget             *entry;
 
1793
        
 
1794
        dialog->combobox = PANEL_GTK_BUILDER_GET (gui, "comboboxentry");
 
1795
 
 
1796
        entry = gtk_bin_get_child (GTK_BIN (dialog->combobox));
 
1797
        gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
 
1798
 
 
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);
 
1803
 
 
1804
        screen = gtk_window_get_screen (GTK_WINDOW (dialog->run_dialog));
 
1805
 
 
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,
 
1810
                      NULL);
 
1811
 
 
1812
        g_signal_connect (entry, "key-press-event",
 
1813
                          G_CALLBACK (entry_event), dialog);
 
1814
                          
 
1815
        dialog->changed_id = g_signal_connect (dialog->combobox, "changed",
 
1816
                                               G_CALLBACK (combobox_changed),
 
1817
                                               dialog);
 
1818
 
 
1819
        gtk_drag_dest_unset (dialog->combobox);
 
1820
        
 
1821
        gtk_drag_dest_set (dialog->combobox,
 
1822
                           GTK_DEST_DEFAULT_MOTION|GTK_DEST_DEFAULT_HIGHLIGHT,
 
1823
                           NULL, 0,
 
1824
                           GDK_ACTION_COPY);
 
1825
        gtk_drag_dest_add_uri_targets (dialog->combobox);
 
1826
 
 
1827
        g_signal_connect (dialog->combobox, "drag_data_received",
 
1828
                          G_CALLBACK (entry_drag_data_received), dialog);
 
1829
}
 
1830
 
 
1831
static char *
 
1832
panel_run_dialog_create_desktop_file (PanelRunDialog *dialog)
 
1833
{
 
1834
        GKeyFile *key_file;
 
1835
        gboolean  exec = FALSE;
 
1836
        char     *text;
 
1837
        char     *name;
 
1838
        char     *icon;
 
1839
        char     *disk;
 
1840
        char     *scheme;
 
1841
        char     *save_uri;
 
1842
 
 
1843
        text = g_strdup (panel_run_dialog_get_combo_text (dialog));
 
1844
        
 
1845
        if (!text || !text [0]) {
 
1846
                g_free (text);
 
1847
                return NULL;
 
1848
        }
 
1849
                
 
1850
        key_file = panel_key_file_new_desktop ();
 
1851
        disk = g_locale_from_utf8 (text, -1, NULL, NULL, NULL);
 
1852
 
 
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);
 
1857
        g_free (scheme);
 
1858
                
 
1859
        if (exec) {
 
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);
 
1863
        } else {
 
1864
                GFile *file;
 
1865
                char  *uri;
 
1866
 
 
1867
                file = panel_util_get_file_optional_homedir (disk);
 
1868
                uri = g_file_get_uri (file);
 
1869
                g_object_unref (file);
 
1870
 
 
1871
                panel_key_file_set_string (key_file, "Type", "Link");
 
1872
                panel_key_file_set_string (key_file, "URL", uri);
 
1873
                name = uri;
 
1874
        }
 
1875
 
 
1876
        g_free (disk);
 
1877
 
 
1878
        panel_key_file_set_locale_string (key_file, "Name",
 
1879
                                          (dialog->item_name) ?
 
1880
                                          dialog->item_name : text);
 
1881
 
 
1882
        panel_key_file_set_boolean (key_file, "Terminal",
 
1883
                                    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->terminal_checkbox)));
 
1884
 
 
1885
        icon = NULL;
 
1886
        if (dialog->gicon)
 
1887
                icon = panel_util_get_icon_name_from_g_icon (dialog->gicon);
 
1888
        if (icon != NULL) {
 
1889
                panel_key_file_set_locale_string (key_file, "Icon",
 
1890
                                                  icon);
 
1891
                g_free (icon);
 
1892
        } else
 
1893
                panel_key_file_set_locale_string (key_file, "Icon",
 
1894
                                                  PANEL_ICON_LAUNCHER);
 
1895
 
 
1896
        save_uri = panel_make_unique_desktop_uri (g_get_tmp_dir (), name);
 
1897
        disk = g_filename_from_uri (save_uri, NULL, NULL);
 
1898
 
 
1899
        if (!disk || !panel_key_file_to_file (key_file, disk, NULL)) {
 
1900
                g_free (save_uri);
 
1901
                save_uri = NULL;
 
1902
        }
 
1903
 
 
1904
        g_key_file_free (key_file);
 
1905
        g_free (disk);
 
1906
        g_free (name);
 
1907
        g_free (text);
 
1908
 
 
1909
        return save_uri;
 
1910
}
 
1911
 
 
1912
static void
 
1913
pixmap_drag_data_get (GtkWidget          *run_dialog,
 
1914
                      GdkDragContext     *context,
 
1915
                      GtkSelectionData   *selection_data,
 
1916
                      guint               info,
 
1917
                      guint               time,
 
1918
                      PanelRunDialog     *dialog)
 
1919
{
 
1920
        char *uri;
 
1921
 
 
1922
        if (dialog->use_program_list && dialog->desktop_path)
 
1923
                uri = g_filename_to_uri (dialog->desktop_path, NULL, NULL);
 
1924
        else
 
1925
                uri = panel_run_dialog_create_desktop_file (dialog);
 
1926
 
 
1927
        if (uri) {
 
1928
                gtk_selection_data_set (selection_data,
 
1929
                                        gtk_selection_data_get_target (selection_data), 8,
 
1930
                                        (unsigned char *) uri, strlen (uri));
 
1931
                g_free (uri);
 
1932
        }
 
1933
}
 
1934
 
 
1935
static void
 
1936
panel_run_dialog_setup_pixmap (PanelRunDialog *dialog,
 
1937
                               GtkBuilder     *gui)
 
1938
{
 
1939
        dialog->pixmap = PANEL_GTK_BUILDER_GET (gui, "icon_pixmap");
 
1940
        
 
1941
        g_signal_connect (dialog->run_dialog, "drag_data_get",
 
1942
                          G_CALLBACK (pixmap_drag_data_get),
 
1943
                          dialog);
 
1944
}
 
1945
 
 
1946
static PanelRunDialog *
 
1947
panel_run_dialog_new (GdkScreen  *screen,
 
1948
                      GtkBuilder *gui,
 
1949
                      guint32    activate_time)
 
1950
{
 
1951
        PanelRunDialog *dialog;
 
1952
 
 
1953
        dialog = g_new0 (PanelRunDialog, 1);
 
1954
 
 
1955
        dialog->run_dialog = PANEL_GTK_BUILDER_GET (gui, "panel_run_dialog");
 
1956
 
 
1957
        dialog->run_settings = g_settings_new (PANEL_RUN_SCHEMA);
 
1958
        
 
1959
        g_signal_connect_swapped (dialog->run_dialog, "response",
 
1960
                                  G_CALLBACK (panel_run_dialog_response), dialog);
 
1961
                                  
 
1962
        g_signal_connect_swapped (dialog->run_dialog, "destroy",
 
1963
                                  G_CALLBACK (panel_run_dialog_destroy), dialog);
 
1964
 
 
1965
        dialog->run_button = PANEL_GTK_BUILDER_GET (gui, "run_button");
 
1966
        dialog->terminal_checkbox = PANEL_GTK_BUILDER_GET (gui, "terminal_checkbox");
 
1967
        
 
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);
 
1973
 
 
1974
        gtk_window_set_icon_name (GTK_WINDOW (dialog->run_dialog),
 
1975
                                  PANEL_ICON_RUN);
 
1976
        panel_run_dialog_set_default_icon (dialog, FALSE);
 
1977
 
 
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);
 
1982
 
 
1983
        panel_run_dialog_update_program_list (dialog->run_settings, NULL, dialog);
 
1984
 
 
1985
        gtk_widget_set_sensitive (dialog->run_button, FALSE);
 
1986
        
 
1987
        gtk_dialog_set_default_response (GTK_DIALOG (dialog->run_dialog),
 
1988
                                         GTK_RESPONSE_OK);
 
1989
 
 
1990
        gtk_window_set_screen (GTK_WINDOW (dialog->run_dialog), screen);
 
1991
 
 
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),
 
1995
                                      activate_time);
 
1996
        gtk_widget_show (dialog->run_dialog);
 
1997
        
 
1998
        return dialog;
 
1999
}
 
2000
 
 
2001
static void
 
2002
panel_run_dialog_static_dialog_destroyed (PanelRunDialog *dialog)
 
2003
{
 
2004
        /* just reset the static dialog to NULL for next time */
 
2005
        static_dialog = NULL;
 
2006
}
 
2007
 
 
2008
void
 
2009
panel_run_dialog_present (GdkScreen *screen,
 
2010
                          guint32    activate_time)
 
2011
{
 
2012
        GtkBuilder *gui;
 
2013
 
 
2014
        if (panel_lockdown_get_disable_command_line_s ())
 
2015
                return;
 
2016
 
 
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),
 
2020
                                              activate_time);
 
2021
                gtk_widget_grab_focus (static_dialog->combobox);
 
2022
                return;
 
2023
        }
 
2024
 
 
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",
 
2029
                                       NULL);
 
2030
 
 
2031
        static_dialog = panel_run_dialog_new (screen, gui, activate_time);
 
2032
 
 
2033
        g_signal_connect_swapped (static_dialog->run_dialog, "destroy",
 
2034
                                  G_CALLBACK (panel_run_dialog_static_dialog_destroyed),
 
2035
                                  static_dialog);
 
2036
 
 
2037
        g_object_unref (gui);
 
2038
}