OSDN Git Service

Modify features and documents for 1.98b the urgent security release.
[ffftp/ffftp.git] / contrib / putty / UNIX / GTKWIN.C
diff --git a/contrib/putty/UNIX/GTKWIN.C b/contrib/putty/UNIX/GTKWIN.C
deleted file mode 100644 (file)
index f2a13ae..0000000
+++ /dev/null
@@ -1,3645 +0,0 @@
-/*\r
- * gtkwin.c: the main code that runs a PuTTY terminal emulator and\r
- * backend in a GTK window.\r
- */\r
-\r
-#define _GNU_SOURCE\r
-\r
-#include <string.h>\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <signal.h>\r
-#include <stdio.h>\r
-#include <time.h>\r
-#include <errno.h>\r
-#include <fcntl.h>\r
-#include <unistd.h>\r
-#include <sys/types.h>\r
-#include <sys/wait.h>\r
-#include <gtk/gtk.h>\r
-#include <gdk/gdkkeysyms.h>\r
-#include <gdk/gdkx.h>\r
-#include <X11/Xlib.h>\r
-#include <X11/Xutil.h>\r
-#include <X11/Xatom.h>\r
-\r
-#define PUTTY_DO_GLOBALS              /* actually _define_ globals */\r
-\r
-#include "putty.h"\r
-#include "terminal.h"\r
-#include "gtkfont.h"\r
-\r
-#define CAT2(x,y) x ## y\r
-#define CAT(x,y) CAT2(x,y)\r
-#define ASSERT(x) enum {CAT(assertion_,__LINE__) = 1 / (x)}\r
-\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-ASSERT(sizeof(long) <= sizeof(gsize));\r
-#define LONG_TO_GPOINTER(l) GSIZE_TO_POINTER(l)\r
-#define GPOINTER_TO_LONG(p) GPOINTER_TO_SIZE(p)\r
-#else /* Gtk 1.2 */\r
-ASSERT(sizeof(long) <= sizeof(gpointer));\r
-#define LONG_TO_GPOINTER(l) ((gpointer)(long)(l))\r
-#define GPOINTER_TO_LONG(p) ((long)(p))\r
-#endif\r
-\r
-/* Colours come in two flavours: configurable, and xterm-extended. */\r
-#define NCFGCOLOURS (lenof(((Config *)0)->colours))\r
-#define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */\r
-#define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS)\r
-\r
-GdkAtom compound_text_atom, utf8_string_atom;\r
-\r
-extern char **pty_argv;               /* declared in pty.c */\r
-extern int use_pty_argv;\r
-\r
-/*\r
- * Timers are global across all sessions (even if we were handling\r
- * multiple sessions, which we aren't), so the current timer ID is\r
- * a global variable.\r
- */\r
-static guint timer_id = 0;\r
-\r
-struct gui_data {\r
-    GtkWidget *window, *area, *sbar;\r
-    GtkBox *hbox;\r
-    GtkAdjustment *sbar_adjust;\r
-    GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2,\r
-       *restartitem;\r
-    GtkWidget *sessionsmenu;\r
-    GdkPixmap *pixmap;\r
-    unifont *fonts[4];                 /* normal, bold, wide, widebold */\r
-    int xpos, ypos, gotpos, gravity;\r
-    GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor;\r
-    GdkColor cols[NALLCOLOURS];\r
-    GdkColormap *colmap;\r
-    wchar_t *pastein_data;\r
-    int direct_to_font;\r
-    int pastein_data_len;\r
-    char *pasteout_data, *pasteout_data_ctext, *pasteout_data_utf8;\r
-    int pasteout_data_len, pasteout_data_ctext_len, pasteout_data_utf8_len;\r
-    int font_width, font_height;\r
-    int width, height;\r
-    int ignore_sbar;\r
-    int mouseptr_visible;\r
-    int busy_status;\r
-    guint term_paste_idle_id;\r
-    guint term_exit_idle_id;\r
-    int alt_keycode;\r
-    int alt_digits;\r
-    char wintitle[sizeof(((Config *)0)->wintitle)];\r
-    char icontitle[sizeof(((Config *)0)->wintitle)];\r
-    int master_fd, master_func_id;\r
-    void *ldisc;\r
-    Backend *back;\r
-    void *backhandle;\r
-    Terminal *term;\r
-    void *logctx;\r
-    int exited;\r
-    struct unicode_data ucsdata;\r
-    Config cfg;\r
-    void *eventlogstuff;\r
-    char *progname, **gtkargvstart;\r
-    int ngtkargs;\r
-    guint32 input_event_time; /* Timestamp of the most recent input event. */\r
-    int reconfiguring;\r
-};\r
-\r
-struct draw_ctx {\r
-    GdkGC *gc;\r
-    struct gui_data *inst;\r
-};\r
-\r
-static int send_raw_mouse;\r
-\r
-static char *app_name = "pterm";\r
-\r
-static void start_backend(struct gui_data *inst);\r
-\r
-char *x_get_default(const char *key)\r
-{\r
-    return XGetDefault(GDK_DISPLAY(), app_name, key);\r
-}\r
-\r
-void connection_fatal(void *frontend, char *p, ...)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-\r
-    va_list ap;\r
-    char *msg;\r
-    va_start(ap, p);\r
-    msg = dupvprintf(p, ap);\r
-    va_end(ap);\r
-    inst->exited = TRUE;\r
-    fatal_message_box(inst->window, msg);\r
-    sfree(msg);\r
-    if (inst->cfg.close_on_exit == FORCE_ON)\r
-        cleanup_exit(1);\r
-}\r
-\r
-/*\r
- * Default settings that are specific to pterm.\r
- */\r
-FontSpec platform_default_fontspec(const char *name)\r
-{\r
-    FontSpec ret;\r
-    if (!strcmp(name, "Font"))\r
-       strcpy(ret.name, "server:fixed");\r
-    else\r
-       *ret.name = '\0';\r
-    return ret;\r
-}\r
-\r
-Filename platform_default_filename(const char *name)\r
-{\r
-    Filename ret;\r
-    if (!strcmp(name, "LogFileName"))\r
-       strcpy(ret.path, "putty.log");\r
-    else\r
-       *ret.path = '\0';\r
-    return ret;\r
-}\r
-\r
-char *platform_default_s(const char *name)\r
-{\r
-    if (!strcmp(name, "SerialLine"))\r
-       return dupstr("/dev/ttyS0");\r
-    return NULL;\r
-}\r
-\r
-int platform_default_i(const char *name, int def)\r
-{\r
-    if (!strcmp(name, "CloseOnExit"))\r
-       return 2;  /* maps to FORCE_ON after painful rearrangement :-( */\r
-    if (!strcmp(name, "WinNameAlways"))\r
-       return 0;  /* X natively supports icon titles, so use 'em by default */\r
-    return def;\r
-}\r
-\r
-/* Dummy routine, only required in plink. */\r
-void ldisc_update(void *frontend, int echo, int edit)\r
-{\r
-}\r
-\r
-char *get_ttymode(void *frontend, const char *mode)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return term_get_ttymode(inst->term, mode);\r
-}\r
-\r
-int from_backend(void *frontend, int is_stderr, const char *data, int len)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return term_data(inst->term, is_stderr, data, len);\r
-}\r
-\r
-int from_backend_untrusted(void *frontend, const char *data, int len)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return term_data_untrusted(inst->term, data, len);\r
-}\r
-\r
-int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)p->frontend;\r
-    int ret;\r
-    ret = cmdline_get_passwd_input(p, in, inlen);\r
-    if (ret == -1)\r
-       ret = term_get_userpass_input(inst->term, p, in, inlen);\r
-    return ret;\r
-}\r
-\r
-void logevent(void *frontend, const char *string)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-\r
-    log_eventlog(inst->logctx, string);\r
-\r
-    logevent_dlg(inst->eventlogstuff, string);\r
-}\r
-\r
-int font_dimension(void *frontend, int which)/* 0 for width, 1 for height */\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-\r
-    if (which)\r
-       return inst->font_height;\r
-    else\r
-       return inst->font_width;\r
-}\r
-\r
-/*\r
- * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT)\r
- * into a cooked one (SELECT, EXTEND, PASTE).\r
- * \r
- * In Unix, this is not configurable; the X button arrangement is\r
- * rock-solid across all applications, everyone has a three-button\r
- * mouse or a means of faking it, and there is no need to switch\r
- * buttons around at all.\r
- */\r
-static Mouse_Button translate_button(Mouse_Button button)\r
-{\r
-    /* struct gui_data *inst = (struct gui_data *)frontend; */\r
-\r
-    if (button == MBT_LEFT)\r
-       return MBT_SELECT;\r
-    if (button == MBT_MIDDLE)\r
-       return MBT_PASTE;\r
-    if (button == MBT_RIGHT)\r
-       return MBT_EXTEND;\r
-    return 0;                         /* shouldn't happen */\r
-}\r
-\r
-/*\r
- * Return the top-level GtkWindow associated with a particular\r
- * front end instance.\r
- */\r
-void *get_window(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return inst->window;\r
-}\r
-\r
-/*\r
- * Minimise or restore the window in response to a server-side\r
- * request.\r
- */\r
-void set_iconic(void *frontend, int iconic)\r
-{\r
-    /*\r
-     * GTK 1.2 doesn't know how to do this.\r
-     */\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    if (iconic)\r
-       gtk_window_iconify(GTK_WINDOW(inst->window));\r
-    else\r
-       gtk_window_deiconify(GTK_WINDOW(inst->window));\r
-#endif\r
-}\r
-\r
-/*\r
- * Move the window in response to a server-side request.\r
- */\r
-void move_window(void *frontend, int x, int y)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    /*\r
-     * I assume that when the GTK version of this call is available\r
-     * we should use it. Not sure how it differs from the GDK one,\r
-     * though.\r
-     */\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    gtk_window_move(GTK_WINDOW(inst->window), x, y);\r
-#else\r
-    gdk_window_move(inst->window->window, x, y);\r
-#endif\r
-}\r
-\r
-/*\r
- * Move the window to the top or bottom of the z-order in response\r
- * to a server-side request.\r
- */\r
-void set_zorder(void *frontend, int top)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    if (top)\r
-       gdk_window_raise(inst->window->window);\r
-    else\r
-       gdk_window_lower(inst->window->window);\r
-}\r
-\r
-/*\r
- * Refresh the window in response to a server-side request.\r
- */\r
-void refresh_window(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    term_invalidate(inst->term);\r
-}\r
-\r
-/*\r
- * Maximise or restore the window in response to a server-side\r
- * request.\r
- */\r
-void set_zoomed(void *frontend, int zoomed)\r
-{\r
-    /*\r
-     * GTK 1.2 doesn't know how to do this.\r
-     */\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    if (zoomed)\r
-       gtk_window_maximize(GTK_WINDOW(inst->window));\r
-    else\r
-       gtk_window_unmaximize(GTK_WINDOW(inst->window));\r
-#endif\r
-}\r
-\r
-/*\r
- * Report whether the window is iconic, for terminal reports.\r
- */\r
-int is_iconic(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return !gdk_window_is_viewable(inst->window->window);\r
-}\r
-\r
-/*\r
- * Report the window's position, for terminal reports.\r
- */\r
-void get_window_pos(void *frontend, int *x, int *y)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    /*\r
-     * I assume that when the GTK version of this call is available\r
-     * we should use it. Not sure how it differs from the GDK one,\r
-     * though.\r
-     */\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    gtk_window_get_position(GTK_WINDOW(inst->window), x, y);\r
-#else\r
-    gdk_window_get_position(inst->window->window, x, y);\r
-#endif\r
-}\r
-\r
-/*\r
- * Report the window's pixel size, for terminal reports.\r
- */\r
-void get_window_pixels(void *frontend, int *x, int *y)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    /*\r
-     * I assume that when the GTK version of this call is available\r
-     * we should use it. Not sure how it differs from the GDK one,\r
-     * though.\r
-     */\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    gtk_window_get_size(GTK_WINDOW(inst->window), x, y);\r
-#else\r
-    gdk_window_get_size(inst->window->window, x, y);\r
-#endif\r
-}\r
-\r
-/*\r
- * Return the window or icon title.\r
- */\r
-char *get_window_title(void *frontend, int icon)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return icon ? inst->icontitle : inst->wintitle;\r
-}\r
-\r
-gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    if (!inst->exited && inst->cfg.warn_on_close) {\r
-       if (!reallyclose(inst))\r
-           return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-static void update_mouseptr(struct gui_data *inst)\r
-{\r
-    switch (inst->busy_status) {\r
-      case BUSY_NOT:\r
-       if (!inst->mouseptr_visible) {\r
-           gdk_window_set_cursor(inst->area->window, inst->blankcursor);\r
-       } else if (send_raw_mouse) {\r
-           gdk_window_set_cursor(inst->area->window, inst->rawcursor);\r
-       } else {\r
-           gdk_window_set_cursor(inst->area->window, inst->textcursor);\r
-       }\r
-       break;\r
-      case BUSY_WAITING:    /* XXX can we do better? */\r
-      case BUSY_CPU:\r
-       /* We always display these cursors. */\r
-       gdk_window_set_cursor(inst->area->window, inst->waitcursor);\r
-       break;\r
-      default:\r
-       assert(0);\r
-    }\r
-}\r
-\r
-static void show_mouseptr(struct gui_data *inst, int show)\r
-{\r
-    if (!inst->cfg.hide_mouseptr)\r
-       show = 1;\r
-    inst->mouseptr_visible = show;\r
-    update_mouseptr(inst);\r
-}\r
-\r
-void draw_backing_rect(struct gui_data *inst)\r
-{\r
-    GdkGC *gc = gdk_gc_new(inst->area->window);\r
-    gdk_gc_set_foreground(gc, &inst->cols[258]);    /* default background */\r
-    gdk_draw_rectangle(inst->pixmap, gc, 1, 0, 0,\r
-                      inst->cfg.width * inst->font_width + 2*inst->cfg.window_border,\r
-                      inst->cfg.height * inst->font_height + 2*inst->cfg.window_border);\r
-    gdk_gc_unref(gc);\r
-}\r
-\r
-gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    int w, h, need_size = 0;\r
-\r
-    /*\r
-     * See if the terminal size has changed, in which case we must\r
-     * let the terminal know.\r
-     */\r
-    w = (event->width - 2*inst->cfg.window_border) / inst->font_width;\r
-    h = (event->height - 2*inst->cfg.window_border) / inst->font_height;\r
-    if (w != inst->width || h != inst->height) {\r
-       inst->cfg.width = inst->width = w;\r
-       inst->cfg.height = inst->height = h;\r
-       need_size = 1;\r
-    }\r
-\r
-    if (inst->pixmap) {\r
-       gdk_pixmap_unref(inst->pixmap);\r
-       inst->pixmap = NULL;\r
-    }\r
-\r
-    inst->pixmap = gdk_pixmap_new(widget->window,\r
-                                 (inst->cfg.width * inst->font_width +\r
-                                  2*inst->cfg.window_border),\r
-                                 (inst->cfg.height * inst->font_height +\r
-                                  2*inst->cfg.window_border), -1);\r
-\r
-    draw_backing_rect(inst);\r
-\r
-    if (need_size && inst->term) {\r
-       term_size(inst->term, h, w, inst->cfg.savelines);\r
-    }\r
-\r
-    if (inst->term)\r
-       term_invalidate(inst->term);\r
-\r
-    return TRUE;\r
-}\r
-\r
-gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-\r
-    /*\r
-     * Pass the exposed rectangle to terminal.c, which will call us\r
-     * back to do the actual painting.\r
-     */\r
-    if (inst->pixmap) {\r
-       gdk_draw_pixmap(widget->window,\r
-                       widget->style->fg_gc[GTK_WIDGET_STATE(widget)],\r
-                       inst->pixmap,\r
-                       event->area.x, event->area.y,\r
-                       event->area.x, event->area.y,\r
-                       event->area.width, event->area.height);\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-#define KEY_PRESSED(k) \\r
-    (inst->keystate[(k) / 32] & (1 << ((k) % 32)))\r
-\r
-gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    char output[256];\r
-    wchar_t ucsoutput[2];\r
-    int ucsval, start, end, special, output_charset, use_ucsoutput;\r
-\r
-    /* Remember the timestamp. */\r
-    inst->input_event_time = event->time;\r
-\r
-    /* By default, nothing is generated. */\r
-    end = start = 0;\r
-    special = use_ucsoutput = FALSE;\r
-    output_charset = CS_ISO8859_1;\r
-\r
-    /*\r
-     * If Alt is being released after typing an Alt+numberpad\r
-     * sequence, we should generate the code that was typed.\r
-     * \r
-     * Note that we only do this if more than one key was actually\r
-     * pressed - I don't think Alt+NumPad4 should be ^D or that\r
-     * Alt+NumPad3 should be ^C, for example. There's no serious\r
-     * inconvenience in having to type a zero before a single-digit\r
-     * character code.\r
-     */\r
-    if (event->type == GDK_KEY_RELEASE &&\r
-       (event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L ||\r
-        event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) &&\r
-       inst->alt_keycode >= 0 && inst->alt_digits > 1) {\r
-#ifdef KEY_DEBUGGING\r
-       printf("Alt key up, keycode = %d\n", inst->alt_keycode);\r
-#endif\r
-       /*\r
-        * FIXME: we might usefully try to do something clever here\r
-        * about interpreting the generated key code in a way that's\r
-        * appropriate to the line code page.\r
-        */\r
-       output[0] = inst->alt_keycode;\r
-       end = 1;\r
-       goto done;\r
-    }\r
-\r
-    if (event->type == GDK_KEY_PRESS) {\r
-#ifdef KEY_DEBUGGING\r
-       {\r
-           int i;\r
-           printf("keypress: keyval = %04x, state = %08x; string =",\r
-                  event->keyval, event->state);\r
-           for (i = 0; event->string[i]; i++)\r
-               printf(" %02x", (unsigned char) event->string[i]);\r
-           printf("\n");\r
-       }\r
-#endif\r
-\r
-       /*\r
-        * NYI: Compose key (!!! requires Unicode faff before even trying)\r
-        */\r
-\r
-       /*\r
-        * If Alt has just been pressed, we start potentially\r
-        * accumulating an Alt+numberpad code. We do this by\r
-        * setting alt_keycode to -1 (nothing yet but plausible).\r
-        */\r
-       if ((event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L ||\r
-            event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R)) {\r
-           inst->alt_keycode = -1;\r
-            inst->alt_digits = 0;\r
-           goto done;                 /* this generates nothing else */\r
-       }\r
-\r
-       /*\r
-        * If we're seeing a numberpad key press with Mod1 down,\r
-        * consider adding it to alt_keycode if that's sensible.\r
-        * Anything _else_ with Mod1 down cancels any possibility\r
-        * of an ALT keycode: we set alt_keycode to -2.\r
-        */\r
-       if ((event->state & GDK_MOD1_MASK) && inst->alt_keycode != -2) {\r
-           int digit = -1;\r
-           switch (event->keyval) {\r
-             case GDK_KP_0: case GDK_KP_Insert: digit = 0; break;\r
-             case GDK_KP_1: case GDK_KP_End: digit = 1; break;\r
-             case GDK_KP_2: case GDK_KP_Down: digit = 2; break;\r
-             case GDK_KP_3: case GDK_KP_Page_Down: digit = 3; break;\r
-             case GDK_KP_4: case GDK_KP_Left: digit = 4; break;\r
-             case GDK_KP_5: case GDK_KP_Begin: digit = 5; break;\r
-             case GDK_KP_6: case GDK_KP_Right: digit = 6; break;\r
-             case GDK_KP_7: case GDK_KP_Home: digit = 7; break;\r
-             case GDK_KP_8: case GDK_KP_Up: digit = 8; break;\r
-             case GDK_KP_9: case GDK_KP_Page_Up: digit = 9; break;\r
-           }\r
-           if (digit < 0)\r
-               inst->alt_keycode = -2;   /* it's invalid */\r
-           else {\r
-#ifdef KEY_DEBUGGING\r
-               printf("Adding digit %d to keycode %d", digit,\r
-                      inst->alt_keycode);\r
-#endif\r
-               if (inst->alt_keycode == -1)\r
-                   inst->alt_keycode = digit;   /* one-digit code */\r
-               else\r
-                   inst->alt_keycode = inst->alt_keycode * 10 + digit;\r
-                inst->alt_digits++;\r
-#ifdef KEY_DEBUGGING\r
-               printf(" gives new code %d\n", inst->alt_keycode);\r
-#endif\r
-               /* Having used this digit, we now do nothing more with it. */\r
-               goto done;\r
-           }\r
-       }\r
-\r
-       /*\r
-        * Shift-PgUp and Shift-PgDn don't even generate keystrokes\r
-        * at all.\r
-        */\r
-       if (event->keyval == GDK_Page_Up && (event->state & GDK_SHIFT_MASK)) {\r
-           term_scroll(inst->term, 0, -inst->cfg.height/2);\r
-           return TRUE;\r
-       }\r
-       if (event->keyval == GDK_Page_Up && (event->state & GDK_CONTROL_MASK)) {\r
-           term_scroll(inst->term, 0, -1);\r
-           return TRUE;\r
-       }\r
-       if (event->keyval == GDK_Page_Down && (event->state & GDK_SHIFT_MASK)) {\r
-           term_scroll(inst->term, 0, +inst->cfg.height/2);\r
-           return TRUE;\r
-       }\r
-       if (event->keyval == GDK_Page_Down && (event->state & GDK_CONTROL_MASK)) {\r
-           term_scroll(inst->term, 0, +1);\r
-           return TRUE;\r
-       }\r
-\r
-       /*\r
-        * Neither does Shift-Ins.\r
-        */\r
-       if (event->keyval == GDK_Insert && (event->state & GDK_SHIFT_MASK)) {\r
-           request_paste(inst);\r
-           return TRUE;\r
-       }\r
-\r
-       special = FALSE;\r
-       use_ucsoutput = FALSE;\r
-\r
-       /* ALT+things gives leading Escape. */\r
-       output[0] = '\033';\r
-#if !GTK_CHECK_VERSION(2,0,0)\r
-       /*\r
-        * In vanilla X, and hence also GDK 1.2, the string received\r
-        * as part of a keyboard event is assumed to be in\r
-        * ISO-8859-1. (Seems woefully shortsighted in i18n terms,\r
-        * but it's true: see the man page for XLookupString(3) for\r
-        * confirmation.)\r
-        */\r
-       output_charset = CS_ISO8859_1;\r
-       strncpy(output+1, event->string, lenof(output)-1);\r
-#else\r
-       /*\r
-        * GDK 2.0 arranges to have done some translation for us: in\r
-        * GDK 2.0, event->string is encoded in the current locale.\r
-        *\r
-        * (However, it's also deprecated; we really ought to be\r
-        * using a GTKIMContext.)\r
-        *\r
-        * So we use the standard C library function mbstowcs() to\r
-        * convert from the current locale into Unicode; from there\r
-        * we can convert to whatever PuTTY is currently working in.\r
-        * (In fact I convert straight back to UTF-8 from\r
-        * wide-character Unicode, for the sake of simplicity: that\r
-        * way we can still use exactly the same code to manipulate\r
-        * the string, such as prefixing ESC.)\r
-        */\r
-       output_charset = CS_UTF8;\r
-       {\r
-           wchar_t widedata[32], *wp;\r
-           int wlen;\r
-           int ulen;\r
-\r
-           wlen = mb_to_wc(DEFAULT_CODEPAGE, 0,\r
-                           event->string, strlen(event->string),\r
-                           widedata, lenof(widedata)-1);\r
-\r
-           wp = widedata;\r
-           ulen = charset_from_unicode(&wp, &wlen, output+1, lenof(output)-2,\r
-                                       CS_UTF8, NULL, NULL, 0);\r
-           output[1+ulen] = '\0';\r
-       }\r
-#endif\r
-\r
-       if (!output[1] &&\r
-           (ucsval = keysym_to_unicode(event->keyval)) >= 0) {\r
-           ucsoutput[0] = '\033';\r
-           ucsoutput[1] = ucsval;\r
-           use_ucsoutput = TRUE;\r
-           end = 2;\r
-       } else {\r
-           output[lenof(output)-1] = '\0';\r
-           end = strlen(output);\r
-       }\r
-       if (event->state & GDK_MOD1_MASK) {\r
-           start = 0;\r
-           if (end == 1) end = 0;\r
-       } else\r
-           start = 1;\r
-\r
-       /* Control-` is the same as Control-\ (unless gtk has a better idea) */\r
-       if (!output[1] && event->keyval == '`' &&\r
-           (event->state & GDK_CONTROL_MASK)) {\r
-           output[1] = '\x1C';\r
-           use_ucsoutput = FALSE;\r
-           end = 2;\r
-       }\r
-\r
-       /* Control-Break sends a Break special to the backend */\r
-       if (event->keyval == GDK_Break &&\r
-           (event->state & GDK_CONTROL_MASK)) {\r
-           if (inst->back)\r
-               inst->back->special(inst->backhandle, TS_BRK);\r
-           return TRUE;\r
-       }\r
-\r
-       /* We handle Return ourselves, because it needs to be flagged as\r
-        * special to ldisc. */\r
-       if (event->keyval == GDK_Return) {\r
-           output[1] = '\015';\r
-           use_ucsoutput = FALSE;\r
-           end = 2;\r
-           special = TRUE;\r
-       }\r
-\r
-       /* Control-2, Control-Space and Control-@ are NUL */\r
-       if (!output[1] &&\r
-           (event->keyval == ' ' || event->keyval == '2' ||\r
-            event->keyval == '@') &&\r
-           (event->state & (GDK_SHIFT_MASK |\r
-                            GDK_CONTROL_MASK)) == GDK_CONTROL_MASK) {\r
-           output[1] = '\0';\r
-           use_ucsoutput = FALSE;\r
-           end = 2;\r
-       }\r
-\r
-       /* Control-Shift-Space is 160 (ISO8859 nonbreaking space) */\r
-       if (!output[1] && event->keyval == ' ' &&\r
-           (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ==\r
-           (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) {\r
-           output[1] = '\240';\r
-           output_charset = CS_ISO8859_1;\r
-           use_ucsoutput = FALSE;\r
-           end = 2;\r
-       }\r
-\r
-       /* We don't let GTK tell us what Backspace is! We know better. */\r
-       if (event->keyval == GDK_BackSpace &&\r
-           !(event->state & GDK_SHIFT_MASK)) {\r
-           output[1] = inst->cfg.bksp_is_delete ? '\x7F' : '\x08';\r
-           use_ucsoutput = FALSE;\r
-           end = 2;\r
-           special = TRUE;\r
-       }\r
-       /* For Shift Backspace, do opposite of what is configured. */\r
-       if (event->keyval == GDK_BackSpace &&\r
-           (event->state & GDK_SHIFT_MASK)) {\r
-           output[1] = inst->cfg.bksp_is_delete ? '\x08' : '\x7F';\r
-           use_ucsoutput = FALSE;\r
-           end = 2;\r
-           special = TRUE;\r
-       }\r
-\r
-       /* Shift-Tab is ESC [ Z */\r
-       if (event->keyval == GDK_ISO_Left_Tab ||\r
-           (event->keyval == GDK_Tab && (event->state & GDK_SHIFT_MASK))) {\r
-           end = 1 + sprintf(output+1, "\033[Z");\r
-           use_ucsoutput = FALSE;\r
-       }\r
-       /* And normal Tab is Tab, if the keymap hasn't already told us.\r
-        * (Curiously, at least one version of the MacOS 10.5 X server\r
-        * doesn't translate Tab for us. */\r
-       if (event->keyval == GDK_Tab && end <= 1) {\r
-           output[1] = '\t';\r
-           end = 2;\r
-       }\r
-\r
-       /*\r
-        * NetHack keypad mode.\r
-        */\r
-       if (inst->cfg.nethack_keypad) {\r
-           char *keys = NULL;\r
-           switch (event->keyval) {\r
-             case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break;\r
-             case GDK_KP_2: case GDK_KP_Down: keys = "jJ\012"; break;\r
-             case GDK_KP_3: case GDK_KP_Page_Down: keys = "nN\016"; break;\r
-             case GDK_KP_4: case GDK_KP_Left: keys = "hH\010"; break;\r
-             case GDK_KP_5: case GDK_KP_Begin: keys = "..."; break;\r
-             case GDK_KP_6: case GDK_KP_Right: keys = "lL\014"; break;\r
-             case GDK_KP_7: case GDK_KP_Home: keys = "yY\031"; break;\r
-             case GDK_KP_8: case GDK_KP_Up: keys = "kK\013"; break;\r
-             case GDK_KP_9: case GDK_KP_Page_Up: keys = "uU\025"; break;\r
-           }\r
-           if (keys) {\r
-               end = 2;\r
-               if (event->state & GDK_CONTROL_MASK)\r
-                   output[1] = keys[2];\r
-               else if (event->state & GDK_SHIFT_MASK)\r
-                   output[1] = keys[1];\r
-               else\r
-                   output[1] = keys[0];\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-       }\r
-\r
-       /*\r
-        * Application keypad mode.\r
-        */\r
-       if (inst->term->app_keypad_keys && !inst->cfg.no_applic_k) {\r
-           int xkey = 0;\r
-           switch (event->keyval) {\r
-             case GDK_Num_Lock: xkey = 'P'; break;\r
-             case GDK_KP_Divide: xkey = 'Q'; break;\r
-             case GDK_KP_Multiply: xkey = 'R'; break;\r
-             case GDK_KP_Subtract: xkey = 'S'; break;\r
-               /*\r
-                * Keypad + is tricky. It covers a space that would\r
-                * be taken up on the VT100 by _two_ keys; so we\r
-                * let Shift select between the two. Worse still,\r
-                * in xterm function key mode we change which two...\r
-                */\r
-             case GDK_KP_Add:\r
-               if (inst->cfg.funky_type == FUNKY_XTERM) {\r
-                   if (event->state & GDK_SHIFT_MASK)\r
-                       xkey = 'l';\r
-                   else\r
-                       xkey = 'k';\r
-               } else if (event->state & GDK_SHIFT_MASK)\r
-                       xkey = 'm';\r
-               else\r
-                   xkey = 'l';\r
-               break;\r
-             case GDK_KP_Enter: xkey = 'M'; break;\r
-             case GDK_KP_0: case GDK_KP_Insert: xkey = 'p'; break;\r
-             case GDK_KP_1: case GDK_KP_End: xkey = 'q'; break;\r
-             case GDK_KP_2: case GDK_KP_Down: xkey = 'r'; break;\r
-             case GDK_KP_3: case GDK_KP_Page_Down: xkey = 's'; break;\r
-             case GDK_KP_4: case GDK_KP_Left: xkey = 't'; break;\r
-             case GDK_KP_5: case GDK_KP_Begin: xkey = 'u'; break;\r
-             case GDK_KP_6: case GDK_KP_Right: xkey = 'v'; break;\r
-             case GDK_KP_7: case GDK_KP_Home: xkey = 'w'; break;\r
-             case GDK_KP_8: case GDK_KP_Up: xkey = 'x'; break;\r
-             case GDK_KP_9: case GDK_KP_Page_Up: xkey = 'y'; break;\r
-             case GDK_KP_Decimal: case GDK_KP_Delete: xkey = 'n'; break;\r
-           }\r
-           if (xkey) {\r
-               if (inst->term->vt52_mode) {\r
-                   if (xkey >= 'P' && xkey <= 'S')\r
-                       end = 1 + sprintf(output+1, "\033%c", xkey);\r
-                   else\r
-                       end = 1 + sprintf(output+1, "\033?%c", xkey);\r
-               } else\r
-                   end = 1 + sprintf(output+1, "\033O%c", xkey);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-       }\r
-\r
-       /*\r
-        * Next, all the keys that do tilde codes. (ESC '[' nn '~',\r
-        * for integer decimal nn.)\r
-        *\r
-        * We also deal with the weird ones here. Linux VCs replace F1\r
-        * to F5 by ESC [ [ A to ESC [ [ E. rxvt doesn't do _that_, but\r
-        * does replace Home and End (1~ and 4~) by ESC [ H and ESC O w\r
-        * respectively.\r
-        */\r
-       {\r
-           int code = 0;\r
-           switch (event->keyval) {\r
-             case GDK_F1:\r
-               code = (event->state & GDK_SHIFT_MASK ? 23 : 11);\r
-               break;\r
-             case GDK_F2:\r
-               code = (event->state & GDK_SHIFT_MASK ? 24 : 12);\r
-               break;\r
-             case GDK_F3:\r
-               code = (event->state & GDK_SHIFT_MASK ? 25 : 13);\r
-               break;\r
-             case GDK_F4:\r
-               code = (event->state & GDK_SHIFT_MASK ? 26 : 14);\r
-               break;\r
-             case GDK_F5:\r
-               code = (event->state & GDK_SHIFT_MASK ? 28 : 15);\r
-               break;\r
-             case GDK_F6:\r
-               code = (event->state & GDK_SHIFT_MASK ? 29 : 17);\r
-               break;\r
-             case GDK_F7:\r
-               code = (event->state & GDK_SHIFT_MASK ? 31 : 18);\r
-               break;\r
-             case GDK_F8:\r
-               code = (event->state & GDK_SHIFT_MASK ? 32 : 19);\r
-               break;\r
-             case GDK_F9:\r
-               code = (event->state & GDK_SHIFT_MASK ? 33 : 20);\r
-               break;\r
-             case GDK_F10:\r
-               code = (event->state & GDK_SHIFT_MASK ? 34 : 21);\r
-               break;\r
-             case GDK_F11:\r
-               code = 23;\r
-               break;\r
-             case GDK_F12:\r
-               code = 24;\r
-               break;\r
-             case GDK_F13:\r
-               code = 25;\r
-               break;\r
-             case GDK_F14:\r
-               code = 26;\r
-               break;\r
-             case GDK_F15:\r
-               code = 28;\r
-               break;\r
-             case GDK_F16:\r
-               code = 29;\r
-               break;\r
-             case GDK_F17:\r
-               code = 31;\r
-               break;\r
-             case GDK_F18:\r
-               code = 32;\r
-               break;\r
-             case GDK_F19:\r
-               code = 33;\r
-               break;\r
-             case GDK_F20:\r
-               code = 34;\r
-               break;\r
-           }\r
-           if (!(event->state & GDK_CONTROL_MASK)) switch (event->keyval) {\r
-             case GDK_Home: case GDK_KP_Home:\r
-               code = 1;\r
-               break;\r
-             case GDK_Insert: case GDK_KP_Insert:\r
-               code = 2;\r
-               break;\r
-             case GDK_Delete: case GDK_KP_Delete:\r
-               code = 3;\r
-               break;\r
-             case GDK_End: case GDK_KP_End:\r
-               code = 4;\r
-               break;\r
-             case GDK_Page_Up: case GDK_KP_Page_Up:\r
-               code = 5;\r
-               break;\r
-             case GDK_Page_Down: case GDK_KP_Page_Down:\r
-               code = 6;\r
-               break;\r
-           }\r
-           /* Reorder edit keys to physical order */\r
-           if (inst->cfg.funky_type == FUNKY_VT400 && code <= 6)\r
-               code = "\0\2\1\4\5\3\6"[code];\r
-\r
-           if (inst->term->vt52_mode && code > 0 && code <= 6) {\r
-               end = 1 + sprintf(output+1, "\x1B%c", " HLMEIG"[code]);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-\r
-           if (inst->cfg.funky_type == FUNKY_SCO &&     /* SCO function keys */\r
-               code >= 11 && code <= 34) {\r
-               char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{";\r
-               int index = 0;\r
-               switch (event->keyval) {\r
-                 case GDK_F1: index = 0; break;\r
-                 case GDK_F2: index = 1; break;\r
-                 case GDK_F3: index = 2; break;\r
-                 case GDK_F4: index = 3; break;\r
-                 case GDK_F5: index = 4; break;\r
-                 case GDK_F6: index = 5; break;\r
-                 case GDK_F7: index = 6; break;\r
-                 case GDK_F8: index = 7; break;\r
-                 case GDK_F9: index = 8; break;\r
-                 case GDK_F10: index = 9; break;\r
-                 case GDK_F11: index = 10; break;\r
-                 case GDK_F12: index = 11; break;\r
-               }\r
-               if (event->state & GDK_SHIFT_MASK) index += 12;\r
-               if (event->state & GDK_CONTROL_MASK) index += 24;\r
-               end = 1 + sprintf(output+1, "\x1B[%c", codes[index]);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-           if (inst->cfg.funky_type == FUNKY_SCO &&     /* SCO small keypad */\r
-               code >= 1 && code <= 6) {\r
-               char codes[] = "HL.FIG";\r
-               if (code == 3) {\r
-                   output[1] = '\x7F';\r
-                   end = 2;\r
-               } else {\r
-                   end = 1 + sprintf(output+1, "\x1B[%c", codes[code-1]);\r
-               }\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-           if ((inst->term->vt52_mode || inst->cfg.funky_type == FUNKY_VT100P) &&\r
-               code >= 11 && code <= 24) {\r
-               int offt = 0;\r
-               if (code > 15)\r
-                   offt++;\r
-               if (code > 21)\r
-                   offt++;\r
-               if (inst->term->vt52_mode)\r
-                   end = 1 + sprintf(output+1,\r
-                                     "\x1B%c", code + 'P' - 11 - offt);\r
-               else\r
-                   end = 1 + sprintf(output+1,\r
-                                     "\x1BO%c", code + 'P' - 11 - offt);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-           if (inst->cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) {\r
-               end = 1 + sprintf(output+1, "\x1B[[%c", code + 'A' - 11);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-           if (inst->cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) {\r
-               if (inst->term->vt52_mode)\r
-                   end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11);\r
-               else\r
-                   end = 1 + sprintf(output+1, "\x1BO%c", code + 'P' - 11);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-           if (inst->cfg.rxvt_homeend && (code == 1 || code == 4)) {\r
-               end = 1 + sprintf(output+1, code == 1 ? "\x1B[H" : "\x1BOw");\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-           if (code) {\r
-               end = 1 + sprintf(output+1, "\x1B[%d~", code);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-       }\r
-\r
-       /*\r
-        * Cursor keys. (This includes the numberpad cursor keys,\r
-        * if we haven't already done them due to app keypad mode.)\r
-        * \r
-        * Here we also process un-numlocked un-appkeypadded KP5,\r
-        * which sends ESC [ G.\r
-        */\r
-       {\r
-           int xkey = 0;\r
-           switch (event->keyval) {\r
-             case GDK_Up: case GDK_KP_Up: xkey = 'A'; break;\r
-             case GDK_Down: case GDK_KP_Down: xkey = 'B'; break;\r
-             case GDK_Right: case GDK_KP_Right: xkey = 'C'; break;\r
-             case GDK_Left: case GDK_KP_Left: xkey = 'D'; break;\r
-             case GDK_Begin: case GDK_KP_Begin: xkey = 'G'; break;\r
-           }\r
-           if (xkey) {\r
-               end = 1 + format_arrow_key(output+1, inst->term, xkey,\r
-                                          event->state & GDK_CONTROL_MASK);\r
-               use_ucsoutput = FALSE;\r
-               goto done;\r
-           }\r
-       }\r
-       goto done;\r
-    }\r
-\r
-    done:\r
-\r
-    if (end-start > 0) {\r
-#ifdef KEY_DEBUGGING\r
-       int i;\r
-       printf("generating sequence:");\r
-       for (i = start; i < end; i++)\r
-           printf(" %02x", (unsigned char) output[i]);\r
-       printf("\n");\r
-#endif\r
-\r
-       if (special) {\r
-           /*\r
-            * For special control characters, the character set\r
-            * should never matter.\r
-            */\r
-           output[end] = '\0';        /* NUL-terminate */\r
-           if (inst->ldisc)\r
-               ldisc_send(inst->ldisc, output+start, -2, 1);\r
-       } else if (!inst->direct_to_font) {\r
-           if (!use_ucsoutput) {\r
-               if (inst->ldisc)\r
-                   lpage_send(inst->ldisc, output_charset, output+start,\r
-                              end-start, 1);\r
-           } else {\r
-               /*\r
-                * We generated our own Unicode key data from the\r
-                * keysym, so use that instead.\r
-                */\r
-               if (inst->ldisc)\r
-                   luni_send(inst->ldisc, ucsoutput+start, end-start, 1);\r
-           }\r
-       } else {\r
-           /*\r
-            * In direct-to-font mode, we just send the string\r
-            * exactly as we received it.\r
-            */\r
-           if (inst->ldisc)\r
-               ldisc_send(inst->ldisc, output+start, end-start, 1);\r
-       }\r
-\r
-       show_mouseptr(inst, 0);\r
-       term_seen_key_event(inst->term);\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-gboolean button_internal(struct gui_data *inst, guint32 timestamp,\r
-                        GdkEventType type, guint ebutton, guint state,\r
-                        gdouble ex, gdouble ey)\r
-{\r
-    int shift, ctrl, alt, x, y, button, act;\r
-\r
-    /* Remember the timestamp. */\r
-    inst->input_event_time = timestamp;\r
-\r
-    show_mouseptr(inst, 1);\r
-\r
-    if (ebutton == 4 && type == GDK_BUTTON_PRESS) {\r
-       term_scroll(inst->term, 0, -5);\r
-       return TRUE;\r
-    }\r
-    if (ebutton == 5 && type == GDK_BUTTON_PRESS) {\r
-       term_scroll(inst->term, 0, +5);\r
-       return TRUE;\r
-    }\r
-\r
-    shift = state & GDK_SHIFT_MASK;\r
-    ctrl = state & GDK_CONTROL_MASK;\r
-    alt = state & GDK_MOD1_MASK;\r
-\r
-    if (ebutton == 3 && ctrl) {\r
-       gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,\r
-                      ebutton, timestamp);\r
-       return TRUE;\r
-    }\r
-\r
-    if (ebutton == 1)\r
-       button = MBT_LEFT;\r
-    else if (ebutton == 2)\r
-       button = MBT_MIDDLE;\r
-    else if (ebutton == 3)\r
-       button = MBT_RIGHT;\r
-    else\r
-       return FALSE;                  /* don't even know what button! */\r
-\r
-    switch (type) {\r
-      case GDK_BUTTON_PRESS: act = MA_CLICK; break;\r
-      case GDK_BUTTON_RELEASE: act = MA_RELEASE; break;\r
-      case GDK_2BUTTON_PRESS: act = MA_2CLK; break;\r
-      case GDK_3BUTTON_PRESS: act = MA_3CLK; break;\r
-      default: return FALSE;          /* don't know this event type */\r
-    }\r
-\r
-    if (send_raw_mouse && !(inst->cfg.mouse_override && shift) &&\r
-       act != MA_CLICK && act != MA_RELEASE)\r
-       return TRUE;                   /* we ignore these in raw mouse mode */\r
-\r
-    x = (ex - inst->cfg.window_border) / inst->font_width;\r
-    y = (ey - inst->cfg.window_border) / inst->font_height;\r
-\r
-    term_mouse(inst->term, button, translate_button(button), act,\r
-              x, y, shift, ctrl, alt);\r
-\r
-    return TRUE;\r
-}\r
-\r
-gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    return button_internal(inst, event->time, event->type, event->button,\r
-                          event->state, event->x, event->y);\r
-}\r
-\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-/*\r
- * In GTK 2, mouse wheel events have become a new type of event.\r
- * This handler translates them back into button-4 and button-5\r
- * presses so that I don't have to change my old code too much :-)\r
- */\r
-gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    guint button;\r
-\r
-    if (event->direction == GDK_SCROLL_UP)\r
-       button = 4;\r
-    else if (event->direction == GDK_SCROLL_DOWN)\r
-       button = 5;\r
-    else\r
-       return FALSE;\r
-\r
-    return button_internal(inst, event->time, GDK_BUTTON_PRESS,\r
-                          button, event->state, event->x, event->y);\r
-}\r
-#endif\r
-\r
-gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    int shift, ctrl, alt, x, y, button;\r
-\r
-    /* Remember the timestamp. */\r
-    inst->input_event_time = event->time;\r
-\r
-    show_mouseptr(inst, 1);\r
-\r
-    shift = event->state & GDK_SHIFT_MASK;\r
-    ctrl = event->state & GDK_CONTROL_MASK;\r
-    alt = event->state & GDK_MOD1_MASK;\r
-    if (event->state & GDK_BUTTON1_MASK)\r
-       button = MBT_LEFT;\r
-    else if (event->state & GDK_BUTTON2_MASK)\r
-       button = MBT_MIDDLE;\r
-    else if (event->state & GDK_BUTTON3_MASK)\r
-       button = MBT_RIGHT;\r
-    else\r
-       return FALSE;                  /* don't even know what button! */\r
-\r
-    x = (event->x - inst->cfg.window_border) / inst->font_width;\r
-    y = (event->y - inst->cfg.window_border) / inst->font_height;\r
-\r
-    term_mouse(inst->term, button, translate_button(button), MA_DRAG,\r
-              x, y, shift, ctrl, alt);\r
-\r
-    return TRUE;\r
-}\r
-\r
-void frontend_keypress(void *handle)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)handle;\r
-\r
-    /*\r
-     * If our child process has exited but not closed, terminate on\r
-     * any keypress.\r
-     */\r
-    if (inst->exited)\r
-       exit(0);\r
-}\r
-\r
-static gint idle_exit_func(gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    int exitcode;\r
-\r
-    if (!inst->exited &&\r
-        (exitcode = inst->back->exitcode(inst->backhandle)) >= 0) {\r
-       inst->exited = TRUE;\r
-       if (inst->cfg.close_on_exit == FORCE_ON ||\r
-           (inst->cfg.close_on_exit == AUTO && exitcode == 0))\r
-           gtk_main_quit();           /* just go */\r
-       if (inst->ldisc) {\r
-           ldisc_free(inst->ldisc);\r
-           inst->ldisc = NULL;\r
-       }\r
-       if (inst->back) {\r
-           inst->back->free(inst->backhandle);\r
-           inst->backhandle = NULL;\r
-           inst->back = NULL;\r
-            term_provide_resize_fn(inst->term, NULL, NULL);\r
-           update_specials_menu(inst);\r
-       }\r
-       gtk_widget_set_sensitive(inst->restartitem, TRUE);\r
-    }\r
-\r
-    gtk_idle_remove(inst->term_exit_idle_id);\r
-    return TRUE;\r
-}\r
-\r
-void notify_remote_exit(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-\r
-    inst->term_exit_idle_id = gtk_idle_add(idle_exit_func, inst);\r
-}\r
-\r
-static gint timer_trigger(gpointer data)\r
-{\r
-    long now = GPOINTER_TO_LONG(data);\r
-    long next;\r
-    long ticks;\r
-\r
-    if (run_timers(now, &next)) {\r
-       ticks = next - GETTICKCOUNT();\r
-       timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,\r
-                                  LONG_TO_GPOINTER(next));\r
-    }\r
-\r
-    /*\r
-     * Never let a timer resume. If we need another one, we've\r
-     * asked for it explicitly above.\r
-     */\r
-    return FALSE;\r
-}\r
-\r
-void timer_change_notify(long next)\r
-{\r
-    long ticks;\r
-\r
-    if (timer_id)\r
-       gtk_timeout_remove(timer_id);\r
-\r
-    ticks = next - GETTICKCOUNT();\r
-    if (ticks <= 0)\r
-       ticks = 1;                     /* just in case */\r
-\r
-    timer_id = gtk_timeout_add(ticks, timer_trigger,\r
-                              LONG_TO_GPOINTER(next));\r
-}\r
-\r
-void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)\r
-{\r
-    /*\r
-     * We must process exceptional notifications before ordinary\r
-     * readability ones, or we may go straight past the urgent\r
-     * marker.\r
-     */\r
-    if (condition & GDK_INPUT_EXCEPTION)\r
-        select_result(sourcefd, 4);\r
-    if (condition & GDK_INPUT_READ)\r
-        select_result(sourcefd, 1);\r
-    if (condition & GDK_INPUT_WRITE)\r
-        select_result(sourcefd, 2);\r
-}\r
-\r
-void destroy(GtkWidget *widget, gpointer data)\r
-{\r
-    gtk_main_quit();\r
-}\r
-\r
-gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    term_set_focus(inst->term, event->in);\r
-    term_update(inst->term);\r
-    show_mouseptr(inst, 1);\r
-    return FALSE;\r
-}\r
-\r
-void set_busy_status(void *frontend, int status)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    inst->busy_status = status;\r
-    update_mouseptr(inst);\r
-}\r
-\r
-/*\r
- * set or clear the "raw mouse message" mode\r
- */\r
-void set_raw_mouse_mode(void *frontend, int activate)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    activate = activate && !inst->cfg.no_mouse_rep;\r
-    send_raw_mouse = activate;\r
-    update_mouseptr(inst);\r
-}\r
-\r
-void request_resize(void *frontend, int w, int h)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    int large_x, large_y;\r
-    int offset_x, offset_y;\r
-    int area_x, area_y;\r
-    GtkRequisition inner, outer;\r
-\r
-    /*\r
-     * This is a heinous hack dreamed up by the gnome-terminal\r
-     * people to get around a limitation in gtk. The problem is\r
-     * that in order to set the size correctly we really need to be\r
-     * calling gtk_window_resize - but that needs to know the size\r
-     * of the _whole window_, not the drawing area. So what we do\r
-     * is to set an artificially huge size request on the drawing\r
-     * area, recompute the resulting size request on the window,\r
-     * and look at the difference between the two. That gives us\r
-     * the x and y offsets we need to translate drawing area size\r
-     * into window size for real, and then we call\r
-     * gtk_window_resize.\r
-     */\r
-\r
-    /*\r
-     * We start by retrieving the current size of the whole window.\r
-     * Adding a bit to _that_ will give us a value we can use as a\r
-     * bogus size request which guarantees to be bigger than the\r
-     * current size of the drawing area.\r
-     */\r
-    get_window_pixels(inst, &large_x, &large_y);\r
-    large_x += 32;\r
-    large_y += 32;\r
-\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    gtk_widget_set_size_request(inst->area, large_x, large_y);\r
-#else\r
-    gtk_widget_set_usize(inst->area, large_x, large_y);\r
-#endif\r
-    gtk_widget_size_request(inst->area, &inner);\r
-    gtk_widget_size_request(inst->window, &outer);\r
-\r
-    offset_x = outer.width - inner.width;\r
-    offset_y = outer.height - inner.height;\r
-\r
-    area_x = inst->font_width * w + 2*inst->cfg.window_border;\r
-    area_y = inst->font_height * h + 2*inst->cfg.window_border;\r
-\r
-    /*\r
-     * Now we must set the size request on the drawing area back to\r
-     * something sensible before we commit the real resize. Best\r
-     * way to do this, I think, is to set it to what the size is\r
-     * really going to end up being.\r
-     */\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    gtk_widget_set_size_request(inst->area, area_x, area_y);\r
-    gtk_window_resize(GTK_WINDOW(inst->window),\r
-                     area_x + offset_x, area_y + offset_y);\r
-#else\r
-    gtk_widget_set_usize(inst->area, area_x, area_y);\r
-    gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), area_x, area_y);\r
-    /*\r
-     * I can no longer remember what this call to\r
-     * gtk_container_dequeue_resize_handler is for. It was\r
-     * introduced in r3092 with no comment, and the commit log\r
-     * message was uninformative. I'm _guessing_ its purpose is to\r
-     * prevent gratuitous resize processing on the window given\r
-     * that we're about to resize it anyway, but I have no idea\r
-     * why that's so incredibly vital.\r
-     * \r
-     * I've tried removing the call, and nothing seems to go\r
-     * wrong. I've backtracked to r3092 and tried removing the\r
-     * call there, and still nothing goes wrong. So I'm going to\r
-     * adopt the working hypothesis that it's superfluous; I won't\r
-     * actually remove it from the GTK 1.2 code, but I won't\r
-     * attempt to replicate its functionality in the GTK 2 code\r
-     * above.\r
-     */\r
-    gtk_container_dequeue_resize_handler(GTK_CONTAINER(inst->window));\r
-    gdk_window_resize(inst->window->window,\r
-                     area_x + offset_x, area_y + offset_y);\r
-#endif\r
-}\r
-\r
-static void real_palette_set(struct gui_data *inst, int n, int r, int g, int b)\r
-{\r
-    gboolean success[1];\r
-\r
-    inst->cols[n].red = r * 0x0101;\r
-    inst->cols[n].green = g * 0x0101;\r
-    inst->cols[n].blue = b * 0x0101;\r
-\r
-    gdk_colormap_free_colors(inst->colmap, inst->cols + n, 1);\r
-    gdk_colormap_alloc_colors(inst->colmap, inst->cols + n, 1,\r
-                             FALSE, TRUE, success);\r
-    if (!success[0])\r
-       g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", appname,\r
-               n, r, g, b);\r
-}\r
-\r
-void set_window_background(struct gui_data *inst)\r
-{\r
-    if (inst->area && inst->area->window)\r
-       gdk_window_set_background(inst->area->window, &inst->cols[258]);\r
-    if (inst->window && inst->window->window)\r
-       gdk_window_set_background(inst->window->window, &inst->cols[258]);\r
-}\r
-\r
-void palette_set(void *frontend, int n, int r, int g, int b)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    if (n >= 16)\r
-       n += 256 - 16;\r
-    if (n > NALLCOLOURS)\r
-       return;\r
-    real_palette_set(inst, n, r, g, b);\r
-    if (n == 258) {\r
-       /* Default Background changed. Ensure space between text area and\r
-        * window border is redrawn */\r
-       set_window_background(inst);\r
-       draw_backing_rect(inst);\r
-       gtk_widget_queue_draw(inst->area);\r
-    }\r
-}\r
-\r
-void palette_reset(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    /* This maps colour indices in inst->cfg to those used in inst->cols. */\r
-    static const int ww[] = {\r
-       256, 257, 258, 259, 260, 261,\r
-       0, 8, 1, 9, 2, 10, 3, 11,\r
-       4, 12, 5, 13, 6, 14, 7, 15\r
-    };\r
-    gboolean success[NALLCOLOURS];\r
-    int i;\r
-\r
-    assert(lenof(ww) == NCFGCOLOURS);\r
-\r
-    if (!inst->colmap) {\r
-       inst->colmap = gdk_colormap_get_system();\r
-    } else {\r
-       gdk_colormap_free_colors(inst->colmap, inst->cols, NALLCOLOURS);\r
-    }\r
-\r
-    for (i = 0; i < NCFGCOLOURS; i++) {\r
-       inst->cols[ww[i]].red = inst->cfg.colours[i][0] * 0x0101;\r
-       inst->cols[ww[i]].green = inst->cfg.colours[i][1] * 0x0101;\r
-       inst->cols[ww[i]].blue = inst->cfg.colours[i][2] * 0x0101;\r
-    }\r
-\r
-    for (i = 0; i < NEXTCOLOURS; i++) {\r
-       if (i < 216) {\r
-           int r = i / 36, g = (i / 6) % 6, b = i % 6;\r
-           inst->cols[i+16].red = r ? r * 0x2828 + 0x3737 : 0;\r
-           inst->cols[i+16].green = g ? g * 0x2828 + 0x3737 : 0;\r
-           inst->cols[i+16].blue = b ? b * 0x2828 + 0x3737 : 0;\r
-       } else {\r
-           int shade = i - 216;\r
-           shade = shade * 0x0a0a + 0x0808;\r
-           inst->cols[i+16].red = inst->cols[i+16].green =\r
-               inst->cols[i+16].blue = shade;\r
-       }\r
-    }\r
-\r
-    gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS,\r
-                             FALSE, TRUE, success);\r
-    for (i = 0; i < NALLCOLOURS; i++) {\r
-       if (!success[i])\r
-           g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n",\r
-                    appname, i, inst->cfg.colours[i][0],\r
-                    inst->cfg.colours[i][1], inst->cfg.colours[i][2]);\r
-    }\r
-\r
-    /* Since Default Background may have changed, ensure that space\r
-     * between text area and window border is refreshed. */\r
-    set_window_background(inst);\r
-    if (inst->area && inst->area->window) {\r
-       draw_backing_rect(inst);\r
-       gtk_widget_queue_draw(inst->area);\r
-    }\r
-}\r
-\r
-/* Ensure that all the cut buffers exist - according to the ICCCM, we must\r
- * do this before we start using cut buffers.\r
- */\r
-void init_cutbuffers()\r
-{\r
-    unsigned char empty[] = "";\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, empty, 0);\r
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),\r
-                   XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, empty, 0);\r
-}\r
-\r
-/* Store the data in a cut-buffer. */\r
-void store_cutbuffer(char * ptr, int len)\r
-{\r
-    /* ICCCM says we must rotate the buffers before storing to buffer 0. */\r
-    XRotateBuffers(GDK_DISPLAY(), 1);\r
-    XStoreBytes(GDK_DISPLAY(), ptr, len);\r
-}\r
-\r
-/* Retrieve data from a cut-buffer.\r
- * Returned data needs to be freed with XFree().\r
- */\r
-char * retrieve_cutbuffer(int * nbytes)\r
-{\r
-    char * ptr;\r
-    ptr = XFetchBytes(GDK_DISPLAY(), nbytes);\r
-    if (*nbytes <= 0 && ptr != 0) {\r
-       XFree(ptr);\r
-       ptr = 0;\r
-    }\r
-    return ptr;\r
-}\r
-\r
-void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_deselect)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    if (inst->pasteout_data)\r
-       sfree(inst->pasteout_data);\r
-    if (inst->pasteout_data_ctext)\r
-       sfree(inst->pasteout_data_ctext);\r
-    if (inst->pasteout_data_utf8)\r
-       sfree(inst->pasteout_data_utf8);\r
-\r
-    /*\r
-     * Set up UTF-8 and compound text paste data. This only happens\r
-     * if we aren't in direct-to-font mode using the D800 hack.\r
-     */\r
-    if (!inst->direct_to_font) {\r
-       wchar_t *tmp = data;\r
-       int tmplen = len;\r
-       XTextProperty tp;\r
-       char *list[1];\r
-\r
-       inst->pasteout_data_utf8 = snewn(len*6, char);\r
-       inst->pasteout_data_utf8_len = len*6;\r
-       inst->pasteout_data_utf8_len =\r
-           charset_from_unicode(&tmp, &tmplen, inst->pasteout_data_utf8,\r
-                                inst->pasteout_data_utf8_len,\r
-                                CS_UTF8, NULL, NULL, 0);\r
-       if (inst->pasteout_data_utf8_len == 0) {\r
-           sfree(inst->pasteout_data_utf8);\r
-           inst->pasteout_data_utf8 = NULL;\r
-       } else {\r
-           inst->pasteout_data_utf8 =\r
-               sresize(inst->pasteout_data_utf8,\r
-                       inst->pasteout_data_utf8_len + 1, char);\r
-           inst->pasteout_data_utf8[inst->pasteout_data_utf8_len] = '\0';\r
-       }\r
-\r
-       /*\r
-        * Now let Xlib convert our UTF-8 data into compound text.\r
-        */\r
-       list[0] = inst->pasteout_data_utf8;\r
-       if (Xutf8TextListToTextProperty(GDK_DISPLAY(), list, 1,\r
-                                       XCompoundTextStyle, &tp) == 0) {\r
-           inst->pasteout_data_ctext = snewn(tp.nitems+1, char);\r
-           memcpy(inst->pasteout_data_ctext, tp.value, tp.nitems);\r
-           inst->pasteout_data_ctext_len = tp.nitems;\r
-           XFree(tp.value);\r
-       } else {\r
-            inst->pasteout_data_ctext = NULL;\r
-            inst->pasteout_data_ctext_len = 0;\r
-        }\r
-    } else {\r
-       inst->pasteout_data_utf8 = NULL;\r
-       inst->pasteout_data_utf8_len = 0;\r
-       inst->pasteout_data_ctext = NULL;\r
-       inst->pasteout_data_ctext_len = 0;\r
-    }\r
-\r
-    inst->pasteout_data = snewn(len*6, char);\r
-    inst->pasteout_data_len = len*6;\r
-    inst->pasteout_data_len = wc_to_mb(inst->ucsdata.line_codepage, 0,\r
-                                      data, len, inst->pasteout_data,\r
-                                      inst->pasteout_data_len,\r
-                                      NULL, NULL, NULL);\r
-    if (inst->pasteout_data_len == 0) {\r
-       sfree(inst->pasteout_data);\r
-       inst->pasteout_data = NULL;\r
-    } else {\r
-       inst->pasteout_data =\r
-           sresize(inst->pasteout_data, inst->pasteout_data_len, char);\r
-    }\r
-\r
-    store_cutbuffer(inst->pasteout_data, inst->pasteout_data_len);\r
-\r
-    if (gtk_selection_owner_set(inst->area, GDK_SELECTION_PRIMARY,\r
-                               inst->input_event_time)) {\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-       gtk_selection_clear_targets(inst->area, GDK_SELECTION_PRIMARY);\r
-#endif\r
-       gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,\r
-                                GDK_SELECTION_TYPE_STRING, 1);\r
-       if (inst->pasteout_data_ctext)\r
-           gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,\r
-                                    compound_text_atom, 1);\r
-       if (inst->pasteout_data_utf8)\r
-           gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,\r
-                                    utf8_string_atom, 1);\r
-    }\r
-\r
-    if (must_deselect)\r
-       term_deselect(inst->term);\r
-}\r
-\r
-void selection_get(GtkWidget *widget, GtkSelectionData *seldata,\r
-                  guint info, guint time_stamp, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    if (seldata->target == utf8_string_atom)\r
-       gtk_selection_data_set(seldata, seldata->target, 8,\r
-                              (unsigned char *)inst->pasteout_data_utf8,\r
-                              inst->pasteout_data_utf8_len);\r
-    else if (seldata->target == compound_text_atom)\r
-       gtk_selection_data_set(seldata, seldata->target, 8,\r
-                              (unsigned char *)inst->pasteout_data_ctext,\r
-                              inst->pasteout_data_ctext_len);\r
-    else\r
-       gtk_selection_data_set(seldata, seldata->target, 8,\r
-                              (unsigned char *)inst->pasteout_data,\r
-                              inst->pasteout_data_len);\r
-}\r
-\r
-gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata,\r
-                    gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-\r
-    term_deselect(inst->term);\r
-    if (inst->pasteout_data)\r
-       sfree(inst->pasteout_data);\r
-    if (inst->pasteout_data_ctext)\r
-       sfree(inst->pasteout_data_ctext);\r
-    if (inst->pasteout_data_utf8)\r
-       sfree(inst->pasteout_data_utf8);\r
-    inst->pasteout_data = NULL;\r
-    inst->pasteout_data_len = 0;\r
-    inst->pasteout_data_ctext = NULL;\r
-    inst->pasteout_data_ctext_len = 0;\r
-    inst->pasteout_data_utf8 = NULL;\r
-    inst->pasteout_data_utf8_len = 0;\r
-    return TRUE;\r
-}\r
-\r
-void request_paste(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    /*\r
-     * In Unix, pasting is asynchronous: all we can do at the\r
-     * moment is to call gtk_selection_convert(), and when the data\r
-     * comes back _then_ we can call term_do_paste().\r
-     */\r
-\r
-    if (!inst->direct_to_font) {\r
-       /*\r
-        * First we attempt to retrieve the selection as a UTF-8\r
-        * string (which we will convert to the correct code page\r
-        * before sending to the session, of course). If that\r
-        * fails, selection_received() will be informed and will\r
-        * fall back to an ordinary string.\r
-        */\r
-       gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,\r
-                             utf8_string_atom,\r
-                             inst->input_event_time);\r
-    } else {\r
-       /*\r
-        * If we're in direct-to-font mode, we disable UTF-8\r
-        * pasting, and go straight to ordinary string data.\r
-        */\r
-       gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,\r
-                             GDK_SELECTION_TYPE_STRING,\r
-                             inst->input_event_time);\r
-    }\r
-}\r
-\r
-gint idle_paste_func(gpointer data);   /* forward ref */\r
-\r
-void selection_received(GtkWidget *widget, GtkSelectionData *seldata,\r
-                       guint time, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    XTextProperty tp;\r
-    char **list;\r
-    char *text;\r
-    int length, count, ret;\r
-    int free_list_required = 0;\r
-    int free_required = 0;\r
-    int charset;\r
-\r
-    if (seldata->target == utf8_string_atom && seldata->length <= 0) {\r
-       /*\r
-        * Failed to get a UTF-8 selection string. Try compound\r
-        * text next.\r
-        */\r
-       gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,\r
-                             compound_text_atom,\r
-                             inst->input_event_time);\r
-       return;\r
-    }\r
-\r
-    if (seldata->target == compound_text_atom && seldata->length <= 0) {\r
-       /*\r
-        * Failed to get UTF-8 or compound text. Try an ordinary\r
-        * string.\r
-        */\r
-       gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,\r
-                             GDK_SELECTION_TYPE_STRING,\r
-                             inst->input_event_time);\r
-       return;\r
-    }\r
-\r
-    /*\r
-     * If we have data, but it's not of a type we can deal with,\r
-     * we have to ignore the data.\r
-     */\r
-    if (seldata->length > 0 &&\r
-       seldata->type != GDK_SELECTION_TYPE_STRING &&\r
-       seldata->type != compound_text_atom &&\r
-       seldata->type != utf8_string_atom)\r
-       return;\r
-\r
-    /*\r
-     * If we have no data, try looking in a cut buffer.\r
-     */\r
-    if (seldata->length <= 0) {\r
-       text = retrieve_cutbuffer(&length);\r
-       if (length == 0)\r
-           return;\r
-       /* Xterm is rumoured to expect Latin-1, though I havn't checked the\r
-        * source, so use that as a de-facto standard. */\r
-       charset = CS_ISO8859_1;\r
-       free_required = 1;\r
-    } else {\r
-       /*\r
-        * Convert COMPOUND_TEXT into UTF-8.\r
-        */\r
-       if (seldata->type == compound_text_atom) {\r
-           tp.value = seldata->data;\r
-           tp.encoding = (Atom) seldata->type;\r
-           tp.format = seldata->format;\r
-           tp.nitems = seldata->length;\r
-           ret = Xutf8TextPropertyToTextList(GDK_DISPLAY(), &tp,\r
-                                             &list, &count);\r
-           if (ret != 0 || count != 1) {\r
-               /*\r
-                * Compound text failed; fall back to STRING.\r
-                */\r
-               gtk_selection_convert(inst->area, GDK_SELECTION_PRIMARY,\r
-                                     GDK_SELECTION_TYPE_STRING,\r
-                                     inst->input_event_time);\r
-               return;\r
-           }\r
-           text = list[0];\r
-           length = strlen(list[0]);\r
-           charset = CS_UTF8;\r
-           free_list_required = 1;\r
-       } else {\r
-           text = (char *)seldata->data;\r
-           length = seldata->length;\r
-           charset = (seldata->type == utf8_string_atom ?\r
-                      CS_UTF8 : inst->ucsdata.line_codepage);\r
-       }\r
-    }\r
-\r
-    if (inst->pastein_data)\r
-       sfree(inst->pastein_data);\r
-\r
-    inst->pastein_data = snewn(length, wchar_t);\r
-    inst->pastein_data_len = length;\r
-    inst->pastein_data_len =\r
-       mb_to_wc(charset, 0, text, length,\r
-                inst->pastein_data, inst->pastein_data_len);\r
-\r
-    term_do_paste(inst->term);\r
-\r
-    if (term_paste_pending(inst->term))\r
-       inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);\r
-\r
-    if (free_list_required)\r
-       XFreeStringList(list);\r
-    if (free_required)\r
-       XFree(text);\r
-}\r
-\r
-gint idle_paste_func(gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-\r
-    if (term_paste_pending(inst->term))\r
-       term_paste(inst->term);\r
-    else\r
-       gtk_idle_remove(inst->term_paste_idle_id);\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-void get_clip(void *frontend, wchar_t ** p, int *len)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-\r
-    if (p) {\r
-       *p = inst->pastein_data;\r
-       *len = inst->pastein_data_len;\r
-    }\r
-}\r
-\r
-static void set_window_titles(struct gui_data *inst)\r
-{\r
-    /*\r
-     * We must always call set_icon_name after calling set_title,\r
-     * since set_title will write both names. Irritating, but such\r
-     * is life.\r
-     */\r
-    gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle);\r
-    if (!inst->cfg.win_name_always)\r
-       gdk_window_set_icon_name(inst->window->window, inst->icontitle);\r
-}\r
-\r
-void set_title(void *frontend, char *title)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    strncpy(inst->wintitle, title, lenof(inst->wintitle));\r
-    inst->wintitle[lenof(inst->wintitle)-1] = '\0';\r
-    set_window_titles(inst);\r
-}\r
-\r
-void set_icon(void *frontend, char *title)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    strncpy(inst->icontitle, title, lenof(inst->icontitle));\r
-    inst->icontitle[lenof(inst->icontitle)-1] = '\0';\r
-    set_window_titles(inst);\r
-}\r
-\r
-void set_sbar(void *frontend, int total, int start, int page)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    if (!inst->cfg.scrollbar)\r
-       return;\r
-    inst->sbar_adjust->lower = 0;\r
-    inst->sbar_adjust->upper = total;\r
-    inst->sbar_adjust->value = start;\r
-    inst->sbar_adjust->page_size = page;\r
-    inst->sbar_adjust->step_increment = 1;\r
-    inst->sbar_adjust->page_increment = page/2;\r
-    inst->ignore_sbar = TRUE;\r
-    gtk_adjustment_changed(inst->sbar_adjust);\r
-    inst->ignore_sbar = FALSE;\r
-}\r
-\r
-void scrollbar_moved(GtkAdjustment *adj, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-\r
-    if (!inst->cfg.scrollbar)\r
-       return;\r
-    if (!inst->ignore_sbar)\r
-       term_scroll(inst->term, 1, (int)adj->value);\r
-}\r
-\r
-void sys_cursor(void *frontend, int x, int y)\r
-{\r
-    /*\r
-     * This is meaningless under X.\r
-     */\r
-}\r
-\r
-/*\r
- * This is still called when mode==BELL_VISUAL, even though the\r
- * visual bell is handled entirely within terminal.c, because we\r
- * may want to perform additional actions on any kind of bell (for\r
- * example, taskbar flashing in Windows).\r
- */\r
-void do_beep(void *frontend, int mode)\r
-{\r
-    if (mode == BELL_DEFAULT)\r
-       gdk_beep();\r
-}\r
-\r
-int char_width(Context ctx, int uc)\r
-{\r
-    /*\r
-     * Under X, any fixed-width font really _is_ fixed-width.\r
-     * Double-width characters will be dealt with using a separate\r
-     * font. For the moment we can simply return 1.\r
-     * \r
-     * FIXME: but is that also true of Pango?\r
-     */\r
-    return 1;\r
-}\r
-\r
-Context get_ctx(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    struct draw_ctx *dctx;\r
-\r
-    if (!inst->area->window)\r
-       return NULL;\r
-\r
-    dctx = snew(struct draw_ctx);\r
-    dctx->inst = inst;\r
-    dctx->gc = gdk_gc_new(inst->area->window);\r
-    return dctx;\r
-}\r
-\r
-void free_ctx(Context ctx)\r
-{\r
-    struct draw_ctx *dctx = (struct draw_ctx *)ctx;\r
-    /* struct gui_data *inst = dctx->inst; */\r
-    GdkGC *gc = dctx->gc;\r
-    gdk_gc_unref(gc);\r
-    sfree(dctx);\r
-}\r
-\r
-/*\r
- * Draw a line of text in the window, at given character\r
- * coordinates, in given attributes.\r
- *\r
- * We are allowed to fiddle with the contents of `text'.\r
- */\r
-void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,\r
-                     unsigned long attr, int lattr)\r
-{\r
-    struct draw_ctx *dctx = (struct draw_ctx *)ctx;\r
-    struct gui_data *inst = dctx->inst;\r
-    GdkGC *gc = dctx->gc;\r
-    int ncombining, combining;\r
-    int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold;\r
-    int monochrome = gtk_widget_get_visual(inst->area)->depth == 1;\r
-\r
-    if (attr & TATTR_COMBINING) {\r
-       ncombining = len;\r
-       len = 1;\r
-    } else\r
-       ncombining = 1;\r
-\r
-    nfg = ((monochrome ? ATTR_DEFFG : (attr & ATTR_FGMASK)) >> ATTR_FGSHIFT);\r
-    nbg = ((monochrome ? ATTR_DEFBG : (attr & ATTR_BGMASK)) >> ATTR_BGSHIFT);\r
-    if (!!(attr & ATTR_REVERSE) ^ (monochrome && (attr & TATTR_ACTCURS))) {\r
-       t = nfg;\r
-       nfg = nbg;\r
-       nbg = t;\r
-    }\r
-    if (inst->cfg.bold_colour && (attr & ATTR_BOLD)) {\r
-       if (nfg < 16) nfg |= 8;\r
-       else if (nfg >= 256) nfg |= 1;\r
-    }\r
-    if (inst->cfg.bold_colour && (attr & ATTR_BLINK)) {\r
-       if (nbg < 16) nbg |= 8;\r
-       else if (nbg >= 256) nbg |= 1;\r
-    }\r
-    if ((attr & TATTR_ACTCURS) && !monochrome) {\r
-       nfg = 260;\r
-       nbg = 261;\r
-    }\r
-\r
-    fontid = shadow = 0;\r
-\r
-    if (attr & ATTR_WIDE) {\r
-       widefactor = 2;\r
-       fontid |= 2;\r
-    } else {\r
-       widefactor = 1;\r
-    }\r
-\r
-    if ((attr & ATTR_BOLD) && !inst->cfg.bold_colour) {\r
-       bold = 1;\r
-       fontid |= 1;\r
-    } else {\r
-       bold = 0;\r
-    }\r
-\r
-    if (!inst->fonts[fontid]) {\r
-       int i;\r
-       /*\r
-        * Fall back through font ids with subsets of this one's\r
-        * set bits, in order.\r
-        */\r
-       for (i = fontid; i-- > 0 ;) {\r
-           if (i & ~fontid)\r
-               continue;              /* some other bit is set */\r
-           if (inst->fonts[i]) {\r
-               fontid = i;\r
-               break;\r
-           }\r
-       }\r
-       assert(inst->fonts[fontid]);   /* we should at least have hit zero */\r
-    }\r
-\r
-    if ((lattr & LATTR_MODE) != LATTR_NORM) {\r
-       x *= 2;\r
-       if (x >= inst->term->cols)\r
-           return;\r
-       if (x + len*2*widefactor > inst->term->cols)\r
-           len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */\r
-       rlen = len * 2;\r
-    } else\r
-       rlen = len;\r
-\r
-    {\r
-       GdkRectangle r;\r
-\r
-       r.x = x*inst->font_width+inst->cfg.window_border;\r
-       r.y = y*inst->font_height+inst->cfg.window_border;\r
-       r.width = rlen*widefactor*inst->font_width;\r
-       r.height = inst->font_height;\r
-       gdk_gc_set_clip_rectangle(gc, &r);\r
-    }\r
-\r
-    gdk_gc_set_foreground(gc, &inst->cols[nbg]);\r
-    gdk_draw_rectangle(inst->pixmap, gc, 1,\r
-                      x*inst->font_width+inst->cfg.window_border,\r
-                      y*inst->font_height+inst->cfg.window_border,\r
-                      rlen*widefactor*inst->font_width, inst->font_height);\r
-\r
-    gdk_gc_set_foreground(gc, &inst->cols[nfg]);\r
-    {\r
-       gchar *gcs;\r
-\r
-       /*\r
-        * FIXME: this length is hardwired on the assumption that\r
-        * conversions from wide to multibyte characters will\r
-        * never generate more than 10 bytes for a single wide\r
-        * character.\r
-        */\r
-       gcs = snewn(len*10+1, gchar);\r
-\r
-       for (combining = 0; combining < ncombining; combining++) {\r
-           int mblen = wc_to_mb(inst->fonts[fontid]->real_charset, 0,\r
-                                text + combining, len, gcs, len*10+1, ".",\r
-                                NULL, NULL);\r
-           unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid],\r
-                             x*inst->font_width+inst->cfg.window_border,\r
-                             y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,\r
-                             gcs, mblen, widefactor > 1, bold, inst->font_width);\r
-       }\r
-\r
-       sfree(gcs);\r
-    }\r
-\r
-    if (attr & ATTR_UNDER) {\r
-       int uheight = inst->fonts[0]->ascent + 1;\r
-       if (uheight >= inst->font_height)\r
-           uheight = inst->font_height - 1;\r
-       gdk_draw_line(inst->pixmap, gc, x*inst->font_width+inst->cfg.window_border,\r
-                     y*inst->font_height + uheight + inst->cfg.window_border,\r
-                     (x+len)*widefactor*inst->font_width-1+inst->cfg.window_border,\r
-                     y*inst->font_height + uheight + inst->cfg.window_border);\r
-    }\r
-\r
-    if ((lattr & LATTR_MODE) != LATTR_NORM) {\r
-       /*\r
-        * I can't find any plausible StretchBlt equivalent in the\r
-        * X server, so I'm going to do this the slow and painful\r
-        * way. This will involve repeated calls to\r
-        * gdk_draw_pixmap() to stretch the text horizontally. It's\r
-        * O(N^2) in time and O(N) in network bandwidth, but you\r
-        * try thinking of a better way. :-(\r
-        */\r
-       int i;\r
-       for (i = 0; i < len * widefactor * inst->font_width; i++) {\r
-           gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap,\r
-                           x*inst->font_width+inst->cfg.window_border + 2*i,\r
-                           y*inst->font_height+inst->cfg.window_border,\r
-                           x*inst->font_width+inst->cfg.window_border + 2*i+1,\r
-                           y*inst->font_height+inst->cfg.window_border,\r
-                           len * widefactor * inst->font_width - i, inst->font_height);\r
-       }\r
-       len *= 2;\r
-       if ((lattr & LATTR_MODE) != LATTR_WIDE) {\r
-           int dt, db;\r
-           /* Now stretch vertically, in the same way. */\r
-           if ((lattr & LATTR_MODE) == LATTR_BOT)\r
-               dt = 0, db = 1;\r
-           else\r
-               dt = 1, db = 0;\r
-           for (i = 0; i < inst->font_height; i+=2) {\r
-               gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap,\r
-                               x*inst->font_width+inst->cfg.window_border,\r
-                               y*inst->font_height+inst->cfg.window_border+dt*i+db,\r
-                               x*inst->font_width+inst->cfg.window_border,\r
-                               y*inst->font_height+inst->cfg.window_border+dt*(i+1),\r
-                               len * widefactor * inst->font_width, inst->font_height-i-1);\r
-           }\r
-       }\r
-    }\r
-}\r
-\r
-void do_text(Context ctx, int x, int y, wchar_t *text, int len,\r
-            unsigned long attr, int lattr)\r
-{\r
-    struct draw_ctx *dctx = (struct draw_ctx *)ctx;\r
-    struct gui_data *inst = dctx->inst;\r
-    GdkGC *gc = dctx->gc;\r
-    int widefactor;\r
-\r
-    do_text_internal(ctx, x, y, text, len, attr, lattr);\r
-\r
-    if (attr & ATTR_WIDE) {\r
-       widefactor = 2;\r
-    } else {\r
-       widefactor = 1;\r
-    }\r
-\r
-    if ((lattr & LATTR_MODE) != LATTR_NORM) {\r
-       x *= 2;\r
-       if (x >= inst->term->cols)\r
-           return;\r
-       if (x + len*2*widefactor > inst->term->cols)\r
-           len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */\r
-       len *= 2;\r
-    }\r
-\r
-    gdk_draw_pixmap(inst->area->window, gc, inst->pixmap,\r
-                   x*inst->font_width+inst->cfg.window_border,\r
-                   y*inst->font_height+inst->cfg.window_border,\r
-                   x*inst->font_width+inst->cfg.window_border,\r
-                   y*inst->font_height+inst->cfg.window_border,\r
-                   len*widefactor*inst->font_width, inst->font_height);\r
-}\r
-\r
-void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,\r
-              unsigned long attr, int lattr)\r
-{\r
-    struct draw_ctx *dctx = (struct draw_ctx *)ctx;\r
-    struct gui_data *inst = dctx->inst;\r
-    GdkGC *gc = dctx->gc;\r
-\r
-    int active, passive, widefactor;\r
-\r
-    if (attr & TATTR_PASCURS) {\r
-       attr &= ~TATTR_PASCURS;\r
-       passive = 1;\r
-    } else\r
-       passive = 0;\r
-    if ((attr & TATTR_ACTCURS) && inst->cfg.cursor_type != 0) {\r
-       attr &= ~TATTR_ACTCURS;\r
-        active = 1;\r
-    } else\r
-        active = 0;\r
-    do_text_internal(ctx, x, y, text, len, attr, lattr);\r
-\r
-    if (attr & TATTR_COMBINING)\r
-       len = 1;\r
-\r
-    if (attr & ATTR_WIDE) {\r
-       widefactor = 2;\r
-    } else {\r
-       widefactor = 1;\r
-    }\r
-\r
-    if ((lattr & LATTR_MODE) != LATTR_NORM) {\r
-       x *= 2;\r
-       if (x >= inst->term->cols)\r
-           return;\r
-       if (x + len*2*widefactor > inst->term->cols)\r
-           len = (inst->term->cols-x)/2/widefactor;/* trim to LH half */\r
-       len *= 2;\r
-    }\r
-\r
-    if (inst->cfg.cursor_type == 0) {\r
-       /*\r
-        * An active block cursor will already have been done by\r
-        * the above do_text call, so we only need to do anything\r
-        * if it's passive.\r
-        */\r
-       if (passive) {\r
-           gdk_gc_set_foreground(gc, &inst->cols[261]);\r
-           gdk_draw_rectangle(inst->pixmap, gc, 0,\r
-                              x*inst->font_width+inst->cfg.window_border,\r
-                              y*inst->font_height+inst->cfg.window_border,\r
-                              len*widefactor*inst->font_width-1, inst->font_height-1);\r
-       }\r
-    } else {\r
-       int uheight;\r
-       int startx, starty, dx, dy, length, i;\r
-\r
-       int char_width;\r
-\r
-       if ((attr & ATTR_WIDE) || (lattr & LATTR_MODE) != LATTR_NORM)\r
-           char_width = 2*inst->font_width;\r
-       else\r
-           char_width = inst->font_width;\r
-\r
-       if (inst->cfg.cursor_type == 1) {\r
-           uheight = inst->fonts[0]->ascent + 1;\r
-           if (uheight >= inst->font_height)\r
-               uheight = inst->font_height - 1;\r
-\r
-           startx = x * inst->font_width + inst->cfg.window_border;\r
-           starty = y * inst->font_height + inst->cfg.window_border + uheight;\r
-           dx = 1;\r
-           dy = 0;\r
-           length = len * widefactor * char_width;\r
-       } else {\r
-           int xadjust = 0;\r
-           if (attr & TATTR_RIGHTCURS)\r
-               xadjust = char_width - 1;\r
-           startx = x * inst->font_width + inst->cfg.window_border + xadjust;\r
-           starty = y * inst->font_height + inst->cfg.window_border;\r
-           dx = 0;\r
-           dy = 1;\r
-           length = inst->font_height;\r
-       }\r
-\r
-       gdk_gc_set_foreground(gc, &inst->cols[261]);\r
-       if (passive) {\r
-           for (i = 0; i < length; i++) {\r
-               if (i % 2 == 0) {\r
-                   gdk_draw_point(inst->pixmap, gc, startx, starty);\r
-               }\r
-               startx += dx;\r
-               starty += dy;\r
-           }\r
-       } else if (active) {\r
-           gdk_draw_line(inst->pixmap, gc, startx, starty,\r
-                         startx + (length-1) * dx, starty + (length-1) * dy);\r
-       } /* else no cursor (e.g., blinked off) */\r
-    }\r
-\r
-    gdk_draw_pixmap(inst->area->window, gc, inst->pixmap,\r
-                   x*inst->font_width+inst->cfg.window_border,\r
-                   y*inst->font_height+inst->cfg.window_border,\r
-                   x*inst->font_width+inst->cfg.window_border,\r
-                   y*inst->font_height+inst->cfg.window_border,\r
-                   len*widefactor*inst->font_width, inst->font_height);\r
-}\r
-\r
-GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val)\r
-{\r
-    /*\r
-     * Truly hideous hack: GTK doesn't allow us to set the mouse\r
-     * cursor foreground and background colours unless we've _also_\r
-     * created our own cursor from bitmaps. Therefore, I need to\r
-     * load the `cursor' font and draw glyphs from it on to\r
-     * pixmaps, in order to construct my cursors with the fg and bg\r
-     * I want. This is a gross hack, but it's more self-contained\r
-     * than linking in Xlib to find the X window handle to\r
-     * inst->area and calling XRecolorCursor, and it's more\r
-     * futureproof than hard-coding the shapes as bitmap arrays.\r
-     */\r
-    static GdkFont *cursor_font = NULL;\r
-    GdkPixmap *source, *mask;\r
-    GdkGC *gc;\r
-    GdkColor cfg = { 0, 65535, 65535, 65535 };\r
-    GdkColor cbg = { 0, 0, 0, 0 };\r
-    GdkColor dfg = { 1, 65535, 65535, 65535 };\r
-    GdkColor dbg = { 0, 0, 0, 0 };\r
-    GdkCursor *ret;\r
-    gchar text[2];\r
-    gint lb, rb, wid, asc, desc, w, h, x, y;\r
-\r
-    if (cursor_val == -2) {\r
-       gdk_font_unref(cursor_font);\r
-       return NULL;\r
-    }\r
-\r
-    if (cursor_val >= 0 && !cursor_font) {\r
-       cursor_font = gdk_font_load("cursor");\r
-       if (cursor_font)\r
-           gdk_font_ref(cursor_font);\r
-    }\r
-\r
-    /*\r
-     * Get the text extent of the cursor in question. We use the\r
-     * mask character for this, because it's typically slightly\r
-     * bigger than the main character.\r
-     */\r
-    if (cursor_val >= 0) {\r
-       text[1] = '\0';\r
-       text[0] = (char)cursor_val + 1;\r
-       gdk_string_extents(cursor_font, text, &lb, &rb, &wid, &asc, &desc);\r
-       w = rb-lb; h = asc+desc; x = -lb; y = asc;\r
-    } else {\r
-       w = h = 1;\r
-       x = y = 0;\r
-    }\r
-\r
-    source = gdk_pixmap_new(NULL, w, h, 1);\r
-    mask = gdk_pixmap_new(NULL, w, h, 1);\r
-\r
-    /*\r
-     * Draw the mask character on the mask pixmap.\r
-     */\r
-    gc = gdk_gc_new(mask);\r
-    gdk_gc_set_foreground(gc, &dbg);\r
-    gdk_draw_rectangle(mask, gc, 1, 0, 0, w, h);\r
-    if (cursor_val >= 0) {\r
-       text[1] = '\0';\r
-       text[0] = (char)cursor_val + 1;\r
-       gdk_gc_set_foreground(gc, &dfg);\r
-       gdk_draw_text(mask, cursor_font, gc, x, y, text, 1);\r
-    }\r
-    gdk_gc_unref(gc);\r
-\r
-    /*\r
-     * Draw the main character on the source pixmap.\r
-     */\r
-    gc = gdk_gc_new(source);\r
-    gdk_gc_set_foreground(gc, &dbg);\r
-    gdk_draw_rectangle(source, gc, 1, 0, 0, w, h);\r
-    if (cursor_val >= 0) {\r
-       text[1] = '\0';\r
-       text[0] = (char)cursor_val;\r
-       gdk_gc_set_foreground(gc, &dfg);\r
-       gdk_draw_text(source, cursor_font, gc, x, y, text, 1);\r
-    }\r
-    gdk_gc_unref(gc);\r
-\r
-    /*\r
-     * Create the cursor.\r
-     */\r
-    ret = gdk_cursor_new_from_pixmap(source, mask, &cfg, &cbg, x, y);\r
-\r
-    /*\r
-     * Clean up.\r
-     */\r
-    gdk_pixmap_unref(source);\r
-    gdk_pixmap_unref(mask);\r
-\r
-    return ret;\r
-}\r
-\r
-void modalfatalbox(char *p, ...)\r
-{\r
-    va_list ap;\r
-    fprintf(stderr, "FATAL ERROR: ");\r
-    va_start(ap, p);\r
-    vfprintf(stderr, p, ap);\r
-    va_end(ap);\r
-    fputc('\n', stderr);\r
-    exit(1);\r
-}\r
-\r
-void cmdline_error(char *p, ...)\r
-{\r
-    va_list ap;\r
-    fprintf(stderr, "%s: ", appname);\r
-    va_start(ap, p);\r
-    vfprintf(stderr, p, ap);\r
-    va_end(ap);\r
-    fputc('\n', stderr);\r
-    exit(1);\r
-}\r
-\r
-char *get_x_display(void *frontend)\r
-{\r
-    return gdk_get_display();\r
-}\r
-\r
-long get_windowid(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-    return (long)GDK_WINDOW_XWINDOW(inst->area->window);\r
-}\r
-\r
-static void help(FILE *fp) {\r
-    if(fprintf(fp,\r
-"pterm option summary:\n"\r
-"\n"\r
-"  --display DISPLAY         Specify X display to use (note '--')\n"\r
-"  -name PREFIX              Prefix when looking up resources (default: pterm)\n"\r
-"  -fn FONT                  Normal text font\n"\r
-"  -fb FONT                  Bold text font\n"\r
-"  -geometry GEOMETRY        Position and size of window (size in characters)\n"\r
-"  -sl LINES                 Number of lines of scrollback\n"\r
-"  -fg COLOUR, -bg COLOUR    Foreground/background colour\n"\r
-"  -bfg COLOUR, -bbg COLOUR  Foreground/background bold colour\n"\r
-"  -cfg COLOUR, -bfg COLOUR  Foreground/background cursor colour\n"\r
-"  -T TITLE                  Window title\n"\r
-"  -ut, +ut                  Do(default) or do not update utmp\n"\r
-"  -ls, +ls                  Do(default) or do not make shell a login shell\n"\r
-"  -sb, +sb                  Do(default) or do not display a scrollbar\n"\r
-"  -log PATH                 Log all output to a file\n"\r
-"  -nethack                  Map numeric keypad to hjklyubn direction keys\n"\r
-"  -xrm RESOURCE-STRING      Set an X resource\n"\r
-"  -e COMMAND [ARGS...]      Execute command (consumes all remaining args)\n"\r
-        ) < 0 || fflush(fp) < 0) {\r
-       perror("output error");\r
-       exit(1);\r
-    }\r
-}\r
-\r
-int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,\r
-               struct gui_data *inst, Config *cfg)\r
-{\r
-    int err = 0;\r
-    char *val;\r
-\r
-    /*\r
-     * Macros to make argument handling easier. Note that because\r
-     * they need to call `continue', they cannot be contained in\r
-     * the usual do {...} while (0) wrapper to make them\r
-     * syntactically single statements; hence it is not legal to\r
-     * use one of these macros as an unbraced statement between\r
-     * `if' and `else'.\r
-     */\r
-#define EXPECTS_ARG { \\r
-    if (--argc <= 0) { \\r
-       err = 1; \\r
-       fprintf(stderr, "%s: %s expects an argument\n", appname, p); \\r
-        continue; \\r
-    } else \\r
-       val = *++argv; \\r
-}\r
-#define SECOND_PASS_ONLY { if (!do_everything) continue; }\r
-\r
-    while (--argc > 0) {\r
-       char *p = *++argv;\r
-        int ret;\r
-\r
-       /*\r
-        * Shameless cheating. Debian requires all X terminal\r
-        * emulators to support `-T title'; but\r
-        * cmdline_process_param will eat -T (it means no-pty) and\r
-        * complain that pterm doesn't support it. So, in pterm\r
-        * only, we convert -T into -title.\r
-        */\r
-       if ((cmdline_tooltype & TOOLTYPE_NONNETWORK) &&\r
-           !strcmp(p, "-T"))\r
-           p = "-title";\r
-\r
-        ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL),\r
-                                    do_everything ? 1 : -1, cfg);\r
-\r
-       if (ret == -2) {\r
-           cmdline_error("option \"%s\" requires an argument", p);\r
-       } else if (ret == 2) {\r
-           --argc, ++argv;            /* skip next argument */\r
-            continue;\r
-       } else if (ret == 1) {\r
-            continue;\r
-        }\r
-\r
-       if (!strcmp(p, "-fn") || !strcmp(p, "-font")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->font.name, val, sizeof(cfg->font.name));\r
-           cfg->font.name[sizeof(cfg->font.name)-1] = '\0';\r
-\r
-       } else if (!strcmp(p, "-fb")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->boldfont.name, val, sizeof(cfg->boldfont.name));\r
-           cfg->boldfont.name[sizeof(cfg->boldfont.name)-1] = '\0';\r
-\r
-       } else if (!strcmp(p, "-fw")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->widefont.name, val, sizeof(cfg->widefont.name));\r
-           cfg->widefont.name[sizeof(cfg->widefont.name)-1] = '\0';\r
-\r
-       } else if (!strcmp(p, "-fwb")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->wideboldfont.name, val, sizeof(cfg->wideboldfont.name));\r
-           cfg->wideboldfont.name[sizeof(cfg->wideboldfont.name)-1] = '\0';\r
-\r
-       } else if (!strcmp(p, "-cs")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->line_codepage, val, sizeof(cfg->line_codepage));\r
-           cfg->line_codepage[sizeof(cfg->line_codepage)-1] = '\0';\r
-\r
-       } else if (!strcmp(p, "-geometry")) {\r
-           int flags, x, y;\r
-           unsigned int w, h;\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-\r
-           flags = XParseGeometry(val, &x, &y, &w, &h);\r
-           if (flags & WidthValue)\r
-               cfg->width = (int)w;\r
-           if (flags & HeightValue)\r
-               cfg->height = (int)h;\r
-\r
-            if (flags & (XValue | YValue)) {\r
-                inst->xpos = x;\r
-                inst->ypos = y;\r
-                inst->gotpos = TRUE;\r
-                inst->gravity = ((flags & XNegative ? 1 : 0) |\r
-                                 (flags & YNegative ? 2 : 0));\r
-            }\r
-\r
-       } else if (!strcmp(p, "-sl")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           cfg->savelines = atoi(val);\r
-\r
-       } else if (!strcmp(p, "-fg") || !strcmp(p, "-bg") ||\r
-                  !strcmp(p, "-bfg") || !strcmp(p, "-bbg") ||\r
-                  !strcmp(p, "-cfg") || !strcmp(p, "-cbg")) {\r
-           GdkColor col;\r
-\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           if (!gdk_color_parse(val, &col)) {\r
-               err = 1;\r
-               fprintf(stderr, "%s: unable to parse colour \"%s\"\n",\r
-                        appname, val);\r
-           } else {\r
-               int index;\r
-               index = (!strcmp(p, "-fg") ? 0 :\r
-                        !strcmp(p, "-bg") ? 2 :\r
-                        !strcmp(p, "-bfg") ? 1 :\r
-                        !strcmp(p, "-bbg") ? 3 :\r
-                        !strcmp(p, "-cfg") ? 4 :\r
-                        !strcmp(p, "-cbg") ? 5 : -1);\r
-               assert(index != -1);\r
-               cfg->colours[index][0] = col.red / 256;\r
-               cfg->colours[index][1] = col.green / 256;\r
-               cfg->colours[index][2] = col.blue / 256;\r
-           }\r
-\r
-       } else if (use_pty_argv && !strcmp(p, "-e")) {\r
-           /* This option swallows all further arguments. */\r
-           if (!do_everything)\r
-               break;\r
-\r
-           if (--argc > 0) {\r
-               int i;\r
-               pty_argv = snewn(argc+1, char *);\r
-               ++argv;\r
-               for (i = 0; i < argc; i++)\r
-                   pty_argv[i] = argv[i];\r
-               pty_argv[argc] = NULL;\r
-               break;                 /* finished command-line processing */\r
-           } else\r
-               err = 1, fprintf(stderr, "%s: -e expects an argument\n",\r
-                                 appname);\r
-\r
-       } else if (!strcmp(p, "-title")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->wintitle, val, sizeof(cfg->wintitle));\r
-           cfg->wintitle[sizeof(cfg->wintitle)-1] = '\0';\r
-\r
-       } else if (!strcmp(p, "-log")) {\r
-           EXPECTS_ARG;\r
-           SECOND_PASS_ONLY;\r
-           strncpy(cfg->logfilename.path, val, sizeof(cfg->logfilename.path));\r
-           cfg->logfilename.path[sizeof(cfg->logfilename.path)-1] = '\0';\r
-           cfg->logtype = LGTYP_DEBUG;\r
-\r
-       } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->stamp_utmp = 0;\r
-\r
-       } else if (!strcmp(p, "-ut")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->stamp_utmp = 1;\r
-\r
-       } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->login_shell = 0;\r
-\r
-       } else if (!strcmp(p, "-ls")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->login_shell = 1;\r
-\r
-       } else if (!strcmp(p, "-nethack")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->nethack_keypad = 1;\r
-\r
-       } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->scrollbar = 0;\r
-\r
-       } else if (!strcmp(p, "-sb")) {\r
-           SECOND_PASS_ONLY;\r
-           cfg->scrollbar = 0;\r
-\r
-       } else if (!strcmp(p, "-name")) {\r
-           EXPECTS_ARG;\r
-           app_name = val;\r
-\r
-       } else if (!strcmp(p, "-xrm")) {\r
-           EXPECTS_ARG;\r
-           provide_xrm_string(val);\r
-\r
-       } else if(!strcmp(p, "-help") || !strcmp(p, "--help")) {\r
-           help(stdout);\r
-           exit(0);\r
-\r
-        } else if (!strcmp(p, "-pgpfp")) {\r
-            pgp_fingerprints();\r
-            exit(1);\r
-\r
-       } else if(p[0] != '-' && (!do_everything ||\r
-                                  process_nonoption_arg(p, cfg,\r
-                                                       allow_launch))) {\r
-            /* do nothing */\r
-\r
-       } else {\r
-           err = 1;\r
-           fprintf(stderr, "%s: unrecognized option '%s'\n", appname, p);\r
-       }\r
-    }\r
-\r
-    return err;\r
-}\r
-\r
-int uxsel_input_add(int fd, int rwx) {\r
-    int flags = 0;\r
-    if (rwx & 1) flags |= GDK_INPUT_READ;\r
-    if (rwx & 2) flags |= GDK_INPUT_WRITE;\r
-    if (rwx & 4) flags |= GDK_INPUT_EXCEPTION;\r
-    assert(flags);\r
-    return gdk_input_add(fd, flags, fd_input_func, NULL);\r
-}\r
-\r
-void uxsel_input_remove(int id) {\r
-    gdk_input_remove(id);\r
-}\r
-\r
-void setup_fonts_ucs(struct gui_data *inst)\r
-{\r
-    if (inst->fonts[0])\r
-        unifont_destroy(inst->fonts[0]);\r
-    if (inst->fonts[1])\r
-        unifont_destroy(inst->fonts[1]);\r
-    if (inst->fonts[2])\r
-        unifont_destroy(inst->fonts[2]);\r
-    if (inst->fonts[3])\r
-        unifont_destroy(inst->fonts[3]);\r
-\r
-    inst->fonts[0] = unifont_create(inst->area, inst->cfg.font.name,\r
-                                   FALSE, FALSE,\r
-                                   inst->cfg.shadowboldoffset,\r
-                                   inst->cfg.shadowbold);\r
-    if (!inst->fonts[0]) {\r
-       fprintf(stderr, "%s: unable to load font \"%s\"\n", appname,\r
-               inst->cfg.font.name);\r
-       exit(1);\r
-    }\r
-\r
-    if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) {\r
-       inst->fonts[1] = NULL;\r
-    } else {\r
-       inst->fonts[1] = unifont_create(inst->area, inst->cfg.boldfont.name,\r
-                                       FALSE, TRUE,\r
-                                       inst->cfg.shadowboldoffset,\r
-                                       inst->cfg.shadowbold);\r
-       if (!inst->fonts[1]) {\r
-           fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname,\r
-                   inst->cfg.boldfont.name);\r
-           exit(1);\r
-       }\r
-    }\r
-\r
-    if (inst->cfg.widefont.name[0]) {\r
-       inst->fonts[2] = unifont_create(inst->area, inst->cfg.widefont.name,\r
-                                       TRUE, FALSE,\r
-                                       inst->cfg.shadowboldoffset,\r
-                                       inst->cfg.shadowbold);\r
-       if (!inst->fonts[2]) {\r
-           fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname,\r
-                   inst->cfg.widefont.name);\r
-           exit(1);\r
-       }\r
-    } else {\r
-       inst->fonts[2] = NULL;\r
-    }\r
-\r
-    if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) {\r
-       inst->fonts[3] = NULL;\r
-    } else {\r
-       inst->fonts[3] = unifont_create(inst->area,\r
-                                       inst->cfg.wideboldfont.name, TRUE,\r
-                                       TRUE, inst->cfg.shadowboldoffset,\r
-                                       inst->cfg.shadowbold);\r
-       if (!inst->fonts[3]) {\r
-           fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname,\r
-                   inst->cfg.boldfont.name);\r
-           exit(1);\r
-       }\r
-    }\r
-\r
-    inst->font_width = inst->fonts[0]->width;\r
-    inst->font_height = inst->fonts[0]->height;\r
-\r
-    inst->direct_to_font = init_ucs(&inst->ucsdata, inst->cfg.line_codepage,\r
-                                   inst->cfg.utf8_override,\r
-                                   inst->fonts[0]->public_charset,\r
-                                   inst->cfg.vtmode);\r
-}\r
-\r
-void set_geom_hints(struct gui_data *inst)\r
-{\r
-    GdkGeometry geom;\r
-    geom.min_width = inst->font_width + 2*inst->cfg.window_border;\r
-    geom.min_height = inst->font_height + 2*inst->cfg.window_border;\r
-    geom.max_width = geom.max_height = -1;\r
-    geom.base_width = 2*inst->cfg.window_border;\r
-    geom.base_height = 2*inst->cfg.window_border;\r
-    geom.width_inc = inst->font_width;\r
-    geom.height_inc = inst->font_height;\r
-    geom.min_aspect = geom.max_aspect = 0;\r
-    gtk_window_set_geometry_hints(GTK_WINDOW(inst->window), inst->area, &geom,\r
-                                  GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE |\r
-                                  GDK_HINT_RESIZE_INC);\r
-}\r
-\r
-void clear_scrollback_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    term_clrsb(inst->term);\r
-}\r
-\r
-void reset_terminal_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    term_pwron(inst->term, TRUE);\r
-    if (inst->ldisc)\r
-       ldisc_send(inst->ldisc, NULL, 0, 0);\r
-}\r
-\r
-void copy_all_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    term_copyall(inst->term);\r
-}\r
-\r
-void special_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    int code = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(item),\r
-                                                  "user-data"));\r
-\r
-    if (inst->back)\r
-       inst->back->special(inst->backhandle, code);\r
-}\r
-\r
-void about_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    about_box(inst->window);\r
-}\r
-\r
-void event_log_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    showeventlog(inst->eventlogstuff, inst->window);\r
-}\r
-\r
-void change_settings_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    /* This maps colour indices in inst->cfg to those used in inst->cols. */\r
-    static const int ww[] = {\r
-       256, 257, 258, 259, 260, 261,\r
-       0, 8, 1, 9, 2, 10, 3, 11,\r
-       4, 12, 5, 13, 6, 14, 7, 15\r
-    };\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    char *title = dupcat(appname, " Reconfiguration", NULL);\r
-    Config cfg2, oldcfg;\r
-    int i, need_size;\r
-\r
-    assert(lenof(ww) == NCFGCOLOURS);\r
-\r
-    if (inst->reconfiguring)\r
-      return;\r
-    else\r
-      inst->reconfiguring = TRUE;\r
-\r
-    cfg2 = inst->cfg;                  /* structure copy */\r
-\r
-    if (do_config_box(title, &cfg2, 1,\r
-                     inst->back?inst->back->cfg_info(inst->backhandle):0)) {\r
-\r
-        oldcfg = inst->cfg;            /* structure copy */\r
-        inst->cfg = cfg2;              /* structure copy */\r
-\r
-        /* Pass new config data to the logging module */\r
-        log_reconfig(inst->logctx, &cfg2);\r
-        /*\r
-         * Flush the line discipline's edit buffer in the case\r
-         * where local editing has just been disabled.\r
-         */\r
-        if (inst->ldisc)\r
-           ldisc_send(inst->ldisc, NULL, 0, 0);\r
-        /* Pass new config data to the terminal */\r
-        term_reconfig(inst->term, &cfg2);\r
-        /* Pass new config data to the back end */\r
-        if (inst->back)\r
-           inst->back->reconfig(inst->backhandle, &cfg2);\r
-\r
-        /*\r
-         * Just setting inst->cfg is sufficient to cause colour\r
-         * setting changes to appear on the next ESC]R palette\r
-         * reset. But we should also check whether any colour\r
-         * settings have been changed, and revert the ones that\r
-         * have to the new default, on the assumption that the user\r
-         * is most likely to want an immediate update.\r
-         */\r
-        for (i = 0; i < NCFGCOLOURS; i++) {\r
-            if (oldcfg.colours[i][0] != cfg2.colours[i][0] ||\r
-                oldcfg.colours[i][1] != cfg2.colours[i][1] ||\r
-                oldcfg.colours[i][2] != cfg2.colours[i][2]) {\r
-                real_palette_set(inst, ww[i], cfg2.colours[i][0],\r
-                                 cfg2.colours[i][1],\r
-                                 cfg2.colours[i][2]);\r
-\r
-               /*\r
-                * If the default background has changed, we must\r
-                * repaint the space in between the window border\r
-                * and the text area.\r
-                */\r
-               if (i == 258) {\r
-                   set_window_background(inst);\r
-                   draw_backing_rect(inst);\r
-               }\r
-           }\r
-        }\r
-\r
-        /*\r
-         * If the scrollbar needs to be shown, hidden, or moved\r
-         * from one end to the other of the window, do so now.\r
-         */\r
-        if (oldcfg.scrollbar != cfg2.scrollbar) {\r
-            if (cfg2.scrollbar)\r
-                gtk_widget_show(inst->sbar);\r
-            else\r
-                gtk_widget_hide(inst->sbar);\r
-        }\r
-        if (oldcfg.scrollbar_on_left != cfg2.scrollbar_on_left) {\r
-            gtk_box_reorder_child(inst->hbox, inst->sbar,\r
-                                  cfg2.scrollbar_on_left ? 0 : 1);\r
-        }\r
-\r
-        /*\r
-         * Change the window title, if required.\r
-         */\r
-        if (strcmp(oldcfg.wintitle, cfg2.wintitle))\r
-            set_title(inst, cfg2.wintitle);\r
-       set_window_titles(inst);\r
-\r
-        /*\r
-         * Redo the whole tangled fonts and Unicode mess if\r
-         * necessary.\r
-         */\r
-        if (strcmp(oldcfg.font.name, cfg2.font.name) ||\r
-            strcmp(oldcfg.boldfont.name, cfg2.boldfont.name) ||\r
-            strcmp(oldcfg.widefont.name, cfg2.widefont.name) ||\r
-            strcmp(oldcfg.wideboldfont.name, cfg2.wideboldfont.name) ||\r
-            strcmp(oldcfg.line_codepage, cfg2.line_codepage) ||\r
-           oldcfg.vtmode != cfg2.vtmode ||\r
-           oldcfg.shadowbold != cfg2.shadowbold) {\r
-            setup_fonts_ucs(inst);\r
-            need_size = 1;\r
-        } else\r
-            need_size = 0;\r
-\r
-        /*\r
-         * Resize the window.\r
-         */\r
-        if (oldcfg.width != cfg2.width || oldcfg.height != cfg2.height ||\r
-            oldcfg.window_border != cfg2.window_border || need_size) {\r
-            set_geom_hints(inst);\r
-            request_resize(inst, cfg2.width, cfg2.height);\r
-        } else {\r
-           /*\r
-            * The above will have caused a call to term_size() for\r
-            * us if it happened. If the user has fiddled with only\r
-            * the scrollback size, the above will not have\r
-            * happened and we will need an explicit term_size()\r
-            * here.\r
-            */\r
-           if (oldcfg.savelines != cfg2.savelines)\r
-               term_size(inst->term, inst->term->rows, inst->term->cols,\r
-                         cfg2.savelines);\r
-       }\r
-\r
-        term_invalidate(inst->term);\r
-\r
-       /*\r
-        * We do an explicit full redraw here to ensure the window\r
-        * border has been redrawn as well as the text area.\r
-        */\r
-       gtk_widget_queue_draw(inst->area);\r
-    }\r
-    sfree(title);\r
-    inst->reconfiguring = FALSE;\r
-}\r
-\r
-void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)\r
-{\r
-    /*\r
-     * Re-execing ourself is not an exact science under Unix. I do\r
-     * the best I can by using /proc/self/exe if available and by\r
-     * assuming argv[0] can be found on $PATH if not.\r
-     * \r
-     * Note that we also have to reconstruct the elements of the\r
-     * original argv which gtk swallowed, since the user wants the\r
-     * new session to appear on the same X display as the old one.\r
-     */\r
-    char **args;\r
-    va_list ap;\r
-    int i, n;\r
-    int pid;\r
-\r
-    /*\r
-     * Collect the arguments with which to re-exec ourself.\r
-     */\r
-    va_start(ap, fd_to_close);\r
-    n = 2;                            /* progname and terminating NULL */\r
-    n += inst->ngtkargs;\r
-    while (va_arg(ap, char *) != NULL)\r
-       n++;\r
-    va_end(ap);\r
-\r
-    args = snewn(n, char *);\r
-    args[0] = inst->progname;\r
-    args[n-1] = NULL;\r
-    for (i = 0; i < inst->ngtkargs; i++)\r
-       args[i+1] = inst->gtkargvstart[i];\r
-\r
-    i++;\r
-    va_start(ap, fd_to_close);\r
-    while ((args[i++] = va_arg(ap, char *)) != NULL);\r
-    va_end(ap);\r
-\r
-    assert(i == n);\r
-\r
-    /*\r
-     * Do the double fork.\r
-     */\r
-    pid = fork();\r
-    if (pid < 0) {\r
-       perror("fork");\r
-       return;\r
-    }\r
-\r
-    if (pid == 0) {\r
-       int pid2 = fork();\r
-       if (pid2 < 0) {\r
-           perror("fork");\r
-           _exit(1);\r
-       } else if (pid2 > 0) {\r
-           /*\r
-            * First child has successfully forked second child. My\r
-            * Work Here Is Done. Note the use of _exit rather than\r
-            * exit: the latter appears to cause destroy messages\r
-            * to be sent to the X server. I suspect gtk uses\r
-            * atexit.\r
-            */\r
-           _exit(0);\r
-       }\r
-\r
-       /*\r
-        * If we reach here, we are the second child, so we now\r
-        * actually perform the exec.\r
-        */\r
-       if (fd_to_close >= 0)\r
-           close(fd_to_close);\r
-\r
-       execv("/proc/self/exe", args);\r
-       execvp(inst->progname, args);\r
-       perror("exec");\r
-       _exit(127);\r
-\r
-    } else {\r
-       int status;\r
-       waitpid(pid, &status, 0);\r
-    }\r
-\r
-}\r
-\r
-void dup_session_menuitem(GtkMenuItem *item, gpointer gdata)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)gdata;\r
-    /*\r
-     * For this feature we must marshal cfg and (possibly) pty_argv\r
-     * into a byte stream, create a pipe, and send this byte stream\r
-     * to the child through the pipe.\r
-     */\r
-    int i, ret, size;\r
-    char *data;\r
-    char option[80];\r
-    int pipefd[2];\r
-\r
-    if (pipe(pipefd) < 0) {\r
-       perror("pipe");\r
-       return;\r
-    }\r
-\r
-    size = sizeof(inst->cfg);\r
-    if (use_pty_argv && pty_argv) {\r
-       for (i = 0; pty_argv[i]; i++)\r
-           size += strlen(pty_argv[i]) + 1;\r
-    }\r
-\r
-    data = snewn(size, char);\r
-    memcpy(data, &inst->cfg, sizeof(inst->cfg));\r
-    if (use_pty_argv && pty_argv) {\r
-       int p = sizeof(inst->cfg);\r
-       for (i = 0; pty_argv[i]; i++) {\r
-           strcpy(data + p, pty_argv[i]);\r
-           p += strlen(pty_argv[i]) + 1;\r
-       }\r
-       assert(p == size);\r
-    }\r
-\r
-    sprintf(option, "---[%d,%d]", pipefd[0], size);\r
-    fcntl(pipefd[0], F_SETFD, 0);\r
-    fork_and_exec_self(inst, pipefd[1], option, NULL);\r
-    close(pipefd[0]);\r
-\r
-    i = ret = 0;\r
-    while (i < size && (ret = write(pipefd[1], data + i, size - i)) > 0)\r
-       i += ret;\r
-    if (ret < 0)\r
-       perror("write to pipe");\r
-    close(pipefd[1]);\r
-    sfree(data);\r
-}\r
-\r
-int read_dupsession_data(struct gui_data *inst, Config *cfg, char *arg)\r
-{\r
-    int fd, i, ret, size;\r
-    char *data;\r
-\r
-    if (sscanf(arg, "---[%d,%d]", &fd, &size) != 2) {\r
-       fprintf(stderr, "%s: malformed magic argument `%s'\n", appname, arg);\r
-       exit(1);\r
-    }\r
-\r
-    data = snewn(size, char);\r
-    i = ret = 0;\r
-    while (i < size && (ret = read(fd, data + i, size - i)) > 0)\r
-       i += ret;\r
-    if (ret < 0) {\r
-       perror("read from pipe");\r
-       exit(1);\r
-    } else if (i < size) {\r
-       fprintf(stderr, "%s: unexpected EOF in Duplicate Session data\n",\r
-               appname);\r
-       exit(1);\r
-    }\r
-\r
-    memcpy(cfg, data, sizeof(Config));\r
-    if (use_pty_argv && size > sizeof(Config)) {\r
-       int n = 0;\r
-       i = sizeof(Config);\r
-       while (i < size) {\r
-           while (i < size && data[i]) i++;\r
-           if (i >= size) {\r
-               fprintf(stderr, "%s: malformed Duplicate Session data\n",\r
-                       appname);\r
-               exit(1);\r
-           }\r
-           i++;\r
-           n++;\r
-       }\r
-       pty_argv = snewn(n+1, char *);\r
-       pty_argv[n] = NULL;\r
-       n = 0;\r
-       i = sizeof(Config);\r
-       while (i < size) {\r
-           char *p = data + i;\r
-           while (i < size && data[i]) i++;\r
-           assert(i < size);\r
-           i++;\r
-           pty_argv[n++] = dupstr(p);\r
-       }\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-void new_session_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-\r
-    fork_and_exec_self(inst, -1, NULL);\r
-}\r
-\r
-void restart_session_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-\r
-    if (!inst->back) {\r
-       logevent(inst, "----- Session restarted -----");\r
-       term_pwron(inst->term, FALSE);\r
-       start_backend(inst);\r
-       inst->exited = FALSE;\r
-    }\r
-}\r
-\r
-void saved_session_menuitem(GtkMenuItem *item, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    char *str = (char *)gtk_object_get_data(GTK_OBJECT(item), "user-data");\r
-\r
-    fork_and_exec_self(inst, -1, "-load", str, NULL);\r
-}\r
-\r
-void saved_session_freedata(GtkMenuItem *item, gpointer data)\r
-{\r
-    char *str = (char *)gtk_object_get_data(GTK_OBJECT(item), "user-data");\r
-\r
-    sfree(str);\r
-}\r
-\r
-static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)data;\r
-    struct sesslist sesslist;\r
-    int i;\r
-\r
-    gtk_container_foreach(GTK_CONTAINER(inst->sessionsmenu),\r
-                         (GtkCallback)gtk_widget_destroy, NULL);\r
-\r
-    get_sesslist(&sesslist, TRUE);\r
-    /* skip sesslist.sessions[0] == Default Settings */\r
-    for (i = 1; i < sesslist.nsessions; i++) {\r
-       GtkWidget *menuitem =\r
-           gtk_menu_item_new_with_label(sesslist.sessions[i]);\r
-       gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem);\r
-       gtk_widget_show(menuitem);\r
-       gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",\r
-                           dupstr(sesslist.sessions[i]));\r
-       gtk_signal_connect(GTK_OBJECT(menuitem), "activate",\r
-                          GTK_SIGNAL_FUNC(saved_session_menuitem),\r
-                          inst);\r
-       gtk_signal_connect(GTK_OBJECT(menuitem), "destroy",\r
-                          GTK_SIGNAL_FUNC(saved_session_freedata),\r
-                          inst);\r
-    }\r
-    if (sesslist.nsessions <= 1) {\r
-       GtkWidget *menuitem =\r
-           gtk_menu_item_new_with_label("(No sessions)");\r
-       gtk_widget_set_sensitive(menuitem, FALSE);\r
-       gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem);\r
-       gtk_widget_show(menuitem);\r
-    }\r
-    get_sesslist(&sesslist, FALSE); /* free up */\r
-}\r
-\r
-void set_window_icon(GtkWidget *window, const char *const *const *icon,\r
-                    int n_icon)\r
-{\r
-    GdkPixmap *iconpm;\r
-    GdkBitmap *iconmask;\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    GList *iconlist;\r
-    int n;\r
-#endif\r
-\r
-    if (!n_icon)\r
-       return;\r
-\r
-    gtk_widget_realize(window);\r
-    iconpm = gdk_pixmap_create_from_xpm_d(window->window, &iconmask,\r
-                                         NULL, (gchar **)icon[0]);\r
-    gdk_window_set_icon(window->window, NULL, iconpm, iconmask);\r
-\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    iconlist = NULL;\r
-    for (n = 0; n < n_icon; n++) {\r
-       iconlist =\r
-           g_list_append(iconlist,\r
-                         gdk_pixbuf_new_from_xpm_data((const gchar **)\r
-                                                      icon[n]));\r
-    }\r
-    gdk_window_set_icon_list(window->window, iconlist);\r
-#endif\r
-}\r
-\r
-void update_specials_menu(void *frontend)\r
-{\r
-    struct gui_data *inst = (struct gui_data *)frontend;\r
-\r
-    const struct telnet_special *specials;\r
-\r
-    if (inst->back)\r
-       specials = inst->back->get_specials(inst->backhandle);\r
-    else\r
-       specials = NULL;\r
-\r
-    /* I believe this disposes of submenus too. */\r
-    gtk_container_foreach(GTK_CONTAINER(inst->specialsmenu),\r
-                         (GtkCallback)gtk_widget_destroy, NULL);\r
-    if (specials) {\r
-       int i;\r
-       GtkWidget *menu = inst->specialsmenu;\r
-       /* A lame "stack" for submenus that will do for now. */\r
-       GtkWidget *saved_menu = NULL;\r
-       int nesting = 1;\r
-       for (i = 0; nesting > 0; i++) {\r
-           GtkWidget *menuitem = NULL;\r
-           switch (specials[i].code) {\r
-             case TS_SUBMENU:\r
-               assert (nesting < 2);\r
-               saved_menu = menu; /* XXX lame stacking */\r
-               menu = gtk_menu_new();\r
-               menuitem = gtk_menu_item_new_with_label(specials[i].name);\r
-               gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);\r
-               gtk_container_add(GTK_CONTAINER(saved_menu), menuitem);\r
-               gtk_widget_show(menuitem);\r
-               menuitem = NULL;\r
-               nesting++;\r
-               break;\r
-             case TS_EXITMENU:\r
-               nesting--;\r
-               if (nesting) {\r
-                   menu = saved_menu; /* XXX lame stacking */\r
-                   saved_menu = NULL;\r
-               }\r
-               break;\r
-             case TS_SEP:\r
-               menuitem = gtk_menu_item_new();\r
-               break;\r
-             default:\r
-               menuitem = gtk_menu_item_new_with_label(specials[i].name);\r
-               gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",\r
-                                   GINT_TO_POINTER(specials[i].code));\r
-               gtk_signal_connect(GTK_OBJECT(menuitem), "activate",\r
-                                  GTK_SIGNAL_FUNC(special_menuitem), inst);\r
-               break;\r
-           }\r
-           if (menuitem) {\r
-               gtk_container_add(GTK_CONTAINER(menu), menuitem);\r
-               gtk_widget_show(menuitem);\r
-           }\r
-       }\r
-       gtk_widget_show(inst->specialsitem1);\r
-       gtk_widget_show(inst->specialsitem2);\r
-    } else {\r
-       gtk_widget_hide(inst->specialsitem1);\r
-       gtk_widget_hide(inst->specialsitem2);\r
-    }\r
-}\r
-\r
-static void start_backend(struct gui_data *inst)\r
-{\r
-    extern Backend *select_backend(Config *cfg);\r
-    char *realhost;\r
-    const char *error;\r
-\r
-    inst->back = select_backend(&inst->cfg);\r
-\r
-    error = inst->back->init((void *)inst, &inst->backhandle,\r
-                            &inst->cfg, inst->cfg.host, inst->cfg.port,\r
-                            &realhost, inst->cfg.tcp_nodelay,\r
-                            inst->cfg.tcp_keepalives);\r
-\r
-    if (error) {\r
-       char *msg = dupprintf("Unable to open connection to %s:\n%s",\r
-                             inst->cfg.host, error);\r
-       inst->exited = TRUE;\r
-       fatal_message_box(inst->window, msg);\r
-       sfree(msg);\r
-       exit(0);\r
-    }\r
-\r
-    if (inst->cfg.wintitle[0]) {\r
-       set_title(inst, inst->cfg.wintitle);\r
-       set_icon(inst, inst->cfg.wintitle);\r
-    } else {\r
-       char *title = make_default_wintitle(realhost);\r
-       set_title(inst, title);\r
-       set_icon(inst, title);\r
-       sfree(title);\r
-    }\r
-    sfree(realhost);\r
-\r
-    inst->back->provide_logctx(inst->backhandle, inst->logctx);\r
-\r
-    term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle);\r
-\r
-    inst->ldisc =\r
-       ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle,\r
-                    inst);\r
-\r
-    gtk_widget_set_sensitive(inst->restartitem, FALSE);\r
-}\r
-\r
-int pt_main(int argc, char **argv)\r
-{\r
-    extern int cfgbox(Config *cfg);\r
-    struct gui_data *inst;\r
-\r
-    /*\r
-     * Create an instance structure and initialise to zeroes\r
-     */\r
-    inst = snew(struct gui_data);\r
-    memset(inst, 0, sizeof(*inst));\r
-    inst->alt_keycode = -1;            /* this one needs _not_ to be zero */\r
-    inst->busy_status = BUSY_NOT;\r
-\r
-    /* defer any child exit handling until we're ready to deal with\r
-     * it */\r
-    block_signal(SIGCHLD, 1);\r
-\r
-    inst->progname = argv[0];\r
-    /*\r
-     * Copy the original argv before letting gtk_init fiddle with\r
-     * it. It will be required later.\r
-     */\r
-    {\r
-       int i, oldargc;\r
-       inst->gtkargvstart = snewn(argc-1, char *);\r
-       for (i = 1; i < argc; i++)\r
-           inst->gtkargvstart[i-1] = dupstr(argv[i]);\r
-       oldargc = argc;\r
-       gtk_init(&argc, &argv);\r
-       inst->ngtkargs = oldargc - argc;\r
-    }\r
-\r
-    if (argc > 1 && !strncmp(argv[1], "---", 3)) {\r
-       read_dupsession_data(inst, &inst->cfg, argv[1]);\r
-       /* Splatter this argument so it doesn't clutter a ps listing */\r
-       memset(argv[1], 0, strlen(argv[1]));\r
-    } else {\r
-       /* By default, we bring up the config dialog, rather than launching\r
-        * a session. This gets set to TRUE if something happens to change\r
-        * that (e.g., a hostname is specified on the command-line). */\r
-       int allow_launch = FALSE;\r
-       if (do_cmdline(argc, argv, 0, &allow_launch, inst, &inst->cfg))\r
-           exit(1);                   /* pre-defaults pass to get -class */\r
-       do_defaults(NULL, &inst->cfg);\r
-       if (do_cmdline(argc, argv, 1, &allow_launch, inst, &inst->cfg))\r
-           exit(1);                   /* post-defaults, do everything */\r
-\r
-       cmdline_run_saved(&inst->cfg);\r
-\r
-       if (loaded_session)\r
-           allow_launch = TRUE;\r
-\r
-       if ((!allow_launch || !cfg_launchable(&inst->cfg)) &&\r
-           !cfgbox(&inst->cfg))\r
-           exit(0);                   /* config box hit Cancel */\r
-    }\r
-\r
-    if (!compound_text_atom)\r
-        compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE);\r
-    if (!utf8_string_atom)\r
-        utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);\r
-\r
-    inst->area = gtk_drawing_area_new();\r
-\r
-    setup_fonts_ucs(inst);\r
-    init_cutbuffers();\r
-\r
-    inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);\r
-    if (inst->cfg.winclass[0])\r
-        gtk_window_set_wmclass(GTK_WINDOW(inst->window),\r
-                               inst->cfg.winclass, inst->cfg.winclass);\r
-\r
-    /*\r
-     * Set up the colour map.\r
-     */\r
-    palette_reset(inst);\r
-\r
-    inst->width = inst->cfg.width;\r
-    inst->height = inst->cfg.height;\r
-\r
-    gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area),\r
-                         inst->font_width * inst->cfg.width + 2*inst->cfg.window_border,\r
-                         inst->font_height * inst->cfg.height + 2*inst->cfg.window_border);\r
-    inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0));\r
-    inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust);\r
-    inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0));\r
-    /*\r
-     * We always create the scrollbar; it remains invisible if\r
-     * unwanted, so we can pop it up quickly if it suddenly becomes\r
-     * desirable.\r
-     */\r
-    if (inst->cfg.scrollbar_on_left)\r
-        gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0);\r
-    gtk_box_pack_start(inst->hbox, inst->area, TRUE, TRUE, 0);\r
-    if (!inst->cfg.scrollbar_on_left)\r
-        gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0);\r
-\r
-    gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox));\r
-\r
-    set_geom_hints(inst);\r
-\r
-    gtk_widget_show(inst->area);\r
-    if (inst->cfg.scrollbar)\r
-       gtk_widget_show(inst->sbar);\r
-    else\r
-       gtk_widget_hide(inst->sbar);\r
-    gtk_widget_show(GTK_WIDGET(inst->hbox));\r
-\r
-    if (inst->gotpos) {\r
-        int x = inst->xpos, y = inst->ypos;\r
-        GtkRequisition req;\r
-        gtk_widget_size_request(GTK_WIDGET(inst->window), &req);\r
-        if (inst->gravity & 1) x += gdk_screen_width() - req.width;\r
-        if (inst->gravity & 2) y += gdk_screen_height() - req.height;\r
-       gtk_window_set_position(GTK_WINDOW(inst->window), GTK_WIN_POS_NONE);\r
-       gtk_widget_set_uposition(GTK_WIDGET(inst->window), x, y);\r
-    }\r
-\r
-    gtk_signal_connect(GTK_OBJECT(inst->window), "destroy",\r
-                      GTK_SIGNAL_FUNC(destroy), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->window), "delete_event",\r
-                      GTK_SIGNAL_FUNC(delete_window), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->window), "key_press_event",\r
-                      GTK_SIGNAL_FUNC(key_event), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->window), "key_release_event",\r
-                      GTK_SIGNAL_FUNC(key_event), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->window), "focus_in_event",\r
-                      GTK_SIGNAL_FUNC(focus_event), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->window), "focus_out_event",\r
-                      GTK_SIGNAL_FUNC(focus_event), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "configure_event",\r
-                      GTK_SIGNAL_FUNC(configure_area), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "expose_event",\r
-                      GTK_SIGNAL_FUNC(expose_area), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "button_press_event",\r
-                      GTK_SIGNAL_FUNC(button_event), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "button_release_event",\r
-                      GTK_SIGNAL_FUNC(button_event), inst);\r
-#if GTK_CHECK_VERSION(2,0,0)\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "scroll_event",\r
-                      GTK_SIGNAL_FUNC(scroll_event), inst);\r
-#endif\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "motion_notify_event",\r
-                      GTK_SIGNAL_FUNC(motion_event), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "selection_received",\r
-                      GTK_SIGNAL_FUNC(selection_received), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "selection_get",\r
-                      GTK_SIGNAL_FUNC(selection_get), inst);\r
-    gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event",\r
-                      GTK_SIGNAL_FUNC(selection_clear), inst);\r
-    if (inst->cfg.scrollbar)\r
-       gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",\r
-                          GTK_SIGNAL_FUNC(scrollbar_moved), inst);\r
-    gtk_widget_add_events(GTK_WIDGET(inst->area),\r
-                         GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |\r
-                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |\r
-                         GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK);\r
-\r
-    {\r
-       extern const char *const *const main_icon[];\r
-       extern const int n_main_icon;\r
-       set_window_icon(inst->window, main_icon, n_main_icon);\r
-    }\r
-\r
-    gtk_widget_show(inst->window);\r
-\r
-    set_window_background(inst);\r
-\r
-    /*\r
-     * Set up the Ctrl+rightclick context menu.\r
-     */\r
-    {\r
-       GtkWidget *menuitem;\r
-       char *s;\r
-       extern const int use_event_log, new_session, saved_sessions;\r
-\r
-       inst->menu = gtk_menu_new();\r
-\r
-#define MKMENUITEM(title, func) do                                      \\r
-        {                                                               \\r
-            menuitem = gtk_menu_item_new_with_label(title);             \\r
-            gtk_container_add(GTK_CONTAINER(inst->menu), menuitem);     \\r
-            gtk_widget_show(menuitem);                                  \\r
-            gtk_signal_connect(GTK_OBJECT(menuitem), "activate",        \\r
-                               GTK_SIGNAL_FUNC(func), inst);            \\r
-        } while (0)\r
-\r
-#define MKSUBMENU(title) do                                             \\r
-        {                                                               \\r
-            menuitem = gtk_menu_item_new_with_label(title);             \\r
-            gtk_container_add(GTK_CONTAINER(inst->menu), menuitem);     \\r
-            gtk_widget_show(menuitem);                                  \\r
-        } while (0)\r
-\r
-#define MKSEP() do                                                      \\r
-        {                                                               \\r
-            menuitem = gtk_menu_item_new();                             \\r
-            gtk_container_add(GTK_CONTAINER(inst->menu), menuitem);     \\r
-            gtk_widget_show(menuitem);                                  \\r
-        } while (0)\r
-\r
-       if (new_session)\r
-           MKMENUITEM("New Session...", new_session_menuitem);\r
-        MKMENUITEM("Restart Session", restart_session_menuitem);\r
-       inst->restartitem = menuitem;\r
-       gtk_widget_set_sensitive(inst->restartitem, FALSE);\r
-        MKMENUITEM("Duplicate Session", dup_session_menuitem);\r
-       if (saved_sessions) {\r
-           inst->sessionsmenu = gtk_menu_new();\r
-           /* sessionsmenu will be updated when it's invoked */\r
-           /* XXX is this the right way to do dynamic menus in Gtk? */\r
-           MKMENUITEM("Saved Sessions", update_savedsess_menu);\r
-           gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem),\r
-                                     inst->sessionsmenu);\r
-       }\r
-       MKSEP();\r
-        MKMENUITEM("Change Settings...", change_settings_menuitem);\r
-       MKSEP();\r
-       if (use_event_log)\r
-           MKMENUITEM("Event Log", event_log_menuitem);\r
-       MKSUBMENU("Special Commands");\r
-       inst->specialsmenu = gtk_menu_new();\r
-       gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), inst->specialsmenu);\r
-       inst->specialsitem1 = menuitem;\r
-       MKSEP();\r
-       inst->specialsitem2 = menuitem;\r
-       gtk_widget_hide(inst->specialsitem1);\r
-       gtk_widget_hide(inst->specialsitem2);\r
-       MKMENUITEM("Clear Scrollback", clear_scrollback_menuitem);\r
-       MKMENUITEM("Reset Terminal", reset_terminal_menuitem);\r
-       MKMENUITEM("Copy All", copy_all_menuitem);\r
-       MKSEP();\r
-       s = dupcat("About ", appname, NULL);\r
-       MKMENUITEM(s, about_menuitem);\r
-       sfree(s);\r
-#undef MKMENUITEM\r
-#undef MKSUBMENU\r
-#undef MKSEP\r
-    }\r
-\r
-    inst->textcursor = make_mouse_ptr(inst, GDK_XTERM);\r
-    inst->rawcursor = make_mouse_ptr(inst, GDK_LEFT_PTR);\r
-    inst->waitcursor = make_mouse_ptr(inst, GDK_WATCH);\r
-    inst->blankcursor = make_mouse_ptr(inst, -1);\r
-    make_mouse_ptr(inst, -2);         /* clean up cursor font */\r
-    inst->currcursor = inst->textcursor;\r
-    show_mouseptr(inst, 1);\r
-\r
-    inst->eventlogstuff = eventlogstuff_new();\r
-\r
-    inst->term = term_init(&inst->cfg, &inst->ucsdata, inst);\r
-    inst->logctx = log_init(inst, &inst->cfg);\r
-    term_provide_logctx(inst->term, inst->logctx);\r
-\r
-    uxsel_init();\r
-\r
-    term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines);\r
-\r
-    start_backend(inst);\r
-\r
-    ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */\r
-\r
-    /* now we're reday to deal with the child exit handler being\r
-     * called */\r
-    block_signal(SIGCHLD, 0);\r
-\r
-    /*\r
-     * Block SIGPIPE: if we attempt Duplicate Session or similar\r
-     * and it falls over in some way, we certainly don't want\r
-     * SIGPIPE terminating the main pterm/PuTTY. Note that we do\r
-     * this _after_ (at least pterm) forks off its child process,\r
-     * since the child wants SIGPIPE handled in the usual way.\r
-     */\r
-    block_signal(SIGPIPE, 1);\r
-\r
-    inst->exited = FALSE;\r
-\r
-    gtk_main();\r
-\r
-    return 0;\r
-}\r