vteapp.c 34 KB
Newer Older
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
1 2 3
/*
 * Copyright (C) 2001,2002 Red Hat, Inc.
 *
4 5 6 7
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
8
 *
9 10
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
13
 *
14 15 16
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
17 18
 */

19

20
#include <config.h>
21

22
#include <stdlib.h>
23
#include <sys/ioctl.h>
24
#include <sys/stat.h>
25
#include <errno.h>
26
#include <fcntl.h>
27
#include <string.h>
28
#include <unistd.h>
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
29 30
#include <gtk/gtk.h>
#include <glib-object.h>
31
#include "debug.h"
32 33

#undef VTE_DISABLE_DEPRECATED
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
34
#include "vte.h"
35

36
#include <glib/gi18n.h>
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
37

38
#define DINGUS1 "(((gopher|news|telnet|nntp|file|http|ftp|https)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.]+(:[0-9]*)?"
39 40 41 42 43 44 45
#define DINGUS2 DINGUS1 "/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"]"

static const char *builtin_dingus[] = {
  DINGUS1,
  DINGUS2,
  NULL
};
46

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
47
static void
48
window_title_changed(GtkWidget *widget, gpointer win)
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
49 50
{
	GtkWindow *window;
51

52 53
	g_assert(VTE_TERMINAL(widget));
	g_assert(GTK_IS_WINDOW(win));
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
54
	window = GTK_WINDOW(win);
55

56
	gtk_window_set_title(window, vte_terminal_get_window_title(VTE_TERMINAL(widget)));
57 58 59 60 61
}

static void
icon_title_changed(GtkWidget *widget, gpointer win)
{
62 63
	g_assert(VTE_TERMINAL(widget));
	g_assert(GTK_IS_WINDOW(win));
64 65

	g_message("Icon title changed to \"%s\".\n",
66
		  vte_terminal_get_icon_title(VTE_TERMINAL(widget)));
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
67 68 69
}

static void
70
char_size_changed(GtkWidget *widget, guint width, guint height, gpointer data)
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
71 72 73
{
	GtkWindow *window;
	GdkGeometry geometry;
74
	GtkBorder padding;
75

76 77
	g_assert(GTK_IS_WINDOW(data));
	g_assert(VTE_IS_TERMINAL(widget));
78

79
	window = GTK_WINDOW(data);
80
	if (!gtk_widget_get_realized (GTK_WIDGET (window)))
81
		return;
82

83 84 85 86
        gtk_style_context_get_padding(gtk_widget_get_style_context(widget),
                                      gtk_widget_get_state_flags(widget),
                                      &padding);
        geometry.width_inc = width;
87
	geometry.height_inc = height;
88 89
	geometry.base_width = padding.left + padding.right;
	geometry.base_height = padding.top + padding.bottom;
90 91
	geometry.min_width = geometry.base_width + width * 2;
	geometry.min_height = geometry.base_height + height * 2;
92 93 94 95 96 97 98 99 100 101 102 103 104 105

	gtk_window_set_geometry_hints(window, widget, &geometry,
				      GDK_HINT_RESIZE_INC |
				      GDK_HINT_BASE_SIZE |
				      GDK_HINT_MIN_SIZE);
}

static void
char_size_realized(GtkWidget *widget, gpointer data)
{
	VteTerminal *terminal;
	GtkWindow *window;
	GdkGeometry geometry;
	guint width, height;
106
	GtkBorder padding;
107 108 109 110 111 112

	g_assert(GTK_IS_WINDOW(data));
	g_assert(VTE_IS_TERMINAL(widget));

	terminal = VTE_TERMINAL(widget);
	window = GTK_WINDOW(data);
113
	if (!gtk_widget_get_realized (GTK_WIDGET(window)))
114 115
		return;

116 117 118 119
        gtk_style_context_get_padding(gtk_widget_get_style_context(widget),
                                      gtk_widget_get_state_flags(widget),
                                      &padding);
        width = vte_terminal_get_char_width (terminal);
120 121 122
	height = vte_terminal_get_char_height (terminal);
	geometry.width_inc = width;
	geometry.height_inc = height;
123 124
	geometry.base_width = padding.left + padding.right;
	geometry.base_height = padding.top + padding.bottom;
125 126
	geometry.min_width = geometry.base_width + width * 2;
	geometry.min_height = geometry.base_height + height * 2;
127

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
128
	gtk_window_set_geometry_hints(window, widget, &geometry,
129 130 131
				      GDK_HINT_RESIZE_INC |
				      GDK_HINT_BASE_SIZE |
				      GDK_HINT_MIN_SIZE);
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
132 133
}

134

135
static void
136
destroy_and_quit(VteTerminal *terminal, GtkWidget *window)
137
{
138
	const char *output_file = g_object_get_data (G_OBJECT (terminal), "output_file");
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

	if (output_file) {
		GFile *file;
		GOutputStream *stream;
		GError *error = NULL;

		file = g_file_new_for_commandline_arg (output_file);
		stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error));

		if (stream) {
			vte_terminal_write_contents (terminal, stream,
						     VTE_TERMINAL_WRITE_DEFAULT,
						     NULL, &error);
			g_object_unref (stream);
		}

		if (error) {
			g_printerr ("%s\n", error->message);
			g_error_free (error);
		}

		g_object_unref (file);
	}

163 164
	gtk_widget_destroy (window);
	gtk_main_quit ();
165
}
166
static void
167
delete_event(GtkWidget *window, GdkEvent *event, gpointer terminal)
168
{
169
	destroy_and_quit(VTE_TERMINAL (terminal), window);
170 171
}
static void
172
child_exited(GtkWidget *terminal, int status, gpointer window)
173
{
174
	_vte_debug_print(VTE_DEBUG_MISC, "Child exited with status %x\n", status);
175
	destroy_and_quit(VTE_TERMINAL (terminal), GTK_WIDGET (window));
176
}
177

178 179 180 181 182 183 184
static void
status_line_changed(GtkWidget *widget, gpointer data)
{
	g_print("Status = `%s'.\n",
		vte_terminal_get_status_line(VTE_TERMINAL(widget)));
}

185 186 187 188 189 190
static int
button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
	VteTerminal *terminal;
	char *match;
	int tag;
191
	GtkBorder padding;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
192
	int char_width, char_height;
193

194 195 196
	switch (event->button) {
	case 3:
		terminal = VTE_TERMINAL(widget);
197

198 199 200 201
                gtk_style_context_get_padding(gtk_widget_get_style_context(widget),
                                              gtk_widget_get_state_flags(widget),
                                              &padding);
                char_width = vte_terminal_get_char_width (terminal);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
202
		char_height = vte_terminal_get_char_height (terminal);
203
		match = vte_terminal_match_check(terminal,
204 205
						 (event->x - padding.left) / char_width,
						 (event->y - padding.top) / char_height,
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
						 &tag);
		if (match != NULL) {
			g_print("Matched `%s' (%d).\n", match, tag);
			g_free(match);
			if (GPOINTER_TO_INT(data) != 0) {
				vte_terminal_match_remove(terminal, tag);
			}
		}
		break;
	case 1:
	case 2:
	default:
		break;
	}
	return FALSE;
}

static void
iconify_window(GtkWidget *widget, gpointer data)
{
226
	gtk_window_iconify(data);
227 228 229 230 231
}

static void
deiconify_window(GtkWidget *widget, gpointer data)
{
232
	gtk_window_deiconify(data);
233 234 235 236 237
}

static void
raise_window(GtkWidget *widget, gpointer data)
{
238 239
	GdkWindow *window;

240
	if (GTK_IS_WIDGET(data)) {
241 242 243
		window = gtk_widget_get_window(GTK_WIDGET(data));
		if (window) {
			gdk_window_raise(window);
244 245 246 247 248 249 250
		}
	}
}

static void
lower_window(GtkWidget *widget, gpointer data)
{
251 252
	GdkWindow *window;

253
	if (GTK_IS_WIDGET(data)) {
254 255 256
		window = gtk_widget_get_window(GTK_WIDGET(data));
		if (window) {
			gdk_window_lower(window);
257 258 259 260 261 262 263
		}
	}
}

static void
maximize_window(GtkWidget *widget, gpointer data)
{
264 265
	GdkWindow *window;

266
	if (GTK_IS_WIDGET(data)) {
267 268 269
		window = gtk_widget_get_window(GTK_WIDGET(data));
		if (window) {
			gdk_window_maximize(window);
270 271 272 273 274 275 276
		}
	}
}

static void
restore_window(GtkWidget *widget, gpointer data)
{
277 278
	GdkWindow *window;

279
	if (GTK_IS_WIDGET(data)) {
280 281 282
		window = gtk_widget_get_window(GTK_WIDGET(data));
		if (window) {
			gdk_window_unmaximize(window);
283 284 285 286 287 288 289
		}
	}
}

static void
refresh_window(GtkWidget *widget, gpointer data)
{
290 291
	GdkWindow *window;
	GtkAllocation allocation;
292
	GdkRectangle rect;
293

294
	if (GTK_IS_WIDGET(data)) {
295 296 297
		window = gtk_widget_get_window(widget);
		if (window) {
			gtk_widget_get_allocation(widget, &allocation);
298
			rect.x = rect.y = 0;
299 300 301
			rect.width = allocation.width;
			rect.height = allocation.height;
			gdk_window_invalidate_rect(window, &rect, TRUE);
302 303 304 305 306 307 308 309
		}
	}
}

static void
resize_window(GtkWidget *widget, guint width, guint height, gpointer data)
{
	VteTerminal *terminal;
310

311
	if ((GTK_IS_WINDOW(data)) && (width >= 2) && (height >= 2)) {
Behdad Esfahbod's avatar
Behdad Esfahbod committed
312
		gint owidth, oheight, char_width, char_height, column_count, row_count;
313
		GtkBorder padding;
314

315
		terminal = VTE_TERMINAL(widget);
316

317
		gtk_window_get_size(GTK_WINDOW(data), &owidth, &oheight);
318 319

		/* Take into account border overhead. */
Behdad Esfahbod's avatar
Behdad Esfahbod committed
320 321 322 323
		char_width = vte_terminal_get_char_width (terminal);
		char_height = vte_terminal_get_char_height (terminal);
		column_count = vte_terminal_get_column_count (terminal);
		row_count = vte_terminal_get_row_count (terminal);
324 325 326
                gtk_style_context_get_padding(gtk_widget_get_style_context(widget),
                                              gtk_widget_get_state_flags(widget),
                                              &padding);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
327

328 329
                owidth -= char_width * column_count + padding.left + padding.right;
                oheight -= char_height * row_count + padding.top + padding.bottom;
330 331 332 333 334 335 336 337
		gtk_window_resize(GTK_WINDOW(data),
				  width + owidth, height + oheight);
	}
}

static void
move_window(GtkWidget *widget, guint x, guint y, gpointer data)
{
338 339
	GdkWindow *window;

340
	if (GTK_IS_WIDGET(data)) {
341 342 343
		window = gtk_widget_get_window(GTK_WIDGET(data));
		if (window) {
			gdk_window_move(window, x, y);
344 345 346 347
		}
	}
}

348
static void
349
adjust_font_size(GtkWidget *widget, gpointer data, gdouble factor)
350 351
{
	VteTerminal *terminal;
352
        gdouble scale;
353
        glong char_width, char_height;
354 355 356 357
	gint columns, rows, owidth, oheight;

	/* Read the screen dimensions in cells. */
	terminal = VTE_TERMINAL(widget);
358 359
	columns = vte_terminal_get_column_count(terminal);
	rows = vte_terminal_get_row_count(terminal);
360 361 362

	/* Take into account padding and border overhead. */
	gtk_window_get_size(GTK_WINDOW(data), &owidth, &oheight);
363 364
        char_width = vte_terminal_get_char_width (terminal);
        char_height = vte_terminal_get_char_height (terminal);
365 366
	owidth -= char_width * columns;
	oheight -= char_height * rows;
367

368 369
	scale = vte_terminal_get_font_scale(terminal);
        vte_terminal_set_font_scale(terminal, scale * factor);
370 371 372 373 374

        /* This above call will have changed the char size! */
        char_width = vte_terminal_get_char_width (terminal);
        char_height = vte_terminal_get_char_height (terminal);

375
	gtk_window_resize(GTK_WINDOW(data),
376 377
			  columns * char_width + owidth,
			  rows * char_height + oheight);
378 379 380 381 382
}

static void
increase_font_size(GtkWidget *widget, gpointer data)
{
383
	adjust_font_size(widget, data, 1.2);
384 385 386 387 388
}

static void
decrease_font_size(GtkWidget *widget, gpointer data)
{
389
	adjust_font_size(widget, data, 1. / 1.2);
390 391
}

392 393 394 395 396 397
static gboolean
read_and_feed(GIOChannel *source, GIOCondition condition, gpointer data)
{
	char buf[2048];
	gsize size;
	GIOStatus status;
398
	g_assert(VTE_IS_TERMINAL(data));
399 400 401 402 403 404 405 406 407 408
	status = g_io_channel_read_chars(source, buf, sizeof(buf),
					 &size, NULL);
	if ((status == G_IO_STATUS_NORMAL) && (size > 0)) {
		vte_terminal_feed(VTE_TERMINAL(data), buf, size);
		return TRUE;
	}
	return FALSE;
}

static void
409
disconnect_watch(gpointer data)
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
{
	g_source_remove(GPOINTER_TO_INT(data));
}

static void
clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data,
	      guint info, gpointer owner)
{
	/* No-op. */
	return;
}

static void
take_xconsole_ownership(GtkWidget *widget, gpointer data)
{
	char *name, hostname[255];
	GdkAtom atom;
	GtkClipboard *clipboard;
428 429 430 431 432 433 434 435
        GtkTargetList *target_list;
        GtkTargetEntry *targets;
        int n_targets;

        target_list = gtk_target_list_new(NULL, 0);
        gtk_target_list_add_text_targets(target_list, 0);
        targets = gtk_target_table_new_from_list (target_list, &n_targets);
        gtk_target_list_unref(target_list);
436 437 438 439 440

	memset(hostname, '\0', sizeof(hostname));
	gethostname(hostname, sizeof(hostname) - 1);

	name = g_strdup_printf("MIT_CONSOLE_%s", hostname);
441
	atom = gdk_atom_intern(name, FALSE);
442 443
	clipboard = gtk_clipboard_get_for_display(gtk_widget_get_display(widget),
						  atom);
444 445 446 447
	g_free(name);

	gtk_clipboard_set_with_owner(clipboard,
				     targets,
448
				     n_targets,
449 450 451 452 453
				     clipboard_get,
				     (GtkClipboardClearFunc)gtk_main_quit,
				     G_OBJECT(widget));
}

454 455 456 457 458 459
static void
add_weak_pointer(GObject *object, GtkWidget **target)
{
	g_object_add_weak_pointer(object, (gpointer*)target);
}

460 461
static void
terminal_notify_cb(GObject *object,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
462 463
		   GParamSpec *pspec,
		   gpointer user_data)
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
{
  GValue value = { 0, };
  char *value_string;

  if (!pspec ||
      pspec->owner_type != VTE_TYPE_TERMINAL)
    return;


  g_value_init(&value, pspec->value_type);
  g_object_get_property(object, pspec->name, &value);
  value_string = g_strdup_value_contents(&value);
  g_print("NOTIFY property \"%s\" value '%s'\n", pspec->name, value_string);
  g_free(value_string);
  g_value_unset(&value);
}

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
/* Derived terminal class */

typedef struct _VteappTerminal      VteappTerminal;
typedef struct _VteappTerminalClass VteappTerminalClass;

struct _VteappTerminalClass {
        VteTerminalClass parent_class;
};
struct _VteappTerminal {
        VteTerminal parent_instance;
};

static GType vteapp_terminal_get_type(void);

G_DEFINE_TYPE(VteappTerminal, vteapp_terminal, VTE_TYPE_TERMINAL)

static void
vteapp_terminal_class_init(VteappTerminalClass *klass)
{
}

static void
vteapp_terminal_init(VteappTerminal *terminal)
{
}

static GtkWidget *
vteapp_terminal_new(void)
{
        return g_object_new(vteapp_terminal_get_type(), NULL);
}

/* Command line options */

515 516
static int
parse_enum(GType type,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
517
	   const char *string)
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
{
  GEnumClass *enum_klass;
  const GEnumValue *enum_value;
  int value = 0;

  enum_klass = (GEnumClass*)g_type_class_ref(type);
  enum_value = g_enum_get_value_by_nick(enum_klass, string);
  if (enum_value)
    value = enum_value->value;
  else
    g_warning("Unknown enum '%s'\n", string);
  g_type_class_unref(enum_klass);

  return value;
}

534 535
static guint
parse_flags(GType type,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
536
	    const char *string)
537 538 539 540 541 542 543 544 545 546 547 548
{
  GFlagsClass *flags_klass;
  guint value = 0;
  char **flags;
  guint i;

  flags = g_strsplit_set(string, ",|", -1);
  if (flags == NULL)
    return 0;

  flags_klass = (GFlagsClass*)g_type_class_ref(type);
  for (i = 0; flags[i] != NULL; ++i) {
Behdad Esfahbod's avatar
Behdad Esfahbod committed
549
	  const GFlagsValue *flags_value;
550

Behdad Esfahbod's avatar
Behdad Esfahbod committed
551 552 553 554 555
	  flags_value = g_flags_get_value_by_nick(flags_klass, flags[i]);
	  if (flags_value)
		  value |= flags_value->value;
	  else
		  g_warning("Unknown flag '%s'\n", flags[i]);
556 557 558 559 560 561
  }
  g_type_class_unref(flags_klass);

  return value;
}

562 563 564 565 566 567 568 569 570 571 572 573
static gboolean
parse_color (const gchar *value,
             GdkRGBA *color)
{
        if (!gdk_rgba_parse(color, value)) {
                g_printerr("Failed to parse value \"%s\" as color", value);
                return FALSE;
        }

        return TRUE;
}

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
static void
add_dingus (VteTerminal *terminal,
            char **dingus)
{
        const GdkCursorType cursors[] = { GDK_GUMBY, GDK_HAND1 };
        GRegex *regex;
        GError *error;
        int id, i;

        for (i = 0; dingus[i]; ++i) {
                error = NULL;
                if (!(regex = g_regex_new(dingus[i], G_REGEX_OPTIMIZE, 0, &error))) {
                        g_warning("Failed to compile regex '%s': %s\n",
                                  dingus[i], error->message);
                        g_error_free(error);
                        continue;
                }

                id = vte_terminal_match_add_gregex(terminal, regex, 0);
                g_regex_unref (regex);
                vte_terminal_match_set_cursor_type(terminal, id,
                                                   cursors[i % G_N_ELEMENTS(cursors)]);
        }
}

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
599 600 601
int
main(int argc, char **argv)
{
602
	GdkScreen *screen;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
603
	GdkVisual *visual;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
604
	GtkWidget *window, *widget,*hbox = NULL, *scrollbar, *scrolled_window = NULL;
605
	VteTerminal *terminal;
606 607
	char *env_add[] = {
#ifdef VTE_DEBUG
608
		(char *) "FOO=BAR", (char *) "BOO=BIZ",
609 610
#endif
		NULL};
611
        char *transparent = NULL;
612 613
        char *encoding = NULL;
        char *cjk_ambiguous_width = NULL;
614
	gboolean audible = TRUE,
615
		 debug = FALSE, no_builtin_dingus = FALSE, dbuffer = TRUE,
616
		 console = FALSE, keep = FALSE,
617 618
                icon_title = FALSE, shell = TRUE,
		 reverse = FALSE, use_geometry_hints = TRUE,
619
		 use_scrolled_window = FALSE,
620
		 show_object_notifications = FALSE, rewrap = TRUE;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
621
	char *geometry = NULL;
622
	gint lines = -1;
623
	const char *message = "Launching interactive shell...\r\n";
624
	const char *font = NULL;
625
	const char *termcap = NULL;
626
	const char *command = NULL;
627
	const char *working_directory = NULL;
628
	const char *output_file = NULL;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
629 630 631 632
	char *pty_flags_string = NULL;
	char *cursor_blink_mode_string = NULL;
	char *cursor_shape_string = NULL;
	char *scrollbar_policy_string = NULL;
633
        char *border_width_string = NULL;
634 635 636
        char *cursor_color_string = NULL;
        char *highlight_foreground_color_string = NULL;
        char *highlight_background_color_string = NULL;
637
        char **dingus = NULL;
638
	GdkRGBA fore, back;
639 640
	const GOptionEntry options[]={
		{
Chris Wilson's avatar
Chris Wilson committed
641 642
			"console", 'C', 0,
			G_OPTION_ARG_NONE, &console,
643 644
			"Watch /dev/console", NULL
		},
645 646 647 648 649
                {
                        "no-builtin-dingus", 0, G_OPTION_FLAG_REVERSE,
                        G_OPTION_ARG_NONE, &no_builtin_dingus,
                        "Highlight URLs inside the terminal", NULL
                },
650
		{
651 652 653
			"dingu", 'D', 0,
			G_OPTION_ARG_STRING_ARRAY, &dingus,
			"Add regex highlight", NULL
654
		},
655 656 657 658 659
		{
			"no-rewrap", 'R', G_OPTION_FLAG_REVERSE,
			G_OPTION_ARG_NONE, &rewrap,
			"Disable rewrapping on resize", NULL
		},
660
		{
Chris Wilson's avatar
Chris Wilson committed
661 662
			"shell", 'S', G_OPTION_FLAG_REVERSE,
			G_OPTION_ARG_NONE, &shell,
663 664 665
			"Disable spawning a shell inside the terminal", NULL
		},
		{
Chris Wilson's avatar
Chris Wilson committed
666
			"transparent", 'T', 0,
667 668
			G_OPTION_ARG_STRING, &transparent,
			"Enable the use of a transparent background", "ALPHA"
669 670 671 672 673 674 675 676 677
		},
		{
			"double-buffer", '2', G_OPTION_FLAG_REVERSE,
			G_OPTION_ARG_NONE, &dbuffer,
			"Disable double-buffering", NULL
		},
		{
			"audible", 'a', G_OPTION_FLAG_REVERSE,
			G_OPTION_ARG_NONE, &audible,
678
			"Use visible, instead of audible, terminal bell",
Chris Wilson's avatar
Chris Wilson committed
679
			NULL
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
		},
		{
			"command", 'c', 0,
			G_OPTION_ARG_STRING, &command,
			"Execute a command in the terminal", NULL
		},
		{
			"debug", 'd', 0,
			G_OPTION_ARG_NONE, &debug,
			"Enable various debugging checks", NULL
		},
		{
			"font", 'f', 0,
			G_OPTION_ARG_STRING, &font,
			"Specify a font to use", NULL
		},
		{
697 698
			"geometry", 'g', 0,
			G_OPTION_ARG_STRING, &geometry,
Chris Wilson's avatar
Chris Wilson committed
699
			"Set the size (in characters) and position", "GEOMETRY"
700 701
		},
		{
702 703 704 705 706 707 708 709
			"highlight-foreground-color", 0, 0,
			G_OPTION_ARG_STRING, &highlight_foreground_color_string,
			"Enable distinct highlight foreground color for selection", NULL
		},
		{
			"highlight-background-color", 0, 0,
			G_OPTION_ARG_STRING, &highlight_background_color_string,
			"Enable distinct highlight background color for selection", NULL
710 711 712 713 714 715 716 717 718
		},
		{
			"icon-title", 'i', 0,
			G_OPTION_ARG_NONE, &icon_title,
			"Enable the setting of the icon title", NULL
		},
		{
			"keep", 'k', 0,
			G_OPTION_ARG_NONE, &keep,
Chris Wilson's avatar
Chris Wilson committed
719
			"Live on after the window closes", NULL
720 721 722 723 724 725
		},
		{
			"scrollback-lines", 'n', 0,
			G_OPTION_ARG_INT, &lines,
			"Specify the number of scrollback-lines", NULL
		},
Behdad Esfahbod's avatar
Behdad Esfahbod committed
726 727 728 729 730
		{
			"cursor-blink", 0, 0,
			G_OPTION_ARG_STRING, &cursor_blink_mode_string,
			"Cursor blink mode (system|on|off)", "MODE"
		},
731
		{
732 733
			"cursor-color", 0, 0,
			G_OPTION_ARG_STRING, &cursor_color_string,
734 735
			"Enable a colored cursor", NULL
		},
736 737
		{
			"cursor-shape", 0, 0,
738 739
			G_OPTION_ARG_STRING, &cursor_shape_string,
			"Set cursor shape (block|underline|ibeam)", NULL
740
		},
741 742 743 744 745
		{
			"termcap", 't', 0,
			G_OPTION_ARG_STRING, &termcap,
			"Specify the terminal emulation to use", NULL
		},
746 747 748 749 750 751 752 753 754 755
		{
			"encoding", 0, 0,
			G_OPTION_ARG_STRING, &encoding,
			"Specify the terminal encoding to use", NULL
		},
		{
			"cjk-width", 0, 0,
			G_OPTION_ARG_STRING, &cjk_ambiguous_width,
			"Specify the cjk ambiguous width to use for UTF-8 encoding", "NARROW|WIDE"
		},
756 757 758 759 760 761 762 763 764 765 766
		{
			"working-directory", 'w', 0,
			G_OPTION_ARG_FILENAME, &working_directory,
			"Specify the initial working directory of the terminal",
			NULL
		},
		{
			"reverse", 0, 0,
			G_OPTION_ARG_NONE, &reverse,
			"Reverse foreground/background colors", NULL
		},
767 768 769 770 771 772
		{
			"no-geometry-hints", 'G', G_OPTION_FLAG_REVERSE,
			G_OPTION_ARG_NONE, &use_geometry_hints,
			"Allow the terminal to be resized to any dimension, not constrained to fit to an integer multiple of characters",
			NULL
		},
773 774 775 776 777 778 779 780
		{
			"scrolled-window", 'W', 0,
			G_OPTION_ARG_NONE, &use_scrolled_window,
			"Use a GtkScrolledWindow as terminal container",
			NULL
		},
		{
			"scrollbar-policy", 'P', 0,
781 782
			G_OPTION_ARG_STRING, &scrollbar_policy_string,
			"Set the policy for the vertical scroolbar in the scrolled window (always|auto|never; default:always)",
783 784
			NULL
		},
785 786 787 788 789 790
		{
			"object-notifications", 'N', 0,
			G_OPTION_ARG_NONE, &show_object_notifications,
			"Print VteTerminal object notifications",
			NULL
		},
791 792 793 794 795
		{
			"output-file", 0, 0,
			G_OPTION_ARG_STRING, &output_file,
			"Save terminal contents to file at exit", NULL
		},
796 797 798 799 800
		{
			"pty-flags", 0, 0,
			G_OPTION_ARG_STRING, &pty_flags_string,
			"PTY flags set from default|no-utmp|no-wtmp|no-lastlog|no-helper|no-fallback", NULL
		},
801 802 803 804 805
                {
                        "border-width", 0, 0,
                        G_OPTION_ARG_STRING, &border_width_string,
                        "Border with", "WIDTH"
                },
806 807 808 809
		{ NULL }
	};
	GOptionContext *context;
	GError *error = NULL;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
810 811 812 813
	VteTerminalCursorBlinkMode cursor_blink_mode = VTE_CURSOR_BLINK_SYSTEM;
	VteTerminalCursorShape cursor_shape = VTE_CURSOR_SHAPE_BLOCK;
	GtkPolicyType scrollbar_policy = GTK_POLICY_ALWAYS;
	VtePtyFlags pty_flags = VTE_PTY_DEFAULT;
814

815 816
        _vte_debug_init();

817 818 819 820 821 822
	/* Have to do this early. */
	if (getenv("VTE_PROFILE_MEMORY")) {
		if (atol(getenv("VTE_PROFILE_MEMORY")) != 0) {
			g_mem_set_vtable(glib_mem_profiler_table);
		}
	}
823 824 825
        if (g_getenv("VTE_CJK_WIDTH")) {
                g_printerr("VTE_CJK_WIDTH is not supported anymore, use --cjk-width instead\n");
        }
826

827 828 829 830 831 832 833 834 835 836
	context = g_option_context_new (" - test VTE terminal emulation");
	g_option_context_add_main_entries (context, options, NULL);
	g_option_context_add_group (context, gtk_get_option_group (TRUE));
	g_option_context_parse (context, &argc, &argv, &error);
	g_option_context_free (context);
	if (error != NULL) {
		g_printerr ("Failed to parse command line arguments: %s\n",
				error->message);
		g_error_free (error);
		return 1;
837
	}
838

Behdad Esfahbod's avatar
Behdad Esfahbod committed
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
	if (cursor_blink_mode_string) {
		cursor_blink_mode = parse_enum(VTE_TYPE_TERMINAL_CURSOR_BLINK_MODE, cursor_blink_mode_string);
		g_free(cursor_blink_mode_string);
	}
	if (cursor_shape_string) {
		cursor_shape = parse_enum(VTE_TYPE_TERMINAL_CURSOR_SHAPE, cursor_shape_string);
		g_free(cursor_shape_string);
	}
	if (scrollbar_policy_string) {
		scrollbar_policy = parse_enum(GTK_TYPE_POLICY_TYPE, scrollbar_policy_string);
		g_free(scrollbar_policy_string);
	}
	if (pty_flags_string) {
		pty_flags |= parse_flags(VTE_TYPE_PTY_FLAGS, pty_flags_string);
		g_free(pty_flags_string);
	}
855

856
	if (!reverse) {
857 858
		back.red = back.green = back.blue = 1.0; back.alpha = 1.0;
		fore.red = fore.green = fore.blue = 0.0; fore.alpha = 1.0;
859
	} else {
860 861
		back.red = back.green = back.blue = 0.0; back.alpha = 1.0;
		fore.red = fore.green = fore.blue = 1.0; fore.alpha = 1.0;
862
	}
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
863

864
	gdk_window_set_debug_updates(debug);
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
865 866 867 868

	/* Create a window to hold the scrolling shell, and hook its
	 * delete event to the quit function.. */
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
869 870
	gtk_container_set_resize_mode(GTK_CONTAINER(window),
				      GTK_RESIZE_IMMEDIATE);
871 872 873 874 875 876 877
        if (border_width_string) {
                guint w;

                w = g_ascii_strtoull (border_width_string, NULL, 10);
                gtk_container_set_border_width(GTK_CONTAINER(window), w);
                g_free (border_width_string);
        }
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
878

879
	/* Set ARGB visual */
880
	screen = gtk_widget_get_screen (window);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
881 882 883
	visual = gdk_screen_get_rgba_visual(screen);
	if (visual)
		gtk_widget_set_visual(GTK_WIDGET(window), visual);
884

Behdad Esfahbod's avatar
Behdad Esfahbod committed
885 886 887 888 889 890 891 892 893 894
	if (use_scrolled_window) {
		scrolled_window = gtk_scrolled_window_new (NULL, NULL);
		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
					       GTK_POLICY_NEVER, scrollbar_policy);
		gtk_container_add(GTK_CONTAINER(window), scrolled_window);
	} else {
		/* Create a box to hold everything. */
		hbox = gtk_hbox_new(0, FALSE);
		gtk_container_add(GTK_CONTAINER(window), hbox);
	}
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
895 896

	/* Create the terminal widget and add it to the scrolling shell. */
897
	widget = vteapp_terminal_new();
898
	terminal = VTE_TERMINAL (widget);
899
        if (!dbuffer) {
900 901
		gtk_widget_set_double_buffered(widget, dbuffer);
	}
Behdad Esfahbod's avatar
Behdad Esfahbod committed
902 903 904 905 906 907 908
	if (show_object_notifications)
		g_signal_connect(terminal, "notify", G_CALLBACK(terminal_notify_cb), NULL);
	if (use_scrolled_window) {
		gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(terminal));
	} else {
		gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
	}
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
909 910 911

	/* Connect to the "char_size_changed" signal to set geometry hints
	 * whenever the font used by the terminal is changed. */
912
	if (use_geometry_hints) {
913
		char_size_changed(widget, 0, 0, window);
914
		g_signal_connect(widget, "char-size-changed",
915
				 G_CALLBACK(char_size_changed), window);
916 917
		g_signal_connect(widget, "realize",
				 G_CALLBACK(char_size_realized), window);
918
	}
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
919

920 921
	/* Connect to the "window_title_changed" signal to set the main
	 * window's title. */
922
	g_signal_connect(widget, "window-title-changed",
923
			 G_CALLBACK(window_title_changed), window);
924
	if (icon_title) {
925
		g_signal_connect(widget, "icon-title-changed",
926 927
				 G_CALLBACK(icon_title_changed), window);
	}
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
928

929
	/* Connect to the "status-line-changed" signal. */
930
	g_signal_connect(widget, "status-line-changed",
931 932
			 G_CALLBACK(status_line_changed), widget);

933
	/* Connect to the "button-press" event. */
934
	g_signal_connect(widget, "button-press-event",
935 936 937
			 G_CALLBACK(button_pressed), widget);

	/* Connect to application request signals. */
938
	g_signal_connect(widget, "iconify-window",
939
			 G_CALLBACK(iconify_window), window);
940
	g_signal_connect(widget, "deiconify-window",
941
			 G_CALLBACK(deiconify_window), window);
942
	g_signal_connect(widget, "raise-window",
943
			 G_CALLBACK(raise_window), window);
944
	g_signal_connect(widget, "lower-window",
945
			 G_CALLBACK(lower_window), window);
946
	g_signal_connect(widget, "maximize-window",
947
			 G_CALLBACK(maximize_window), window);
948
	g_signal_connect(widget, "restore-window",
949
			 G_CALLBACK(restore_window), window);
950
	g_signal_connect(widget, "refresh-window",
951
			 G_CALLBACK(refresh_window), window);
952
	g_signal_connect(widget, "resize-window",
953
			 G_CALLBACK(resize_window), window);
954
	g_signal_connect(widget, "move-window",
955 956
			 G_CALLBACK(move_window), window);

957
	/* Connect to font tweakage. */
958
	g_signal_connect(widget, "increase-font-size",
959
			 G_CALLBACK(increase_font_size), window);
960
	g_signal_connect(widget, "decrease-font-size",
961 962
			 G_CALLBACK(decrease_font_size), window);

Behdad Esfahbod's avatar
Behdad Esfahbod committed
963 964
	if (!use_scrolled_window) {
		/* Create the scrollbar for the widget. */
965
		scrollbar = gtk_vscrollbar_new(gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(terminal)));
Behdad Esfahbod's avatar
Behdad Esfahbod committed
966 967
		gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE, FALSE, 0);
	}
Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
968

969
	/* Set some defaults. */
970 971
	vte_terminal_set_audible_bell(terminal, audible);
	vte_terminal_set_visible_bell(terminal, !audible);
972
	vte_terminal_set_cursor_blink_mode(terminal, cursor_blink_mode);
973 974 975 976
	vte_terminal_set_scroll_on_output(terminal, FALSE);
	vte_terminal_set_scroll_on_keystroke(terminal, TRUE);
	vte_terminal_set_scrollback_lines(terminal, lines);
	vte_terminal_set_mouse_autohide(terminal, TRUE);
977

978
	if (transparent != NULL) {
979
                back.alpha = g_ascii_strtod (transparent, NULL);
980
                g_free (transparent);
981
        }
982

983
	vte_terminal_set_colors_rgba(terminal, &fore, &back, NULL, 0);
984 985 986 987 988 989 990 991 992 993 994 995

	if (cursor_color_string) {
                GdkRGBA rgba;
                if (parse_color (cursor_color_string, &rgba))
                        vte_terminal_set_color_cursor_rgba(terminal, &rgba);
                g_free(cursor_color_string);
	}
	if (highlight_foreground_color_string) {
                GdkRGBA rgba;
                if (parse_color (highlight_foreground_color_string, &rgba))
                        vte_terminal_set_color_cursor_rgba(terminal, &rgba);
                g_free(highlight_foreground_color_string);
996
	}
997 998 999 1000 1001
	if (highlight_background_color_string) {
                GdkRGBA rgba;
                if (parse_color (highlight_background_color_string, &rgba))
                        vte_terminal_set_color_cursor_rgba(terminal, &rgba);
                g_free(highlight_background_color_string);
1002
	}
1003

1004 1005
	if (termcap != NULL) {
		vte_terminal_set_emulation(terminal, termcap);
1006
	}
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
        if (encoding != NULL) {
                vte_terminal_set_encoding(terminal, encoding);
                g_free(encoding);
        }
        if (cjk_ambiguous_width != NULL) {
                int width = 1;

                if (g_ascii_strcasecmp(cjk_ambiguous_width, "narrow") == 0)
                        width = 1;
                else if (g_ascii_strcasecmp(cjk_ambiguous_width, "wide") == 0)
                        width = 2;
                else
                        g_printerr("Unrecognised value \"%s\" for --cjk-width\n",
                                   cjk_ambiguous_width);
                g_free(cjk_ambiguous_width);

                vte_terminal_set_cjk_ambiguous_width(terminal, width);
        }

Behdad Esfahbod's avatar
Behdad Esfahbod committed
1026
	vte_terminal_set_cursor_shape(terminal, cursor_shape);
1027

1028 1029
	vte_terminal_set_rewrap_on_resize(terminal, rewrap);

1030
	/* Set the default font. */
1031
        if (font) {
1032 1033 1034 1035 1036
                PangoFontDescription *desc;

                desc = pango_font_description_from_string(font);
                vte_terminal_set_font(terminal, desc);
                pango_font_description_free(desc);
1037
        }
1038

1039
	/* Match "abcdefg". */
1040 1041
	if (!no_builtin_dingus) {
                add_dingus (terminal, (char **) builtin_dingus);
1042
	}
1043 1044 1045 1046
	if (dingus) {
                add_dingus (terminal, dingus);
                g_strfreev (dingus);
        }
1047

1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
	if (console) {
		/* Open a "console" connection. */
		int consolefd = -1, yes = 1, watch;
		GIOChannel *channel;
		consolefd = open("/dev/console", O_RDONLY | O_NOCTTY);
		if (consolefd != -1) {
			/* Assume failure. */
			console = FALSE;
#ifdef TIOCCONS
			if (ioctl(consolefd, TIOCCONS, &yes) != -1) {
				/* Set up a listener. */
				channel = g_io_channel_unix_new(consolefd);
				watch = g_io_add_watch(channel,
						       G_IO_IN,
						       read_and_feed,
						       widget);
1064 1065 1066 1067 1068 1069 1070 1071
				g_signal_connect_swapped(widget,
                                                         "eof",
                                                         G_CALLBACK(disconnect_watch),
                                                         GINT_TO_POINTER(watch));
				g_signal_connect_swapped(widget,
                                                         "child-exited",
                                                         G_CALLBACK(disconnect_watch),
                                                         GINT_TO_POINTER(watch));
1072
				g_signal_connect(widget,
1073 1074 1075
						 "realize",
						 G_CALLBACK(take_xconsole_ownership),
						 NULL);
1076
#ifdef VTE_DEBUG
1077
				vte_terminal_feed(terminal,
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
						  "Console log for ...\r\n",
						  -1);
#endif
				/* Record success. */
				console = TRUE;
			}
#endif
		} else {
			/* Bail back to normal mode. */
			g_warning(_("Could not open console.\n"));
			close(consolefd);
			console = FALSE;
		}
1091
	}
1092

1093
	if (!console) {
1094
		if (shell) {
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1095 1096 1097 1098
			GError *err = NULL;
			char **command_argv = NULL;
			int command_argc;
			GPid pid = -1;
1099
                        char *free_me = NULL;
1100

1101 1102
			_VTE_DEBUG_IF(VTE_DEBUG_MISC)
				vte_terminal_feed(terminal, message, -1);
1103

1104
                        if (command == NULL || *command == '\0')
1105
                                command = free_me = vte_get_user_shell ();
1106

Behdad Esfahbod's avatar
Behdad Esfahbod committed
1107 1108
			if (command == NULL || *command == '\0')
				command = g_getenv ("SHELL");
1109

Behdad Esfahbod's avatar
Behdad Esfahbod committed
1110 1111
			if (command == NULL || *command == '\0')
				command = "/bin/sh";
1112

1113
			if (!g_shell_parse_argv(command, &command_argc, &command_argv, &err) ||
Christian Persch's avatar
Christian Persch committed
1114
			    !vte_terminal_spawn_sync(terminal,
1115 1116 1117 1118 1119 1120 1121
							    pty_flags,
							    NULL,
							    command_argv,
							    env_add,
							    G_SPAWN_SEARCH_PATH,
							    NULL, NULL,
							    &pid,
Christian Persch's avatar
Christian Persch committed
1122
                                                            NULL /* cancellable */,
1123 1124 1125 1126 1127 1128 1129
							    &err)) {
				g_warning("Failed to fork: %s\n", err->message);
				g_error_free(err);
			} else {
				g_print("Fork succeeded, PID %d\n", pid);
			}

1130
                        g_free (free_me);
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1131
			g_strfreev(command_argv);
1132
		} else {
1133
                        #ifdef HAVE_FORK
Christian Persch's avatar
Christian Persch committed
1134
                        GError *err = NULL;
1135 1136 1137 1138
                        VtePty *pty;
			pid_t pid;
                        int i;

Christian Persch's avatar
Christian Persch committed
1139 1140 1141 1142 1143 1144 1145
                        pty = vte_pty_new_sync(VTE_PTY_DEFAULT, NULL, &err);
                        if (pty == NULL) {
                                g_printerr ("Failed to create PTY: %s\n", err->message);
                                g_error_free(err);
                                return 1;
                        }

1146 1147
			pid = fork();
			switch (pid) {
1148 1149
			case -1:
				/* abnormal */
1150
				g_warning("Error forking: %s",
Christian Persch's avatar
Christian Persch committed
1151
					  g_strerror(errno));
1152 1153
                                g_object_unref(pty);
                                break;
1154 1155
			case 0:
				/* child */
1156 1157
                                vte_pty_child_setup(pty);

1158 1159 1160 1161
				for (i = 0; ; i++) {
					switch (i % 3) {
					case 0:
					case 1:
1162
						g_print("%d\n", i);
1163 1164
						break;
					case 2:
1165
						g_printerr("%d\n", i);
1166 1167 1168 1169 1170 1171 1172
						break;
					}
					sleep(1);
				}
				_exit(0);
				break;
			default:
Christian Persch's avatar
Christian Persch committed
1173
                                vte_terminal_set_pty(terminal, pty);
1174 1175 1176 1177
                                g_object_unref(pty);
                                vte_terminal_watch_child(terminal, pid);
				g_print("Child PID is %d (mine is %d).\n",
					(int) pid, (int) getpid());
1178 1179 1180
				/* normal */
				break;
			}
1181
                        #endif /* HAVE_FORK */
1182
		}
1183
	}
1184

1185 1186
	g_object_set_data (G_OBJECT (widget), "output_file", (gpointer) output_file);

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
1187
	/* Go for it! */
1188 1189 1190
	g_signal_connect(widget, "child-exited", G_CALLBACK(child_exited), window);
	g_signal_connect(window, "delete-event", G_CALLBACK(delete_event), widget);

1191 1192
	add_weak_pointer(G_OBJECT(widget), &widget);
	add_weak_pointer(G_OBJECT(window), &window);
1193

Behdad Esfahbod's avatar
Behdad Esfahbod committed
1194 1195 1196 1197 1198
	gtk_widget_realize(widget);
	if (geometry) {
		if (!gtk_window_parse_geometry (GTK_WINDOW(window), geometry)) {
			g_warning (_("Could not parse the geometry spec passed to --geometry"));
		}
1199
	} else {
1200 1201 1202
		/* As of GTK+ 2.91.0, the default size of a window comes from its minimum
		 * size not its natural size, so we need to set the right default size
		 * explicitly */
1203
		gtk_window_set_default_geometry (GTK_WINDOW (window),
1204 1205 1206
						 vte_terminal_get_column_count (terminal),
						 vte_terminal_get_row_count (terminal));
	}
1207

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
1208
	gtk_widget_show_all(window);
1209

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
1210 1211
	gtk_main();

1212 1213 1214
	g_assert(widget == NULL);
	g_assert(window == NULL);

1215 1216 1217 1218 1219 1220
	if (keep) {
		while (TRUE) {
			sleep(60);
		}
	}

Nalin Dahyabhai's avatar
Nalin Dahyabhai committed
1221 1222
	return 0;
}