~ubuntu-branches/ubuntu/saucy/sgt-puzzles/saucy

« back to all changes in this revision

Viewing changes to gtk.c

  • Committer: Package Import Robot
  • Author(s): Ben Hutchings
  • Date: 2013-06-30 03:20:16 UTC
  • mfrom: (1.1.16) (3.1.17 sid)
  • Revision ID: package-import@ubuntu.com-20130630032016-f884y3laa67smdoc
Tags: 9872-1
* New upstream version
  - Add an explicit -lm to the link lines in Makefile.gtk (Closes: #713476)
  - Add Undead by Steffen Bauer, an implementation of 'Haunted Mirror Maze'
  - Add Unruly by Lennard Sprong, an implementation of a puzzle usually
    called 'Tohu wa Vohu'
* Add DEP-3 headers to patches
* pearl: Require width or height to be at least 6 for Tricky
  (Closes: #667963)
* debian/watch: Update ViewVC URL regex
* Add 'sgt-' prefix to all command names and remove 'game' suffix, but
  retain symlinks under the old names (see #684193)
* Use upstream short descriptions in English manual pages and package
  description
* Update German translation, thanks to Helge Kreutzmann

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
#include <locale.h>
18
18
 
19
19
#include <sys/time.h>
 
20
#include <sys/resource.h>
20
21
 
21
22
#include <gtk/gtk.h>
22
23
#include <gdk/gdkkeysyms.h>
130
131
    GtkAccelGroup *accelgroup;
131
132
    GtkWidget *area;
132
133
    GtkWidget *statusbar;
 
134
    GtkWidget *menubar;
133
135
    guint statusctx;
134
136
    int w, h;
135
137
    midend *me;
162
164
#ifdef OLD_FILESEL
163
165
    char *filesel_name;
164
166
#endif
 
167
    int drawing_area_shrink_pending;
165
168
    GSList *preset_radio;
166
169
    int n_preset_menu_items;
167
170
    int preset_threaded;
1674
1677
    }
1675
1678
}
1676
1679
 
 
1680
static gboolean not_size_allocated_yet(GtkWidget *w)
 
1681
{
 
1682
    /*
 
1683
     * This function tests whether a widget has not yet taken up space
 
1684
     * on the screen which it will occupy in future. (Therefore, it
 
1685
     * returns true only if the widget does exist but does not have a
 
1686
     * size allocation. A null widget is already taking up all the
 
1687
     * space it ever will.)
 
1688
     */
 
1689
    if (!w)
 
1690
        return FALSE;        /* nonexistent widgets aren't a problem */
 
1691
 
 
1692
#if GTK_CHECK_VERSION(2,18,0)  /* skip if no gtk_widget_get_allocation */
 
1693
    {
 
1694
        GtkAllocation a;
 
1695
        gtk_widget_get_allocation(w, &a);
 
1696
        if (a.height == 0 || a.width == 0)
 
1697
            return TRUE;       /* widget exists but has no size yet */
 
1698
    }
 
1699
#endif
 
1700
 
 
1701
    return FALSE;
 
1702
}
 
1703
 
 
1704
static void try_shrink_drawing_area(frontend *fe)
 
1705
{
 
1706
    if (fe->drawing_area_shrink_pending &&
 
1707
        !not_size_allocated_yet(fe->menubar) &&
 
1708
        !not_size_allocated_yet(fe->statusbar)) {
 
1709
        /*
 
1710
         * In order to permit the user to resize the window smaller as
 
1711
         * well as bigger, we call this function after the window size
 
1712
         * has ended up where we want it. This shouldn't shrink the
 
1713
         * window immediately; it just arranges that the next time the
 
1714
         * user tries to shrink it, they can.
 
1715
         *
 
1716
         * However, at puzzle creation time, we defer the first of
 
1717
         * these operations until after the menu bar and status bar
 
1718
         * are actually visible. On Ubuntu 12.04 I've found that these
 
1719
         * can take a while to be displayed, and that it's a mistake
 
1720
         * to reduce the drawing area's size allocation before they've
 
1721
         * turned up or else the drawing area makes room for them by
 
1722
         * shrinking to less than the size we intended.
 
1723
         */
 
1724
        gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), 1, 1);
 
1725
        fe->drawing_area_shrink_pending = FALSE;
 
1726
    }
 
1727
}
 
1728
 
 
1729
static gint configure_window(GtkWidget *widget,
 
1730
                             GdkEventConfigure *event, gpointer data)
 
1731
{
 
1732
    frontend *fe = (frontend *)data;
 
1733
    /*
 
1734
     * When the main puzzle window changes size, it might be because
 
1735
     * the menu bar or status bar has turned up after starting off
 
1736
     * absent, in which case we should have another go at enacting a
 
1737
     * pending shrink of the drawing area.
 
1738
     */
 
1739
    try_shrink_drawing_area(fe);
 
1740
    return FALSE;
 
1741
}
 
1742
 
1677
1743
static void resize_fe(frontend *fe)
1678
1744
{
1679
1745
    int x, y;
1681
1747
    get_size(fe, &x, &y);
1682
1748
    fe->w = x;
1683
1749
    fe->h = y;
 
1750
    fe->drawing_area_shrink_pending = FALSE;
1684
1751
    gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
1685
1752
    {
1686
1753
        GtkRequisition req;
1687
1754
        gtk_widget_size_request(GTK_WIDGET(fe->window), &req);
1688
1755
        gtk_window_resize(GTK_WINDOW(fe->window), req.width, req.height);
1689
1756
    }
1690
 
    /*
1691
 
     * Now that we've established the preferred size of the window,
1692
 
     * reduce the drawing area's size request so the user can shrink
1693
 
     * the window.
1694
 
     */
1695
 
    gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), 1, 1);
 
1757
    fe->drawing_area_shrink_pending = TRUE;
 
1758
    try_shrink_drawing_area(fe);
1696
1759
}
1697
1760
 
1698
1761
static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
2132
2195
{
2133
2196
    frontend *fe;
2134
2197
    GtkBox *vbox, *hbox;
2135
 
    GtkWidget *menubar, *menu, *menuitem;
 
2198
    GtkWidget *menu, *menuitem;
2136
2199
    GdkPixmap *iconpm;
2137
2200
    GList *iconlist;
2138
2201
    int x, y, n;
2219
2282
    gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0);
2220
2283
    gtk_widget_show(GTK_WIDGET(hbox));
2221
2284
 
2222
 
    menubar = gtk_menu_bar_new();
2223
 
    gtk_box_pack_start(hbox, menubar, TRUE, TRUE, 0);
2224
 
    gtk_widget_show(menubar);
 
2285
    fe->menubar = gtk_menu_bar_new();
 
2286
    gtk_box_pack_start(hbox, fe->menubar, TRUE, TRUE, 0);
 
2287
    gtk_widget_show(fe->menubar);
2225
2288
 
2226
2289
    menuitem = gtk_menu_item_new_with_mnemonic("_Game");
2227
 
    gtk_container_add(GTK_CONTAINER(menubar), menuitem);
 
2290
    gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem);
2228
2291
    gtk_widget_show(menuitem);
2229
2292
 
2230
2293
    menu = gtk_menu_new();
2263
2326
        int i;
2264
2327
 
2265
2328
        menuitem = gtk_menu_item_new_with_mnemonic("_Type");
2266
 
        gtk_container_add(GTK_CONTAINER(menubar), menuitem);
 
2329
        gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem);
2267
2330
        gtk_widget_show(menuitem);
2268
2331
 
2269
2332
        submenu = gtk_menu_new();
2342
2405
    add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q');
2343
2406
 
2344
2407
    menuitem = gtk_menu_item_new_with_mnemonic("_Help");
2345
 
    gtk_container_add(GTK_CONTAINER(menubar), menuitem);
 
2408
    gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem);
2346
2409
    gtk_widget_show(menuitem);
2347
2410
 
2348
2411
    menu = gtk_menu_new();
2441
2504
    GTK_WIDGET_UNSET_FLAGS(fe->area, GTK_DOUBLE_BUFFERED);
2442
2505
#endif
2443
2506
    get_size(fe, &x, &y);
 
2507
    fe->drawing_area_shrink_pending = FALSE;
2444
2508
    gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
2445
2509
    fe->w = x;
2446
2510
    fe->h = y;
2474
2538
                       GTK_SIGNAL_FUNC(map_window), fe);
2475
2539
    gtk_signal_connect(GTK_OBJECT(fe->area), "configure_event",
2476
2540
                       GTK_SIGNAL_FUNC(configure_area), fe);
 
2541
    gtk_signal_connect(GTK_OBJECT(fe->window), "configure_event",
 
2542
                       GTK_SIGNAL_FUNC(configure_window), fe);
2477
2543
 
2478
2544
    gtk_widget_add_events(GTK_WIDGET(fe->area),
2479
2545
                          GDK_BUTTON_PRESS_MASK |
2499
2565
    gtk_widget_show(fe->area);
2500
2566
    gtk_widget_show(fe->window);
2501
2567
 
2502
 
    /*
2503
 
     * Now that we've established the preferred size of the window,
2504
 
     * reduce the drawing area's size request so the user can shrink
2505
 
     * the window.
2506
 
     */
2507
 
    gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), 1, 1);
 
2568
    fe->drawing_area_shrink_pending = TRUE;
 
2569
    try_shrink_drawing_area(fe);
2508
2570
    set_window_background(fe, 0);
2509
2571
 
2510
2572
    return fe;
2535
2597
    int i;
2536
2598
    char *error;
2537
2599
    int ngenerate = 0, print = FALSE, px = 1, py = 1;
 
2600
    int time_generation = FALSE, test_solve = FALSE, list_presets = FALSE;
2538
2601
    int soln = FALSE, colour = FALSE;
2539
2602
    float scale = 1.0F;
2540
2603
    float redo_proportion = 0.0F;
2553
2616
        pname++;
2554
2617
    else
2555
2618
        pname = argv[0];
 
2619
    if (!strncmp(pname, "sgt-", 4))
 
2620
        pname += 4;
2556
2621
    for (i = 0; i < gamecount; i++) {
2557
2622
        size_t len = strlen(gamelist[i].name);
2558
2623
        if (!strncmp(pname, gamelist[i].name, len) &&
2607
2672
                }
2608
2673
            } else
2609
2674
                ngenerate = 1;
 
2675
        } else if (doing_opts && !strcmp(p, "--time-generation")) {
 
2676
            time_generation = TRUE;
 
2677
        } else if (doing_opts && !strcmp(p, "--test-solve")) {
 
2678
            test_solve = TRUE;
 
2679
        } else if (doing_opts && !strcmp(p, "--list-presets")) {
 
2680
            list_presets = TRUE;
2610
2681
        } else if (doing_opts && !strcmp(p, "--save")) {
2611
2682
            if (--ac > 0) {
2612
2683
                savefile = *++av;
2728
2799
        }
2729
2800
    }
2730
2801
 
2731
 
    if (*errbuf) {
2732
 
        fputs(errbuf, stderr);
2733
 
        return 1;
2734
 
    }
2735
 
 
2736
2802
    /*
2737
2803
     * Special standalone mode for generating puzzle IDs on the
2738
2804
     * command line. Useful for generating puzzles to be printed
2760
2826
        char *id;
2761
2827
        document *doc = NULL;
2762
2828
 
 
2829
        /*
 
2830
         * If we're in this branch, we should display any pending
 
2831
         * error message from the command line, since GTK isn't going
 
2832
         * to take another crack at making sense of it.
 
2833
         */
 
2834
        if (*errbuf) {
 
2835
            fputs(errbuf, stderr);
 
2836
            return 1;
 
2837
        }
 
2838
 
2763
2839
        n = ngenerate;
2764
2840
 
2765
2841
        me = midend_new(NULL, &thegame, NULL, NULL);
2790
2866
         * generated descriptive game IDs.)
2791
2867
         */
2792
2868
        while (ngenerate == 0 || i < n) {
2793
 
            char *pstr, *err;
 
2869
            char *pstr, *err, *seed;
 
2870
            struct rusage before, after;
2794
2871
 
2795
2872
            if (ngenerate == 0) {
2796
2873
                pstr = fgetline(stdin);
2816
2893
                    return 1;
2817
2894
                }
2818
2895
            }
 
2896
 
 
2897
            if (time_generation)
 
2898
                getrusage(RUSAGE_SELF, &before);
 
2899
 
 
2900
            midend_new_game(me);
 
2901
 
 
2902
            seed = midend_get_random_seed(me);
 
2903
 
 
2904
            if (time_generation) {
 
2905
                double elapsed;
 
2906
 
 
2907
                getrusage(RUSAGE_SELF, &after);
 
2908
 
 
2909
                elapsed = (after.ru_utime.tv_sec -
 
2910
                           before.ru_utime.tv_sec);
 
2911
                elapsed += (after.ru_utime.tv_usec -
 
2912
                            before.ru_utime.tv_usec) / 1000000.0;
 
2913
 
 
2914
                printf("%s %s: %.6f\n", thegame.name, seed, elapsed);
 
2915
            }
 
2916
 
 
2917
            if (test_solve && thegame.can_solve) {
 
2918
                /*
 
2919
                 * Now destroy the aux_info in the midend, by means of
 
2920
                 * re-entering the same game id, and then try to solve
 
2921
                 * it.
 
2922
                 */
 
2923
                char *game_id, *err;
 
2924
 
 
2925
                game_id = midend_get_game_id(me);
 
2926
                err = midend_game_id(me, game_id);
 
2927
                if (err) {
 
2928
                    fprintf(stderr, "%s %s: game id re-entry error: %s\n",
 
2929
                            thegame.name, seed, err);
 
2930
                    return 1;
 
2931
                }
 
2932
                midend_new_game(me);
 
2933
                sfree(game_id);
 
2934
 
 
2935
                err = midend_solve(me);
 
2936
                /*
 
2937
                 * If the solve operation returned the error "Solution
 
2938
                 * not known for this puzzle", that's OK, because that
 
2939
                 * just means it's a puzzle for which we don't have an
 
2940
                 * algorithmic solver and hence can't solve it without
 
2941
                 * the aux_info, e.g. Netslide. Any other error is a
 
2942
                 * problem, though.
 
2943
                 */
 
2944
                if (err && strcmp(err, "Solution not known for this puzzle")) {
 
2945
                    fprintf(stderr, "%s %s: solve error: %s\n",
 
2946
                            thegame.name, seed, err);
 
2947
                    return 1;
 
2948
                }
 
2949
            }
 
2950
 
2819
2951
            sfree(pstr);
2820
 
 
2821
 
            midend_new_game(me);
 
2952
            sfree(seed);
2822
2953
 
2823
2954
            if (doc) {
2824
2955
                err = midend_print_puzzle(me, doc, soln);
2862
2993
                }
2863
2994
                sfree(realname);
2864
2995
            }
2865
 
            if (!doc && !savefile) {
 
2996
            if (!doc && !savefile && !time_generation) {
2866
2997
                id = midend_get_game_id(me);
2867
2998
                puts(id);
2868
2999
                sfree(id);
2881
3012
        midend_free(me);
2882
3013
 
2883
3014
        return 0;
 
3015
    } else if (list_presets) {
 
3016
        /*
 
3017
         * Another specialist mode which causes the puzzle to list the
 
3018
         * game_params strings for all its preset configurations.
 
3019
         */
 
3020
        int i, npresets;
 
3021
        midend *me;
 
3022
 
 
3023
        me = midend_new(NULL, &thegame, NULL, NULL);
 
3024
        npresets = midend_num_presets(me);
 
3025
 
 
3026
        for (i = 0; i < npresets; i++) {
 
3027
            game_params *params;
 
3028
            char *name, *paramstr;
 
3029
 
 
3030
            midend_fetch_preset(me, i, &name, &params);
 
3031
            paramstr = thegame.encode_params(params, TRUE);
 
3032
 
 
3033
            printf("%s %s\n", paramstr, name);
 
3034
            sfree(paramstr);
 
3035
        }
 
3036
 
 
3037
        midend_free(me);
 
3038
        return 0;
2884
3039
    } else {
2885
3040
        frontend *fe;
2886
3041