mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
0244bca5cb
If this occurs before cmdline_run_saved, then the latter will use its saved pointers to arguments in the freed CmdlineArgList. Affects uses of PuTTY without a saved session (like 'putty -ssh foohost'), and a very small number of pterm options, in particular -sessionlog. This is the simplest possible fix: just remove the free completely, so that the parsed command-line arguments leak. There's at most one instance of them per process, so it doesn't matter.
679 lines
20 KiB
C
679 lines
20 KiB
C
/*
|
|
* main-gtk-simple.c: the common main-program code between the
|
|
* straight-up Unix PuTTY and pterm, which they do not share with the
|
|
* multi-session main-gtk-application.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 "unifont.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;
|
|
|
|
/*
|
|
* 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 (!nextarg) { \
|
|
err = true; \
|
|
fprintf(stderr, "%s: %s expects an argument\n", appname, p); \
|
|
continue; \
|
|
} else { \
|
|
arglistpos++; \
|
|
} \
|
|
} else ((void)0)
|
|
#define SECOND_PASS_ONLY if (1) { \
|
|
if (!do_everything) \
|
|
continue; \
|
|
} else ((void)0)
|
|
|
|
CmdlineArgList *arglist = cmdline_arg_list_from_argv(argc, argv);
|
|
size_t arglistpos = 0;
|
|
while (arglist->args[arglistpos]) {
|
|
CmdlineArg *arg = arglist->args[arglistpos++];
|
|
CmdlineArg *nextarg = arglist->args[arglistpos];
|
|
const char *p = cmdline_arg_to_str(arg);
|
|
const char *val = cmdline_arg_to_str(nextarg);
|
|
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(
|
|
arg, nextarg, do_everything ? 1 : -1, conf);
|
|
|
|
if (ret == -2) {
|
|
cmdline_error("option \"%s\" requires an argument", p);
|
|
} else if (ret == 2) {
|
|
arglistpos++;
|
|
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 (nextarg) {
|
|
pty_argv = cmdline_arg_remainder(nextarg);
|
|
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")) {
|
|
EXPECTS_ARG;
|
|
SECOND_PASS_ONLY;
|
|
Filename *fn = cmdline_arg_to_filename(nextarg);
|
|
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(0);
|
|
|
|
} else if (has_ca_config_box &&
|
|
(!strcmp(p, "-host-ca") || !strcmp(p, "--host-ca") ||
|
|
!strcmp(p, "-host_ca") || !strcmp(p, "--host_ca"))) {
|
|
show_ca_config_box_synchronously();
|
|
exit(0);
|
|
|
|
} 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;
|
|
}
|