diff options
Diffstat (limited to 'unix/gtkmain.c')
-rw-r--r-- | unix/gtkmain.c | 673 |
1 files changed, 0 insertions, 673 deletions
diff --git a/unix/gtkmain.c b/unix/gtkmain.c deleted file mode 100644 index ec8f7da4..00000000 --- a/unix/gtkmain.c +++ /dev/null @@ -1,673 +0,0 @@ -/* - * gtkmain.c: the common main-program code between the straight-up - * Unix PuTTY and pterm, which they do not share with the - * multi-session gtkapp.c. - */ - -#define _GNU_SOURCE - -#include <string.h> -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <stdio.h> -#include <time.h> -#include <errno.h> -#include <locale.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <gtk/gtk.h> -#if !GTK_CHECK_VERSION(3,0,0) -#include <gdk/gdkkeysyms.h> -#endif - -#if GTK_CHECK_VERSION(2,0,0) -#include <gtk/gtkimmodule.h> -#endif - -#define MAY_REFER_TO_GTK_IN_HEADERS - -#include "putty.h" -#include "terminal.h" -#include "gtkcompat.h" -#include "gtkfont.h" -#include "gtkmisc.h" - -#ifndef NOT_X_WINDOWS -#include <gdk/gdkx.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xatom.h> -#include "x11misc.h" -#endif - -static char *progname, **gtkargvstart; -static int ngtkargs; - -static const char *app_name = "pterm"; - -char *x_get_default(const char *key) -{ -#ifndef NOT_X_WINDOWS - Display *disp; - if ((disp = get_x11_display()) == NULL) - return NULL; - return XGetDefault(disp, app_name, key); -#else - return NULL; -#endif -} - -void fork_and_exec_self(int fd_to_close, ...) -{ - /* - * Re-execing ourself is not an exact science under Unix. I do - * the best I can by using /proc/self/exe if available and by - * assuming argv[0] can be found on $PATH if not. - * - * Note that we also have to reconstruct the elements of the - * original argv which gtk swallowed, since the user wants the - * new session to appear on the same X display as the old one. - */ - char **args; - va_list ap; - int i, n; - int pid; - - /* - * Collect the arguments with which to re-exec ourself. - */ - va_start(ap, fd_to_close); - n = 2; /* progname and terminating NULL */ - n += ngtkargs; - while (va_arg(ap, char *) != NULL) - n++; - va_end(ap); - - args = snewn(n, char *); - args[0] = progname; - args[n-1] = NULL; - for (i = 0; i < ngtkargs; i++) - args[i+1] = gtkargvstart[i]; - - i++; - va_start(ap, fd_to_close); - while ((args[i++] = va_arg(ap, char *)) != NULL); - va_end(ap); - - assert(i == n); - - /* - * Do the double fork. - */ - pid = fork(); - if (pid < 0) { - perror("fork"); - sfree(args); - return; - } - - if (pid == 0) { - int pid2 = fork(); - if (pid2 < 0) { - perror("fork"); - _exit(1); - } else if (pid2 > 0) { - /* - * First child has successfully forked second child. My - * Work Here Is Done. Note the use of _exit rather than - * exit: the latter appears to cause destroy messages - * to be sent to the X server. I suspect gtk uses - * atexit. - */ - _exit(0); - } - - /* - * If we reach here, we are the second child, so we now - * actually perform the exec. - */ - if (fd_to_close >= 0) - close(fd_to_close); - - execv("/proc/self/exe", args); - execvp(progname, args); - perror("exec"); - _exit(127); - - } else { - int status; - sfree(args); - waitpid(pid, &status, 0); - } - -} - -void launch_duplicate_session(Conf *conf) -{ - /* - * For this feature we must marshal conf and (possibly) pty_argv - * into a byte stream, create a pipe, and send this byte stream - * to the child through the pipe. - */ - int i, ret; - strbuf *serialised; - char option[80]; - int pipefd[2]; - - if (pipe(pipefd) < 0) { - perror("pipe"); - return; - } - - serialised = strbuf_new(); - - conf_serialise(BinarySink_UPCAST(serialised), conf); - if (use_pty_argv && pty_argv) - for (i = 0; pty_argv[i]; i++) - put_asciz(serialised, pty_argv[i]); - - sprintf(option, "---[%d,%zu]", pipefd[0], serialised->len); - noncloexec(pipefd[0]); - fork_and_exec_self(pipefd[1], option, NULL); - close(pipefd[0]); - - i = ret = 0; - while (i < serialised->len && - (ret = write(pipefd[1], serialised->s + i, - serialised->len - i)) > 0) - i += ret; - if (ret < 0) - perror("write to pipe"); - close(pipefd[1]); - strbuf_free(serialised); -} - -void launch_new_session(void) -{ - fork_and_exec_self(-1, NULL); -} - -void launch_saved_session(const char *str) -{ - fork_and_exec_self(-1, "-load", str, NULL); -} - -int read_dupsession_data(Conf *conf, char *arg) -{ - int fd, i, ret, size; - char *data; - BinarySource src[1]; - - if (sscanf(arg, "---[%d,%d]", &fd, &size) != 2) { - fprintf(stderr, "%s: malformed magic argument `%s'\n", appname, arg); - exit(1); - } - - data = snewn(size, char); - i = ret = 0; - while (i < size && (ret = read(fd, data + i, size - i)) > 0) - i += ret; - if (ret < 0) { - perror("read from pipe"); - exit(1); - } else if (i < size) { - fprintf(stderr, "%s: unexpected EOF in Duplicate Session data\n", - appname); - exit(1); - } - - BinarySource_BARE_INIT(src, data, size); - if (!conf_deserialise(conf, src)) { - fprintf(stderr, "%s: malformed Duplicate Session data\n", appname); - exit(1); - } - if (use_pty_argv) { - int pty_argc = 0; - size_t argv_startpos = src->pos; - - while (get_asciz(src), !get_err(src)) - pty_argc++; - - src->err = BSE_NO_ERROR; - - if (pty_argc > 0) { - src->pos = argv_startpos; - - pty_argv = snewn(pty_argc + 1, char *); - pty_argv[pty_argc] = NULL; - for (i = 0; i < pty_argc; i++) - pty_argv[i] = dupstr(get_asciz(src)); - } - } - - if (get_err(src) || get_avail(src) > 0) { - fprintf(stderr, "%s: malformed Duplicate Session data\n", appname); - exit(1); - } - - sfree(data); - return 0; -} - -static void help(FILE *fp) { - if(fprintf(fp, -"pterm option summary:\n" -"\n" -" --display DISPLAY Specify X display to use (note '--')\n" -" -name PREFIX Prefix when looking up resources (default: pterm)\n" -" -fn FONT Normal text font\n" -" -fb FONT Bold text font\n" -" -geometry GEOMETRY Position and size of window (size in characters)\n" -" -sl LINES Number of lines of scrollback\n" -" -fg COLOUR, -bg COLOUR Foreground/background colour\n" -" -bfg COLOUR, -bbg COLOUR Foreground/background bold colour\n" -" -cfg COLOUR, -bfg COLOUR Foreground/background cursor colour\n" -" -T TITLE Window title\n" -" -ut, +ut Do(default) or do not update utmp\n" -" -ls, +ls Do(default) or do not make shell a login shell\n" -" -sb, +sb Do(default) or do not display a scrollbar\n" -" -log PATH, -sessionlog PATH Log all output to a file\n" -" -nethack Map numeric keypad to hjklyubn direction keys\n" -" -xrm RESOURCE-STRING Set an X resource\n" -" -e COMMAND [ARGS...] Execute command (consumes all remaining args)\n" - ) < 0 || fflush(fp) < 0) { - perror("output error"); - exit(1); - } -} - -static void version(FILE *fp) { - char *buildinfo_text = buildinfo("\n"); - if(fprintf(fp, "%s: %s\n%s\n", appname, ver, buildinfo_text) < 0 || - fflush(fp) < 0) { - perror("output error"); - exit(1); - } - sfree(buildinfo_text); -} - -static const char *geometry_string; - -void cmdline_error(const char *p, ...) -{ - va_list ap; - fprintf(stderr, "%s: ", appname); - va_start(ap, p); - vfprintf(stderr, p, ap); - va_end(ap); - fputc('\n', stderr); - exit(1); -} - -void window_setup_error(const char *errmsg) -{ - fprintf(stderr, "%s: %s\n", appname, errmsg); - exit(1); -} - -bool do_cmdline(int argc, char **argv, bool do_everything, Conf *conf) -{ - bool err = false; - char *val; - - /* - * Macros to make argument handling easier. - * - * Note that because they need to call `continue', they cannot be - * contained in the usual do {...} while (0) wrapper to make them - * syntactically single statements. I use the alternative if (1) - * {...} else ((void)0). - */ -#define EXPECTS_ARG if (1) { \ - if (--argc <= 0) { \ - err = true; \ - fprintf(stderr, "%s: %s expects an argument\n", appname, p); \ - continue; \ - } else \ - val = *++argv; \ - } else ((void)0) -#define SECOND_PASS_ONLY if (1) { \ - if (!do_everything) \ - continue; \ - } else ((void)0) - - while (--argc > 0) { - const char *p = *++argv; - int ret; - - /* - * Shameless cheating. Debian requires all X terminal - * emulators to support `-T title'; but - * cmdline_process_param will eat -T (it means no-pty) and - * complain that pterm doesn't support it. So, in pterm - * only, we convert -T into -title. - */ - if ((cmdline_tooltype & TOOLTYPE_NONNETWORK) && - !strcmp(p, "-T")) - p = "-title"; - - ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), - do_everything ? 1 : -1, conf); - - if (ret == -2) { - cmdline_error("option \"%s\" requires an argument", p); - } else if (ret == 2) { - --argc, ++argv; /* skip next argument */ - continue; - } else if (ret == 1) { - continue; - } - - if (!strcmp(p, "-fn") || !strcmp(p, "-font")) { - FontSpec *fs; - EXPECTS_ARG; - SECOND_PASS_ONLY; - fs = fontspec_new(val); - conf_set_fontspec(conf, CONF_font, fs); - fontspec_free(fs); - - } else if (!strcmp(p, "-fb")) { - FontSpec *fs; - EXPECTS_ARG; - SECOND_PASS_ONLY; - fs = fontspec_new(val); - conf_set_fontspec(conf, CONF_boldfont, fs); - fontspec_free(fs); - - } else if (!strcmp(p, "-fw")) { - FontSpec *fs; - EXPECTS_ARG; - SECOND_PASS_ONLY; - fs = fontspec_new(val); - conf_set_fontspec(conf, CONF_widefont, fs); - fontspec_free(fs); - - } else if (!strcmp(p, "-fwb")) { - FontSpec *fs; - EXPECTS_ARG; - SECOND_PASS_ONLY; - fs = fontspec_new(val); - conf_set_fontspec(conf, CONF_wideboldfont, fs); - fontspec_free(fs); - - } else if (!strcmp(p, "-cs")) { - EXPECTS_ARG; - SECOND_PASS_ONLY; - conf_set_str(conf, CONF_line_codepage, val); - - } else if (!strcmp(p, "-geometry")) { - EXPECTS_ARG; - SECOND_PASS_ONLY; - geometry_string = val; - } else if (!strcmp(p, "-sl")) { - EXPECTS_ARG; - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_savelines, atoi(val)); - - } else if (!strcmp(p, "-fg") || !strcmp(p, "-bg") || - !strcmp(p, "-bfg") || !strcmp(p, "-bbg") || - !strcmp(p, "-cfg") || !strcmp(p, "-cbg")) { - EXPECTS_ARG; - SECOND_PASS_ONLY; - - { -#if GTK_CHECK_VERSION(3,0,0) - GdkRGBA rgba; - bool success = gdk_rgba_parse(&rgba, val); -#else - GdkColor col; - bool success = gdk_color_parse(val, &col); -#endif - - if (!success) { - err = true; - fprintf(stderr, "%s: unable to parse colour \"%s\"\n", - appname, val); - } else { -#if GTK_CHECK_VERSION(3,0,0) - int r = rgba.red * 255; - int g = rgba.green * 255; - int b = rgba.blue * 255; -#else - int r = col.red / 256; - int g = col.green / 256; - int b = col.blue / 256; -#endif - - int index; - index = (!strcmp(p, "-fg") ? 0 : - !strcmp(p, "-bg") ? 2 : - !strcmp(p, "-bfg") ? 1 : - !strcmp(p, "-bbg") ? 3 : - !strcmp(p, "-cfg") ? 4 : - !strcmp(p, "-cbg") ? 5 : -1); - assert(index != -1); - - conf_set_int_int(conf, CONF_colours, index*3+0, r); - conf_set_int_int(conf, CONF_colours, index*3+1, g); - conf_set_int_int(conf, CONF_colours, index*3+2, b); - } - } - - } else if (use_pty_argv && !strcmp(p, "-e")) { - /* This option swallows all further arguments. */ - if (!do_everything) - break; - - if (--argc > 0) { - int i; - pty_argv = snewn(argc+1, char *); - ++argv; - for (i = 0; i < argc; i++) - pty_argv[i] = argv[i]; - pty_argv[argc] = NULL; - break; /* finished command-line processing */ - } else - err = true, fprintf(stderr, "%s: -e expects an argument\n", - appname); - - } else if (!strcmp(p, "-title")) { - EXPECTS_ARG; - SECOND_PASS_ONLY; - conf_set_str(conf, CONF_wintitle, val); - - } else if (!strcmp(p, "-log")) { - Filename *fn; - EXPECTS_ARG; - SECOND_PASS_ONLY; - fn = filename_from_str(val); - conf_set_filename(conf, CONF_logfilename, fn); - conf_set_int(conf, CONF_logtype, LGTYP_DEBUG); - filename_free(fn); - - } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_stamp_utmp, false); - - } else if (!strcmp(p, "-ut")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_stamp_utmp, true); - - } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_login_shell, false); - - } else if (!strcmp(p, "-ls")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_login_shell, true); - - } else if (!strcmp(p, "-nethack")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_nethack_keypad, true); - - } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_scrollbar, false); - - } else if (!strcmp(p, "-sb")) { - SECOND_PASS_ONLY; - conf_set_bool(conf, CONF_scrollbar, true); - - } else if (!strcmp(p, "-name")) { - EXPECTS_ARG; - app_name = val; - - } else if (!strcmp(p, "-xrm")) { - EXPECTS_ARG; - provide_xrm_string(val, appname); - - } else if(!strcmp(p, "-help") || !strcmp(p, "--help")) { - help(stdout); - exit(0); - - } else if(!strcmp(p, "-version") || !strcmp(p, "--version")) { - version(stdout); - exit(0); - - } else if (!strcmp(p, "-pgpfp")) { - pgp_fingerprints(); - exit(1); - - } else if (p[0] != '-') { - /* Non-option arguments not handled by cmdline.c are errors. */ - if (do_everything) { - err = true; - fprintf(stderr, "%s: unexpected non-option argument '%s'\n", - appname, p); - } - - } else { - err = true; - fprintf(stderr, "%s: unrecognized option '%s'\n", appname, p); - } - } - - return err; -} - -GtkWidget *make_gtk_toplevel_window(GtkFrontend *frontend) -{ - return gtk_window_new(GTK_WINDOW_TOPLEVEL); -} - -const bool buildinfo_gtk_relevant = true; - -struct post_initial_config_box_ctx { - Conf *conf; - const char *geometry_string; -}; - -static void post_initial_config_box(void *vctx, int result) -{ - struct post_initial_config_box_ctx ctx = - *(struct post_initial_config_box_ctx *)vctx; - sfree(vctx); - - if (result > 0) { - new_session_window(ctx.conf, ctx.geometry_string); - } else { - /* In this main(), which only runs one session in total, a - * negative result from the initial config box means we simply - * terminate. */ - conf_free(ctx.conf); - gtk_main_quit(); - } -} - -void session_window_closed(void) -{ - gtk_main_quit(); -} - -int main(int argc, char **argv) -{ - Conf *conf; - bool need_config_box; - - setlocale(LC_CTYPE, ""); - - /* Call the function in ux{putty,pterm}.c to do app-type - * specific setup */ - setup(true); /* true means we are a one-session process */ - - progname = argv[0]; - - /* - * Copy the original argv before letting gtk_init fiddle with - * it. It will be required later. - */ - { - int i, oldargc; - gtkargvstart = snewn(argc-1, char *); - for (i = 1; i < argc; i++) - gtkargvstart[i-1] = dupstr(argv[i]); - oldargc = argc; - gtk_init(&argc, &argv); - ngtkargs = oldargc - argc; - } - - conf = conf_new(); - - gtkcomm_setup(); - - /* - * Block SIGPIPE: if we attempt Duplicate Session or similar and - * it falls over in some way, we certainly don't want SIGPIPE - * terminating the main pterm/PuTTY. However, we'll have to - * unblock it again when pterm forks. - */ - block_signal(SIGPIPE, true); - - if (argc > 1 && !strncmp(argv[1], "---", 3)) { - read_dupsession_data(conf, argv[1]); - /* Splatter this argument so it doesn't clutter a ps listing */ - smemclr(argv[1], strlen(argv[1])); - - assert(!dup_check_launchable || conf_launchable(conf)); - need_config_box = false; - } else { - if (do_cmdline(argc, argv, false, conf)) - exit(1); /* pre-defaults pass to get -class */ - do_defaults(NULL, conf); - if (do_cmdline(argc, argv, true, conf)) - exit(1); /* post-defaults, do everything */ - - cmdline_run_saved(conf); - - if (cmdline_tooltype & TOOLTYPE_HOST_ARG) - need_config_box = !cmdline_host_ok(conf); - else - need_config_box = false; - } - - if (need_config_box) { - /* - * Put up the initial config box, which will pass the provided - * parameters (with conf updated) to new_session_window() when - * (if) the user selects Open. Or it might close without - * creating a session window, if the user selects Cancel. Or - * it might just create the session window immediately if this - * is a pterm-style app which doesn't have an initial config - * box at all. - */ - struct post_initial_config_box_ctx *ctx = - snew(struct post_initial_config_box_ctx); - ctx->conf = conf; - ctx->geometry_string = geometry_string; - initial_config_box(conf, post_initial_config_box, ctx); - } else { - /* - * No initial config needed; just create the session window - * now. - */ - new_session_window(conf, geometry_string); - } - - gtk_main(); - - return 0; -} |