int mouseptr_visible;
int busy_status;
guint term_paste_idle_id;
+ guint term_exit_idle_id;
int alt_keycode;
int alt_digits;
char wintitle[sizeof(((Config *)0)->wintitle)];
return def;
}
+/* Dummy routine, only required in plink. */
void ldisc_update(void *frontend, int echo, int edit)
{
- /*
- * This is a stub in pterm. If I ever produce a Unix
- * command-line ssh/telnet/rlogin client (i.e. a port of plink)
- * then it will require some termios manoeuvring analogous to
- * that in the Windows plink.c, but here it's meaningless.
- */
}
char *get_ttymode(void *frontend, const char *mode)
gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
- char output[32];
+ char output[256];
wchar_t ucsoutput[2];
- int ucsval, start, end, special, use_ucsoutput;
+ int ucsval, start, end, special, output_charset, use_ucsoutput;
/* Remember the timestamp. */
inst->input_event_time = event->time;
/* By default, nothing is generated. */
end = start = 0;
special = use_ucsoutput = FALSE;
+ output_charset = CS_ISO8859_1;
/*
* If Alt is being released after typing an Alt+numberpad
#ifdef KEY_DEBUGGING
printf("Alt key up, keycode = %d\n", inst->alt_keycode);
#endif
+ /*
+ * FIXME: we might usefully try to do something clever here
+ * about interpreting the generated key code in a way that's
+ * appropriate to the line code page.
+ */
output[0] = inst->alt_keycode;
end = 1;
goto done;
/* ALT+things gives leading Escape. */
output[0] = '\033';
- strncpy(output+1, event->string, 31);
- if (!*event->string &&
+#if !GTK_CHECK_VERSION(2,0,0)
+ /*
+ * In vanilla X, and hence also GDK 1.2, the string received
+ * as part of a keyboard event is assumed to be in
+ * ISO-8859-1. (Seems woefully shortsighted in i18n terms,
+ * but it's true: see the man page for XLookupString(3) for
+ * confirmation.)
+ */
+ output_charset = CS_ISO8859_1;
+ strncpy(output+1, event->string, lenof(output)-1);
+#else
+ /*
+ * GDK 2.0 arranges to have done some translation for us: in
+ * GDK 2.0, event->string is encoded in the current locale.
+ *
+ * (However, it's also deprecated; we really ought to be
+ * using a GTKIMContext.)
+ *
+ * So we use the standard C library function mbstowcs() to
+ * convert from the current locale into Unicode; from there
+ * we can convert to whatever PuTTY is currently working in.
+ * (In fact I convert straight back to UTF-8 from
+ * wide-character Unicode, for the sake of simplicity: that
+ * way we can still use exactly the same code to manipulate
+ * the string, such as prefixing ESC.)
+ */
+ output_charset = CS_UTF8;
+ {
+ wchar_t widedata[32], *wp;
+ int wlen;
+ int ulen;
+
+ wlen = mb_to_wc(DEFAULT_CODEPAGE, 0,
+ event->string, strlen(event->string),
+ widedata, lenof(widedata)-1);
+
+ wp = widedata;
+ ulen = charset_from_unicode(&wp, &wlen, output+1, lenof(output)-2,
+ CS_UTF8, NULL, NULL, 0);
+ output[1+ulen] = '\0';
+ }
+#endif
+
+ if (!output[1] &&
(ucsval = keysym_to_unicode(event->keyval)) >= 0) {
ucsoutput[0] = '\033';
ucsoutput[1] = ucsval;
use_ucsoutput = TRUE;
end = 2;
} else {
- output[31] = '\0';
+ output[lenof(output)-1] = '\0';
end = strlen(output);
}
if (event->state & GDK_MOD1_MASK) {
start = 1;
/* Control-` is the same as Control-\ (unless gtk has a better idea) */
- if (!event->string[0] && event->keyval == '`' &&
+ if (!output[1] && event->keyval == '`' &&
(event->state & GDK_CONTROL_MASK)) {
output[1] = '\x1C';
use_ucsoutput = FALSE;
}
/* Control-2, Control-Space and Control-@ are NUL */
- if (!event->string[0] &&
+ if (!output[1] &&
(event->keyval == ' ' || event->keyval == '2' ||
event->keyval == '@') &&
(event->state & (GDK_SHIFT_MASK |
}
/* Control-Shift-Space is 160 (ISO8859 nonbreaking space) */
- if (!event->string[0] && event->keyval == ' ' &&
+ if (!output[1] && event->keyval == ' ' &&
(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ==
(GDK_SHIFT_MASK | GDK_CONTROL_MASK)) {
output[1] = '\240';
+ output_charset = CS_ISO8859_1;
use_ucsoutput = FALSE;
end = 2;
}
ldisc_send(inst->ldisc, output+start, -2, 1);
} else if (!inst->direct_to_font) {
if (!use_ucsoutput) {
- /*
- * The stuff we've just generated is assumed to be
- * ISO-8859-1! This sounds insane, but `man
- * XLookupString' agrees: strings of this type
- * returned from the X server are hardcoded to
- * 8859-1. Strictly speaking we should be doing
- * this using some sort of GtkIMContext, which (if
- * we're lucky) would give us our data directly in
- * Unicode; but that's not supported in GTK 1.2 as
- * far as I can tell, and it's poorly documented
- * even in 2.0, so it'll have to wait.
- */
if (inst->ldisc)
- lpage_send(inst->ldisc, CS_ISO8859_1, output+start,
+ lpage_send(inst->ldisc, output_charset, output+start,
end-start, 1);
} else {
/*
return TRUE;
}
-gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
+gboolean button_internal(struct gui_data *inst, guint32 timestamp,
+ GdkEventType type, guint ebutton, guint state,
+ gdouble ex, gdouble ey)
{
- struct gui_data *inst = (struct gui_data *)data;
int shift, ctrl, alt, x, y, button, act;
/* Remember the timestamp. */
- inst->input_event_time = event->time;
+ inst->input_event_time = timestamp;
show_mouseptr(inst, 1);
- if (event->button == 4 && event->type == GDK_BUTTON_PRESS) {
+ if (ebutton == 4 && type == GDK_BUTTON_PRESS) {
term_scroll(inst->term, 0, -5);
return TRUE;
}
- if (event->button == 5 && event->type == GDK_BUTTON_PRESS) {
+ if (ebutton == 5 && type == GDK_BUTTON_PRESS) {
term_scroll(inst->term, 0, +5);
return TRUE;
}
- shift = event->state & GDK_SHIFT_MASK;
- ctrl = event->state & GDK_CONTROL_MASK;
- alt = event->state & GDK_MOD1_MASK;
+ shift = state & GDK_SHIFT_MASK;
+ ctrl = state & GDK_CONTROL_MASK;
+ alt = state & GDK_MOD1_MASK;
- if (event->button == 3 && ctrl) {
+ if (ebutton == 3 && ctrl) {
gtk_menu_popup(GTK_MENU(inst->menu), NULL, NULL, NULL, NULL,
- event->button, event->time);
+ ebutton, timestamp);
return TRUE;
}
- if (event->button == 1)
+ if (ebutton == 1)
button = MBT_LEFT;
- else if (event->button == 2)
+ else if (ebutton == 2)
button = MBT_MIDDLE;
- else if (event->button == 3)
+ else if (ebutton == 3)
button = MBT_RIGHT;
else
return FALSE; /* don't even know what button! */
- switch (event->type) {
+ switch (type) {
case GDK_BUTTON_PRESS: act = MA_CLICK; break;
case GDK_BUTTON_RELEASE: act = MA_RELEASE; break;
case GDK_2BUTTON_PRESS: act = MA_2CLK; break;
act != MA_CLICK && act != MA_RELEASE)
return TRUE; /* we ignore these in raw mouse mode */
- x = (event->x - inst->cfg.window_border) / inst->font_width;
- y = (event->y - inst->cfg.window_border) / inst->font_height;
+ x = (ex - inst->cfg.window_border) / inst->font_width;
+ y = (ey - inst->cfg.window_border) / inst->font_height;
term_mouse(inst->term, button, translate_button(button), act,
x, y, shift, ctrl, alt);
return TRUE;
}
+gboolean button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ struct gui_data *inst = (struct gui_data *)data;
+ return button_internal(inst, event->time, event->type, event->button,
+ event->state, event->x, event->y);
+}
+
+#if GTK_CHECK_VERSION(2,0,0)
+/*
+ * In GTK 2, mouse wheel events have become a new type of event.
+ * This handler translates them back into button-4 and button-5
+ * presses so that I don't have to change my old code too much :-)
+ */
+gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data)
+{
+ struct gui_data *inst = (struct gui_data *)data;
+ guint button;
+
+ if (event->direction == GDK_SCROLL_UP)
+ button = 4;
+ else if (event->direction == GDK_SCROLL_DOWN)
+ button = 5;
+ else
+ return FALSE;
+
+ return button_internal(inst, event->time, GDK_BUTTON_PRESS,
+ button, event->state, event->x, event->y);
+}
+#endif
+
gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
{
struct gui_data *inst = (struct gui_data *)data;
exit(0);
}
-void notify_remote_exit(void *frontend)
+static gint idle_exit_func(gpointer data)
{
- struct gui_data *inst = (struct gui_data *)frontend;
+ struct gui_data *inst = (struct gui_data *)data;
int exitcode;
if (!inst->exited &&
term_provide_resize_fn(inst->term, NULL, NULL);
update_specials_menu(inst);
}
- gtk_widget_show(inst->restartitem);
+ gtk_widget_set_sensitive(inst->restartitem, TRUE);
}
+
+ gtk_idle_remove(inst->term_exit_idle_id);
+ return TRUE;
+}
+
+void notify_remote_exit(void *frontend)
+{
+ struct gui_data *inst = (struct gui_data *)frontend;
+
+ inst->term_exit_idle_id = gtk_idle_add(idle_exit_func, inst);
}
static gint timer_trigger(gpointer data)
{
- long now = GPOINTER_TO_INT(data);
+ long now = GPOINTER_TO_SIZE(data);
long next;
long ticks;
if (run_timers(now, &next)) {
ticks = next - GETTICKCOUNT();
timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,
- GINT_TO_POINTER(next));
+ GSIZE_TO_POINTER(next));
}
/*
ticks = 1; /* just in case */
timer_id = gtk_timeout_add(ticks, timer_trigger,
- GINT_TO_POINTER(next));
+ GSIZE_TO_POINTER(next));
}
void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
if (gtk_selection_owner_set(inst->area, GDK_SELECTION_PRIMARY,
inst->input_event_time)) {
+#if GTK_CHECK_VERSION(2,0,0)
+ gtk_selection_clear_targets(inst->area, GDK_SELECTION_PRIMARY);
+#endif
gtk_selection_add_target(inst->area, GDK_SELECTION_PRIMARY,
GDK_SELECTION_TYPE_STRING, 1);
if (inst->pasteout_data_ctext)
(GtkCallback)gtk_widget_destroy, NULL);
get_sesslist(&sesslist, TRUE);
+ /* skip sesslist.sessions[0] == Default Settings */
for (i = 1; i < sesslist.nsessions; i++) {
GtkWidget *menuitem =
gtk_menu_item_new_with_label(sesslist.sessions[i]);
GTK_SIGNAL_FUNC(saved_session_freedata),
inst);
}
+ if (sesslist.nsessions <= 1) {
+ GtkWidget *menuitem =
+ gtk_menu_item_new_with_label("(No sessions)");
+ gtk_widget_set_sensitive(menuitem, FALSE);
+ gtk_container_add(GTK_CONTAINER(inst->sessionsmenu), menuitem);
+ gtk_widget_show(menuitem);
+ }
get_sesslist(&sesslist, FALSE); /* free up */
}
ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle,
inst);
- gtk_widget_hide(inst->restartitem);
+ gtk_widget_set_sensitive(inst->restartitem, FALSE);
}
int pt_main(int argc, char **argv)
GTK_SIGNAL_FUNC(button_event), inst);
gtk_signal_connect(GTK_OBJECT(inst->area), "button_release_event",
GTK_SIGNAL_FUNC(button_event), inst);
+#if GTK_CHECK_VERSION(2,0,0)
+ gtk_signal_connect(GTK_OBJECT(inst->area), "scroll_event",
+ GTK_SIGNAL_FUNC(scroll_event), inst);
+#endif
gtk_signal_connect(GTK_OBJECT(inst->area), "motion_notify_event",
GTK_SIGNAL_FUNC(motion_event), inst);
gtk_signal_connect(GTK_OBJECT(inst->area), "selection_received",
GTK_SIGNAL_FUNC(func), inst); \
} while (0)
if (new_session)
- MKMENUITEM("New Session", new_session_menuitem);
+ MKMENUITEM("New Session...", new_session_menuitem);
MKMENUITEM("Restart Session", restart_session_menuitem);
inst->restartitem = menuitem;
- gtk_widget_hide(inst->restartitem);
+ gtk_widget_set_sensitive(inst->restartitem, FALSE);
MKMENUITEM("Duplicate Session", dup_session_menuitem);
if (saved_sessions) {
inst->sessionsmenu = gtk_menu_new();
inst->sessionsmenu);
}
MKMENUITEM(NULL, NULL);
- MKMENUITEM("Change Settings", change_settings_menuitem);
+ MKMENUITEM("Change Settings...", change_settings_menuitem);
MKMENUITEM(NULL, NULL);
if (use_event_log)
MKMENUITEM("Event Log", event_log_menuitem);