~ubuntu-branches/ubuntu/dapper/xfce-mcs-plugins/dapper

« back to all changes in this revision

Viewing changes to plugins/keyboard_plugin/shortcuts_plugin.c

  • Committer: Bazaar Package Importer
  • Author(s): Jani Monoses
  • Date: 2006-04-11 17:40:35 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20060411174035-4y90hf4358m65r1k
Tags: 4.3.0svn+r20838-0ubuntu1
Upstream svn snapshot (merge keyboard and shortcut plugins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $Id: shortcuts_plugin.c 20800 2006-04-07 22:18:46Z olivier $
 
2
 *
 
3
 * Copyright (c) 2006 Jean-Francois Wauthy <pollux@xfce.org>
 
4
 *                    Olivier Fourdan <fourdan@xfce.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 * 
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU Library 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 02111-1307, USA.
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#ifdef HAVE_STDLIB_H
 
26
#include <stdlib.h>
 
27
#endif
 
28
 
 
29
#ifdef HAVE_STRING_H
 
30
#include <string.h>
 
31
#endif
 
32
 
 
33
#include <sys/types.h>
 
34
#include <sys/stat.h>
 
35
#include <unistd.h>
 
36
 
 
37
#include <X11/Xlib.h>
 
38
#include <X11/keysym.h>
 
39
 
 
40
#include <gdk/gdkkeysyms.h>
 
41
#include <gtk/gtk.h>
 
42
#include <libxfce4mcs/mcs-manager.h>
 
43
#include <libxfce4util/libxfce4util.h>
 
44
#include <libxfcegui4/libxfcegui4.h>
 
45
#include <xfce-mcs-manager/manager-plugin.h>
 
46
 
 
47
#include "keys_management.h"
 
48
#include "shortcuts_plugin.h"
 
49
 
 
50
/* */
 
51
#define DEFAULT_SHORTCUT_THEME "Default"
 
52
#define DEFAULT_SHORTCUTS_PATH PACKAGE_DATADIR"/shortcuts/default.xml"
 
53
#define BORDER 5
 
54
 
 
55
enum
 
56
{
 
57
    COLUMN_THEME_NAME,
 
58
    COLUMN_FILE_NAME,
 
59
    THEMES_NUM_COLUMNS
 
60
};
 
61
 
 
62
enum
 
63
{
 
64
    COLUMN_COMMAND,
 
65
    COLUMN_SHORTCUT,
 
66
    SHORTCUTS_NUM_COLUMNS
 
67
};
 
68
 
 
69
typedef struct _shortcut_tree_foreach_struct shortcut_tree_foreach_struct;
 
70
struct _shortcut_tree_foreach_struct
 
71
{
 
72
    gchar *shortcut;
 
73
    gchar *path;
 
74
    GtkTreeSelection *selection;
 
75
    gboolean found;
 
76
};
 
77
 
 
78
typedef struct _launcher launcher;
 
79
struct _launcher
 
80
{
 
81
    MyKey *key;
 
82
    gchar *command;
 
83
};
 
84
 
 
85
/* globals */
 
86
static gboolean wait_release = FALSE;
 
87
static GSList *shortcut_list = NULL;
 
88
static gchar *theme_name = NULL;
 
89
static gchar *theme_path = NULL;
 
90
 
 
91
/* static prototypes */
 
92
static void run_dialog (McsPlugin *);
 
93
gboolean shortcuts_plugin_save_settings (McsPlugin *);
 
94
static void cb_browse_command (GtkWidget *, GtkEntry *);
 
95
static gboolean command_exists (const gchar *);
 
96
 
 
97
/****************************/
 
98
/* Low-level events filter  */
 
99
/****************************/
 
100
 
 
101
static void
 
102
handleKeyPress (XKeyPressedEvent * ev)
 
103
{
 
104
    GSList *element;
 
105
    int state;
 
106
 
 
107
    state = ev->state & MODIFIER_MASK;
 
108
 
 
109
    if (wait_release)
 
110
    {
 
111
        return;
 
112
    }
 
113
 
 
114
    for (element = shortcut_list; element != NULL; element = g_slist_next (element))
 
115
    {
 
116
        launcher *shortcut = (launcher *) element->data;
 
117
        if ((shortcut->key->keycode == ev->keycode) && (shortcut->key->modifier == state))
 
118
        {
 
119
            GError *error = NULL;
 
120
            GdkDisplay *gdisplay;
 
121
            GdkScreen *gscr;
 
122
            gint monitor;
 
123
            
 
124
            /* We must wait for a release event before te trigger another key press */
 
125
            wait_release = TRUE;
 
126
            gdisplay = gdk_display_get_default ();
 
127
            gscr = xfce_gdk_display_locate_monitor_with_pointer (gdisplay, &monitor);
 
128
            
 
129
            if (!xfce_gdk_spawn_command_line_on_screen (gscr, shortcut->command, &error))
 
130
            {
 
131
                if (error)
 
132
                {
 
133
                    g_warning ("%s", error->message);
 
134
                    g_error_free (error);
 
135
                }
 
136
            }
 
137
            return;
 
138
        }
 
139
    }
 
140
}
 
141
 
 
142
static void
 
143
handleKeyRelease (XKeyReleasedEvent * ev)
 
144
{
 
145
    wait_release = FALSE;
 
146
}
 
147
 
 
148
static void
 
149
handleMappingNotify (XMappingEvent * ev)
 
150
{
 
151
    GSList *element;
 
152
 
 
153
    /* Clear up the flag as the keyboard mapping changes, we may never receive the release event */
 
154
    wait_release = FALSE;
 
155
 
 
156
    /* Refreshes the stored modifier and keymap information */
 
157
    XRefreshKeyboardMapping (ev);
 
158
 
 
159
    /* Update internal modifiers masks if necessary */
 
160
    if (ev->request == MappingModifier)
 
161
    {
 
162
        init_modifiers ();
 
163
    }
 
164
 
 
165
    /* Regrab all keys if the notify is for keyboard (ie not pointer) */
 
166
    if (ev->request != MappingPointer)
 
167
    {
 
168
        for (element = shortcut_list; element != NULL; element = g_slist_next (element))
 
169
        {
 
170
            launcher *shortcut = (launcher *) element->data;
 
171
            ungrab_key (shortcut->key);
 
172
            grab_key (shortcut->key);
 
173
        }
 
174
    }
 
175
}
 
176
 
 
177
static void
 
178
handle_event (XEvent * ev)
 
179
{
 
180
    switch (ev->type)
 
181
    {
 
182
        case KeyPress:
 
183
            handleKeyPress ((XKeyPressedEvent *) ev);
 
184
            break;
 
185
        case KeyRelease:
 
186
            handleKeyRelease ((XKeyReleasedEvent *) ev);
 
187
            break;
 
188
        case MappingNotify:
 
189
            handleMappingNotify ((XMappingEvent *) ev);
 
190
            break;
 
191
        default:
 
192
            break;
 
193
    }
 
194
}
 
195
 
 
196
static XfceFilterStatus
 
197
event_filter (XEvent * xevent, gpointer data)
 
198
{
 
199
    handle_event (xevent);
 
200
    return XEV_FILTER_STOP;
 
201
}
 
202
 
 
203
void
 
204
add_event_listener (void)
 
205
{
 
206
    GdkScreen *gscr;
 
207
    GdkDisplay *gdisplay;
 
208
    GdkWindow *event_win;
 
209
    GtkWidget *gtk_win;
 
210
    XfceFilterSetup *xfilter;
 
211
 
 
212
    gdisplay = gdk_display_get_default ();
 
213
    gscr = gdk_display_get_default_screen (gdisplay);
 
214
 
 
215
    gtk_win = gtk_window_new (GTK_WINDOW_POPUP);
 
216
    gtk_window_set_screen (GTK_WINDOW (gtk_win), gscr);
 
217
    gtk_window_resize (GTK_WINDOW (gtk_win), 5, 5);
 
218
    gtk_window_move (GTK_WINDOW (gtk_win), -1000, -1000);
 
219
    gtk_widget_show (GTK_WIDGET (gtk_win));
 
220
 
 
221
    XAllowEvents (GDK_DISPLAY_XDISPLAY (gdisplay), AsyncBoth, CurrentTime);
 
222
    event_win = xfce_add_event_win (gscr, KeyPressMask | KeyReleaseMask);
 
223
    gdk_window_set_user_data (event_win, gtk_win);
 
224
 
 
225
    xfilter = xfce_init_event_filter (NULL);
 
226
    xfce_push_event_filter (xfilter, event_filter, (gpointer) NULL);
 
227
}
 
228
 
 
229
static void
 
230
free_launcher_data (launcher * shortcut)
 
231
{
 
232
    ungrab_key (shortcut->key);
 
233
    g_free (shortcut->key);
 
234
    g_free (shortcut->command);
 
235
}
 
236
 
 
237
static void
 
238
free_shortcut_list (void)
 
239
{
 
240
    GSList *element;
 
241
 
 
242
    for (element = shortcut_list; element != NULL; element = g_slist_next (element))
 
243
    {
 
244
        launcher *launcher_data = (launcher *) element->data;
 
245
        free_launcher_data (launcher_data);
 
246
        g_free (launcher_data);
 
247
    }
 
248
 
 
249
    g_slist_free (shortcut_list);
 
250
    shortcut_list = NULL;
 
251
}
 
252
 
 
253
static GSList *
 
254
search_key_in_shortcut_list (gchar * key_string)
 
255
{
 
256
    GSList *element;
 
257
    MyKey *key;
 
258
 
 
259
    key = parseKeyString (key_string);
 
260
 
 
261
    for (element = shortcut_list; element != NULL; element = g_slist_next (element))
 
262
    {
 
263
        launcher *shortcut = (launcher *) element->data;
 
264
 
 
265
        if ((shortcut->key->keycode == key->keycode) && (shortcut->key->modifier == key->modifier))
 
266
        {
 
267
            g_free (key);
 
268
            return (element);
 
269
        }
 
270
    }
 
271
 
 
272
    g_free (key);
 
273
    return (NULL);
 
274
}
 
275
 
 
276
/*********************/
 
277
/* Parsing functions */
 
278
/*********************/
 
279
struct ShortcutsFileParserState
 
280
{
 
281
    gboolean started;
 
282
    GtkWidget *treeview;
 
283
    GQueue *parents;
 
284
    gchar *theme_name;
 
285
};
 
286
 
 
287
static gint
 
288
_find_attribute (const gchar ** attribute_names, const gchar * attr)
 
289
{
 
290
    gint i;
 
291
 
 
292
    for (i = 0; attribute_names[i]; i++)
 
293
    {
 
294
        if (!strcmp (attribute_names[i], attr))
 
295
            return i;
 
296
    }
 
297
 
 
298
    return -1;
 
299
}
 
300
 
 
301
/* functions used to extract the theme name */
 
302
static void
 
303
get_theme_name_start (GMarkupParseContext * context, const gchar * element_name,
 
304
    const gchar ** attribute_names, const gchar ** attribute_values, gpointer user_data, GError ** error)
 
305
{
 
306
    struct ShortcutsFileParserState *state = user_data;
 
307
 
 
308
    if (!state->started && !strcmp (element_name, "shortcuts-theme"))
 
309
    {
 
310
        int i;
 
311
 
 
312
        state->started = TRUE;
 
313
        if ((i = _find_attribute (attribute_names, "name")) != -1)
 
314
            state->theme_name = g_strdup (attribute_values[i]);
 
315
 
 
316
    }
 
317
    else if (!state->started)
 
318
        return;
 
319
}
 
320
 
 
321
static void
 
322
get_theme_name_end (GMarkupParseContext * context, const gchar * element_name, gpointer user_data, GError ** error)
 
323
{
 
324
    struct ShortcutsFileParserState *state = user_data;
 
325
 
 
326
    if (!strcmp (element_name, "shortcuts-theme"))
 
327
        state->started = FALSE;
 
328
}
 
329
 
 
330
static gchar *
 
331
get_theme_name (const gchar * filename)
 
332
{
 
333
    gchar *theme_name = NULL;
 
334
    gchar *file_contents = NULL;
 
335
    GMarkupParseContext *gpcontext = NULL;
 
336
    struct stat st;
 
337
    struct ShortcutsFileParserState state = { FALSE, NULL, NULL, NULL };
 
338
    GMarkupParser gmparser = { get_theme_name_start, get_theme_name_end, NULL, NULL, NULL };
 
339
    GError *err = NULL;
 
340
#ifdef HAVE_MMAP
 
341
    gint fd = -1;
 
342
    void *maddr = NULL;
 
343
#endif
 
344
 
 
345
    g_return_val_if_fail ( filename != NULL, NULL);
 
346
 
 
347
    if (stat (filename, &st) < 0)
 
348
    {
 
349
        g_warning ("Unable to open the shortcuts definitions file\n");
 
350
        goto cleanup;
 
351
    }
 
352
 
 
353
#ifdef HAVE_MMAP
 
354
    fd = open (filename, O_RDONLY, 0);
 
355
    if (fd < 0)
 
356
        goto cleanup;
 
357
 
 
358
    maddr = mmap (NULL, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
 
359
    if (maddr)
 
360
        file_contents = maddr;
 
361
#endif
 
362
 
 
363
    if (!file_contents && !g_file_get_contents (filename, &file_contents, NULL, &err))
 
364
    {
 
365
        if (err)
 
366
        {
 
367
            g_warning ("Unable to read file '%s' (%d): %s\n", filename, err->code, err->message);
 
368
            g_error_free (err);
 
369
        }
 
370
        goto cleanup;
 
371
    }
 
372
 
 
373
    state.started = FALSE;
 
374
    state.parents = g_queue_new ();
 
375
 
 
376
    gpcontext = g_markup_parse_context_new (&gmparser, 0, &state, NULL);
 
377
 
 
378
    if (!g_markup_parse_context_parse (gpcontext, file_contents, st.st_size, &err))
 
379
    {
 
380
        g_warning ("Error parsing shortcuts definitions (%d): %s\n", err->code, err->message);
 
381
        g_error_free (err);
 
382
        goto cleanup;
 
383
    }
 
384
 
 
385
    if (g_markup_parse_context_end_parse (gpcontext, NULL))
 
386
        theme_name = g_strdup (state.theme_name);
 
387
 
 
388
  cleanup:
 
389
    if (gpcontext)
 
390
        g_markup_parse_context_free (gpcontext);
 
391
#ifdef HAVE_MMAP
 
392
    if (maddr)
 
393
    {
 
394
        munmap (maddr, st.st_size);
 
395
        file_contents = NULL;
 
396
    }
 
397
    if (fd > -1)
 
398
        close (fd);
 
399
#endif
 
400
    if (file_contents)
 
401
        free (file_contents);
 
402
    if (state.parents)
 
403
    {
 
404
        g_queue_foreach (state.parents, (GFunc) g_free, NULL);
 
405
        g_queue_free (state.parents);
 
406
    }
 
407
    if (state.theme_name)
 
408
        g_free (state.theme_name);
 
409
 
 
410
    return theme_name;
 
411
}
 
412
 
 
413
/* functions used to extract the theme name */
 
414
static void
 
415
parse_theme_start (GMarkupParseContext * context, const gchar * element_name,
 
416
    const gchar ** attribute_names, const gchar ** attribute_values, gpointer user_data, GError ** error)
 
417
{
 
418
    struct ShortcutsFileParserState *state = user_data;
 
419
    int i, j;
 
420
 
 
421
    if (!state->started && !strcmp (element_name, "shortcuts-theme"))
 
422
    {
 
423
        state->started = TRUE;
 
424
    }
 
425
    else if (!state->started)
 
426
        return;
 
427
 
 
428
    i = _find_attribute (attribute_names, "keys");
 
429
    j = _find_attribute (attribute_names, "command");
 
430
 
 
431
    if (!strcmp (element_name, "shortcut") && (i != -1) && (j != -1))
 
432
    {
 
433
 
 
434
        if (state->treeview)
 
435
        {
 
436
            GtkTreeIter iter;
 
437
            GtkTreeModel *model;
 
438
 
 
439
            model = gtk_tree_view_get_model (GTK_TREE_VIEW (state->treeview));
 
440
            gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
 
441
            gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
442
                                COLUMN_COMMAND, attribute_values[j], 
 
443
                                COLUMN_SHORTCUT, attribute_values[i] ? attribute_values[i] : "", -1);
 
444
        }
 
445
        
 
446
        if (attribute_values[i])
 
447
        {
 
448
            launcher *shortcut;
 
449
 
 
450
            shortcut = g_new (launcher, 1);
 
451
            shortcut->key = parseKeyString ((gchar *) attribute_values[i]);
 
452
            shortcut->command = g_strdup ((gchar *) attribute_values[j]);
 
453
            grab_key (shortcut->key);
 
454
 
 
455
            shortcut_list = g_slist_append (shortcut_list, shortcut);
 
456
        }
 
457
    }
 
458
}
 
459
 
 
460
static void
 
461
parse_theme_end (GMarkupParseContext * context, const gchar * element_name, gpointer user_data, GError ** error)
 
462
{
 
463
    struct ShortcutsFileParserState *state = user_data;
 
464
 
 
465
    if (!strcmp (element_name, "shortcuts-theme"))
 
466
        state->started = FALSE;
 
467
}
 
468
 
 
469
static gboolean
 
470
parse_theme (const gchar * filename, KeyboardMcsDialog * dialog)
 
471
{
 
472
    gboolean ret = FALSE;
 
473
    GtkTreeModel *model;
 
474
    gchar *file_contents = NULL;
 
475
    GMarkupParseContext *gpcontext = NULL;
 
476
    struct stat st;
 
477
    struct ShortcutsFileParserState state = { FALSE, NULL, NULL, NULL };
 
478
    GMarkupParser gmparser = { parse_theme_start, parse_theme_end, NULL, NULL, NULL };
 
479
    GError *err = NULL;
 
480
#ifdef HAVE_MMAP
 
481
    gint fd = -1;
 
482
    void *maddr = NULL;
 
483
#endif
 
484
 
 
485
    g_return_val_if_fail ((filename != NULL), FALSE);
 
486
 
 
487
    if (stat (filename, &st) < 0)
 
488
    {
 
489
        g_warning ("Unable to open the shortcuts definitions file\n");
 
490
        goto cleanup;
 
491
    }
 
492
 
 
493
#ifdef HAVE_MMAP
 
494
    fd = open (filename, O_RDONLY, 0);
 
495
    if (fd < 0)
 
496
        goto cleanup;
 
497
 
 
498
    maddr = mmap (NULL, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
 
499
    if (maddr)
 
500
        file_contents = maddr;
 
501
#endif
 
502
 
 
503
    if (!file_contents && !g_file_get_contents (filename, &file_contents, NULL, &err))
 
504
    {
 
505
        if (err)
 
506
        {
 
507
            g_warning ("Unable to read file '%s' (%d): %s\n", filename, err->code, err->message);
 
508
            g_error_free (err);
 
509
        }
 
510
        goto cleanup;
 
511
    }
 
512
 
 
513
    state.started = FALSE;
 
514
    state.parents = g_queue_new ();
 
515
    if (dialog)
 
516
    {
 
517
        state.treeview = dialog->treeview_shortcuts;
 
518
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (state.treeview));
 
519
        gtk_list_store_clear (GTK_LIST_STORE (model));
 
520
    }
 
521
    else
 
522
    {
 
523
        state.treeview = NULL;
 
524
    }
 
525
        
 
526
 
 
527
    if (shortcut_list)
 
528
        free_shortcut_list ();
 
529
 
 
530
    gpcontext = g_markup_parse_context_new (&gmparser, 0, &state, NULL);
 
531
 
 
532
    if (!g_markup_parse_context_parse (gpcontext, file_contents, st.st_size, &err))
 
533
    {
 
534
        g_warning ("Error parsing shortcuts definitions (%d): %s\n", err->code, err->message);
 
535
        g_error_free (err);
 
536
        goto cleanup;
 
537
    }
 
538
 
 
539
    if (g_markup_parse_context_end_parse (gpcontext, NULL))
 
540
    {
 
541
        if (dialog)
 
542
            dialog->theme_modified = FALSE;
 
543
        ret = TRUE;
 
544
    }
 
545
 
 
546
  cleanup:
 
547
    if (gpcontext)
 
548
        g_markup_parse_context_free (gpcontext);
 
549
#ifdef HAVE_MMAP
 
550
    if (maddr)
 
551
    {
 
552
        munmap (maddr, st.st_size);
 
553
        file_contents = NULL;
 
554
    }
 
555
    if (fd > -1)
 
556
        close (fd);
 
557
#endif
 
558
    if (file_contents)
 
559
        free (file_contents);
 
560
    if (state.parents)
 
561
    {
 
562
        g_queue_foreach (state.parents, (GFunc) g_free, NULL);
 
563
        g_queue_free (state.parents);
 
564
    }
 
565
    if (state.theme_name)
 
566
        g_free (state.theme_name);
 
567
 
 
568
    return ret;
 
569
}
 
570
 
 
571
static gboolean
 
572
save_theme_foreach_func (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
 
573
{
 
574
    gchar *command;
 
575
    gchar *shortcut;
 
576
    FILE *file_theme;
 
577
 
 
578
    gtk_tree_model_get (model, iter, COLUMN_COMMAND, &command, COLUMN_SHORTCUT, &shortcut, -1);
 
579
 
 
580
    file_theme = (FILE *) data;
 
581
 
 
582
    fprintf (file_theme, "\t<shortcut command=\"%s\" keys=\"%s\"/>\n", command, shortcut ? shortcut : "");
 
583
 
 
584
    g_free (command);
 
585
    g_free (shortcut);
 
586
 
 
587
    return FALSE;
 
588
}
 
589
 
 
590
void
 
591
shortcuts_plugin_save_theme (KeyboardMcsDialog * dialog)
 
592
{
 
593
    GtkTreeModel *model;
 
594
    FILE *file_theme;
 
595
 
 
596
    g_return_if_fail (dialog != NULL);
 
597
 
 
598
    file_theme = fopen (theme_path, "w+");
 
599
 
 
600
    fprintf (file_theme, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
601
    fprintf (file_theme, "<shortcuts-theme name=\"%s\">\n", theme_name);
 
602
 
 
603
    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_shortcuts));
 
604
    gtk_tree_model_foreach (model, &save_theme_foreach_func, file_theme);
 
605
 
 
606
    fprintf (file_theme, "</shortcuts-theme>\n");
 
607
 
 
608
    dialog->theme_modified = FALSE;
 
609
 
 
610
    fclose (file_theme);
 
611
}
 
612
 
 
613
/********************/
 
614
/* Plugin internals */
 
615
/********************/
 
616
static gint
 
617
themes_sort_func (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data)
 
618
{
 
619
    gchar *a_str = NULL;
 
620
    gchar *b_str = NULL;
 
621
    gint result;
 
622
 
 
623
    gtk_tree_model_get (model, a, 0, &a_str, -1);
 
624
    gtk_tree_model_get (model, b, 0, &b_str, -1);
 
625
 
 
626
    if (a_str == NULL)
 
627
        a_str = g_strdup ("");
 
628
    if (b_str == NULL)
 
629
        b_str = g_strdup ("");
 
630
 
 
631
    result = g_utf8_collate (a_str, b_str);
 
632
 
 
633
    g_free (a_str);
 
634
    g_free (b_str);
 
635
 
 
636
    return result;
 
637
}
 
638
 
 
639
static gint
 
640
shortcuts_sort_func (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data)
 
641
{
 
642
    gchar *a_str = NULL;
 
643
    gchar *b_str = NULL;
 
644
    gint result;
 
645
 
 
646
    gtk_tree_model_get (model, a, 0, &a_str, -1);
 
647
    gtk_tree_model_get (model, b, 0, &b_str, -1);
 
648
 
 
649
    if (a_str == NULL)
 
650
        a_str = g_strdup ("");
 
651
    if (b_str == NULL)
 
652
        b_str = g_strdup ("");
 
653
 
 
654
    result = g_utf8_collate (a_str, b_str);
 
655
 
 
656
    g_free (a_str);
 
657
    g_free (b_str);
 
658
 
 
659
    return result;
 
660
}
 
661
 
 
662
void shortcuts_plugin_response (gint response_id, KeyboardMcsDialog* status)
 
663
{
 
664
    if(response_id == GTK_RESPONSE_HELP)
 
665
    {
 
666
        g_message("HELP: TBD");
 
667
        return;
 
668
    }
 
669
 
 
670
    /*gtk_widget_destroy (dialog);*/
 
671
}
 
672
 
 
673
static void
 
674
update_themes_list (KeyboardMcsDialog * dialog)
 
675
{
 
676
    GtkTreeModel *model;
 
677
    gchar *path;
 
678
    const gchar *filename;
 
679
    GtkTreeIter iter;
 
680
    GtkTreeRowReference *row_ref = NULL;
 
681
 
 
682
    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_shortcuts));
 
683
    gtk_list_store_clear (GTK_LIST_STORE (model));
 
684
    model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_themes));
 
685
    gtk_list_store_clear (GTK_LIST_STORE (model));
 
686
 
 
687
    /* Default system theme first */
 
688
    gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
 
689
    gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_THEME_NAME, DEFAULT_SHORTCUT_THEME, 
 
690
                                                       COLUMN_FILE_NAME, DEFAULT_SHORTCUTS_PATH, -1);
 
691
    if (strcmp(DEFAULT_SHORTCUT_THEME, theme_name) == 0)
 
692
    {
 
693
        GtkTreePath *tree_path = gtk_tree_model_get_path(model, &iter);
 
694
        row_ref = gtk_tree_row_reference_new(model, tree_path);
 
695
        gtk_tree_path_free(tree_path);
 
696
    }
 
697
 
 
698
    path = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, "xfce4/shortcuts/");
 
699
 
 
700
    if (path)
 
701
    {
 
702
        GDir *dir_shortcuts;
 
703
 
 
704
        dir_shortcuts = g_dir_open (path, 0, NULL);
 
705
 
 
706
        while ((filename = g_dir_read_name (dir_shortcuts)))
 
707
        {
 
708
            if (g_str_has_suffix (filename, ".xml"))
 
709
            {
 
710
                gchar *full_path;
 
711
                gchar *theme;
 
712
 
 
713
                full_path = g_build_filename (path, filename, NULL);
 
714
 
 
715
                theme = get_theme_name (full_path);
 
716
 
 
717
                if (theme)
 
718
                {
 
719
                    gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
 
720
                    gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_THEME_NAME, theme, 
 
721
                                                                       COLUMN_FILE_NAME, full_path, -1);
 
722
 
 
723
                    if(strcmp(theme, theme_name) == 0)
 
724
                    {
 
725
                        GtkTreePath *tree_path = gtk_tree_model_get_path(model, &iter);
 
726
                        row_ref = gtk_tree_row_reference_new(model, tree_path);
 
727
                        gtk_tree_path_free(tree_path);
 
728
                    }
 
729
                }
 
730
                else
 
731
                    g_warning ("Error while loading themes : %s has no name", full_path);
 
732
 
 
733
                g_free (full_path);
 
734
                g_free (theme);
 
735
            }
 
736
        }
 
737
    }
 
738
 
 
739
    if(row_ref)
 
740
    {
 
741
        GtkTreePath *tree_path;
 
742
 
 
743
        tree_path = gtk_tree_row_reference_get_path(row_ref);
 
744
        gtk_tree_view_set_cursor(GTK_TREE_VIEW (dialog->treeview_themes), tree_path, NULL, FALSE);
 
745
 
 
746
        gtk_tree_path_free(tree_path);
 
747
        gtk_tree_row_reference_free(row_ref);
 
748
    }
 
749
 
 
750
    g_free (path);
 
751
}
 
752
 
 
753
static void
 
754
dialog_set_sensitive (KeyboardMcsDialog * dialog, gboolean active)
 
755
{
 
756
    gtk_widget_set_sensitive (dialog->button_del_theme, active);
 
757
    gtk_widget_set_sensitive (dialog->button_add_shortcut, active);
 
758
    gtk_widget_set_sensitive (dialog->button_del_shortcut, active);
 
759
    gtk_widget_set_sensitive (dialog->treeview_shortcuts, active);
 
760
    gtk_widget_set_sensitive (dialog->menuitem_popup_rename_theme, active);
 
761
    gtk_widget_set_sensitive (dialog->menuitem_popup_del_theme, active);
 
762
}
 
763
 
 
764
static void
 
765
cb_treeview_themes_selection_changed (GtkTreeSelection * selection, gpointer data)
 
766
{
 
767
    KeyboardMcsDialog *dialog;
 
768
    GtkTreeIter iter;
 
769
    GtkTreeModel *model;
 
770
    McsPlugin *mcs_plugin;
 
771
    gchar *new_theme, *new_path;
 
772
 
 
773
    dialog = (KeyboardMcsDialog *) data;
 
774
    mcs_plugin = dialog->mcs_plugin;
 
775
 
 
776
    if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
777
    {
 
778
        gtk_tree_model_get (model, &iter, COLUMN_THEME_NAME, &new_theme, COLUMN_FILE_NAME, &new_path, -1);
 
779
        dialog_set_sensitive (dialog, strcmp (DEFAULT_SHORTCUT_THEME, new_theme));
 
780
 
 
781
        if (theme_name && strcmp (theme_name, new_theme))
 
782
        {
 
783
            if (g_file_test (new_path, G_FILE_TEST_EXISTS))
 
784
            {
 
785
                /* save the current theme */
 
786
                if (dialog->theme_modified)
 
787
                    shortcuts_plugin_save_theme (dialog);
 
788
 
 
789
                /* update and notify the channel value */
 
790
                g_free (theme_name);
 
791
                g_free (theme_path);
 
792
                theme_name = new_theme;
 
793
                theme_path = new_path;
 
794
                mcs_manager_set_string (mcs_plugin->manager, "Xfce4/ShortcutThemeName", CHANNEL3, new_theme);
 
795
                mcs_manager_set_string (mcs_plugin->manager, "Xfce4/ShortcutThemeFile", CHANNEL3, new_path);
 
796
                mcs_manager_notify (mcs_plugin->manager, CHANNEL3);
 
797
                shortcuts_plugin_save_settings (mcs_plugin);
 
798
 
 
799
                /* load the new theme in the treeview */
 
800
                parse_theme (new_path, dialog);
 
801
            }
 
802
            else
 
803
            {
 
804
                g_warning ("The shortcut theme file doesn't exist !");
 
805
 
 
806
                g_free (new_theme);
 
807
                g_free (new_path);
 
808
                update_themes_list (dialog);
 
809
            }
 
810
        }
 
811
    }
 
812
    else
 
813
    {
 
814
        dialog_set_sensitive (dialog, FALSE);
 
815
    }
 
816
}
 
817
 
 
818
/* theme treeview : popup menu */
 
819
static void
 
820
show_rename_theme_dialog (KeyboardMcsDialog * dialog)
 
821
{
 
822
    GtkWidget *dialog_input;
 
823
    GtkWidget *hbox;
 
824
    GtkWidget *label;
 
825
    GtkWidget *entry;
 
826
 
 
827
    dialog_input = gtk_dialog_new_with_buttons (_("Rename theme"), 
 
828
                                                GTK_WINDOW (gtk_widget_get_toplevel(dialog->dialog_keyboard)),
 
829
                                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, 
 
830
                                                GTK_STOCK_CANCEL, 
 
831
                                                GTK_RESPONSE_REJECT, 
 
832
                                                GTK_STOCK_OK, 
 
833
                                                GTK_RESPONSE_ACCEPT, 
 
834
                                                NULL);
 
835
    gtk_dialog_set_default_response (GTK_DIALOG (dialog_input),
 
836
                                     GTK_RESPONSE_ACCEPT);
 
837
 
 
838
    hbox = gtk_hbox_new (FALSE, BORDER);
 
839
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_input)->vbox), hbox, FALSE, TRUE, BORDER);
 
840
    gtk_widget_show (hbox);
 
841
 
 
842
    label = gtk_label_new (_("New name:"));
 
843
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
844
    gtk_widget_show (label);
 
845
 
 
846
    entry = gtk_entry_new ();
 
847
    gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
 
848
    gtk_entry_set_text (GTK_ENTRY (entry), theme_name);
 
849
    gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
 
850
    gtk_widget_show (entry);
 
851
 
 
852
    if (gtk_dialog_run (GTK_DIALOG (dialog_input)) == GTK_RESPONSE_ACCEPT)
 
853
    {
 
854
        g_free (theme_name);
 
855
        theme_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
 
856
 
 
857
        shortcuts_plugin_save_theme (dialog);
 
858
        update_themes_list (dialog);
 
859
    }
 
860
 
 
861
    gtk_widget_destroy (dialog_input);
 
862
}
 
863
 
 
864
static void
 
865
cb_treeview_themes_activate (GtkWidget * treeview, GtkTreePath * path, GtkTreeViewColumn * column, gpointer data)
 
866
{
 
867
    KeyboardMcsDialog * dialog = (KeyboardMcsDialog *) data;
 
868
    
 
869
    if (strcmp(DEFAULT_SHORTCUT_THEME, theme_name))
 
870
    {
 
871
        show_rename_theme_dialog (dialog);
 
872
    }
 
873
}
 
874
 
 
875
static void
 
876
cb_popup_rename_theme (GtkWidget * widget, gpointer data)
 
877
{
 
878
    KeyboardMcsDialog * dialog = (KeyboardMcsDialog *) data;
 
879
    
 
880
    if (strcmp(DEFAULT_SHORTCUT_THEME, theme_name))
 
881
    {
 
882
        show_rename_theme_dialog (dialog);
 
883
    }
 
884
}
 
885
 
 
886
static void
 
887
show_edit_shortcut_dialog (KeyboardMcsDialog * dialog)
 
888
{
 
889
}
 
890
 
 
891
/* shortcut edition */
 
892
static gboolean
 
893
is_modifier (guint keycode)
 
894
{
 
895
    XModifierKeymap *keymap;
 
896
    gboolean result = FALSE;
 
897
    gint n;
 
898
 
 
899
    keymap = XGetModifierMapping (gdk_display);
 
900
    for (n = 0; n < keymap->max_keypermod * 8; ++n)
 
901
    {
 
902
        if (keycode == keymap->modifiermap[n])
 
903
        {
 
904
            result = TRUE;
 
905
            break;
 
906
        }
 
907
    }
 
908
 
 
909
    XFreeModifiermap (keymap);
 
910
 
 
911
    return result;
 
912
}
 
913
 
 
914
static gboolean
 
915
shortcut_tree_foreach_func (GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data)
 
916
{
 
917
    shortcut_tree_foreach_struct *stfs = (shortcut_tree_foreach_struct *) data;
 
918
    gchar *shortcut_key = stfs->shortcut;
 
919
    gchar *current_shortcut = NULL;
 
920
 
 
921
    gtk_tree_model_get (model, iter, COLUMN_SHORTCUT, &current_shortcut, -1);
 
922
 
 
923
    if (!gtk_tree_selection_path_is_selected (stfs->selection, path) && (strcmp (shortcut_key, current_shortcut) == 0))
 
924
    {
 
925
        stfs->found = TRUE;
 
926
        stfs->path = gtk_tree_path_to_string (path);
 
927
    }
 
928
 
 
929
    g_free (current_shortcut);
 
930
    return stfs->found;
 
931
}
 
932
 
 
933
static gboolean
 
934
cb_compose_shortcut (GtkWidget * widget, GdkEventKey * event, gpointer data)
 
935
{
 
936
    KeyboardMcsDialog *dialog;
 
937
    GdkModifierType consumed_modifiers = 0;
 
938
    gchar shortcut_string[80] = "";
 
939
    guint keyval;
 
940
    gchar *accelerator;
 
941
 
 
942
    gint i;
 
943
    gchar **shortcuts;
 
944
    gchar **current_shortcut;
 
945
    shortcut_tree_foreach_struct stfs;
 
946
 
 
947
    GtkTreeModel *model;
 
948
    GtkTreeSelection *selection;
 
949
    GtkTreeIter iter;
 
950
 
 
951
    GSList *element;
 
952
    gchar *command;
 
953
 
 
954
    if (is_modifier (event->hardware_keycode))
 
955
        return TRUE;
 
956
 
 
957
    dialog = (KeyboardMcsDialog *) data;
 
958
 
 
959
    gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), event->hardware_keycode, event->state, event->group, NULL, NULL, NULL, &consumed_modifiers);
 
960
    keyval = gdk_keyval_to_lower (event->keyval);
 
961
 
 
962
    if (keyval == GDK_ISO_Left_Tab)
 
963
        keyval = GDK_Tab;
 
964
 
 
965
    /* Release keyboard */
 
966
    gdk_keyboard_ungrab (GDK_CURRENT_TIME);
 
967
 
 
968
    accelerator = gtk_accelerator_name (keyval, event->state);
 
969
 
 
970
    for (i = 0; i < strlen (accelerator); i++)
 
971
    {
 
972
        if (accelerator[i] == '>')
 
973
            accelerator[i] = '<';
 
974
    }
 
975
 
 
976
    shortcuts = g_strsplit (accelerator, "<", 0);
 
977
 
 
978
    current_shortcut = shortcuts;
 
979
    while (*current_shortcut)
 
980
    {
 
981
        if (strlen (*current_shortcut) > 0 && (strcmp (*current_shortcut, "Mod2") != 0))
 
982
        {
 
983
            strcat (shortcut_string, *current_shortcut);
 
984
            strcat (shortcut_string, "+");
 
985
        }
 
986
        *current_shortcut++;
 
987
    }
 
988
 
 
989
    shortcut_string[strlen (shortcut_string) - 1] = '\0';       /* replace the trailing '+' */
 
990
    g_free (accelerator);
 
991
    g_strfreev (shortcuts);
 
992
 
 
993
    /* check if shorcut already exists */
 
994
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview_shortcuts));
 
995
    gtk_tree_selection_get_selected (selection, &model, &iter);
 
996
 
 
997
    stfs.shortcut = shortcut_string;
 
998
    stfs.found = FALSE;
 
999
    stfs.selection = selection;
 
1000
    gtk_tree_model_foreach (model, &shortcut_tree_foreach_func, &stfs);
 
1001
 
 
1002
    if (stfs.found)
 
1003
    {
 
1004
        GtkTreePath *path_old;
 
1005
        GtkTreeIter iter_old;
 
1006
        GtkWidget *dialog;
 
1007
 
 
1008
        dialog = gtk_message_dialog_new (GTK_WINDOW (widget),
 
1009
            GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("Shortcut already in use !\nAre you sure you want to use it ?"));
 
1010
 
 
1011
        if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_NO)
 
1012
        {
 
1013
            gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_OK);
 
1014
            return TRUE;
 
1015
        }
 
1016
 
 
1017
        path_old = gtk_tree_path_new_from_string (stfs.path);
 
1018
        gtk_tree_model_get_iter (model, &iter_old, path_old);
 
1019
        g_free (stfs.path);
 
1020
        gtk_tree_path_free (path_old);
 
1021
 
 
1022
        gtk_list_store_set (GTK_LIST_STORE (model), &iter_old, COLUMN_SHORTCUT, "", -1);
 
1023
    }
 
1024
 
 
1025
    gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_SHORTCUT, shortcut_string, -1);
 
1026
 
 
1027
    gtk_tree_model_get (model, &iter, COLUMN_COMMAND, &command, -1);
 
1028
 
 
1029
    if ((element = search_key_in_shortcut_list (shortcut_string)) != NULL)
 
1030
    {
 
1031
        /* Change the command associated with the shortcut */
 
1032
        launcher *launcher_data = (launcher *) element->data;
 
1033
 
 
1034
        free_launcher_data (launcher_data);
 
1035
        launcher_data->key = parseKeyString (shortcut_string);
 
1036
        launcher_data->command = g_strdup (command);
 
1037
        grab_key (launcher_data->key);
 
1038
    }
 
1039
    else
 
1040
    {
 
1041
        /* Add the shortcut to the list */
 
1042
        launcher *launcher_data;
 
1043
 
 
1044
        launcher_data = g_new (launcher, 1);
 
1045
        launcher_data->key = parseKeyString (shortcut_string);
 
1046
        launcher_data->command = g_strdup (command);
 
1047
        grab_key (launcher_data->key);
 
1048
        shortcut_list = g_slist_append (shortcut_list, launcher_data);
 
1049
    }
 
1050
 
 
1051
    g_free (command);
 
1052
 
 
1053
    /* End operations */
 
1054
    dialog->theme_modified = TRUE;
 
1055
    gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_OK);
 
1056
    return TRUE;
 
1057
}
 
1058
 
 
1059
static void
 
1060
cb_treeview_shortcuts_activate (GtkWidget * treeview, GtkTreePath * path, GtkTreeViewColumn * column, gpointer data)
 
1061
{
 
1062
    KeyboardMcsDialog *dialog = (KeyboardMcsDialog *) data;
 
1063
 
 
1064
    if (column == gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), COLUMN_COMMAND))
 
1065
    {
 
1066
        GtkTreeSelection *selection;
 
1067
        GtkTreeModel *model;
 
1068
        GtkTreeIter iter;
 
1069
 
 
1070
        gchar *shortcut = NULL;
 
1071
        gchar *command = NULL;
 
1072
 
 
1073
        GtkWidget *dialog_command;
 
1074
        GtkWidget *label;
 
1075
        GtkWidget *entry;
 
1076
        GtkWidget *img;
 
1077
        GtkWidget *button;
 
1078
        GtkWidget *hbox;
 
1079
        GtkWidget *hbox_entry;
 
1080
 
 
1081
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
1082
        gtk_tree_selection_get_selected (selection, &model, &iter);
 
1083
        gtk_tree_model_get (model, &iter, COLUMN_SHORTCUT, &shortcut, COLUMN_COMMAND, &command, -1);
 
1084
 
 
1085
        /* Create dialog */
 
1086
        dialog_command = gtk_dialog_new_with_buttons (_("Choose command"), 
 
1087
            GTK_WINDOW (gtk_widget_get_toplevel(dialog->dialog_keyboard)),
 
1088
            GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 
1089
        gtk_dialog_set_default_response (GTK_DIALOG (dialog_command),
 
1090
            GTK_RESPONSE_OK);
 
1091
        label = gtk_label_new (_("Command:"));
 
1092
        entry = gtk_entry_new_with_max_length (255);
 
1093
        gtk_entry_set_text (GTK_ENTRY (entry), command);
 
1094
        gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
 
1095
 
 
1096
        hbox_entry = gtk_hbox_new (FALSE, BORDER);
 
1097
        gtk_box_pack_start (GTK_BOX (hbox_entry), entry, FALSE, FALSE, 0);
 
1098
        img = gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
 
1099
        button = gtk_button_new ();
 
1100
        gtk_container_add (GTK_CONTAINER (button), img);
 
1101
        g_signal_connect (G_CALLBACK (button), "clicked", G_CALLBACK (cb_browse_command), entry);
 
1102
        gtk_box_pack_start (GTK_BOX (hbox_entry), button, FALSE, FALSE, 0);
 
1103
 
 
1104
        hbox = gtk_hbox_new (FALSE, BORDER);
 
1105
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
1106
        gtk_box_pack_start (GTK_BOX (hbox), hbox_entry, FALSE, TRUE, 0);
 
1107
        gtk_container_set_border_width (GTK_CONTAINER (hbox), BORDER);
 
1108
 
 
1109
        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_command)->vbox), hbox, FALSE, TRUE, 0);
 
1110
        gtk_widget_show_all (dialog_command);
 
1111
 
 
1112
        if (gtk_dialog_run (GTK_DIALOG (dialog_command)) == GTK_RESPONSE_OK)
 
1113
        {
 
1114
 
 
1115
            if (strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0 && command_exists (gtk_entry_get_text (GTK_ENTRY (entry))))
 
1116
            {
 
1117
                gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_COMMAND, gtk_entry_get_text (GTK_ENTRY (entry)), -1);
 
1118
                dialog->theme_modified = TRUE;
 
1119
            }
 
1120
            else
 
1121
                xfce_err (_("The command doesn't exist or the file is not executable !"));
 
1122
        }
 
1123
 
 
1124
        gtk_widget_destroy (dialog_command);
 
1125
        g_free (shortcut);
 
1126
        g_free (command);
 
1127
    }
 
1128
    else if (column == gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), COLUMN_SHORTCUT))
 
1129
    {
 
1130
        GtkTreeSelection *selection;
 
1131
        GtkTreeModel *model;
 
1132
        GtkTreeIter iter;
 
1133
        gchar *command = NULL;
 
1134
        gchar *shortcut = NULL;
 
1135
        GtkWidget *dialog_compose;
 
1136
        GtkWidget *hbox;
 
1137
        GdkPixbuf *icon = NULL;
 
1138
        GtkWidget *image;
 
1139
        GtkWidget *label;
 
1140
        GtkWidget *button;
 
1141
        GSList *element;
 
1142
        gint response;
 
1143
        gchar *dialog_text = NULL;
 
1144
 
 
1145
        /* Get shortcut name */
 
1146
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
1147
        gtk_tree_selection_get_selected (selection, &model, &iter);
 
1148
        gtk_tree_model_get (model, &iter, COLUMN_COMMAND, &command, COLUMN_SHORTCUT, &shortcut, -1);
 
1149
 
 
1150
        if ((element = search_key_in_shortcut_list (shortcut)))
 
1151
        {
 
1152
            launcher *launcher_data = (launcher *) element->data;
 
1153
 
 
1154
            free_launcher_data (launcher_data);
 
1155
            shortcut_list = g_slist_remove (shortcut_list, launcher_data);
 
1156
            g_free (launcher_data);
 
1157
        }
 
1158
 
 
1159
        dialog_text = g_strdup_printf ("<i>%s</i>\n<b>%s</b>", _("Set shortcut for command:"), command);
 
1160
 
 
1161
        /* Create dialog */
 
1162
        dialog_compose = gtk_dialog_new_with_buttons (_("Set shortcut"), 
 
1163
            GTK_WINDOW (gtk_widget_get_toplevel(dialog->dialog_keyboard)),
 
1164
            GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
 
1165
 
 
1166
        button = xfce_create_mixed_button (GTK_STOCK_CLEAR, _("No shortcut"));
 
1167
        gtk_widget_show (button);
 
1168
        gtk_dialog_add_action_widget (GTK_DIALOG (dialog_compose), button, GTK_RESPONSE_NO);
 
1169
 
 
1170
        hbox = gtk_hbox_new (FALSE, BORDER);
 
1171
        gtk_container_set_border_width (GTK_CONTAINER (hbox), BORDER);
 
1172
        gtk_widget_show (hbox);
 
1173
 
 
1174
        icon = xfce_themed_icon_load ("xfce4-keys.png", 48);
 
1175
        if (icon)
 
1176
        {
 
1177
            image = gtk_image_new_from_pixbuf (icon);
 
1178
            gtk_widget_show (image);
 
1179
            gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
 
1180
        }
 
1181
 
 
1182
        label = gtk_label_new (dialog_text);
 
1183
        gtk_label_set_markup (GTK_LABEL (label), dialog_text);
 
1184
        gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
 
1185
        gtk_widget_show (label);
 
1186
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
1187
 
 
1188
        gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_compose)->vbox), hbox, FALSE, TRUE, 0);
 
1189
 
 
1190
        /* Center cancel button */
 
1191
        gtk_button_box_set_layout (GTK_BUTTON_BOX (GTK_DIALOG (dialog_compose)->action_area), GTK_BUTTONBOX_SPREAD);
 
1192
 
 
1193
        /* Connect signals */
 
1194
        g_signal_connect (G_OBJECT (dialog_compose), "key-release-event", G_CALLBACK (cb_compose_shortcut), dialog);
 
1195
 
 
1196
        /* Take control on the keyboard */
 
1197
        if (gdk_keyboard_grab (gtk_widget_get_root_window (label), TRUE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
 
1198
        {
 
1199
            g_warning ("Cannot grab the keyboard");
 
1200
            g_free (dialog_text);
 
1201
            g_free (shortcut);
 
1202
            g_free (command);
 
1203
            return;
 
1204
        }
 
1205
 
 
1206
        /* Show dialog */
 
1207
        response = gtk_dialog_run (GTK_DIALOG (dialog_compose));
 
1208
 
 
1209
        if (response == GTK_RESPONSE_NO)
 
1210
        {
 
1211
            gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_SHORTCUT, "", -1);
 
1212
            dialog->theme_modified = TRUE;
 
1213
        }
 
1214
 
 
1215
        /* Release keyboard if not yet done */
 
1216
        gdk_keyboard_ungrab (GDK_CURRENT_TIME);
 
1217
 
 
1218
        gtk_widget_destroy (dialog_compose);
 
1219
        g_free (dialog_text);
 
1220
        g_free (command);
 
1221
        g_free (shortcut);
 
1222
    }
 
1223
 
 
1224
}
 
1225
 
 
1226
static void
 
1227
cb_popup_edit_shortcut (GtkWidget * widget, gpointer data)
 
1228
{
 
1229
    show_edit_shortcut_dialog (data);
 
1230
}
 
1231
 
 
1232
static gboolean
 
1233
cb_popup_menu_themes (GtkTreeView * treeview, GdkEventButton * event, gpointer data)
 
1234
{
 
1235
    KeyboardMcsDialog *dialog;
 
1236
 
 
1237
    dialog = (KeyboardMcsDialog *) data;
 
1238
 
 
1239
    /* Right click draws the context menu */
 
1240
    if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS))
 
1241
    {
 
1242
        GtkTreePath *path;
 
1243
        GdkScreen *screen;
 
1244
 
 
1245
        if (gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, NULL, NULL, NULL))
 
1246
        {
 
1247
            GtkTreeSelection *selection;
 
1248
            GtkTreeModel *model;
 
1249
            GtkTreeIter iter;
 
1250
            gchar *theme_name;
 
1251
 
 
1252
            selection = gtk_tree_view_get_selection (treeview);
 
1253
            gtk_tree_selection_unselect_all (selection);
 
1254
            gtk_tree_selection_select_path (selection, path);
 
1255
            gtk_tree_selection_get_selected (selection, &model, &iter);
 
1256
            gtk_tree_model_get (model, &iter, COLUMN_THEME_NAME, &theme_name, -1);
 
1257
            
 
1258
            if (strcmp (DEFAULT_SHORTCUT_THEME, theme_name))
 
1259
            {
 
1260
                gtk_widget_set_sensitive (dialog->menuitem_popup_rename_theme, TRUE);
 
1261
                gtk_widget_set_sensitive (dialog->menuitem_popup_del_theme, TRUE);
 
1262
            }
 
1263
            else
 
1264
            {
 
1265
                gtk_widget_set_sensitive (dialog->menuitem_popup_rename_theme, FALSE);
 
1266
                gtk_widget_set_sensitive (dialog->menuitem_popup_del_theme, FALSE);
 
1267
            }
 
1268
            g_free (theme_name);
 
1269
 
 
1270
        }
 
1271
        else
 
1272
        {
 
1273
            gtk_widget_set_sensitive (dialog->menuitem_popup_rename_theme, FALSE);
 
1274
            gtk_widget_set_sensitive (dialog->menuitem_popup_del_theme, FALSE);
 
1275
        }
 
1276
 
 
1277
        screen = xfce_gdk_display_locate_monitor_with_pointer (NULL, NULL);
 
1278
        gtk_menu_set_screen (GTK_MENU (dialog->menu_popup_themes), screen ? screen : gdk_screen_get_default ());
 
1279
        gtk_menu_popup (GTK_MENU (dialog->menu_popup_themes), NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time ());
 
1280
        return TRUE;
 
1281
    }
 
1282
 
 
1283
    return FALSE;
 
1284
}
 
1285
 
 
1286
/* shortcuts treeview : popup menu */
 
1287
static gboolean
 
1288
cb_popup_menu_shortcuts (GtkTreeView * treeview, GdkEventButton * event, gpointer data)
 
1289
{
 
1290
    KeyboardMcsDialog *dialog;
 
1291
 
 
1292
    dialog = (KeyboardMcsDialog *) data;
 
1293
 
 
1294
    /* Right click draws the context menu */
 
1295
    if ((event->button == 3) && (event->type == GDK_BUTTON_PRESS))
 
1296
    {
 
1297
        GtkTreePath *path;
 
1298
        GdkScreen *screen;
 
1299
 
 
1300
        if (gtk_tree_view_get_path_at_pos (treeview, event->x, event->y, &path, NULL, NULL, NULL))
 
1301
        {
 
1302
            GtkTreeSelection *selection;
 
1303
 
 
1304
            selection = gtk_tree_view_get_selection (treeview);
 
1305
            gtk_tree_selection_unselect_all (selection);
 
1306
            gtk_tree_selection_select_path (selection, path);
 
1307
            gtk_widget_set_sensitive (dialog->menuitem_popup_edit_shortcut, TRUE);
 
1308
            gtk_widget_set_sensitive (dialog->menuitem_popup_del_shortcut, TRUE);
 
1309
        }
 
1310
        else
 
1311
        {
 
1312
            gtk_widget_set_sensitive (dialog->menuitem_popup_edit_shortcut, FALSE);
 
1313
            gtk_widget_set_sensitive (dialog->menuitem_popup_del_shortcut, FALSE);
 
1314
        }
 
1315
 
 
1316
        screen = xfce_gdk_display_locate_monitor_with_pointer (NULL, NULL);
 
1317
        gtk_menu_set_screen (GTK_MENU (dialog->menu_popup_shortcuts), screen ? screen : gdk_screen_get_default ());
 
1318
        gtk_menu_popup (GTK_MENU (dialog->menu_popup_shortcuts), NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time ());
 
1319
        return TRUE;
 
1320
    }
 
1321
 
 
1322
    return FALSE;
 
1323
}
 
1324
 
 
1325
static void
 
1326
add_theme (KeyboardMcsDialog *dialog)
 
1327
{
 
1328
    GtkWidget *dialog_input;
 
1329
    GtkWidget *hbox;
 
1330
    GtkWidget *label;
 
1331
    GtkWidget *entry;
 
1332
    GtkTreeSelection *selection;
 
1333
 
 
1334
    dialog_input = gtk_dialog_new_with_buttons (_("New theme"), 
 
1335
                                                GTK_WINDOW (gtk_widget_get_toplevel(dialog->dialog_keyboard)),
 
1336
                                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, 
 
1337
                                                GTK_STOCK_CANCEL, 
 
1338
                                                GTK_RESPONSE_REJECT, 
 
1339
                                                GTK_STOCK_OK, 
 
1340
                                                GTK_RESPONSE_ACCEPT, 
 
1341
                                                NULL);
 
1342
    gtk_dialog_set_default_response (GTK_DIALOG (dialog_input),
 
1343
                                     GTK_RESPONSE_ACCEPT);
 
1344
    hbox = gtk_hbox_new (FALSE, BORDER);
 
1345
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_input)->vbox), hbox, FALSE, TRUE, BORDER);
 
1346
    gtk_widget_show (hbox);
 
1347
 
 
1348
    label = gtk_label_new (_("Name:"));
 
1349
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
1350
    gtk_widget_show (label);
 
1351
 
 
1352
    entry = gtk_entry_new ();
 
1353
    gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
 
1354
    gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, TRUE, 0);
 
1355
    gtk_widget_show (entry);
 
1356
 
 
1357
    if ((gtk_dialog_run (GTK_DIALOG (dialog_input)) == GTK_RESPONSE_ACCEPT) &&
 
1358
        strcmp(DEFAULT_SHORTCUT_THEME, gtk_entry_get_text (GTK_ENTRY (entry))))
 
1359
    {
 
1360
        gchar *path;
 
1361
        gchar *temp;
 
1362
        gchar *full_path;
 
1363
 
 
1364
        FILE *file_theme;
 
1365
        GtkTreeIter iter;
 
1366
        GtkTreeModel *model;
 
1367
 
 
1368
        path = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, "xfce4/shortcuts/");
 
1369
        temp = g_build_filename (path, gtk_entry_get_text (GTK_ENTRY (entry)), NULL);
 
1370
        full_path = g_strconcat (temp, ".xml", NULL);
 
1371
        g_free (temp);
 
1372
 
 
1373
        while (g_file_test (full_path, G_FILE_TEST_EXISTS))
 
1374
        {
 
1375
            GtkWidget *dialog_filename;
 
1376
            GtkWidget *entry_new_filename;
 
1377
 
 
1378
            xfce_warn ("The file %s already exists, please select an other name.", full_path);
 
1379
            g_free (full_path);
 
1380
 
 
1381
            dialog_filename = gtk_dialog_new_with_buttons (_("File already exists"), 
 
1382
                                                           GTK_WINDOW (gtk_widget_get_toplevel(dialog->dialog_keyboard)),
 
1383
                                                           GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, 
 
1384
                                                           GTK_STOCK_CANCEL, 
 
1385
                                                           GTK_RESPONSE_REJECT, 
 
1386
                                                           GTK_STOCK_OK, 
 
1387
                                                           GTK_RESPONSE_ACCEPT, 
 
1388
                                                           NULL);
 
1389
 
 
1390
            hbox = gtk_hbox_new (FALSE, BORDER);
 
1391
            gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_filename)->vbox), hbox, FALSE, TRUE, BORDER);
 
1392
            gtk_widget_show (hbox);
 
1393
 
 
1394
            label = gtk_label_new (_("Filename:"));
 
1395
            gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
1396
            gtk_widget_show (label);
 
1397
 
 
1398
            entry_new_filename = gtk_entry_new ();
 
1399
            gtk_box_pack_start (GTK_BOX (hbox), entry_new_filename, FALSE, TRUE, 0);
 
1400
            gtk_widget_show (entry_new_filename);
 
1401
 
 
1402
            if (gtk_dialog_run (GTK_DIALOG (dialog_filename)) == GTK_RESPONSE_ACCEPT)
 
1403
            {
 
1404
                temp = g_build_filename (path, gtk_entry_get_text (GTK_ENTRY (entry_new_filename)), NULL);
 
1405
 
 
1406
                if (g_str_has_suffix (temp, ".xml"))
 
1407
                    full_path = g_strdup (temp);
 
1408
                else
 
1409
                    full_path = g_strconcat (temp, ".xml", NULL);
 
1410
 
 
1411
                g_free (temp);
 
1412
            }
 
1413
            else
 
1414
            {
 
1415
                gtk_widget_destroy (dialog_filename);
 
1416
                gtk_widget_destroy (dialog_input);
 
1417
                g_free (path);
 
1418
                return;
 
1419
            }
 
1420
            gtk_widget_destroy (dialog_filename);
 
1421
        }
 
1422
 
 
1423
        if (dialog->theme_modified)
 
1424
            shortcuts_plugin_save_theme (dialog);
 
1425
 
 
1426
        file_theme = fopen (full_path, "w");
 
1427
        fprintf (file_theme, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1428
        fprintf (file_theme, "<shortcuts-theme name=\"%s\">\n", gtk_entry_get_text (GTK_ENTRY (entry)));
 
1429
        fprintf (file_theme, "</shortcuts-theme>\n");
 
1430
        fclose (file_theme);
 
1431
 
 
1432
        model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_themes));
 
1433
        gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
 
1434
        gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_THEME_NAME, gtk_entry_get_text (GTK_ENTRY (entry)), COLUMN_FILE_NAME, full_path, -1);
 
1435
 
 
1436
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview_themes));
 
1437
        gtk_tree_selection_select_iter (selection, &iter);
 
1438
 
 
1439
        g_free (path);
 
1440
        g_free (full_path);
 
1441
    }
 
1442
 
 
1443
    gtk_widget_destroy (dialog_input);
 
1444
}
 
1445
 
 
1446
static void
 
1447
del_theme (KeyboardMcsDialog *dialog)
 
1448
{
 
1449
    GtkTreeSelection *selection;
 
1450
    GtkTreeModel *model;
 
1451
    GtkTreeIter iter;
 
1452
    gchar *theme_name;
 
1453
    gchar *theme_path;
 
1454
    gchar *message;
 
1455
 
 
1456
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview_themes));
 
1457
 
 
1458
    if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 
1459
    {
 
1460
        g_warning ("no theme selected to delete");
 
1461
        return;
 
1462
    }
 
1463
 
 
1464
    gtk_tree_model_get (model, &iter, COLUMN_THEME_NAME, &theme_name, COLUMN_FILE_NAME, &theme_path, -1);
 
1465
 
 
1466
    message = g_strdup_printf (_("Do you really want to delete the '%s' theme ?"), theme_name);
 
1467
 
 
1468
    if (xfce_confirm (message, GTK_STOCK_YES, NULL))
 
1469
    {
 
1470
        unlink (theme_path);
 
1471
        update_themes_list (dialog);
 
1472
    }
 
1473
 
 
1474
    g_free (theme_name);
 
1475
    g_free (theme_path);
 
1476
    g_free (message);
 
1477
}
 
1478
 
 
1479
static void
 
1480
cb_button_add_theme_clicked (GtkWidget * widget, gpointer data)
 
1481
{
 
1482
    add_theme ((KeyboardMcsDialog *) data);
 
1483
}
 
1484
 
 
1485
static void
 
1486
cb_button_del_theme_clicked (GtkWidget * widget, gpointer data)
 
1487
{
 
1488
    del_theme ((KeyboardMcsDialog *) data);
 
1489
}
 
1490
 
 
1491
static void
 
1492
cb_menuitem_add_theme_activate (GtkWidget * widget, gpointer data)
 
1493
{
 
1494
    add_theme ((KeyboardMcsDialog *) data);
 
1495
}
 
1496
 
 
1497
static void
 
1498
cb_menuitem_del_theme_activate (GtkWidget * widget, gpointer data)
 
1499
{
 
1500
    del_theme ((KeyboardMcsDialog *) data);
 
1501
}
 
1502
 
 
1503
static void
 
1504
cb_button_del_shortcut_clicked (GtkWidget * widget, gpointer data)
 
1505
{
 
1506
    KeyboardMcsDialog *dialog;
 
1507
    GtkTreeSelection *selection;
 
1508
    GtkTreeModel *model;
 
1509
    GtkTreeIter iter;
 
1510
    gchar *command;
 
1511
    gchar *shortcut;
 
1512
    gchar *message;
 
1513
 
 
1514
    dialog = (KeyboardMcsDialog *) data;
 
1515
 
 
1516
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview_shortcuts));
 
1517
 
 
1518
    if (!gtk_tree_selection_get_selected (selection, &model, &iter))
 
1519
    {
 
1520
        g_warning ("no shortcut selected to delete");
 
1521
        return;
 
1522
    }
 
1523
 
 
1524
    gtk_tree_model_get (model, &iter, COLUMN_COMMAND, &command, COLUMN_SHORTCUT, &shortcut, -1);
 
1525
 
 
1526
    message = g_strdup_printf (_("Do you really want to delete the shorcut entry for the '%s' command ?"), command);
 
1527
 
 
1528
    if (xfce_confirm (message, GTK_STOCK_YES, NULL))
 
1529
    {
 
1530
        GSList *element;
 
1531
 
 
1532
        dialog->theme_modified = TRUE;
 
1533
 
 
1534
        if ((element = search_key_in_shortcut_list (shortcut)) != NULL)
 
1535
        {
 
1536
            launcher *launcher_data = (launcher *) element->data;
 
1537
 
 
1538
            free_launcher_data (launcher_data);
 
1539
            shortcut_list = g_slist_remove (shortcut_list, launcher_data);
 
1540
            g_free (launcher_data);
 
1541
        }
 
1542
        gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
 
1543
    }
 
1544
 
 
1545
    g_free (shortcut);
 
1546
    g_free (command);
 
1547
    g_free (message);
 
1548
}
 
1549
 
 
1550
static void
 
1551
cb_button_add_shortcut_clicked (GtkWidget * widget, gpointer data)
 
1552
{
 
1553
    KeyboardMcsDialog *dialog;
 
1554
    GtkWidget *dialog_command;
 
1555
    GtkWidget *label;
 
1556
    GtkWidget *entry;
 
1557
    GtkWidget *img;
 
1558
    GtkWidget *button;
 
1559
    GtkWidget *hbox;
 
1560
    GtkWidget *hbox_entry;
 
1561
 
 
1562
    dialog = (KeyboardMcsDialog *) data;
 
1563
 
 
1564
    /* Create dialog */
 
1565
    dialog_command = gtk_dialog_new_with_buttons (_("Choose command"), 
 
1566
                                                  GTK_WINDOW (gtk_widget_get_toplevel(dialog->dialog_keyboard)),
 
1567
                                                  GTK_DIALOG_MODAL, 
 
1568
                                                  GTK_STOCK_CANCEL, 
 
1569
                                                  GTK_RESPONSE_CANCEL, 
 
1570
                                                  GTK_STOCK_OK, 
 
1571
                                                  GTK_RESPONSE_OK,
 
1572
                                                  NULL);
 
1573
    gtk_dialog_set_default_response (GTK_DIALOG (dialog_command),
 
1574
                                     GTK_RESPONSE_OK);
 
1575
 
 
1576
    label = gtk_label_new (_("Command:"));
 
1577
    entry = gtk_entry_new_with_max_length (255);
 
1578
    gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
 
1579
 
 
1580
    hbox_entry = gtk_hbox_new (FALSE, BORDER);
 
1581
    gtk_box_pack_start (GTK_BOX (hbox_entry), entry, FALSE, FALSE, 0);
 
1582
    img = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON);
 
1583
    button = gtk_button_new ();
 
1584
    gtk_container_add (GTK_CONTAINER (button), img);
 
1585
    g_signal_connect (G_CALLBACK (button), "clicked", G_CALLBACK (cb_browse_command), entry);
 
1586
    gtk_box_pack_start (GTK_BOX (hbox_entry), button, FALSE, FALSE, 0);
 
1587
 
 
1588
    hbox = gtk_hbox_new (FALSE, BORDER);
 
1589
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
 
1590
    gtk_box_pack_start (GTK_BOX (hbox), hbox_entry, FALSE, TRUE, 0);
 
1591
    gtk_container_set_border_width (GTK_CONTAINER (hbox), BORDER);
 
1592
 
 
1593
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog_command)->vbox), hbox, FALSE, TRUE, 0);
 
1594
    gtk_widget_show_all (dialog_command);
 
1595
 
 
1596
    if (gtk_dialog_run (GTK_DIALOG (dialog_command)) == GTK_RESPONSE_OK)
 
1597
    {
 
1598
 
 
1599
        if (strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0 && command_exists (gtk_entry_get_text (GTK_ENTRY (entry))))
 
1600
        {
 
1601
            GtkTreeModel *model;
 
1602
            GtkTreeIter iter;
 
1603
 
 
1604
            model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_shortcuts));
 
1605
            gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
 
1606
            gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_COMMAND, 
 
1607
                                gtk_entry_get_text (GTK_ENTRY (entry)), COLUMN_SHORTCUT, "", -1);
 
1608
            dialog->theme_modified = TRUE;
 
1609
        }
 
1610
        else
 
1611
            xfce_err (_("The command doesn't exist or the file is not executable !"));
 
1612
    }
 
1613
 
 
1614
    gtk_widget_destroy (dialog_command);
 
1615
}
 
1616
 
 
1617
/********************/
 
1618
/* Shortcut edition */
 
1619
/********************/
 
1620
static gboolean
 
1621
command_exists (const gchar * command)
 
1622
{
 
1623
    gchar *cmd_buf = NULL;
 
1624
    gchar *cmd_tok = NULL;
 
1625
    gboolean result = FALSE;
 
1626
 
 
1627
    cmd_buf = g_strdup (command);
 
1628
    cmd_tok = strtok (cmd_buf, " ");
 
1629
 
 
1630
    if (g_find_program_in_path (cmd_buf) != NULL)
 
1631
        result = TRUE;
 
1632
 
 
1633
    g_free (cmd_buf);
 
1634
 
 
1635
    return result;
 
1636
}
 
1637
 
 
1638
static void
 
1639
cb_browse_command (GtkWidget * widget, GtkEntry * entry_command)
 
1640
{
 
1641
    GtkWidget *filesel_dialog;
 
1642
 
 
1643
    filesel_dialog = xfce_file_chooser_new (_("Select command"), NULL,
 
1644
                                            XFCE_FILE_CHOOSER_ACTION_OPEN, 
 
1645
                                            GTK_STOCK_CANCEL, 
 
1646
                                            GTK_RESPONSE_CANCEL, 
 
1647
                                            GTK_STOCK_OPEN, 
 
1648
                                            GTK_RESPONSE_ACCEPT, 
 
1649
                                            NULL);
 
1650
 
 
1651
    xfce_file_chooser_set_filename (XFCE_FILE_CHOOSER (filesel_dialog), 
 
1652
                                    gtk_entry_get_text (entry_command));
 
1653
    xfce_gtk_window_center_on_monitor_with_pointer (GTK_WINDOW (filesel_dialog));
 
1654
 
 
1655
    if (gtk_dialog_run (GTK_DIALOG (filesel_dialog)) == GTK_RESPONSE_ACCEPT)
 
1656
    {
 
1657
        gchar *filename;
 
1658
 
 
1659
        filename = xfce_file_chooser_get_filename (XFCE_FILE_CHOOSER (filesel_dialog));
 
1660
        gtk_entry_set_text (entry_command, filename);
 
1661
 
 
1662
        g_free (filename);
 
1663
    }
 
1664
 
 
1665
    gtk_widget_destroy (filesel_dialog);
 
1666
}
 
1667
 
 
1668
GtkWidget* shortcuts_plugin_create_dialog (KeyboardMcsDialog *dialog)
 
1669
{
 
1670
    GtkWidget *hbox, *hbox2;
 
1671
    GtkWidget *vbox;
 
1672
    GtkWidget *frame;
 
1673
 
 
1674
    GtkListStore *model;
 
1675
 
 
1676
    hbox = gtk_hbox_new (FALSE, BORDER);
 
1677
    gtk_container_set_border_width (GTK_CONTAINER (hbox), BORDER);
 
1678
    gtk_widget_show (hbox);
 
1679
 
 
1680
    /* */
 
1681
    frame = xfce_framebox_new (_("Themes"), FALSE);
 
1682
    gtk_widget_show (frame);
 
1683
    gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, TRUE, 0);
 
1684
 
 
1685
    vbox = gtk_vbox_new (FALSE, BORDER);
 
1686
    gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
 
1687
    gtk_widget_show (vbox);
 
1688
    xfce_framebox_add (XFCE_FRAMEBOX (frame), vbox);
 
1689
 
 
1690
    dialog->scrolledwindow_themes = gtk_scrolled_window_new (NULL, NULL);
 
1691
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dialog->scrolledwindow_themes), 
 
1692
                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
1693
    gtk_container_set_border_width (GTK_CONTAINER (dialog->scrolledwindow_themes), BORDER);
 
1694
    gtk_widget_show (dialog->scrolledwindow_themes);
 
1695
    gtk_box_pack_start (GTK_BOX (vbox), dialog->scrolledwindow_themes, TRUE, TRUE, 0);
 
1696
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (dialog->scrolledwindow_themes), GTK_SHADOW_IN);
 
1697
 
 
1698
    dialog->treeview_themes = gtk_tree_view_new ();
 
1699
    gtk_widget_show (dialog->treeview_themes);
 
1700
    gtk_container_add (GTK_CONTAINER (dialog->scrolledwindow_themes), dialog->treeview_themes);
 
1701
    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->treeview_themes), FALSE);
 
1702
 
 
1703
    dialog->button_add_theme = gtk_button_new_from_stock (GTK_STOCK_ADD);
 
1704
    gtk_widget_show (dialog->button_add_theme);
 
1705
    gtk_box_pack_start (GTK_BOX (vbox), dialog->button_add_theme, FALSE, FALSE, 0);
 
1706
    dialog->button_del_theme = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
 
1707
    gtk_widget_show (dialog->button_del_theme);
 
1708
    gtk_box_pack_start (GTK_BOX (vbox), dialog->button_del_theme, FALSE, FALSE, 0);
 
1709
    gtk_widget_set_sensitive (dialog->button_del_theme, FALSE);
 
1710
 
 
1711
    /* */
 
1712
    frame = xfce_framebox_new (_("Shortcuts"), FALSE);
 
1713
    gtk_widget_show (frame);
 
1714
    gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
 
1715
 
 
1716
    vbox = gtk_vbox_new (FALSE, BORDER);
 
1717
    gtk_container_set_border_width (GTK_CONTAINER (vbox), BORDER);
 
1718
    gtk_widget_show (vbox);
 
1719
    xfce_framebox_add (XFCE_FRAMEBOX (frame), vbox);
 
1720
 
 
1721
    dialog->scrolledwindow_shortcuts = gtk_scrolled_window_new (NULL, NULL);
 
1722
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dialog->scrolledwindow_shortcuts), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
1723
    gtk_container_set_border_width (GTK_CONTAINER (dialog->scrolledwindow_shortcuts), BORDER);
 
1724
    gtk_widget_show (dialog->scrolledwindow_shortcuts);
 
1725
    gtk_box_pack_start (GTK_BOX (vbox), dialog->scrolledwindow_shortcuts, TRUE, TRUE, 0);
 
1726
    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (dialog->scrolledwindow_shortcuts), GTK_SHADOW_IN);
 
1727
 
 
1728
    model = gtk_list_store_new (SHORTCUTS_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
 
1729
    dialog->treeview_shortcuts = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
 
1730
    gtk_widget_show (dialog->treeview_shortcuts);
 
1731
    gtk_container_add (GTK_CONTAINER (dialog->scrolledwindow_shortcuts), dialog->treeview_shortcuts);
 
1732
    gtk_widget_set_size_request (dialog->treeview_shortcuts, 350, 200);
 
1733
 
 
1734
    hbox2 = gtk_hbox_new (FALSE, BORDER);
 
1735
    gtk_container_set_border_width (GTK_CONTAINER (hbox2), BORDER);
 
1736
    gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
 
1737
    gtk_widget_show (hbox2);
 
1738
 
 
1739
    dialog->button_add_shortcut = gtk_button_new_from_stock (GTK_STOCK_ADD);
 
1740
    gtk_widget_show (dialog->button_add_shortcut);
 
1741
    gtk_box_pack_start (GTK_BOX (hbox2), dialog->button_add_shortcut, TRUE, FALSE, 0);
 
1742
    gtk_widget_set_sensitive (dialog->button_add_shortcut, FALSE);
 
1743
    dialog->button_del_shortcut = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
 
1744
    gtk_widget_show (dialog->button_del_shortcut);
 
1745
    gtk_box_pack_start (GTK_BOX (hbox2), dialog->button_del_shortcut, TRUE, FALSE, 0);
 
1746
    gtk_widget_set_sensitive (dialog->button_del_shortcut, FALSE);
 
1747
 
 
1748
    /* popup menus */
 
1749
    dialog->menu_popup_themes = gtk_menu_new ();
 
1750
    dialog->menuitem_popup_rename_theme = gtk_image_menu_item_new_from_stock (GTK_STOCK_EDIT, NULL);
 
1751
    gtk_container_add (GTK_CONTAINER (dialog->menu_popup_themes), dialog->menuitem_popup_rename_theme);
 
1752
    dialog->menuitem_popup_add_theme = gtk_image_menu_item_new_from_stock (GTK_STOCK_ADD, NULL);
 
1753
    gtk_container_add (GTK_CONTAINER (dialog->menu_popup_themes), dialog->menuitem_popup_add_theme);
 
1754
    dialog->menuitem_popup_del_theme = gtk_image_menu_item_new_from_stock (GTK_STOCK_REMOVE, NULL);
 
1755
    gtk_container_add (GTK_CONTAINER (dialog->menu_popup_themes), dialog->menuitem_popup_del_theme);
 
1756
    gtk_widget_show_all (dialog->menu_popup_themes);
 
1757
 
 
1758
    dialog->menu_popup_shortcuts = gtk_menu_new ();
 
1759
    dialog->menuitem_popup_edit_shortcut = gtk_image_menu_item_new_from_stock (GTK_STOCK_EDIT, NULL);
 
1760
    gtk_container_add (GTK_CONTAINER (dialog->menu_popup_shortcuts), dialog->menuitem_popup_edit_shortcut);
 
1761
    dialog->menuitem_popup_add_shortcut = gtk_image_menu_item_new_from_stock (GTK_STOCK_ADD, NULL);
 
1762
    gtk_container_add (GTK_CONTAINER (dialog->menu_popup_shortcuts), dialog->menuitem_popup_add_shortcut);
 
1763
    dialog->menuitem_popup_del_shortcut = gtk_image_menu_item_new_from_stock (GTK_STOCK_REMOVE, NULL);
 
1764
    gtk_container_add (GTK_CONTAINER (dialog->menu_popup_shortcuts), dialog->menuitem_popup_del_shortcut);
 
1765
    gtk_widget_show_all (dialog->menu_popup_shortcuts);
 
1766
 
 
1767
    return hbox;
 
1768
}
 
1769
 
 
1770
void shortcuts_plugin_setup_dialog (KeyboardMcsDialog * dialog)
 
1771
{
 
1772
    GtkTreeModel *model;
 
1773
    GtkTreeSelection *selection;
 
1774
 
 
1775
    dialog->theme_modified = FALSE;
 
1776
 
 
1777
    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (dialog->treeview_themes),
 
1778
                                                 -1, 
 
1779
                                                 NULL, 
 
1780
                                                 gtk_cell_renderer_text_new (), 
 
1781
                                                 "text", 
 
1782
                                                 COLUMN_THEME_NAME, 
 
1783
                                                 NULL);
 
1784
 
 
1785
    model = (GtkTreeModel *) gtk_list_store_new (THEMES_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
 
1786
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), 0, themes_sort_func, NULL, NULL);
 
1787
    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, GTK_SORT_ASCENDING);
 
1788
    gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview_themes), model);
 
1789
 
 
1790
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->treeview_themes));
 
1791
    gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
 
1792
    g_signal_connect (G_OBJECT (selection), "changed", (GCallback) cb_treeview_themes_selection_changed, dialog);
 
1793
 
 
1794
    g_signal_connect (G_OBJECT (dialog->treeview_themes), "button-press-event", G_CALLBACK (cb_popup_menu_themes), dialog);
 
1795
    g_signal_connect (G_OBJECT (dialog->button_add_theme), "clicked", G_CALLBACK (cb_button_add_theme_clicked), dialog);
 
1796
    g_signal_connect (G_OBJECT (dialog->button_del_theme), "clicked", G_CALLBACK (cb_button_del_theme_clicked), dialog);
 
1797
 
 
1798
    /* shortcuts treeview */
 
1799
    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (dialog->treeview_shortcuts), 
 
1800
                                                 -1, 
 
1801
                                                 _("Command"),
 
1802
                                                 gtk_cell_renderer_text_new (), 
 
1803
                                                 "text", 
 
1804
                                                 COLUMN_COMMAND, 
 
1805
                                                 NULL);
 
1806
    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (dialog->treeview_shortcuts), 
 
1807
                                                 -1, 
 
1808
                                                 _("Shortcut"),
 
1809
                                                 gtk_cell_renderer_text_new (), 
 
1810
                                                 "text", 
 
1811
                                                 COLUMN_SHORTCUT, 
 
1812
                                                 NULL);
 
1813
 
 
1814
    model = (GtkTreeModel *) gtk_list_store_new (SHORTCUTS_NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
 
1815
    gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), 0, shortcuts_sort_func, NULL, NULL);
 
1816
    gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 0, GTK_SORT_ASCENDING);
 
1817
    gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview_shortcuts), model);
 
1818
    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->treeview_shortcuts), TRUE);
 
1819
 
 
1820
    g_signal_connect (G_OBJECT (dialog->treeview_shortcuts), "button-press-event", G_CALLBACK (cb_popup_menu_shortcuts), dialog);
 
1821
    g_signal_connect (G_OBJECT (dialog->button_add_shortcut), "clicked", G_CALLBACK (cb_button_add_shortcut_clicked), dialog);
 
1822
    g_signal_connect (G_OBJECT (dialog->button_del_shortcut), "clicked", G_CALLBACK (cb_button_del_shortcut_clicked), dialog);
 
1823
 
 
1824
    /* popup menus */
 
1825
    g_signal_connect (G_OBJECT (dialog->menuitem_popup_rename_theme), "activate", G_CALLBACK (cb_popup_rename_theme), dialog);
 
1826
    g_signal_connect (G_OBJECT (dialog->menuitem_popup_add_theme), "activate", G_CALLBACK (cb_menuitem_add_theme_activate), dialog);
 
1827
    g_signal_connect (G_OBJECT (dialog->menuitem_popup_del_theme), "activate", G_CALLBACK (cb_menuitem_del_theme_activate), dialog);
 
1828
    g_signal_connect (G_OBJECT (dialog->treeview_themes), "row-activated", G_CALLBACK (cb_treeview_themes_activate), dialog);
 
1829
 
 
1830
    g_signal_connect (G_OBJECT (dialog->menuitem_popup_edit_shortcut), "activate", G_CALLBACK (cb_popup_edit_shortcut), dialog);
 
1831
    g_signal_connect (G_OBJECT (dialog->treeview_shortcuts), "row-activated", G_CALLBACK (cb_treeview_shortcuts_activate), dialog);
 
1832
 
 
1833
    update_themes_list (dialog);
 
1834
 
 
1835
    xfce_gtk_window_center_on_monitor_with_pointer (GTK_WINDOW (dialog->dialog_keyboard));
 
1836
    gdk_x11_window_set_user_time(GTK_WIDGET (dialog->dialog_keyboard)->window, 
 
1837
            gdk_x11_get_server_time (GTK_WIDGET (dialog->dialog_keyboard)->window));
 
1838
            
 
1839
    gtk_widget_show (dialog->dialog_keyboard);
 
1840
}
 
1841
 
 
1842
gboolean shortcuts_plugin_save_settings (McsPlugin * plugin)
 
1843
{
 
1844
    gboolean result;
 
1845
    gchar *file, *path;
 
1846
 
 
1847
    path = g_build_filename ("xfce4", RCDIR, RCFILE3, NULL);
 
1848
    file = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, path, TRUE);
 
1849
 
 
1850
    result = mcs_manager_save_channel_to_file (plugin->manager, CHANNEL3, file);
 
1851
    g_free (path);
 
1852
    g_free (file);
 
1853
 
 
1854
    return (result);
 
1855
}
 
1856
 
 
1857
void shortcuts_plugin_init(McsPlugin * plugin)
 
1858
{
 
1859
    gchar *file, *path;
 
1860
    McsSetting *setting;
 
1861
 
 
1862
    /* read settings channel from file */
 
1863
    path = g_build_filename ("xfce4", RCDIR, RCFILE3, NULL);
 
1864
    file = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, path);
 
1865
    g_free (path);
 
1866
 
 
1867
    if (!file)
 
1868
    {
 
1869
        file = xfce_get_userfile (OLD_RCDIR, RCFILE3, NULL);
 
1870
    }
 
1871
 
 
1872
    if (g_file_test (file, G_FILE_TEST_EXISTS))
 
1873
    {
 
1874
        mcs_manager_add_channel_from_file (plugin->manager, CHANNEL3, file);
 
1875
    }
 
1876
    else
 
1877
    {
 
1878
        mcs_manager_add_channel (plugin->manager, CHANNEL3);
 
1879
    }
 
1880
    g_free (file);
 
1881
 
 
1882
    mcs_manager_notify (plugin->manager, CHANNEL3);
 
1883
 
 
1884
    setting = mcs_manager_setting_lookup(plugin->manager, "Xfce4/ShortcutThemeName", CHANNEL3);
 
1885
    if (setting) 
 
1886
    {
 
1887
        theme_name = g_strdup(setting->data.v_string);
 
1888
    }
 
1889
    else
 
1890
    {
 
1891
        theme_name = g_strdup(DEFAULT_SHORTCUT_THEME);
 
1892
    }
 
1893
 
 
1894
    setting = mcs_manager_setting_lookup(plugin->manager, "Xfce4/ShortcutThemeFile", CHANNEL3);
 
1895
    if (setting) 
 
1896
    {
 
1897
        theme_path = g_strdup(setting->data.v_string);
 
1898
    }
 
1899
    else
 
1900
    {
 
1901
        theme_path = g_strdup(DEFAULT_SHORTCUTS_PATH);
 
1902
    }
 
1903
 
 
1904
    init_modifiers ();
 
1905
    parse_theme (theme_path, NULL);
 
1906
    add_event_listener ();
 
1907
}
 
1908
 
 
1909
void shortcuts_plugin_load_theme (KeyboardMcsDialog *dialog)
 
1910
{
 
1911
    gchar *path = NULL;
 
1912
 
 
1913
    /* check XDG_CONFIG_HOME/xfce4/shortcuts/ exists; if not it creates it */
 
1914
    path = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, "xfce4/shortcuts/", TRUE);
 
1915
    if (G_UNLIKELY (path == NULL))
 
1916
    {
 
1917
        g_warning ("failed to create the shorcuts directory");
 
1918
        return;
 
1919
    }
 
1920
    g_free (path);
 
1921
 
 
1922
    parse_theme (theme_path, dialog);
 
1923
}