#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 */
+#define MAY_REFER_TO_GTK_IN_HEADERS
+
#include "putty.h"
#include "terminal.h"
#include "gtkfont.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;
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;
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);
}
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)
{
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);
}
/*
* 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)
}
/* 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)
{
}
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.
/*
* 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;
+ if (inst->ldisc)
+ 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)
{
- 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);
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! */
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;
* 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 &&
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)
{
- long now = GPOINTER_TO_LONG(data);
- long next;
+ unsigned long now = GPOINTER_TO_LONG(data);
+ unsigned long next, then;
long ticks;
- if (run_timers(now, &next)) {
- ticks = next - GETTICKCOUNT();
- timer_id = gtk_timeout_add(ticks > 0 ? ticks : 1, timer_trigger,
+ /*
+ * 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)
+ ticks = 0;
+ else
+ ticks = next - now;
+ timer_id = gtk_timeout_add(ticks, timer_trigger,
LONG_TO_GPOINTER(next));
}
/*
- * 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;
}
-void timer_change_notify(long next)
+void timer_change_notify(unsigned long next)
{
long ticks;
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) {
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;
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)
}
}
+static void version(FILE *fp) {
+ if(fprintf(fp, "%s: %s\n", appname, ver) < 0 || fflush(fp) < 0) {
+ perror("output error");
+ exit(1);
+ }
+}
+
int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
struct gui_data *inst, Conf *conf)
{
}
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;
help(stdout);
exit(0);
+ } else if(!strcmp(p, "-version") || !strcmp(p, "--version")) {
+ version(stdout);
+ exit(0);
+
} else if (!strcmp(p, "-pgpfp")) {
pgp_fingerprints();
exit(1);
gdk_input_remove(id);
}
-void setup_fonts_ucs(struct gui_data *inst)
+char *setup_fonts_ucs(struct gui_data *inst)
{
int shadowbold = conf_get_int(inst->conf, CONF_shadowbold);
int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset);
FontSpec *fs;
-
- if (inst->fonts[0])
- unifont_destroy(inst->fonts[0]);
- if (inst->fonts[1])
- unifont_destroy(inst->fonts[1]);
- if (inst->fonts[2])
- unifont_destroy(inst->fonts[2]);
- if (inst->fonts[3])
- unifont_destroy(inst->fonts[3]);
+ unifont *fonts[4];
+ int i;
fs = conf_get_fontspec(inst->conf, CONF_font);
- inst->fonts[0] = unifont_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);
- exit(1);
+ fonts[0] = multifont_create(inst->area, fs->name, FALSE, FALSE,
+ shadowboldoffset, shadowbold);
+ if (!fonts[0]) {
+ return dupprintf("unable to load font \"%s\"", fs->name);
}
fs = conf_get_fontspec(inst->conf, CONF_boldfont);
if (shadowbold || !fs->name[0]) {
- inst->fonts[1] = NULL;
+ fonts[1] = NULL;
} else {
- inst->fonts[1] = unifont_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);
- exit(1);
+ fonts[1] = multifont_create(inst->area, fs->name, FALSE, TRUE,
+ shadowboldoffset, shadowbold);
+ if (!fonts[1]) {
+ if (fonts[0])
+ unifont_destroy(fonts[0]);
+ return dupprintf("unable to load bold font \"%s\"", 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);
- if (!inst->fonts[2]) {
- fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname,
- fs->name);
- exit(1);
+ fonts[2] = multifont_create(inst->area, fs->name, TRUE, FALSE,
+ shadowboldoffset, shadowbold);
+ if (!fonts[2]) {
+ for (i = 0; i < 2; i++)
+ if (fonts[i])
+ unifont_destroy(fonts[i]);
+ return dupprintf("unable to load wide font \"%s\"", fs->name);
}
} else {
- inst->fonts[2] = NULL;
+ fonts[2] = NULL;
}
fs = conf_get_fontspec(inst->conf, CONF_wideboldfont);
if (shadowbold || !fs->name[0]) {
- inst->fonts[3] = NULL;
+ fonts[3] = NULL;
} else {
- inst->fonts[3] = unifont_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);
- exit(1);
+ fonts[3] = multifont_create(inst->area, fs->name, TRUE, TRUE,
+ shadowboldoffset, shadowbold);
+ if (!fonts[3]) {
+ for (i = 0; i < 3; i++)
+ if (fonts[i])
+ unifont_destroy(fonts[i]);
+ return dupprintf("unable to load wide bold font \"%s\"", fs->name);
}
}
+ /*
+ * Now we've got past all the possible error conditions, we can
+ * actually update our state.
+ */
+
+ for (i = 0; i < 4; i++) {
+ if (inst->fonts[i])
+ unifont_destroy(inst->fonts[i]);
+ inst->fonts[i] = fonts[i];
+ }
+
inst->font_width = inst->fonts[0]->width;
inst->font_height = inst->fonts[0]->height;
conf_get_int(inst->conf, CONF_utf8_override),
inst->fonts[0]->public_charset,
conf_get_int(inst->conf, CONF_vtmode));
+
+ return NULL;
}
void set_geom_hints(struct gui_data *inst)
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)
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;
else
inst->reconfiguring = TRUE;
+ title = dupcat(appname, " Reconfiguration", NULL);
+
oldconf = inst->conf;
newconf = conf_copy(inst->conf);
* 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 */
* 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);
}
* Redo the whole tangled fonts and Unicode mess if
* necessary.
*/
+ need_size = FALSE;
if (strcmp(conf_get_fontspec(oldconf, CONF_font)->name,
conf_get_fontspec(newconf, CONF_font)->name) ||
strcmp(conf_get_fontspec(oldconf, CONF_boldfont)->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) !=
conf_get_int(newconf, CONF_shadowbold) ||
conf_get_int(oldconf, CONF_shadowboldoffset) !=
conf_get_int(newconf, CONF_shadowboldoffset)) {
- setup_fonts_ucs(inst);
- need_size = 1;
- } else
- need_size = 0;
+ char *errmsg = setup_fonts_ucs(inst);
+ if (errmsg) {
+ char *msgboxtext =
+ dupprintf("Could not change fonts in terminal window: %s\n",
+ errmsg);
+ messagebox(inst->window, "Font setup error", msgboxtext,
+ string_width("Could not change fonts in terminal window:"),
+ "OK", 'o', +1, 1,
+ NULL);
+ sfree(msgboxtext);
+ sfree(errmsg);
+ } else {
+ need_size = TRUE;
+ }
+ }
/*
* Resize the window.
pid = fork();
if (pid < 0) {
perror("fork");
+ sfree(args);
return;
}
} else {
int status;
+ sfree(args);
waitpid(pid, &status, 0);
}
}
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]);
}
}
+ sfree(data);
+
return 0;
}
extern int cfgbox(Conf *conf);
struct gui_data *inst;
+ setlocale(LC_CTYPE, "");
+
/*
* Create an instance structure and initialise to zeroes
*/
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 */
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();
- setup_fonts_ucs(inst);
+#if GTK_CHECK_VERSION(2,0,0)
+ inst->imc = gtk_im_multicontext_new();
+#endif
+
+ {
+ char *errmsg = setup_fonts_ucs(inst);
+ if (errmsg) {
+ fprintf(stderr, "%s: %s\n", appname, errmsg);
+ exit(1);
+ }
+ }
init_cutbuffers();
inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
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);
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);
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 */