3 * $Id: xcatch.c,v 1.10 2004/04/08 01:36:29 mdw Exp $
5 * Catch input and trap it in an X window
7 * (c) 1998 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of the Edgeware X tools collection.
14 * X tools is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * X tools is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with X tools; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Header files ------------------------------------------------------*/
37 #include <sys/types.h>
45 #include <mLib/dstr.h>
46 #include <mLib/mdwopt.h>
47 #include <mLib/report.h>
48 #include <mLib/quis.h>
50 #include <mgLib/cancel.h>
51 #include <mgLib/msg.h>
53 /*----- Inportant state ---------------------------------------------------*/
55 static unsigned int flags;
60 static GtkWidget *textbox = 0;
63 static pid_t kid = -1;
66 /*----- Main code ---------------------------------------------------------*/
68 /* --- The window's closed --- */
70 static void killwin(GtkWidget *w, gpointer p)
78 /* --- Some input has arrived --- */
80 static void ready(gpointer data, gint fd, GdkInputCondition c)
85 GtkAdjustment *va = 0;
87 /* --- If not ready to read then go away --- */
89 if (!(c & GDK_INPUT_READ))
92 /* --- Decide whether to scroll the window --- */
95 t = GTK_TEXT(textbox);
97 if (va->value + va->page_size < va->upper)
102 /* --- Read data into the buffer --- *
104 * This is a bit of a mess.
108 int r = read(fd, buf, sizeof(buf));
110 /* --- The read failed --- *
112 * Maybe there's no more data to read. In this case, we get
113 * @EWOULDBLOCK@, indicating it's time to stop and do something else.
114 * Otherwise something serious has happened.
118 if (errno == EWOULDBLOCK)
120 msg(QUIS, ":~OK", "error reading data: %s", strerror(errno));
124 /* --- End of file --- *
126 * If the box is closed, then exit quiety; otherwise wait for it to
139 /* --- If there's no output window, create one --- */
146 win = gtk_dialog_new();
147 gtk_window_set_policy(GTK_WINDOW(win), 1, 1, 0);
148 gtk_signal_connect(GTK_OBJECT(win), "destroy",
149 GTK_SIGNAL_FUNC(killwin), 0);
151 tbl = gtk_table_new(2, 2, 0);
152 gtk_container_border_width(GTK_CONTAINER(tbl), 8);
153 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(win)->vbox), tbl, 1, 1, 1);
154 gtk_widget_show(tbl);
156 textbox = gtk_text_new(0, 0);
157 t = GTK_TEXT(textbox);
159 gtk_table_attach(GTK_TABLE(tbl), textbox, 0, 1, 0, 1,
160 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
161 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
163 gtk_text_set_editable(t, 0);
164 gtk_widget_set_usize(textbox, 500, 300);
166 gtk_widget_show(textbox);
168 w = gtk_vscrollbar_new(va);
169 gtk_table_attach(GTK_TABLE(tbl), w, 1, 2, 0, 1,
170 0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
173 w = gtk_hscrollbar_new(t->hadj);
174 gtk_table_attach(GTK_TABLE(tbl), w, 0, 1, 1, 2,
175 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0, 0);
178 gtk_box_set_homogeneous(GTK_BOX(GTK_DIALOG(win)->action_area), 0);
179 w = gtk_button_new_with_label("Dismiss");
180 gtk_signal_connect_object(GTK_OBJECT(w), "clicked",
181 GTK_SIGNAL_FUNC(gtk_object_destroy),
183 gtk_box_pack_end(GTK_BOX(GTK_DIALOG(win)->action_area), w, 0, 0, 0);
184 GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
185 gtk_widget_grab_default(w);
186 cancel(GTK_WINDOW(win), w);
189 gtk_widget_show(win);
192 gtk_text_insert(t, font, 0, 0, buf, r);
198 gtk_adjustment_set_value(va, va->upper - va->page_size);
202 /* --- Signal handler --- */
204 static void reap(int sig)
211 k = waitpid(-1, &s, WNOHANG);
216 status = WEXITSTATUS(s);
224 /* --- Main program --- */
226 static void version(FILE *fp)
228 fprintf(fp, "%s (xtoys version " VERSION ")\n", QUIS);
231 static void usage(FILE *fp)
233 fprintf(fp, "Usage: %s [-f file] [-F font] [command [args...]]\n", QUIS);
236 int main(int argc, char *argv[])
242 gtk_init(&argc, &argv);
245 static struct option opt[] = {
246 { "help", 0, 0, 'h' },
247 { "usage", 0, 0, 'u' },
248 { "version", 0, 0, 'v' },
249 { "file", OPTF_ARGREQ, 0, 'f' },
250 { "font", OPTF_ARGREQ, 0, 'F' },
253 int i = mdwopt(argc, argv, "+huvf:F:", opt, 0, 0, 0);
265 "Catches input from a pipe or other source, and captures it in a window.\n"
266 "Nothing is displayed if there's no input.\n"
268 "Options provided:\n"
270 "-h, --help Display this help text\n"
271 "-u, --usage Display a quick usage summary\n"
272 "-v, --version Display the version number\n"
273 "-f, --file=FILE\t Read input from the named file\n"
274 "-F, --font=FONT\t Display output in the named font\n",
287 if ((fd = open(optarg, O_RDONLY)) < 0) {
288 die(1, "couldn't open file: %s", strerror(errno));
293 font = gdk_font_load(optarg);
301 if (flags & f_bogus) {
312 sigset_t newmask, oldmask;
314 /* --- Set up a signal handler --- */
316 sa.sa_handler = reap;
317 sigemptyset(&sa.sa_mask);
318 sa.sa_flags = SA_NOCLDSTOP;
320 sa.sa_flags |= SA_RESTART;
322 sigaction(SIGCHLD, &sa, 0);
324 /* --- Start a child program --- */
327 die(1, "couldn't open pipe: %s", strerror(errno));
329 sigemptyset(&newmask);
330 sigaddset(&newmask, SIGCHLD);
331 sigprocmask(SIG_BLOCK, &newmask, &oldmask);
335 die(1, "couldn't fork: %s", strerror(errno));
340 if (pfd[1] != STDOUT_FILENO)
341 dup2(pfd[1], STDOUT_FILENO);
342 if (pfd[1] != STDERR_FILENO)
343 dup2(pfd[1], STDERR_FILENO);
344 if (pfd[1] != STDOUT_FILENO && pfd[1] != STDERR_FILENO)
346 execvp(argv[optind], argv + optind);
348 dstr_putf(&d, "%s: couldn't run `%s': %s\n",
349 QUIS, argv[optind], strerror(errno));
350 write(STDERR_FILENO, d.buf, d.len);
355 sigprocmask(SIG_SETMASK, &oldmask, 0);
362 int f = fcntl(fd, F_GETFL);
363 fcntl(fd, F_SETFL, f | O_NONBLOCK);
366 gdk_input_add(fd, GDK_INPUT_READ, ready, 0);
371 /*----- That's all, folks -------------------------------------------------*/