X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkwin.c;h=f3a17d58434c2fdb1453fac5ea2ce95e794ce227;hb=d23c0972cd850c77871f9a314e0520d7023c8b62;hp=f403a80796dcb568997c9a52d40ff433f2f15616;hpb=bbc9709b48515954f2f3eb631d1a6bea960bda18;p=PuTTY.git diff --git a/unix/gtkwin.c b/unix/gtkwin.c index f403a807..f3a17d58 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -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; @@ -136,6 +136,7 @@ static int send_raw_mouse; static 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) { @@ -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) { } @@ -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; } @@ -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; @@ -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 */