X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/b8b0c81f36cda5cad1ac9e17616b727111d27ac1..97c2790f5b9e14225acc4b2a20ef33f0be4ab70c:/gtk.c diff --git a/gtk.c b/gtk.c index 24b2cca..7483a98 100644 --- a/gtk.c +++ b/gtk.c @@ -76,16 +76,17 @@ struct frontend { config_item *cfg; int cfg_which, cfgret; GtkWidget *cfgbox; - char *paste_data; + void *paste_data; int paste_data_len; + char *laststatus; }; void get_random_seed(void **randseed, int *randseedsize) { - time_t *tp = snew(time_t); - time(tp); - *randseed = (void *)tp; - *randseedsize = sizeof(time_t); + struct timeval *tvp = snew(struct timeval); + gettimeofday(tvp, NULL); + *randseed = (void *)tvp; + *randseedsize = sizeof(struct timeval); } void frontend_default_colour(frontend *fe, float *output) @@ -98,10 +99,19 @@ void frontend_default_colour(frontend *fe, float *output) void status_bar(frontend *fe, char *text) { + char *rewritten; + assert(fe->statusbar); - gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx); - gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, text); + 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); + } } void start_draw(frontend *fe) @@ -317,24 +327,26 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { frontend *fe = (frontend *)data; int keyval; + int shift = (event->state & GDK_SHIFT_MASK) ? MOD_SHFT : 0; + int ctrl = (event->state & GDK_CONTROL_MASK) ? MOD_CTRL : 0; if (!fe->pixmap) return TRUE; if (event->keyval == GDK_Up) - keyval = CURSOR_UP; + keyval = shift | ctrl | CURSOR_UP; else if (event->keyval == GDK_KP_Up || event->keyval == GDK_KP_8) keyval = MOD_NUM_KEYPAD | '8'; else if (event->keyval == GDK_Down) - keyval = CURSOR_DOWN; + keyval = shift | ctrl | CURSOR_DOWN; else if (event->keyval == GDK_KP_Down || event->keyval == GDK_KP_2) keyval = MOD_NUM_KEYPAD | '2'; else if (event->keyval == GDK_Left) - keyval = CURSOR_LEFT; + keyval = shift | ctrl | CURSOR_LEFT; else if (event->keyval == GDK_KP_Left || event->keyval == GDK_KP_4) keyval = MOD_NUM_KEYPAD | '4'; else if (event->keyval == GDK_Right) - keyval = CURSOR_RIGHT; + keyval = shift | ctrl | CURSOR_RIGHT; else if (event->keyval == GDK_KP_Right || event->keyval == GDK_KP_6) keyval = MOD_NUM_KEYPAD | '6'; else if (event->keyval == GDK_KP_Home || event->keyval == GDK_KP_7) @@ -375,10 +387,10 @@ static gint button_event(GtkWidget *widget, GdkEventButton *event, if (event->button == 2 || (event->state & GDK_SHIFT_MASK)) button = MIDDLE_BUTTON; + else if (event->button == 3 || (event->state & GDK_MOD1_MASK)) + button = RIGHT_BUTTON; else if (event->button == 1) button = LEFT_BUTTON; - else if (event->button == 3) - button = RIGHT_BUTTON; else return FALSE; /* don't even know what button! */ @@ -462,7 +474,7 @@ static gint configure_area(GtkWidget *widget, gdk_draw_rectangle(fe->pixmap, gc, 1, 0, 0, fe->w, fe->h); gdk_gc_unref(gc); - midend_redraw(fe->me); + midend_force_redraw(fe->me); return TRUE; } @@ -554,7 +566,7 @@ void message_box(GtkWidget *parent, char *title, char *msg, int centre) GTK_SIGNAL_FUNC(win_key_press), ok); gtk_window_set_modal(GTK_WINDOW(window), TRUE); gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(parent)); - //set_transient_window_pos(parent, window); + /* set_transient_window_pos(parent, window); */ gtk_widget_show(window); gtk_main(); } @@ -786,7 +798,7 @@ static int get_config(frontend *fe, int which) gtk_window_set_modal(GTK_WINDOW(fe->cfgbox), TRUE); gtk_window_set_transient_for(GTK_WINDOW(fe->cfgbox), GTK_WINDOW(fe->window)); - //set_transient_window_pos(fe->window, fe->cfgbox); + /* set_transient_window_pos(fe->window, fe->cfgbox); */ gtk_widget_show(fe->cfgbox); gtk_main(); @@ -824,6 +836,8 @@ int paste_initialised = FALSE; void init_paste() { + unsigned char empty[] = { 0 }; + if (paste_initialised) return; @@ -837,21 +851,21 @@ void init_paste() * ICCCM, we must do this before we start using cut buffers. */ XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER0, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER1, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER2, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER3, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER4, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER5, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER6, XA_STRING, 8, PropModeAppend, empty, 0); XChangeProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), - XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, "", 0); + XA_CUT_BUFFER7, XA_STRING, 8, PropModeAppend, empty, 0); } /* Store data in a cut-buffer. */ @@ -937,6 +951,13 @@ static void menu_solve_event(GtkMenuItem *menuitem, gpointer data) error_box(fe->window, msg); } +static void menu_restart_event(GtkMenuItem *menuitem, gpointer data) +{ + frontend *fe = (frontend *)data; + + midend_restart_game(fe->me); +} + static void menu_config_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; @@ -998,7 +1019,11 @@ static frontend *new_window(char *game_id, char **error) fe = snew(frontend); + fe->timer_active = FALSE; + fe->timer_id = -1; + fe->me = midend_new(fe, &thegame); + if (game_id) { *error = midend_game_id(fe->me, game_id); if (*error) { @@ -1032,7 +1057,12 @@ static frontend *new_window(char *game_id, char **error) gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "New", 'n'); - add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Restart", 'r'); + + menuitem = gtk_menu_item_new_with_label("Restart"); + gtk_container_add(GTK_CONTAINER(menu), menuitem); + gtk_signal_connect(GTK_OBJECT(menuitem), "activate", + GTK_SIGNAL_FUNC(menu_restart_event), fe); + gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_label("Specific..."); gtk_object_set_data(GTK_OBJECT(menuitem), "user-data", @@ -1131,24 +1161,9 @@ static frontend *new_window(char *game_id, char **error) fe->ncolours = ncolours; fe->colours = snewn(ncolours, GdkColor); for (i = 0; i < ncolours; i++) { - /* - * Just for Gareth: if you dislike any of the standard - * colours, here's your chance to configure them in a - * really hacky way. - */ - char buf[80], *e; - unsigned int r, g, b; - sprintf(buf, "PUZZLE_COLOUR_%d", i); - if ((e = getenv(buf)) != NULL && - sscanf(e, "%2x%2x%2x", &r, &g, &b) == 3) { - fe->colours[i].red = r * 0x101; - fe->colours[i].green = g * 0x101; - fe->colours[i].blue = b * 0x101; - } else { - fe->colours[i].red = colours[i*3] * 0xFFFF; - fe->colours[i].green = colours[i*3+1] * 0xFFFF; - fe->colours[i].blue = colours[i*3+2] * 0xFFFF; - } + fe->colours[i].red = colours[i*3] * 0xFFFF; + fe->colours[i].green = colours[i*3+1] * 0xFFFF; + fe->colours[i].blue = colours[i*3+2] * 0xFFFF; } success = snewn(ncolours, gboolean); gdk_colormap_alloc_colors(fe->colmap, fe->colours, ncolours, @@ -1197,7 +1212,7 @@ static frontend *new_window(char *game_id, char **error) fe->fonts = NULL; fe->nfonts = fe->fontsize = 0; - fe->timer_active = FALSE; + fe->laststatus = NULL; fe->paste_data = NULL; fe->paste_data_len = 0; @@ -1239,6 +1254,12 @@ int main(int argc, char **argv) char *pname = argv[0]; char *error; + if (argc > 1 && !strcmp(argv[1], "--version")) { + printf("%s, from Simon Tatham's Portable Puzzle Collection\n%s\n", + thegame.name, ver); + return 0; + } + /* * Special standalone mode for generating puzzle IDs on the * command line. Useful for generating puzzles to be printed @@ -1277,7 +1298,10 @@ int main(int argc, char **argv) if ( (seed = strchr(params, '#')) != NULL ) *seed++ = '\0'; thegame.decode_params(par, params); - } else { + } + if ((error = thegame.validate_params(par)) != NULL) { + fprintf(stderr, "%s: %s\n", pname, error); + return 1; } parstr = thegame.encode_params(par, FALSE); @@ -1295,7 +1319,7 @@ int main(int argc, char **argv) while (n-- > 0) { game_aux_info *aux = NULL; - char *desc = thegame.new_desc(par, rs, &aux); + char *desc = thegame.new_desc(par, rs, &aux, FALSE); printf("%s:%s\n", parstr, desc); sfree(desc); if (aux)