1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 09:58:01 +00:00
putty-source/unix/gtkmain.c

630 lines
16 KiB
C
Raw Normal View History

Divide the whole of gtkwin.c into three parts. This lays further groundwork for the OS X GTK3 port, which is going to have to deal with multiple sessions sharing the same process. gtkwin.c was a bit too monolithic for this, since it included some process-global runtime state (timers, toplevel callbacks), some process startup stuff (gtk_init, gtk_main, argv processing) and some per-session-window stuff. The per-session stuff remains in gtkwin.c, with the top-level function now being new_session_window() taking a Conf. The new gtkmain.c contains the outer skeleton of pt_main(), handling argv processing and one-off startup stuff like setlocale; and the new gtkcomm.c contains the pieces of PuTTY infrastructure like timers and uxsel that are shared between multiple sessions rather than reinstantiated per session, which have been rewritten to use global variables rather than fields in 'inst' (since it's now clear to me that they'll have to apply to all the insts in existence at once). There are still some lurking assumptions of one-session-per-process, e.g. the use of gtk_main_quit when a session finishes, and the fact that the config box insists on running as a separate invocation of gtk_main so that one session's preliminary config box can't coexist with another session already active. But this should make it possible to at least write an OS X app good enough to start testing with, even if it doesn't get everything quite right yet. This change is almost entirely rearranging existing code, so it shouldn't be seriously destabilising. But two noticeable actual changes have happened, both pleasantly simplifying: Firstly, the global-variables rewrite of gtkcomm.c has allowed the post_main edifice to become a great deal simpler. Most of its complexity was about remembering what 'inst' it had to call back to, and in fact the right answer is that it shouldn't be calling back to one at all. So now the post_main() called by gtkdlg.c has become the same function as the old inst_post_main() that actually did the work, instead of the two having to be connected by a piece of ugly plumbing. Secondly, a piece of code that's vanished completely in this refactoring is the temporary blocking of SIGCHLD around most of the session setup code. This turns out to have been introduced in 2002, _before_ I switched to using the intra-process signal pipe strategy for SIGCHLD handling in 2003. So I now expect that we should be robust in any case against receiving SIGCHLD at an inconvenient moment, and hence there's no need to block it.
2016-03-22 21:24:30 +00:00
/*
* 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>
#endif
static char *progname, **gtkargvstart;
static int ngtkargs;
extern char **pty_argv; /* declared in pty.c */
extern int use_pty_argv;
static const char *app_name = "pterm";
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 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, sersize, size;
char *data;
char option[80];
int pipefd[2];
if (pipe(pipefd) < 0) {
perror("pipe");
return;
}
size = sersize = conf_serialised_size(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(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(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);
}
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, 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;
}
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);
}
}
static struct gui_data *the_inst;
static const char *geometry_string;
int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
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;
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;
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;
}
GtkWidget *make_gtk_toplevel_window(void *frontend)
{
return gtk_window_new(GTK_WINDOW_TOPLEVEL);
}
Divide the whole of gtkwin.c into three parts. This lays further groundwork for the OS X GTK3 port, which is going to have to deal with multiple sessions sharing the same process. gtkwin.c was a bit too monolithic for this, since it included some process-global runtime state (timers, toplevel callbacks), some process startup stuff (gtk_init, gtk_main, argv processing) and some per-session-window stuff. The per-session stuff remains in gtkwin.c, with the top-level function now being new_session_window() taking a Conf. The new gtkmain.c contains the outer skeleton of pt_main(), handling argv processing and one-off startup stuff like setlocale; and the new gtkcomm.c contains the pieces of PuTTY infrastructure like timers and uxsel that are shared between multiple sessions rather than reinstantiated per session, which have been rewritten to use global variables rather than fields in 'inst' (since it's now clear to me that they'll have to apply to all the insts in existence at once). There are still some lurking assumptions of one-session-per-process, e.g. the use of gtk_main_quit when a session finishes, and the fact that the config box insists on running as a separate invocation of gtk_main so that one session's preliminary config box can't coexist with another session already active. But this should make it possible to at least write an OS X app good enough to start testing with, even if it doesn't get everything quite right yet. This change is almost entirely rearranging existing code, so it shouldn't be seriously destabilising. But two noticeable actual changes have happened, both pleasantly simplifying: Firstly, the global-variables rewrite of gtkcomm.c has allowed the post_main edifice to become a great deal simpler. Most of its complexity was about remembering what 'inst' it had to call back to, and in fact the right answer is that it shouldn't be calling back to one at all. So now the post_main() called by gtkdlg.c has become the same function as the old inst_post_main() that actually did the work, instead of the two having to be connected by a piece of ugly plumbing. Secondly, a piece of code that's vanished completely in this refactoring is the temporary blocking of SIGCHLD around most of the session setup code. This turns out to have been introduced in 2002, _before_ I switched to using the intra-process signal pipe strategy for SIGCHLD handling in 2003. So I now expect that we should be robust in any case against receiving SIGCHLD at an inconvenient moment, and hence there's no need to block it.
2016-03-22 21:24:30 +00:00
extern int cfgbox(Conf *conf);
int main(int argc, char **argv)
Divide the whole of gtkwin.c into three parts. This lays further groundwork for the OS X GTK3 port, which is going to have to deal with multiple sessions sharing the same process. gtkwin.c was a bit too monolithic for this, since it included some process-global runtime state (timers, toplevel callbacks), some process startup stuff (gtk_init, gtk_main, argv processing) and some per-session-window stuff. The per-session stuff remains in gtkwin.c, with the top-level function now being new_session_window() taking a Conf. The new gtkmain.c contains the outer skeleton of pt_main(), handling argv processing and one-off startup stuff like setlocale; and the new gtkcomm.c contains the pieces of PuTTY infrastructure like timers and uxsel that are shared between multiple sessions rather than reinstantiated per session, which have been rewritten to use global variables rather than fields in 'inst' (since it's now clear to me that they'll have to apply to all the insts in existence at once). There are still some lurking assumptions of one-session-per-process, e.g. the use of gtk_main_quit when a session finishes, and the fact that the config box insists on running as a separate invocation of gtk_main so that one session's preliminary config box can't coexist with another session already active. But this should make it possible to at least write an OS X app good enough to start testing with, even if it doesn't get everything quite right yet. This change is almost entirely rearranging existing code, so it shouldn't be seriously destabilising. But two noticeable actual changes have happened, both pleasantly simplifying: Firstly, the global-variables rewrite of gtkcomm.c has allowed the post_main edifice to become a great deal simpler. Most of its complexity was about remembering what 'inst' it had to call back to, and in fact the right answer is that it shouldn't be calling back to one at all. So now the post_main() called by gtkdlg.c has become the same function as the old inst_post_main() that actually did the work, instead of the two having to be connected by a piece of ugly plumbing. Secondly, a piece of code that's vanished completely in this refactoring is the temporary blocking of SIGCHLD around most of the session setup code. This turns out to have been introduced in 2002, _before_ I switched to using the intra-process signal pipe strategy for SIGCHLD handling in 2003. So I now expect that we should be robust in any case against receiving SIGCHLD at an inconvenient moment, and hence there's no need to block it.
2016-03-22 21:24:30 +00:00
{
Conf *conf;
int need_config_box;
setlocale(LC_CTYPE, "");
{
/* Call the function in ux{putty,pterm}.c to do app-type
* specific setup */
extern void setup(int);
setup(TRUE); /* TRUE means we are a one-session process */
}
Divide the whole of gtkwin.c into three parts. This lays further groundwork for the OS X GTK3 port, which is going to have to deal with multiple sessions sharing the same process. gtkwin.c was a bit too monolithic for this, since it included some process-global runtime state (timers, toplevel callbacks), some process startup stuff (gtk_init, gtk_main, argv processing) and some per-session-window stuff. The per-session stuff remains in gtkwin.c, with the top-level function now being new_session_window() taking a Conf. The new gtkmain.c contains the outer skeleton of pt_main(), handling argv processing and one-off startup stuff like setlocale; and the new gtkcomm.c contains the pieces of PuTTY infrastructure like timers and uxsel that are shared between multiple sessions rather than reinstantiated per session, which have been rewritten to use global variables rather than fields in 'inst' (since it's now clear to me that they'll have to apply to all the insts in existence at once). There are still some lurking assumptions of one-session-per-process, e.g. the use of gtk_main_quit when a session finishes, and the fact that the config box insists on running as a separate invocation of gtk_main so that one session's preliminary config box can't coexist with another session already active. But this should make it possible to at least write an OS X app good enough to start testing with, even if it doesn't get everything quite right yet. This change is almost entirely rearranging existing code, so it shouldn't be seriously destabilising. But two noticeable actual changes have happened, both pleasantly simplifying: Firstly, the global-variables rewrite of gtkcomm.c has allowed the post_main edifice to become a great deal simpler. Most of its complexity was about remembering what 'inst' it had to call back to, and in fact the right answer is that it shouldn't be calling back to one at all. So now the post_main() called by gtkdlg.c has become the same function as the old inst_post_main() that actually did the work, instead of the two having to be connected by a piece of ugly plumbing. Secondly, a piece of code that's vanished completely in this refactoring is the temporary blocking of SIGCHLD around most of the session setup code. This turns out to have been introduced in 2002, _before_ I switched to using the intra-process signal pipe strategy for SIGCHLD handling in 2003. So I now expect that we should be robust in any case against receiving SIGCHLD at an inconvenient moment, and hence there's no need to block it.
2016-03-22 21:24:30 +00:00
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, 1);
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(conf_launchable(conf));
need_config_box = FALSE;
} 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, conf))
exit(1); /* pre-defaults pass to get -class */
do_defaults(NULL, conf);
if (do_cmdline(argc, argv, 1, &allow_launch, conf))
exit(1); /* post-defaults, do everything */
cmdline_run_saved(conf);
if (loaded_session)
allow_launch = TRUE;
need_config_box = (!allow_launch || !conf_launchable(conf));
}
/*
* Put up the config box.
*/
if (need_config_box && !cfgbox(conf))
exit(0); /* config box hit Cancel */
/*
* Create the main session window. We don't really need to keep
* the return value - the fact that it'll be linked from a zillion
* GTK and glib bits and bobs known to the main loop will be
* sufficient to make everything actually happen - but we stash it
* in a global variable anyway, so that it'll be easy to find in a
* debugger.
*/
the_inst = new_session_window(conf, geometry_string);
gtk_main();
return 0;
}