Add the missing code to treat data coming from the input method as
[u/mdw/putty] / unix / gtkwin.c
index 303052a..e72664a 100644 (file)
@@ -13,6 +13,7 @@
 #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"
@@ -68,6 +73,9 @@ struct gui_data {
        *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;
@@ -104,14 +112,14 @@ struct gui_data {
     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);
 }
@@ -151,24 +159,20 @@ void connection_fatal(void *frontend, char *p, ...)
 /*
  * 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)
@@ -493,6 +497,10 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
     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;
 }
 
@@ -543,21 +551,26 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
      * 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) {
@@ -673,13 +686,13 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
        output_charset = CS_ISO8859_1;
        strncpy(output+1, event->string, lenof(output)-1);
 #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.
@@ -1140,6 +1153,16 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
     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)
@@ -2065,11 +2088,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
        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;
     }
@@ -2087,7 +2110,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
        widefactor = 1;
     }
 
-    if ((attr & ATTR_BOLD) && !inst->bold_colour) {
+    if ((attr & ATTR_BOLD) && (inst->bold_style & 1)) {
        bold = 1;
        fontid |= 1;
     } else {
@@ -2138,28 +2161,12 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
                       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) {
@@ -2348,6 +2355,17 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
                    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)
@@ -2557,36 +2575,36 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
         }
 
        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;
@@ -2666,13 +2684,13 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
            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;
@@ -2745,6 +2763,24 @@ 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);
+    }
+}
+
 void setup_fonts_ucs(struct gui_data *inst)
 {
     int shadowbold = conf_get_int(inst->conf, CONF_shadowbold);
@@ -2761,8 +2797,8 @@ void setup_fonts_ucs(struct gui_data *inst)
         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);
@@ -2773,8 +2809,8 @@ void setup_fonts_ucs(struct gui_data *inst)
     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);
@@ -2784,8 +2820,8 @@ void setup_fonts_ucs(struct gui_data *inst)
 
     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);
@@ -2799,8 +2835,8 @@ void setup_fonts_ucs(struct gui_data *inst)
     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);
@@ -2991,6 +3027,8 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data)
                   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) !=
@@ -3446,6 +3484,8 @@ int pt_main(int argc, char **argv)
     extern int cfgbox(Conf *conf);
     struct gui_data *inst;
 
+    setlocale(LC_CTYPE, "");
+
     /*
      * Create an instance structure and initialise to zeroes
      */
@@ -3507,6 +3547,10 @@ int pt_main(int argc, char **argv)
 
     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();
 
@@ -3597,6 +3641,10 @@ int pt_main(int argc, char **argv)
                       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);