2 * Copyright (C) 2003 Red Hat, Inc.
4 * This is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Library General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "../config.h"
21 #include <sys/types.h>
33 #include <libzvt/libzvt.h>
37 static GArray *contents = NULL;
41 * Implementation for a TextView widget.
44 terminal_init_text_view(GtkWidget **widget)
46 *widget = gtk_text_view_new();
47 gtk_text_view_set_editable(GTK_TEXT_VIEW(*widget), TRUE);
50 terminal_shell_text_view(GtkWidget *widget)
54 static GtkAdjustment *
55 terminal_adjustment_text_view(GtkWidget *terminal)
57 return (GTK_TEXT_VIEW(terminal))->vadjustment;
62 * Implementation for a VteTerminal widget.
65 terminal_init_vte(GtkWidget **terminal)
67 *terminal = vte_terminal_new();
68 g_signal_connect(G_OBJECT(*terminal), "eof",
69 G_CALLBACK(gtk_main_quit), NULL);
70 g_signal_connect(G_OBJECT(*terminal), "child-exited",
71 G_CALLBACK(gtk_main_quit), NULL);
74 terminal_shell_vte(GtkWidget *terminal)
76 vte_terminal_fork_command(VTE_TERMINAL(terminal),
77 getenv("SHELL") ? getenv("SHELL") : "/bin/sh",
80 g_get_home_dir() ? g_get_home_dir() : NULL,
85 static GtkAdjustment *
86 terminal_adjustment_vte(GtkWidget *terminal)
88 return (VTE_TERMINAL(terminal))->adjustment;
94 * Implementation for a ZvtTerm widget.
97 terminal_hint_zvt(GtkWidget *widget, gpointer data)
104 terminal = ZVT_TERM(widget);
106 toplevel = gtk_widget_get_toplevel(widget);
107 g_assert(toplevel != NULL);
109 gtk_widget_ensure_style(widget);
110 style = widget->style;
111 hints.base_width = style->xthickness * 2 + 2;
112 hints.base_height = style->ythickness * 2;
114 hints.width_inc = terminal->charwidth;
115 hints.height_inc = terminal->charheight;
116 hints.min_width = hints.base_width + hints.width_inc;
117 hints.min_height = hints.base_height + hints.height_inc;
119 gtk_window_set_geometry_hints(GTK_WINDOW(toplevel),
122 GDK_HINT_RESIZE_INC |
125 gtk_widget_queue_resize(widget);
128 terminal_init_zvt(GtkWidget **terminal)
130 *terminal = zvt_term_new();
131 g_signal_connect_after(G_OBJECT(*terminal), "realize",
132 G_CALLBACK(terminal_hint_zvt), NULL);
135 terminal_shell_zvt(GtkWidget *terminal)
138 shell = getenv("SHELL") ? getenv("SHELL") : "/bin/sh";
139 g_signal_connect(G_OBJECT(terminal), "child-died",
140 G_CALLBACK(gtk_main_quit), NULL);
141 if (zvt_term_forkpty(ZVT_TERM(terminal), 0) == 0) {
142 execlp(shell, shell, NULL);
143 g_assert_not_reached();
146 static GtkAdjustment *
147 terminal_adjustment_zvt(GtkWidget *terminal)
149 return (ZVT_TERM(terminal))->adjustment;
153 * Implementation for broken setups.
156 terminal_init_broken(GtkWidget **terminal)
158 g_error("libzvt not found at compile-time");
162 terminal_shell_broken(GtkWidget *terminal)
164 g_error("libzvt not found at compile-time");
167 static GtkAdjustment *
168 terminal_adjustment_broken(GtkWidget *terminal)
170 g_error("libzvt not found at compile-time");
177 * Update the contents of the widget with the data from our contents array.
180 update_contents(AtkObject *obj, GtkWidget *widget)
185 caret = atk_text_get_caret_offset(ATK_TEXT(obj));
186 s = g_string_new("");
187 for (i = 0; i < contents->len; i++) {
189 s = g_string_append(s, "[CARET]");
191 s = g_string_append_unichar(s,
192 g_array_index(contents,
197 s = g_string_append(s, "[CARET]");
199 if (GTK_IS_LABEL(widget)) {
200 gtk_label_set_text(GTK_LABEL(widget), s->str);
201 gtk_label_set_selectable(GTK_LABEL(widget),
202 atk_text_get_n_selections(ATK_TEXT(obj)) > 0);
203 if (gtk_label_get_selectable(GTK_LABEL(widget))) {
204 int selection_start, selection_end;
205 atk_text_get_selection(ATK_TEXT(obj), 0,
208 gtk_label_select_region(GTK_LABEL(widget),
209 selection_start, selection_end);
212 g_string_free(s, TRUE);
215 /* Handle inserted text by inserting the text into our gunichar array. */
217 text_changed_insert(AtkObject *obj, gint offset, gint length, gpointer data)
223 inserted = atk_text_get_text(ATK_TEXT(obj), offset, offset + length);
225 if (!g_utf8_validate(inserted, -1, NULL)) {
227 g_error("UTF-8 validation error");
234 c = g_utf8_get_char(p);
235 if (offset + i >= contents->len) {
236 g_array_append_val(contents, c);
238 g_array_insert_val(contents, offset + i, c);
241 p = g_utf8_next_char(p);
245 if ((getenv("REFLECT_VERBOSE") != NULL) &&
246 (atol(getenv("REFLECT_VERBOSE")) != 0)) {
247 fprintf(stderr, "Inserted %d chars ('%.*s') at %d,",
248 length, (int)(p - inserted), inserted, offset);
249 fprintf(stderr, " buffer contains %d characters.\n",
256 update_contents(obj, GTK_WIDGET(data));
259 /* Handle deleted text by removing the text from our gunichar array. */
261 text_changed_delete(AtkObject *obj, gint offset, gint length, gpointer data)
264 for (i = offset + length - 1; i >= offset; i--) {
265 if (i > contents->len - 1) {
266 g_warning("Invalid character %d was deleted.\n", i);
268 g_array_remove_index(contents, i);
271 if ((getenv("REFLECT_VERBOSE") != NULL) &&
272 (atol(getenv("REFLECT_VERBOSE")) != 0)) {
273 fprintf(stderr, "Deleted %d chars at %d.\n", length, offset);
276 update_contents(obj, GTK_WIDGET(data));
280 text_caret_moved(AtkObject *obj, gint offset, gpointer data)
282 update_contents(obj, GTK_WIDGET(data));
286 text_selection_changed(AtkObject *obj, gpointer data)
288 update_contents(obj, GTK_WIDGET(data));
291 /* Wrapper versions. */
293 terminal_init(GtkWidget **terminal)
298 terminal_init_zvt(terminal);
301 terminal_init_broken(terminal);
306 terminal_init_text_view(terminal);
310 terminal_init_vte(terminal);
313 g_assert_not_reached();
316 terminal_shell(GtkWidget *terminal)
320 terminal_shell_zvt(terminal);
323 terminal_shell_broken(terminal);
328 terminal_shell_text_view(terminal);
332 terminal_shell_vte(terminal);
335 g_assert_not_reached();
337 static GtkAdjustment *
338 terminal_adjustment(GtkWidget *terminal)
342 return terminal_adjustment_zvt(terminal);
344 return terminal_adjustment_broken(terminal);
348 return terminal_adjustment_text_view(terminal);
351 return terminal_adjustment_vte(terminal);
353 g_assert_not_reached();
357 main(int argc, char **argv)
359 GtkWidget *label, *terminal, *tophalf, *pane, *window, *scrollbar, *sw;
365 gtk_init(&argc, &argv);
367 contents = g_array_new(TRUE, FALSE, sizeof(gunichar));
369 terminal_init(&terminal);
372 tophalf = gtk_scrolled_window_new(NULL, terminal_adjustment(terminal));
373 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tophalf),
374 GTK_POLICY_AUTOMATIC,
375 GTK_POLICY_AUTOMATIC);
377 gtk_container_add(GTK_CONTAINER(tophalf), terminal);
379 tophalf = gtk_hbox_new(FALSE, 0);
381 gtk_box_pack_start(GTK_BOX(tophalf), terminal, TRUE, TRUE, 0);
382 gtk_widget_show(terminal);
384 scrollbar = gtk_vscrollbar_new(terminal_adjustment(terminal));
385 gtk_box_pack_start(GTK_BOX(tophalf), scrollbar, FALSE, TRUE, 0);
386 gtk_widget_show(scrollbar);
388 gtk_widget_show(terminal);
390 label = gtk_label_new("");
391 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
392 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
394 sw = gtk_scrolled_window_new(NULL, NULL);
395 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw), label);
396 gtk_widget_show(label);
398 pane = gtk_vpaned_new();
399 gtk_paned_pack1(GTK_PANED(pane), tophalf, TRUE, FALSE);
400 gtk_paned_pack2(GTK_PANED(pane), sw, TRUE, FALSE);
401 gtk_widget_show(tophalf);
404 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
405 g_signal_connect(G_OBJECT(window), "delete_event",
406 G_CALLBACK(gtk_main_quit), NULL);
407 gtk_container_add(GTK_CONTAINER(window), pane);
408 gtk_widget_show(pane);
410 obj = gtk_widget_get_accessible(terminal);
411 g_assert(obj != NULL);
412 g_signal_connect(G_OBJECT(obj), "text-changed::insert",
413 G_CALLBACK(text_changed_insert), label);
414 g_signal_connect(G_OBJECT(obj), "text-changed::delete",
415 G_CALLBACK(text_changed_delete), label);
416 g_signal_connect(G_OBJECT(obj), "text-caret-moved",
417 G_CALLBACK(text_caret_moved), label);
418 g_signal_connect(G_OBJECT(obj), "text-selection-changed",
419 G_CALLBACK(text_selection_changed), label);
421 count = atk_text_get_character_count(ATK_TEXT(obj));
423 text = atk_text_get_text(ATK_TEXT(obj), 0, count);
426 contents->len < count;
427 p = g_utf8_next_char(p)) {
428 c = g_utf8_get_char(p);
429 g_array_append_val(contents, c);
434 terminal_shell(terminal);
436 gtk_window_set_default_size(GTK_WINDOW(window), 600, 450);
437 gtk_widget_show(window);
439 update_contents(obj, terminal);
443 g_array_free(contents, TRUE);