chiark / gitweb /
Net: rework status line to cope with empty squares.
[sgt-puzzles.git] / gtk.c
diff --git a/gtk.c b/gtk.c
index 0333e5466223385d1afb52f945ff24415d3f3063..ab3ad8b3688cfe6748779d2bed810269367c17a1 100644 (file)
--- a/gtk.c
+++ b/gtk.c
@@ -144,6 +144,9 @@ struct frontend {
     GtkWidget *area;
     GtkWidget *statusbar;
     GtkWidget *menubar;
+#if GTK_CHECK_VERSION(3,20,0)
+    GtkCssProvider *css_provider;
+#endif
     guint statusctx;
     int w, h;
     midend *me;
@@ -290,7 +293,27 @@ static void set_colour(frontend *fe, int colour)
 
 static void set_window_background(frontend *fe, int colour)
 {
-#if GTK_CHECK_VERSION(3,0,0)
+#if GTK_CHECK_VERSION(3,20,0)
+    char css_buf[512];
+    sprintf(css_buf, ".background { "
+            "background-color: #%02x%02x%02x; }",
+            (unsigned)(fe->colours[3*colour + 0] * 255),
+            (unsigned)(fe->colours[3*colour + 1] * 255),
+            (unsigned)(fe->colours[3*colour + 2] * 255));
+    if (!fe->css_provider)
+        fe->css_provider = gtk_css_provider_new();
+    if (!gtk_css_provider_load_from_data(
+            GTK_CSS_PROVIDER(fe->css_provider), css_buf, -1, NULL))
+        assert(0 && "Couldn't load CSS");
+    gtk_style_context_add_provider(
+        gtk_widget_get_style_context(fe->window),
+        GTK_STYLE_PROVIDER(fe->css_provider),
+        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    gtk_style_context_add_provider(
+        gtk_widget_get_style_context(fe->area),
+        GTK_STYLE_PROVIDER(fe->css_provider),
+        GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+#elif GTK_CHECK_VERSION(3,0,0)
     GdkRGBA rgba;
     rgba.red = fe->colours[3*colour + 0];
     rgba.green = fe->colours[3*colour + 1];
@@ -439,11 +462,13 @@ static void clear_backing_store(frontend *fe)
     fe->image = NULL;
 }
 
-static void wipe_and_destroy_cairo(frontend *fe, cairo_t *cr)
+static void wipe_and_maybe_destroy_cairo(frontend *fe, cairo_t *cr,
+                                         int destroy)
 {
     cairo_set_source_rgb(cr, fe->colours[0], fe->colours[1], fe->colours[2]);
     cairo_paint(cr);
-    cairo_destroy(cr);
+    if (destroy)
+        cairo_destroy(cr);
 }
 
 static void setup_backing_store(frontend *fe)
@@ -455,12 +480,29 @@ static void setup_backing_store(frontend *fe)
     fe->image = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
                                           fe->pw, fe->ph);
 
-    wipe_and_destroy_cairo(fe, cairo_create(fe->image));
+    wipe_and_maybe_destroy_cairo(fe, cairo_create(fe->image), TRUE);
 #ifndef USE_CAIRO_WITHOUT_PIXMAP
-    wipe_and_destroy_cairo(fe, gdk_cairo_create(fe->pixmap));
+    wipe_and_maybe_destroy_cairo(fe, gdk_cairo_create(fe->pixmap), TRUE);
+#endif
+#if GTK_CHECK_VERSION(3,22,0)
+    {
+        GdkWindow *gdkwin;
+        cairo_region_t *region;
+        GdkDrawingContext *drawctx;
+        cairo_t *cr;
+
+        gdkwin = gtk_widget_get_window(fe->area);
+        region = gdk_window_get_clip_region(gdkwin);
+        drawctx = gdk_window_begin_draw_frame(gdkwin, region);
+        cr = gdk_drawing_context_get_cairo_context(drawctx);
+        wipe_and_maybe_destroy_cairo(fe, cr, FALSE);
+        gdk_window_end_draw_frame(gdkwin, drawctx);
+        cairo_region_destroy(region);
+    }
+#else
+    wipe_and_maybe_destroy_cairo(
+        fe, gdk_cairo_create(gtk_widget_get_window(fe->area)), TRUE);
 #endif
-    wipe_and_destroy_cairo(fe, gdk_cairo_create
-                           (gtk_widget_get_window(fe->area)));
 }
 
 static int backing_store_ok(frontend *fe)
@@ -1205,10 +1247,14 @@ static gint button_event(GtkWidget *widget, GdkEventButton *event,
        button = RIGHT_BUTTON;
     else if (event->button == 1)
        button = LEFT_BUTTON;
+    else if (event->button == 8 && event->type == GDK_BUTTON_PRESS)
+        button = 'u';
+    else if (event->button == 9 && event->type == GDK_BUTTON_PRESS)
+        button = 'r';
     else
        return FALSE;                  /* don't even know what button! */
 
-    if (event->type == GDK_BUTTON_RELEASE)
+    if (event->type == GDK_BUTTON_RELEASE && button >= LEFT_BUTTON)
         button += LEFT_RELEASE - LEFT_BUTTON;
 
     if (!midend_process_key(fe->me, event->x - fe->ox,
@@ -1306,22 +1352,22 @@ static gint configure_area(GtkWidget *widget,
 {
     frontend *fe = (frontend *)data;
     int x, y;
+    int oldw = fe->w, oldpw = fe->pw, oldh = fe->h, oldph = fe->ph;
 
     x = event->width;
     y = event->height;
-
-    if (x != fe->w || y != fe->h || !backing_store_ok(fe)) {
+    fe->w = x;
+    fe->h = y;
+    midend_size(fe->me, &x, &y, TRUE);
+    fe->pw = x;
+    fe->ph = y;
+    fe->ox = (fe->w - fe->pw) / 2;
+    fe->oy = (fe->h - fe->ph) / 2;
+
+    if (oldw != fe->w || oldpw != fe->pw ||
+        oldh != fe->h || oldph != fe->ph || !backing_store_ok(fe)) {
         if (backing_store_ok(fe))
             teardown_backing_store(fe);
-
-        fe->w = x;
-        fe->h = y;
-        midend_size(fe->me, &x, &y, TRUE);
-        fe->pw = x;
-        fe->ph = y;
-        fe->ox = (fe->w - fe->pw) / 2;
-        fe->oy = (fe->h - fe->ph) / 2;
-
         setup_backing_store(fe);
     }
 
@@ -1394,6 +1440,13 @@ static void align_label(GtkLabel *label, double x, double y)
 #if GTK_CHECK_VERSION(3,16,0)
     gtk_label_set_xalign(label, x);
     gtk_label_set_yalign(label, y);
+#elif GTK_CHECK_VERSION(3,14,0)
+    gtk_widget_set_halign(GTK_WIDGET(label),
+                          x == 0 ? GTK_ALIGN_START :
+                          x == 1 ? GTK_ALIGN_END : GTK_ALIGN_CENTER);
+    gtk_widget_set_valign(GTK_WIDGET(label),
+                          y == 0 ? GTK_ALIGN_START :
+                          y == 1 ? GTK_ALIGN_END : GTK_ALIGN_CENTER);
 #else
     gtk_misc_set_alignment(GTK_MISC(label), x, y);
 #endif
@@ -1924,6 +1977,24 @@ static gint configure_window(GtkWidget *widget,
     return FALSE;
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+static int window_extra_height(frontend *fe)
+{
+    int ret = 0;
+    if (fe->menubar) {
+        GtkRequisition req;
+        gtk_widget_get_preferred_size(fe->menubar, &req, NULL);
+        ret += req.height;
+    }
+    if (fe->statusbar) {
+        GtkRequisition req;
+        gtk_widget_get_preferred_size(fe->statusbar, &req, NULL);
+        ret += req.height;
+    }
+    return ret;
+}
+#endif
+
 static void resize_fe(frontend *fe)
 {
     int x, y;
@@ -1931,7 +2002,7 @@ static void resize_fe(frontend *fe)
     get_size(fe, &x, &y);
 
 #if GTK_CHECK_VERSION(3,0,0)
-    gtk_window_resize_to_geometry(GTK_WINDOW(fe->window), x, y);
+    gtk_window_resize(GTK_WINDOW(fe->window), x, y + window_extra_height(fe));
 #else
     fe->drawing_area_shrink_pending = FALSE;
     gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
@@ -1959,6 +2030,7 @@ static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
     midend_new_game(fe->me);
     changed_preset(fe);
     resize_fe(fe);
+    midend_redraw(fe->me);
 }
 
 GdkAtom compound_text_atom, utf8_string_atom;
@@ -2094,8 +2166,9 @@ static char *file_selector(frontend *fe, char *title, int save)
                                    NULL);
 
     if (gtk_dialog_run(GTK_DIALOG(filesel)) == GTK_RESPONSE_ACCEPT) {
-        const char *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filesel));
+        char *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filesel));
         filesel_name = dupstr(name);
+        g_free(name);
     }
 
     gtk_widget_destroy(filesel);
@@ -2145,15 +2218,14 @@ static void menu_save_event(GtkMenuItem *menuitem, gpointer data)
                    " file \"%.*s\"?",
                    FILENAME_MAX, name);
            if (!message_box(fe->window, "Question", buf, TRUE, MB_YESNO))
-               return;
+                goto free_and_return;
        }
 
        fp = fopen(name, "w");
-        sfree(name);
 
         if (!fp) {
             error_box(fe->window, "Unable to open save file");
-            return;
+            goto free_and_return;
         }
 
        {
@@ -2167,10 +2239,11 @@ static void menu_save_event(GtkMenuItem *menuitem, gpointer data)
                sprintf(boxmsg, "Error writing save file: %.400s",
                        strerror(errno));
                error_box(fe->window, boxmsg);
-               return;
+               goto free_and_return;
            }
        }
-
+    free_and_return:
+        sfree(name);
     }
 }
 
@@ -2201,6 +2274,7 @@ static void menu_load_event(GtkMenuItem *menuitem, gpointer data)
 
        changed_preset(fe);
         resize_fe(fe);
+        midend_redraw(fe->me);
     }
 }
 
@@ -2238,6 +2312,7 @@ static void menu_config_event(GtkMenuItem *menuitem, gpointer data)
 
     midend_new_game(fe->me);
     resize_fe(fe);
+    midend_redraw(fe->me);
 }
 
 static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
@@ -2322,6 +2397,9 @@ static frontend *new_window(char *arg, int argtype, char **error)
     extern const int n_xpm_icons;
 
     fe = snew(frontend);
+#if GTK_CHECK_VERSION(3,20,0)
+    fe->css_provider = NULL;
+#endif
 
     fe->timer_active = FALSE;
     fe->timer_id = -1;
@@ -2636,15 +2714,23 @@ static frontend *new_window(char *arg, int argtype, char **error)
 #endif
     {
         GdkGeometry geom;
-        geom.base_width = geom.base_height = 0;
+        geom.base_width = 0;
+#if GTK_CHECK_VERSION(3,0,0)
+        geom.base_height = window_extra_height(fe);
+        gtk_window_set_geometry_hints(GTK_WINDOW(fe->window), NULL,
+                                      &geom, GDK_HINT_BASE_SIZE);
+#else
+        geom.base_height = 0;
         gtk_window_set_geometry_hints(GTK_WINDOW(fe->window), fe->area,
                                       &geom, GDK_HINT_BASE_SIZE);
+#endif
     }
     fe->w = -1;
     fe->h = -1;
     get_size(fe, &x, &y);
 #if GTK_CHECK_VERSION(3,0,0)
-    gtk_window_set_default_geometry(GTK_WINDOW(fe->window), x, y);
+    gtk_window_set_default_size(GTK_WINDOW(fe->window),
+                                x, y + window_extra_height(fe));
 #else
     fe->drawing_area_shrink_pending = FALSE;
     gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);