+void set_icon(void *frontend, char *title)
+{
+ struct gui_data *inst = (struct gui_data *)frontend;
+ sfree(inst->icontitle);
+ inst->icontitle = dupstr(title);
+ set_window_titles(inst);
+}
+
+void set_title_and_icon(void *frontend, char *title, char *icon)
+{
+ struct gui_data *inst = (struct gui_data *)frontend;
+ sfree(inst->wintitle);
+ inst->wintitle = dupstr(title);
+ sfree(inst->icontitle);
+ inst->icontitle = dupstr(icon);
+ set_window_titles(inst);
+}
+
+void set_sbar(void *frontend, int total, int start, int page)
+{
+ struct gui_data *inst = (struct gui_data *)frontend;
+ if (!conf_get_int(inst->conf, CONF_scrollbar))
+ return;
+ gtk_adjustment_set_lower(inst->sbar_adjust, 0);
+ gtk_adjustment_set_upper(inst->sbar_adjust, total);
+ gtk_adjustment_set_value(inst->sbar_adjust, start);
+ gtk_adjustment_set_page_size(inst->sbar_adjust, page);
+ gtk_adjustment_set_step_increment(inst->sbar_adjust, 1);
+ gtk_adjustment_set_page_increment(inst->sbar_adjust, page/2);
+ inst->ignore_sbar = TRUE;
+ gtk_adjustment_changed(inst->sbar_adjust);
+ inst->ignore_sbar = FALSE;
+}
+
+void scrollbar_moved(GtkAdjustment *adj, gpointer data)
+{
+ struct gui_data *inst = (struct gui_data *)data;
+
+ if (!conf_get_int(inst->conf, CONF_scrollbar))
+ return;
+ if (!inst->ignore_sbar)
+ term_scroll(inst->term, 1, (int)gtk_adjustment_get_value(adj));
+}
+
+void sys_cursor(void *frontend, int x, int y)
+{
+ /*
+ * This is meaningless under X.
+ */
+}
+
+/*
+ * This is still called when mode==BELL_VISUAL, even though the
+ * visual bell is handled entirely within terminal.c, because we
+ * may want to perform additional actions on any kind of bell (for
+ * example, taskbar flashing in Windows).
+ */
+void do_beep(void *frontend, int mode)
+{
+ if (mode == BELL_DEFAULT)
+ gdk_beep();
+}
+
+int char_width(Context ctx, int uc)
+{
+ /*
+ * In this front end, double-width characters are handled using a
+ * separate font, so this can safely just return 1 always.
+ */
+ return 1;
+}
+
+Context get_ctx(void *frontend)
+{
+ struct gui_data *inst = (struct gui_data *)frontend;
+ struct draw_ctx *dctx;
+
+ if (!gtk_widget_get_window(inst->area))
+ return NULL;
+
+ dctx = snew(struct draw_ctx);
+ dctx->inst = inst;
+ dctx->uctx.type = inst->drawtype;
+#ifdef DRAW_TEXT_GDK
+ if (dctx->uctx.type == DRAWTYPE_GDK) {
+ /* If we're doing GDK-based drawing, then we also expect
+ * inst->pixmap to exist. */
+ dctx->uctx.u.gdk.target = inst->pixmap;
+ dctx->uctx.u.gdk.gc = gdk_gc_new(gtk_widget_get_window(inst->area));
+ }
+#endif
+#ifdef DRAW_TEXT_CAIRO
+ if (dctx->uctx.type == DRAWTYPE_CAIRO) {
+ dctx->uctx.u.cairo.widget = GTK_WIDGET(inst->area);
+ /* If we're doing Cairo drawing, we expect inst->surface to
+ * exist, and we draw to that first, regardless of whether we
+ * subsequently copy the results to inst->pixmap. */
+ dctx->uctx.u.cairo.cr = cairo_create(inst->surface);
+ cairo_setup_dctx(dctx);
+ }
+#endif
+ return dctx;
+}
+
+void free_ctx(Context ctx)
+{
+ struct draw_ctx *dctx = (struct draw_ctx *)ctx;
+ /* struct gui_data *inst = dctx->inst; */
+#ifdef DRAW_TEXT_GDK
+ if (dctx->uctx.type == DRAWTYPE_GDK) {
+ gdk_gc_unref(dctx->uctx.u.gdk.gc);
+ }
+#endif
+#ifdef DRAW_TEXT_CAIRO
+ if (dctx->uctx.type == DRAWTYPE_CAIRO) {
+ cairo_destroy(dctx->uctx.u.cairo.cr);
+ }
+#endif
+ sfree(dctx);
+}
+
+
+static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h)
+{
+#if defined DRAW_TEXT_CAIRO && !defined NO_BACKING_PIXMAPS
+ if (dctx->uctx.type == DRAWTYPE_CAIRO) {
+ /*
+ * If inst->surface and inst->pixmap both exist, then we've
+ * just drawn new content to the former which we must copy to
+ * the latter.
+ */
+ cairo_t *cr = gdk_cairo_create(dctx->inst->pixmap);
+ cairo_set_source_surface(cr, dctx->inst->surface, 0, 0);
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+ }
+#endif
+
+ /*
+ * Now we just queue a window redraw, which will cause
+ * inst->surface or inst->pixmap (whichever is appropriate for our
+ * compile mode) to be copied to the real window when we receive
+ * the resulting "expose" or "draw" event.
+ *
+ * Amazingly, this one API call is actually valid in all versions
+ * of GTK :-)
+ */
+ gtk_widget_queue_draw_area(dctx->inst->area, x, y, w, h);
+}
+
+static void draw_set_colour(struct draw_ctx *dctx, int col)