Since r6711, puzzles built with Gtk 1.2 would take double actions when a menu
[sgt/puzzles] / gtk.c
diff --git a/gtk.c b/gtk.c
index 6fef7b8..99cc4cb 100644 (file)
--- a/gtk.c
+++ b/gtk.c
@@ -96,6 +96,7 @@ struct font {
  */
 struct frontend {
     GtkWidget *window;
+    GtkAccelGroup *accelgroup;
     GtkWidget *area;
     GtkWidget *statusbar;
     guint statusctx;
@@ -116,7 +117,6 @@ struct frontend {
     GtkWidget *cfgbox;
     void *paste_data;
     int paste_data_len;
-    char *laststatus;
     int pw, ph;                        /* pixmap size (w, h are area size) */
     int ox, oy;                        /* offset of pixmap in drawing area */
     char *filesel_name;
@@ -141,19 +141,11 @@ void frontend_default_colour(frontend *fe, float *output)
 void gtk_status_bar(void *handle, char *text)
 {
     frontend *fe = (frontend *)handle;
-    char *rewritten;
 
     assert(fe->statusbar);
 
-    rewritten = midend_rewrite_statusbar(fe->me, text);
-    if (!fe->laststatus || strcmp(rewritten, fe->laststatus)) {
-       gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx);
-       gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, rewritten);
-       sfree(fe->laststatus);
-       fe->laststatus = rewritten;
-    } else {
-       sfree(rewritten);
-    }
+    gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx);
+    gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, text);
 }
 
 void gtk_start_draw(void *handle)
@@ -290,6 +282,8 @@ void gtk_draw_text(void *handle, int x, int y, int fonttype, int fontsize,
 
         if (align & ALIGN_VCENTRE)
             rect.y -= rect.height / 2;
+       else
+           rect.y -= rect.height;
 
         if (align & ALIGN_HCENTRE)
             rect.x -= rect.width / 2;
@@ -317,6 +311,8 @@ void gtk_draw_text(void *handle, int x, int y, int fonttype, int fontsize,
                            &lb, &rb, &wid, &asc, &desc);
         if (align & ALIGN_VCENTRE)
             y += asc - (asc+desc)/2;
+       else
+            y += asc;
 
        /*
         * ... but horizontal extents with respect to the provided
@@ -373,7 +369,17 @@ void gtk_draw_poly(void *handle, int *coords, int npoints,
     }
     assert(outlinecolour >= 0);
     gdk_gc_set_foreground(fe->gc, &fe->colours[outlinecolour]);
-    gdk_draw_polygon(fe->pixmap, fe->gc, FALSE, points, npoints);
+
+    /*
+     * In principle we ought to be able to use gdk_draw_polygon for
+     * the outline as well. In fact, it turns out to interact badly
+     * with a clipping region, for no terribly obvious reason, so I
+     * draw the outline as a sequence of lines instead.
+     */
+    for (i = 0; i < npoints; i++)
+       gdk_draw_line(fe->pixmap, fe->gc,
+                     points[i].x, points[i].y,
+                     points[(i+1)%npoints].x, points[(i+1)%npoints].y);
 
     sfree(points);
 }
@@ -512,6 +518,16 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
     if (!fe->pixmap)
         return TRUE;
 
+#if !GTK_CHECK_VERSION(2,0,0)
+    /* Gtk 1.2 passes a key event to this function even if it's also
+     * defined as an accelerator.
+     * Gtk 2 doesn't do this, and this function appears not to exist there. */
+    if (fe->accelgroup &&
+        gtk_accel_group_get_entry(fe->accelgroup,
+        event->keyval, event->state))
+        return TRUE;
+#endif
+
     if (event->keyval == GDK_Up)
         keyval = shift | ctrl | CURSOR_UP;
     else if (event->keyval == GDK_KP_Up || event->keyval == GDK_KP_8)
@@ -540,6 +556,10 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
         keyval = MOD_NUM_KEYPAD | '0';
     else if (event->keyval == GDK_KP_Begin || event->keyval == GDK_KP_5)
         keyval = MOD_NUM_KEYPAD | '5';
+    else if (event->keyval == GDK_BackSpace ||
+            event->keyval == GDK_Delete ||
+            event->keyval == GDK_KP_Delete)
+        keyval = '\177';
     else if (event->string[0] && !event->string[1])
         keyval = (unsigned char)event->string[0];
     else
@@ -662,6 +682,8 @@ static gint configure_area(GtkWidget *widget,
     gc = gdk_gc_new(fe->area->window);
     gdk_gc_set_foreground(gc, &fe->colours[0]);
     gdk_draw_rectangle(fe->pixmap, gc, 1, 0, 0, fe->pw, fe->ph);
+    gdk_draw_rectangle(widget->window, gc, 1, 0, 0,
+                      event->width, event->height);
     gdk_gc_unref(gc);
 
     midend_force_redraw(fe->me);
@@ -1395,11 +1417,29 @@ static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont,
                                          char *text, int key)
 {
     GtkWidget *menuitem = gtk_menu_item_new_with_label(text);
+    int keyqual;
     gtk_container_add(cont, menuitem);
     gtk_object_set_data(GTK_OBJECT(menuitem), "user-data",
                         GINT_TO_POINTER(key));
     gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
                       GTK_SIGNAL_FUNC(menu_key_event), fe);
+    switch (key & ~0x1F) {
+      case 0x00:
+       key += 0x60;
+       keyqual = GDK_CONTROL_MASK;
+       break;
+      case 0x40:
+       key += 0x20;
+       keyqual = GDK_SHIFT_MASK;
+       break;
+      default:
+       keyqual = 0;
+       break;
+    }
+    gtk_widget_add_accelerator(menuitem,
+                              "activate", fe->accelgroup,
+                              key, keyqual,
+                              GTK_ACCEL_VISIBLE);
     gtk_widget_show(menuitem);
     return menuitem;
 }
@@ -1447,8 +1487,9 @@ static frontend *new_window(char *arg, char **error)
                        " nor a save file (%.400s)", err, strerror(errno));
            } else {
                err = midend_deserialise(fe->me, savefile_read, fp);
-               sprintf(errbuf, "%.800s", err);
-               fclose(fp);
+                if (err)
+                    sprintf(errbuf, "%.800s", err);
+                fclose(fp);
            }
         }
        if (*errbuf) {
@@ -1464,15 +1505,14 @@ static frontend *new_window(char *arg, char **error)
 
     fe->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     gtk_window_set_title(GTK_WINDOW(fe->window), thegame.name);
-#if 0
-    gtk_window_set_resizable(GTK_WINDOW(fe->window), FALSE);
-#else
-    gtk_window_set_policy(GTK_WINDOW(fe->window), FALSE, FALSE, TRUE);
-#endif
+
     vbox = GTK_BOX(gtk_vbox_new(FALSE, 0));
     gtk_container_add(GTK_CONTAINER(fe->window), GTK_WIDGET(vbox));
     gtk_widget_show(GTK_WIDGET(vbox));
 
+    fe->accelgroup = gtk_accel_group_new();
+    gtk_window_add_accel_group(GTK_WINDOW(fe->window), fe->accelgroup);
+
     menubar = gtk_menu_bar_new();
     gtk_box_pack_start(vbox, menubar, FALSE, FALSE, 0);
     gtk_widget_show(menubar);
@@ -1557,7 +1597,7 @@ static frontend *new_window(char *arg, char **error)
     gtk_widget_show(menuitem);
     add_menu_separator(GTK_CONTAINER(menu));
     add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Undo", 'u');
-    add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Redo", '\x12');
+    add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Redo", 'r');
     if (thegame.can_format_as_text) {
        add_menu_separator(GTK_CONTAINER(menu));
        menuitem = gtk_menu_item_new_with_label("Copy");
@@ -1651,8 +1691,6 @@ static frontend *new_window(char *arg, char **error)
     fe->fonts = NULL;
     fe->nfonts = fe->fontsize = 0;
 
-    fe->laststatus = NULL;
-
     fe->paste_data = NULL;
     fe->paste_data_len = 0;