#include <stdio.h>
#include <time.h>
#include <errno.h>
+#include <locale.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
+#if GTK_CHECK_VERSION(2,0,0)
+#include <gtk/gtkimmodule.h>
+#endif
+
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
*restartitem;
GtkWidget *sessionsmenu;
GdkPixmap *pixmap;
+#if GTK_CHECK_VERSION(2,0,0)
+ GtkIMContext *imc;
+#endif
unifont *fonts[4]; /* normal, bold, wide, widebold */
int xpos, ypos, gotpos, gravity;
GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor;
guint32 input_event_time; /* Timestamp of the most recent input event. */
int reconfiguring;
/* Cached things out of conf that we refer to a lot */
- int bold_colour;
+ int bold_style;
int window_border;
int cursor_type;
};
static void cache_conf_values(struct gui_data *inst)
{
- inst->bold_colour = conf_get_int(inst->conf, CONF_bold_colour);
+ inst->bold_style = conf_get_int(inst->conf, CONF_bold_style);
inst->window_border = conf_get_int(inst->conf, CONF_window_border);
inst->cursor_type = conf_get_int(inst->conf, CONF_cursor_type);
}
/*
* Default settings that are specific to pterm.
*/
-FontSpec platform_default_fontspec(const char *name)
+FontSpec *platform_default_fontspec(const char *name)
{
- FontSpec ret;
if (!strcmp(name, "Font"))
- strcpy(ret.name, "server:fixed");
+ return fontspec_new("server:fixed");
else
- *ret.name = '\0';
- return ret;
+ return fontspec_new("");
}
-Filename platform_default_filename(const char *name)
+Filename *platform_default_filename(const char *name)
{
- Filename ret;
if (!strcmp(name, "LogFileName"))
- strcpy(ret.path, "putty.log");
+ return filename_from_str("putty.log");
else
- *ret.path = '\0';
- return ret;
+ return filename_from_str("");
}
char *platform_default_s(const char *name)
if (inst->term)
term_invalidate(inst->term);
+#if GTK_CHECK_VERSION(2,0,0)
+ gtk_im_context_set_client_window(inst->imc, widget->window);
+#endif
+
return TRUE;
}
char output[256];
wchar_t ucsoutput[2];
int ucsval, start, end, special, output_charset, use_ucsoutput;
+ int nethack_mode, app_keypad_mode;
/* Remember the timestamp. */
inst->input_event_time = event->time;
* inconvenience in having to type a zero before a single-digit
* character code.
*/
- if (event->type == GDK_KEY_RELEASE &&
- (event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L ||
- event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) &&
- inst->alt_keycode >= 0 && inst->alt_digits > 1) {
+ if (event->type == GDK_KEY_RELEASE) {
+ if ((event->keyval == GDK_Meta_L || event->keyval == GDK_Alt_L ||
+ event->keyval == GDK_Meta_R || event->keyval == GDK_Alt_R) &&
+ inst->alt_keycode >= 0 && inst->alt_digits > 1) {
#ifdef KEY_DEBUGGING
- printf("Alt key up, keycode = %d\n", inst->alt_keycode);
+ 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;
+ }
+#if GTK_CHECK_VERSION(2,0,0)
+ if (gtk_im_context_filter_keypress(inst->imc, event))
+ return TRUE;
#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;
}
if (event->type == GDK_KEY_PRESS) {
special = FALSE;
use_ucsoutput = FALSE;
+ nethack_mode = conf_get_int(inst->conf, CONF_nethack_keypad);
+ app_keypad_mode = (inst->term->app_keypad_keys &&
+ !conf_get_int(inst->conf, CONF_no_applic_k));
+
/* ALT+things gives leading Escape. */
output[0] = '\033';
#if !GTK_CHECK_VERSION(2,0,0)
output_charset = CS_ISO8859_1;
strncpy(output+1, event->string, lenof(output)-1);
#else
+ /*
+ * Most things can now be passed to
+ * gtk_im_context_filter_keypress without breaking anything
+ * below this point. An exception is the numeric keypad if
+ * we're in Nethack or application mode: the IM will eat
+ * numeric keypad presses if Num Lock is on, but we don't want
+ * it to.
+ */
+ if (app_keypad_mode &&
+ (event->keyval == GDK_Num_Lock ||
+ event->keyval == GDK_KP_Divide ||
+ event->keyval == GDK_KP_Multiply ||
+ event->keyval == GDK_KP_Subtract ||
+ event->keyval == GDK_KP_Add ||
+ event->keyval == GDK_KP_Enter ||
+ event->keyval == GDK_KP_0 ||
+ event->keyval == GDK_KP_Insert ||
+ event->keyval == GDK_KP_1 ||
+ event->keyval == GDK_KP_End ||
+ event->keyval == GDK_KP_2 ||
+ event->keyval == GDK_KP_Down ||
+ event->keyval == GDK_KP_3 ||
+ event->keyval == GDK_KP_Page_Down ||
+ event->keyval == GDK_KP_4 ||
+ event->keyval == GDK_KP_Left ||
+ event->keyval == GDK_KP_5 ||
+ event->keyval == GDK_KP_Begin ||
+ event->keyval == GDK_KP_6 ||
+ event->keyval == GDK_KP_Right ||
+ event->keyval == GDK_KP_7 ||
+ event->keyval == GDK_KP_Home ||
+ event->keyval == GDK_KP_8 ||
+ event->keyval == GDK_KP_Up ||
+ event->keyval == GDK_KP_9 ||
+ event->keyval == GDK_KP_Page_Up ||
+ event->keyval == GDK_KP_Decimal ||
+ event->keyval == GDK_KP_Delete)) {
+ /* app keypad; do nothing */
+ } else if (nethack_mode &&
+ (event->keyval == GDK_KP_1 ||
+ event->keyval == GDK_KP_End ||
+ event->keyval == GDK_KP_2 ||
+ event->keyval == GDK_KP_Down ||
+ event->keyval == GDK_KP_3 ||
+ event->keyval == GDK_KP_Page_Down ||
+ event->keyval == GDK_KP_4 ||
+ event->keyval == GDK_KP_Left ||
+ event->keyval == GDK_KP_5 ||
+ event->keyval == GDK_KP_Begin ||
+ event->keyval == GDK_KP_6 ||
+ event->keyval == GDK_KP_Right ||
+ event->keyval == GDK_KP_7 ||
+ event->keyval == GDK_KP_Home ||
+ event->keyval == GDK_KP_8 ||
+ event->keyval == GDK_KP_Up ||
+ event->keyval == GDK_KP_9 ||
+ event->keyval == GDK_KP_Page_Up)) {
+ /* nethack mode; do nothing */
+ } else {
+ if (gtk_im_context_filter_keypress(inst->imc, event))
+ return TRUE;
+ }
+
/*
* 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.
*/
output_charset = CS_UTF8;
{
- wchar_t widedata[32], *wp;
+ wchar_t widedata[32];
+ const wchar_t *wp;
int wlen;
int ulen;
/*
* NetHack keypad mode.
*/
- if (conf_get_int(inst->conf, CONF_nethack_keypad)) {
+ if (nethack_mode) {
char *keys = NULL;
switch (event->keyval) {
case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break;
/*
* Application keypad mode.
*/
- if (inst->term->app_keypad_keys &&
- !conf_get_int(inst->conf, CONF_no_applic_k)) {
+ if (app_keypad_mode) {
int xkey = 0;
switch (event->keyval) {
case GDK_Num_Lock: xkey = 'P'; break;
return TRUE;
}
+#if GTK_CHECK_VERSION(2,0,0)
+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);
+ show_mouseptr(inst, 0);
+ term_seen_key_event(inst->term);
+}
+#endif
+
gboolean button_internal(struct gui_data *inst, guint32 timestamp,
GdkEventType type, guint ebutton, guint state,
gdouble ex, gdouble ey)
* if we aren't in direct-to-font mode using the D800 hack.
*/
if (!inst->direct_to_font) {
- wchar_t *tmp = data;
+ const wchar_t *tmp = data;
int tmplen = len;
XTextProperty tp;
char *list[1];
nfg = nbg;
nbg = t;
}
- if (inst->bold_colour && (attr & ATTR_BOLD)) {
+ if ((inst->bold_style & 2) && (attr & ATTR_BOLD)) {
if (nfg < 16) nfg |= 8;
else if (nfg >= 256) nfg |= 1;
}
- if (inst->bold_colour && (attr & ATTR_BLINK)) {
+ if ((inst->bold_style & 2) && (attr & ATTR_BLINK)) {
if (nbg < 16) nbg |= 8;
else if (nbg >= 256) nbg |= 1;
}
widefactor = 1;
}
- if ((attr & ATTR_BOLD) && !inst->bold_colour) {
+ if ((attr & ATTR_BOLD) && (inst->bold_style & 1)) {
bold = 1;
fontid |= 1;
} else {
rlen*widefactor*inst->font_width, inst->font_height);
gdk_gc_set_foreground(gc, &inst->cols[nfg]);
- {
- gchar *gcs;
-
- /*
- * FIXME: this length is hardwired on the assumption that
- * conversions from wide to multibyte characters will
- * never generate more than 10 bytes for a single wide
- * character.
- */
- gcs = snewn(len*10+1, gchar);
-
- for (combining = 0; combining < ncombining; combining++) {
- int mblen = wc_to_mb(inst->fonts[fontid]->real_charset, 0,
- text + combining, len, gcs, len*10+1, ".",
- NULL, NULL);
- unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid],
- x*inst->font_width+inst->window_border,
- y*inst->font_height+inst->window_border+inst->fonts[0]->ascent,
- gcs, mblen, widefactor > 1, bold, inst->font_width);
- }
-
- sfree(gcs);
+ for (combining = 0; combining < ncombining; combining++) {
+ unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid],
+ x*inst->font_width+inst->window_border,
+ y*inst->font_height+inst->window_border+inst->fonts[0]->ascent,
+ text + combining, len, widefactor > 1,
+ bold, inst->font_width);
}
if (attr & ATTR_UNDER) {
x*inst->font_width+inst->window_border,
y*inst->font_height+inst->window_border,
len*widefactor*inst->font_width, inst->font_height);
+
+#if GTK_CHECK_VERSION(2,0,0)
+ {
+ GdkRectangle cursorrect;
+ cursorrect.x = x*inst->font_width+inst->window_border;
+ cursorrect.y = y*inst->font_height+inst->window_border;
+ cursorrect.width = len*widefactor*inst->font_width;
+ cursorrect.height = inst->font_height;
+ gtk_im_context_set_cursor_location(inst->imc, &cursorrect);
+ }
+#endif
}
GdkCursor *make_mouse_ptr(struct gui_data *inst, int cursor_val)
}
if (!strcmp(p, "-fn") || !strcmp(p, "-font")) {
- FontSpec fs;
+ FontSpec *fs;
EXPECTS_ARG;
SECOND_PASS_ONLY;
- strncpy(fs.name, val, sizeof(fs.name));
- fs.name[sizeof(fs.name)-1] = '\0';
- conf_set_fontspec(conf, CONF_font, &fs);
+ fs = fontspec_new(val);
+ conf_set_fontspec(conf, CONF_font, fs);
+ fontspec_free(fs);
} else if (!strcmp(p, "-fb")) {
- FontSpec fs;
+ FontSpec *fs;
EXPECTS_ARG;
SECOND_PASS_ONLY;
- strncpy(fs.name, val, sizeof(fs.name));
- fs.name[sizeof(fs.name)-1] = '\0';
- conf_set_fontspec(conf, CONF_boldfont, &fs);
+ fs = fontspec_new(val);
+ conf_set_fontspec(conf, CONF_boldfont, fs);
+ fontspec_free(fs);
} else if (!strcmp(p, "-fw")) {
- FontSpec fs;
+ FontSpec *fs;
EXPECTS_ARG;
SECOND_PASS_ONLY;
- strncpy(fs.name, val, sizeof(fs.name));
- fs.name[sizeof(fs.name)-1] = '\0';
- conf_set_fontspec(conf, CONF_widefont, &fs);
+ fs = fontspec_new(val);
+ conf_set_fontspec(conf, CONF_widefont, fs);
+ fontspec_free(fs);
} else if (!strcmp(p, "-fwb")) {
- FontSpec fs;
+ FontSpec *fs;
EXPECTS_ARG;
SECOND_PASS_ONLY;
- strncpy(fs.name, val, sizeof(fs.name));
- fs.name[sizeof(fs.name)-1] = '\0';
- conf_set_fontspec(conf, CONF_wideboldfont, &fs);
+ fs = fontspec_new(val);
+ conf_set_fontspec(conf, CONF_wideboldfont, fs);
+ fontspec_free(fs);
} else if (!strcmp(p, "-cs")) {
EXPECTS_ARG;
conf_set_str(conf, CONF_wintitle, val);
} else if (!strcmp(p, "-log")) {
- Filename fn;
+ Filename *fn;
EXPECTS_ARG;
SECOND_PASS_ONLY;
- strncpy(fn.path, val, sizeof(fn.path));
- fn.path[sizeof(fn.path)-1] = '\0';
- conf_set_filename(conf, CONF_logfilename, &fn);
+ fn = filename_from_str(val);
+ conf_set_filename(conf, CONF_logfilename, fn);
conf_set_int(conf, CONF_logtype, LGTYP_DEBUG);
+ filename_free(fn);
} else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) {
SECOND_PASS_ONLY;
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);
+ }
+}
+
void setup_fonts_ucs(struct gui_data *inst)
{
int shadowbold = conf_get_int(inst->conf, CONF_shadowbold);
unifont_destroy(inst->fonts[3]);
fs = conf_get_fontspec(inst->conf, CONF_font);
- inst->fonts[0] = unifont_create(inst->area, fs->name, FALSE, FALSE,
- shadowboldoffset, shadowbold);
+ inst->fonts[0] = multifont_create(inst->area, fs->name, FALSE, FALSE,
+ shadowboldoffset, shadowbold);
if (!inst->fonts[0]) {
fprintf(stderr, "%s: unable to load font \"%s\"\n", appname,
fs->name);
if (shadowbold || !fs->name[0]) {
inst->fonts[1] = NULL;
} else {
- inst->fonts[1] = unifont_create(inst->area, fs->name, FALSE, TRUE,
- shadowboldoffset, shadowbold);
+ inst->fonts[1] = multifont_create(inst->area, fs->name, FALSE, TRUE,
+ shadowboldoffset, shadowbold);
if (!inst->fonts[1]) {
fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname,
fs->name);
fs = conf_get_fontspec(inst->conf, CONF_widefont);
if (fs->name[0]) {
- inst->fonts[2] = unifont_create(inst->area, fs->name, TRUE, FALSE,
- shadowboldoffset, shadowbold);
+ inst->fonts[2] = multifont_create(inst->area, fs->name, TRUE, FALSE,
+ shadowboldoffset, shadowbold);
if (!inst->fonts[2]) {
fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname,
fs->name);
if (shadowbold || !fs->name[0]) {
inst->fonts[3] = NULL;
} else {
- inst->fonts[3] = unifont_create(inst->area, fs->name, TRUE, TRUE,
- shadowboldoffset, shadowbold);
+ inst->fonts[3] = multifont_create(inst->area, fs->name, TRUE, TRUE,
+ shadowboldoffset, shadowbold);
if (!inst->fonts[3]) {
fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname,
fs->name);
conf_get_fontspec(newconf, CONF_wideboldfont)->name) ||
strcmp(conf_get_str(oldconf, CONF_line_codepage),
conf_get_str(newconf, CONF_line_codepage)) ||
+ conf_get_int(oldconf, CONF_utf8_override) !=
+ conf_get_int(newconf, CONF_utf8_override) ||
conf_get_int(oldconf, CONF_vtmode) !=
conf_get_int(newconf, CONF_vtmode) ||
conf_get_int(oldconf, CONF_shadowbold) !=
extern int cfgbox(Conf *conf);
struct gui_data *inst;
+ setlocale(LC_CTYPE, "");
+
/*
* Create an instance structure and initialise to zeroes
*/
if (argc > 1 && !strncmp(argv[1], "---", 3)) {
read_dupsession_data(inst, inst->conf, argv[1]);
/* Splatter this argument so it doesn't clutter a ps listing */
- memset(argv[1], 0, strlen(argv[1]));
+ smemclr(argv[1], strlen(argv[1]));
} else {
/* By default, we bring up the config dialog, rather than launching
* a session. This gets set to TRUE if something happens to change
inst->area = gtk_drawing_area_new();
+#if GTK_CHECK_VERSION(2,0,0)
+ inst->imc = gtk_im_multicontext_new();
+#endif
+
setup_fonts_ucs(inst);
init_cutbuffers();
GTK_SIGNAL_FUNC(selection_get), inst);
gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event",
GTK_SIGNAL_FUNC(selection_clear), inst);
+#if GTK_CHECK_VERSION(2,0,0)
+ g_signal_connect(G_OBJECT(inst->imc), "commit",
+ G_CALLBACK(input_method_commit_event), inst);
+#endif
if (conf_get_int(inst->conf, CONF_scrollbar))
gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",
GTK_SIGNAL_FUNC(scrollbar_moved), inst);