config_item *cfg;
int cfg_which, cfgret;
GtkWidget *cfgbox;
- char *paste_data;
+ 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 */
};
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)
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)
fe->area->style->fg_gc[GTK_WIDGET_STATE(fe->area)],
fe->pixmap,
fe->bbox_l, fe->bbox_u,
- fe->bbox_l, fe->bbox_u,
+ fe->ox + fe->bbox_l, fe->oy + fe->bbox_u,
fe->bbox_r - fe->bbox_l, fe->bbox_d - fe->bbox_u);
}
}
{
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)
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! */
if (event->type == GDK_BUTTON_RELEASE)
button += LEFT_RELEASE - LEFT_BUTTON;
- if (!midend_process_key(fe->me, event->x, event->y, button))
+ if (!midend_process_key(fe->me, event->x - fe->ox,
+ event->y - fe->oy, button))
gtk_widget_destroy(fe->window);
return TRUE;
else
return FALSE; /* don't even know what button! */
- if (!midend_process_key(fe->me, event->x, event->y, button))
+ if (!midend_process_key(fe->me, event->x - fe->ox,
+ event->y - fe->oy, button))
gtk_widget_destroy(fe->window);
return TRUE;
gdk_draw_pixmap(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
fe->pixmap,
- event->area.x, event->area.y,
+ event->area.x - fe->ox, event->area.y - fe->oy,
event->area.x, event->area.y,
event->area.width, event->area.height);
}
{
frontend *fe = (frontend *)data;
GdkGC *gc;
+ int x, y;
if (fe->pixmap)
gdk_pixmap_unref(fe->pixmap);
- fe->pixmap = gdk_pixmap_new(widget->window, fe->w, fe->h, -1);
+ x = fe->w = event->width;
+ y = fe->h = event->height;
+ 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;
+
+ fe->pixmap = gdk_pixmap_new(widget->window, fe->pw, fe->ph, -1);
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->w, fe->h);
+ gdk_draw_rectangle(fe->pixmap, gc, 1, 0, 0, fe->pw, fe->ph);
gdk_gc_unref(gc);
- midend_redraw(fe->me);
+ midend_force_redraw(fe->me);
return TRUE;
}
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();
}
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();
gtk_widget_destroy(fe->window);
}
+static void get_size(frontend *fe, int *px, int *py)
+{
+ int x, y;
+
+ /*
+ * Currently I don't want to make the GTK port scale large
+ * puzzles to fit on the screen. This is because X does permit
+ * extremely large windows and many window managers provide a
+ * means of navigating round them, and the users I consulted
+ * before deciding said that they'd rather have enormous puzzle
+ * windows spanning multiple screen pages than have them
+ * shrunk. I could change my mind later or introduce
+ * configurability; this would be the place to do so, by
+ * replacing the initial values of x and y with the screen
+ * dimensions.
+ */
+ x = INT_MAX;
+ y = INT_MAX;
+ midend_size(fe->me, &x, &y, FALSE);
+ *px = x;
+ *py = y;
+}
+
+#if !GTK_CHECK_VERSION(2,0,0)
+#define gtk_window_resize(win, x, y) \
+ gdk_window_resize(GTK_WIDGET(win)->window, x, y)
+#endif
+
static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
{
frontend *fe = (frontend *)data;
midend_set_params(fe->me, params);
midend_new_game(fe->me);
- midend_size(fe->me, &x, &y);
- gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ get_size(fe, &x, &y);
fe->w = x;
fe->h = y;
+ gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ gtk_window_resize(GTK_WINDOW(fe->window), 1, 1);
}
GdkAtom compound_text_atom, utf8_string_atom;
void init_paste()
{
+ unsigned char empty[] = { 0 };
+
if (paste_initialised)
return;
* 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. */
return;
midend_new_game(fe->me);
- midend_size(fe->me, &x, &y);
- gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ get_size(fe, &x, &y);
fe->w = x;
fe->h = y;
+ gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+ gtk_window_resize(GTK_WINDOW(fe->window), 1, 1);
}
static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
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) {
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,
fe->statusbar = NULL;
fe->area = gtk_drawing_area_new();
- midend_size(fe->me, &x, &y);
+ get_size(fe, &x, &y);
gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
fe->w = x;
fe->h = y;
- gtk_box_pack_end(vbox, fe->area, FALSE, FALSE, 0);
+ gtk_box_pack_end(vbox, fe->area, TRUE, TRUE, 0);
fe->pixmap = NULL;
fe->fonts = NULL;
fe->nfonts = fe->fontsize = 0;
- fe->timer_active = FALSE;
+ fe->laststatus = NULL;
fe->paste_data = NULL;
fe->paste_data_len = 0;
gtk_widget_show(fe->area);
gtk_widget_show(fe->window);
+ gdk_window_set_background(fe->area->window, &fe->colours[0]);
+ gdk_window_set_background(fe->window->window, &fe->colours[0]);
+
return fe;
}
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
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);
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)