#endif
#if GTK_CHECK_VERSION(2,8,0)
# define USE_CAIRO
+# if GTK_CHECK_VERSION(3,0,0) || defined(GDK_DISABLE_DEPRECATED)
+# define USE_CAIRO_WITHOUT_PIXMAP
+# endif
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+/* The old names are still more concise! */
+#define gtk_hbox_new(x,y) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,y)
+#define gtk_vbox_new(x,y) gtk_box_new(GTK_ORIENTATION_VERTICAL,y)
+/* GTK 3 has retired stock button labels */
+#define LABEL_OK "_OK"
+#define LABEL_CANCEL "_Cancel"
+#define LABEL_NO "_No"
+#define LABEL_YES "_Yes"
+#define LABEL_SAVE "_Save"
+#define LABEL_OPEN "_Open"
+#define gtk_button_new_with_our_label gtk_button_new_with_mnemonic
+#else
+#define LABEL_OK GTK_STOCK_OK
+#define LABEL_CANCEL GTK_STOCK_CANCEL
+#define LABEL_NO GTK_STOCK_NO
+#define LABEL_YES GTK_STOCK_YES
+#define LABEL_SAVE GTK_STOCK_SAVE
+#define LABEL_OPEN GTK_STOCK_OPEN
+#define gtk_button_new_with_our_label gtk_button_new_from_stock
#endif
/* #undef USE_CAIRO */
const float *colours;
cairo_t *cr;
cairo_surface_t *image;
+#ifndef USE_CAIRO_WITHOUT_PIXMAP
GdkPixmap *pixmap;
+#endif
GdkColor background; /* for painting outside puzzle area */
#else
GdkPixmap *pixmap;
#ifdef OLD_FILESEL
char *filesel_name;
#endif
- int drawing_area_shrink_pending;
GSList *preset_radio;
int n_preset_menu_items;
int preset_threaded;
GtkWidget *preset_custom;
GtkWidget *copy_menu_item;
+#if !GTK_CHECK_VERSION(3,0,0)
+ int drawing_area_shrink_pending;
int menubar_is_local;
+#endif
};
struct blitter {
void frontend_default_colour(frontend *fe, float *output)
{
+#if !GTK_CHECK_VERSION(3,0,0)
+ /*
+ * Use the widget style's default background colour as the
+ * background for the puzzle drawing area.
+ */
GdkColor col = gtk_widget_get_style(fe->window)->bg[GTK_STATE_NORMAL];
output[0] = col.red / 65535.0;
output[1] = col.green / 65535.0;
output[2] = col.blue / 65535.0;
+#else
+ /*
+ * GTK 3 has decided that there's no such thing as a 'default
+ * background colour' any more, because widget styles might set
+ * the background to something more complicated like a background
+ * image. We don't want to get into overlaying our entire puzzle
+ * on an arbitrary background image, so we'll just make up a
+ * reasonable shade of grey.
+ */
+ output[0] = output[1] = output[2] = 0.9F;
+#endif
}
void gtk_status_bar(void *handle, char *text)
static void teardown_drawing(frontend *fe)
{
- cairo_t *cr;
-
cairo_destroy(fe->cr);
fe->cr = NULL;
- cr = gdk_cairo_create(fe->pixmap);
- cairo_set_source_surface(cr, fe->image, 0, 0);
- cairo_rectangle(cr,
- fe->bbox_l - 1,
- fe->bbox_u - 1,
- fe->bbox_r - fe->bbox_l + 2,
- fe->bbox_d - fe->bbox_u + 2);
- cairo_fill(cr);
- cairo_destroy(cr);
+#ifndef USE_CAIRO_WITHOUT_PIXMAP
+ {
+ cairo_t *cr = gdk_cairo_create(fe->pixmap);
+ cairo_set_source_surface(cr, fe->image, 0, 0);
+ cairo_rectangle(cr,
+ fe->bbox_l - 1,
+ fe->bbox_u - 1,
+ fe->bbox_r - fe->bbox_l + 2,
+ fe->bbox_d - fe->bbox_u + 2);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+ }
+#endif
}
static void snaffle_colours(frontend *fe)
static void set_window_background(frontend *fe, int colour)
{
+#if GTK_CHECK_VERSION(3,0,0)
+ GdkRGBA rgba;
+ rgba.red = fe->colours[3*colour + 0];
+ rgba.green = fe->colours[3*colour + 1];
+ rgba.blue = fe->colours[3*colour + 2];
+ rgba.alpha = 1.0;
+ gdk_window_set_background_rgba(gtk_widget_get_window(fe->area), &rgba);
+ gdk_window_set_background_rgba(gtk_widget_get_window(fe->window), &rgba);
+#else
GdkColormap *colmap;
colmap = gdk_colormap_get_system();
&fe->background);
gdk_window_set_background(gtk_widget_get_window(fe->window),
&fe->background);
+#endif
}
static PangoLayout *make_pango_layout(frontend *fe)
fe->image = NULL;
}
-static void setup_backing_store(frontend *fe)
+static void wipe_and_destroy_cairo(frontend *fe, cairo_t *cr)
{
- cairo_t *cr;
- int i;
+ cairo_set_source_rgb(cr, fe->colours[0], fe->colours[1], fe->colours[2]);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+}
+static void setup_backing_store(frontend *fe)
+{
+#ifndef USE_CAIRO_WITHOUT_PIXMAP
fe->pixmap = gdk_pixmap_new(gtk_widget_get_window(fe->area),
fe->pw, fe->ph, -1);
+#endif
fe->image = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
fe->pw, fe->ph);
- for (i = 0; i < 3; i++) {
- switch (i) {
- case 0: cr = cairo_create(fe->image); break;
- case 1: cr = gdk_cairo_create(fe->pixmap); break;
- case 2: cr = gdk_cairo_create(gtk_widget_get_window(fe->area));
- break;
- }
- cairo_set_source_rgb(cr,
- fe->colours[0], fe->colours[1], fe->colours[2]);
- cairo_paint(cr);
- cairo_destroy(cr);
- }
+ wipe_and_destroy_cairo(fe, cairo_create(fe->image));
+#ifndef USE_CAIRO_WITHOUT_PIXMAP
+ wipe_and_destroy_cairo(fe, gdk_cairo_create(fe->pixmap));
+#endif
+ wipe_and_destroy_cairo(fe, gdk_cairo_create
+ (gtk_widget_get_window(fe->area)));
}
static int backing_store_ok(frontend *fe)
static void teardown_backing_store(frontend *fe)
{
cairo_surface_destroy(fe->image);
+#ifndef USE_CAIRO_WITHOUT_PIXMAP
gdk_pixmap_unref(fe->pixmap);
+#endif
fe->image = NULL;
}
#endif
+#ifndef USE_CAIRO_WITHOUT_PIXMAP
static void repaint_rectangle(frontend *fe, GtkWidget *widget,
int x, int y, int w, int h)
{
x - fe->ox, y - fe->oy, x, y, w, h);
gdk_gc_unref(gc);
}
+#endif
/* ----------------------------------------------------------------------
* Pango font functions.
teardown_drawing(fe);
if (fe->bbox_l < fe->bbox_r && fe->bbox_u < fe->bbox_d) {
+#ifdef USE_CAIRO_WITHOUT_PIXMAP
+ gtk_widget_queue_draw_area(fe->area,
+ fe->bbox_l - 1 + fe->ox,
+ fe->bbox_u - 1 + fe->oy,
+ fe->bbox_r - fe->bbox_l + 2,
+ fe->bbox_d - fe->bbox_u + 2);
+#else
repaint_rectangle(fe, fe->area,
fe->bbox_l - 1 + fe->ox,
fe->bbox_u - 1 + fe->oy,
fe->bbox_r - fe->bbox_l + 2,
fe->bbox_d - fe->bbox_u + 2);
+#endif
}
}
return TRUE;
}
+#if GTK_CHECK_VERSION(3,0,0)
+static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+ frontend *fe = (frontend *)data;
+ GdkRectangle dirtyrect;
+
+ gdk_cairo_get_clip_rectangle(cr, &dirtyrect);
+ cairo_set_source_surface(cr, fe->image, fe->ox, fe->oy);
+ cairo_rectangle(cr, dirtyrect.x, dirtyrect.y,
+ dirtyrect.width, dirtyrect.height);
+ cairo_fill(cr);
+
+ return TRUE;
+}
+#else
static gint expose_area(GtkWidget *widget, GdkEventExpose *event,
gpointer data)
{
frontend *fe = (frontend *)data;
if (backing_store_ok(fe)) {
+#ifdef USE_CAIRO_WITHOUT_PIXMAP
+ cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
+ cairo_set_source_surface(cr, fe->image, fe->ox, fe->oy);
+ cairo_rectangle(cr, event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_fill(cr);
+ cairo_destroy(cr);
+#else
repaint_rectangle(fe, widget,
event->area.x, event->area.y,
event->area.width, event->area.height);
+#endif
}
return TRUE;
}
+#endif
static gint map_window(GtkWidget *widget, GdkEvent *event,
gpointer data)
if (!fe)
return; /* can happen due to --generate */
if (fe->timer_active)
- gtk_timeout_remove(fe->timer_id);
+ g_source_remove(fe->timer_id);
fe->timer_active = FALSE;
}
if (!fe)
return; /* can happen due to --generate */
if (!fe->timer_active) {
- fe->timer_id = gtk_timeout_add(20, timer_func, fe);
+ fe->timer_id = g_timeout_add(20, timer_func, fe);
gettimeofday(&fe->last_time, NULL);
}
fe->timer_active = TRUE;
gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
if (type == MB_OK) {
- titles = GTK_STOCK_OK "\0";
+ titles = LABEL_OK "\0";
def = cancel = 0;
} else {
assert(type == MB_YESNO);
- titles = GTK_STOCK_NO "\0" GTK_STOCK_YES "\0";
+ titles = LABEL_NO "\0" LABEL_YES "\0";
def = 1;
cancel = 0;
}
i = 0;
while (*titles) {
- button = gtk_button_new_from_stock(titles);
+ button = gtk_button_new_with_our_label(titles);
gtk_box_pack_end
(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(window))),
button, FALSE, FALSE, 0);
gtk_window_set_title(GTK_WINDOW(fe->cfgbox), title);
sfree(title);
- w = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+ w = gtk_button_new_with_our_label(LABEL_CANCEL);
gtk_box_pack_end
(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(fe->cfgbox))),
w, FALSE, FALSE, 0);
G_CALLBACK(config_cancel_button_clicked), fe);
cancel = w;
- w = gtk_button_new_from_stock(GTK_STOCK_OK);
+ w = gtk_button_new_with_our_label(LABEL_OK);
gtk_box_pack_end
(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(fe->cfgbox))),
w, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(w), "clicked",
G_CALLBACK(config_ok_button_clicked), fe);
+#if GTK_CHECK_VERSION(3,0,0)
+ table = gtk_grid_new();
+#else
table = gtk_table_new(1, 2, FALSE);
+#endif
y = 0;
gtk_box_pack_start
(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(fe->cfgbox))),
gtk_widget_show(table);
for (i = fe->cfg; i->type != C_END; i++) {
+#if !GTK_CHECK_VERSION(3,0,0)
gtk_table_resize(GTK_TABLE(table), y+1, 2);
+#endif
switch (i->type) {
case C_STRING:
w = gtk_label_new(i->name);
gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_grid_attach(GTK_GRID(table), w, 0, y, 1, 1);
+#else
gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1,
GTK_SHRINK | GTK_FILL,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
3, 3);
+#endif
gtk_widget_show(w);
w = gtk_entry_new();
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_grid_attach(GTK_GRID(table), w, 1, y, 1, 1);
+ g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
+#else
gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
3, 3);
+#endif
gtk_entry_set_text(GTK_ENTRY(w), i->sval);
g_signal_connect(G_OBJECT(w), "changed",
G_CALLBACK(editbox_changed), i);
w = gtk_check_button_new_with_label(i->name);
g_signal_connect(G_OBJECT(w), "toggled",
G_CALLBACK(button_toggled), i);
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_grid_attach(GTK_GRID(table), w, 0, y, 2, 1);
+ g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
+#else
gtk_table_attach(GTK_TABLE(table), w, 0, 2, y, y+1,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
3, 3);
+#endif
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), i->ival);
gtk_widget_show(w);
break;
w = gtk_label_new(i->name);
gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_grid_attach(GTK_GRID(table), w, 0, y, 1, 1);
+#else
gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1,
GTK_SHRINK | GTK_FILL,
GTK_EXPAND | GTK_SHRINK | GTK_FILL ,
3, 3);
+#endif
gtk_widget_show(w);
{
G_CALLBACK(droplist_sel), i);
}
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_grid_attach(GTK_GRID(table), w, 1, y, 1, 1);
+ g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL);
+#else
gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
3, 3);
+#endif
gtk_widget_show(w);
break;
}
}
}
+#if !GTK_CHECK_VERSION(3,0,0)
static gboolean not_size_allocated_yet(GtkWidget *w)
{
/*
fe->drawing_area_shrink_pending = FALSE;
}
}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
static gint configure_window(GtkWidget *widget,
GdkEventConfigure *event, gpointer data)
{
- frontend *fe = (frontend *)data;
+#if !GTK_CHECK_VERSION(3,0,0)
/*
* When the main puzzle window changes size, it might be because
* the menu bar or status bar has turned up after starting off
* absent, in which case we should have another go at enacting a
* pending shrink of the drawing area.
*/
+ frontend *fe = (frontend *)data;
try_shrink_drawing_area(fe);
+#endif
return FALSE;
}
int x, y;
get_size(fe, &x, &y);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_window_resize_to_geometry(GTK_WINDOW(fe->window), x, y);
+#else
fe->w = x;
fe->h = y;
fe->drawing_area_shrink_pending = FALSE;
}
fe->drawing_area_shrink_pending = TRUE;
try_shrink_drawing_area(fe);
+#endif
}
static void menu_preset_event(GtkMenuItem *menuitem, gpointer data)
GTK_WINDOW(fe->window),
save ? GTK_FILE_CHOOSER_ACTION_SAVE :
GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- save ? GTK_STOCK_SAVE : GTK_STOCK_OPEN,
+ LABEL_CANCEL, GTK_RESPONSE_CANCEL,
+ save ? LABEL_SAVE : LABEL_OPEN,
GTK_RESPONSE_ACCEPT,
NULL);
frontend *fe;
GtkBox *vbox, *hbox;
GtkWidget *menu, *menuitem;
- GdkPixmap *iconpm;
GList *iconlist;
int x, y, n;
char errbuf[1024];
midend_new_game(fe->me);
}
+#if !GTK_CHECK_VERSION(3,0,0)
{
/*
* try_shrink_drawing_area() will do some fiddling with the
fe->menubar_is_local = !unity_mode;
}
}
+#endif
fe->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(fe->window), thegame.name);
(GTK_STATUSBAR(fe->statusbar), "game");
gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx,
"test");
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_widget_get_preferred_size(fe->statusbar, &req, NULL);
+#else
gtk_widget_size_request(fe->statusbar, &req);
-#if 0
- /* For GTK 2.0, should we be using gtk_widget_set_size_request? */
#endif
- gtk_widget_set_usize(viewport, -1, req.height);
+ gtk_widget_set_size_request(viewport, -1, req.height);
} else
fe->statusbar = NULL;
fe->area = gtk_drawing_area_new();
-#if GTK_CHECK_VERSION(2,0,0)
+#if GTK_CHECK_VERSION(2,0,0) && !GTK_CHECK_VERSION(3,0,0)
gtk_widget_set_double_buffered(fe->area, FALSE);
#endif
+ {
+ GdkGeometry geom;
+ geom.base_width = geom.base_height = 0;
+ gtk_window_set_geometry_hints(GTK_WINDOW(fe->window), fe->area,
+ &geom, GDK_HINT_BASE_SIZE);
+ }
get_size(fe, &x, &y);
+#if GTK_CHECK_VERSION(3,0,0)
+ gtk_window_set_default_geometry(GTK_WINDOW(fe->window), x, y);
+#else
fe->drawing_area_shrink_pending = FALSE;
gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y);
+#endif
fe->w = x;
fe->h = y;
G_CALLBACK(selection_get), fe);
g_signal_connect(G_OBJECT(fe->area), "selection_clear_event",
G_CALLBACK(selection_clear), fe);
+#if GTK_CHECK_VERSION(3,0,0)
+ g_signal_connect(G_OBJECT(fe->area), "draw",
+ G_CALLBACK(draw_area), fe);
+#else
g_signal_connect(G_OBJECT(fe->area), "expose_event",
G_CALLBACK(expose_area), fe);
+#endif
g_signal_connect(G_OBJECT(fe->window), "map_event",
G_CALLBACK(map_window), fe);
g_signal_connect(G_OBJECT(fe->area), "configure_event",
GDK_POINTER_MOTION_HINT_MASK);
if (n_xpm_icons) {
- gtk_widget_realize(fe->window);
- iconpm = gdk_pixmap_create_from_xpm_d
- (gtk_widget_get_window(fe->window), NULL, NULL,
- (gchar **)xpm_icons[0]);
- gdk_window_set_icon(gtk_widget_get_window(fe->window),
- NULL, iconpm, NULL);
+ gtk_window_set_icon(GTK_WINDOW(fe->window),
+ gdk_pixbuf_new_from_xpm_data
+ ((const gchar **)xpm_icons[0]));
+
iconlist = NULL;
for (n = 0; n < n_xpm_icons; n++) {
iconlist =
gdk_pixbuf_new_from_xpm_data((const gchar **)
xpm_icons[n]));
}
- gdk_window_set_icon_list(gtk_widget_get_window(fe->window), iconlist);
+ gtk_window_set_icon_list(GTK_WINDOW(fe->window), iconlist);
}
gtk_widget_show(fe->area);
gtk_widget_show(fe->window);
+#if !GTK_CHECK_VERSION(3,0,0)
fe->drawing_area_shrink_pending = TRUE;
try_shrink_drawing_area(fe);
+#endif
+
set_window_background(fe, 0);
return fe;