]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/gtkwin.c
Giant const-correctness patch of doom!
[PuTTY.git] / unix / gtkwin.c
index da40e5447324d5fc84a933d1e71874bb30eb24b5..e8345881cd803d391da8aa1ccf6fdca7433bd99f 100644 (file)
@@ -93,8 +93,8 @@ struct gui_data {
     int ignore_sbar;
     int mouseptr_visible;
     int busy_status;
-    guint term_paste_idle_id;
-    guint term_exit_idle_id;
+    guint toplevel_callback_idle_id;
+    int idle_fn_scheduled, quit_fn_scheduled;
     int alt_keycode;
     int alt_digits;
     char *wintitle;
@@ -133,16 +133,17 @@ struct draw_ctx {
 
 static int send_raw_mouse;
 
-static char *app_name = "pterm";
+static const char *app_name = "pterm";
 
 static void start_backend(struct gui_data *inst);
+static void exit_callback(void *vinst);
 
 char *x_get_default(const char *key)
 {
     return XGetDefault(GDK_DISPLAY(), app_name, key);
 }
 
-void connection_fatal(void *frontend, char *p, ...)
+void connection_fatal(void *frontend, const char *p, ...)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
 
@@ -151,11 +152,10 @@ void connection_fatal(void *frontend, char *p, ...)
     va_start(ap, p);
     msg = dupvprintf(p, ap);
     va_end(ap);
-    inst->exited = TRUE;
     fatal_message_box(inst->window, msg);
     sfree(msg);
-    if (conf_get_int(inst->conf, CONF_close_on_exit) == FORCE_ON)
-        cleanup_exit(1);
+
+    queue_toplevel_callback(exit_callback, inst);
 }
 
 /*
@@ -194,7 +194,7 @@ int platform_default_i(const char *name, int def)
 }
 
 /* Dummy routine, only required in plink. */
-void ldisc_update(void *frontend, int echo, int edit)
+void frontend_echoedit_update(void *frontend, int echo, int edit)
 {
 }
 
@@ -221,7 +221,7 @@ int from_backend_eof(void *frontend)
     return TRUE;   /* do respond to incoming EOF with outgoing */
 }
 
-int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
+int get_userpass_input(prompts_t *p, const unsigned char *in, int inlen)
 {
     struct gui_data *inst = (struct gui_data *)p->frontend;
     int ret;
@@ -885,7 +885,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
         * NetHack keypad mode.
         */
        if (nethack_mode) {
-           char *keys = NULL;
+           const char *keys = NULL;
            switch (event->keyval) {
              case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break;
              case GDK_KP_2: case GDK_KP_Down: keys = "jJ\012"; break;
@@ -1223,7 +1223,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
 void input_method_commit_event(GtkIMContext *imc, gchar *str, gpointer data)
 {
     struct gui_data *inst = (struct gui_data *)data;
-    lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1);
+    if (inst->ldisc)
+        lpage_send(inst->ldisc, CS_UTF8, str, strlen(str), 1);
     show_mouseptr(inst, 0);
     term_seen_key_event(inst->term);
 }
@@ -1233,26 +1234,32 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
                         GdkEventType type, guint ebutton, guint state,
                         gdouble ex, gdouble ey)
 {
-    int shift, ctrl, alt, x, y, button, act;
+    int shift, ctrl, alt, x, y, button, act, raw_mouse_mode;
 
     /* Remember the timestamp. */
     inst->input_event_time = timestamp;
 
     show_mouseptr(inst, 1);
 
-    if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
-       term_scroll(inst->term, 0, -5);
-       return TRUE;
-    }
-    if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
-       term_scroll(inst->term, 0, +5);
-       return TRUE;
-    }
-
     shift = state & GDK_SHIFT_MASK;
     ctrl = state & GDK_CONTROL_MASK;
     alt = state & GDK_MOD1_MASK;
 
+    raw_mouse_mode =
+        send_raw_mouse && !(shift && conf_get_int(inst->conf,
+                                                  CONF_mouse_override));
+
+    if (!raw_mouse_mode) {
+        if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
+            term_scroll(inst->term, 0, -5);
+            return TRUE;
+        }
+        if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
+            term_scroll(inst->term, 0, +5);
+            return TRUE;
+        }
+    }
+
     if (ebutton == 3 && ctrl) {
        gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,
                       ebutton, timestamp);
@@ -1265,6 +1272,10 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
        button = MBT_MIDDLE;
     else if (ebutton == 3)
        button = MBT_RIGHT;
+    else if (ebutton == 4)
+       button = MBT_WHEEL_UP;
+    else if (ebutton == 5)
+       button = MBT_WHEEL_DOWN;
     else
        return FALSE;                  /* don't even know what button! */
 
@@ -1276,9 +1287,7 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp,
       default: return FALSE;          /* don't know this event type */
     }
 
-    if (send_raw_mouse && !(shift && conf_get_int(inst->conf,
-                                                 CONF_mouse_override)) &&
-       act != MA_CLICK && act != MA_RELEASE)
+    if (raw_mouse_mode && act != MA_CLICK && act != MA_RELEASE)
        return TRUE;                   /* we ignore these in raw mouse mode */
 
     x = (ex - inst->window_border) / inst->font_width;
@@ -1360,12 +1369,12 @@ void frontend_keypress(void *handle)
      * any keypress.
      */
     if (inst->exited)
-       exit(0);
+       cleanup_exit(0);
 }
 
-static gint idle_exit_func(gpointer data)
+static void exit_callback(void *vinst)
 {
-    struct gui_data *inst = (struct gui_data *)data;
+    struct gui_data *inst = (struct gui_data *)vinst;
     int exitcode, close_on_exit;
 
     if (!inst->exited &&
@@ -1379,25 +1388,86 @@ static gint idle_exit_func(gpointer data)
            ldisc_free(inst->ldisc);
            inst->ldisc = NULL;
        }
-       if (inst->back) {
-           inst->back->free(inst->backhandle);
-           inst->backhandle = NULL;
-           inst->back = NULL;
-            term_provide_resize_fn(inst->term, NULL, NULL);
-           update_specials_menu(inst);
-       }
+        inst->back->free(inst->backhandle);
+        inst->backhandle = NULL;
+        inst->back = NULL;
+        term_provide_resize_fn(inst->term, NULL, NULL);
+        update_specials_menu(inst);
        gtk_widget_set_sensitive(inst->restartitem, TRUE);
     }
+}
+
+void notify_remote_exit(void *frontend)
+{
+    struct gui_data *inst = (struct gui_data *)frontend;
+
+    queue_toplevel_callback(exit_callback, inst);
+}
+
+static void notify_toplevel_callback(void *frontend);
+
+static gint quit_toplevel_callback_func(gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+
+    notify_toplevel_callback(inst);
+
+    inst->quit_fn_scheduled = FALSE;
+
+    return 0;
+}
+
+static gint idle_toplevel_callback_func(gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+
+    if (gtk_main_level() > 1) {
+        /*
+         * We don't run the callbacks if we're in the middle of a
+         * subsidiary gtk_main. Instead, ask for a callback when we
+         * get back out of the subsidiary main loop (if we haven't
+         * already arranged one), so we can reschedule ourself then.
+         */
+        if (!inst->quit_fn_scheduled) {
+            gtk_quit_add(2, quit_toplevel_callback_func, inst);
+            inst->quit_fn_scheduled = TRUE;
+        }
+        /*
+         * And unschedule this idle function, since we've now done
+         * everything we can until the innermost gtk_main has quit and
+         * can reschedule us with a chance of actually taking action.
+         */
+        if (inst->idle_fn_scheduled) { /* double-check, just in case */
+            gtk_idle_remove(inst->toplevel_callback_idle_id);
+            inst->idle_fn_scheduled = FALSE;
+        }
+    } else {
+        run_toplevel_callbacks();
+    }
+
+    /*
+     * If we've emptied our toplevel callback queue, unschedule
+     * ourself. Otherwise, leave ourselves pending so we'll be called
+     * again to deal with more callbacks after another round of the
+     * event loop.
+     */
+    if (!toplevel_callback_pending() && inst->idle_fn_scheduled) {
+        gtk_idle_remove(inst->toplevel_callback_idle_id);
+        inst->idle_fn_scheduled = FALSE;
+    }
 
-    gtk_idle_remove(inst->term_exit_idle_id);
     return TRUE;
 }
 
-void notify_remote_exit(void *frontend)
+static void notify_toplevel_callback(void *frontend)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
 
-    inst->term_exit_idle_id = gtk_idle_add(idle_exit_func, inst);
+    if (!inst->idle_fn_scheduled) {
+        inst->toplevel_callback_idle_id =
+            gtk_idle_add(idle_toplevel_callback_func, inst);
+        inst->idle_fn_scheduled = TRUE;
+    }
 }
 
 static gint timer_trigger(gpointer data)
@@ -1406,7 +1476,21 @@ static gint timer_trigger(gpointer data)
     unsigned long next, then;
     long ticks;
 
-    if (run_timers(now, &next)) {
+    /*
+     * Destroy the timer we got here on.
+     */
+    if (timer_id) {
+       gtk_timeout_remove(timer_id);
+        timer_id = 0;
+    }
+
+    /*
+     * run_timers() may cause a call to timer_change_notify, in which
+     * case a new timer will already have been set up and left in
+     * timer_id. If it hasn't, and run_timers reports that some timing
+     * still needs to be done, we do it ourselves.
+     */
+    if (run_timers(now, &next) && !timer_id) {
        then = now;
        now = GETTICKCOUNT();
        if (now - then > next - then)
@@ -1418,8 +1502,9 @@ static gint timer_trigger(gpointer data)
     }
 
     /*
-     * Never let a timer resume. If we need another one, we've
-     * asked for it explicitly above.
+     * Returning FALSE means 'don't call this timer again', which
+     * _should_ be redundant given that we removed it above, but just
+     * in case, return FALSE anyway.
      */
     return FALSE;
 }
@@ -1597,7 +1682,7 @@ void palette_set(void *frontend, int n, int r, int g, int b)
     struct gui_data *inst = (struct gui_data *)frontend;
     if (n >= 16)
        n += 256 - 16;
-    if (n > NALLCOLOURS)
+    if (n >= NALLCOLOURS)
        return;
     real_palette_set(inst, n, r, g, b);
     if (n == 258) {
@@ -1980,28 +2065,12 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
 
     term_do_paste(inst->term);
 
-    if (term_paste_pending(inst->term))
-       inst->term_paste_idle_id = gtk_idle_add(idle_paste_func, inst);
-
     if (free_list_required)
        XFreeStringList(list);
     if (free_required)
        XFree(text);
 }
 
-gint idle_paste_func(gpointer data)
-{
-    struct gui_data *inst = (struct gui_data *)data;
-
-    if (term_paste_pending(inst->term))
-       term_paste(inst->term);
-    else
-       gtk_idle_remove(inst->term_paste_idle_id);
-
-    return TRUE;
-}
-
-
 void get_clip(void *frontend, wchar_t ** p, int *len)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
@@ -2534,7 +2603,7 @@ GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val)
     return ret;
 }
 
-void modalfatalbox(char *p, ...)
+void modalfatalbox(const char *p, ...)
 {
     va_list ap;
     fprintf(stderr, "FATAL ERROR: ");
@@ -2545,7 +2614,7 @@ void modalfatalbox(char *p, ...)
     exit(1);
 }
 
-void cmdline_error(char *p, ...)
+void cmdline_error(const char *p, ...)
 {
     va_list ap;
     fprintf(stderr, "%s: ", appname);
@@ -2626,7 +2695,7 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
 #define SECOND_PASS_ONLY { if (!do_everything) continue; }
 
     while (--argc > 0) {
-       char *p = *++argv;
+       const char *p = *++argv;
         int ret;
 
        /*
@@ -2845,24 +2914,6 @@ void uxsel_input_remove(int id) {
     gdk_input_remove(id);
 }
 
-int frontend_net_pending_error_idle_id;
-int frontend_got_net_pending_errors = FALSE;
-gboolean frontend_net_pending_errors(gpointer data)
-{
-    net_pending_errors();
-    gtk_idle_remove(frontend_net_pending_error_idle_id);
-    frontend_got_net_pending_errors = FALSE;
-    return FALSE;
-}
-void frontend_net_error_pending(void)
-{
-    if (!frontend_got_net_pending_errors) {
-        frontend_got_net_pending_errors = TRUE;
-        frontend_net_pending_error_idle_id =
-            gtk_idle_add(frontend_net_pending_errors, NULL);
-    }
-}
-
 char *setup_fonts_ucs(struct gui_data *inst)
 {
     int shadowbold = conf_get_int(inst->conf, CONF_shadowbold);
@@ -2899,7 +2950,7 @@ char *setup_fonts_ucs(struct gui_data *inst)
             for (i = 0; i < 2; i++)
                 if (fonts[i])
                     unifont_destroy(fonts[i]);
-            return dupprintf("%s: unable to load wide font \"%s\"", fs->name);
+            return dupprintf("unable to load wide font \"%s\"", fs->name);
        }
     } else {
        fonts[2] = NULL;
@@ -2915,8 +2966,7 @@ char *setup_fonts_ucs(struct gui_data *inst)
             for (i = 0; i < 3; i++)
                 if (fonts[i])
                     unifont_destroy(fonts[i]);
-           return dupprintf("%s: unable to load wide bold font \"%s\"",
-                             fs->name);
+           return dupprintf("unable to load wide bold font \"%s\"", fs->name);
        }
     }
 
@@ -2970,7 +3020,7 @@ void reset_terminal_menuitem(GtkMenuItem *item, gpointer data)
     struct gui_data *inst = (struct gui_data *)data;
     term_pwron(inst->term, TRUE);
     if (inst->ldisc)
-       ldisc_send(inst->ldisc, NULL, 0, 0);
+       ldisc_echoedit_update(inst->ldisc);
 }
 
 void copy_all_menuitem(GtkMenuItem *item, gpointer data)
@@ -3010,7 +3060,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
        4, 12, 5, 13, 6, 14, 7, 15
     };
     struct gui_data *inst = (struct gui_data *)data;
-    char *title = dupcat(appname, " Reconfiguration", NULL);
+    char *title;
     Conf *oldconf, *newconf;
     int i, j, need_size;
 
@@ -3021,6 +3071,8 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
     else
       inst->reconfiguring = TRUE;
 
+    title = dupcat(appname, " Reconfiguration", NULL);
+
     oldconf = inst->conf;
     newconf = conf_copy(inst->conf);
 
@@ -3034,9 +3086,10 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
          * Flush the line discipline's edit buffer in the case
          * where local editing has just been disabled.
          */
-       ldisc_configure(inst->ldisc, inst->conf);
-        if (inst->ldisc)
-           ldisc_send(inst->ldisc, NULL, 0, 0);
+        if (inst->ldisc) {
+            ldisc_configure(inst->ldisc, inst->conf);
+            ldisc_echoedit_update(inst->ldisc);
+        }
         /* Pass new config data to the terminal */
         term_reconfig(inst->term, inst->conf);
         /* Pass new config data to the back end */
@@ -3069,7 +3122,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
                 * repaint the space in between the window border
                 * and the text area.
                 */
-               if (i == 258) {
+               if (ww[i] == 258) {
                    set_window_background(inst);
                    draw_backing_rect(inst);
                }
@@ -3134,6 +3187,7 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
                            string_width("Could not change fonts in terminal window:"),
                            "OK", 'o', +1, 1,
                            NULL);
+                sfree(msgboxtext);
                 sfree(errmsg);
             } else {
                 need_size = TRUE;
@@ -3228,6 +3282,7 @@ void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)
     pid = fork();
     if (pid < 0) {
        perror("fork");
+        sfree(args);
        return;
     }
 
@@ -3261,6 +3316,7 @@ void fork_and_exec_self(struct gui_data *inst, int fd_to_close, ...)
 
     } else {
        int status;
+        sfree(args);
        waitpid(pid, &status, 0);
     }
 
@@ -3302,7 +3358,7 @@ void dup_session_menuitem(GtkMenuItem *item, gpointer gdata)
     }
 
     sprintf(option, "---[%d,%d]", pipefd[0], size);
-    fcntl(pipefd[0], F_SETFD, 0);
+    noncloexec(pipefd[0]);
     fork_and_exec_self(inst, pipefd[1], option, NULL);
     close(pipefd[0]);
 
@@ -3365,6 +3421,8 @@ int read_dupsession_data(struct gui_data *inst, Conf *conf, char *arg)
        }
     }
 
+    sfree(data);
+
     return 0;
 }
 
@@ -3595,6 +3653,8 @@ int pt_main(int argc, char **argv)
     inst->busy_status = BUSY_NOT;
     inst->conf = conf_new();
     inst->wintitle = inst->icontitle = NULL;
+    inst->quit_fn_scheduled = FALSE;
+    inst->idle_fn_scheduled = FALSE;
 
     /* defer any child exit handling until we're ready to deal with
      * it */
@@ -3851,6 +3911,8 @@ int pt_main(int argc, char **argv)
 
     inst->eventlogstuff = eventlogstuff_new();
 
+    request_callback_notifications(notify_toplevel_callback, inst);
+
     inst->term = term_init(inst->conf, &inst->ucsdata, inst);
     inst->logctx = log_init(inst, inst->conf);
     term_provide_logctx(inst->term, inst->logctx);
@@ -3862,7 +3924,7 @@ int pt_main(int argc, char **argv)
 
     start_backend(inst);
 
-    ldisc_send(inst->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */
+    ldisc_echoedit_update(inst->ldisc);     /* cause ldisc to notice changes */
 
     /* now we're reday to deal with the child exit handler being
      * called */