X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkwin.c;h=3ed58b08287a83e590f4aa08a1929b715a124fad;hb=eac66b0281f30be97094fe94174e65477b018812;hp=2879b57e9877814b27202f4f8716aa613c64d320;hpb=a5588cd6353d43a5ada8e4a866b896372574cea5;p=PuTTY.git diff --git a/unix/gtkwin.c b/unix/gtkwin.c index 2879b57e..3ed58b08 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -46,36 +46,12 @@ #include "x11misc.h" -#define CAT2(x,y) x ## y -#define CAT(x,y) CAT2(x,y) -#define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)} - -#if GTK_CHECK_VERSION(2,0,0) -ASSERT(sizeof(long) <= sizeof(gsize)); -#define LONG_TO_GPOINTER(l) GSIZE_TO_POINTER(l) -#define GPOINTER_TO_LONG(p) GPOINTER_TO_SIZE(p) -#else /* Gtk 1.2 */ -ASSERT(sizeof(long) <= sizeof(gpointer)); -#define LONG_TO_GPOINTER(l) ((gpointer)(long)(l)) -#define GPOINTER_TO_LONG(p) ((long)(p)) -#endif - /* Colours come in two flavours: configurable, and xterm-extended. */ #define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */ #define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS) GdkAtom compound_text_atom, utf8_string_atom; -extern char **pty_argv; /* declared in pty.c */ -extern int use_pty_argv; - -/* - * Timers are global across all sessions (even if we were handling - * multiple sessions, which we aren't), so the current timer ID is - * a global variable. - */ -static guint timer_id = 0; - struct clipboard_data_instance; struct gui_data { @@ -142,8 +118,6 @@ struct gui_data { int ignore_sbar; int mouseptr_visible; int busy_status; - guint toplevel_callback_idle_id; - int idle_fn_scheduled, quit_fn_scheduled; int alt_keycode; int alt_digits; char *wintitle; @@ -158,8 +132,6 @@ struct gui_data { struct unicode_data ucsdata; Conf *conf; void *eventlogstuff; - char *progname, **gtkargvstart; - int ngtkargs; guint32 input_event_time; /* Timestamp of the most recent input event. */ int reconfiguring; #if GTK_CHECK_VERSION(3,4,0) @@ -196,21 +168,9 @@ struct draw_ctx { static int send_raw_mouse; -static const char *app_name = "pterm"; - static void start_backend(struct gui_data *inst); static void exit_callback(void *vinst); -char *x_get_default(const char *key) -{ -#ifndef NOT_X_WINDOWS - return XGetDefault(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), - app_name, key); -#else - return NULL; -#endif -} - void connection_fatal(void *frontend, const char *p, ...) { struct gui_data *inst = (struct gui_data *)frontend; @@ -2014,48 +1974,6 @@ static void exit_callback(void *vinst) } } -/* - * Replacement code for the gtk_quit_add() function, which GTK2 - in - * their unbounded wisdom - deprecated without providing any usable - * replacement, and which we were using to ensure that our idle - * function for toplevel callbacks was only run from the outermost - * gtk_main(). - * - * We maintain a global variable with a list of 'struct gui_data' - * instances on which we should call inst_post_main() when a - * subsidiary gtk_main() terminates; then we must make sure that all - * our subsidiary calls to gtk_main() are followed by a call to - * post_main(). - * - * This is kind of overkill in the sense that at the time of writing - * we don't actually ever run more than one 'struct gui_data' instance - * in the same process, but we're _so nearly_ prepared to do that that - * I want to remain futureproof against the possibility of doing so in - * future. - */ -struct post_main_context { - struct post_main_context *next; - struct gui_data *inst; -}; -struct post_main_context *post_main_list_head = NULL; -static void request_post_main(struct gui_data *inst) -{ - struct post_main_context *node = snew(struct post_main_context); - node->next = post_main_list_head; - node->inst = inst; - post_main_list_head = node; -} -static void inst_post_main(struct gui_data *inst); -void post_main(void) -{ - while (post_main_list_head) { - struct post_main_context *node = post_main_list_head; - post_main_list_head = node->next; - inst_post_main(node->inst); - sfree(node); - } -} - void notify_remote_exit(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; @@ -2063,157 +1981,6 @@ void notify_remote_exit(void *frontend) queue_toplevel_callback(exit_callback, inst); } -static void notify_toplevel_callback(void *frontend); - -static void inst_post_main(struct gui_data *inst) -{ - if (gtk_main_level() == 1) { - notify_toplevel_callback(inst); - inst->quit_fn_scheduled = FALSE; - } else { - /* Apparently we're _still_ more than one level deep in - * gtk_main() instances, so we'll need another callback for - * when we get out of the next one. */ - request_post_main(inst); - } -} - -static gint idle_toplevel_callback_func(gpointer data) -{ - struct gui_data *inst = (struct gui_data *)data; - - if (gtk_main_level() > 1) { - /* - * We don't run the callbacks if we're in the middle of a - * subsidiary gtk_main. Instead, ask for a callback when we - * get back out of the subsidiary main loop (if we haven't - * already arranged one), so we can reschedule ourself then. - */ - if (!inst->quit_fn_scheduled) { - request_post_main(inst); - inst->quit_fn_scheduled = TRUE; - } - /* - * And unschedule this idle function, since we've now done - * everything we can until the innermost gtk_main has quit and - * can reschedule us with a chance of actually taking action. - */ - if (inst->idle_fn_scheduled) { /* double-check, just in case */ - g_source_remove(inst->toplevel_callback_idle_id); - inst->idle_fn_scheduled = FALSE; - } - } else { - run_toplevel_callbacks(); - } - - /* - * If we've emptied our toplevel callback queue, unschedule - * ourself. Otherwise, leave ourselves pending so we'll be called - * again to deal with more callbacks after another round of the - * event loop. - */ - if (!toplevel_callback_pending() && inst->idle_fn_scheduled) { - g_source_remove(inst->toplevel_callback_idle_id); - inst->idle_fn_scheduled = FALSE; - } - - return TRUE; -} - -static void notify_toplevel_callback(void *frontend) -{ - struct gui_data *inst = (struct gui_data *)frontend; - - if (!inst->idle_fn_scheduled) { - inst->toplevel_callback_idle_id = - g_idle_add(idle_toplevel_callback_func, inst); - inst->idle_fn_scheduled = TRUE; - } -} - -static gint timer_trigger(gpointer data) -{ - unsigned long now = GPOINTER_TO_LONG(data); - unsigned long next, then; - long ticks; - - /* - * Destroy the timer we got here on. - */ - if (timer_id) { - g_source_remove(timer_id); - timer_id = 0; - } - - /* - * run_timers() may cause a call to timer_change_notify, in which - * case a new timer will already have been set up and left in - * timer_id. If it hasn't, and run_timers reports that some timing - * still needs to be done, we do it ourselves. - */ - if (run_timers(now, &next) && !timer_id) { - then = now; - now = GETTICKCOUNT(); - if (now - then > next - then) - ticks = 0; - else - ticks = next - now; - timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next)); - } - - /* - * Returning FALSE means 'don't call this timer again', which - * _should_ be redundant given that we removed it above, but just - * in case, return FALSE anyway. - */ - return FALSE; -} - -void timer_change_notify(unsigned long next) -{ - long ticks; - - if (timer_id) - g_source_remove(timer_id); - - ticks = next - GETTICKCOUNT(); - if (ticks <= 0) - ticks = 1; /* just in case */ - - timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next)); -} - -#if GTK_CHECK_VERSION(2,0,0) -gboolean fd_input_func(GIOChannel *source, GIOCondition condition, - gpointer data) -{ - int sourcefd = g_io_channel_unix_get_fd(source); - /* - * We must process exceptional notifications before ordinary - * readability ones, or we may go straight past the urgent - * marker. - */ - if (condition & G_IO_PRI) - select_result(sourcefd, 4); - if (condition & G_IO_IN) - select_result(sourcefd, 1); - if (condition & G_IO_OUT) - select_result(sourcefd, 2); - - return TRUE; -} -#else -void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition) -{ - if (condition & GDK_INPUT_EXCEPTION) - select_result(sourcefd, 4); - if (condition & GDK_INPUT_READ) - select_result(sourcefd, 1); - if (condition & GDK_INPUT_WRITE) - select_result(sourcefd, 2); -} -#endif - void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); @@ -3742,341 +3509,6 @@ long get_windowid(void *frontend) } #endif -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) { - if(fprintf(fp, "%s: %s\n", appname, ver) < 0 || fflush(fp) < 0) { - perror("output error"); - exit(1); - } -} - -int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, - struct gui_data *inst, Conf *conf) -{ - int err = 0; - 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; hence it is not legal to - * use one of these macros as an unbraced statement between - * `if' and `else'. - */ -#define EXPECTS_ARG { \ - if (--argc <= 0) { \ - err = 1; \ - fprintf(stderr, "%s: %s expects an argument\n", appname, p); \ - continue; \ - } else \ - val = *++argv; \ -} -#define SECOND_PASS_ONLY { if (!do_everything) continue; } - - 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; - -#if GTK_CHECK_VERSION(2,0,0) - inst->geometry = val; -#else - /* On GTK 1, we have to do this using raw Xlib */ - { - int flags, x, y; - unsigned int w, h; - flags = XParseGeometry(val, &x, &y, &w, &h); - if (flags & WidthValue) - conf_set_int(conf, CONF_width, w); - if (flags & HeightValue) - conf_set_int(conf, CONF_height, h); - - if (flags & (XValue | YValue)) { - inst->xpos = x; - inst->ypos = y; - inst->gotpos = TRUE; - inst->gravity = ((flags & XNegative ? 1 : 0) | - (flags & YNegative ? 2 : 0)); - } - } -#endif - - } 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; - int success = gdk_rgba_parse(&rgba, val); -#else - GdkColor col; - int success = gdk_color_parse(val, &col); -#endif - - if (!success) { - err = 1; - 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 = 1, 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_int(conf, CONF_stamp_utmp, 0); - - } else if (!strcmp(p, "-ut")) { - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_stamp_utmp, 1); - - } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) { - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_login_shell, 0); - - } else if (!strcmp(p, "-ls")) { - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_login_shell, 1); - - } else if (!strcmp(p, "-nethack")) { - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_nethack_keypad, 1); - - } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) { - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_scrollbar, 0); - - } else if (!strcmp(p, "-sb")) { - SECOND_PASS_ONLY; - conf_set_int(conf, CONF_scrollbar, 1); - - } else if (!strcmp(p, "-name")) { - EXPECTS_ARG; - app_name = val; - - } else if (!strcmp(p, "-xrm")) { - EXPECTS_ARG; - provide_xrm_string(val); - - } 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] != '-' && (!do_everything || - process_nonoption_arg(p, conf, - allow_launch))) { - /* do nothing */ - - } else { - err = 1; - fprintf(stderr, "%s: unrecognized option '%s'\n", appname, p); - } - } - - return err; -} - -struct uxsel_id { -#if GTK_CHECK_VERSION(2,0,0) - GIOChannel *chan; - guint watch_id; -#else - int id; -#endif -}; - -uxsel_id *uxsel_input_add(int fd, int rwx) { - uxsel_id *id = snew(uxsel_id); - -#if GTK_CHECK_VERSION(2,0,0) - int flags = 0; - if (rwx & 1) flags |= G_IO_IN; - if (rwx & 2) flags |= G_IO_OUT; - if (rwx & 4) flags |= G_IO_PRI; - id->chan = g_io_channel_unix_new(fd); - g_io_channel_set_encoding(id->chan, NULL, NULL); - id->watch_id = g_io_add_watch_full(id->chan, GDK_PRIORITY_REDRAW+1, flags, - fd_input_func, NULL, NULL); -#else - int flags = 0; - if (rwx & 1) flags |= GDK_INPUT_READ; - if (rwx & 2) flags |= GDK_INPUT_WRITE; - if (rwx & 4) flags |= GDK_INPUT_EXCEPTION; - assert(flags); - id->id = gdk_input_add(fd, flags, fd_input_func, NULL); -#endif - - return id; -} - -void uxsel_input_remove(uxsel_id *id) { -#if GTK_CHECK_VERSION(2,0,0) - g_source_remove(id->watch_id); - g_io_channel_unref(id->chan); -#else - gdk_input_remove(id->id); -#endif - sfree(id); -} - int frontend_is_utf8(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; @@ -4408,200 +3840,16 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) inst->reconfiguring = FALSE; } -void fork_and_exec_self(struct gui_data *inst, 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 += inst->ngtkargs; - while (va_arg(ap, char *) != NULL) - n++; - va_end(ap); - - args = snewn(n, char *); - args[0] = inst->progname; - args[n-1] = NULL; - for (i = 0; i < inst->ngtkargs; i++) - args[i+1] = inst->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(inst->progname, args); - perror("exec"); - _exit(127); - - } else { - int status; - sfree(args); - waitpid(pid, &status, 0); - } - -} - void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) { struct gui_data *inst = (struct gui_data *)gdata; - /* - * 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, sersize, size; - char *data; - char option[80]; - int pipefd[2]; - if (pipe(pipefd) < 0) { - perror("pipe"); - return; - } - - size = sersize = conf_serialised_size(inst->conf); - if (use_pty_argv && pty_argv) { - for (i = 0; pty_argv[i]; i++) - size += strlen(pty_argv[i]) + 1; - } - - data = snewn(size, char); - conf_serialise(inst->conf, data); - if (use_pty_argv && pty_argv) { - int p = sersize; - for (i = 0; pty_argv[i]; i++) { - strcpy(data + p, pty_argv[i]); - p += strlen(pty_argv[i]) + 1; - } - assert(p == size); - } - - sprintf(option, "---[%d,%d]", pipefd[0], size); - noncloexec(pipefd[0]); - fork_and_exec_self(inst, pipefd[1], option, NULL); - close(pipefd[0]); - - i = ret = 0; - while (i < size && (ret = write(pipefd[1], data + i, size - i)) > 0) - i += ret; - if (ret < 0) - perror("write to pipe"); - close(pipefd[1]); - sfree(data); -} - -int read_dupsession_data(struct gui_data *inst, Conf *conf, char *arg) -{ - int fd, i, ret, size, size_used; - char *data; - - 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); - } - - size_used = conf_deserialise(conf, data, size); - if (use_pty_argv && size > size_used) { - int n = 0; - i = size_used; - while (i < size) { - while (i < size && data[i]) i++; - if (i >= size) { - fprintf(stderr, "%s: malformed Duplicate Session data\n", - appname); - exit(1); - } - i++; - n++; - } - pty_argv = snewn(n+1, char *); - pty_argv[n] = NULL; - n = 0; - i = size_used; - while (i < size) { - char *p = data + i; - while (i < size && data[i]) i++; - assert(i < size); - i++; - pty_argv[n++] = dupstr(p); - } - } - - sfree(data); - - return 0; + launch_duplicate_session(inst->conf); } void new_session_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; - - fork_and_exec_self(inst, -1, NULL); + launch_new_session(); } void restart_session_menuitem(GtkMenuItem *item, gpointer data) @@ -4618,10 +3866,9 @@ void restart_session_menuitem(GtkMenuItem *item, gpointer data) void saved_session_menuitem(GtkMenuItem *item, gpointer data) { - struct gui_data *inst = (struct gui_data *)data; char *str = (char *)g_object_get_data(G_OBJECT(item), "user-data"); - fork_and_exec_self(inst, -1, "-load", str, NULL); + launch_saved_session(str); } void saved_session_freedata(GtkMenuItem *item, gpointer data) @@ -4814,13 +4061,10 @@ static void start_backend(struct gui_data *inst) gtk_widget_set_sensitive(inst->restartitem, FALSE); } -int pt_main(int argc, char **argv) +struct gui_data *new_session_window(Conf *conf, const char *geometry_string) { - extern int cfgbox(Conf *conf); struct gui_data *inst; - setlocale(LC_CTYPE, ""); - /* * Create an instance structure and initialise to zeroes */ @@ -4828,57 +4072,34 @@ int pt_main(int argc, char **argv) memset(inst, 0, sizeof(*inst)); inst->alt_keycode = -1; /* this one needs _not_ to be zero */ inst->busy_status = BUSY_NOT; - inst->conf = conf_new(); + inst->conf = conf; inst->wintitle = inst->icontitle = NULL; - inst->quit_fn_scheduled = FALSE; - inst->idle_fn_scheduled = FALSE; inst->drawtype = DRAWTYPE_DEFAULT; #if GTK_CHECK_VERSION(3,4,0) inst->cumulative_scroll = 0.0; #endif - /* defer any child exit handling until we're ready to deal with - * it */ - block_signal(SIGCHLD, 1); - - inst->progname = argv[0]; - /* - * Copy the original argv before letting gtk_init fiddle with - * it. It will be required later. - */ - { - int i, oldargc; - inst->gtkargvstart = snewn(argc-1, char *); - for (i = 1; i < argc; i++) - inst->gtkargvstart[i-1] = dupstr(argv[i]); - oldargc = argc; - gtk_init(&argc, &argv); - inst->ngtkargs = oldargc - argc; - } - - if (argc > 1 && !strncmp(argv[1], "---", 3)) { - read_dupsession_data(inst, inst->conf, argv[1]); - /* Splatter this argument so it doesn't clutter a ps listing */ - smemclr(argv[1], strlen(argv[1])); - } else { - /* By default, we bring up the config dialog, rather than launching - * a session. This gets set to TRUE if something happens to change - * that (e.g., a hostname is specified on the command-line). */ - int allow_launch = FALSE; - if (do_cmdline(argc, argv, 0, &allow_launch, inst, inst->conf)) - exit(1); /* pre-defaults pass to get -class */ - do_defaults(NULL, inst->conf); - if (do_cmdline(argc, argv, 1, &allow_launch, inst, inst->conf)) - exit(1); /* post-defaults, do everything */ - - cmdline_run_saved(inst->conf); - - if (loaded_session) - allow_launch = TRUE; - - if ((!allow_launch || !conf_launchable(inst->conf)) && - !cfgbox(inst->conf)) - exit(0); /* config box hit Cancel */ + if (geometry_string) { +#if GTK_CHECK_VERSION(2,0,0) + inst->geometry = geometry_string; +#else + /* On GTK 1, we have to do this using raw Xlib */ + int flags, x, y; + unsigned int w, h; + flags = XParseGeometry(geometry_string, &x, &y, &w, &h); + if (flags & WidthValue) + conf_set_int(conf, CONF_width, w); + if (flags & HeightValue) + conf_set_int(conf, CONF_height, h); + + if (flags & (XValue | YValue)) { + inst->xpos = x; + inst->ypos = y; + inst->gotpos = TRUE; + inst->gravity = ((flags & XNegative ? 1 : 0) | + (flags & YNegative ? 2 : 0)); + } +#endif } if (!compound_text_atom) @@ -5112,14 +4333,10 @@ int pt_main(int argc, char **argv) inst->eventlogstuff = eventlogstuff_new(); - request_callback_notifications(notify_toplevel_callback, inst); - inst->term = term_init(inst->conf, &inst->ucsdata, inst); inst->logctx = log_init(inst, inst->conf); term_provide_logctx(inst->term, inst->logctx); - uxsel_init(); - term_size(inst->term, inst->height, inst->width, conf_get_int(inst->conf, CONF_savelines)); @@ -5127,22 +4344,7 @@ int pt_main(int argc, char **argv) ldisc_echoedit_update(inst->ldisc); /* cause ldisc to notice changes */ - /* now we're reday to deal with the child exit handler being - * called */ - block_signal(SIGCHLD, 0); - - /* - * 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. Note that we do - * this _after_ (at least pterm) forks off its child process, - * since the child wants SIGPIPE handled in the usual way. - */ - block_signal(SIGPIPE, 1); - inst->exited = FALSE; - gtk_main(); - - return 0; + return inst; }