ec086fce8fc573150eb2b40d3fd5a246acf2fb35
2 * gtk.c: GTK front end for my puzzle collection.
6 * - Handle resizing, probably just by forbidding it.
18 /* ----------------------------------------------------------------------
19 * Error reporting functions used elsewhere.
22 void fatal(char *fmt
, ...)
26 fprintf(stderr
, "fatal error: ");
29 vfprintf(stderr
, fmt
, ap
);
32 fprintf(stderr
, "\n");
36 /* ----------------------------------------------------------------------
37 * GTK front end to puzzles.
41 * This structure holds all the data relevant to a single window.
42 * In principle this would allow us to open multiple independent
43 * puzzle windows, although I can't currently see any real point in
44 * doing so. I'm just coding cleanly because there's no
45 * particularly good reason not to.
57 int bbox_l
, bbox_r
, bbox_u
, bbox_d
;
61 void frontend_default_colour(frontend
*fe
, float *output
)
63 GdkColor col
= fe
->window
->style
->bg
[GTK_STATE_NORMAL
];
64 output
[0] = col
.red
/ 65535.0;
65 output
[1] = col
.green
/ 65535.0;
66 output
[2] = col
.blue
/ 65535.0;
69 void start_draw(frontend
*fe
)
71 fe
->gc
= gdk_gc_new(fe
->area
->window
);
78 void draw_rect(frontend
*fe
, int x
, int y
, int w
, int h
, int colour
)
80 gdk_gc_set_foreground(fe
->gc
, &fe
->colours
[colour
]);
81 gdk_draw_rectangle(fe
->pixmap
, fe
->gc
, 1, x
, y
, w
, h
);
84 void draw_line(frontend
*fe
, int x1
, int y1
, int x2
, int y2
, int colour
)
86 gdk_gc_set_foreground(fe
->gc
, &fe
->colours
[colour
]);
87 gdk_draw_line(fe
->pixmap
, fe
->gc
, x1
, y1
, x2
, y2
);
90 void draw_polygon(frontend
*fe
, int *coords
, int npoints
,
93 GdkPoint
*points
= snewn(npoints
, GdkPoint
);
96 for (i
= 0; i
< npoints
; i
++) {
97 points
[i
].x
= coords
[i
*2];
98 points
[i
].y
= coords
[i
*2+1];
101 gdk_gc_set_foreground(fe
->gc
, &fe
->colours
[colour
]);
102 gdk_draw_polygon(fe
->pixmap
, fe
->gc
, fill
, points
, npoints
);
107 void draw_update(frontend
*fe
, int x
, int y
, int w
, int h
)
109 if (fe
->bbox_l
> x
) fe
->bbox_l
= x
;
110 if (fe
->bbox_r
< x
+w
) fe
->bbox_r
= x
+w
;
111 if (fe
->bbox_u
> y
) fe
->bbox_u
= y
;
112 if (fe
->bbox_d
< y
+h
) fe
->bbox_d
= y
+h
;
115 void end_draw(frontend
*fe
)
117 gdk_gc_unref(fe
->gc
);
120 if (fe
->bbox_l
< fe
->bbox_r
&& fe
->bbox_u
< fe
->bbox_d
) {
121 gdk_draw_pixmap(fe
->area
->window
,
122 fe
->area
->style
->fg_gc
[GTK_WIDGET_STATE(fe
->area
)],
124 fe
->bbox_l
, fe
->bbox_u
,
125 fe
->bbox_l
, fe
->bbox_u
,
126 fe
->bbox_r
- fe
->bbox_l
, fe
->bbox_d
- fe
->bbox_u
);
130 static void destroy(GtkWidget
*widget
, gpointer data
)
135 static gint
key_event(GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
137 frontend
*fe
= (frontend
*)data
;
142 if (event
->string
[0] && !event
->string
[1] &&
143 !midend_process_key(fe
->me
, 0, 0, event
->string
[0]))
144 gtk_widget_destroy(fe
->window
);
149 static gint
button_event(GtkWidget
*widget
, GdkEventButton
*event
,
152 frontend
*fe
= (frontend
*)data
;
158 if (event
->type
!= GDK_BUTTON_PRESS
)
161 if (event
->button
== 1)
162 button
= LEFT_BUTTON
;
163 else if (event
->button
== 2)
164 button
= MIDDLE_BUTTON
;
165 else if (event
->button
== 3)
166 button
= RIGHT_BUTTON
;
168 return FALSE
; /* don't even know what button! */
170 if (!midend_process_key(fe
->me
, event
->x
, event
->y
, button
))
171 gtk_widget_destroy(fe
->window
);
176 static gint
expose_area(GtkWidget
*widget
, GdkEventExpose
*event
,
179 frontend
*fe
= (frontend
*)data
;
182 gdk_draw_pixmap(widget
->window
,
183 widget
->style
->fg_gc
[GTK_WIDGET_STATE(widget
)],
185 event
->area
.x
, event
->area
.y
,
186 event
->area
.x
, event
->area
.y
,
187 event
->area
.width
, event
->area
.height
);
192 static gint
configure_area(GtkWidget
*widget
,
193 GdkEventConfigure
*event
, gpointer data
)
195 frontend
*fe
= (frontend
*)data
;
198 fe
->pixmap
= gdk_pixmap_new(widget
->window
, fe
->w
, fe
->h
, -1);
200 gc
= gdk_gc_new(fe
->area
->window
);
201 gdk_gc_set_foreground(gc
, &fe
->colours
[0]);
202 gdk_draw_rectangle(fe
->pixmap
, gc
, 1, 0, 0, fe
->w
, fe
->h
);
205 midend_redraw(fe
->me
);
210 static gint
timer_func(gpointer data
)
212 frontend
*fe
= (frontend
*)data
;
214 if (fe
->timer_active
)
215 midend_timer(fe
->me
, 0.02); /* may clear timer_active */
217 return fe
->timer_active
;
220 void deactivate_timer(frontend
*fe
)
222 fe
->timer_active
= FALSE
;
225 void activate_timer(frontend
*fe
)
227 gtk_timeout_add(20, timer_func
, fe
);
228 fe
->timer_active
= TRUE
;
231 static frontend
*new_window(void)
238 fe
->me
= midend_new(fe
);
239 midend_new_game(fe
->me
, NULL
);
241 fe
->window
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
248 fe
->colmap
= gdk_colormap_get_system();
249 colours
= midend_colours(fe
->me
, &ncolours
);
250 fe
->ncolours
= ncolours
;
251 fe
->colours
= snewn(ncolours
, GdkColor
);
252 for (i
= 0; i
< ncolours
; i
++) {
253 fe
->colours
[i
].red
= colours
[i
*3] * 0xFFFF;
254 fe
->colours
[i
].green
= colours
[i
*3+1] * 0xFFFF;
255 fe
->colours
[i
].blue
= colours
[i
*3+2] * 0xFFFF;
257 success
= snewn(ncolours
, gboolean
);
258 gdk_colormap_alloc_colors(fe
->colmap
, fe
->colours
, ncolours
,
259 FALSE
, FALSE
, success
);
260 for (i
= 0; i
< ncolours
; i
++) {
262 g_error("couldn't allocate colour %d (#%02x%02x%02x)\n",
263 i
, fe
->colours
[i
].red
>> 8,
264 fe
->colours
[i
].green
>> 8,
265 fe
->colours
[i
].blue
>> 8);
269 fe
->area
= gtk_drawing_area_new();
270 midend_size(fe
->me
, &x
, &y
);
271 gtk_drawing_area_size(GTK_DRAWING_AREA(fe
->area
), x
, y
);
275 gtk_container_add(GTK_CONTAINER(fe
->window
), fe
->area
);
279 gtk_signal_connect(GTK_OBJECT(fe
->window
), "destroy",
280 GTK_SIGNAL_FUNC(destroy
), fe
);
281 gtk_signal_connect(GTK_OBJECT(fe
->window
), "key_press_event",
282 GTK_SIGNAL_FUNC(key_event
), fe
);
283 gtk_signal_connect(GTK_OBJECT(fe
->area
), "button_press_event",
284 GTK_SIGNAL_FUNC(button_event
), fe
);
285 gtk_signal_connect(GTK_OBJECT(fe
->area
), "expose_event",
286 GTK_SIGNAL_FUNC(expose_area
), fe
);
287 gtk_signal_connect(GTK_OBJECT(fe
->area
), "configure_event",
288 GTK_SIGNAL_FUNC(configure_area
), fe
);
290 gtk_widget_add_events(GTK_WIDGET(fe
->area
), GDK_BUTTON_PRESS_MASK
);
292 gtk_widget_show(fe
->area
);
293 gtk_widget_show(fe
->window
);
298 int main(int argc
, char **argv
)
302 gtk_init(&argc
, &argv
);