X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/08d7c4ba7266c626d28273750218446d3c693805..854a4f51614eb4a6a23e15204d30d1e57ef83c6f:/gtk.c diff --git a/gtk.c b/gtk.c index 99cc4cb..30389e9 100644 --- a/gtk.c +++ b/gtk.c @@ -15,6 +15,8 @@ #include #include +#include + #include #include #include @@ -1098,15 +1100,10 @@ static void get_size(frontend *fe, int *px, int *py) gdk_window_resize(GTK_WIDGET(win)->window, x, y) #endif -static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) +static void resize_fe(frontend *fe) { - frontend *fe = (frontend *)data; - game_params *params = - (game_params *)gtk_object_get_data(GTK_OBJECT(menuitem), "user-data"); int x, y; - midend_set_params(fe->me, params); - midend_new_game(fe->me); get_size(fe, &x, &y); fe->w = x; fe->h = y; @@ -1118,6 +1115,17 @@ static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) } } +static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) +{ + frontend *fe = (frontend *)data; + game_params *params = + (game_params *)gtk_object_get_data(GTK_OBJECT(menuitem), "user-data"); + + midend_set_params(fe->me, params); + midend_new_game(fe->me); + resize_fe(fe); +} + GdkAtom compound_text_atom, utf8_string_atom; int paste_initialised = FALSE; @@ -1323,7 +1331,6 @@ static void menu_load_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; char *name, *err; - int x, y; name = file_selector(fe, "Enter name of saved game file to load", FALSE); @@ -1345,16 +1352,7 @@ static void menu_load_event(GtkMenuItem *menuitem, gpointer data) return; } - get_size(fe, &x, &y); - fe->w = x; - fe->h = y; - gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y); - { - GtkRequisition req; - gtk_widget_size_request(GTK_WIDGET(fe->window), &req); - gtk_window_resize(GTK_WINDOW(fe->window), req.width, req.height); - } - + resize_fe(fe); } } @@ -1381,21 +1379,12 @@ static void menu_config_event(GtkMenuItem *menuitem, gpointer data) frontend *fe = (frontend *)data; int which = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(menuitem), "user-data")); - int x, y; if (!get_config(fe, which)) return; midend_new_game(fe->me); - get_size(fe, &x, &y); - fe->w = x; - fe->h = y; - gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y); - { - GtkRequisition req; - gtk_widget_size_request(GTK_WIDGET(fe->window), &req); - gtk_window_resize(GTK_WINDOW(fe->window), req.width, req.height); - } + resize_fe(fe); } static void menu_about_event(GtkMenuItem *menuitem, gpointer data) @@ -1451,13 +1440,19 @@ static void add_menu_separator(GtkContainer *cont) gtk_widget_show(menuitem); } -static frontend *new_window(char *arg, char **error) +enum { ARG_EITHER, ARG_SAVE, ARG_ID }; /* for argtype */ + +static frontend *new_window(char *arg, int argtype, char **error) { frontend *fe; GtkBox *vbox; GtkWidget *menubar, *menu, *menuitem; + GdkPixmap *iconpm; + GList *iconlist; int x, y, n; char errbuf[1024]; + extern char *const *const xpm_icons[]; + extern const int n_xpm_icons; fe = snew(frontend); @@ -1468,30 +1463,53 @@ static frontend *new_window(char *arg, char **error) if (arg) { char *err; + FILE *fp; errbuf[0] = '\0'; - /* - * Try treating the argument as a game ID. - */ - err = midend_game_id(fe->me, arg); - if (!err) { - /* - * It's a valid game ID. - */ - midend_new_game(fe->me); - } else { - FILE *fp = fopen(arg, "r"); + switch (argtype) { + case ARG_ID: + err = midend_game_id(fe->me, arg); + if (!err) + midend_new_game(fe->me); + else + sprintf(errbuf, "Invalid game ID: %.800s", err); + break; + case ARG_SAVE: + fp = fopen(arg, "r"); if (!fp) { - sprintf(errbuf, "Supplied argument is neither a game ID (%.400s)" - " nor a save file (%.400s)", err, strerror(errno)); + sprintf(errbuf, "Error opening file: %.800s", strerror(errno)); } else { err = midend_deserialise(fe->me, savefile_read, fp); if (err) - sprintf(errbuf, "%.800s", err); + sprintf(errbuf, "Invalid save file: %.800s", err); fclose(fp); } - } + break; + default /*case ARG_EITHER*/: + /* + * First try treating the argument as a game ID. + */ + err = midend_game_id(fe->me, arg); + if (!err) { + /* + * It's a valid game ID. + */ + midend_new_game(fe->me); + } else { + FILE *fp = fopen(arg, "r"); + if (!fp) { + sprintf(errbuf, "Supplied argument is neither a game ID (%.400s)" + " nor a save file (%.400s)", err, strerror(errno)); + } else { + err = midend_deserialise(fe->me, savefile_read, fp); + if (err) + sprintf(errbuf, "%.800s", err); + fclose(fp); + } + } + break; + } if (*errbuf) { *error = dupstr(errbuf); midend_free(fe->me); @@ -1585,12 +1603,12 @@ static frontend *new_window(char *arg, char **error) } add_menu_separator(GTK_CONTAINER(menu)); - menuitem = gtk_menu_item_new_with_label("Load"); + menuitem = gtk_menu_item_new_with_label("Load..."); gtk_container_add(GTK_CONTAINER(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_load_event), fe); gtk_widget_show(menuitem); - menuitem = gtk_menu_item_new_with_label("Save"); + menuitem = gtk_menu_item_new_with_label("Save..."); gtk_container_add(GTK_CONTAINER(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", GTK_SIGNAL_FUNC(menu_save_event), fe); @@ -1720,6 +1738,21 @@ static frontend *new_window(char *arg, char **error) GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK); + if (n_xpm_icons) { + gtk_widget_realize(fe->window); + iconpm = gdk_pixmap_create_from_xpm_d(fe->window->window, NULL, + NULL, (gchar **)xpm_icons[0]); + gdk_window_set_icon(fe->window->window, NULL, iconpm, NULL); + iconlist = NULL; + for (n = 0; n < n_xpm_icons; n++) { + iconlist = + g_list_append(iconlist, + gdk_pixbuf_new_from_xpm_data((const gchar **) + xpm_icons[n])); + } + gdk_window_set_icon_list(fe->window->window, iconlist); + } + gtk_widget_show(fe->area); gtk_widget_show(fe->window); @@ -1755,7 +1788,10 @@ int main(int argc, char **argv) int ngenerate = 0, print = FALSE, px = 1, py = 1; int soln = FALSE, colour = FALSE; float scale = 1.0F; + float redo_proportion = 0.0F; char *arg = NULL; + int argtype = ARG_EITHER; + char *screenshot_file = NULL; int doing_opts = TRUE; int ac = argc; char **av = argv; @@ -1826,6 +1862,49 @@ int main(int argc, char **argv) pname); return 1; } + } else if (doing_opts && !strcmp(p, "--redo")) { + /* + * This is an internal option which I don't expect + * users to have any particular use for. The effect of + * --redo is that once the game has been loaded and + * initialised, the next move in the redo chain is + * replayed, and the game screen is redrawn part way + * through the making of the move. This is only + * meaningful if there _is_ a next move in the redo + * chain, which means in turn that this option is only + * useful if you're also passing a save file on the + * command line. + * + * This option is used by the script which generates + * the puzzle icons and website screenshots, and I + * don't imagine it's useful for anything else. + * (Unless, I suppose, users don't like my screenshots + * and want to generate their own in the same way for + * some repackaged version of the puzzles.) + */ + if (--ac > 0) { + redo_proportion = atof(*++av); + } else { + fprintf(stderr, "%s: no argument supplied to '--redo'\n", + pname); + return 1; + } + } else if (doing_opts && !strcmp(p, "--screenshot")) { + /* + * Another internal option for the icon building + * script. This causes a screenshot of the central + * drawing area (i.e. not including the menu bar or + * status bar) to be saved to a PNG file once the + * window has been drawn, and then the application + * quits immediately. + */ + if (--ac > 0) { + screenshot_file = *++av; + } else { + fprintf(stderr, "%s: no argument supplied to '--screenshot'\n", + pname); + return 1; + } } else if (doing_opts && (!strcmp(p, "--with-solutions") || !strcmp(p, "--with-solution") || !strcmp(p, "--with-solns") || @@ -1842,6 +1921,10 @@ int main(int argc, char **argv) return 1; } colour = TRUE; + } else if (doing_opts && !strcmp(p, "--load")) { + argtype = ARG_SAVE; + } else if (doing_opts && !strcmp(p, "--game")) { + argtype = ARG_ID; } else if (doing_opts && !strcmp(p, "--")) { doing_opts = FALSE; } else if (!doing_opts || p[0] != '-') { @@ -1858,6 +1941,11 @@ int main(int argc, char **argv) } } + if (*errbuf) { + fputs(errbuf, stderr); + return 1; + } + /* * Special standalone mode for generating puzzle IDs on the * command line. Useful for generating puzzles to be printed @@ -1885,11 +1973,6 @@ int main(int argc, char **argv) char *id; document *doc = NULL; - if (*errbuf) { - fputs(errbuf, stderr); - return 1; - } - n = ngenerate; me = midend_new(NULL, &thegame, NULL, NULL); @@ -1971,14 +2054,47 @@ int main(int argc, char **argv) return 0; } else { + frontend *fe; gtk_init(&argc, &argv); - if (!new_window(argc > 1 ? argv[1] : NULL, &error)) { + fe = new_window(arg, argtype, &error); + + if (!fe) { fprintf(stderr, "%s: %s\n", pname, error); return 1; } + if (screenshot_file) { + /* + * Some puzzles will not redraw their entire area if + * given a partially completed animation, which means + * we must redraw now and _then_ redraw again after + * freezing the move timer. + */ + midend_force_redraw(fe->me); + } + + if (redo_proportion) { + /* Start a redo. */ + midend_process_key(fe->me, 0, 0, 'r'); + /* And freeze the timer at the specified position. */ + midend_freeze_timer(fe->me, redo_proportion); + } + + if (screenshot_file) { + GdkPixbuf *pb; + GError *gerror = NULL; + + midend_redraw(fe->me); + + pb = gdk_pixbuf_get_from_drawable(NULL, fe->pixmap, + NULL, 0, 0, 0, 0, -1, -1); + gdk_pixbuf_save(pb, screenshot_file, "png", &gerror, NULL); + + exit(0); + } + gtk_main(); }