~ubuntu-branches/ubuntu/karmic/sakura/karmic

« back to all changes in this revision

Viewing changes to src/sakura.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Starr-Bochicchio
  • Date: 2009-06-23 23:58:16 UTC
  • Revision ID: james.westby@ubuntu.com-20090623235816-3viq7c0zza406mw1
Tags: upstream-2.3.4
Import upstream version 2.3.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 *  Filename: sakura.c
 
3
 *  Description: VTE-based terminal emulator
 
4
 *
 
5
 *           Copyright (C) 2006-2008  David Gómez <david@pleyades.net>
 
6
 *           Copyright (C) 2008       Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
 
7
 *
 
8
 *  This program is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License version 2 as
 
10
 *  published by the Free Software Foundation
 
11
 *
 
12
 *  This program is distributed in the hope that it will be useful,
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 *  GNU General Public License for more details.
 
16
 *
 
17
 *  You should have received a copy of the GNU General Public License
 
18
 *  along with this program; if not, write to the Free Software
 
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 *
 
21
 *****************************************************************************/
 
22
 
 
23
#include <stdbool.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <stdarg.h>
 
27
#include <unistd.h>
 
28
#include <wchar.h>
 
29
#include <sys/types.h>
 
30
#include <sys/wait.h>
 
31
#include <sys/stat.h>
 
32
#include <fcntl.h>
 
33
#include <locale.h>
 
34
#include <libintl.h>
 
35
#include <glib.h>
 
36
#include <glib/gstdio.h>
 
37
#include <gtk/gtk.h>
 
38
#include <gdk/gdkkeysyms.h>
 
39
#include <pango/pango.h>
 
40
#include <vte/vte.h>
 
41
 
 
42
#define _(String) gettext(String)
 
43
#define N_(String) (String)
 
44
#define GETTEXT_PACKAGE "sakura"
 
45
 
 
46
#define SAY(format,...) do {\
 
47
        if (strcmp("Debug", BUILDTYPE)==0) {\
 
48
            fprintf(stderr, "[%d] ", getpid());\
 
49
            fprintf(stderr, "[%s] ", __FUNCTION__);\
 
50
            if (format) fprintf(stderr, format, ##__VA_ARGS__);\
 
51
            fputc('\n', stderr);\
 
52
                fflush(stderr);\
 
53
        }\
 
54
} while (0)
 
55
 
 
56
#define PALETTE_SIZE 16
 
57
 
 
58
/* Color palettes. Color lists borrowed from gnome-terminal source (thanks! ;)) */
 
59
const GdkColor tango_palette[PALETTE_SIZE] =
 
60
{
 
61
        { 0, 0x2e2e, 0x3434, 0x3636 },
 
62
        { 0, 0xcccc, 0x0000, 0x0000 },
 
63
        { 0, 0x4e4e, 0x9a9a, 0x0606 },
 
64
        { 0, 0xc4c4, 0xa0a0, 0x0000 },
 
65
        { 0, 0x3434, 0x6565, 0xa4a4 },
 
66
        { 0, 0x7575, 0x5050, 0x7b7b },
 
67
        { 0, 0x0606, 0x9820, 0x9a9a },
 
68
        { 0, 0xd3d3, 0xd7d7, 0xcfcf },
 
69
        { 0, 0x5555, 0x5757, 0x5353 },
 
70
        { 0, 0xefef, 0x2929, 0x2929 },
 
71
        { 0, 0x8a8a, 0xe2e2, 0x3434 },
 
72
        { 0, 0xfcfc, 0xe9e9, 0x4f4f },
 
73
        { 0, 0x7272, 0x9f9f, 0xcfcf },
 
74
        { 0, 0xadad, 0x7f7f, 0xa8a8 },
 
75
        { 0, 0x3434, 0xe2e2, 0xe2e2 },
 
76
        { 0, 0xeeee, 0xeeee, 0xecec }
 
77
};
 
78
 
 
79
const GdkColor linux_palette[PALETTE_SIZE] =
 
80
{
 
81
        { 0, 0x0000, 0x0000, 0x0000 },
 
82
        { 0, 0xaaaa, 0x0000, 0x0000 },
 
83
        { 0, 0x0000, 0xaaaa, 0x0000 },
 
84
        { 0, 0xaaaa, 0x5555, 0x0000 },
 
85
        { 0, 0x0000, 0x0000, 0xaaaa },
 
86
        { 0, 0xaaaa, 0x0000, 0xaaaa },
 
87
        { 0, 0x0000, 0xaaaa, 0xaaaa },
 
88
        { 0, 0xaaaa, 0xaaaa, 0xaaaa },
 
89
        { 0, 0x5555, 0x5555, 0x5555 },
 
90
        { 0, 0xffff, 0x5555, 0x5555 },
 
91
        { 0, 0x5555, 0xffff, 0x5555 },
 
92
        { 0, 0xffff, 0xffff, 0x5555 },
 
93
        { 0, 0x5555, 0x5555, 0xffff },
 
94
        { 0, 0xffff, 0x5555, 0xffff },
 
95
        { 0, 0x5555, 0xffff, 0xffff },
 
96
        { 0, 0xffff, 0xffff, 0xffff }
 
97
};
 
98
 
 
99
const GdkColor xterm_palette[PALETTE_SIZE] =
 
100
{
 
101
        {0, 0x0000, 0x0000, 0x0000 },
 
102
        {0, 0xcdcb, 0x0000, 0x0000 },
 
103
        {0, 0x0000, 0xcdcb, 0x0000 },
 
104
        {0, 0xcdcb, 0xcdcb, 0x0000 },
 
105
        {0, 0x1e1a, 0x908f, 0xffff },
 
106
        {0, 0xcdcb, 0x0000, 0xcdcb },
 
107
        {0, 0x0000, 0xcdcb, 0xcdcb },
 
108
        {0, 0xe5e2, 0xe5e2, 0xe5e2 },
 
109
        {0, 0x4ccc, 0x4ccc, 0x4ccc },
 
110
        {0, 0xffff, 0x0000, 0x0000 },
 
111
        {0, 0x0000, 0xffff, 0x0000 },
 
112
        {0, 0xffff, 0xffff, 0x0000 },
 
113
        {0, 0x4645, 0x8281, 0xb4ae },
 
114
        {0, 0xffff, 0x0000, 0xffff },
 
115
        {0, 0x0000, 0xffff, 0xffff },
 
116
        {0, 0xffff, 0xffff, 0xffff }
 
117
};
 
118
 
 
119
const GdkColor rxvt_palette[PALETTE_SIZE] =
 
120
{
 
121
        { 0, 0x0000, 0x0000, 0x0000 },
 
122
        { 0, 0xcdcd, 0x0000, 0x0000 },
 
123
        { 0, 0x0000, 0xcdcd, 0x0000 },
 
124
        { 0, 0xcdcd, 0xcdcd, 0x0000 },
 
125
        { 0, 0x0000, 0x0000, 0xcdcd },
 
126
        { 0, 0xcdcd, 0x0000, 0xcdcd },
 
127
        { 0, 0x0000, 0xcdcd, 0xcdcd },
 
128
        { 0, 0xfafa, 0xebeb, 0xd7d7 },
 
129
        { 0, 0x4040, 0x4040, 0x4040 },
 
130
        { 0, 0xffff, 0x0000, 0x0000 },
 
131
        { 0, 0x0000, 0xffff, 0x0000 },
 
132
        { 0, 0xffff, 0xffff, 0x0000 },
 
133
        { 0, 0x0000, 0x0000, 0xffff },
 
134
        { 0, 0xffff, 0x0000, 0xffff },
 
135
        { 0, 0x0000, 0xffff, 0xffff },
 
136
        { 0, 0xffff, 0xffff, 0xffff }
 
137
};
 
138
 
 
139
static struct {
 
140
        GtkWidget *main_window;
 
141
        GtkWidget *notebook;
 
142
        GtkWidget *menu;
 
143
        GtkWidget *im_menu;
 
144
        PangoFontDescription *font;
 
145
        GdkColor forecolor;
 
146
        GdkColor backcolor;
 
147
        char *current_match;
 
148
        guint width;
 
149
        guint height;
 
150
        glong columns;
 
151
        glong rows;
 
152
        gint char_width;
 
153
        gint char_height;
 
154
        gint label_count;
 
155
        bool fake_transparency;
 
156
        float opacity_level;
 
157
        char *opacity_level_percent;
 
158
        bool *opacity;
 
159
        bool first_tab;
 
160
        bool show_scrollbar;
 
161
        bool show_closebutton;
 
162
        bool audible_bell;
 
163
        bool visible_bell;
 
164
        bool blinking_cursor;
 
165
        bool full_screen;
 
166
        bool keep_fc; /* Global flag to indicate that we don't want changes in the files and columns values */
 
167
        GtkWidget *item_clear_background; /* We include here only the items which need to be hided */
 
168
        GtkWidget *item_copy_link;
 
169
        GtkWidget *item_open_link;
 
170
        GtkWidget *open_link_separator;
 
171
        GKeyFile *cfg;
 
172
        char *configfile;
 
173
        char *background;
 
174
        char *word_chars;
 
175
        const GdkColor *palette;
 
176
        gint add_tab_accelerator;
 
177
        gint del_tab_accelerator;
 
178
        gint switch_tab_accelerator;
 
179
        gint copy_accelerator;
 
180
        gint scrollbar_accelerator;
 
181
        gint open_url_accelerator;
 
182
        gint add_tab_key;
 
183
        gint del_tab_key;
 
184
        gint prev_tab_key;
 
185
        gint next_tab_key;
 
186
        gint copy_key;
 
187
        gint paste_key;
 
188
        gint scrollbar_key;
 
189
        gint fullscreen_key;
 
190
        GRegex *http_regexp;
 
191
        char *argv[2];
 
192
} sakura;
 
193
 
 
194
struct terminal {
 
195
        GtkWidget *hbox;
 
196
        GtkWidget *vte;     /* Reference to VTE terminal */
 
197
        pid_t pid;          /* pid of the forked proccess */
 
198
        GtkWidget *scrollbar;
 
199
        GtkWidget *label;
 
200
};
 
201
 
 
202
 
 
203
#define ICON_FILE "terminal-tango.svg"
 
204
#define SCROLL_LINES 4096
 
205
#define HTTP_REGEXP "(ftp|http)s?://[-a-zA-Z0-9.?$%&/=_~#.,:;+]*"
 
206
#define CONFIGFILE "sakura.conf"
 
207
#define DEFAULT_COLUMNS 80
 
208
#define DEFAULT_ROWS 24
 
209
#define DEFAULT_FONT "monospace 11"
 
210
#define DEFAULT_WORD_CHARS  "-A-Za-z0-9,./?%&#_~"
 
211
#define DEFAULT_PALETTE "linux"
 
212
#define DEFAULT_ADD_TAB_ACCELERATOR  (GDK_CONTROL_MASK|GDK_SHIFT_MASK)
 
213
#define DEFAULT_DEL_TAB_ACCELERATOR  (GDK_CONTROL_MASK|GDK_SHIFT_MASK)
 
214
#define DEFAULT_SWITCH_TAB_ACCELERATOR  (GDK_MOD1_MASK)
 
215
#define DEFAULT_COPY_ACCELERATOR  (GDK_CONTROL_MASK|GDK_SHIFT_MASK)
 
216
#define DEFAULT_SCROLLBAR_ACCELERATOR  (GDK_CONTROL_MASK|GDK_SHIFT_MASK)
 
217
#define DEFAULT_OPEN_URL_ACCELERATOR (GDK_CONTROL_MASK|GDK_SHIFT_MASK)
 
218
#define DEFAULT_ADD_TAB_KEY  GDK_T
 
219
#define DEFAULT_DEL_TAB_KEY  GDK_W
 
220
#define DEFAULT_PREV_TAB_KEY  GDK_Left
 
221
#define DEFAULT_NEXT_TAB_KEY  GDK_Right
 
222
#define DEFAULT_COPY_KEY  GDK_C
 
223
#define DEFAULT_PASTE_KEY  GDK_V
 
224
#define DEFAULT_SCROLLBAR_KEY  GDK_S
 
225
#define DEFAULT_FULLSCREEN_KEY  GDK_F11
 
226
const char cfg_group[] = "sakura";
 
227
 
 
228
static GQuark term_data_id = 0;
 
229
#define  sakura_get_page_term( sakura, page_idx )  \
 
230
    (struct terminal*)g_object_get_qdata(  \
 
231
            G_OBJECT( gtk_notebook_get_nth_page( (GtkNotebook*)sakura.notebook, page_idx ) ), term_data_id);
 
232
 
 
233
#define  sakura_set_page_term( sakura, page_idx, term )  \
 
234
    g_object_set_qdata_full( \
 
235
            G_OBJECT( gtk_notebook_get_nth_page( (GtkNotebook*)sakura.notebook, page_idx) ), \
 
236
            term_data_id, term, (GDestroyNotify)g_free);
 
237
 
 
238
/* Callbacks */
 
239
static gboolean sakura_key_press (GtkWidget *, GdkEventKey *, gpointer);
 
240
static void     sakura_increase_font (GtkWidget *, void *);
 
241
static void     sakura_decrease_font (GtkWidget *, void *);
 
242
static void     sakura_child_exited (GtkWidget *, void *);
 
243
static void     sakura_eof (GtkWidget *, void *);
 
244
static void     sakura_title_changed (GtkWidget *, void *);
 
245
static gboolean sakura_delete_window (GtkWidget *, void *);
 
246
static void     sakura_destroy_window (GtkWidget *, void *);
 
247
static void     sakura_font_dialog (GtkWidget *, void *);
 
248
static void     sakura_set_name_dialog (GtkWidget *, void *);
 
249
static void     sakura_color_dialog (GtkWidget *, void *);
 
250
static void     sakura_opacity_dialog (GtkWidget *, void *);
 
251
static void     sakura_set_title_dialog (GtkWidget *, void *);
 
252
static void     sakura_select_background_dialog (GtkWidget *, void *);
 
253
static void     sakura_new_tab (GtkWidget *, void *);
 
254
static void     sakura_close_tab (GtkWidget *, void *);
 
255
static void     sakura_full_screen (GtkWidget *, void *);
 
256
static void     sakura_open_url (GtkWidget *, void *);
 
257
static void     sakura_clear (GtkWidget *, void *);
 
258
static gboolean sakura_resized_window(GtkWidget *, GdkEventConfigure *, void *);
 
259
static void     sakura_setname_entry_changed(GtkWidget *, void *);
 
260
static void     sakura_copy(GtkWidget *, void *);
 
261
static void     sakura_paste(GtkWidget *, void *);
 
262
static void     sakura_show_first_tab (GtkWidget *widget, void *data);
 
263
static void     sakura_show_close_button (GtkWidget *widget, void *data);
 
264
static void             sakura_show_scrollbar(GtkWidget *, void *);
 
265
static void     sakura_closebutton_clicked(GtkWidget *, void *);
 
266
 
 
267
/* Misc */
 
268
static void     sakura_error(const char *, ...);
 
269
 
 
270
/* Functions */
 
271
static void     sakura_init();
 
272
static void     sakura_init_popup();
 
273
static void     sakura_destroy();
 
274
static void     sakura_add_tab();
 
275
static void     sakura_del_tab();
 
276
static void     sakura_set_font();
 
277
static void     sakura_set_size(gint, gint);
 
278
static void     sakura_kill_child();
 
279
static void     sakura_set_bgimage();
 
280
static void     sakura_key_file_set_key(GKeyFile *, const gchar *, const gchar *, guint);
 
281
static guint    sakura_key_file_get_key(GKeyFile *, const gchar *, const gchar *);
 
282
 
 
283
static const char *option_font;
 
284
static const char *option_execute;
 
285
static gboolean option_version=FALSE;
 
286
static gint option_ntabs=1;
 
287
static gint option_login = FALSE;
 
288
static const char *option_title;
 
289
static int option_rows, option_columns;
 
290
static gboolean option_hold=FALSE;
 
291
 
 
292
static GOptionEntry entries[] = {
 
293
        { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, N_("Print version number"), NULL },
 
294
        { "font", 'f', 0, G_OPTION_ARG_STRING, &option_font, N_("Select initial terminal font"), NULL },
 
295
        { "ntabs", 'n', 0, G_OPTION_ARG_INT, &option_ntabs, N_("Select initial number of tabs"), NULL },
 
296
        { "execute", 'e', 0, G_OPTION_ARG_STRING, &option_execute, N_("Execute command"), NULL },
 
297
        { "login", 'l', 0, G_OPTION_ARG_NONE, &option_login, N_("Login shell"), NULL },
 
298
        { "title", 't', 0, G_OPTION_ARG_STRING, &option_title, N_("Set window title"), NULL },
 
299
        { "columns", 'c', 0, G_OPTION_ARG_INT, &option_columns, N_("Set columns number"), NULL },
 
300
        { "rows", 'r', 0, G_OPTION_ARG_INT, &option_rows, N_("Set rows number"), NULL },
 
301
        { "hold", 'h', 0, G_OPTION_ARG_NONE, &option_hold, N_("Hold window after execute command"), NULL },
 
302
    { NULL }
 
303
};
 
304
 
 
305
 
 
306
static
 
307
gboolean sakura_key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
 
308
{
 
309
        unsigned int topage=0;
 
310
        gint npages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
311
        gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
312
 
 
313
        if (event->type!=GDK_KEY_PRESS) return FALSE;
 
314
 
 
315
        /* add_tab_accelerator + T or del_tab_accelerator + W pressed */
 
316
        if ( (event->state & sakura.add_tab_accelerator)==sakura.add_tab_accelerator &&
 
317
         event->keyval==sakura.add_tab_key ) {
 
318
                sakura_add_tab();
 
319
        return TRUE;
 
320
    } else if ( (event->state & sakura.del_tab_accelerator)==sakura.del_tab_accelerator &&
 
321
                event->keyval==sakura.del_tab_key ) {
 
322
        sakura_kill_child();
 
323
                /* Delete current tab */
 
324
        sakura_del_tab(page);
 
325
        if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook))==0)
 
326
            sakura_destroy();
 
327
        return TRUE;
 
328
        }
 
329
 
 
330
        /* switch_tab_accelerator + number pressed / switch_tab_accelerator + Left-Right cursor */
 
331
        if ( (event->state & sakura.switch_tab_accelerator) == sakura.switch_tab_accelerator ) {
 
332
                if ((event->keyval>=GDK_1) && (event->keyval<=GDK_9)) {
 
333
                        switch(event->keyval) {
 
334
                                case GDK_1: topage=0; break;
 
335
                                case GDK_2: topage=1; break;
 
336
                                case GDK_3: topage=2; break;
 
337
                                case GDK_4: topage=3; break;
 
338
                                case GDK_5: topage=4; break;
 
339
                                case GDK_6: topage=5; break;
 
340
                                case GDK_7: topage=6; break;
 
341
                                case GDK_8: topage=7; break;
 
342
                                case GDK_9: topage=8; break;
 
343
                        }
 
344
                        if (topage <= npages)
 
345
                                gtk_notebook_set_current_page(GTK_NOTEBOOK(sakura.notebook), topage);
 
346
                        return TRUE;
 
347
                } else if (event->keyval==sakura.prev_tab_key) {
 
348
                        if (gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook))==0) {
 
349
                                gtk_notebook_set_current_page(GTK_NOTEBOOK(sakura.notebook), npages-1);
 
350
                        } else {
 
351
                                gtk_notebook_prev_page(GTK_NOTEBOOK(sakura.notebook));
 
352
                        }
 
353
                        return TRUE;
 
354
                } else if (event->keyval==sakura.next_tab_key) {
 
355
                        if (gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook))==(npages-1)) {
 
356
                                gtk_notebook_set_current_page(GTK_NOTEBOOK(sakura.notebook), 0);
 
357
                        } else {
 
358
                                gtk_notebook_next_page(GTK_NOTEBOOK(sakura.notebook));
 
359
                        }
 
360
                        return TRUE;
 
361
                }
 
362
        }
 
363
 
 
364
        /* copy_accelerator-[C/V] pressed */
 
365
        if ( (event->state & sakura.copy_accelerator)==sakura.copy_accelerator ) {
 
366
                if (event->keyval==sakura.copy_key) {
 
367
                        sakura_copy(NULL, NULL);
 
368
                        return TRUE;
 
369
                } else if (event->keyval==sakura.paste_key) {
 
370
                        sakura_paste(NULL, NULL);
 
371
                        return TRUE;
 
372
                }
 
373
        }
 
374
 
 
375
        /* scrollbar_accelerator-[S] pressed */
 
376
        if ( (event->state & sakura.scrollbar_accelerator)==sakura.scrollbar_accelerator ) {
 
377
                if (event->keyval==sakura.scrollbar_key) {
 
378
                        sakura_show_scrollbar(NULL, NULL);
 
379
                        sakura_set_size(sakura.columns, sakura.rows);
 
380
                        return TRUE;
 
381
                }
 
382
        }
 
383
 
 
384
        /* F11 (fullscreen) pressed */
 
385
        if (event->keyval==sakura.fullscreen_key){
 
386
                sakura_full_screen(NULL, NULL);
 
387
                return TRUE;
 
388
        }
 
389
 
 
390
        return FALSE;
 
391
}
 
392
 
 
393
 
 
394
static gboolean
 
395
sakura_button_press(GtkWidget *widget, GdkEventButton *button_event, gpointer user_data)
 
396
{
 
397
        struct terminal *term;
 
398
        glong column, row;
 
399
        int page, tag;
 
400
 
 
401
        if (button_event->type != GDK_BUTTON_PRESS)
 
402
                return FALSE;
 
403
 
 
404
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
405
        term = sakura_get_page_term(sakura, page);
 
406
 
 
407
        /* Find out if cursor it's over a matched expression...*/
 
408
 
 
409
        /* Get the column and row relative to pointer position */
 
410
        column = ((glong) (button_event->x) / vte_terminal_get_char_width(
 
411
                        VTE_TERMINAL(term->vte)));
 
412
        row = ((glong) (button_event->y) / vte_terminal_get_char_height(
 
413
                        VTE_TERMINAL(term->vte)));
 
414
        sakura.current_match = vte_terminal_match_check(VTE_TERMINAL(term->vte), column, row, &tag);
 
415
 
 
416
        /* Left button: open the URL if any */
 
417
        if (button_event->button == 1 &&
 
418
            ((button_event->state & sakura.open_url_accelerator) == sakura.open_url_accelerator)
 
419
            && sakura.current_match) {
 
420
 
 
421
                sakura_open_url(NULL, NULL);
 
422
 
 
423
                return TRUE;
 
424
        }
 
425
 
 
426
        /* Right button: show the popup menu */
 
427
        if (button_event->button == 3) {
 
428
                GtkMenu *menu;
 
429
                menu = GTK_MENU (widget);
 
430
 
 
431
                if (sakura.current_match) {
 
432
                        /* Show the extra options in the menu */
 
433
                        gtk_widget_show(sakura.item_open_link);
 
434
                        gtk_widget_show(sakura.item_copy_link);
 
435
                        gtk_widget_show(sakura.open_link_separator);
 
436
                } else {
 
437
                        /* Hide all the options */
 
438
                        gtk_widget_hide(sakura.item_open_link);
 
439
                        gtk_widget_hide(sakura.item_copy_link);
 
440
                        gtk_widget_hide(sakura.open_link_separator);
 
441
                }
 
442
 
 
443
                gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button_event->button, button_event->time);
 
444
 
 
445
                return TRUE;
 
446
        }
 
447
 
 
448
        return FALSE;
 
449
}
 
450
 
 
451
 
 
452
static void
 
453
sakura_page_removed (GtkWidget *widget, void *data)
 
454
{
 
455
        if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook))==1) {
 
456
                /* If the first tab is disabled, window size changes and we need
 
457
                 * to recalculate its size */
 
458
                sakura_set_size(sakura.columns, sakura.rows);
 
459
        }
 
460
}
 
461
 
 
462
 
 
463
static void
 
464
sakura_increase_font (GtkWidget *widget, void *data)
 
465
{
 
466
        gint size;
 
467
 
 
468
        size=pango_font_description_get_size(sakura.font);
 
469
        pango_font_description_set_size(sakura.font, ((size/PANGO_SCALE)+1) * PANGO_SCALE);
 
470
 
 
471
        sakura_set_font();
 
472
        sakura_set_size(sakura.columns, sakura.rows);
 
473
}
 
474
 
 
475
 
 
476
static void
 
477
sakura_decrease_font (GtkWidget *widget, void *data)
 
478
{
 
479
        gint size;
 
480
 
 
481
        size=pango_font_description_get_size(sakura.font);
 
482
        pango_font_description_set_size(sakura.font, ((size/PANGO_SCALE)-1) * PANGO_SCALE);
 
483
 
 
484
        sakura_set_font();
 
485
        sakura_set_size(sakura.columns, sakura.rows);
 
486
}
 
487
 
 
488
 
 
489
static void
 
490
sakura_child_exited (GtkWidget *widget, void *data)
 
491
{
 
492
        int status, page;
 
493
        struct terminal *term;
 
494
 
 
495
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
496
        term = sakura_get_page_term(sakura, page);
 
497
 
 
498
        if (option_hold==TRUE) {
 
499
                SAY("hold option has been activated");
 
500
                return;
 
501
        }
 
502
 
 
503
        SAY("waiting for terminal pid %d", term->pid);
 
504
 
 
505
        waitpid(term->pid, &status, WNOHANG);
 
506
        /* TODO: check wait return */
 
507
 
 
508
        sakura_del_tab(page);
 
509
 
 
510
        if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook))==0)
 
511
                sakura_destroy();
 
512
}
 
513
 
 
514
 
 
515
static void
 
516
sakura_eof (GtkWidget *widget, void *data)
 
517
{
 
518
        int status;
 
519
        struct terminal *term;
 
520
 
 
521
        SAY("Got EOF signal");
 
522
 
 
523
        /* Workaround for libvte strange behaviour. There is not child-exited signal for
 
524
           the last terminal, so we need to kill it here.  Check with libvte authors about
 
525
           child-exited/eof signals */
 
526
        if (gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook))==0) {
 
527
 
 
528
                term = sakura_get_page_term(sakura, 0);
 
529
 
 
530
                if (option_hold==TRUE) {
 
531
                        SAY("hold option has been activated");
 
532
                        return;
 
533
                }
 
534
 
 
535
        SAY("waiting for terminal pid (in eof) %d", term->pid);
 
536
 
 
537
        waitpid(term->pid, &status, WNOHANG);
 
538
                /* TODO: check wait return */
 
539
 
 
540
                sakura_del_tab(0);
 
541
 
 
542
                if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook))==0)
 
543
                        sakura_destroy();
 
544
        }
 
545
}
 
546
 
 
547
 
 
548
static void
 
549
sakura_title_changed (GtkWidget *widget, void *data)
 
550
{
 
551
        int page;
 
552
        struct terminal *term;
 
553
 
 
554
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
555
        term = sakura_get_page_term(sakura, page);
 
556
        gtk_label_set_text(GTK_LABEL(term->label),vte_terminal_get_window_title(VTE_TERMINAL(term->vte)));
 
557
 
 
558
        gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(sakura.notebook), term->hbox,
 
559
                                    vte_terminal_get_window_title(VTE_TERMINAL(term->vte)));
 
560
        gtk_window_set_title(GTK_WINDOW(sakura.main_window),
 
561
                         vte_terminal_get_window_title(VTE_TERMINAL(term->vte)));
 
562
}
 
563
 
 
564
 
 
565
static gboolean
 
566
sakura_delete_window (GtkWidget *widget, void *data)
 
567
{
 
568
        GtkWidget *dialog;
 
569
        guint response;
 
570
        gint npages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
571
 
 
572
        if (npages > 1) {
 
573
                dialog=gtk_message_dialog_new(GTK_WINDOW(sakura.main_window), GTK_DIALOG_MODAL,
 
574
                                                                          GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
 
575
                                                                          _("There are %d tabs opened.\n\nDo you really want to close Sakura?"), npages);
 
576
 
 
577
                response=gtk_dialog_run(GTK_DIALOG(dialog));
 
578
                gtk_widget_destroy(dialog);
 
579
 
 
580
                if (response==GTK_RESPONSE_YES)
 
581
                        return FALSE;
 
582
                else {
 
583
                        return TRUE;
 
584
                }
 
585
        }
 
586
 
 
587
        return FALSE;
 
588
}
 
589
 
 
590
 
 
591
static void
 
592
sakura_destroy_window (GtkWidget *widget, void *data)
 
593
{
 
594
        sakura_destroy();
 
595
}
 
596
 
 
597
 
 
598
static void
 
599
sakura_font_dialog (GtkWidget *widget, void *data)
 
600
{
 
601
        GtkWidget *font_dialog;
 
602
        gint response;
 
603
 
 
604
        font_dialog=gtk_font_selection_dialog_new(_("Select font"));
 
605
        gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog),
 
606
                                                pango_font_description_to_string(sakura.font));
 
607
 
 
608
        response=gtk_dialog_run(GTK_DIALOG(font_dialog));
 
609
 
 
610
        if (response==GTK_RESPONSE_OK) {
 
611
                pango_font_description_free(sakura.font);
 
612
                sakura.font=pango_font_description_from_string(gtk_font_selection_dialog_get_font_name(GTK_FONT_SELECTION_DIALOG(font_dialog)));
 
613
                sakura_set_font();
 
614
                sakura_set_size(sakura.columns, sakura.rows);
 
615
                g_key_file_set_value(sakura.cfg, cfg_group, "font", pango_font_description_to_string(sakura.font));
 
616
        }
 
617
 
 
618
        gtk_widget_destroy(font_dialog);
 
619
}
 
620
 
 
621
 
 
622
static void
 
623
sakura_set_name_dialog (GtkWidget *widget, void *data)
 
624
{
 
625
        GtkWidget *input_dialog;
 
626
        GtkWidget *entry, *label;
 
627
        GtkWidget *name_hbox; /* We need this for correct spacing */
 
628
        gint response;
 
629
        int page;
 
630
        struct terminal *term;
 
631
 
 
632
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
633
        term = sakura_get_page_term(sakura, page);
 
634
 
 
635
        input_dialog=gtk_dialog_new_with_buttons(_("Set name"), GTK_WINDOW(sakura.main_window), GTK_DIALOG_MODAL,
 
636
                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
 
637
                                                 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT, NULL);
 
638
 
 
639
        gtk_dialog_set_default_response(GTK_DIALOG(input_dialog), GTK_RESPONSE_ACCEPT);
 
640
        gtk_window_set_modal(GTK_WINDOW(input_dialog), TRUE);
 
641
 
 
642
        /* Set style */
 
643
        gtk_widget_set_name (input_dialog, "set-name-dialog");
 
644
        gtk_rc_parse_string ("widget \"set-name-dialog\" style \"hig-dialog\"\n");
 
645
 
 
646
        name_hbox=gtk_hbox_new(FALSE, 0);
 
647
        entry=gtk_entry_new();
 
648
        label=gtk_label_new(_("New tab text"));
 
649
        /* Set tab label as entry default text */
 
650
        gtk_entry_set_text(GTK_ENTRY(entry), gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(sakura.notebook), term->hbox));
 
651
        gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
 
652
        gtk_box_pack_start(GTK_BOX(name_hbox), label, TRUE, TRUE, 12);
 
653
        gtk_box_pack_start(GTK_BOX(name_hbox), entry, TRUE, TRUE, 12);
 
654
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(input_dialog)->vbox), name_hbox, FALSE, FALSE, 12);
 
655
        /* Disable accept button until some text is entered */
 
656
        g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(sakura_setname_entry_changed), input_dialog);
 
657
        gtk_dialog_set_response_sensitive(GTK_DIALOG(input_dialog), GTK_RESPONSE_ACCEPT, FALSE);
 
658
 
 
659
        gtk_widget_show_all(name_hbox);
 
660
 
 
661
        response=gtk_dialog_run(GTK_DIALOG(input_dialog));
 
662
        if (response==GTK_RESPONSE_ACCEPT) {
 
663
                gtk_label_set_text(GTK_LABEL(term->label), gtk_entry_get_text(GTK_ENTRY(entry)));
 
664
        }
 
665
        gtk_widget_destroy(input_dialog);
 
666
}
 
667
 
 
668
 
 
669
static void
 
670
sakura_color_dialog (GtkWidget *widget, void *data)
 
671
{
 
672
        GtkWidget *color_dialog;
 
673
        GtkWidget *label1, *label2;
 
674
        GtkWidget *buttonfore, *buttonback;
 
675
        GtkWidget *hbox_fore, *hbox_back;
 
676
        gint response;
 
677
        int page;
 
678
        int i, n_pages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
679
        struct terminal *term;
 
680
 
 
681
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
682
        term = sakura_get_page_term(sakura, page);
 
683
 
 
684
        color_dialog=gtk_dialog_new_with_buttons(_("Select color"), GTK_WINDOW(sakura.main_window),
 
685
                                                                    GTK_DIALOG_MODAL,
 
686
                                                                    GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
 
687
                                                                    GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT, NULL);
 
688
 
 
689
        gtk_dialog_set_default_response(GTK_DIALOG(color_dialog), GTK_RESPONSE_ACCEPT);
 
690
        gtk_window_set_modal(GTK_WINDOW(color_dialog), TRUE);
 
691
        /* Set style */
 
692
        gtk_widget_set_name (color_dialog, "set-color-dialog");
 
693
        gtk_rc_parse_string ("widget \"set-color-dialog\" style \"hig-dialog\"\n");
 
694
 
 
695
        hbox_fore=gtk_hbox_new(FALSE, 12);
 
696
        hbox_back=gtk_hbox_new(FALSE, 12);
 
697
        label1=gtk_label_new(_("Select foreground color:"));
 
698
        label2=gtk_label_new(_("Select background color:"));
 
699
        buttonfore=gtk_color_button_new_with_color(&sakura.forecolor);
 
700
        buttonback=gtk_color_button_new_with_color(&sakura.backcolor);
 
701
 
 
702
        gtk_box_pack_start(GTK_BOX(hbox_fore), label1, FALSE, FALSE, 12);
 
703
        gtk_box_pack_end(GTK_BOX(hbox_fore), buttonfore, FALSE, FALSE, 12);
 
704
        gtk_box_pack_start(GTK_BOX(hbox_back), label2, FALSE, FALSE, 12);
 
705
        gtk_box_pack_end(GTK_BOX(hbox_back), buttonback, FALSE, FALSE, 12);
 
706
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(color_dialog)->vbox), hbox_fore, FALSE, FALSE, 6);
 
707
        gtk_box_pack_end(GTK_BOX(GTK_DIALOG(color_dialog)->vbox), hbox_back, FALSE, FALSE, 6);
 
708
 
 
709
        gtk_widget_show_all(GTK_DIALOG(color_dialog)->vbox);
 
710
 
 
711
        response=gtk_dialog_run(GTK_DIALOG(color_dialog));
 
712
 
 
713
        if (response==GTK_RESPONSE_ACCEPT) {
 
714
                gtk_color_button_get_color(GTK_COLOR_BUTTON(buttonfore), &sakura.forecolor);
 
715
                gtk_color_button_get_color(GTK_COLOR_BUTTON(buttonback), &sakura.backcolor);
 
716
 
 
717
                for (i = (n_pages - 1); i >= 0; i--) {
 
718
                        term = sakura_get_page_term(sakura, i);
 
719
                        vte_terminal_set_colors(VTE_TERMINAL(term->vte), &sakura.forecolor, &sakura.backcolor,
 
720
                                                sakura.palette, PALETTE_SIZE);
 
721
                }
 
722
 
 
723
                vte_terminal_set_colors(VTE_TERMINAL(term->vte), &sakura.forecolor, &sakura.backcolor,
 
724
                                        sakura.palette, PALETTE_SIZE);
 
725
 
 
726
                gchar *cfgtmp;
 
727
                cfgtmp = g_strdup_printf("#%02x%02x%02x", sakura.forecolor.red >>8,
 
728
                                         sakura.forecolor.green>>8, sakura.forecolor.blue>>8);
 
729
                g_key_file_set_value(sakura.cfg, cfg_group, "forecolor", cfgtmp);
 
730
                g_free(cfgtmp);
 
731
 
 
732
                cfgtmp = g_strdup_printf("#%02x%02x%02x", sakura.backcolor.red >>8,
 
733
                                         sakura.backcolor.green>>8, sakura.backcolor.blue>>8);
 
734
                g_key_file_set_value(sakura.cfg, cfg_group, "backcolor", cfgtmp);
 
735
                g_free(cfgtmp);
 
736
 
 
737
        }
 
738
 
 
739
        gtk_widget_destroy(color_dialog);
 
740
}
 
741
 
 
742
 
 
743
static void
 
744
sakura_opacity_check (GtkWidget *widget, void *data)
 
745
{
 
746
        bool state;
 
747
 
 
748
        state=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
 
749
 
 
750
        if (state) {
 
751
                /* Enable spinbutton */
 
752
                gtk_widget_set_sensitive(GTK_WIDGET(data), FALSE);
 
753
        } else {
 
754
                /* Disable spinbutton */
 
755
                gtk_widget_set_sensitive(GTK_WIDGET(data), TRUE);
 
756
        }
 
757
}
 
758
 
 
759
 
 
760
static void
 
761
sakura_opacity_dialog (GtkWidget *widget, void *data)
 
762
{
 
763
        GtkWidget *opacity_dialog, *spin_control, *spin_label, *check;
 
764
        GtkObject *spinner_adj;
 
765
        GtkWidget *dialog_hbox, *dialog_vbox, *dialog_spin_hbox;
 
766
        gint response;
 
767
        int page;
 
768
        struct terminal *term;
 
769
 
 
770
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
771
        term = sakura_get_page_term(sakura, page);
 
772
 
 
773
        opacity_dialog=gtk_dialog_new_with_buttons(_("Opacity"), GTK_WINDOW(sakura.main_window), GTK_DIALOG_MODAL,
 
774
                                             GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
 
775
                                                 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT, NULL);
 
776
        gtk_dialog_set_default_response(GTK_DIALOG(opacity_dialog), GTK_RESPONSE_ACCEPT);
 
777
        gtk_window_set_modal(GTK_WINDOW(opacity_dialog), TRUE);
 
778
        /* Set style */
 
779
        gtk_widget_set_name (opacity_dialog, "set-opacity-dialog");
 
780
        gtk_rc_parse_string ("widget \"set-opacity-dialog\" style \"hig-dialog\"\n");
 
781
 
 
782
        spinner_adj = gtk_adjustment_new (((1.0 - sakura.opacity_level) * 100), 0.0, 99.0, 1.0, 5.0, 5.0);
 
783
        spin_control = gtk_spin_button_new(GTK_ADJUSTMENT(spinner_adj), 1.0, 0);
 
784
 
 
785
        spin_label = gtk_label_new(_("Opacity level (%):"));
 
786
        check = gtk_check_button_new_with_label(_("Disable opacity"));
 
787
        dialog_hbox=gtk_hbox_new(FALSE, 0);
 
788
        dialog_vbox=gtk_vbox_new(FALSE, 0);
 
789
        dialog_spin_hbox=gtk_hbox_new(FALSE, 0);
 
790
 
 
791
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(opacity_dialog)->vbox), dialog_hbox, FALSE, FALSE, 6);
 
792
        gtk_box_pack_start(GTK_BOX(dialog_hbox), dialog_vbox, FALSE, FALSE, 12);
 
793
        gtk_box_pack_start(GTK_BOX(dialog_vbox), check, FALSE, FALSE, 6);
 
794
        gtk_box_pack_start(GTK_BOX(dialog_spin_hbox), spin_label, FALSE, FALSE, 6);
 
795
        gtk_box_pack_start(GTK_BOX(dialog_spin_hbox), spin_control, FALSE, FALSE, 6);
 
796
        gtk_box_pack_start(GTK_BOX(dialog_vbox), dialog_spin_hbox, TRUE, TRUE, 6);
 
797
 
 
798
        g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(sakura_opacity_check), spin_control);
 
799
 
 
800
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), !sakura.fake_transparency);
 
801
 
 
802
        gtk_widget_show_all(dialog_hbox);
 
803
 
 
804
        response=gtk_dialog_run(GTK_DIALOG(opacity_dialog));
 
805
        if (response==GTK_RESPONSE_ACCEPT) {
 
806
                char *value;
 
807
                int i, n_pages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
808
 
 
809
                value=g_strdup_printf("%d", gtk_spin_button_get_value_as_int((GtkSpinButton *) spin_control));
 
810
                sakura.opacity_level = ( ( 100 - (atof(value)) ) / 100 );
 
811
                sakura.opacity_level_percent = value;
 
812
                sakura.fake_transparency=!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check));
 
813
 
 
814
                if (sakura.fake_transparency) {
 
815
 
 
816
                        /* Set fake transparency for all tabs */
 
817
                        for (i = (n_pages - 1); i >= 0; i--) {
 
818
                                term = sakura_get_page_term(sakura, i);
 
819
                                vte_terminal_set_background_transparent(VTE_TERMINAL(term->vte), TRUE);
 
820
                                vte_terminal_set_background_saturation(VTE_TERMINAL(term->vte), sakura.opacity_level);
 
821
                        }
 
822
 
 
823
                        sakura.fake_transparency = TRUE;
 
824
                        g_key_file_set_value(sakura.cfg, cfg_group, "fake_transparency", "Yes");
 
825
                } else {
 
826
 
 
827
                        /* Unset fake transparency for all tabs */
 
828
                        for (i = (n_pages - 1); i >= 0; i--) {
 
829
                                term = sakura_get_page_term(sakura, i);
 
830
                                vte_terminal_set_background_transparent(VTE_TERMINAL(term->vte), FALSE);
 
831
                        }
 
832
 
 
833
                        sakura.fake_transparency = FALSE;
 
834
                        g_key_file_set_value(sakura.cfg, cfg_group, "fake_transparency", "No");
 
835
                }
 
836
 
 
837
                g_key_file_set_value(sakura.cfg, cfg_group, "opacity_level", sakura.opacity_level_percent);
 
838
        }
 
839
 
 
840
        gtk_widget_destroy(opacity_dialog);
 
841
}
 
842
 
 
843
 
 
844
static void
 
845
sakura_set_title_dialog (GtkWidget *widget, void *data)
 
846
{
 
847
        GtkWidget *title_dialog;
 
848
        GtkWidget *entry, *label;
 
849
        GtkWidget *title_hbox;
 
850
        gint response;
 
851
        int page;
 
852
        struct terminal *term;
 
853
 
 
854
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
855
        term = sakura_get_page_term(sakura, page);
 
856
 
 
857
        title_dialog=gtk_dialog_new_with_buttons(_("Set window title"), GTK_WINDOW(sakura.main_window), GTK_DIALOG_MODAL,
 
858
                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
 
859
                                                 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT, NULL);
 
860
 
 
861
        gtk_dialog_set_default_response(GTK_DIALOG(title_dialog), GTK_RESPONSE_ACCEPT);
 
862
        gtk_window_set_modal(GTK_WINDOW(title_dialog), TRUE);
 
863
        /* Set style */
 
864
        gtk_widget_set_name (title_dialog, "set-title-dialog");
 
865
        gtk_rc_parse_string ("widget \"set-title-dialog\" style \"hig-dialog\"\n");
 
866
 
 
867
        entry=gtk_entry_new();
 
868
        label=gtk_label_new(_("New window title"));
 
869
        title_hbox=gtk_hbox_new(FALSE, 0);
 
870
        /* Set window label as entry default text */
 
871
        gtk_entry_set_text(GTK_ENTRY(entry), gtk_window_get_title(GTK_WINDOW(sakura.main_window)));
 
872
        gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
 
873
        gtk_box_pack_start(GTK_BOX(title_hbox), label, TRUE, TRUE, 12);
 
874
        gtk_box_pack_start(GTK_BOX(title_hbox), entry, TRUE, TRUE, 12);
 
875
        gtk_box_pack_start(GTK_BOX(GTK_DIALOG(title_dialog)->vbox), title_hbox, FALSE, FALSE, 12);
 
876
        /* Disable accept button until some text is entered */
 
877
        g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(sakura_setname_entry_changed), title_dialog);
 
878
        gtk_dialog_set_response_sensitive(GTK_DIALOG(title_dialog), GTK_RESPONSE_ACCEPT, FALSE);
 
879
 
 
880
        gtk_widget_show_all(title_hbox);
 
881
 
 
882
        response=gtk_dialog_run(GTK_DIALOG(title_dialog));
 
883
        if (response==GTK_RESPONSE_ACCEPT) {
 
884
                gtk_window_set_title(GTK_WINDOW(sakura.main_window), gtk_entry_get_text(GTK_ENTRY(entry)));
 
885
        }
 
886
        gtk_widget_destroy(title_dialog);
 
887
 
 
888
}
 
889
 
 
890
 
 
891
static void
 
892
sakura_select_background_dialog (GtkWidget *widget, void *data)
 
893
{
 
894
        GtkWidget *dialog;
 
895
        gint response;
 
896
        gchar *filename;
 
897
 
 
898
        dialog = gtk_file_chooser_dialog_new (_("Select a background file"), GTK_WINDOW(sakura.main_window),
 
899
                                                                             GTK_FILE_CHOOSER_ACTION_OPEN,
 
900
                                                                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
901
                                                                             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
 
902
                                                                             NULL);
 
903
 
 
904
 
 
905
        response=gtk_dialog_run(GTK_DIALOG(dialog));
 
906
        if (response == GTK_RESPONSE_ACCEPT) {
 
907
                filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
908
                sakura.background=g_strdup(filename);
 
909
                sakura_set_bgimage(sakura.background);
 
910
                gtk_widget_show(sakura.item_clear_background);
 
911
                g_free(filename);
 
912
        }
 
913
 
 
914
        gtk_widget_destroy(dialog);
 
915
}
 
916
 
 
917
 
 
918
static void
 
919
sakura_copy_url (GtkWidget *widget, void *data)
 
920
{
 
921
        GtkClipboard* clip;
 
922
 
 
923
        clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
 
924
        gtk_clipboard_set_text(clip, sakura.current_match, -1 );
 
925
}
 
926
 
 
927
 
 
928
static void
 
929
sakura_open_url (GtkWidget *widget, void *data)
 
930
{
 
931
        GError *error=NULL;
 
932
        gchar *cmd;
 
933
        gchar *browser=NULL;
 
934
 
 
935
        browser=(gchar *)g_getenv("BROWSER");
 
936
 
 
937
        if (browser) {
 
938
                cmd=g_strdup_printf("%s %s", browser, sakura.current_match);
 
939
        } else {
 
940
                if ( (browser = g_find_program_in_path("xdg-open")) ) {
 
941
                        cmd=g_strdup_printf("%s %s", browser, sakura.current_match);
 
942
                        g_free( browser );
 
943
                } else
 
944
                        cmd=g_strdup_printf("firefox %s", sakura.current_match);
 
945
        }
 
946
 
 
947
        if (!g_spawn_command_line_async(cmd, &error)) {
 
948
                sakura_error("Couldn't exec \"%s\": %s", cmd, error->message);
 
949
        }
 
950
 
 
951
        g_free(cmd);
 
952
}
 
953
 
 
954
 
 
955
static void
 
956
sakura_clear (GtkWidget *widget, void *data)
 
957
{
 
958
        int page;
 
959
        struct terminal *term;
 
960
 
 
961
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
962
        term = sakura_get_page_term(sakura, page);
 
963
 
 
964
        gtk_widget_hide(sakura.item_clear_background);
 
965
 
 
966
        vte_terminal_set_background_image(VTE_TERMINAL(term->vte), NULL);
 
967
 
 
968
        // FIXME: is this really needed? IMHO, this should be done just before
 
969
        // dumping the config to the config file.
 
970
        g_key_file_set_value(sakura.cfg, cfg_group, "background", "none");
 
971
 
 
972
        g_free(sakura.background);
 
973
        sakura.background=NULL;
 
974
}
 
975
 
 
976
 
 
977
static void
 
978
sakura_show_first_tab (GtkWidget *widget, void *data)
 
979
{
 
980
        int page;
 
981
        struct terminal *term;
 
982
 
 
983
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
984
        term = sakura_get_page_term(sakura, page);
 
985
 
 
986
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
 
987
                gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), TRUE);
 
988
                g_key_file_set_value(sakura.cfg, cfg_group, "show_always_first_tab", "Yes");
 
989
        } else {
 
990
                /* Only hide tabs if the notebook has one page */
 
991
                if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook)) == 1) {
 
992
                        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), FALSE);
 
993
                }
 
994
                g_key_file_set_value(sakura.cfg, cfg_group, "show_always_first_tab", "No");
 
995
        }
 
996
}
 
997
 
 
998
 
 
999
static void
 
1000
sakura_show_close_button (GtkWidget *widget, void *data)
 
1001
{
 
1002
        int page;
 
1003
        struct terminal *term;
 
1004
 
 
1005
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1006
        term = sakura_get_page_term(sakura, page);
 
1007
 
 
1008
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
 
1009
                g_key_file_set_boolean(sakura.cfg, cfg_group, "closebutton", TRUE);
 
1010
        } else {
 
1011
                g_key_file_set_boolean(sakura.cfg, cfg_group, "closebutton", FALSE);
 
1012
        }
 
1013
}
 
1014
 
 
1015
 
 
1016
static void
 
1017
sakura_show_scrollbar (GtkWidget *widget, void *data)
 
1018
{
 
1019
        int page;
 
1020
        struct terminal *term;
 
1021
        int n_pages;
 
1022
        int i;
 
1023
 
 
1024
        sakura.keep_fc=1;
 
1025
 
 
1026
        n_pages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
1027
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1028
        term = sakura_get_page_term(sakura, page);
 
1029
 
 
1030
        if (!g_key_file_get_boolean(sakura.cfg, cfg_group, "scrollbar", NULL)) {
 
1031
                sakura.show_scrollbar=true;
 
1032
                g_key_file_set_boolean(sakura.cfg, cfg_group, "scrollbar", TRUE);
 
1033
        } else {
 
1034
                sakura.show_scrollbar=false;
 
1035
                g_key_file_set_boolean(sakura.cfg, cfg_group, "scrollbar", FALSE);
 
1036
        }
 
1037
 
 
1038
        /* Toggle/Untoggle the scrollbar for all tabs */
 
1039
        for (i = (n_pages - 1); i >= 0; i--) {
 
1040
                term = sakura_get_page_term(sakura, i);
 
1041
                if (!sakura.show_scrollbar)
 
1042
                        gtk_widget_hide(term->scrollbar);
 
1043
                else
 
1044
                        gtk_widget_show(term->scrollbar);
 
1045
        }
 
1046
}
 
1047
 
 
1048
 
 
1049
static void
 
1050
sakura_audible_bell (GtkWidget *widget, void *data)
 
1051
{
 
1052
        int page;
 
1053
        struct terminal *term;
 
1054
 
 
1055
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1056
        term = sakura_get_page_term(sakura, page);
 
1057
 
 
1058
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
 
1059
                vte_terminal_set_audible_bell (VTE_TERMINAL(term->vte), TRUE);
 
1060
                g_key_file_set_value(sakura.cfg, cfg_group, "audible_bell", "Yes");
 
1061
        } else {
 
1062
                vte_terminal_set_audible_bell (VTE_TERMINAL(term->vte), FALSE);
 
1063
                g_key_file_set_value(sakura.cfg, cfg_group, "audible_bell", "No");
 
1064
        }
 
1065
}
 
1066
 
 
1067
 
 
1068
static void
 
1069
sakura_visible_bell (GtkWidget *widget, void *data)
 
1070
{
 
1071
        int page;
 
1072
        struct terminal *term;
 
1073
 
 
1074
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1075
        term = sakura_get_page_term(sakura, page);
 
1076
 
 
1077
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
 
1078
                vte_terminal_set_visible_bell (VTE_TERMINAL(term->vte), TRUE);
 
1079
                g_key_file_set_value(sakura.cfg, cfg_group, "visible_bell", "Yes");
 
1080
        } else {
 
1081
                vte_terminal_set_visible_bell (VTE_TERMINAL(term->vte), FALSE);
 
1082
                g_key_file_set_value(sakura.cfg, cfg_group, "visible_bell", "No");
 
1083
        }
 
1084
}
 
1085
 
 
1086
 
 
1087
static void
 
1088
sakura_blinking_cursor (GtkWidget *widget, void *data)
 
1089
{
 
1090
        int page;
 
1091
        struct terminal *term;
 
1092
 
 
1093
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1094
        term = sakura_get_page_term(sakura, page);
 
1095
 
 
1096
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
 
1097
                vte_terminal_set_cursor_blink_mode (VTE_TERMINAL(term->vte), VTE_CURSOR_BLINK_ON);
 
1098
                g_key_file_set_value(sakura.cfg, cfg_group, "blinking_cursor", "Yes");
 
1099
        } else {
 
1100
                vte_terminal_set_cursor_blink_mode (VTE_TERMINAL(term->vte), VTE_CURSOR_BLINK_OFF);
 
1101
                g_key_file_set_value(sakura.cfg, cfg_group, "blinking_cursor", "No");
 
1102
        }
 
1103
}
 
1104
 
 
1105
 
 
1106
static void
 
1107
sakura_set_palette(GtkWidget *widget, void *data)
 
1108
{
 
1109
        struct terminal *term;
 
1110
        int n_pages, i;
 
1111
 
 
1112
        char *palette=(char *)data;
 
1113
 
 
1114
        n_pages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
1115
 
 
1116
        if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
 
1117
                if (strcmp(palette, "linux")==0) {
 
1118
                        sakura.palette=linux_palette;
 
1119
                } else if (strcmp(palette, "tango")==0) {
 
1120
                        sakura.palette=tango_palette;
 
1121
                } else if (strcmp(palette, "xterm")==0) {
 
1122
                        sakura.palette=xterm_palette;
 
1123
                } else {
 
1124
                        sakura.palette=rxvt_palette;
 
1125
                }
 
1126
 
 
1127
                for (i = (n_pages - 1); i >= 0; i--) {
 
1128
                        term = sakura_get_page_term(sakura, i);
 
1129
                        vte_terminal_set_colors(VTE_TERMINAL(term->vte), &sakura.forecolor, &sakura.backcolor,
 
1130
                                                sakura.palette, PALETTE_SIZE);
 
1131
                }
 
1132
 
 
1133
                g_key_file_set_value(sakura.cfg, cfg_group, "palette", palette);
 
1134
        }
 
1135
}
 
1136
 
 
1137
 
 
1138
/* Every the window changes its size by an user action (resize, fullscreen), calculate
 
1139
 * the new values for the number of columns and rows */
 
1140
static void
 
1141
sakura_calculate_row_col (gint width, gint height)
 
1142
{
 
1143
        struct terminal *term;
 
1144
        gint x_padding, y_padding;
 
1145
        gint n_pages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
1146
 
 
1147
        if (n_pages==-1) return;
 
1148
 
 
1149
        SAY("Calculating row_col");
 
1150
        term = sakura_get_page_term(sakura, 0);
 
1151
 
 
1152
        /* This is to prevent a race with ConfigureEvents when the window is being destroyed */
 
1153
        if (!VTE_IS_TERMINAL(term->vte)) return;
 
1154
 
 
1155
        vte_terminal_get_padding( VTE_TERMINAL(term->vte), &x_padding, &y_padding );
 
1156
        sakura.char_width = vte_terminal_get_char_width(VTE_TERMINAL(term->vte));
 
1157
        sakura.char_height = vte_terminal_get_char_height(VTE_TERMINAL(term->vte));
 
1158
        /* Ignore resize events in sakura window is in fullscreen */
 
1159
        if (!sakura.keep_fc) {  
 
1160
                /* We cannot trust in vte allocation values, they're unreliable */
 
1161
                /* FIXME: Round values properly */
 
1162
                sakura.columns = (width/sakura.char_width);
 
1163
                sakura.rows = (height/sakura.char_height);
 
1164
                sakura.keep_fc=false;
 
1165
                SAY("new columns %ld and rows %ld", sakura.columns, sakura.rows);
 
1166
        }
 
1167
        sakura.width = sakura.main_window->allocation.width + x_padding;
 
1168
        sakura.height = sakura.main_window->allocation.height + y_padding;
 
1169
        //}
 
1170
}
 
1171
 
 
1172
 
 
1173
/* Retrieve the cwd of the specified term page.
 
1174
 * Original function was from terminal-screen.c of gnome-terminal, copyright (C) 2001 Havoc Pennington
 
1175
 * Adapted by Hong Jen Yee, non-linux shit removed by David Gómez */
 
1176
static char*
 
1177
sakura_get_term_cwd(struct terminal* term)
 
1178
{
 
1179
        char *cwd = NULL;
 
1180
 
 
1181
        if (term->pid >= 0) {
 
1182
                char *file;
 
1183
                char buf[PATH_MAX+1];
 
1184
                int len;
 
1185
 
 
1186
                file = g_strdup_printf ("/proc/%d/cwd", term->pid);
 
1187
                len = readlink (file, buf, sizeof (buf) - 1);
 
1188
 
 
1189
                if (len > 0 && buf[0] == '/') {
 
1190
                        buf[len] = '\0';
 
1191
                        cwd = g_strdup(buf);
 
1192
                }
 
1193
 
 
1194
                g_free(file);
 
1195
        }
 
1196
 
 
1197
        return cwd;
 
1198
}
 
1199
 
 
1200
 
 
1201
static gboolean
 
1202
sakura_resized_window (GtkWidget *widget, GdkEventConfigure *event, void *data)
 
1203
{
 
1204
        if (event->width!=sakura.width || event->height!=sakura.height) {
 
1205
                SAY("sakura w & h %d %d event w & h %d %d",
 
1206
                sakura.width, sakura.height, event->width, event->height);
 
1207
                /* Window has been resized by the user. Recalculate sizes */
 
1208
                sakura_calculate_row_col (event->width, event->height);
 
1209
        } 
 
1210
 
 
1211
        return FALSE;
 
1212
}
 
1213
 
 
1214
 
 
1215
static void
 
1216
sakura_setname_entry_changed (GtkWidget *widget, void *data)
 
1217
{
 
1218
        GtkDialog *title_dialog=(GtkDialog *)data;
 
1219
 
 
1220
        if (strcmp(gtk_entry_get_text(GTK_ENTRY(widget)), "")==0) {
 
1221
                gtk_dialog_set_response_sensitive(GTK_DIALOG(title_dialog), GTK_RESPONSE_ACCEPT, FALSE);
 
1222
        } else {
 
1223
                gtk_dialog_set_response_sensitive(GTK_DIALOG(title_dialog), GTK_RESPONSE_ACCEPT, TRUE);
 
1224
        }
 
1225
}
 
1226
 
 
1227
 
 
1228
/* Parameters are never used */
 
1229
static void
 
1230
sakura_copy (GtkWidget *widget, void *data)
 
1231
{
 
1232
        int page;
 
1233
        struct terminal *term;
 
1234
 
 
1235
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1236
        term = sakura_get_page_term(sakura, page);
 
1237
 
 
1238
        vte_terminal_copy_clipboard(VTE_TERMINAL(term->vte));
 
1239
}
 
1240
 
 
1241
 
 
1242
/* Parameters are never used */
 
1243
static void
 
1244
sakura_paste (GtkWidget *widget, void *data)
 
1245
{
 
1246
        int page;
 
1247
        struct terminal *term;
 
1248
 
 
1249
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1250
        term = sakura_get_page_term(sakura, page);
 
1251
 
 
1252
        vte_terminal_paste_clipboard(VTE_TERMINAL(term->vte));
 
1253
}
 
1254
 
 
1255
 
 
1256
static void
 
1257
sakura_new_tab (GtkWidget *widget, void *data)
 
1258
{
 
1259
        sakura_add_tab();
 
1260
}
 
1261
 
 
1262
 
 
1263
static void
 
1264
sakura_close_tab (GtkWidget *widget, void *data)
 
1265
{
 
1266
        gint page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1267
 
 
1268
        sakura_del_tab(page);
 
1269
 
 
1270
        if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook))==0)
 
1271
                sakura_destroy();
 
1272
}
 
1273
 
 
1274
 
 
1275
static void
 
1276
sakura_full_screen (GtkWidget *widget, void *data)
 
1277
{
 
1278
        if (sakura.full_screen!=TRUE) {
 
1279
                sakura.full_screen=TRUE;
 
1280
                gtk_window_fullscreen(GTK_WINDOW(sakura.main_window));
 
1281
        } else {
 
1282
                gtk_window_unfullscreen(GTK_WINDOW(sakura.main_window));
 
1283
                sakura.full_screen=FALSE;
 
1284
        }
 
1285
}
 
1286
 
 
1287
 
 
1288
/* Callback for the tabs close buttons */
 
1289
static void
 
1290
sakura_closebutton_clicked(GtkWidget *widget, void *data)
 
1291
{
 
1292
        gint page;
 
1293
        GtkWidget *hbox=(GtkWidget *)data;
 
1294
 
 
1295
        page = gtk_notebook_page_num(GTK_NOTEBOOK(sakura.notebook), hbox);
 
1296
        sakura_del_tab(page);
 
1297
 
 
1298
        if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook))==0)
 
1299
                sakura_destroy();
 
1300
}
 
1301
 
 
1302
 
 
1303
/******* Functions ********/
 
1304
 
 
1305
static void
 
1306
sakura_init()
 
1307
{
 
1308
        GError *gerror=NULL;
 
1309
        char* configdir = NULL;
 
1310
 
 
1311
        term_data_id = g_quark_from_static_string("sakura_term");
 
1312
 
 
1313
        /* Config file initialization*/
 
1314
        sakura.cfg = g_key_file_new();
 
1315
 
 
1316
        configdir = g_build_filename( g_get_user_config_dir(), "sakura", NULL );
 
1317
        if( ! g_file_test( g_get_user_config_dir(), G_FILE_TEST_EXISTS) )
 
1318
                g_mkdir( g_get_user_config_dir(), 0755 );
 
1319
        if( ! g_file_test( configdir, G_FILE_TEST_EXISTS) )
 
1320
                g_mkdir( configdir, 0755 );
 
1321
        /* Use more standard-conforming path for config files, if available. */
 
1322
        sakura.configfile=g_build_filename(configdir, CONFIGFILE, NULL);
 
1323
        g_free(configdir);
 
1324
 
 
1325
        if (!g_key_file_load_from_file(sakura.cfg, sakura.configfile, 0, &gerror)) {
 
1326
                char *file_contents;
 
1327
                char *new_file_contents;
 
1328
 
 
1329
                /* Workaround for cfgpool to g_key_file update. We update the config
 
1330
                 * file here if needed. This support should be removed in future
 
1331
                 * versions (3.0?) as everyone is supposed to be using a recent (no cfgpool)
 
1332
                 * sakura release in the future */
 
1333
                rename(sakura.configfile, "/tmp/sakura.cfg.old");
 
1334
                g_file_get_contents("/tmp/sakura.cfg.old", &file_contents, NULL, NULL);
 
1335
                new_file_contents=g_strconcat("[sakura]\n", file_contents, NULL);
 
1336
                g_file_set_contents(sakura.configfile, new_file_contents, strlen(new_file_contents), NULL);
 
1337
                g_free(file_contents); g_free(new_file_contents);
 
1338
                unlink("/tmp/sakura.cfg.old");
 
1339
                g_key_file_load_from_file(sakura.cfg, sakura.configfile, 0, &gerror);
 
1340
        }
 
1341
 
 
1342
 
 
1343
        /* Add default values if needed */
 
1344
        gchar *cfgtmp = NULL;
 
1345
 
 
1346
        /* We can safely ignore errors from g_key_file_get_value(), since if the
 
1347
         * call to g_key_file_has_key() was successful, the key IS there. From the
 
1348
         * glib docs I don't know if we can ignore errors from g_key_file_has_key,
 
1349
         * too. I think we can: the only possible error is that the config file
 
1350
         * doesn't exist, but we have just read it!
 
1351
         */
 
1352
 
 
1353
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "forecolor", NULL)) {
 
1354
                g_key_file_set_value(sakura.cfg, cfg_group, "forecolor", "#c0c0c0");
 
1355
        }
 
1356
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "forecolor", NULL);
 
1357
        gdk_color_parse(cfgtmp, &sakura.forecolor);
 
1358
        g_free(cfgtmp);
 
1359
 
 
1360
 
 
1361
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "backcolor", NULL)) {
 
1362
                g_key_file_set_value(sakura.cfg, cfg_group, "backcolor", "#000000");
 
1363
        }
 
1364
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "backcolor", NULL);
 
1365
        gdk_color_parse(cfgtmp, &sakura.backcolor);
 
1366
        g_free(cfgtmp);
 
1367
 
 
1368
 
 
1369
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "opacity_level", NULL)) {
 
1370
                g_key_file_set_value(sakura.cfg, cfg_group, "opacity_level", "80");
 
1371
        }
 
1372
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "opacity_level", NULL);
 
1373
        sakura.opacity_level_percent=cfgtmp;
 
1374
        sakura.opacity_level=( ( 100 - (atof(cfgtmp)) ) / 100 );
 
1375
        g_free(cfgtmp);
 
1376
 
 
1377
 
 
1378
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "fake_transparency", NULL)) {
 
1379
                g_key_file_set_value(sakura.cfg, cfg_group, "fake_transparency", "No");
 
1380
        }
 
1381
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "fake_transparency", NULL);
 
1382
        if (strcmp(cfgtmp, "Yes")==0) {
 
1383
                sakura.fake_transparency=1;
 
1384
        } else {
 
1385
                sakura.fake_transparency=0;
 
1386
        }
 
1387
        g_free(cfgtmp);
 
1388
 
 
1389
 
 
1390
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "background", NULL)) {
 
1391
                g_key_file_set_value(sakura.cfg, cfg_group, "background", "none");
 
1392
        }
 
1393
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "background", NULL);
 
1394
        if (strcmp(cfgtmp, "none")==0) {
 
1395
                sakura.background=NULL;
 
1396
        } else {
 
1397
                sakura.background=g_strdup(cfgtmp);
 
1398
        }
 
1399
        g_free(cfgtmp);
 
1400
 
 
1401
 
 
1402
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "font", NULL)) {
 
1403
                g_key_file_set_value(sakura.cfg, cfg_group, "font", DEFAULT_FONT);
 
1404
        }
 
1405
 
 
1406
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "show_always_first_tab", NULL)) {
 
1407
                g_key_file_set_value(sakura.cfg, cfg_group, "show_always_first_tab", "No");
 
1408
        }
 
1409
 
 
1410
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "scrollbar", NULL)) {
 
1411
                g_key_file_set_boolean(sakura.cfg, cfg_group, "scrollbar", FALSE);
 
1412
        }
 
1413
        sakura.show_scrollbar = g_key_file_get_boolean(sakura.cfg, cfg_group, "scrollbar", NULL);
 
1414
 
 
1415
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "closebutton", NULL)) {
 
1416
                g_key_file_set_boolean(sakura.cfg, cfg_group, "closebutton", FALSE);
 
1417
        }
 
1418
        sakura.show_closebutton = g_key_file_get_boolean(sakura.cfg, cfg_group, "closebutton", NULL);
 
1419
 
 
1420
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "audible_bell", NULL)) {
 
1421
                g_key_file_set_value(sakura.cfg, cfg_group, "audible_bell", "Yes");
 
1422
        }
 
1423
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "audible_bell", NULL);
 
1424
        sakura.audible_bell= (strcmp(cfgtmp, "Yes")==0) ? 1 : 0;
 
1425
        g_free(cfgtmp);
 
1426
 
 
1427
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "visible_bell", NULL)) {
 
1428
                g_key_file_set_value(sakura.cfg, cfg_group, "visible_bell", "No");
 
1429
        }
 
1430
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "visible_bell", NULL);
 
1431
        sakura.visible_bell= (strcmp(cfgtmp, "Yes")==0) ? 1 : 0;
 
1432
        g_free(cfgtmp);
 
1433
 
 
1434
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "blinking_cursor", NULL)) {
 
1435
                g_key_file_set_value(sakura.cfg, cfg_group, "blinking_cursor", "No");
 
1436
        }
 
1437
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "blinking_cursor", NULL);
 
1438
        sakura.blinking_cursor= (strcmp(cfgtmp, "Yes")==0) ? 1 : 0;
 
1439
        g_free(cfgtmp);
 
1440
 
 
1441
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "word_chars", NULL)) {
 
1442
                g_key_file_set_value(sakura.cfg, cfg_group, "word_chars", DEFAULT_WORD_CHARS);
 
1443
        }
 
1444
        sakura.word_chars = g_key_file_get_value(sakura.cfg, cfg_group, "word_chars", NULL);
 
1445
 
 
1446
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "palette", NULL)) {
 
1447
                g_key_file_set_value(sakura.cfg, cfg_group, "palette", DEFAULT_PALETTE);
 
1448
        }
 
1449
        cfgtmp = g_key_file_get_string(sakura.cfg, cfg_group, "palette", NULL);
 
1450
        if (strcmp(cfgtmp, "linux")==0) {
 
1451
                sakura.palette=linux_palette;
 
1452
        } else if (strcmp(cfgtmp, "tango")==0) {
 
1453
                sakura.palette=tango_palette;
 
1454
        } else if (strcmp(cfgtmp, "xterm")==0) {
 
1455
                sakura.palette=xterm_palette;
 
1456
        } else {
 
1457
                sakura.palette=rxvt_palette;
 
1458
        }
 
1459
        g_free(cfgtmp);
 
1460
 
 
1461
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "add_tab_accelerator", NULL)) {
 
1462
                g_key_file_set_integer(sakura.cfg, cfg_group, "add_tab_accelerator", DEFAULT_ADD_TAB_ACCELERATOR);
 
1463
        }
 
1464
        sakura.add_tab_accelerator = g_key_file_get_integer(sakura.cfg, cfg_group, "add_tab_accelerator", NULL);
 
1465
 
 
1466
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "del_tab_accelerator", NULL)) {
 
1467
                g_key_file_set_integer(sakura.cfg, cfg_group, "del_tab_accelerator", DEFAULT_DEL_TAB_ACCELERATOR);
 
1468
        }
 
1469
        sakura.del_tab_accelerator = g_key_file_get_integer(sakura.cfg, cfg_group, "del_tab_accelerator", NULL);
 
1470
 
 
1471
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "switch_tab_accelerator", NULL)) {
 
1472
                g_key_file_set_integer(sakura.cfg, cfg_group, "switch_tab_accelerator", DEFAULT_SWITCH_TAB_ACCELERATOR);
 
1473
        }
 
1474
        sakura.switch_tab_accelerator = g_key_file_get_integer(sakura.cfg, cfg_group, "switch_tab_accelerator", NULL);
 
1475
 
 
1476
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "copy_accelerator", NULL)) {
 
1477
                g_key_file_set_integer(sakura.cfg, cfg_group, "copy_accelerator", DEFAULT_COPY_ACCELERATOR);
 
1478
        }
 
1479
        sakura.copy_accelerator = g_key_file_get_integer(sakura.cfg, cfg_group, "copy_accelerator", NULL);
 
1480
 
 
1481
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "scrollbar_accelerator", NULL)) {
 
1482
                g_key_file_set_integer(sakura.cfg, cfg_group, "scrollbar_accelerator", DEFAULT_SCROLLBAR_ACCELERATOR);
 
1483
        }
 
1484
        sakura.scrollbar_accelerator = g_key_file_get_integer(sakura.cfg, cfg_group, "scrollbar_accelerator", NULL);
 
1485
        
 
1486
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "open_url_accelerator", NULL)) {
 
1487
                g_key_file_set_integer(sakura.cfg, cfg_group, "open_url_accelerator", DEFAULT_OPEN_URL_ACCELERATOR);
 
1488
        }
 
1489
        sakura.open_url_accelerator = g_key_file_get_integer(sakura.cfg, cfg_group, "open_url_accelerator", NULL);
 
1490
 
 
1491
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "add_tab_key", NULL)) {
 
1492
                sakura_key_file_set_key(sakura.cfg, cfg_group, "add_tab_key", DEFAULT_ADD_TAB_KEY);
 
1493
        }
 
1494
        sakura.add_tab_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "add_tab_key");
 
1495
 
 
1496
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "del_tab_key", NULL)) {
 
1497
                sakura_key_file_set_key(sakura.cfg, cfg_group, "del_tab_key", DEFAULT_DEL_TAB_KEY);
 
1498
        }
 
1499
        sakura.del_tab_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "del_tab_key");
 
1500
 
 
1501
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "prev_tab_key", NULL)) {
 
1502
                sakura_key_file_set_key(sakura.cfg, cfg_group, "prev_tab_key", DEFAULT_PREV_TAB_KEY);
 
1503
        }
 
1504
        sakura.prev_tab_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "prev_tab_key");
 
1505
 
 
1506
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "next_tab_key", NULL)) {
 
1507
                sakura_key_file_set_key(sakura.cfg, cfg_group, "next_tab_key", DEFAULT_NEXT_TAB_KEY);
 
1508
        }
 
1509
        sakura.next_tab_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "next_tab_key");
 
1510
 
 
1511
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "copy_key", NULL)) {
 
1512
                sakura_key_file_set_key(sakura.cfg, cfg_group, "copy_key", DEFAULT_COPY_KEY);
 
1513
        }
 
1514
        sakura.copy_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "copy_key");
 
1515
 
 
1516
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "paste_key", NULL)) {
 
1517
                sakura_key_file_set_key(sakura.cfg, cfg_group, "paste_key", DEFAULT_PASTE_KEY);
 
1518
        }
 
1519
        sakura.paste_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "paste_key");
 
1520
 
 
1521
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "scrollbar_key", NULL)) {
 
1522
                sakura_key_file_set_key(sakura.cfg, cfg_group, "scrollbar_key", DEFAULT_SCROLLBAR_KEY);
 
1523
        }
 
1524
        sakura.scrollbar_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "scrollbar_key");
 
1525
 
 
1526
        if (!g_key_file_has_key(sakura.cfg, cfg_group, "fullscreen_key", NULL)) {
 
1527
                sakura_key_file_set_key(sakura.cfg, cfg_group, "fullscreen_key", DEFAULT_FULLSCREEN_KEY);
 
1528
        }
 
1529
        sakura.fullscreen_key = sakura_key_file_get_key(sakura.cfg, cfg_group, "fullscreen_key");
 
1530
 
 
1531
        /* Set dialog style */
 
1532
        gtk_rc_parse_string ("style \"hig-dialog\" {\n"
 
1533
                             "GtkDialog::action-area-border = 12\n"
 
1534
                         "GtkDialog::button-spacing = 12\n"
 
1535
                         "}\n");
 
1536
 
 
1537
        sakura.main_window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
1538
        gtk_window_set_title(GTK_WINDOW(sakura.main_window), "sakura");
 
1539
        gtk_window_set_icon_from_file(GTK_WINDOW(sakura.main_window), DATADIR "/pixmaps/" ICON_FILE, &gerror);
 
1540
        /* Default terminal size*/
 
1541
        sakura.columns = DEFAULT_COLUMNS;
 
1542
        sakura.rows = DEFAULT_ROWS;
 
1543
 
 
1544
        sakura.notebook=gtk_notebook_new();
 
1545
 
 
1546
        /* Set argv for forked childs */
 
1547
        if (option_login) {
 
1548
                sakura.argv[0]=g_strdup_printf("-%s", g_getenv("SHELL"));
 
1549
        } else {
 
1550
                sakura.argv[0]=g_strdup(g_getenv("SHELL"));
 
1551
        }
 
1552
        sakura.argv[1]=NULL;
 
1553
 
 
1554
        if (option_title) {
 
1555
                gtk_window_set_title(GTK_WINDOW(sakura.main_window), option_title);
 
1556
        }
 
1557
 
 
1558
        if (option_columns) {
 
1559
                sakura.columns = option_columns;
 
1560
        }
 
1561
 
 
1562
        if (option_rows) {
 
1563
                sakura.rows = option_rows;
 
1564
        }
 
1565
 
 
1566
        if (option_font) {
 
1567
                sakura.font=pango_font_description_from_string(option_font);
 
1568
        } else {
 
1569
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "font", NULL);
 
1570
                sakura.font = pango_font_description_from_string(cfgtmp);
 
1571
                free(cfgtmp);
 
1572
        }
 
1573
 
 
1574
        sakura.menu=gtk_menu_new();
 
1575
        sakura.label_count=1;
 
1576
        sakura.full_screen=FALSE;
 
1577
        sakura.keep_fc=false;
 
1578
 
 
1579
        gerror=NULL;
 
1580
        sakura.http_regexp=g_regex_new(HTTP_REGEXP, G_REGEX_CASELESS, G_REGEX_MATCH_NOTEMPTY, &gerror);
 
1581
 
 
1582
        gtk_container_add(GTK_CONTAINER(sakura.main_window), sakura.notebook);
 
1583
 
 
1584
        /* Init notebook */
 
1585
        gtk_notebook_set_scrollable(GTK_NOTEBOOK(sakura.notebook), TRUE);
 
1586
 
 
1587
        sakura_init_popup();
 
1588
 
 
1589
        g_signal_connect(G_OBJECT(sakura.main_window), "delete_event", G_CALLBACK(sakura_delete_window), NULL);
 
1590
        g_signal_connect(G_OBJECT(sakura.main_window), "destroy", G_CALLBACK(sakura_destroy_window), NULL);
 
1591
        g_signal_connect(G_OBJECT(sakura.main_window), "key-press-event", G_CALLBACK(sakura_key_press), NULL);
 
1592
        g_signal_connect(G_OBJECT(sakura.main_window), "configure-event", G_CALLBACK(sakura_resized_window), NULL);
 
1593
}
 
1594
 
 
1595
 
 
1596
static void
 
1597
sakura_init_popup()
 
1598
{
 
1599
        GtkWidget *item_new_tab, *item_set_name, *item_close_tab, *item_copy,
 
1600
                  *item_paste, *item_select_font, *item_select_colors,
 
1601
                  *item_select_background, *item_set_title, *item_full_screen,
 
1602
                  *item_toggle_scrollbar, *item_options, *item_input_methods,
 
1603
                  *item_opacity_menu, *item_show_first_tab, *item_audible_bell, *item_visible_bell,
 
1604
                  *item_blinking_cursor,
 
1605
                  *item_palette, *item_palette_tango, *item_palette_linux, *item_palette_xterm, *item_palette_rxvt,
 
1606
                  *item_show_close_button;
 
1607
        GtkAction *action_open_link, *action_copy_link, *action_new_tab, *action_set_name, *action_close_tab,
 
1608
                  *action_copy, *action_paste, *action_select_font, *action_select_colors,
 
1609
                  *action_select_background, *action_clear_background, *action_opacity, *action_set_title,
 
1610
                  *action_full_screen;
 
1611
        GtkWidget *options_menu, *palette_menu;
 
1612
 
 
1613
        /* Define actions */
 
1614
        action_open_link=gtk_action_new("open_link", _("Open link..."), NULL, NULL);
 
1615
        action_copy_link=gtk_action_new("copy_link", _("Copy link..."), NULL, NULL);
 
1616
        action_new_tab=gtk_action_new("new_tab", _("New tab"), NULL, GTK_STOCK_NEW);
 
1617
        action_set_name=gtk_action_new("set_name", _("Set name..."), NULL, NULL);
 
1618
        action_close_tab=gtk_action_new("close_tab", _("Close tab"), NULL, GTK_STOCK_CLOSE);
 
1619
        action_full_screen=gtk_action_new("full_screen", _("Full screen"), NULL, GTK_STOCK_FULLSCREEN);
 
1620
        action_copy=gtk_action_new("copy", _("Copy"), NULL, GTK_STOCK_COPY);
 
1621
        action_paste=gtk_action_new("paste", _("Paste"), NULL, GTK_STOCK_PASTE);
 
1622
        action_select_font=gtk_action_new("select_font", _("Select font..."), NULL, GTK_STOCK_SELECT_FONT);
 
1623
        action_select_colors=gtk_action_new("select_colors", _("Select colors..."), NULL, GTK_STOCK_SELECT_COLOR);
 
1624
        action_select_background=gtk_action_new("select_background", _("Select background..."), NULL, NULL);
 
1625
        action_clear_background=gtk_action_new("clear_background", _("Clear background"), NULL, NULL);
 
1626
        action_opacity=gtk_action_new("set_opacity", _("Set opacity level..."), NULL, NULL);
 
1627
        action_set_title=gtk_action_new("set_title", _("Set window title..."), NULL, NULL);
 
1628
 
 
1629
        /* Create menuitems */
 
1630
        sakura.item_open_link=gtk_action_create_menu_item(action_open_link);
 
1631
        sakura.item_copy_link=gtk_action_create_menu_item(action_copy_link);
 
1632
        item_new_tab=gtk_action_create_menu_item(action_new_tab);
 
1633
        item_set_name=gtk_action_create_menu_item(action_set_name);
 
1634
        item_close_tab=gtk_action_create_menu_item(action_close_tab);
 
1635
        item_full_screen=gtk_action_create_menu_item(action_full_screen);
 
1636
        item_copy=gtk_action_create_menu_item(action_copy);
 
1637
        item_paste=gtk_action_create_menu_item(action_paste);
 
1638
        item_select_font=gtk_action_create_menu_item(action_select_font);
 
1639
        item_select_colors=gtk_action_create_menu_item(action_select_colors);
 
1640
        item_select_background=gtk_action_create_menu_item(action_select_background);
 
1641
        sakura.item_clear_background=gtk_action_create_menu_item(action_clear_background);
 
1642
        item_opacity_menu=gtk_action_create_menu_item(action_opacity);
 
1643
        item_set_title=gtk_action_create_menu_item(action_set_title);
 
1644
 
 
1645
        item_show_first_tab=gtk_check_menu_item_new_with_label(_("Show always first tab"));
 
1646
        item_show_close_button=gtk_check_menu_item_new_with_label(_("Show tab close button"));
 
1647
        item_toggle_scrollbar=gtk_check_menu_item_new_with_label(_("Toggle scrollbar"));
 
1648
        item_audible_bell=gtk_check_menu_item_new_with_label(_("Set audible bell"));
 
1649
        item_visible_bell=gtk_check_menu_item_new_with_label(_("Set visible bell"));
 
1650
        item_blinking_cursor=gtk_check_menu_item_new_with_label(_("Set blinking cursor"));
 
1651
        item_input_methods=gtk_menu_item_new_with_label(_("Input methods"));
 
1652
        item_palette_tango=gtk_radio_menu_item_new_with_label(NULL, "Tango");
 
1653
        item_palette_linux=gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(item_palette_tango), "Linux");
 
1654
        item_palette_xterm=gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(item_palette_tango), "xterm");
 
1655
        item_palette_rxvt=gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(item_palette_tango), "rxvt");
 
1656
        item_options=gtk_menu_item_new_with_label(_("Options"));
 
1657
        item_palette=gtk_menu_item_new_with_label(_("Set palette"));
 
1658
 
 
1659
        /* Show defaults in menu items */
 
1660
        gchar *cfgtmp = NULL;
 
1661
 
 
1662
        cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "show_always_first_tab", NULL);
 
1663
        if (strcmp(cfgtmp, "Yes")==0) {
 
1664
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_show_first_tab), TRUE);
 
1665
        } else {
 
1666
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_show_first_tab), FALSE);
 
1667
        }
 
1668
        g_free(cfgtmp);
 
1669
 
 
1670
        if (sakura.show_closebutton) {
 
1671
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_show_close_button), TRUE);
 
1672
        } else {
 
1673
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_show_close_button), FALSE);
 
1674
        }
 
1675
 
 
1676
        if (sakura.show_scrollbar) {
 
1677
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_toggle_scrollbar), TRUE);
 
1678
        } else {
 
1679
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_toggle_scrollbar), FALSE);
 
1680
        }
 
1681
 
 
1682
        if (sakura.audible_bell) {
 
1683
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_audible_bell), TRUE);
 
1684
        }
 
1685
 
 
1686
        if (sakura.visible_bell) {
 
1687
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_visible_bell), TRUE);
 
1688
        }
 
1689
 
 
1690
        if (sakura.blinking_cursor) {
 
1691
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_blinking_cursor), TRUE);
 
1692
        }
 
1693
 
 
1694
        cfgtmp = g_key_file_get_string(sakura.cfg, cfg_group, "palette", NULL);
 
1695
        if (strcmp(cfgtmp, "linux")==0) {
 
1696
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_palette_linux), TRUE);
 
1697
        } else if (strcmp(cfgtmp, "tango")==0) {
 
1698
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_palette_tango), TRUE);
 
1699
        } else if (strcmp(cfgtmp, "xterm")==0) {
 
1700
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_palette_xterm), TRUE);
 
1701
        } else {
 
1702
                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item_palette_rxvt), TRUE);
 
1703
        }
 
1704
        g_free(cfgtmp);
 
1705
 
 
1706
        sakura.open_link_separator=gtk_separator_menu_item_new();
 
1707
 
 
1708
        /* Add items to popup menu */
 
1709
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), sakura.item_open_link);
 
1710
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), sakura.item_copy_link);
 
1711
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), sakura.open_link_separator);
 
1712
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_new_tab);
 
1713
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_set_name);
 
1714
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_close_tab);
 
1715
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), gtk_separator_menu_item_new());
 
1716
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_full_screen);
 
1717
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), gtk_separator_menu_item_new());
 
1718
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_copy);
 
1719
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_paste);
 
1720
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), gtk_separator_menu_item_new());
 
1721
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_select_colors);
 
1722
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_select_font);
 
1723
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_select_background);
 
1724
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), sakura.item_clear_background);
 
1725
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), gtk_separator_menu_item_new());
 
1726
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_options);
 
1727
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), gtk_separator_menu_item_new());
 
1728
        gtk_menu_shell_append(GTK_MENU_SHELL(sakura.menu), item_input_methods);
 
1729
 
 
1730
        sakura.im_menu=gtk_menu_new();
 
1731
        options_menu=gtk_menu_new();
 
1732
        palette_menu=gtk_menu_new();
 
1733
 
 
1734
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_show_first_tab);
 
1735
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_show_close_button);
 
1736
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_toggle_scrollbar);
 
1737
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_audible_bell);
 
1738
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_visible_bell);
 
1739
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_blinking_cursor);
 
1740
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), gtk_separator_menu_item_new());
 
1741
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_opacity_menu);
 
1742
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_set_title);
 
1743
        gtk_menu_shell_append(GTK_MENU_SHELL(options_menu), item_palette);
 
1744
        gtk_menu_shell_append(GTK_MENU_SHELL(palette_menu), item_palette_tango);
 
1745
        gtk_menu_shell_append(GTK_MENU_SHELL(palette_menu), item_palette_linux);
 
1746
        gtk_menu_shell_append(GTK_MENU_SHELL(palette_menu), item_palette_xterm);
 
1747
        gtk_menu_shell_append(GTK_MENU_SHELL(palette_menu), item_palette_rxvt);
 
1748
 
 
1749
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item_input_methods), sakura.im_menu);
 
1750
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item_options), options_menu);
 
1751
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(item_palette), palette_menu);
 
1752
 
 
1753
        /* ... and finally assign callbacks to menuitems */
 
1754
        g_signal_connect(G_OBJECT(action_new_tab), "activate", G_CALLBACK(sakura_new_tab), NULL);
 
1755
        g_signal_connect(G_OBJECT(action_set_name), "activate", G_CALLBACK(sakura_set_name_dialog), NULL);
 
1756
        g_signal_connect(G_OBJECT(action_close_tab), "activate", G_CALLBACK(sakura_close_tab), NULL);
 
1757
        g_signal_connect(G_OBJECT(action_select_font), "activate", G_CALLBACK(sakura_font_dialog), NULL);
 
1758
        g_signal_connect(G_OBJECT(action_select_background), "activate",
 
1759
                              G_CALLBACK(sakura_select_background_dialog), NULL);
 
1760
        g_signal_connect(G_OBJECT(action_copy), "activate", G_CALLBACK(sakura_copy), NULL);
 
1761
        g_signal_connect(G_OBJECT(action_paste), "activate", G_CALLBACK(sakura_paste), NULL);
 
1762
        g_signal_connect(G_OBJECT(action_select_colors), "activate", G_CALLBACK(sakura_color_dialog), NULL);
 
1763
 
 
1764
        g_signal_connect(G_OBJECT(item_show_first_tab), "activate", G_CALLBACK(sakura_show_first_tab), NULL);
 
1765
        g_signal_connect(G_OBJECT(item_show_close_button), "activate", G_CALLBACK(sakura_show_close_button), NULL);
 
1766
        g_signal_connect(G_OBJECT(item_toggle_scrollbar), "activate", G_CALLBACK(sakura_show_scrollbar), NULL);
 
1767
        g_signal_connect(G_OBJECT(item_audible_bell), "activate", G_CALLBACK(sakura_audible_bell), NULL);
 
1768
        g_signal_connect(G_OBJECT(item_visible_bell), "activate", G_CALLBACK(sakura_visible_bell), NULL);
 
1769
        g_signal_connect(G_OBJECT(item_blinking_cursor), "activate", G_CALLBACK(sakura_blinking_cursor), NULL);
 
1770
        g_signal_connect(G_OBJECT(action_opacity), "activate", G_CALLBACK(sakura_opacity_dialog), NULL);
 
1771
        g_signal_connect(G_OBJECT(action_set_title), "activate", G_CALLBACK(sakura_set_title_dialog), NULL);
 
1772
        g_signal_connect(G_OBJECT(item_palette_tango), "activate", G_CALLBACK(sakura_set_palette), "tango");
 
1773
        g_signal_connect(G_OBJECT(item_palette_linux), "activate", G_CALLBACK(sakura_set_palette), "linux");
 
1774
        g_signal_connect(G_OBJECT(item_palette_xterm), "activate", G_CALLBACK(sakura_set_palette), "xterm");
 
1775
        g_signal_connect(G_OBJECT(item_palette_rxvt), "activate", G_CALLBACK(sakura_set_palette), "rxvt");
 
1776
 
 
1777
        g_signal_connect(G_OBJECT(action_open_link), "activate", G_CALLBACK(sakura_open_url), NULL);
 
1778
        g_signal_connect(G_OBJECT(action_copy_link), "activate", G_CALLBACK(sakura_copy_url), NULL);
 
1779
        g_signal_connect(G_OBJECT(action_clear_background), "activate", G_CALLBACK(sakura_clear), NULL);
 
1780
        g_signal_connect(G_OBJECT(action_full_screen), "activate", G_CALLBACK(sakura_full_screen), NULL);
 
1781
 
 
1782
 
 
1783
        gtk_widget_show_all(sakura.menu);
 
1784
 
 
1785
        /* We don't want to see this if there's no background image */
 
1786
        if (!sakura.background) {
 
1787
                gtk_widget_hide(sakura.item_clear_background);
 
1788
        }
 
1789
}
 
1790
 
 
1791
 
 
1792
static void
 
1793
sakura_destroy()
 
1794
{
 
1795
        SAY("Destroying sakura");
 
1796
 
 
1797
        /* Delete all existing tabs */
 
1798
        while (gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook)) >= 1) {
 
1799
                sakura_del_tab(-1);
 
1800
        }
 
1801
 
 
1802
        pango_font_description_free(sakura.font);
 
1803
 
 
1804
        if (sakura.background)
 
1805
                free(sakura.background);
 
1806
 
 
1807
        GError *gerror = NULL;
 
1808
        gsize len = 0;
 
1809
        gchar *data = g_key_file_to_data(sakura.cfg, &len, &gerror);
 
1810
        if (!data) {
 
1811
                fprintf(stderr, "%s\n", gerror->message);
 
1812
                exit(EXIT_FAILURE);
 
1813
        }
 
1814
 
 
1815
        /* Write to file */
 
1816
        GIOChannel *cfgfile = g_io_channel_new_file(sakura.configfile, "w", &gerror);
 
1817
        if (!cfgfile) {
 
1818
                fprintf(stderr, "%s\n", gerror->message);
 
1819
                exit(EXIT_FAILURE);
 
1820
        }
 
1821
 
 
1822
        /* FIXME: if the number of chars written is not "len", something happened.
 
1823
         * Check for errors appropriately...*/
 
1824
        GIOStatus status = g_io_channel_write_chars(cfgfile, data, len, NULL, &gerror);
 
1825
        if (status != G_IO_STATUS_NORMAL) {
 
1826
                // FIXME: we should deal with temporary failures (G_IO_STATUS_AGAIN)
 
1827
                fprintf(stderr, "%s\n", gerror->message);
 
1828
                exit(EXIT_FAILURE);
 
1829
        }
 
1830
 
 
1831
        g_io_channel_close(cfgfile);
 
1832
 
 
1833
        g_key_file_free(sakura.cfg);
 
1834
 
 
1835
        free(sakura.configfile);
 
1836
 
 
1837
        gtk_main_quit();
 
1838
 
 
1839
}
 
1840
 
 
1841
 
 
1842
static void
 
1843
sakura_set_size(gint columns, gint rows)
 
1844
{
 
1845
        struct terminal *term;
 
1846
        GtkRequisition main_request;
 
1847
        GtkRequisition term_request;
 
1848
        GdkGeometry hints;
 
1849
        gint pad_x, pad_y;
 
1850
        gint char_width, char_height;
 
1851
 
 
1852
        term = sakura_get_page_term(sakura, 0);
 
1853
 
 
1854
        /* New values used to resize the window */
 
1855
        //sakura.columns = columns;
 
1856
        //sakura.rows = rows;
 
1857
 
 
1858
        vte_terminal_get_padding(VTE_TERMINAL(term->vte), (int *)&pad_x, (int *)&pad_y);
 
1859
        char_width = vte_terminal_get_char_width(VTE_TERMINAL(term->vte));
 
1860
        char_height = vte_terminal_get_char_height(VTE_TERMINAL(term->vte));
 
1861
 
 
1862
        hints.min_width = char_width + pad_x;
 
1863
        hints.min_height = char_height + pad_y;
 
1864
        hints.base_width = pad_x;
 
1865
        hints.base_height = pad_y;
 
1866
        hints.width_inc = char_width;
 
1867
        hints.height_inc = char_height;
 
1868
        gtk_window_set_geometry_hints (GTK_WINDOW (sakura.main_window),
 
1869
                                       GTK_WIDGET (term->vte),
 
1870
                                       &hints,
 
1871
                                       GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE);
 
1872
 
 
1873
        gtk_widget_size_request (sakura.main_window, &main_request);
 
1874
        gtk_widget_size_request (term->vte, &term_request);
 
1875
        sakura.width = main_request.width - term_request.width;
 
1876
        sakura.height = main_request.height - term_request.height;
 
1877
        sakura.width += pad_x + char_width * sakura.columns;
 
1878
        sakura.height += pad_y + char_height * sakura.rows;
 
1879
        if (GTK_WIDGET_MAPPED (sakura.main_window)) {
 
1880
                gtk_window_resize (GTK_WINDOW (sakura.main_window), sakura.width, sakura.height);
 
1881
                SAY("Resizing to %ld columns %ld rows", sakura.columns, sakura.rows);
 
1882
        } else {
 
1883
                gtk_window_set_default_size (GTK_WINDOW (sakura.main_window), sakura.width, sakura.height);
 
1884
        }
 
1885
}
 
1886
 
 
1887
 
 
1888
static void
 
1889
sakura_set_font()
 
1890
{
 
1891
        gint n_pages;
 
1892
        struct terminal *term;
 
1893
        int i;
 
1894
 
 
1895
        n_pages=gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook));
 
1896
 
 
1897
        /* Set the font for all tabs */
 
1898
        for (i = (n_pages - 1); i >= 0; i--) {
 
1899
                term = sakura_get_page_term(sakura, i);
 
1900
                vte_terminal_set_font(VTE_TERMINAL(term->vte), sakura.font);
 
1901
        }
 
1902
}
 
1903
 
 
1904
 
 
1905
static void
 
1906
sakura_add_tab()
 
1907
{
 
1908
        struct terminal *term;
 
1909
        GtkWidget *tab_hbox;
 
1910
        GtkWidget *close_btn;
 
1911
        int index;
 
1912
        gchar *label_text;
 
1913
        gchar *cwd = NULL;
 
1914
        gint w, h;
 
1915
 
 
1916
 
 
1917
        term = g_new0( struct terminal, 1 );
 
1918
        term->hbox=gtk_hbox_new(FALSE, 0);
 
1919
        term->vte=vte_terminal_new();
 
1920
 
 
1921
        /* Create label (and optional close button) for tabs */
 
1922
        label_text=g_strdup_printf(_("Terminal %d"), sakura.label_count++);
 
1923
        term->label=gtk_label_new(label_text);
 
1924
        g_free(label_text);
 
1925
        tab_hbox=gtk_hbox_new(FALSE,2);
 
1926
        gtk_box_pack_start(GTK_BOX(tab_hbox), term->label, FALSE, FALSE, 0);
 
1927
        if (sakura.show_closebutton) {
 
1928
                close_btn=gtk_button_new();
 
1929
                gtk_button_set_relief(GTK_BUTTON(close_btn), GTK_RELIEF_NONE);
 
1930
                GtkWidget *image=gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
 
1931
                gtk_container_add (GTK_CONTAINER (close_btn), image);
 
1932
                /* FIXME: Use GtkWidget set-style signal to properly reflect the changes */
 
1933
                gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (close_btn), GTK_ICON_SIZE_MENU, &w, &h);
 
1934
                gtk_widget_set_size_request(close_btn, w+2, h+2);
 
1935
                gtk_box_pack_start(GTK_BOX(tab_hbox), close_btn, FALSE, FALSE, 0);
 
1936
        }
 
1937
        gtk_widget_show_all(tab_hbox);
 
1938
 
 
1939
        /* Init vte */
 
1940
        vte_terminal_set_scrollback_lines(VTE_TERMINAL(term->vte), SCROLL_LINES);
 
1941
        vte_terminal_match_add_gregex(VTE_TERMINAL(term->vte), sakura.http_regexp, 0);
 
1942
        vte_terminal_set_mouse_autohide(VTE_TERMINAL(term->vte), TRUE);
 
1943
 
 
1944
        term->scrollbar=gtk_vscrollbar_new(vte_terminal_get_adjustment(VTE_TERMINAL(term->vte)));
 
1945
 
 
1946
        gtk_box_pack_start(GTK_BOX(term->hbox), term->vte, TRUE, TRUE, 0);
 
1947
        gtk_box_pack_start(GTK_BOX(term->hbox), term->scrollbar, FALSE, FALSE, 0);
 
1948
 
 
1949
        /* Select the directory to use for the new tab */
 
1950
        index = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
1951
        if(index >= 0) {
 
1952
                struct terminal *prev_term;
 
1953
                prev_term = sakura_get_page_term( sakura, index );
 
1954
                cwd = sakura_get_term_cwd( prev_term );
 
1955
        }
 
1956
        if (!cwd)
 
1957
                cwd = g_get_current_dir();
 
1958
 
 
1959
        /* Keep values when adding tabs */
 
1960
        sakura.keep_fc=true;
 
1961
 
 
1962
        if ((index=gtk_notebook_append_page(GTK_NOTEBOOK(sakura.notebook), term->hbox, tab_hbox))==-1) {
 
1963
                sakura_error("Cannot create a new tab");
 
1964
                return;
 
1965
        }
 
1966
 
 
1967
#if GTK_CHECK_VERSION( 2, 10, 0 )
 
1968
        gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(sakura.notebook), term->hbox, TRUE);
 
1969
        // TODO: Set group id to support detached tabs
 
1970
#if 0
 
1971
        gtk_notebook_set_tab_detachable(GTK_NOTEBOOK(sakura.notebook), term->hbox, TRUE);
 
1972
#endif
 
1973
#endif
 
1974
 
 
1975
        sakura_set_page_term(sakura, index, term );
 
1976
 
 
1977
        /* vte signals */
 
1978
    g_signal_connect(G_OBJECT(term->vte), "increase-font-size", G_CALLBACK(sakura_increase_font), NULL);
 
1979
    g_signal_connect(G_OBJECT(term->vte), "decrease-font-size", G_CALLBACK(sakura_decrease_font), NULL);
 
1980
    g_signal_connect(G_OBJECT(term->vte), "child-exited", G_CALLBACK(sakura_child_exited), NULL);
 
1981
    g_signal_connect(G_OBJECT(term->vte), "eof", G_CALLBACK(sakura_eof), NULL);
 
1982
    g_signal_connect(G_OBJECT(term->vte), "window-title-changed", G_CALLBACK(sakura_title_changed), NULL);
 
1983
    g_signal_connect_swapped(G_OBJECT(term->vte), "button-press-event", G_CALLBACK(sakura_button_press), sakura.menu);
 
1984
 
 
1985
        /* Notebook signals */
 
1986
        g_signal_connect(G_OBJECT(sakura.notebook), "page-removed", G_CALLBACK(sakura_page_removed), NULL);
 
1987
        if (sakura.show_closebutton) {
 
1988
                g_signal_connect(G_OBJECT(close_btn), "clicked", G_CALLBACK(sakura_closebutton_clicked), term->hbox);
 
1989
        }
 
1990
 
 
1991
        /* First tab */
 
1992
        if ( gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook)) == 1) {
 
1993
                gchar *cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "show_always_first_tab", NULL);
 
1994
                if (strcmp(cfgtmp, "Yes")==0) {
 
1995
                        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), TRUE);
 
1996
                } else {
 
1997
                        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), FALSE);
 
1998
                }
 
1999
                g_free(cfgtmp);
 
2000
 
 
2001
                gtk_notebook_set_show_border(GTK_NOTEBOOK(sakura.notebook), FALSE);
 
2002
                sakura_set_font();
 
2003
                gtk_widget_show_all(sakura.main_window);
 
2004
                /* We need only to call set_size for the first tab */
 
2005
                sakura_set_size(sakura.columns, sakura.rows);
 
2006
 
 
2007
                if (option_execute) {
 
2008
                        int command_argc; char **command_argv;
 
2009
                        GError *gerror;
 
2010
                        gchar *path;
 
2011
 
 
2012
                        if (!g_shell_parse_argv(option_execute, &command_argc, &command_argv, &gerror)) {
 
2013
                                sakura_error("Cannot parse command line arguments");
 
2014
                                exit(1);
 
2015
                        }
 
2016
 
 
2017
                        /* Check if the command is valid */
 
2018
                        path=g_find_program_in_path(command_argv[0]);
 
2019
                        if (path)
 
2020
                                free(path);
 
2021
                        else
 
2022
                                option_execute=NULL;
 
2023
 
 
2024
                        term->pid=vte_terminal_fork_command(VTE_TERMINAL(term->vte), command_argv[0],
 
2025
                                                            command_argv, NULL, cwd, FALSE, FALSE, FALSE);
 
2026
                        g_strfreev(command_argv);
 
2027
                        option_execute=NULL;
 
2028
                } else {
 
2029
                        if (option_hold==TRUE) {
 
2030
                                sakura_error("Hold option given without any command");
 
2031
                                option_hold=FALSE;
 
2032
                        }
 
2033
                        /* sakura.argv[0] cannot be used as a parameter, it's different for login shells */
 
2034
                        term->pid=vte_terminal_fork_command(VTE_TERMINAL(term->vte), g_getenv("SHELL"),
 
2035
                                                            sakura.argv, NULL, cwd, FALSE, FALSE, FALSE);
 
2036
                }
 
2037
        /* Not the first tab */
 
2038
        } else {
 
2039
                gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), TRUE);
 
2040
                sakura_set_font();
 
2041
                gtk_widget_show_all(term->hbox);
 
2042
                sakura_set_size(sakura.columns, sakura.rows);
 
2043
                /* Call set_current page after showing the widget: gtk ignores this
 
2044
                 * function in the window is not visible *sigh*. Gtk documentation
 
2045
                 * says this is for "historical" reasons. Me arse */
 
2046
                gtk_notebook_set_current_page(GTK_NOTEBOOK(sakura.notebook), index);
 
2047
                term->pid=vte_terminal_fork_command(VTE_TERMINAL(term->vte), g_getenv("SHELL"),
 
2048
                                                    sakura.argv, NULL, cwd, FALSE, FALSE, FALSE);
 
2049
        }
 
2050
 
 
2051
        free(cwd);
 
2052
 
 
2053
        /* Recalculate sizes if the scrollbar is disabled */
 
2054
        if (!sakura.show_scrollbar) {
 
2055
                gtk_widget_hide(term->scrollbar);
 
2056
                sakura_set_size(sakura.columns, sakura.rows);
 
2057
        }
 
2058
 
 
2059
        /* Configuration per-terminal */
 
2060
        vte_terminal_set_backspace_binding(VTE_TERMINAL(term->vte), VTE_ERASE_ASCII_DELETE);
 
2061
        vte_terminal_set_colors(VTE_TERMINAL(term->vte), &sakura.forecolor, &sakura.backcolor,
 
2062
                                sakura.palette, PALETTE_SIZE);
 
2063
 
 
2064
        if (sakura.fake_transparency) {
 
2065
                vte_terminal_set_background_saturation(VTE_TERMINAL (term->vte), sakura.opacity_level);
 
2066
                vte_terminal_set_background_transparent(VTE_TERMINAL (term->vte),TRUE);
 
2067
        }
 
2068
 
 
2069
        if (sakura.background) {
 
2070
                sakura_set_bgimage(sakura.background);
 
2071
        }
 
2072
 
 
2073
        if (sakura.word_chars) {
 
2074
                vte_terminal_set_word_chars( VTE_TERMINAL (term->vte), sakura.word_chars );
 
2075
        }
 
2076
 
 
2077
        /* Get rid of these nasty bells */
 
2078
        vte_terminal_set_audible_bell (VTE_TERMINAL(term->vte), sakura.audible_bell ? TRUE : FALSE);
 
2079
        vte_terminal_set_visible_bell (VTE_TERMINAL(term->vte), sakura.visible_bell ? TRUE : FALSE);
 
2080
 
 
2081
        /* Disable stupid blinking cursor */
 
2082
        vte_terminal_set_cursor_blink_mode (VTE_TERMINAL(term->vte), sakura.blinking_cursor ? VTE_CURSOR_BLINK_ON : VTE_CURSOR_BLINK_OFF);
 
2083
 
 
2084
 
 
2085
        /* Grrrr. Why the fucking label widget in the notebook STEAL the fucking focus? */
 
2086
        gtk_widget_grab_focus(term->vte);
 
2087
 
 
2088
        /* FIXME: Possible race here. Find some way to force to process all configure
 
2089
         * events before setting keep_fc again to false */
 
2090
        sakura.keep_fc=false;
 
2091
}
 
2092
 
 
2093
 
 
2094
/* Delete the notebook tab passed as a parameter */
 
2095
static void
 
2096
sakura_del_tab(gint page)
 
2097
{
 
2098
        struct terminal *term;
 
2099
        term = sakura_get_page_term(sakura, page);
 
2100
 
 
2101
        /* Do the first tab checks BEFORE deleting the tab, to ensure correct
 
2102
         * sizes are calculated when the tab is deleted */
 
2103
        if ( gtk_notebook_get_n_pages(GTK_NOTEBOOK(sakura.notebook)) == 2) {
 
2104
        char *cfgtmp = g_key_file_get_value(sakura.cfg, cfg_group, "show_always_first_tab", NULL);
 
2105
                if (strcmp(cfgtmp, "Yes")==0) {
 
2106
                        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), TRUE);
 
2107
                } else {
 
2108
                        gtk_notebook_set_show_tabs(GTK_NOTEBOOK(sakura.notebook), FALSE);
 
2109
                }
 
2110
                g_free(cfgtmp);
 
2111
                sakura.keep_fc=true;
 
2112
        }
 
2113
 
 
2114
        gtk_widget_hide(term->hbox);
 
2115
        gtk_notebook_remove_page(GTK_NOTEBOOK(sakura.notebook), page);
 
2116
}
 
2117
 
 
2118
 
 
2119
static void
 
2120
sakura_kill_child()
 
2121
{
 
2122
        /* TODO: Kill the forked child nicely */
 
2123
}
 
2124
 
 
2125
 
 
2126
static void
 
2127
sakura_set_bgimage(char *infile)
 
2128
{
 
2129
        GError *gerror=NULL;
 
2130
        GdkPixbuf *pixbuf=NULL;
 
2131
        int page;
 
2132
        struct terminal *term;
 
2133
 
 
2134
        if (!infile) SAY("File parameter is NULL");
 
2135
 
 
2136
        page = gtk_notebook_get_current_page(GTK_NOTEBOOK(sakura.notebook));
 
2137
        term = sakura_get_page_term(sakura, page);
 
2138
 
 
2139
        /* Check file existence and type */
 
2140
        if (g_file_test(infile, G_FILE_TEST_IS_REGULAR)) {
 
2141
 
 
2142
                pixbuf = gdk_pixbuf_new_from_file (infile, &gerror);
 
2143
                if (!pixbuf) {
 
2144
                        sakura_error("Not using image file, %s\n", gerror->message);
 
2145
                } else {
 
2146
            vte_terminal_set_background_image(VTE_TERMINAL(term->vte), pixbuf);
 
2147
            vte_terminal_set_background_saturation(VTE_TERMINAL(term->vte), TRUE);
 
2148
            vte_terminal_set_background_transparent(VTE_TERMINAL(term->vte),FALSE);
 
2149
 
 
2150
            g_key_file_set_value(sakura.cfg, cfg_group, "background", infile);
 
2151
                }
 
2152
        }
 
2153
}
 
2154
 
 
2155
 
 
2156
static void
 
2157
sakura_key_file_set_key(GKeyFile *cfg,const gchar *cfg_group, const gchar *keyname,guint value) 
 
2158
{
 
2159
        gchar *valname;
 
2160
 
 
2161
        if((cfg==NULL)||(cfg_group==NULL)||(keyname==NULL)) {
 
2162
                return;
 
2163
        }
 
2164
        valname=gdk_keyval_name(value);
 
2165
        g_key_file_set_string(cfg, cfg_group,keyname, valname);
 
2166
}
 
2167
 
 
2168
 
 
2169
static guint
 
2170
sakura_key_file_get_key(GKeyFile *cfg,const gchar *cfg_group,const gchar *keyname)
 
2171
{
 
2172
        gchar *value;
 
2173
        guint retval=GDK_VoidSymbol;
 
2174
 
 
2175
        value=g_key_file_get_string(cfg, cfg_group, keyname, NULL);
 
2176
        if (value!=NULL){
 
2177
                retval=gdk_keyval_from_name(value);
 
2178
                g_free(value);
 
2179
        }
 
2180
 
 
2181
        /* For backwards compatibility with integer values */
 
2182
        /* If gdk_keyval_from_name fail, it seems to be integer value*/
 
2183
        if ((retval==GDK_VoidSymbol)||(retval==0)) {
 
2184
                retval=g_key_file_get_integer(cfg, cfg_group, keyname, NULL);
 
2185
        }
 
2186
 
 
2187
        return retval;
 
2188
}
 
2189
 
 
2190
 
 
2191
static void
 
2192
sakura_error(const char *format, ...)
 
2193
{
 
2194
        GtkWidget *dialog;
 
2195
        va_list args;
 
2196
 
 
2197
        va_start(args, format);
 
2198
 
 
2199
        dialog = gtk_message_dialog_new(GTK_WINDOW(sakura.main_window), GTK_DIALOG_DESTROY_WITH_PARENT,
 
2200
                                        GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, format, args);
 
2201
        gtk_dialog_run (GTK_DIALOG (dialog));
 
2202
 
 
2203
        va_end(args);
 
2204
        gtk_widget_destroy (dialog);
 
2205
}
 
2206
 
 
2207
 
 
2208
int
 
2209
main(int argc, char **argv)
 
2210
{
 
2211
        struct terminal *term;
 
2212
        gchar *localedir;
 
2213
        GError *error=NULL;
 
2214
        GOptionContext *context;
 
2215
        int i;
 
2216
 
 
2217
        /* Localization */
 
2218
        setlocale(LC_ALL, "");
 
2219
        localedir=g_strdup_printf("%s/locale", DATADIR);
 
2220
        textdomain(GETTEXT_PACKAGE);
 
2221
        bindtextdomain(GETTEXT_PACKAGE, localedir);
 
2222
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
2223
 
 
2224
        /* Options parsing */
 
2225
        context = g_option_context_new (_("- vte-based terminal emulator"));
 
2226
        g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
 
2227
        g_option_group_set_translation_domain(gtk_get_option_group(TRUE), GETTEXT_PACKAGE);
 
2228
        g_option_context_add_group (context, gtk_get_option_group(TRUE));
 
2229
        g_option_context_parse (context, &argc, &argv, &error);
 
2230
 
 
2231
        if (option_version) {
 
2232
                fprintf(stderr, _("sakura version is %s\n"), VERSION);
 
2233
                exit(1);
 
2234
        }
 
2235
 
 
2236
        if (option_ntabs <= 0) {
 
2237
                option_ntabs=1;
 
2238
        }
 
2239
 
 
2240
        g_option_context_free(context);
 
2241
 
 
2242
        gtk_init(&argc, &argv);
 
2243
 
 
2244
        /* Init stuff */
 
2245
        sakura_init();
 
2246
 
 
2247
        /* Add first tab */
 
2248
        for (i=0; i<option_ntabs; i++)
 
2249
                sakura_add_tab();
 
2250
 
 
2251
        /* Fill Input Methods menu */
 
2252
        term = sakura_get_page_term(sakura, 0);
 
2253
        vte_terminal_im_append_menuitems(VTE_TERMINAL(term->vte), GTK_MENU_SHELL(sakura.im_menu));
 
2254
 
 
2255
        gtk_main();
 
2256
 
 
2257
        return 0;
 
2258
}