]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - unix/gtkwin.c
Use new GTK3 API call for server-controlled window resize.
[PuTTY.git] / unix / gtkwin.c
index 4062816c7f82f01feac24a6fa0f92c4c35568be7..90e7d52b3218cab599a55090ca632912eb06a53d 100644 (file)
@@ -93,7 +93,9 @@ struct gui_data {
 #endif
     GdkCursor *rawcursor, *textcursor, *blankcursor, *waitcursor, *currcursor;
     GdkColor cols[NALLCOLOURS];
+#if !GTK_CHECK_VERSION(3,0,0)
     GdkColormap *colmap;
+#endif
     wchar_t *pastein_data;
     int direct_to_font;
     int pastein_data_len;
@@ -153,7 +155,8 @@ static void exit_callback(void *vinst);
 char *x_get_default(const char *key)
 {
 #ifndef NOT_X_WINDOWS
-    return XGetDefault(GDK_DISPLAY(), app_name, key);
+    return XGetDefault(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
+                       app_name, key);
 #else
     return NULL;
 #endif
@@ -520,6 +523,66 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
     return TRUE;
 }
 
+#ifdef DRAW_TEXT_CAIRO
+static void cairo_setup_dctx(struct draw_ctx *dctx)
+{
+    cairo_get_matrix(dctx->uctx.u.cairo.cr,
+                     &dctx->uctx.u.cairo.origmatrix);
+    cairo_set_line_width(dctx->uctx.u.cairo.cr, 1.0);
+    cairo_set_line_cap(dctx->uctx.u.cairo.cr, CAIRO_LINE_CAP_SQUARE);
+    cairo_set_line_join(dctx->uctx.u.cairo.cr, CAIRO_LINE_JOIN_MITER);
+    /* This antialiasing setting appears to be ignored for Pango
+     * font rendering but honoured for stroking and filling paths;
+     * I don't quite understand the logic of that, but I won't
+     * complain since it's exactly what I happen to want */
+    cairo_set_antialias(dctx->uctx.u.cairo.cr, CAIRO_ANTIALIAS_NONE);
+}
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+    struct gui_data *inst = (struct gui_data *)data;
+
+    if (inst->term) {
+        struct draw_ctx adctx, *dctx = &adctx;
+        GdkRectangle dirtyrect;
+
+        dctx->inst = inst;
+        dctx->uctx.type = DRAWTYPE_CAIRO;
+        dctx->uctx.u.cairo.widget = widget;
+        dctx->uctx.u.cairo.cr = cr;
+        cairo_setup_dctx(dctx);
+
+        gdk_cairo_get_clip_rectangle(cr, &dirtyrect);
+
+        /*
+         * As in window.c, we clear the 'immediately' flag in the
+         * term_paint() call if the terminal has an update pending, in
+         * case we're constrained within this event to only draw on
+         * the exposed rectangle of the window. (Because if the whole
+         * of a character cell needs a redraw due to a terminal
+         * contents change, the last thing we want is to give it a
+         * _partial_ redraw here due to system-imposed clipping, and
+         * then have the next main terminal update believe it's been
+         * redrawn in full.)
+         *
+         * I don't actually know if GTK draw events will constrain us
+         * in this way, but it's best to be careful...
+         */
+        term_paint(inst->term, dctx,
+                   (dirtyrect.x - inst->window_border) / inst->font_width,
+                   (dirtyrect.y - inst->window_border) / inst->font_height,
+                   (dirtyrect.x + dirtyrect.width -
+                    inst->window_border) / inst->font_width,
+                   (dirtyrect.y + dirtyrect.height -
+                    inst->window_border) / inst->font_height,
+                   !inst->term->window_update_pending);
+    }
+
+    return TRUE;
+}
+#else
 gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
 {
     struct gui_data *inst = (struct gui_data *)data;
@@ -541,20 +604,6 @@ gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
 #else
     if (inst->term) {
         Context ctx = get_ctx(inst);
-        /*
-         * As in window.c, we clear the 'immediately' flag in the
-         * term_paint() call if the terminal has an update pending, in
-         * case we're constrained within this event to only draw on
-         * the exposed rectangle of the window. (Because if the whole
-         * of a character cell needs a redraw due to a terminal
-         * contents change, the last thing we want is to give it a
-         * _partial_ redraw here due to system-imposed clipping, and
-         * then have the next main terminal update believe it's been
-         * redrawn in full.)
-         *
-         * I don't actually know if GTK expose events will constrain
-         * us in this way, but it's best to be careful...
-         */
         term_paint(inst->term, ctx,
                    (event->area.x - inst->window_border) / inst->font_width,
                    (event->area.y - inst->window_border) / inst->font_height,
@@ -569,6 +618,7 @@ gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
 
     return TRUE;
 }
+#endif
 
 #define KEY_PRESSED(k) \
     (inst->keystate[(k) / 32] & (1 << ((k) % 32)))
@@ -1631,13 +1681,28 @@ void timer_change_notify(unsigned long next)
     timer_id = g_timeout_add(ticks, timer_trigger, LONG_TO_GPOINTER(next));
 }
 
-void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
+#if GTK_CHECK_VERSION(2,0,0)
+gboolean fd_input_func(GIOChannel *source, GIOCondition condition,
+                       gpointer data)
 {
+    int sourcefd = g_io_channel_unix_get_fd(source);
     /*
      * We must process exceptional notifications before ordinary
      * readability ones, or we may go straight past the urgent
      * marker.
      */
+    if (condition & G_IO_PRI)
+        select_result(sourcefd, 4);
+    if (condition & G_IO_IN)
+        select_result(sourcefd, 1);
+    if (condition & G_IO_OUT)
+        select_result(sourcefd, 2);
+
+    return TRUE;
+}
+#else
+void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
+{
     if (condition & GDK_INPUT_EXCEPTION)
         select_result(sourcefd, 4);
     if (condition & GDK_INPUT_READ)
@@ -1645,6 +1710,7 @@ void fd_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
     if (condition & GDK_INPUT_WRITE)
         select_result(sourcefd, 2);
 }
+#endif
 
 void destroy(GtkWidget *widget, gpointer data)
 {
@@ -1681,6 +1747,9 @@ void set_raw_mouse_mode(void *frontend, int activate)
 void request_resize(void *frontend, int w, int h)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
+
+#if !GTK_CHECK_VERSION(3,0,0)
+
     int large_x, large_y;
     int offset_x, offset_y;
     int area_x, area_y;
@@ -1753,31 +1822,64 @@ void request_resize(void *frontend, int w, int h)
     gdk_window_resize(gtk_widget_get_window(inst->window),
                      area_x + offset_x, area_y + offset_y);
 #endif
+
+#else /* GTK_CHECK_VERSION(3,0,0) */
+
+    /*
+     * In GTK3, we can do this by using gtk_window_resize_to_geometry,
+     * which uses the fact that we've already set up the main window's
+     * WM hints to reflect the terminal drawing area's resize
+     * increment (i.e. character cell) and the fixed amount of stuff
+     * round the edges.
+     */
+    gtk_window_resize_to_geometry(GTK_WINDOW(inst->window), w, h);
+
+#endif
+
 }
 
 static void real_palette_set(struct gui_data *inst, int n, int r, int g, int b)
 {
-    gboolean success[1];
-
     inst->cols[n].red = r * 0x0101;
     inst->cols[n].green = g * 0x0101;
     inst->cols[n].blue = b * 0x0101;
 
-    gdk_colormap_free_colors(inst->colmap, inst->cols + n, 1);
-    gdk_colormap_alloc_colors(inst->colmap, inst->cols + n, 1,
-                             FALSE, TRUE, success);
-    if (!success[0])
-       g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", appname,
-               n, r, g, b);
+#if !GTK_CHECK_VERSION(3,0,0)
+    {
+        gboolean success[1];
+        gdk_colormap_free_colors(inst->colmap, inst->cols + n, 1);
+        gdk_colormap_alloc_colors(inst->colmap, inst->cols + n, 1,
+                                  FALSE, TRUE, success);
+        if (!success[0])
+            g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n",
+                    appname, n, r, g, b);
+    }
+#endif
+}
+
+void set_gdk_window_background(GdkWindow *win, const GdkColor *col)
+{
+#if GTK_CHECK_VERSION(3,0,0)
+    /* gdk_window_set_background is deprecated; work around its
+     * absence. */
+    GdkRGBA rgba;
+    rgba.red = col->red / 65535.0;
+    rgba.green = col->green / 65535.0;
+    rgba.blue = col->blue / 65535.0;
+    rgba.alpha = 1.0;
+    gdk_window_set_background_rgba(win, &rgba);
+#else
+    gdk_window_set_background(win, col);
+#endif
 }
 
 void set_window_background(struct gui_data *inst)
 {
     if (inst->area && gtk_widget_get_window(inst->area))
-       gdk_window_set_background(gtk_widget_get_window(inst->area),
+       set_gdk_window_background(gtk_widget_get_window(inst->area),
                                   &inst->cols[258]);
     if (inst->window && gtk_widget_get_window(inst->window))
-       gdk_window_set_background(gtk_widget_get_window(inst->window),
+       set_gdk_window_background(gtk_widget_get_window(inst->window),
                                   &inst->cols[258]);
 }
 
@@ -1807,16 +1909,17 @@ void palette_reset(void *frontend)
        0, 8, 1, 9, 2, 10, 3, 11,
        4, 12, 5, 13, 6, 14, 7, 15
     };
-    gboolean success[NALLCOLOURS];
     int i;
 
     assert(lenof(ww) == NCFGCOLOURS);
 
+#if !GTK_CHECK_VERSION(3,0,0)
     if (!inst->colmap) {
        inst->colmap = gdk_colormap_get_system();
     } else {
        gdk_colormap_free_colors(inst->colmap, inst->cols, NALLCOLOURS);
     }
+#endif
 
     for (i = 0; i < NCFGCOLOURS; i++) {
        inst->cols[ww[i]].red =
@@ -1841,16 +1944,21 @@ void palette_reset(void *frontend)
        }
     }
 
-    gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS,
-                             FALSE, TRUE, success);
-    for (i = 0; i < NALLCOLOURS; i++) {
-       if (!success[i])
-           g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n",
-                    appname, i,
-                   conf_get_int_int(inst->conf, CONF_colours, i*3+0),
-                   conf_get_int_int(inst->conf, CONF_colours, i*3+1),
-                   conf_get_int_int(inst->conf, CONF_colours, i*3+2));
+#if !GTK_CHECK_VERSION(3,0,0)
+    {
+        gboolean success[NALLCOLOURS];
+        gdk_colormap_alloc_colors(inst->colmap, inst->cols, NALLCOLOURS,
+                                  FALSE, TRUE, success);
+        for (i = 0; i < NALLCOLOURS; i++) {
+            if (!success[i])
+                g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n",
+                        appname, i,
+                        conf_get_int_int(inst->conf, CONF_colours, i*3+0),
+                        conf_get_int_int(inst->conf, CONF_colours, i*3+1),
+                        conf_get_int_int(inst->conf, CONF_colours, i*3+2));
+        }
     }
+#endif
 
     /* Since Default Background may have changed, ensure that space
      * between text area and window border is refreshed. */
@@ -1868,21 +1976,22 @@ void init_cutbuffers()
 {
 #ifndef NOT_X_WINDOWS
     unsigned char empty[] = "";
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, empty, 0);
-    XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
+    XChangeProperty(disp, GDK_ROOT_WINDOW(),
                    XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, empty, 0);
 #endif
 }
@@ -1891,9 +2000,10 @@ void init_cutbuffers()
 void store_cutbuffer(char * ptr, int len)
 {
 #ifndef NOT_X_WINDOWS
+    Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     /* ICCCM says we must rotate the buffers before storing to buffer 0. */
-    XRotateBuffers(GDK_DISPLAY(), 1);
-    XStoreBytes(GDK_DISPLAY(), ptr, len);
+    XRotateBuffers(disp, 1);
+    XStoreBytes(disp, ptr, len);
 #endif
 }
 
@@ -1903,8 +2013,9 @@ void store_cutbuffer(char * ptr, int len)
 char * retrieve_cutbuffer(int * nbytes)
 {
 #ifndef NOT_X_WINDOWS
+    Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
     char * ptr;
-    ptr = XFetchBytes(GDK_DISPLAY(), nbytes);
+    ptr = XFetchBytes(disp, nbytes);
     if (*nbytes <= 0 && ptr != 0) {
        XFree(ptr);
        ptr = 0;
@@ -1935,6 +2046,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des
 #ifndef NOT_X_WINDOWS
        XTextProperty tp;
        char *list[1];
+        Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
 #endif
 
        inst->pasteout_data_utf8 = snewn(len*6, char);
@@ -1958,7 +2070,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des
         */
 #ifndef NOT_X_WINDOWS
        list[0] = inst->pasteout_data_utf8;
-       if (Xutf8TextListToTextProperty(GDK_DISPLAY(), list, 1,
+       if (Xutf8TextListToTextProperty(disp, list, 1,
                                        XCompoundTextStyle, &tp) == 0) {
            inst->pasteout_data_ctext = snewn(tp.nitems+1, char);
            memcpy(inst->pasteout_data_ctext, tp.value, tp.nitems);
@@ -2157,13 +2269,13 @@ void selection_received(GtkWidget *widget, GtkSelectionData *seldata,
 #ifndef NOT_X_WINDOWS
             XTextProperty tp;
             int ret, count;
+            Display *disp = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
 
            tp.value = (unsigned char *)seldata_data;
            tp.encoding = (Atom) seldata_type;
            tp.format = gtk_selection_data_get_format(seldata);
            tp.nitems = seldata_length;
-           ret = Xutf8TextPropertyToTextList(GDK_DISPLAY(), &tp,
-                                             &list, &count);
+           ret = Xutf8TextPropertyToTextList(disp, &tp, &list, &count);
            if (ret == 0 && count == 1) {
                 text = list[0];
                 length = strlen(list[0]);
@@ -2341,16 +2453,7 @@ Context get_ctx(void *frontend)
     if (dctx->uctx.type == DRAWTYPE_CAIRO) {
         dctx->uctx.u.cairo.widget = GTK_WIDGET(inst->area);
         dctx->uctx.u.cairo.cr = gdk_cairo_create(target);
-        cairo_get_matrix(dctx->uctx.u.cairo.cr,
-                         &dctx->uctx.u.cairo.origmatrix);
-        cairo_set_line_width(dctx->uctx.u.cairo.cr, 1.0);
-        cairo_set_line_cap(dctx->uctx.u.cairo.cr, CAIRO_LINE_CAP_SQUARE);
-        cairo_set_line_join(dctx->uctx.u.cairo.cr, CAIRO_LINE_JOIN_MITER);
-        /* This antialiasing setting appears to be ignored for Pango
-         * font rendering but honoured for stroking and filling paths;
-         * I don't quite understand the logic of that, but I won't
-         * complain since it's exactly what I happen to want */
-        cairo_set_antialias(dctx->uctx.u.cairo.cr, CAIRO_ANTIALIAS_NONE);
+        cairo_setup_dctx(dctx);
     }
 #endif
     return dctx;
@@ -2928,7 +3031,7 @@ void cmdline_error(const char *p, ...)
     exit(1);
 }
 
-char *get_x_display(void *frontend)
+const char *get_x_display(void *frontend)
 {
     return gdk_get_display();
 }
@@ -2937,7 +3040,7 @@ char *get_x_display(void *frontend)
 long get_windowid(void *frontend)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
-    return (long)GDK_WINDOW_XWINDOW(gtk_widget_get_window(inst->area));
+    return (long)GDK_WINDOW_XID(gtk_widget_get_window(inst->area));
 }
 #endif
 
@@ -3213,17 +3316,46 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch,
     return err;
 }
 
-int uxsel_input_add(int fd, int rwx) {
+struct uxsel_id {
+#if GTK_CHECK_VERSION(2,0,0)
+    GIOChannel *chan;
+    guint watch_id;
+#else
+    int id;
+#endif
+};
+
+uxsel_id *uxsel_input_add(int fd, int rwx) {
+    uxsel_id *id = snew(uxsel_id);
+
+#if GTK_CHECK_VERSION(2,0,0)
+    int flags = 0;
+    if (rwx & 1) flags |= G_IO_IN;
+    if (rwx & 2) flags |= G_IO_OUT;
+    if (rwx & 4) flags |= G_IO_PRI;
+    id->chan = g_io_channel_unix_new(fd);
+    g_io_channel_set_encoding(id->chan, NULL, NULL);
+    id->watch_id = g_io_add_watch(id->chan, flags, fd_input_func, NULL);
+#else
     int flags = 0;
     if (rwx & 1) flags |= GDK_INPUT_READ;
     if (rwx & 2) flags |= GDK_INPUT_WRITE;
     if (rwx & 4) flags |= GDK_INPUT_EXCEPTION;
     assert(flags);
-    return gdk_input_add(fd, flags, fd_input_func, NULL);
+    id->id = gdk_input_add(fd, flags, fd_input_func, NULL);
+#endif
+
+    return id;
 }
 
-void uxsel_input_remove(int id) {
-    gdk_input_remove(id);
+void uxsel_input_remove(uxsel_id *id) {
+#if GTK_CHECK_VERSION(2,0,0)
+    g_source_remove(id->watch_id);
+    g_io_channel_unref(id->chan);
+#else
+    gdk_input_remove(id->id);
+#endif
+    sfree(id);
 }
 
 char *setup_fonts_ucs(struct gui_data *inst)
@@ -3812,20 +3944,26 @@ static void update_savedsess_menu(GtkMenuItem *menuitem, gpointer data)
 void set_window_icon(GtkWidget *window, const char *const *const *icon,
                     int n_icon)
 {
-    GdkPixmap *iconpm;
-    GdkBitmap *iconmask;
 #if GTK_CHECK_VERSION(2,0,0)
     GList *iconlist;
     int n;
+#else
+    GdkPixmap *iconpm;
+    GdkBitmap *iconmask;
 #endif
 
     if (!n_icon)
        return;
 
     gtk_widget_realize(window);
+#if GTK_CHECK_VERSION(2,0,0)
+    gtk_window_set_icon(GTK_WINDOW(window),
+                        gdk_pixbuf_new_from_xpm_data((const gchar **)icon[0]));
+#else
     iconpm = gdk_pixmap_create_from_xpm_d(gtk_widget_get_window(window),
                                           &iconmask, NULL, (gchar **)icon[0]);
     gdk_window_set_icon(gtk_widget_get_window(window), NULL, iconpm, iconmask);
+#endif
 
 #if GTK_CHECK_VERSION(2,0,0)
     iconlist = NULL;
@@ -3835,7 +3973,7 @@ void set_window_icon(GtkWidget *window, const char *const *const *icon,
                          gdk_pixbuf_new_from_xpm_data((const gchar **)
                                                       icon[n]));
     }
-    gdk_window_set_icon_list(gtk_widget_get_window(window), iconlist);
+    gtk_window_set_icon_list(GTK_WINDOW(window), iconlist);
 #endif
 }
 
@@ -4116,8 +4254,13 @@ int pt_main(int argc, char **argv)
                      G_CALLBACK(focus_event), inst);
     g_signal_connect(G_OBJECT(inst->area), "configure_event",
                      G_CALLBACK(configure_area), inst);
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(inst->area), "draw",
+                     G_CALLBACK(draw_area), inst);
+#else
     g_signal_connect(G_OBJECT(inst->area), "expose_event",
                      G_CALLBACK(expose_area), inst);
+#endif
     g_signal_connect(G_OBJECT(inst->area), "button_press_event",
                      G_CALLBACK(button_event), inst);
     g_signal_connect(G_OBJECT(inst->area), "button_release_event",