1 /* $Header: /home/jcb/MahJong/newmj/RCS/gui-dial.c,v 12.15 2020/05/16 15:46:02 jcb Exp $
2 * gui-dial.c
3 * dialog box functions.
4 */
5 /****************** COPYRIGHT STATEMENT **********************
6 * This file is Copyright (c) 2000 by J. C. Bradfield. *
7 * Distribution and use is governed by the LICENCE file that *
8 * accompanies this file. *
9 * The moral rights of the author are asserted. *
10 * *
11 ***************** DISCLAIMER OF WARRANTY ********************
12 * This code is not warranted fit for any purpose. See the *
13 * LICENCE file for further information. *
14 * *
15 *************************************************************/
16
17 #include "gui.h"
18 #ifdef GTK2
19 #define GTK_WINDOW_DIALOG GTK_WINDOW_TOPLEVEL
20 #endif
21
22 static const char rcs_id[] = "$Header: /home/jcb/MahJong/newmj/RCS/gui-dial.c,v 12.15 2020/05/16 15:46:02 jcb Exp $";
23
24 static void continue_callback(GtkWidget *w, gpointer data);
25 static void turn_callback(GtkWidget *w, gpointer data);
26
27 static void debug_report_query_popup(void);
28
29 /* useful things */
30 const char *windnames[] = { "none", "East", "South", "West", "North" };
31 const char *shortwindnames[] = { " ", "E", "S", "W", "N" };
32
33 /* check box to keep keyboard focus in message window */
34 static GtkWidget *mfocus;
35
36 /* This grabs focus, unless the chat window is in the main window
37 and has focus. This stops focus being lost from the chat entry
38 box every time a dialog pops up. (Requested by users, to avoid
39 accidental discards.
40 Moreover, if the appropriate checkbox is set, it
41 keeps the focus in the message window.
42 */
43 static void grab_focus_if_appropriate(GtkWidget *w);
44
45 /* Used sordidly and internally */
46 static GtkRequisition discard_req = { 0, 0};
47 /* Why an array? So I can pass pointers around */
48 DiscardDialog discard_dialog[1];
49
50 /* dialog box for specifying chows */
51 GtkWidget *chow_dialog;
52 /* Stores the three TileSetBoxes */
53 static TileSetBox chowtsbs[3];
54 /* and the three buttons */
55 static GtkWidget *chowbuttons[3];
56
57 /* dialog box for declaring specials */
58 GtkWidget *ds_dialog;
59
60 /* dialog box for continuing with next hand */
61 GtkWidget *continue_dialog;
62
63 /* for end of game */
64 GtkWidget *end_dialog;
65
66 /* dialog for opening connection */
67 GtkWidget *open_dialog;
68 GtkWidget *openmenuentry, *newgamemenuentry, *resumegamemenuentry,
69 *savemenuentry, *saveasmenuentry, *closemenuentry, *gameoptionsmenuentry;
70 /* entry for showing warnings window */
71 static GtkWidget *warningentry;
72
73 /* dialog box for action when it's our turn.
74 Actions: Discard Kong Mah Jong
75 As of 11.80, Kong includes adding a tile to an existing pung
76 */
77 GtkWidget *turn_dialog;
78 GtkWidget *turn_dialog_label; /* used to display number of tiles left */
79
80 /* dialog box for closed sets when scoring.
81 Actions: Eyes Chow Pung Done
82 */
83 GtkWidget *scoring_dialog;
84
85 /* window for game status display */
86 GtkWidget *status_window;
87
88 /* window for "about" information */
89 GtkWidget *about_window;
90 /* window to nag for donations */
91 GtkWidget *nag_window;
92
93 /* an array of text widgets for displaying scores etc.
94 Element 4 is for settlements.
95 The others are for each player: currently, I think
96 these should be table relative.
97 */
98 GtkWidget *scoring_notebook;
99 GtkWidget *textpages[5];
100 GtkWidget *textlabels[5]; /* labels for the pages */
101 GtkWidget *textwindow; /* and the window for it */
102
103 /* Window for scoring history */
104 GtkWidget *scorehistorywindow;
105 GtkWidget *scorehistorytext;
106
107 /* The window for messages, and the display text widget */
108 GtkWidget *messagewindow, *messagetext;
109
110 #ifdef GTK2
111 GtkTextBuffer *messagetextbuf;
112 GtkTextIter messagetextiter;
113 #endif
114
115 /* Warning window */
116 GtkWidget *warningwindow, *warningtext;
117
118 #ifdef GTK2
119 GtkTextBuffer *warningtextbuf;
120 GtkTextIter warningtextiter;
121 #endif
122
123 /* The Save As.. dialog */
124 GtkWidget *save_window;
125 /* and its text entry widget */
126 GtkWidget *save_text;
127
128 /* Password entry dialog */
129 GtkWidget *password_window;
130 /* and its text entry widget */
131 GtkWidget *password_text;
132
133 /* The window for display options */
134 GtkWidget *display_option_dialog = NULL;
135
136 /* the window for updating the game options */
137 GtkWidget *game_option_dialog = NULL;
138 GtkWidget *game_option_panel = NULL;
139 /* and some of its buttons */
140 GtkWidget *game_option_apply_button = NULL;
141 GtkWidget *game_option_prefs_button = NULL;
142
143 /* and a very similar one for option preferences */
144 GtkWidget *game_prefs_dialog = NULL;
145 GtkWidget *game_prefs_panel = NULL;
146
147 /* and one for playing preferences */
148 GtkWidget *playing_prefs_dialog = NULL;
149
150 /* and one for debugging options */
151 static GtkWidget *debug_options_dialog = NULL;
152
153 /* message entry widget */
154 static GtkWidget *message_entry = NULL;
155
156 /* time at which progress bar was started */
157 static struct timeval pstart;
158 static int pinterval = 25; /* timeout interval in ms */
159 static intptr_t pbar_timeout_instance = 0; /* track dead timeouts */
160 static GtkWidget *pbar;
161
162 /* timeout handler for the dialog progress bar */
pbar_timeout(gpointer instance)163 static int pbar_timeout(gpointer instance) {
164 int timeleft;
165 struct timeval timenow;
166
167 if ( pbar_timeout_instance != (intptr_t) instance ) return FALSE; /* dead timeout */
168 if ( ! GTK_WIDGET_VISIBLE(discard_dialog->widget) ) return FALSE;
169 gettimeofday(&timenow,NULL);
170 timeleft = ptimeout-(1000*(timenow.tv_sec-pstart.tv_sec)
171 +(timenow.tv_usec-pstart.tv_usec)/1000);
172 if ( timeleft <= 0 ) {
173 /* we should not hide the claim dialog: the timeout is really
174 controlled by the server, not us */
175 /* However, if we are supposed to be handling timeouts locally,
176 we'd better send a noclaim! */
177 if ( local_timeouts ) {
178 disc_callback(NULL,(gpointer)NoClaim);
179 }
180 return FALSE;
181 }
182 gtk_progress_bar_update(GTK_PROGRESS_BAR(pbar),1.0-(timeleft+0.0)/(ptimeout+0.0));
183 return TRUE;
184 }
185
186 /* popup the discard dialog. Arguments:
187 Tile, player whence it came (as an ori),
188 mode = 0 (normal), 1 (claiming tile for mah jong), 2 (claiming from kong) */
discard_dialog_popup(Tile t,int ori,int mode)189 void discard_dialog_popup(Tile t, int ori, int mode) {
190 int i;
191 char buf[128];
192 static Tile lastt; static int lastori, lastmode;
193
194 /* So that we don't work if it's already popped up: */
195 if ( GTK_WIDGET_VISIBLE(discard_dialog->widget)
196 && t == lastt && lastori == ori && lastmode == mode ) return;
197 lastt = t; lastori = ori; lastmode = mode;
198
199 if ( mode != discard_dialog->mode ) {
200 discard_dialog->mode = mode;
201 if ( mode == 0 ) {
202 gtk_widget_show(discard_dialog->noclaim);
203 gtk_widget_hide(discard_dialog->eyes);
204 gtk_widget_show(discard_dialog->chow);
205 gtk_widget_show(discard_dialog->pung);
206 gtk_widget_hide(discard_dialog->special);
207 gtk_widget_show(discard_dialog->kong);
208 gtk_widget_show(discard_dialog->mahjong);
209 gtk_widget_hide(discard_dialog->robkong);
210 } else if ( mode == 1 ) {
211 gtk_widget_hide(discard_dialog->noclaim);
212 gtk_widget_show(discard_dialog->eyes);
213 gtk_widget_show(discard_dialog->chow);
214 gtk_widget_show(discard_dialog->pung);
215 gtk_widget_show(discard_dialog->special);
216 gtk_widget_hide(discard_dialog->kong);
217 gtk_widget_hide(discard_dialog->mahjong);
218 gtk_widget_hide(discard_dialog->robkong);
219 } else {
220 gtk_widget_show(discard_dialog->noclaim);
221 gtk_widget_hide(discard_dialog->eyes);
222 gtk_widget_hide(discard_dialog->chow);
223 gtk_widget_hide(discard_dialog->pung);
224 gtk_widget_hide(discard_dialog->special);
225 gtk_widget_hide(discard_dialog->kong);
226 gtk_widget_hide(discard_dialog->mahjong);
227 gtk_widget_show(discard_dialog->robkong);
228 }
229 }
230 if ( mode == 0 ) grab_focus_if_appropriate(discard_dialog->noclaim);
231
232 /* set the appropriate tile */
233 for ( i=1 ; i < 4 ; i++ ) {
234 if ( i == ori ) {
235 button_set_tile(discard_dialog->tiles[i],t,i);
236 gtk_widget_show(discard_dialog->tiles[i]);
237 } else {
238 gtk_widget_hide(discard_dialog->tiles[i]);
239 }
240 }
241 gtk_widget_hide(discard_dialog->tilename);
242 if ( mode == 1 ) {
243 gtk_label_set_text(GTK_LABEL(discard_dialog->tilename),
244 "Claim discard for:");
245 } else {
246 /* if not showing wall, say how many tiles left */
247 if ( ! showwall ) {
248 if ( ori == 1 ) sprintf(buf,"(%d tiles left) %s",
249 the_game->wall.live_end-the_game->wall.live_used,
250 tile_name(the_game->tile));
251 else sprintf(buf,"%s (%d tiles left)",
252 tile_name(the_game->tile),
253 the_game->wall.live_end-the_game->wall.live_used);
254 } else {
255 strcpy(buf,tile_name(the_game->tile));
256 }
257 gtk_label_set_text(GTK_LABEL(discard_dialog->tilename),buf);
258 }
259 if ( mode == 0 ) {
260 static const gfloat xal[] = { 0.5,1.0,0.5,0.0 };
261 gtk_misc_set_alignment(GTK_MISC(discard_dialog->tilename),
262 xal[ori],0.5);
263 } else {
264 gtk_misc_set_alignment(GTK_MISC(discard_dialog->tilename),
265 0.5,0.5);
266 }
267 gtk_widget_show(discard_dialog->tilename);
268 dialog_popup(discard_dialog->widget,DPCentred);
269 /* and start the progress bar timeout if appropriate */
270 if ( the_game->state != MahJonging && ptimeout > 0 ) {
271 gtk_widget_show(pbar);
272 gettimeofday(&pstart,NULL);
273 /* we may as well calculate an appropriate value of pbar_timeout
274 each time... we want it to update every half pixel, or 40 times
275 a second, whichever is slower */
276 if ( pbar->allocation.width > 1 ) {
277 /* in case it isn't realized yet */
278 pinterval = ptimeout/(2*pbar->allocation.width);
279 }
280 if ( pinterval < 25 ) pinterval = 25;
281 gtk_timeout_add(pinterval,pbar_timeout,(gpointer) ++pbar_timeout_instance);
282 } else {
283 gtk_widget_hide(pbar);
284 }
285 }
286
287 /* this macro generates a variable for an accelerator group,
288 and a function to add or remove it. The macro argument is included
289 in the name of the variable and function */
290 #define ACCELFUN(NAME) \
291 static GtkAccelGroup *NAME ## _accel;\
292 static void add_or_remove_ ## NAME ## _accels(GtkWidget *w UNUSED, gpointer data)\
293 {\
294 static int there = 0;\
295 if ( NAME ## _accel == NULL ) return;\
296 if ( data ) {\
297 if (GTK_HAS_FOCUS & GTK_WIDGET_FLAGS(message_entry)) return;\
298 if ( ! there )\
299 gtk_window_add_accel_group(GTK_WINDOW(topwindow),NAME ## _accel);\
300 there = 1;\
301 } else {\
302 if ( there )\
303 gtk_window_remove_accel_group(GTK_WINDOW(topwindow),NAME ## _accel);\
304 there = 0;\
305 }\
306 }
307
308 /* an accelerator group for the discard dialog */
ACCELFUN(discard)309 ACCELFUN(discard)
310
311 /* initialize it */
312 /* Structure:
313 If the dialog is in the middle:
314 lefttile opptile righttile
315 tile name
316 progress bar
317 Pass/Draw Chow Pung Kong MahJong
318 otherwise:
319 tilename progress bar
320 buttons
321 */
322 void discard_dialog_init(void) {
323 GtkWidget *box, *tilebox, *left, *opp, *right, *lbl,
324 *butbox, *but, *pixm;
325 DiscardDialog *dd = &discard_dialog[0];
326
327 if ( dd->widget ) {
328 gtk_widget_destroy(dd->widget);
329 dd->widget = NULL;
330 }
331
332 switch ( dialogs_position ) {
333 case DialogsCentral:
334 case DialogsUnspecified:
335 /* event box so there's a window to have background */
336 dd->widget = gtk_event_box_new();
337 gtk_fixed_put(GTK_FIXED(discard_area),dd->widget,0,0);
338 /* it'll be moved later */
339 break;
340 case DialogsBelow:
341 dd->widget = gtk_event_box_new();
342 gtk_box_pack_start(GTK_BOX(dialoglowerbox),dd->widget,1,0,0);
343 /* show it, so that the top window includes it when first mapped */
344 gtk_widget_show(dd->widget);
345 break;
346 case DialogsPopup:
347 dd->widget = gtk_window_new(GTK_WINDOW_DIALOG);
348 gtk_signal_connect (GTK_OBJECT (dd->widget), "delete_event",
349 GTK_SIGNAL_FUNC (gtk_widget_hide), NULL);
350 }
351
352 box = gtk_vbox_new(0,dialog_vert_spacing);
353 gtk_widget_show(box);
354 gtk_container_add(GTK_CONTAINER(dd->widget),box);
355 dd->mode = -1; /* so that personality will be set */
356 gtk_container_set_border_width(GTK_CONTAINER(box),
357 dialog_border_width);
358
359 tilebox = gtk_hbox_new(0,0);
360 if ( dialogs_position != DialogsBelow ) gtk_widget_show(tilebox);
361
362 left = gtk_button_new();
363 GTK_WIDGET_UNSET_FLAGS(left,GTK_CAN_FOCUS);
364 gtk_widget_show(left);
365 pixm = gtk_pixmap_new(tilepixmaps[3][HiddenTile],NULL);
366 gtk_widget_show(pixm);
367 gtk_container_add(GTK_CONTAINER(left),pixm);
368 opp = gtk_button_new();
369 GTK_WIDGET_UNSET_FLAGS(opp,GTK_CAN_FOCUS);
370 gtk_widget_show(opp);
371 pixm = gtk_pixmap_new(tilepixmaps[2][HiddenTile],NULL);
372 gtk_widget_show(pixm);
373 gtk_container_add(GTK_CONTAINER(opp),pixm);
374 right = gtk_button_new();
375 GTK_WIDGET_UNSET_FLAGS(right,GTK_CAN_FOCUS);
376 gtk_widget_show(right);
377 pixm = gtk_pixmap_new(tilepixmaps[1][HiddenTile],NULL);
378 gtk_widget_show(pixm);
379 gtk_container_add(GTK_CONTAINER(right),pixm);
380 gtk_box_pack_start(GTK_BOX(tilebox),left,0,0,0);
381 gtk_box_pack_start(GTK_BOX(tilebox),opp,1,0,0);
382 gtk_box_pack_end(GTK_BOX(tilebox),right,0,0,0);
383 dd->tiles[1] = right;
384 dd->tiles[2] = opp;
385 dd->tiles[3] = left;
386
387 lbl = gtk_label_new("name of tile");
388 gtk_widget_show(lbl);
389 dd->tilename = lbl;
390
391 butbox = gtk_hbox_new(1,dialog_button_spacing); /* homogeneous, spaced */
392 gtk_widget_show(butbox);
393
394 /* accelerators for discard dialog actions */
395 discard_accel = gtk_accel_group_new();
396
397 but = gtk_button_new_with_label("No claim");
398 gtk_widget_show(but);
399 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
400 gtk_signal_connect(GTK_OBJECT(but),"clicked",
401 GTK_SIGNAL_FUNC(disc_callback),(gpointer)NoClaim);
402 dd->noclaim = but;
403 #ifdef GTK2
404 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_n,0,0);
405 #else
406 gtk_accel_group_add(discard_accel,GDK_n,0,0,GTK_OBJECT(but),"clicked");
407 #endif
408 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
409
410 but = gtk_button_new_with_label("Eyes");
411 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
412 /* not shown in normal state */
413 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
414 gtk_signal_connect(GTK_OBJECT(but),"clicked"
415 ,GTK_SIGNAL_FUNC(disc_callback),(gpointer)PairClaim);
416 dd->eyes = but;
417 #ifdef GTK2
418 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_e,0,0);
419 #else
420 gtk_accel_group_add(discard_accel,GDK_e,0,0,GTK_OBJECT(but),"clicked");
421 #endif
422 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
423
424 but = gtk_button_new_with_label("Chow");
425 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
426 gtk_widget_show(but);
427 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
428 gtk_signal_connect(GTK_OBJECT(but),"clicked"
429 ,GTK_SIGNAL_FUNC(disc_callback),(gpointer)ChowClaim);
430 dd->chow = but;
431 #ifdef GTK2
432 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_c,0,0);
433 #else
434 gtk_accel_group_add(discard_accel,GDK_c,0,0,GTK_OBJECT(but),"clicked");
435 #endif
436 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
437
438 but = gtk_button_new_with_label("Pung");
439 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
440 gtk_widget_show(but);
441 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
442 gtk_signal_connect(GTK_OBJECT(but),"clicked",GTK_SIGNAL_FUNC(disc_callback),(gpointer)PungClaim);
443 dd->pung = but;
444 #ifdef GTK2
445 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_p,0,0);
446 #else
447 gtk_accel_group_add(discard_accel,GDK_p,0,0,GTK_OBJECT(but),"clicked");
448 #endif
449 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
450
451 but = gtk_button_new_with_label("Special Hand");
452 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
453 /* gtk_widget_show(but); */ /* don't show this; uses other space */
454 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
455 gtk_signal_connect(GTK_OBJECT(but),"clicked",GTK_SIGNAL_FUNC(disc_callback),(gpointer)SpecialSetClaim);
456 dd->special = but;
457 #ifdef GTK2
458 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_s,0,0);
459 #else
460 gtk_accel_group_add(discard_accel,GDK_s,0,0,GTK_OBJECT(but),"clicked");
461 #endif
462 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
463
464 but = gtk_button_new_with_label("Kong");
465 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
466 gtk_widget_show(but);
467 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
468 gtk_signal_connect(GTK_OBJECT(but),"clicked",GTK_SIGNAL_FUNC(disc_callback),(gpointer)KongClaim);
469 dd->kong = but;
470 #ifdef GTK2
471 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_k,0,0);
472 #else
473 gtk_accel_group_add(discard_accel,GDK_k,0,0,GTK_OBJECT(but),"clicked");
474 #endif
475 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
476
477 but = gtk_button_new_with_label("Mah Jong");
478 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
479 gtk_widget_show(but);
480 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
481 gtk_signal_connect(GTK_OBJECT(but),"clicked",GTK_SIGNAL_FUNC(disc_callback),(gpointer)MahJongClaim);
482 dd->mahjong = but;
483 #ifdef GTK2
484 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_m,0,0);
485 #else
486 gtk_accel_group_add(discard_accel,GDK_m,0,0,GTK_OBJECT(but),"clicked");
487 #endif
488 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
489
490 but = gtk_button_new_with_label("Rob the Kong - Mah Jong!");
491 GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS);
492 /* gtk_widget_show(but); */ /* don't show this; it uses the space of others */
493 gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0);
494 gtk_signal_connect(GTK_OBJECT(but),"clicked",GTK_SIGNAL_FUNC(disc_callback),(gpointer)MahJongClaim);
495 dd->robkong = but;
496 #ifdef GTK2
497 gtk_widget_add_accelerator(GTK_WIDGET(but),"clicked",discard_accel,GDK_r,0,0);
498 #else
499 gtk_accel_group_add(discard_accel,GDK_r,0,0,GTK_OBJECT(but),"clicked");
500 #endif
501 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_");
502
503 pbar = gtk_progress_bar_new();
504 gtk_widget_show(pbar);
505
506 /* These are packed in reverse order so they float to the bottom */
507 gtk_box_pack_end(GTK_BOX(box),butbox,0,0,0);
508 gtk_box_pack_end(GTK_BOX(box),lbl,0,0,0);
509 gtk_box_pack_end(GTK_BOX(box),pbar,0,0,0);
510 gtk_box_pack_end(GTK_BOX(box),tilebox,0,0,0);
511
512 /* OK, now ask its size: store the result, and keep it
513 this size for ever more */
514 gtk_widget_size_request(dd->widget,&discard_req);
515 gtk_widget_set_usize(dd->widget,discard_req.width,discard_req.height);
516
517 /* we have to ensure that the accelerators are only available when
518 the widget is popped up */
519 gtk_signal_connect(GTK_OBJECT(discard_dialog->widget),"hide",GTK_SIGNAL_FUNC(add_or_remove_discard_accels),(gpointer)0);
520 gtk_signal_connect(GTK_OBJECT(discard_dialog->widget),"show",GTK_SIGNAL_FUNC(add_or_remove_discard_accels),(gpointer)1);
521
522 }
523
524 static GtkWidget *turn_dialog_discard_button;
525 static GtkWidget *turn_dialog_calling_button;
526
turn_dialog_popup(void)527 void turn_dialog_popup(void) {
528 /* only original call is allowed, so hide the calling
529 button after first discard */
530 if ( pflag(our_player,NoDiscard) )
531 gtk_widget_show(turn_dialog_calling_button);
532 else
533 gtk_widget_hide(turn_dialog_calling_button);
534 /* if not showing wall, put tiles left in label */
535 if ( ! showwall ) {
536 char buf[128];
537 sprintf(buf,"(%d tiles left) Select tile and:",
538 the_game->wall.live_end-the_game->wall.live_used);
539 gtk_label_set_text(GTK_LABEL(turn_dialog_label),buf);
540 } else {
541 gtk_label_set_text(GTK_LABEL(turn_dialog_label),"Select tile and:");
542 }
543 dialog_popup(turn_dialog,DPOnDiscardOnce);
544 grab_focus_if_appropriate(turn_dialog_discard_button);
545 }
546
547 /* callback when we toggle one of our tiles.
548 data is our index number.
549 If data also has bit 7 set, force the tile active.
550 If called with NULL widget, clear selection
551 */
552
conc_callback(GtkWidget * w,gpointer data)553 void conc_callback(GtkWidget *w, gpointer data) {
554 int active;
555 int i;
556 int force=0, index=-1;
557 static GtkWidget *selected = NULL; /* for radiogroup functionality */
558
559 active = (w && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)));
560 if ( active ) index = ((int)(intptr_t)data)& 127;
561 force = (w && (((int)(intptr_t)data) & 128));
562
563
564 if ( w && just_doubleclicked == w) force = 1;
565
566 /* make sure all other tiles are unselected, if we're active,
567 or if we're called to clear: we don't just rely
568 on the selected variable, since under some circumstances we
569 can end up with two tiles active, by accident as it were */
570 /* FIXME: this relies on induced callbacks being executed synchronously */
571 if ( active || w == NULL) {
572 for ( i = 0; i<14; i++ ) {
573 if ( pdisps[0].conc[i] && pdisps[0].conc[i] != w) {
574 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pdisps[0].conc[i]),
575 FALSE);
576 }
577 }
578 }
579 selected_button = index;
580 selected = NULL;
581 if ( active ) selected = w;
582
583 if ( w == NULL ) return;
584
585 /* change the label on the discard button to be declare if
586 this is a flower */
587 gtk_label_set_text(GTK_LABEL(GTK_BIN(turn_dialog_discard_button)->child),
588 is_special(our_player->concealed[index]) ? "Declare" : "Discard");
589
590 if ( force ) {
591 /* if it's not active, set it active: we'll then
592 be invoked normally, so we just return now. */
593 if ( ! active ) {
594 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),TRUE);
595 return;
596 }
597 }
598
599 /* if we were double clicked, invoke the turn callback directly */
600 if ( w && just_doubleclicked == w) {
601 just_doubleclicked = 0;
602 turn_callback(w,(gpointer)PMsgDiscard);
603 }
604 }
605
606 /* This detects doubleclicks on the concealed buttons */
doubleclicked(GtkWidget * w,GdkEventButton * eb,gpointer data UNUSED)607 gint doubleclicked(GtkWidget *w, GdkEventButton *eb,gpointer data UNUSED) {
608 if ( eb->type != GDK_2BUTTON_PRESS ) return FALSE;
609 /* This is disgusting. We set a global doubleclicked flag,
610 which is noticed by the toggle callback */
611 just_doubleclicked = w;
612 return FALSE;
613 }
614
615 /* callback attached to the buttons of the discarding dialog.
616 They pass PMsgDiscard, PMsgDeclareClosedKong,
617 PMsgAddToPung, or PMsgMahJong.
618 As of 11.80, PMsgDeclareClosedKong may mean that or AddToPung,
619 and we must work out which here.
620 Passed PMsgDiscard + 1000000 to declare calling.
621 Also invoked by the declaring special callback:
622 with DeclareSpecial to declare a special, Kong if appropriate,
623 and NoClaim to indicate the end of declaration.
624 Also invoked by scoring dialog with appropriate values */
625
turn_callback(GtkWidget * w UNUSED,gpointer data)626 static void turn_callback(GtkWidget *w UNUSED, gpointer data) {
627 PMsgUnion m;
628 Tile selected_tile;
629
630 /* it is possible for this to be invoked when it shouldn't be,
631 for example double-clicking on a tile (or hitting space on a tile?)
632 when no dialog is up. So let's check that one of possible dialogs
633 is up */
634 if ( ! (GTK_WIDGET_VISIBLE(turn_dialog)
635 || GTK_WIDGET_VISIBLE(ds_dialog)
636 || GTK_WIDGET_VISIBLE(scoring_dialog) ) ) return;
637
638 selected_tile = (selected_button < 0) ? HiddenTile : our_player->concealed[selected_button];
639
640 m.type = (PlayerMsgType)data;
641
642 if ( m.type == PMsgMahJong ) {
643 // set the discard to 0 for cleanliness.
644 m.mahjong.discard = 0;
645 send_packet(&m);
646 return;
647 }
648 if ( m.type == PMsgDeclareClosedKong ) {
649 if ( player_can_declare_closed_kong(our_player,selected_tile) ) {
650 /* that's fine */
651 } else {
652 /* assume they mean add to pung */
653 m.type = PMsgAddToPung;
654 }
655 }
656 if ( m.type == PMsgShowTiles
657 || m.type == PMsgFormClosedSpecialSet ) {
658 closed_set_in_progress = 1;
659 send_packet(&m);
660 return;
661 }
662
663 if ( the_game->state == DeclaringSpecials
664 && m.type == PMsgNoClaim ) {
665 selected_tile = HiddenTile;
666 m.type = PMsgDeclareSpecial;
667 conc_callback(NULL,NULL); /* clear the selection */
668 }
669
670 /* in declaring specials, use this to finish */
671 if ( selected_tile == HiddenTile ) {
672 if ( the_game->state == DeclaringSpecials )
673 m.type = PMsgDeclareSpecial;
674 else {
675 error_dialog_popup("No tile selected!");
676 return;
677 }
678 }
679 if ( is_special(selected_tile) )
680 m.type = PMsgDeclareSpecial;
681
682 switch ( m.type ) {
683 case PMsgDeclareSpecial:
684 m.declarespecial.tile = selected_tile;
685 break;
686 case PMsgDiscard:
687 if ( selected_button >= 0 )
688 player_set_discard_hint(our_player,selected_button);
689 m.discard.tile = selected_tile;
690 m.discard.calling = 0;
691 break;
692 case PMsgDiscard+1000000:
693 if ( selected_button >= 0 )
694 player_set_discard_hint(our_player,selected_button);
695 m.type = PMsgDiscard;
696 m.discard.tile = selected_tile;
697 m.discard.calling = 1;
698 break;
699 case PMsgDeclareClosedKong:
700 m.declareclosedkong.tile = selected_tile;
701 break;
702 case PMsgAddToPung:
703 m.addtopung.tile = selected_tile;
704 break;
705 case PMsgFormClosedPair:
706 m.formclosedpair.tile = selected_tile;
707 closed_set_in_progress = 1;
708 break;
709 case PMsgFormClosedChow:
710 m.formclosedchow.tile = selected_tile;
711 closed_set_in_progress = 1;
712 break;
713 case PMsgFormClosedPung:
714 m.formclosedpung.tile = selected_tile;
715 closed_set_in_progress = 1;
716 break;
717 default:
718 warn("bad type in turn_callback");
719 return;
720 }
721 send_packet(&m);
722 }
723
724 /* callback when one of the discard dialog buttons is clicked */
disc_callback(GtkWidget * w UNUSED,gpointer data)725 void disc_callback(GtkWidget *w UNUSED, gpointer data) {
726 PMsgUnion m;
727
728 switch ( (intptr_t) data) {
729 case NoClaim:
730 m.type = PMsgNoClaim;
731 m.noclaim.discard = the_game->serial;
732 break;
733 case ChowClaim:
734 m.type = PMsgChow;
735 m.chow.discard = the_game->serial;
736 m.chow.cpos = AnyPos; /* worry about it later */
737 break;
738 case PairClaim:
739 m.type = PMsgPair;
740 break;
741 case SpecialSetClaim:
742 m.type = PMsgSpecialSet;
743 break;
744 case PungClaim:
745 m.type = PMsgPung;
746 m.pung.discard = the_game->serial;
747 break;
748 case KongClaim:
749 m.type = PMsgKong;
750 m.kong.discard = the_game->serial;
751 break;
752 case MahJongClaim:
753 m.type = PMsgMahJong;
754 m.mahjong.discard = the_game->serial;
755 break;
756 default:
757 warn("disc callback called with unexpected data");
758 return;
759 }
760
761 /* If the server has a protocol version before 1050, we mustn't
762 send an AnyPos while mahjonging, as it doesn't know how to
763 handle it; so pop up the chow dialog directly */
764 if ( server_pversion < 1050 && the_game->state == MahJonging && m.type == PMsgChow ) {
765 do_chow(NULL,(gpointer)AnyPos);
766 } else {
767 send_packet(&m);
768 }
769 }
770
ACCELFUN(chow)771 ACCELFUN(chow)
772
773 /* Now create the Chow dialog box:
774 Structure: three boxes, each containing a tileset showing
775 a possible chow. Below that, a label "which chow?".
776 Below that, three buttons to select.
777 */
778 void chow_dialog_init(void) {
779 GtkWidget *box,*u,*v; int i;
780
781 if ( chow_dialog ) {
782 gtk_widget_destroy(chow_dialog);
783 chow_dialog = NULL;
784 }
785
786 switch ( dialogs_position ) {
787 case DialogsCentral:
788 case DialogsUnspecified:
789 chow_dialog = gtk_event_box_new();
790 gtk_fixed_put(GTK_FIXED(discard_area),chow_dialog,0,0);
791 break;
792 case DialogsPopup:
793 case DialogsBelow:
794 chow_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
795 gtk_signal_connect (GTK_OBJECT (chow_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
796 /* This one is allowed to shrink, and should */
797 gtk_window_set_policy(GTK_WINDOW(chow_dialog),1,1,1);
798 }
799 box = gtk_vbox_new(0,dialog_vert_spacing);
800 gtk_container_set_border_width(GTK_CONTAINER(box),
801 dialog_border_width);
802 gtk_widget_show(box);
803 gtk_container_add(GTK_CONTAINER(chow_dialog),box);
804 u = gtk_hbox_new(0,dialog_button_spacing);
805 gtk_widget_show(u);
806 gtk_box_pack_start(GTK_BOX(box),u,0,0,0);
807 for (i=0;i<3;i++) {
808 v = gtk_hbox_new(0,0);
809 gtk_widget_show(v);
810 gtk_box_pack_start(GTK_BOX(u),v,0,0,0);
811 chowtsbs[i].widget = v;
812 tilesetbox_init(&chowtsbs[i],0,GTK_SIGNAL_FUNC(do_chow),(gpointer)(intptr_t)i);
813 }
814 u = gtk_label_new("Which chow?");
815 gtk_widget_show(u);
816 gtk_box_pack_start(GTK_BOX(box),u,0,0,0);
817 u = gtk_hbox_new(1,dialog_button_spacing);
818 gtk_widget_show(u);
819 gtk_box_pack_start(GTK_BOX(box),u,0,0,0);
820
821 chow_accel = gtk_accel_group_new();
822
823 for (i=0;i<3;i++) {
824 static int keys[] = { GDK_l, GDK_m, GDK_u };
825 v = gtk_button_new_with_label(player_print_ChowPosition(i));
826 GTK_WIDGET_UNSET_FLAGS(v,GTK_CAN_FOCUS);
827 gtk_widget_show(v);
828 gtk_box_pack_start(GTK_BOX(u),v,1,1,0);
829 chowbuttons[i] = v;
830 gtk_signal_connect(GTK_OBJECT(v),"clicked",GTK_SIGNAL_FUNC(do_chow),(gpointer)(intptr_t)i);
831 #ifdef GTK2
832 gtk_widget_add_accelerator(GTK_WIDGET(v),"clicked",chow_accel,keys[i],0,0);
833 #else
834 gtk_accel_group_add(chow_accel,keys[i],0,0,GTK_OBJECT(v),"clicked");
835 #endif
836 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(v)->child),"_");
837 }
838
839 gtk_signal_connect(GTK_OBJECT(chow_dialog),"hide",GTK_SIGNAL_FUNC(add_or_remove_chow_accels),(gpointer)0);
840 gtk_signal_connect(GTK_OBJECT(chow_dialog),"show",GTK_SIGNAL_FUNC(add_or_remove_chow_accels),(gpointer)1);
841
842 }
843
844 /* now create the declaring specials dialog.
845 Contains a button for declare (special), kong, and done.
846 If no flowers, just kongs.
847 */
848 static GtkWidget *ds_dialog_declare_button;
849 static GtkWidget *ds_dialog_finish_button;
850
ACCELFUN(ds)851 ACCELFUN(ds)
852
853 void ds_dialog_init(void) {
854 GtkWidget *box, *bbox, *w;
855
856 if ( ds_dialog ) {
857 gtk_widget_destroy(ds_dialog);
858 ds_dialog = NULL;
859 }
860
861 switch ( dialogs_position ) {
862 case DialogsCentral:
863 case DialogsUnspecified:
864 ds_dialog = gtk_event_box_new();
865 gtk_fixed_put(GTK_FIXED(discard_area),ds_dialog,0,0);
866 break;
867 case DialogsBelow:
868 ds_dialog = gtk_event_box_new();
869 gtk_box_pack_start(GTK_BOX(dialoglowerbox),ds_dialog,1,0,0);
870 break;
871 case DialogsPopup:
872 ds_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
873 gtk_signal_connect (GTK_OBJECT (ds_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
874 }
875
876 box = gtk_vbox_new(0,dialog_vert_spacing);
877 gtk_container_set_border_width(GTK_CONTAINER(box),
878 dialog_border_width);
879 gtk_widget_show(box);
880 gtk_container_add(GTK_CONTAINER(ds_dialog),box);
881
882 bbox = gtk_hbox_new(1,dialog_button_spacing);
883 gtk_widget_show(bbox);
884 gtk_box_pack_end(GTK_BOX(box),bbox,0,0,0);
885
886 if ( game_get_option_value(the_game,GOFlowers,NULL).optbool )
887 w = gtk_label_new("Declare Flowers/Seasons (and kongs)\nSelect tile and:");
888 else
889 w = gtk_label_new("Declare kongs\nSelect tile and:");
890 gtk_widget_show(w);
891 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
892
893 ds_accel = gtk_accel_group_new();
894
895 if ( game_get_option_value(the_game,GOFlowers,NULL).optbool ) {
896 ds_dialog_declare_button = w = gtk_button_new_with_label("Declare");
897 gtk_widget_show(w);
898 gtk_box_pack_start(GTK_BOX(bbox),w,1,1,0);
899 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgDeclareSpecial);
900 #ifdef GTK2
901 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",ds_accel,GDK_d,0,0);
902 #else
903 gtk_accel_group_add(ds_accel,GDK_d,0,0,GTK_OBJECT(w),"clicked");
904 #endif
905 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
906 }
907
908 w = gtk_button_new_with_label("Kong");
909 gtk_widget_show(w);
910 gtk_box_pack_start(GTK_BOX(bbox),w,1,1,0);
911 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgDeclareClosedKong);
912 #ifdef GTK2
913 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",ds_accel,GDK_k,0,0);
914 #else
915 gtk_accel_group_add(ds_accel,GDK_k,0,0,GTK_OBJECT(w),"clicked");
916 #endif
917 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
918
919 ds_dialog_finish_button = w = gtk_button_new_with_label("Finish");
920 gtk_widget_show(w);
921 gtk_box_pack_start(GTK_BOX(bbox),w,1,1,0);
922 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgNoClaim);
923 #ifdef GTK2
924 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",ds_accel,GDK_f,0,0);
925 #else
926 gtk_accel_group_add(ds_accel,GDK_f,0,0,GTK_OBJECT(w),"clicked");
927 #endif
928 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
929
930 gtk_signal_connect(GTK_OBJECT(ds_dialog),"hide",GTK_SIGNAL_FUNC(add_or_remove_ds_accels),(gpointer)0);
931 gtk_signal_connect(GTK_OBJECT(ds_dialog),"show",GTK_SIGNAL_FUNC(add_or_remove_ds_accels),(gpointer)1);
932 }
933
ds_dialog_popup(void)934 void ds_dialog_popup(void) {
935 dialog_popup(ds_dialog,DPCentredOnce);
936 if ( game_get_option_value(the_game,GOFlowers,NULL).optbool )
937 grab_focus_if_appropriate(ds_dialog_declare_button);
938 else
939 grab_focus_if_appropriate(ds_dialog_finish_button);
940 }
941 /* dialog to ask to continue with next hand */
942 static GtkWidget *continue_dialog_continue_button;
943 static GtkWidget *continue_dialog_label;
944
continue_dialog_init(void)945 void continue_dialog_init(void) {
946 GtkWidget *box, *w;
947
948 if ( continue_dialog ) {
949 gtk_widget_destroy(continue_dialog);
950 continue_dialog = NULL;
951 }
952
953 switch ( dialogs_position ) {
954 case DialogsCentral:
955 case DialogsUnspecified:
956 continue_dialog = gtk_event_box_new();
957 gtk_fixed_put(GTK_FIXED(discard_area),continue_dialog,0,0);
958 break;
959 case DialogsBelow:
960 continue_dialog = gtk_event_box_new();
961 gtk_box_pack_start(GTK_BOX(dialoglowerbox),continue_dialog,1,0,0);
962 break;
963 case DialogsPopup:
964 continue_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
965 gtk_signal_connect (GTK_OBJECT (continue_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
966 }
967
968 box = gtk_vbox_new(0,dialog_vert_spacing);
969 gtk_container_set_border_width(GTK_CONTAINER(box),
970 dialog_border_width);
971 gtk_widget_show(box);
972 gtk_container_add(GTK_CONTAINER(continue_dialog),box);
973
974 continue_dialog_continue_button = w = gtk_button_new_with_label("Ready");
975 gtk_widget_show(w);
976 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
977 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(continue_callback),(gpointer)(intptr_t)PMsgDiscard);
978
979 /* created and packed second so things float to bottom */
980
981 continue_dialog_label = w = gtk_label_new("Here is some dummy text to space");
982 gtk_widget_show(w);
983 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
984
985 }
986
continue_dialog_popup(void)987 void continue_dialog_popup(void) {
988 static char buf[256];
989 /* the text of the display depends on whether we've said we're ready */
990 if ( ! the_game->active ) {
991 strcpy(buf,"Waiting for game to (re)start");
992 gtk_label_set_text(GTK_LABEL(continue_dialog_label),buf);
993 gtk_widget_hide(continue_dialog_continue_button);
994 }
995 else if ( the_game->ready[our_seat] ) {
996 strcpy(buf,"Waiting for others ");
997 strcat(buf,the_game->paused);
998 gtk_label_set_text(GTK_LABEL(continue_dialog_label),buf);
999 gtk_widget_hide(continue_dialog_continue_button);
1000 } else {
1001 strcpy(buf,"Ready ");
1002 strcat(buf,the_game->paused);
1003 strcat(buf,"?");
1004 gtk_label_set_text(GTK_LABEL(continue_dialog_label),buf);
1005 gtk_widget_show(continue_dialog_continue_button);
1006 grab_focus_if_appropriate(continue_dialog_continue_button);
1007 }
1008 dialog_popup(continue_dialog,DPCentredOnce);
1009 }
1010
continue_callback(GtkWidget * w UNUSED,gpointer data UNUSED)1011 static void continue_callback(GtkWidget *w UNUSED, gpointer data UNUSED) {
1012 PMsgReadyMsg rm;
1013 rm.type = PMsgReady;
1014 send_packet(&rm);
1015 }
1016
1017 /* dialog to ask to close at end of game */
1018 static GtkWidget *end_dialog_end_button;
1019 static GtkWidget *end_dialog_label;
1020
1021 static void end_callback(GtkWidget *w UNUSED, gpointer data UNUSED);
1022
end_dialog_init(void)1023 void end_dialog_init(void) {
1024 GtkWidget *box, *w;
1025
1026 if ( end_dialog ) {
1027 gtk_widget_destroy(end_dialog);
1028 end_dialog = NULL;
1029 }
1030
1031 switch ( dialogs_position ) {
1032 case DialogsCentral:
1033 case DialogsUnspecified:
1034 end_dialog = gtk_event_box_new();
1035 gtk_fixed_put(GTK_FIXED(discard_area),end_dialog,0,0);
1036 break;
1037 case DialogsBelow:
1038 end_dialog = gtk_event_box_new();
1039 gtk_box_pack_start(GTK_BOX(dialoglowerbox),end_dialog,1,0,0);
1040 break;
1041 case DialogsPopup:
1042 end_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
1043 gtk_signal_connect (GTK_OBJECT (end_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1044 }
1045
1046 box = gtk_vbox_new(0,dialog_vert_spacing);
1047 gtk_container_set_border_width(GTK_CONTAINER(box),
1048 dialog_border_width);
1049 gtk_widget_show(box);
1050 gtk_container_add(GTK_CONTAINER(end_dialog),box);
1051
1052 end_dialog_end_button = w = gtk_button_new_with_label("Done");
1053 gtk_widget_show(w);
1054 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
1055 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(end_callback),(gpointer)(intptr_t)PMsgDiscard);
1056
1057 /* created and packed second so things float to bottom */
1058
1059 end_dialog_label = w = gtk_label_new("GAME OVER");
1060 gtk_widget_show(w);
1061 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
1062
1063 }
1064
end_dialog_popup(void)1065 void end_dialog_popup(void) {
1066 grab_focus_if_appropriate(end_dialog_end_button);
1067 dialog_popup(end_dialog,DPCentredOnce);
1068 }
1069
end_callback(GtkWidget * w UNUSED,gpointer data UNUSED)1070 static void end_callback(GtkWidget *w UNUSED, gpointer data UNUSED) {
1071 close_connection(0);
1072 gtk_widget_hide(end_dialog);
1073 status_showraise();
1074 }
1075
1076 /* how many are up; used for positioning - not multi-thread safe! */
1077 static int num_error_dialogs = 0;
1078
1079 /* function called to close an error dialog */
kill_error(GtkObject * data)1080 static void kill_error(GtkObject *data) {
1081 gtk_widget_destroy(GTK_WIDGET(data));
1082 num_error_dialogs--;
1083 }
1084
1085 /* popup an error box (new for each message),
1086 or an info box (which doesn't have error tile in it)' */
_error_dialog_popup(char * msg,int iserror)1087 static void _error_dialog_popup(char *msg,int iserror) {
1088 GtkWidget *box, *hbox, *w, *error_dialog, *error_message;
1089
1090 if ( topwindow == NULL ) {
1091 warn("error_dialog_popup: windows not initialized");
1092 return;
1093 }
1094
1095 if ( num_error_dialogs >= 10 ) {
1096 warn("Too many error dialogs up to print error: %s",msg);
1097 return;
1098 }
1099
1100 error_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
1101 gtk_signal_connect_object(GTK_OBJECT (error_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_destroy),
1102 GTK_OBJECT(error_dialog));
1103 gtk_container_set_border_width(GTK_CONTAINER(error_dialog),
1104 dialog_border_width);
1105
1106 box = gtk_vbox_new(0,dialog_vert_spacing);
1107 gtk_widget_show(box);
1108 gtk_container_add(GTK_CONTAINER(error_dialog),box);
1109
1110 hbox = gtk_hbox_new(0,dialog_button_spacing);
1111 gtk_widget_show(hbox);
1112 gtk_box_pack_start(GTK_BOX(box),hbox,0,0,0);
1113
1114 if ( iserror ) {
1115 w = gtk_pixmap_new(tilepixmaps[0][ErrorTile],NULL);
1116 gtk_widget_show(w);
1117 gtk_box_pack_start(GTK_BOX(hbox),w,0,0,0);
1118 }
1119
1120 error_message = gtk_label_new(msg);
1121 gtk_widget_show(error_message);
1122 gtk_box_pack_start(GTK_BOX(hbox),error_message,0,0,0);
1123
1124 w = gtk_button_new_with_label("OK");
1125 gtk_widget_show(w);
1126 gtk_box_pack_start(GTK_BOX(box),w,0,0,0);
1127 gtk_signal_connect_object(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(kill_error),GTK_OBJECT(error_dialog));
1128 gtk_window_set_focus(GTK_WINDOW(error_dialog),w);
1129
1130 dialog_popup(error_dialog,DPErrorPos);
1131 num_error_dialogs++;
1132 gdk_window_raise(error_dialog->window);
1133 }
1134
error_dialog_popup(char * msg)1135 void error_dialog_popup(char *msg) {
1136 _error_dialog_popup(msg,1);
1137 }
1138
info_dialog_popup(char * msg)1139 void info_dialog_popup(char *msg) {
1140 _error_dialog_popup(msg,0);
1141 }
1142
1143
1144
1145 GtkWidget *openfile, *openhost, *openport,
1146 *openfiletext, *openhosttext, *openporttext, *openidtext, *opennametext,
1147 #ifdef GTK2
1148 *opengamefilechooser,
1149 #endif
1150 *opengamefile, *opengamefiletext, *opentimeout;
1151
1152 GtkWidget *openallowdisconnectbutton,*opensaveonexitbutton,*openrandomseatsbutton,
1153 *openplayercheckboxes[3],*openplayernames[3],*openplayeroptions[3],*opentimeoutspinbutton;
1154 static GtkWidget *opengamepanel,*openplayeroptionboxes[3],
1155 *openconnectbutton,*openstartbutton, *openresumebutton, *openhosttoggle, *openunixtoggle;
1156
1157 /* callback used in next function */
openbut_callback(GtkWidget * w,gpointer data)1158 static void openbut_callback(GtkWidget *w, gpointer data) {
1159 int active = GTK_TOGGLE_BUTTON(w)->active;
1160
1161 switch ( (int)(intptr_t)data ) {
1162 case 1:
1163 if ( active ) {
1164 /* selected network */
1165 gtk_widget_set_sensitive(openfile,0);
1166 gtk_widget_set_sensitive(openhost,1);
1167 gtk_widget_set_sensitive(openport,1);
1168 }
1169 break;
1170 case 2:
1171 if ( active ) {
1172 /* selected Unix socket */
1173 gtk_widget_set_sensitive(openfile,1);
1174 gtk_widget_set_sensitive(openhost,0);
1175 gtk_widget_set_sensitive(openport,0);
1176 }
1177 break;
1178 case 10:
1179 case 11:
1180 case 12:
1181 gtk_widget_set_sensitive(openplayeroptionboxes[((int)(intptr_t)data)-10],active);
1182 break;
1183 }
1184 }
1185
1186 #ifdef GTK2
1187 /* callback for the file chooser dialog used below */
chooser_callback(GtkDialog * w,gint rid,gpointer userdata)1188 static void chooser_callback(GtkDialog *w, gint rid, gpointer userdata) {
1189 if ( rid == GTK_RESPONSE_ACCEPT ) {
1190 gchar *f = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(opengamefilechooser));
1191 gchar *buf;
1192 if ( f != NULL && (buf = g_filename_to_utf8(f,-1,NULL,NULL,NULL)) != NULL ) {
1193 gchar cbuf[2*PATH_MAX+1];
1194 getcwd(cbuf,2*PATH_MAX);
1195 gchar *b = buf;
1196 if ( strncmp(cbuf,buf,strlen(cbuf)) == 0 ) {
1197 b = buf + strlen(cbuf);
1198 #ifdef WIN32
1199 if ( *b == '\\' ) b++;
1200 #else
1201 if ( *b == '/' ) b++;
1202 #endif
1203 }
1204 gtk_entry_set_text(GTK_ENTRY(opengamefiletext),b);
1205 } else {
1206 error_dialog_popup("Unexpected error choosing file!");
1207 }
1208 gtk_widget_hide(opengamefilechooser);
1209 g_free(f);
1210 g_free(buf);
1211 } else {
1212 gtk_widget_hide(opengamefilechooser);
1213 }
1214 }
1215
1216 #endif
1217
1218 /* the dialog for opening a connection.
1219 Arguments are initial values for id, name
1220 text entry fields, */
open_dialog_init(char * idt,char * nt)1221 void open_dialog_init(char *idt, char *nt) {
1222 /* Layout of the box:
1223 x Connect to host
1224 x Use Unix socket
1225 Hostname
1226 ........
1227 Port
1228 ....
1229 Filename
1230 ....
1231 Player ID
1232 ....
1233 Name
1234 ....
1235 OPEN CANCEL
1236 */
1237 int i;
1238 GtkWidget *box, *bbox, *but1, *but2, *w1, *w2;
1239 open_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1240 gtk_window_set_policy(GTK_WINDOW(open_dialog),FALSE,FALSE,TRUE);
1241 gtk_signal_connect (GTK_OBJECT (open_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1242 gtk_container_set_border_width(GTK_CONTAINER(open_dialog),
1243 dialog_border_width);
1244
1245 box = gtk_vbox_new(0,dialog_vert_spacing);
1246 gtk_widget_show(box);
1247 gtk_container_add(GTK_CONTAINER(open_dialog),box);
1248
1249 w1 = gtk_hbox_new(0,dialog_button_spacing);
1250 gtk_widget_show(w1);
1251 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
1252 openhosttoggle = but1 = gtk_radio_button_new_with_label(NULL,"Internet server");
1253 GTK_WIDGET_UNSET_FLAGS(but1,GTK_CAN_FOCUS);
1254 #ifndef WIN32
1255 gtk_widget_show(but1);
1256 #endif
1257 gtk_box_pack_start(GTK_BOX(w1),but1,0,0,0);
1258 openunixtoggle = but2 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"Unix socket server");
1259 GTK_WIDGET_UNSET_FLAGS(but2,GTK_CAN_FOCUS);
1260 #ifndef WIN32
1261 gtk_widget_show(but2);
1262 #endif
1263 gtk_box_pack_end(GTK_BOX(w1),but2,0,0,0);
1264
1265 gtk_signal_connect(GTK_OBJECT(but1),"toggled",GTK_SIGNAL_FUNC(openbut_callback),(gpointer)1);
1266 gtk_signal_connect(GTK_OBJECT(but2),"toggled",GTK_SIGNAL_FUNC(openbut_callback),(gpointer)2);
1267
1268 w2 = gtk_hbox_new(0,dialog_button_spacing);
1269 gtk_widget_show(w2);
1270 gtk_box_pack_start(GTK_BOX(box),w2,0,0,0);
1271 openhost = gtk_hbox_new(0,0);
1272 gtk_widget_show(openhost);
1273 gtk_box_pack_start(GTK_BOX(w2),openhost,0,0,0);
1274 w1 = gtk_label_new("Host: ");
1275 gtk_widget_show(w1);
1276 gtk_box_pack_start(GTK_BOX(openhost),w1,0,0,0);
1277 openhosttext = gtk_entry_new();
1278 gtk_widget_show(openhosttext);
1279 gtk_box_pack_start(GTK_BOX(openhost),openhosttext,0,0,0);
1280
1281 openport = gtk_hbox_new(0,0);
1282 gtk_widget_show(openport);
1283 gtk_box_pack_start(GTK_BOX(w2),openport,0,0,0);
1284 w1 = gtk_label_new("Port: ");
1285 gtk_widget_show(w1);
1286 gtk_box_pack_start(GTK_BOX(openport),w1,0,0,0);
1287 openporttext = gtk_entry_new_with_max_length(5);
1288 gtk_widget_set_usize(openporttext,75,0);
1289 gtk_widget_show(openporttext);
1290 gtk_box_pack_start(GTK_BOX(openport),openporttext,0,0,0);
1291
1292 openfile = gtk_hbox_new(0,0);
1293 #ifndef WIN32
1294 gtk_widget_show(openfile);
1295 #endif
1296 gtk_box_pack_start(GTK_BOX(box),openfile,0,0,0);
1297 w1 = gtk_label_new("Socket file: ");
1298 gtk_widget_show(w1);
1299 gtk_box_pack_start(GTK_BOX(openfile),w1,0,0,0);
1300 openfiletext = gtk_entry_new();
1301 gtk_widget_show(openfiletext);
1302 gtk_box_pack_start(GTK_BOX(openfile),openfiletext,0,0,0);
1303
1304 opengamefile = gtk_hbox_new(0,0);
1305 gtk_widget_show(opengamefile);
1306 gtk_box_pack_start(GTK_BOX(box),opengamefile,0,0,0);
1307 w1 = gtk_label_new("Saved game file: ");
1308 gtk_widget_show(w1);
1309 gtk_box_pack_start(GTK_BOX(opengamefile),w1,0,0,0);
1310 opengamefiletext = gtk_entry_new();
1311 gtk_widget_show(opengamefiletext);
1312 gtk_box_pack_start(GTK_BOX(opengamefile),opengamefiletext,0,0,0);
1313
1314 #ifdef GTK2
1315 opengamefilechooser =
1316 gtk_file_chooser_dialog_new("Resume from...",
1317 GTK_WINDOW(open_dialog),
1318 GTK_FILE_CHOOSER_ACTION_OPEN,
1319 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1320 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1321 NULL);
1322 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(opengamefilechooser),1);
1323 char fbuf[PATH_MAX+1];
1324 if ( getcwd(fbuf,PATH_MAX) != NULL ) {
1325 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(opengamefilechooser),
1326 fbuf);
1327 }
1328 GtkFileFilter *filter = gtk_file_filter_new();
1329 gtk_file_filter_add_pattern(filter, "*.mjs");
1330 gtk_file_filter_set_name(filter,".mjs files");
1331 GtkFileFilter *afilter = gtk_file_filter_new();
1332 gtk_file_filter_add_pattern(afilter, "*");
1333 gtk_file_filter_set_name(afilter,"All files");
1334 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(opengamefilechooser),filter);
1335 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(opengamefilechooser),afilter);
1336 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(opengamefilechooser),filter);
1337 gtk_signal_connect(GTK_OBJECT(opengamefilechooser),"response",
1338 GTK_SIGNAL_FUNC(chooser_callback),NULL);
1339
1340 w1 = gtk_button_new_with_label("Browse...");
1341 gtk_widget_show(w1);
1342 gtk_box_pack_start(GTK_BOX(opengamefile),w1,0,0,0);
1343 gtk_signal_connect_object(GTK_OBJECT(w1),"clicked",GTK_SIGNAL_FUNC(gtk_widget_show),GTK_OBJECT(opengamefilechooser));
1344 #endif
1345
1346 w2 = gtk_hbox_new(0,0);
1347 gtk_widget_show(w2);
1348 gtk_box_pack_start(GTK_BOX(box),w2,0,0,0);
1349 w1 = gtk_label_new("Player ID: ");
1350 gtk_widget_show(w1);
1351 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1352 openidtext = gtk_entry_new();
1353 gtk_widget_show(openidtext);
1354 gtk_entry_set_text(GTK_ENTRY(openidtext),idt);
1355 gtk_box_pack_start(GTK_BOX(w2),openidtext,0,0,0);
1356
1357 w2 = gtk_hbox_new(0,0);
1358 gtk_widget_show(w2);
1359 gtk_box_pack_start(GTK_BOX(box),w2,0,0,0);
1360 w1 = gtk_label_new("Name: ");
1361 gtk_widget_show(w1);
1362 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1363 opennametext = gtk_entry_new();
1364 gtk_widget_show(opennametext);
1365 if ( ! nt || !nt[0] ) nt = getenv("LOGNAME");
1366 if ( ! nt ) nt = getlogin(); /* may need to be in sysdep.c */
1367 gtk_entry_set_text(GTK_ENTRY(opennametext),nt);
1368 gtk_box_pack_start(GTK_BOX(w2),opennametext,0,0,0);
1369
1370 /* Now some stuff for when this panel is in its personality as
1371 a start game panel */
1372 opengamepanel = bbox = gtk_vbox_new(0,dialog_vert_spacing);
1373 /* gtk_widget_show(bbox); */
1374 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
1375
1376 for ( i = 0 ; i < 3 ; i++ ) {
1377 static const char *playerlabs[] = { "Second player:" , "Third player:",
1378 "Fourth player:" };
1379
1380 w2 = gtk_hbox_new(0,dialog_button_spacing);
1381 gtk_widget_show(w2);
1382 gtk_box_pack_start(GTK_BOX(bbox),w2,0,0,0);
1383 w1 = gtk_label_new(playerlabs[i]);
1384 gtk_widget_show(w1);
1385 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1386 openplayercheckboxes[i] = w1 =
1387 gtk_check_button_new_with_label("Start computer player ");
1388 gtk_widget_show(w1);
1389 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w1),1);
1390 gtk_box_pack_end(GTK_BOX(w2),w1,0,0,0);
1391 gtk_signal_connect(GTK_OBJECT(w1),"toggled",GTK_SIGNAL_FUNC(openbut_callback),(gpointer)(intptr_t)(10+i));
1392 openplayeroptionboxes[i] = w2 = gtk_hbox_new(0,dialog_button_spacing);
1393 gtk_widget_show(w2);
1394 gtk_box_pack_start(GTK_BOX(bbox),w2,0,0,0);
1395 w1 = gtk_label_new(" Name:");
1396 gtk_widget_show(w1);
1397 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1398 openplayernames[i] = w1 = gtk_entry_new();
1399 gtk_entry_set_text(GTK_ENTRY(w1),robot_names[i]);
1400 gtk_widget_show(w1);
1401 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1402 w1 = gtk_label_new(" Options:");
1403 gtk_widget_show(w1);
1404 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1405 openplayeroptions[i] = w1 = gtk_entry_new();
1406 gtk_entry_set_text(GTK_ENTRY(w1),robot_options[i]);
1407 gtk_widget_show(w1);
1408 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1409 }
1410
1411 openallowdisconnectbutton = w1 =
1412 gtk_check_button_new_with_label("Allow disconnection from game");
1413 gtk_widget_show(w1);
1414 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
1415
1416 opensaveonexitbutton = w1 =
1417 gtk_check_button_new_with_label("Save game state on exit");
1418 gtk_widget_show(w1);
1419 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
1420
1421 openrandomseatsbutton = w1 =
1422 gtk_check_button_new_with_label("Seat players randomly");
1423 gtk_widget_show(w1);
1424 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
1425
1426 opentimeoutspinbutton = w1 =
1427 gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(1.0*game_get_option_entry_from_table(&prefs_table,GOTimeout,NULL)->value.optnat,0.0,300.0,1.0,10.0,0.0)),
1428 0.0,0);
1429 gtk_widget_show(w1);
1430 opentimeout = w2 = gtk_hbox_new(0,dialog_button_spacing);
1431 gtk_widget_show(w2);
1432 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1433 w1 = gtk_label_new("seconds allowed for claims");
1434 gtk_widget_show(w1);
1435 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
1436 gtk_box_pack_start(GTK_BOX(bbox),w2,0,0,0);
1437
1438 w1 = gtk_hbox_new(0,dialog_button_spacing);
1439 gtk_widget_show(w1);
1440 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
1441 openconnectbutton = w2 = gtk_button_new_with_label("Connect");
1442 gtk_widget_show(w2);
1443 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
1444 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(open_connection),0);
1445 openstartbutton = w2 = gtk_button_new_with_label("Start Game");
1446 /* gtk_widget_show(w2); */
1447 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
1448 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(open_connection),(gpointer)1);
1449 openresumebutton = w2 = gtk_button_new_with_label("Resume Game");
1450 /* gtk_widget_show(w2); */
1451 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
1452 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(open_connection),(gpointer)2);
1453 w2 = gtk_button_new_with_label("Cancel");
1454 gtk_widget_show(w2);
1455 gtk_box_pack_end(GTK_BOX(w1),w2,0,0,0);
1456 gtk_signal_connect_object(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(open_dialog));
1457 /* initialize dialog values */
1458 open_dialog_popup(NULL,(gpointer)-1);
1459 }
1460
1461 /* if data is -1, just set the values of the open dialog fields,
1462 to be picked up by do_connect */
open_dialog_popup(GtkWidget * w UNUSED,gpointer data)1463 void open_dialog_popup(GtkWidget *w UNUSED, gpointer data) {
1464 int new = 0, join = 0, resume = 0;
1465 char buf[256];
1466 char ht[256], pt[10], ft[256], idt[10];
1467 int usehost = 1;
1468 ht[0] = pt[0] = idt[0] = ft[0] = 0;
1469 if ( strchr(address,':') ) {
1470 /* grrr */
1471 if ( address[0] == ':' ) {
1472 strcpy(ht,"localhost");
1473 strcpy(pt,address+1);
1474 } else {
1475 sscanf(address,"%[^:]:%s",ht,pt);
1476 }
1477 } else {
1478 strcpy(ft,address);
1479 usehost = 0;
1480 }
1481 /* set the default id to be our current id */
1482 sprintf(buf,"%d",our_id);
1483
1484 if ( (int)(intptr_t)data == 1 ) new = 1;
1485 if ( (int)(intptr_t)data == 0 ) join = 1;
1486 if ( (int)(intptr_t)data == 2 ) resume = 1;
1487 gtk_entry_set_text(GTK_ENTRY(openidtext),buf);
1488 /* set the host and port etc from the address */
1489 gtk_widget_set_sensitive(openhost,usehost);
1490 gtk_entry_set_text(GTK_ENTRY(openhosttext),ht);
1491 gtk_widget_set_sensitive(openport,usehost);
1492 gtk_entry_set_text(GTK_ENTRY(openporttext),pt);
1493 gtk_widget_set_sensitive(openfile,!usehost);
1494 gtk_entry_set_text(GTK_ENTRY(openfiletext),ft);
1495
1496 if ( (int)(intptr_t)data == -1 ) return;
1497
1498 if ( join ) {
1499 gtk_widget_show(openhost);
1500 } else {
1501 gtk_widget_hide(openhost);
1502 gtk_entry_set_text(GTK_ENTRY(openhosttext),"localhost");
1503 }
1504
1505 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(usehost ? openhosttoggle : openunixtoggle),1);
1506
1507
1508 if ( resume ) gtk_widget_show(opengamefile);
1509 else gtk_widget_hide(opengamefile);
1510 if ( new || resume ) gtk_widget_show(opengamepanel);
1511 else gtk_widget_hide(opengamepanel);
1512 if ( new ) gtk_widget_show(opentimeout);
1513 else gtk_widget_hide(opentimeout);
1514 if ( new ) gtk_widget_show(openrandomseatsbutton);
1515 else gtk_widget_hide(openrandomseatsbutton);
1516 if ( new ) gtk_widget_show(openstartbutton);
1517 else gtk_widget_hide(openstartbutton);
1518 if ( join ) gtk_widget_show(openconnectbutton);
1519 else gtk_widget_hide(openconnectbutton);
1520 if ( resume ) gtk_widget_show(openresumebutton);
1521 else gtk_widget_hide(openresumebutton);
1522
1523 dialog_popup(open_dialog,DPCentredOnce);
1524
1525 if ( new ) gtk_widget_grab_focus(openstartbutton);
1526 if ( join ) gtk_widget_grab_focus(openconnectbutton);
1527 if ( resume ) gtk_widget_grab_focus(openresumebutton);
1528 }
1529
1530
ACCELFUN(turn)1531 ACCELFUN(turn)
1532
1533 /* the turn dialog: buttons for Discard (also declares specs),
1534 Kong (concealed or adding to pung), Mah Jong */
1535 void turn_dialog_init(void) {
1536 GtkWidget *box, *butbox, *w;
1537
1538 if ( turn_dialog ) {
1539 gtk_widget_destroy(turn_dialog);
1540 turn_dialog = NULL;
1541 }
1542
1543 switch ( dialogs_position ) {
1544 case DialogsCentral:
1545 case DialogsUnspecified:
1546 turn_dialog = gtk_event_box_new();
1547 gtk_fixed_put(GTK_FIXED(discard_area),turn_dialog,0,0);
1548 break;
1549 case DialogsBelow:
1550 turn_dialog = gtk_event_box_new();
1551 gtk_box_pack_start(GTK_BOX(dialoglowerbox),turn_dialog,1,0,0);
1552 break;
1553 case DialogsPopup:
1554 turn_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
1555 gtk_signal_connect (GTK_OBJECT (turn_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1556 }
1557
1558 box = gtk_vbox_new(0,dialog_vert_spacing);
1559 gtk_container_set_border_width(GTK_CONTAINER(box),
1560 dialog_border_width);
1561 gtk_widget_show(box);
1562 gtk_container_add(GTK_CONTAINER(turn_dialog),box);
1563
1564 butbox = gtk_hbox_new(1,dialog_button_spacing);
1565 gtk_widget_show(butbox);
1566 gtk_box_pack_end(GTK_BOX(box),butbox,0,0,0);
1567
1568 turn_dialog_label = w = gtk_label_new("Select tile and:");
1569 gtk_widget_show(w);
1570 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
1571
1572 turn_accel = gtk_accel_group_new();
1573
1574 w = gtk_button_new_with_label("Discard");
1575 gtk_widget_show(w);
1576 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1577 /* so other function can set it */
1578 turn_dialog_discard_button = w;
1579 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgDiscard);
1580 #ifdef GTK2
1581 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",turn_accel,GDK_d,0,0);
1582 #else
1583 gtk_accel_group_add(turn_accel,GDK_d,0,0,GTK_OBJECT(w),"clicked");
1584 #endif
1585 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1586
1587 w = gtk_button_new_with_label("& Calling");
1588 gtk_widget_show(w);
1589 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1590 /* so other function can set it */
1591 turn_dialog_calling_button = w;
1592 /* this assumes knowledge that protocol enums don't go above
1593 1000000 */
1594 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)(PMsgDiscard+1000000));
1595 #ifdef GTK2
1596 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",turn_accel,GDK_c,0,0);
1597 #else
1598 gtk_accel_group_add(turn_accel,GDK_c,0,0,GTK_OBJECT(w),"clicked");
1599 #endif
1600 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child)," _");
1601
1602 w = gtk_button_new_with_label("Kong");
1603 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1604 gtk_widget_show(w);
1605 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1606 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgDeclareClosedKong);
1607 #ifdef GTK2
1608 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",turn_accel,GDK_k,0,0);
1609 #else
1610 gtk_accel_group_add(turn_accel,GDK_k,0,0,GTK_OBJECT(w),"clicked");
1611 #endif
1612 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1613
1614 w = gtk_button_new_with_label("Mah Jong!");
1615 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1616 gtk_widget_show(w);
1617 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1618 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgMahJong);
1619 #ifdef GTK2
1620 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",turn_accel,GDK_m,0,0);
1621 #else
1622 gtk_accel_group_add(turn_accel,GDK_m,0,0,GTK_OBJECT(w),"clicked");
1623 #endif
1624 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1625
1626 gtk_signal_connect(GTK_OBJECT(turn_dialog),"hide",GTK_SIGNAL_FUNC(add_or_remove_turn_accels),(gpointer)0);
1627 gtk_signal_connect(GTK_OBJECT(turn_dialog),"show",GTK_SIGNAL_FUNC(add_or_remove_turn_accels),(gpointer)1);
1628
1629 }
1630
1631 /* dialog for scoring phase: forming closed sets */
1632 static GtkWidget *scoring_done, *scoring_special;
1633
ACCELFUN(scoring)1634 ACCELFUN(scoring)
1635
1636 void scoring_dialog_init(void) {
1637 GtkWidget *box, *butbox, *w;
1638
1639 if ( scoring_dialog ) {
1640 gtk_widget_destroy(scoring_dialog);
1641 scoring_dialog = NULL;
1642 }
1643
1644 switch ( dialogs_position ) {
1645 case DialogsCentral:
1646 case DialogsUnspecified:
1647 scoring_dialog = gtk_event_box_new();
1648 gtk_fixed_put(GTK_FIXED(discard_area),scoring_dialog,0,0);
1649 break;
1650 case DialogsBelow:
1651 scoring_dialog = gtk_event_box_new();
1652 gtk_box_pack_start(GTK_BOX(dialoglowerbox),scoring_dialog,1,0,0);
1653 break;
1654 case DialogsPopup:
1655 scoring_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
1656 gtk_signal_connect (GTK_OBJECT (scoring_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1657 }
1658
1659 box = gtk_vbox_new(0,dialog_vert_spacing);
1660 gtk_container_set_border_width(GTK_CONTAINER(box),
1661 dialog_border_width);
1662 gtk_widget_show(box);
1663 gtk_container_add(GTK_CONTAINER(scoring_dialog),box);
1664
1665 butbox = gtk_hbox_new(1,dialog_button_spacing);
1666 gtk_widget_show(butbox);
1667 gtk_box_pack_end(GTK_BOX(box),butbox,0,0,0);
1668
1669 w = gtk_label_new("Declare concealed sets\nSelect 1st tile and:");
1670 gtk_widget_show(w);
1671 gtk_box_pack_end(GTK_BOX(box),w,0,0,0);
1672
1673 scoring_accel = gtk_accel_group_new();
1674
1675 w = gtk_button_new_with_label("Eyes");
1676 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1677 gtk_widget_show(w);
1678 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1679 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgFormClosedPair);
1680 #ifdef GTK2
1681 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",scoring_accel,GDK_e,0,0);
1682 #else
1683 gtk_accel_group_add(scoring_accel,GDK_e,0,0,GTK_OBJECT(w),"clicked");
1684 #endif
1685 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1686
1687
1688 w = gtk_button_new_with_label("Chow");
1689 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1690 gtk_widget_show(w);
1691 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1692 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgFormClosedChow);
1693 #ifdef GTK2
1694 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",scoring_accel,GDK_c,0,0);
1695 #else
1696 gtk_accel_group_add(scoring_accel,GDK_c,0,0,GTK_OBJECT(w),"clicked");
1697 #endif
1698 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1699
1700 w = gtk_button_new_with_label("Pung");
1701 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1702 gtk_widget_show(w);
1703 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1704 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgFormClosedPung);
1705 #ifdef GTK2
1706 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",scoring_accel,GDK_p,0,0);
1707 #else
1708 gtk_accel_group_add(scoring_accel,GDK_p,0,0,GTK_OBJECT(w),"clicked");
1709 #endif
1710 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1711
1712 scoring_special = w = gtk_button_new_with_label("Special Hand");
1713 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1714 gtk_widget_show(w);
1715 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1716 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgFormClosedSpecialSet);
1717 #ifdef GTK2
1718 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",scoring_accel,GDK_s,0,0);
1719 #else
1720 gtk_accel_group_add(scoring_accel,GDK_s,0,0,GTK_OBJECT(w),"clicked");
1721 #endif
1722 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1723
1724 scoring_done = w = gtk_button_new_with_label("Finished");
1725 GTK_WIDGET_UNSET_FLAGS(w,GTK_CAN_FOCUS);
1726 /* gtk_widget_show(w); */ /* uses same space as special hand */
1727 gtk_box_pack_start(GTK_BOX(butbox),w,1,1,0);
1728 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(turn_callback),(gpointer)(intptr_t)PMsgShowTiles);
1729 #ifdef GTK2
1730 gtk_widget_add_accelerator(GTK_WIDGET(w),"clicked",scoring_accel,GDK_f,0,0);
1731 #else
1732 gtk_accel_group_add(scoring_accel,GDK_f,0,0,GTK_OBJECT(w),"clicked");
1733 #endif
1734 gtk_label_set_pattern(GTK_LABEL(GTK_BIN(w)->child),"_");
1735
1736 gtk_signal_connect(GTK_OBJECT(scoring_dialog),"hide",GTK_SIGNAL_FUNC(add_or_remove_scoring_accels),(gpointer)0);
1737 gtk_signal_connect(GTK_OBJECT(scoring_dialog),"show",GTK_SIGNAL_FUNC(add_or_remove_scoring_accels),(gpointer)1);
1738
1739 }
1740
scoring_dialog_popup(void)1741 void scoring_dialog_popup(void) {
1742 if ( the_game->player == our_seat ) {
1743 gtk_widget_show(scoring_special);
1744 gtk_widget_hide(scoring_done);
1745 } else {
1746 gtk_widget_hide(scoring_special);
1747 gtk_widget_show(scoring_done);
1748 }
1749 dialog_popup(scoring_dialog,DPCentredOnce);
1750 }
1751
1752 /* used above - it removes all the accelerators when the focus
1753 enters the chat widget, to avoid accidents */
mentry_focus_callback(GtkWidget * w UNUSED,GdkEventFocus e UNUSED,gpointer u UNUSED)1754 static gint mentry_focus_callback(GtkWidget *w UNUSED,GdkEventFocus e UNUSED,gpointer u UNUSED) {
1755 add_or_remove_discard_accels(NULL,0);
1756 add_or_remove_chow_accels(NULL,0);
1757 add_or_remove_ds_accels(NULL,0);
1758 add_or_remove_turn_accels(NULL,0);
1759 add_or_remove_scoring_accels(NULL,0);
1760 return 0;
1761 }
1762
1763 /* close a widget, saving its position for next open */
close_saving_posn(GtkWidget * w)1764 void close_saving_posn(GtkWidget *w) {
1765 gint x,y;
1766 gdk_window_get_deskrelative_origin(w->window,&x,&y);
1767 gtk_widget_set_uposition(w,x,y);
1768 /* gtk2 seems to lose the information over unmap/map */
1769 gtk_object_set_data(GTK_OBJECT(w),"position-set",(gpointer)1);
1770 gtk_object_set_data(GTK_OBJECT(w),"position-x",(gpointer)(intptr_t)x);
1771 gtk_object_set_data(GTK_OBJECT(w),"position-y",(gpointer)(intptr_t)y);
1772 gtk_widget_hide(w);
1773 }
1774
1775 /* the textwindow for scoring information etc */
textwindow_init(void)1776 void textwindow_init(void) {
1777 int i;
1778 GtkWidget
1779 #ifndef GTK2
1780 *sbar,
1781 #endif
1782 *obox, *box, *tmp, *lbl,*textw;
1783
1784 textwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1785 gtk_signal_connect (GTK_OBJECT (textwindow), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1786 /* must allow shrinking */
1787 gtk_window_set_policy(GTK_WINDOW(textwindow),TRUE,TRUE,FALSE);
1788 gtk_window_set_title(GTK_WINDOW(textwindow),"Scoring calculations");
1789
1790 // we used to set the size here, but I think that's better done
1791 // on popup
1792
1793 obox = gtk_vbox_new(0,dialog_vert_spacing);
1794 gtk_container_set_border_width(GTK_CONTAINER(obox),dialog_border_width);
1795 gtk_widget_show(obox);
1796 gtk_container_add(GTK_CONTAINER(textwindow),obox);
1797
1798 scoring_notebook = gtk_notebook_new();
1799 GTK_WIDGET_UNSET_FLAGS(scoring_notebook,GTK_CAN_FOCUS);
1800 gtk_notebook_set_homogeneous_tabs(GTK_NOTEBOOK(scoring_notebook),1);
1801 gtk_widget_show(scoring_notebook);
1802 gtk_box_pack_start(GTK_BOX(obox),scoring_notebook,1,1,0);
1803
1804 for (i=0;i<5;i++) {
1805 #ifdef GTK2
1806 textw = gtk_text_view_new();
1807 gtk_text_view_set_editable(GTK_TEXT_VIEW(textw),FALSE);
1808 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textw),FALSE);
1809 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textw),GTK_WRAP_WORD_CHAR);
1810 #else
1811 GtkStyle *s;
1812 textw = gtk_text_new(NULL,NULL);
1813 #endif
1814 gtk_widget_show(textw);
1815 textpages[i] = textw;
1816 #ifdef GTK2
1817 box = gtk_scrolled_window_new(NULL,NULL);
1818 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(box),GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
1819 gtk_container_add(GTK_CONTAINER(box),textw);
1820 #else
1821 sbar = gtk_vscrollbar_new(GTK_TEXT (textw)->vadj);
1822 gtk_widget_show(sbar);
1823 box = gtk_hbox_new(0,0);
1824 gtk_box_pack_start(GTK_BOX(box),sbar,0,0,0);
1825 gtk_box_pack_start(GTK_BOX(box),textw,1,1,0);
1826 #endif
1827 gtk_widget_show(box);
1828 lbl = gtk_label_new((i==4) ? "Settlement" : "");
1829 gtk_widget_show(lbl);
1830 textlabels[i] = lbl;
1831 gtk_notebook_append_page(GTK_NOTEBOOK(scoring_notebook),box,lbl);
1832 gtk_widget_realize(textw);
1833 #ifndef GTK2
1834 if ( fixed_font ) {
1835 s = gtk_style_copy(gtk_widget_get_style(textw));
1836 s->font = fixed_font;
1837 gtk_widget_set_style(textw,s);
1838 }
1839 #endif
1840 }
1841
1842 tmp = gtk_button_new_with_label("Close");
1843 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(textwindow));
1844 gtk_widget_show(tmp);
1845 gtk_box_pack_end(GTK_BOX(obox),tmp,0,0,0);
1846 gtk_widget_grab_focus(tmp);
1847 }
1848
1849 /* the textwindow for scoring history */
1850
scorehistory_init(void)1851 void scorehistory_init(void) {
1852 int i;
1853 GtkWidget
1854 #ifndef GTK2
1855 *sbar,
1856 #endif
1857 *obox, *box, *tmp, *lbl,*textw;
1858
1859 scorehistorywindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1860 gtk_signal_connect (GTK_OBJECT (scorehistorywindow), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1861 /* must allow shrinking */
1862 gtk_window_set_policy(GTK_WINDOW(scorehistorywindow),TRUE,TRUE,FALSE);
1863 gtk_window_set_title(GTK_WINDOW(scorehistorywindow),"Scoring history");
1864
1865 gtk_widget_set_usize(scorehistorywindow,0,400);
1866
1867 obox = gtk_vbox_new(0,dialog_vert_spacing);
1868 gtk_container_set_border_width(GTK_CONTAINER(obox),dialog_border_width);
1869 gtk_widget_show(obox);
1870 gtk_container_add(GTK_CONTAINER(scorehistorywindow),obox);
1871
1872 #ifdef GTK2
1873 scorehistorytext = textw = gtk_text_view_new();
1874 gtk_text_view_set_editable(GTK_TEXT_VIEW(textw),FALSE);
1875 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textw),FALSE);
1876 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textw),GTK_WRAP_NONE);
1877 #else
1878 GtkStyle *s;
1879 scorehistorytext = textw = gtk_text_new(NULL,NULL);
1880 gtk_text_set_word_wrap(GTK_TEXT(textw),FALSE);
1881 gtk_text_set_editable(GTK_TEXT(textw),FALSE);
1882 #endif
1883 gtk_widget_show(textw);
1884 #ifdef GTK2
1885 box = gtk_scrolled_window_new(NULL,NULL);
1886 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(box),GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
1887 gtk_container_add(GTK_CONTAINER(box),textw);
1888 #else
1889 sbar = gtk_vscrollbar_new(GTK_TEXT (textw)->vadj);
1890 gtk_widget_show(sbar);
1891 box = gtk_hbox_new(0,0);
1892 gtk_box_pack_start(GTK_BOX(box),sbar,0,0,0);
1893 gtk_box_pack_start(GTK_BOX(box),textw,1,1,0);
1894 #endif
1895 gtk_box_pack_start(GTK_BOX(obox),box,1,1,0);
1896 gtk_widget_show(box);
1897 gtk_widget_realize(textw);
1898 #ifndef GTK2
1899 if ( fixed_font ) {
1900 s = gtk_style_copy(gtk_widget_get_style(textw));
1901 s->font = fixed_font;
1902 gtk_widget_set_style(textw,s);
1903 }
1904 #endif
1905
1906 tmp = gtk_button_new_with_label("Close");
1907 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(scorehistorywindow));
1908 gtk_widget_show(tmp);
1909 gtk_box_pack_end(GTK_BOX(obox),tmp,0,0,0);
1910 gtk_widget_grab_focus(tmp);
1911 }
1912
1913 /* the callback when user hits return in the message composition window */
mentry_callback(GtkWidget * widget UNUSED,GtkWidget * mentry)1914 static void mentry_callback(GtkWidget *widget UNUSED,GtkWidget *mentry) {
1915 const gchar *mentry_text;
1916 PMsgSendMessageMsg smm;
1917 mentry_text = gtk_entry_get_text(GTK_ENTRY(mentry));
1918 smm.type = PMsgSendMessage;
1919 smm.addressee = 0; /* broadcast only at present ... */
1920 smm.text = (char *)mentry_text;
1921 send_packet(&smm);
1922 gtk_entry_set_text(GTK_ENTRY(mentry),"");
1923 }
1924
1925 static gint mentry_focus_callback(GtkWidget *w,GdkEventFocus e,gpointer u);
1926
1927 /* the window for messages */
messagewindow_init(void)1928 void messagewindow_init(void) {
1929 GtkWidget *obox, *box, *tmp, *mentry, *label;
1930 #ifndef GTK2
1931 GtkWidget *sbar;
1932 GtkStyle *s;
1933 #endif
1934
1935 if ( !info_windows_in_main ) {
1936 messagewindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1937 gtk_signal_connect (GTK_OBJECT (messagewindow), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
1938 /* must allow shrinking */
1939 gtk_window_set_policy(GTK_WINDOW(messagewindow),TRUE,TRUE,FALSE);
1940 gtk_window_set_title(GTK_WINDOW(messagewindow),"Messages");
1941 /* reasonable size is ... */
1942 gtk_window_set_default_size(GTK_WINDOW(messagewindow),400,300);
1943 }
1944
1945 obox = gtk_vbox_new(0,info_windows_in_main ? 0 : dialog_vert_spacing);
1946 if ( !info_windows_in_main ) {
1947 gtk_container_set_border_width(GTK_CONTAINER(obox),dialog_border_width);
1948 }
1949 gtk_widget_show(obox);
1950 if ( info_windows_in_main ) {
1951 messagewindow = obox;
1952 gtk_box_pack_end(GTK_BOX(info_box),messagewindow,1,1,0);
1953 } else {
1954 gtk_container_add(GTK_CONTAINER(messagewindow),obox);
1955 }
1956
1957 #ifdef GTK2
1958 messagetext = gtk_text_view_new();
1959 gtk_text_view_set_editable(GTK_TEXT_VIEW(messagetext),FALSE);
1960 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(messagetext),FALSE);
1961 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(messagetext),GTK_WRAP_WORD_CHAR);
1962 messagetextbuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (messagetext));
1963 gtk_text_buffer_get_iter_at_offset (messagetextbuf, &messagetextiter, 0);
1964 #else
1965 messagetext = gtk_text_new(NULL,NULL);
1966 #endif
1967 if ( info_windows_in_main ) {
1968 gtk_widget_set_usize(messagetext,0,50);
1969 }
1970 gtk_widget_show(messagetext);
1971 #ifdef GTK2
1972 box = gtk_scrolled_window_new(NULL,NULL);
1973 gtk_container_add(GTK_CONTAINER(box),messagetext);
1974 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(box),GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
1975 #else
1976 sbar = gtk_vscrollbar_new(GTK_TEXT (messagetext)->vadj);
1977 gtk_widget_show(sbar);
1978 box = gtk_hbox_new(0,0);
1979 gtk_box_pack_start(GTK_BOX(box),sbar,0,0,0);
1980 gtk_box_pack_start(GTK_BOX(box),messagetext,1,1,0);
1981 #endif
1982 gtk_widget_show(box);
1983 gtk_box_pack_start(GTK_BOX(obox),box,1,1,0);
1984 gtk_widget_realize(messagetext);
1985 #ifndef GTK2
1986 if ( fixed_font ) {
1987 s = gtk_style_copy(gtk_widget_get_style(messagetext));
1988 s->font = fixed_font;
1989 gtk_widget_set_style(messagetext,s);
1990 }
1991 #endif
1992
1993 GTK_WIDGET_UNSET_FLAGS(messagetext,GTK_CAN_FOCUS); /* entry widget shd focus */
1994
1995 label = gtk_label_new(info_windows_in_main ? "Chat:" : "Send message:");
1996 GTK_WIDGET_UNSET_FLAGS(label,GTK_CAN_FOCUS);
1997 gtk_misc_set_alignment(GTK_MISC(label),0.0,0.5);
1998 gtk_widget_show(label);
1999
2000 /* the thing for sending messages */
2001 message_entry = mentry = gtk_entry_new();
2002 gtk_widget_show(mentry);
2003 gtk_signal_connect(GTK_OBJECT(mentry),"activate",GTK_SIGNAL_FUNC(mentry_callback),mentry);
2004 gtk_signal_connect(GTK_OBJECT(mentry),"focus-in-event",GTK_SIGNAL_FUNC(mentry_focus_callback),mentry);
2005
2006 if ( !info_windows_in_main ) {
2007 gtk_box_pack_start(GTK_BOX(obox),label,0,0,0);
2008 gtk_box_pack_start(GTK_BOX(obox),mentry,0,0,0);
2009 } else {
2010 GtkWidget *w = gtk_hbox_new(0,0);
2011 gtk_widget_show(w);
2012 gtk_box_pack_start(GTK_BOX(w),label,0,0,0);
2013 gtk_box_pack_start(GTK_BOX(w),mentry,0,0,0);
2014 mfocus = gtk_check_button_new_with_label("keep cursor here");
2015 GTK_WIDGET_UNSET_FLAGS(mfocus,GTK_CAN_FOCUS);
2016 gtk_widget_show(mfocus);
2017 gtk_box_pack_start(GTK_BOX(w),mfocus,0,0,0);
2018 gtk_box_pack_start(GTK_BOX(obox),w,0,0,0);
2019 }
2020
2021
2022 if ( !info_windows_in_main ) {
2023 tmp = gtk_button_new_with_label("Close");
2024 GTK_WIDGET_UNSET_FLAGS(tmp,GTK_CAN_FOCUS); /* entry widget shd focus */
2025 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(messagewindow));
2026 gtk_widget_show(tmp);
2027 gtk_box_pack_end(GTK_BOX(obox),tmp,0,0,0);
2028 /* god knows how focus would work if this happened in the topwindow! */
2029 gtk_widget_grab_focus(mentry);
2030 }
2031 }
2032
2033 /* the window for showing warnings */
warningwindow_init(void)2034 void warningwindow_init(void) {
2035 GtkWidget *obox, *box, *tmp, *label;
2036 #ifndef GTK2
2037 GtkWidget *sbar;
2038 GtkStyle *s;
2039 #endif
2040
2041 if ( warningwindow ) { gtk_widget_destroy(warningwindow); }
2042 warningwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2043 gtk_signal_connect (GTK_OBJECT (warningwindow), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
2044 /* must allow shrinking */
2045 gtk_window_set_policy(GTK_WINDOW(warningwindow),TRUE,TRUE,FALSE);
2046 gtk_window_set_title(GTK_WINDOW(warningwindow),"Warnings");
2047 /* reasonable size is ... */
2048 gtk_window_set_default_size(GTK_WINDOW(warningwindow),400,300);
2049
2050 obox = gtk_vbox_new(0,dialog_vert_spacing);
2051 gtk_container_set_border_width(GTK_CONTAINER(obox),dialog_border_width);
2052 gtk_widget_show(obox);
2053 gtk_container_add(GTK_CONTAINER(warningwindow),obox);
2054
2055 label = gtk_label_new(
2056 "Apart from when a player disconnects,\n"
2057 "warnings usually indicate a bug or other\n"
2058 "unexpected situation. If in doubt,\n"
2059 "please mail mahjong@stevens-bradfield.com\n"
2060 "with the warning text and a description\n"
2061 "of the situation in which it occurred.");
2062 GTK_WIDGET_UNSET_FLAGS(label,GTK_CAN_FOCUS);
2063 gtk_widget_show(label);
2064 gtk_box_pack_start(GTK_BOX(obox),label,0,0,0);
2065
2066 #ifdef GTK2
2067 warningtext = gtk_text_view_new();
2068 warningtextbuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (warningtext));
2069 gtk_text_buffer_get_iter_at_offset (warningtextbuf, &warningtextiter, 0);
2070 #else
2071 warningtext = gtk_text_new(NULL,NULL);
2072 #endif
2073 gtk_widget_show(warningtext);
2074 #ifdef GTK2
2075 box = gtk_scrolled_window_new(NULL,NULL);
2076 gtk_container_add(GTK_CONTAINER(box),warningtext);
2077 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(box),GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
2078 #else
2079 sbar = gtk_vscrollbar_new(GTK_TEXT (warningtext)->vadj);
2080 gtk_widget_show(sbar);
2081 box = gtk_hbox_new(0,0);
2082 gtk_box_pack_start(GTK_BOX(box),sbar,0,0,0);
2083 gtk_box_pack_start(GTK_BOX(box),warningtext,1,1,0);
2084 #endif
2085 gtk_widget_show(box);
2086 gtk_box_pack_start(GTK_BOX(obox),box,1,1,0);
2087 gtk_widget_realize(warningtext);
2088 #ifndef GTK2
2089 if ( fixed_font ) {
2090 s = gtk_style_copy(gtk_widget_get_style(warningtext));
2091 s->font = fixed_font;
2092 gtk_widget_set_style(warningtext,s);
2093 }
2094 #endif
2095
2096 GTK_WIDGET_UNSET_FLAGS(warningtext,GTK_CAN_FOCUS);
2097
2098 box = gtk_hbox_new(0,0);
2099 gtk_widget_show(box);
2100 gtk_box_pack_end(GTK_BOX(obox),box,0,0,0);
2101
2102 tmp = gtk_button_new_with_label("Clear Warnings");
2103 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(warning_clear),NULL);
2104 gtk_widget_show(tmp);
2105 gtk_box_pack_start(GTK_BOX(box),tmp,1,1,0);
2106
2107 tmp = gtk_button_new_with_label("Close");
2108 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(warningwindow));
2109 gtk_widget_show(tmp);
2110 gtk_box_pack_end(GTK_BOX(box),tmp,1,1,0);
2111
2112 /* check for cached warnings */
2113 log_msg_add(0,NULL);
2114 }
2115
warningraise(void)2116 static void warningraise(void) {
2117 showraise(warningwindow);
2118 }
2119
2120 static int warning_numbers = 0;
2121
2122
warning_clear(void)2123 void warning_clear(void) {
2124 warning_numbers = 0;
2125 #ifdef GTK2
2126 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(warningtextbuf),"",0);
2127 gtk_text_buffer_get_iter_at_offset (warningtextbuf, &warningtextiter, 0);
2128 #else
2129 gtk_editable_delete_text(GTK_EDITABLE(warningtext),0,-1);
2130 #endif
2131 gtk_widget_hide(warningentry);
2132 close_saving_posn(warningwindow);
2133 }
2134
2135 static GtkWidget *debug_options_reporting; /* query dialog */
2136
file_report(char * warning)2137 static void file_report(char *warning) {
2138 SOCKET fd;
2139 static int in_progress = 0;
2140 static int waiting_permission = 0;
2141 /* don't enter this routine twice.
2142 However, if we're waiting for permission, the permission is
2143 given by calling this routine with a non-null or null argument.
2144 */
2145 if ( in_progress && ! waiting_permission ) return;
2146 if ( debug_reports == DebugReportsNever ) return;
2147 in_progress = 1;
2148 if ( debug_reports != DebugReportsAlways ) {
2149 static char saved_warning[50000];
2150 if ( waiting_permission ) {
2151 waiting_permission = 0;
2152 gtk_widget_hide(debug_options_reporting);
2153 control_server_processing(1);
2154 if ( warning ) {
2155 // permission received
2156 warning = saved_warning;
2157 } else {
2158 // permission denied
2159 in_progress = 0;
2160 return;
2161 }
2162 } else {
2163 // need to ask for permission
2164 waiting_permission = 1;
2165 // save the warning text
2166 strmcpy(saved_warning,warning,49999);
2167 // disable processing of input from the server, to avoid confusion
2168 control_server_processing(0);
2169 debug_report_query_popup();
2170 return;
2171 }
2172 }
2173 // now file the report
2174 fd = plain_connect_to_host("www.stevens-bradfield.com:9000");
2175 if ( fd == INVALID_SOCKET ) {
2176 warn("unable to file error report");
2177 } else {
2178 static char header[] = "From: <nobody@nobody.nobody>\n"
2179 "To: mahjong@stevens-bradfield.com\n"
2180 "Subject: XMJ internal error report\n"
2181 "\n"
2182 "XMJ version: ";
2183 char msg[1024];
2184 int n;
2185 put_data(fd,header,strlen(header));
2186 put_data(fd,(char *)version,strlen(version));
2187 put_data(fd,"\n",1);
2188 put_data(fd,warning,strlen(warning));
2189 put_data(fd,NULL,0);
2190 n = get_data(fd,msg,1023);
2191 if ( n > 0 ) {
2192 info_dialog_popup(msg);
2193 }
2194 plain_close_socket(fd);
2195 }
2196 in_progress = 0;
2197 }
2198
2199
2200 /* a second argument of NULL just checks for stashed warnings to be
2201 transferred to the window */
log_msg_add(LogLevel l,char * warning)2202 int log_msg_add(LogLevel l,char *warning) {
2203 static char buf[1024] = "";
2204 if ( warning && l >= LogWarning) warning_numbers++;
2205 /* if the warning window is not currently available,
2206 cache the warning until it is */
2207 if ( warningwindow == NULL ) {
2208 if ( warning ) {
2209 strncat(buf,warning,1023-strlen(buf));
2210 }
2211 } else {
2212 if ( buf[0] ) {
2213 #ifdef GTK2
2214 gtk_text_buffer_insert(warningtextbuf,&warningtextiter,buf,-1);
2215 gtk_text_buffer_get_end_iter(warningtextbuf,&warningtextiter);
2216 #else
2217 gtk_text_insert(GTK_TEXT(warningtext),NULL,NULL,NULL,buf,-1);
2218 #endif
2219 buf[0] = 0;
2220 }
2221 if ( warning ) {
2222 #ifdef GTK2
2223 gtk_text_buffer_insert(warningtextbuf,&warningtextiter,warning,-1);
2224 gtk_text_buffer_get_end_iter(warningtextbuf,&warningtextiter);
2225 #else
2226 gtk_text_insert(GTK_TEXT(warningtext),NULL,NULL,NULL,warning,-1);
2227 #endif
2228 }
2229 if ( warning_numbers > 0 ) gtk_widget_show(warningentry);
2230 /* if the log level exceeds warning, try to file a report,
2231 and give user a message */
2232 if ( l > LogWarning ) {
2233 file_report(warning);
2234 error_dialog_popup("The program has encountered an internal error.\n"
2235 "This will probably cause it to crash very soon. Sorry!");
2236 }
2237 }
2238 /* tell warn to print the warning anyway */
2239 return 0;
2240 }
2241
2242 /* callback for saving as */
save_callback(GtkWidget * w UNUSED,gpointer data UNUSED)2243 static void save_callback(GtkWidget *w UNUSED, gpointer data UNUSED) {
2244 PMsgSaveStateMsg m;
2245
2246 m.type = PMsgSaveState;
2247 m.filename = (char *)gtk_entry_get_text(GTK_ENTRY(save_text));
2248 send_packet(&m);
2249 close_saving_posn(save_window);
2250 }
2251
2252 /* window for Save As ... function */
save_init(void)2253 static void save_init(void) {
2254 GtkWidget *box, *bbox, *w1, *tmp;
2255
2256
2257 save_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2258 gtk_signal_connect (GTK_OBJECT (save_window), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
2259 gtk_container_set_border_width(GTK_CONTAINER(save_window),
2260 dialog_border_width);
2261
2262 bbox = gtk_vbox_new(0,0);
2263 gtk_widget_show(bbox);
2264 gtk_container_add(GTK_CONTAINER(save_window),bbox);
2265
2266 w1 = gtk_label_new("Save as:");
2267 gtk_widget_show(w1);
2268 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2269
2270 box = gtk_hbox_new(0,0);
2271 gtk_widget_show(box);
2272 gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
2273
2274 save_text = gtk_entry_new();
2275 gtk_widget_show(save_text);
2276 gtk_box_pack_start(GTK_BOX(box),save_text,0,0,0);
2277
2278 w1 = gtk_label_new(".mjs");
2279 gtk_widget_show(w1);
2280 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
2281
2282 box = gtk_hbox_new(0,0);
2283 gtk_widget_show(box);
2284 gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
2285
2286 tmp = gtk_button_new_with_label("Save");
2287 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(save_callback),0);
2288 gtk_widget_show(tmp);
2289 gtk_box_pack_start(GTK_BOX(box),tmp,1,1,0);
2290
2291 tmp = gtk_button_new_with_label("Cancel");
2292 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(save_window));
2293 gtk_widget_show(tmp);
2294 gtk_box_pack_start(GTK_BOX(box),tmp,1,1,0);
2295
2296 }
2297
2298 /* callback for password */
password_callback(GtkWidget * w UNUSED,gpointer data UNUSED)2299 static void password_callback(GtkWidget *w UNUSED, gpointer data UNUSED) {
2300 PMsgAuthInfoMsg m;
2301
2302 m.type = PMsgAuthInfo;
2303 strcpy(m.authtype,"basic");
2304 m.authdata = (char *)gtk_entry_get_text(GTK_ENTRY(password_text));
2305 send_packet(&m);
2306 close_saving_posn(password_window);
2307 }
2308
2309 /* window for password request */
password_init(void)2310 static void password_init(void) {
2311 GtkWidget *box, *bbox, *w1, *tmp;
2312
2313 password_window = gtk_window_new(GTK_WINDOW_DIALOG);
2314 gtk_signal_connect (GTK_OBJECT (password_window), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
2315 gtk_container_set_border_width(GTK_CONTAINER(password_window),
2316 dialog_border_width);
2317
2318 bbox = gtk_vbox_new(0,0);
2319 gtk_widget_show(bbox);
2320 gtk_container_add(GTK_CONTAINER(password_window),bbox);
2321
2322 w1 = gtk_label_new("Password required:");
2323 gtk_widget_show(w1);
2324 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2325
2326 box = gtk_hbox_new(0,0);
2327 gtk_widget_show(box);
2328 gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
2329
2330 password_text = gtk_entry_new();
2331 gtk_widget_show(password_text);
2332 gtk_box_pack_start(GTK_BOX(box),password_text,0,0,0);
2333
2334 box = gtk_hbox_new(0,0);
2335 gtk_widget_show(box);
2336 gtk_box_pack_start(GTK_BOX(bbox),box,0,0,0);
2337
2338 tmp = gtk_button_new_with_label("OK");
2339 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(password_callback),0);
2340 gtk_widget_show(tmp);
2341 gtk_box_pack_start(GTK_BOX(box),tmp,1,1,0);
2342
2343 gtk_widget_show(tmp);
2344 gtk_box_pack_start(GTK_BOX(box),tmp,1,1,0);
2345
2346 }
2347
2348
2349 /* radio buttons for dialog positions */
2350 static GtkWidget *display_option_dialog_dialogposn[DialogsPopup+1];
2351 /* checkbox for animation */
2352 static GtkWidget *display_option_dialog_animation;
2353 /* checkbox for nopopups */
2354 static GtkWidget *display_option_dialog_nopopups;
2355 /* checkbox for tiletips */
2356 static GtkWidget *display_option_dialog_tiletips;
2357 /* checkbox for rotatelabels */
2358 static GtkWidget *display_option_dialog_rotatelabels;
2359 /* checkbox for thinking_claim */
2360 static GtkWidget *display_option_dialog_thinking_claim;
2361 /* checkbox for alert_mahjong */
2362 static GtkWidget *display_option_dialog_alert_mahjong;
2363 /* check box for iconify option */
2364 static GtkWidget *display_option_dialog_iconify;
2365 /* check box for info in main */
2366 static GtkWidget *display_option_dialog_info_in_main;
2367 /* radiobuttons for show wall */
2368 static GtkWidget *display_option_dialog_showwall[3];
2369 static GtkWidget *display_option_dialog_tileset, *display_option_dialog_tileset_path;
2370 /* text entry for size */
2371 static GtkWidget *display_option_size_entry;
2372 /* radio buttons for sort tiles */
2373 static GtkWidget *display_option_dialog_sort_tiles[3];
2374 #ifdef GTK2
2375 /* text entry for gtk2rc file */
2376 static GtkWidget *display_option_dialog_gtk2_rcfile;
2377 /* checkbox entry for use_system_gtkrc */
2378 static GtkWidget *display_option_dialog_use_system_gtkrc;
2379 #endif
2380
2381 static void display_option_dialog_apply(void);
2382 static void display_option_dialog_save(void);
2383 static void display_option_dialog_refresh(void);
2384
2385 /* things used below */
2386 static GtkWidget *mfontwindow;
2387 static GtkWidget *mfont_selector;
mfontsel_callback(GtkWidget * w UNUSED,gpointer data)2388 static void mfontsel_callback(GtkWidget *w UNUSED, gpointer data) {
2389 if ( data ) {
2390 /* use default */
2391 main_font_name[0] = 0;
2392 } else {
2393 /* use selection */
2394 strmcpy(main_font_name,gtk_font_selection_get_font_name(GTK_FONT_SELECTION(mfont_selector)),256);
2395 }
2396 gtk_widget_hide(mfontwindow);
2397 }
2398
2399 static GtkWidget *tfontwindow;
2400 static GtkWidget *tfont_selector;
tfontsel_callback(GtkWidget * w UNUSED,gpointer data)2401 static void tfontsel_callback(GtkWidget *w UNUSED, gpointer data) {
2402 if ( data ) {
2403 /* use default */
2404 text_font_name[0] = 0;
2405 } else {
2406 /* use selection */
2407 strmcpy(text_font_name,gtk_font_selection_get_font_name(GTK_FONT_SELECTION(tfont_selector)),256);
2408 }
2409 gtk_widget_hide(tfontwindow);
2410 }
2411
2412 static GtkWidget *tcolwindow;
2413 static GtkWidget *tcolor_selector;
tcolsel_callback(GtkWidget * w UNUSED,gpointer data)2414 static void tcolsel_callback(GtkWidget *w UNUSED, gpointer data) {
2415 if ( data ) {
2416 /* use default */
2417 table_colour_name[0] = 0;
2418 } else {
2419 /* use selection */
2420 gdouble c[4];
2421 gtk_color_selection_get_color(GTK_COLOR_SELECTION(tcolor_selector),c);
2422 #ifdef GTK2
2423 sprintf(table_colour_name,"#%04X%04X%04X",(int)(0xFFFF*c[0]),(int)(0xFFFF*c[1]),(int)(0xFFFF*c[2]));
2424 #else
2425 sprintf(table_colour_name,"rgb:%04X/%04X/%04X",(int)(0xFFFF*c[0]),(int)(0xFFFF*c[1]),(int)(0xFFFF*c[2]));
2426 #endif
2427 }
2428 gtk_widget_hide(tcolwindow);
2429 }
2430
2431 /* window for display options */
display_option_dialog_init(void)2432 static void display_option_dialog_init(void) {
2433 GtkWidget *box, *bbox, *hbox, *but1, *but2, *but3, *w1, *w2;
2434
2435 display_option_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
2436 gtk_signal_connect (GTK_OBJECT (display_option_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
2437 gtk_container_set_border_width(GTK_CONTAINER(display_option_dialog),
2438 dialog_border_width);
2439
2440 box = gtk_vbox_new(0,dialog_vert_spacing);
2441 gtk_widget_show(box);
2442 gtk_container_add(GTK_CONTAINER(display_option_dialog),box);
2443
2444 bbox = gtk_vbox_new(0,0);
2445 gtk_widget_show(bbox);
2446 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
2447
2448 w1 = gtk_label_new("Position of action dialogs:");
2449 gtk_widget_show(w1);
2450 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2451
2452 hbox = gtk_hbox_new(0,dialog_button_spacing);
2453 gtk_widget_show(hbox);
2454 gtk_box_pack_start(GTK_BOX(bbox),hbox,0,0,0);
2455
2456 but1 = gtk_radio_button_new_with_label(NULL,"central");
2457 gtk_widget_show(but1);
2458 gtk_box_pack_start(GTK_BOX(hbox),but1,0,0,0);
2459 display_option_dialog_dialogposn[DialogsCentral] = but1 ;
2460
2461 but2 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"below");
2462 gtk_widget_show(but2);
2463 gtk_box_pack_start(GTK_BOX(hbox),but2,0,0,0);
2464 display_option_dialog_dialogposn[DialogsBelow] = but2;
2465
2466 but3 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"popup");
2467 gtk_widget_show(but3);
2468 gtk_box_pack_start(GTK_BOX(hbox),but3,0,0,0);
2469 display_option_dialog_dialogposn[DialogsPopup] = but3;
2470
2471 /* animation */
2472 display_option_dialog_animation = but1 =
2473 gtk_check_button_new_with_label("Animation");
2474 gtk_widget_show(but1);
2475 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2476
2477 /* info in main */
2478 display_option_dialog_info_in_main = but1 =
2479 gtk_check_button_new_with_label("Display status and messages in main window");
2480 gtk_widget_show(but1);
2481 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2482
2483 /* nopopups */
2484 display_option_dialog_nopopups = but1 =
2485 gtk_check_button_new_with_label("Don't popup scoring/message windows");
2486 gtk_widget_show(but1);
2487 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2488
2489 /* tiletips */
2490 display_option_dialog_tiletips = but1 =
2491 gtk_check_button_new_with_label("Tiletips always shown");
2492 gtk_widget_show(but1);
2493 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2494
2495 /* rotatelabels */
2496 display_option_dialog_rotatelabels = but1 =
2497 gtk_check_button_new_with_label("Rotate player info text");
2498 gtk_widget_show(but1);
2499 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2500
2501 /* thinking_claim */
2502 display_option_dialog_thinking_claim = but1 =
2503 gtk_check_button_new_with_label("Show when players are thinking");
2504 gtk_widget_show(but1);
2505 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2506
2507 /* mah-jong */
2508 display_option_dialog_alert_mahjong = but1 =
2509 gtk_check_button_new_with_label("Alert on possible mah-jong");
2510 gtk_widget_show(but1);
2511 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2512
2513 /* display size */
2514 hbox = gtk_hbox_new(0,dialog_button_spacing);
2515 gtk_widget_show(hbox);
2516 gtk_box_pack_start(GTK_BOX(box),hbox,0,0,0);
2517 w1 = gtk_label_new("Display size (in tile-widths):");
2518 gtk_widget_show(w1);
2519 gtk_box_pack_start(GTK_BOX(hbox),w1,0,0,0);
2520 w1 = gtk_combo_new();
2521 gtk_entry_set_max_length(GTK_ENTRY(GTK_COMBO(w1)->entry),6);
2522 gtk_widget_show(w1);
2523 gtk_box_pack_start(GTK_BOX(hbox),w1,0,0,0);
2524 { GList *gl = NULL;
2525 gl = g_list_append(gl,"19");
2526 gl = g_list_append(gl,"18");
2527 gl = g_list_append(gl,"17");
2528 gl = g_list_append(gl,"16");
2529 gl = g_list_append(gl,"15");
2530 gl = g_list_append(gl,"14");
2531 gl = g_list_append(gl,"(auto)");
2532 gtk_combo_set_popdown_strings(GTK_COMBO(w1),gl);
2533 }
2534 gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(w1)->entry),FALSE);
2535 display_option_size_entry = GTK_COMBO(w1)->entry;
2536
2537 /* showwall setting */
2538 bbox = gtk_vbox_new(0,0);
2539 gtk_widget_show(bbox);
2540 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
2541
2542 w1 = gtk_label_new("Show the wall:");
2543 gtk_widget_show(w1);
2544 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2545
2546 hbox = gtk_hbox_new(0,dialog_button_spacing);
2547 gtk_widget_show(hbox);
2548 gtk_box_pack_start(GTK_BOX(bbox),hbox,0,0,0);
2549
2550 but1 = gtk_radio_button_new_with_label(NULL,"always");
2551 gtk_widget_show(but1);
2552 gtk_box_pack_start(GTK_BOX(hbox),but1,0,0,0);
2553 display_option_dialog_showwall[1] = but1 ;
2554
2555 but2 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"when room");
2556 gtk_widget_show(but2);
2557 gtk_box_pack_start(GTK_BOX(hbox),but2,0,0,0);
2558 display_option_dialog_showwall[2] = but2;
2559
2560 but3 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"never");
2561 gtk_widget_show(but3);
2562 gtk_box_pack_start(GTK_BOX(hbox),but3,0,0,0);
2563 display_option_dialog_showwall[0] = but3;
2564
2565 /* sort tiles setting */
2566 bbox = gtk_vbox_new(0,0);
2567 gtk_widget_show(bbox);
2568 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
2569
2570 w1 = gtk_label_new("Sort tiles in hand:");
2571 gtk_widget_show(w1);
2572 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2573
2574 hbox = gtk_hbox_new(0,dialog_button_spacing);
2575 gtk_widget_show(hbox);
2576 gtk_box_pack_start(GTK_BOX(bbox),hbox,0,0,0);
2577
2578 but1 = gtk_radio_button_new_with_label(NULL,"always");
2579 gtk_widget_show(but1);
2580 gtk_box_pack_start(GTK_BOX(hbox),but1,0,0,0);
2581 display_option_dialog_sort_tiles[SortAlways] = but1 ;
2582
2583 but2 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"during deal");
2584 gtk_widget_show(but2);
2585 gtk_box_pack_start(GTK_BOX(hbox),but2,0,0,0);
2586 display_option_dialog_sort_tiles[SortDeal] = but2;
2587
2588 but3 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but1)),"never");
2589 gtk_widget_show(but3);
2590 gtk_box_pack_start(GTK_BOX(hbox),but3,0,0,0);
2591 display_option_dialog_sort_tiles[SortNever] = but3;
2592
2593 /* iconify */
2594 display_option_dialog_iconify = but1 =
2595 gtk_check_button_new_with_label("Iconify all windows with main");
2596 gtk_widget_show(but1);
2597 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2598
2599 /* tileset name */
2600 bbox = gtk_hbox_new(0,0);
2601 gtk_widget_show(bbox);
2602 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
2603
2604 w1 = gtk_label_new("Tileset: ");
2605 gtk_widget_show(w1);
2606 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2607
2608 display_option_dialog_tileset = w1 = gtk_entry_new();
2609 gtk_widget_show(w1);
2610 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2611
2612 /* tileset path */
2613 bbox = gtk_hbox_new(0,0);
2614 gtk_widget_show(bbox);
2615 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
2616
2617 w1 = gtk_label_new("Tileset Path: ");
2618 gtk_widget_show(w1);
2619 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2620
2621 display_option_dialog_tileset_path = w1 = gtk_entry_new();
2622 gtk_widget_show(w1);
2623 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2624
2625 /* deal with the selection of the system font */
2626 { GtkWidget *box, *tmp, *w, *fsdial;
2627 if ( mfontwindow ) { gtk_widget_destroy(mfontwindow); }
2628 mfontwindow = gtk_window_new(GTK_WINDOW_DIALOG);
2629 gtk_window_set_title(GTK_WINDOW(mfontwindow),"Main font selection");
2630 box = gtk_vbox_new(0,dialog_vert_spacing);
2631 gtk_widget_show(box);
2632 gtk_container_add(GTK_CONTAINER(mfontwindow),box);
2633 mfont_selector = fsdial = gtk_font_selection_new();
2634 gtk_widget_show(fsdial);
2635 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsdial),
2636 "I hope you're enjoying the game");
2637 gtk_box_pack_start(GTK_BOX(box),fsdial,0,0,0);
2638 tmp = gtk_hbox_new(1,dialog_button_spacing);
2639 gtk_widget_show(tmp);
2640 gtk_box_pack_start(GTK_BOX(box),tmp,0,0,0);
2641
2642 w = gtk_button_new_with_label("Select");
2643 gtk_widget_show(w);
2644 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2645 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(mfontsel_callback),(gpointer) 0);
2646
2647 w = gtk_button_new_with_label("Use default");
2648 gtk_widget_show(w);
2649 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2650 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(mfontsel_callback),(gpointer) 1);
2651
2652 w = gtk_button_new_with_label("Cancel");
2653 gtk_widget_show(w);
2654 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2655 gtk_signal_connect_object(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(mfontwindow));
2656 }
2657
2658 w1 = gtk_button_new_with_label("Main font selection...");
2659 gtk_widget_show(w1);
2660 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
2661 gtk_signal_connect_object(GTK_OBJECT(w1),"clicked",GTK_SIGNAL_FUNC(showraise),GTK_OBJECT(mfontwindow));
2662
2663 /* deal with the selection of the text font */
2664 { GtkWidget *box, *tmp, *w, *fsdial;
2665 if ( tfontwindow ) { gtk_widget_destroy(tfontwindow); }
2666 tfontwindow = gtk_window_new(GTK_WINDOW_DIALOG);
2667 gtk_window_set_title(GTK_WINDOW(tfontwindow),"Text font selection");
2668 box = gtk_vbox_new(0,dialog_vert_spacing);
2669 gtk_widget_show(box);
2670 gtk_container_add(GTK_CONTAINER(tfontwindow),box);
2671 tfont_selector = fsdial = gtk_font_selection_new();
2672 gtk_widget_show(fsdial);
2673 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsdial),
2674 "I hope you're enjoying the game");
2675 gtk_box_pack_start(GTK_BOX(box),fsdial,0,0,0);
2676 tmp = gtk_hbox_new(1,dialog_button_spacing);
2677 gtk_widget_show(tmp);
2678 gtk_box_pack_start(GTK_BOX(box),tmp,0,0,0);
2679
2680 w = gtk_button_new_with_label("Select");
2681 gtk_widget_show(w);
2682 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2683 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(tfontsel_callback),(gpointer) 0);
2684
2685 w = gtk_button_new_with_label("Use default");
2686 gtk_widget_show(w);
2687 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2688 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(tfontsel_callback),(gpointer) 1);
2689
2690 w = gtk_button_new_with_label("Cancel");
2691 gtk_widget_show(w);
2692 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2693 gtk_signal_connect_object(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(tfontwindow));
2694 }
2695
2696 w1 = gtk_button_new_with_label("Text font selection...");
2697 gtk_widget_show(w1);
2698 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
2699 gtk_signal_connect_object(GTK_OBJECT(w1),"clicked",GTK_SIGNAL_FUNC(showraise),GTK_OBJECT(tfontwindow));
2700
2701 /* deal with selection of table colour */
2702 { GtkWidget *box, *tmp, *w, *csdial;
2703 if ( tcolwindow ) { gtk_widget_destroy(tcolwindow); }
2704 tcolwindow = gtk_window_new(GTK_WINDOW_DIALOG);
2705 gtk_window_set_title(GTK_WINDOW(tcolwindow),"Table colour selection");
2706 box = gtk_vbox_new(0,dialog_vert_spacing);
2707 gtk_widget_show(box);
2708 gtk_container_add(GTK_CONTAINER(tcolwindow),box);
2709 tcolor_selector = csdial = gtk_color_selection_new();
2710 gtk_widget_show(csdial);
2711 gtk_box_pack_start(GTK_BOX(box),csdial,0,0,0);
2712 tmp = gtk_hbox_new(1,dialog_button_spacing);
2713 gtk_widget_show(tmp);
2714 gtk_box_pack_start(GTK_BOX(box),tmp,0,0,0);
2715
2716 w = gtk_button_new_with_label("Select");
2717 gtk_widget_show(w);
2718 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2719 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(tcolsel_callback),(gpointer) 0);
2720
2721 w = gtk_button_new_with_label("Use default");
2722 gtk_widget_show(w);
2723 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2724 gtk_signal_connect(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(tcolsel_callback),(gpointer) 1);
2725
2726 w = gtk_button_new_with_label("Cancel");
2727 gtk_widget_show(w);
2728 gtk_box_pack_start(GTK_BOX(tmp),w,1,1,0);
2729 gtk_signal_connect_object(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(tcolwindow));
2730 }
2731
2732
2733 w1 = gtk_button_new_with_label("Table colour selection...");
2734 gtk_widget_show(w1);
2735 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
2736 gtk_signal_connect_object(GTK_OBJECT(w1),"clicked",GTK_SIGNAL_FUNC(showraise),GTK_OBJECT(tcolwindow));
2737
2738 #ifdef GTK2
2739 /* gtk2rcfile */
2740 bbox = gtk_hbox_new(0,0);
2741 gtk_widget_show(bbox);
2742 gtk_box_pack_start(GTK_BOX(box),bbox,0,0,0);
2743
2744 w1 = gtk_label_new("Gtk2 Rcfile: ");
2745 gtk_widget_show(w1);
2746 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2747
2748 display_option_dialog_gtk2_rcfile = w1 = gtk_entry_new();
2749 gtk_widget_show(w1);
2750 gtk_box_pack_start(GTK_BOX(bbox),w1,0,0,0);
2751
2752 /* use_system_gtkrc */
2753 display_option_dialog_use_system_gtkrc = but1 =
2754 gtk_check_button_new_with_label("Use system gtkrc");
2755 gtk_widget_show(but1);
2756 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
2757
2758 #endif
2759
2760 /* apply, save and close buttons */
2761 w1 = gtk_hbox_new(1,dialog_button_spacing);
2762 gtk_widget_show(w1);
2763 gtk_box_pack_end(GTK_BOX(box),w1,0,0,0);
2764
2765 w2 = gtk_button_new_with_label("Save & Apply");
2766 gtk_widget_show(w2);
2767 gtk_box_pack_start(GTK_BOX(w1),w2,1,1,0);
2768 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(display_option_dialog_save),NULL);
2769
2770 w2 = gtk_button_new_with_label("Apply (no save)");
2771 gtk_widget_show(w2);
2772 gtk_box_pack_start(GTK_BOX(w1),w2,1,1,0);
2773 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(display_option_dialog_apply),NULL);
2774
2775 w2 = gtk_button_new_with_label("Cancel");
2776 gtk_widget_show(w2);
2777 gtk_box_pack_start(GTK_BOX(w1),w2,1,1,0);
2778 gtk_signal_connect_object(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(display_option_dialog));
2779 }
2780
2781 static char old_main_font_name[256];
2782 static char old_text_font_name[256];
2783 static char old_table_colour_name[256];
2784
2785 /* make the panel match reality */
display_option_dialog_refresh(void)2786 static void display_option_dialog_refresh(void) {
2787 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_dialogposn[dialogs_position]),1);
2788 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_animation),animate);
2789 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_nopopups),nopopups);
2790 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_info_in_main),info_windows_in_main);
2791 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_tiletips),tiletips);
2792 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_rotatelabels),rotatelabels);
2793 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_thinking_claim),thinking_claim);
2794 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_alert_mahjong),alert_mahjong);
2795 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_showwall[pref_showwall == -1 ? 2 : pref_showwall]),1);
2796 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_sort_tiles[sort_tiles]),1);
2797 if ( display_size == 0 ) {
2798 gtk_entry_set_text(GTK_ENTRY(display_option_size_entry),"(auto)");
2799 } else {
2800 char buf[5];
2801 sprintf(buf,"%d",display_size);
2802 gtk_entry_set_text(GTK_ENTRY(display_option_size_entry),buf);
2803 }
2804 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_iconify),iconify_dialogs_with_main);
2805 gtk_entry_set_text(GTK_ENTRY(display_option_dialog_tileset),
2806 tileset ? tileset : "");
2807 #ifdef GTK2
2808 gtk_entry_set_text(GTK_ENTRY(display_option_dialog_gtk2_rcfile),
2809 gtk2_rcfile);
2810 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_option_dialog_use_system_gtkrc),use_system_gtkrc);
2811 #endif
2812 gtk_entry_set_text(GTK_ENTRY(display_option_dialog_tileset_path),
2813 tileset_path ? tileset_path : "");
2814 strmcpy(old_main_font_name,main_font_name,256);
2815 if ( main_font_name[0] ) {
2816 gtk_font_selection_set_font_name(GTK_FONT_SELECTION(mfont_selector),
2817 main_font_name);
2818 }
2819 strmcpy(old_text_font_name,text_font_name,256);
2820 if ( text_font_name[0] ) {
2821 gtk_font_selection_set_font_name(GTK_FONT_SELECTION(tfont_selector),
2822 text_font_name);
2823 } else if ( fallback_text_font_name[0] ) {
2824 gtk_font_selection_set_font_name(GTK_FONT_SELECTION(tfont_selector),
2825 fallback_text_font_name);
2826 }
2827 strmcpy(old_table_colour_name,table_colour_name,256);
2828 }
2829
2830 /* apply the selected options */
display_option_dialog_apply(void)2831 static void display_option_dialog_apply(void) {
2832 int i;
2833 unsigned int newdp = dialogs_position;
2834 int old;
2835 char *newt;
2836 GtkWidget *wwindow;
2837 int restart = 0; /* set to 1 if we need to recreate the display */
2838
2839 /* if we produce any warnings now, and then restart, they won't be seen
2840 in the gui, since the warning window will be destroyed.
2841 So disable the warning window, and reinstate it later */
2842 wwindow = warningwindow;
2843 warningwindow = NULL;
2844
2845 for (i=DialogsCentral; i <= DialogsPopup; i++) {
2846 if ( GTK_TOGGLE_BUTTON(display_option_dialog_dialogposn[i])->active )
2847 newdp = i;
2848 }
2849 if ( newdp != dialogs_position ) restart = 1;
2850 dialogs_position = newdp;
2851 set_animation(GTK_TOGGLE_BUTTON(display_option_dialog_animation)->active);
2852 old = info_windows_in_main;
2853 info_windows_in_main = GTK_TOGGLE_BUTTON(display_option_dialog_info_in_main)->active;
2854 if ( old != info_windows_in_main ) restart = 1;
2855 nopopups = GTK_TOGGLE_BUTTON(display_option_dialog_nopopups)->active;
2856 tiletips = GTK_TOGGLE_BUTTON(display_option_dialog_tiletips)->active;
2857 int old_rotatelabels = rotatelabels;
2858 rotatelabels = GTK_TOGGLE_BUTTON(display_option_dialog_rotatelabels)->active;
2859 if ( old_rotatelabels != rotatelabels ) {
2860 gtk_label_set_angle(pdisps[3].infolab, rotatelabels ? 270 : 0);
2861 gtk_label_set_angle(pdisps[1].infolab, rotatelabels ? 90 : 0);
2862 }
2863 thinking_claim = GTK_TOGGLE_BUTTON(display_option_dialog_thinking_claim)->active;
2864 alert_mahjong = GTK_TOGGLE_BUTTON(display_option_dialog_alert_mahjong)->active;
2865 iconify_dialogs_with_main = GTK_TOGGLE_BUTTON(display_option_dialog_iconify)->active;
2866 i =
2867 (GTK_TOGGLE_BUTTON(display_option_dialog_showwall[0])->active ? 0 :
2868 GTK_TOGGLE_BUTTON(display_option_dialog_showwall[1])->active ? 1 : -1 );
2869 if ( pref_showwall != i ) {
2870 restart = 1;
2871 showwall = pref_showwall = i;
2872 }
2873 for (i=0;i<3
2874 && !GTK_TOGGLE_BUTTON(display_option_dialog_sort_tiles[i])->active;
2875 i++);
2876 if ( i < 3 ) sort_tiles = i;
2877 old = display_size;
2878 newt = (char *)gtk_entry_get_text(GTK_ENTRY(display_option_size_entry));
2879 if ( strcmp(newt,"(auto)") == 0 ) {
2880 display_size = 0;
2881 } else {
2882 sscanf(newt,"%d",&display_size);
2883 }
2884 if ( display_size != old ) restart = 1;
2885 newt = (char *)gtk_entry_get_text(GTK_ENTRY(display_option_dialog_tileset));
2886 if ( ! tileset ) tileset = "";
2887 if ( strcmp(newt,tileset) != 0 ) {
2888 restart = 1;
2889 tileset = newt;
2890 }
2891 newt = (char *)gtk_entry_get_text(GTK_ENTRY(display_option_dialog_tileset_path));
2892 if ( ! tileset_path ) tileset_path = "";
2893 if ( strcmp(newt,tileset_path) != 0 ) {
2894 restart = 1;
2895 tileset_path = newt;
2896 }
2897 #ifdef GTK2
2898 newt = (char *)gtk_entry_get_text(GTK_ENTRY(display_option_dialog_gtk2_rcfile));
2899 if ( strcmp(newt,gtk2_rcfile) != 0 ) {
2900 /* we can't restart for this one */
2901 error_dialog_popup("Restart xmj for gtk2_rcfile change to take effect");
2902 strmcpy(gtk2_rcfile,newt,sizeof(gtk2_rcfile));
2903 }
2904 old = use_system_gtkrc;
2905 use_system_gtkrc = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(display_option_dialog_use_system_gtkrc));
2906 if ( old != use_system_gtkrc ) {
2907 /* we can't restart for this one */
2908 error_dialog_popup("Restart xmj for use_system_gtkrc change to take effect");
2909 }
2910 #endif
2911 if ( strncmp(old_main_font_name,main_font_name,256) != 0 ) {
2912 #ifdef GTK2
2913 char c[300];
2914 strcpy(c,"gtk-font-name = \"");
2915 char *d = c + strlen(c);
2916 strmcpy(d,main_font_name,256);
2917 strcat(c,"\"");
2918 gtk_rc_parse_string(c);
2919 gtk_rc_reset_styles(gtk_settings_get_default());
2920 #else
2921 restart = 1;
2922 #endif
2923 }
2924 if ( strncmp(old_text_font_name,text_font_name,256) != 0 ) {
2925 #ifdef GTK2
2926 char c[300];
2927 strcpy(c,"style \"text\" { font_name = \"");
2928 char *d = c + strlen(c);
2929 strmcpy(d,text_font_name,256);
2930 strcat(c,"\" }");
2931 gtk_rc_parse_string(c);
2932 gtk_rc_reset_styles(gtk_settings_get_default());
2933 #else
2934 restart = 1;
2935 #endif
2936 }
2937 if ( strncmp(old_table_colour_name,table_colour_name,256) != 0 ) {
2938 #ifdef GTK2
2939 char c[300];
2940 strcpy(c,"style \"table\" { bg[NORMAL] = \"");
2941 char *d = c + strlen(c);
2942 strmcpy(d,table_colour_name,256);
2943 strcat(c,"\" }");
2944 gtk_rc_parse_string(c);
2945 gtk_rc_reset_styles(gtk_settings_get_default());
2946 #else
2947 restart = 1;
2948 #endif
2949 }
2950 close_saving_posn(display_option_dialog);
2951 if ( restart ) {
2952 /* need to destroy the warning window ourselves, since
2953 we've nulled it */
2954 if ( wwindow ) gtk_widget_destroy(wwindow);
2955 destroy_display();
2956 create_display();
2957 } else {
2958 /* re-instate warnings */
2959 warningwindow = wwindow;
2960 log_msg_add(0,NULL);
2961 }
2962 }
2963
2964 /* save options */
display_option_dialog_save(void)2965 static void display_option_dialog_save(void) {
2966 /* first apply */
2967 display_option_dialog_apply();
2968 /* then save */
2969 if ( read_or_update_rcfile(NULL,XmjrcNone,XmjrcDisplay) == 0 ) {
2970 error_dialog_popup("Error updating rc file");
2971 }
2972 }
2973
2974 /* various widgets needed in the playing prefs dialog */
2975 static GtkWidget *playing_prefs_auto_specials;
2976 static GtkWidget *playing_prefs_auto_losing;
2977 static GtkWidget *playing_prefs_auto_winning;
2978
2979 static void playing_prefs_dialog_apply(void);
2980 static void playing_prefs_dialog_save(void);
2981 static void playing_prefs_dialog_refresh(void);
2982
2983 /* dialog for specifying playing preferences */
playing_prefs_dialog_init(void)2984 static void playing_prefs_dialog_init(void) {
2985 GtkWidget *box, *but1, *w1, *w2;
2986
2987 playing_prefs_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
2988 gtk_signal_connect (GTK_OBJECT (playing_prefs_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
2989 gtk_container_set_border_width(GTK_CONTAINER(playing_prefs_dialog),
2990 dialog_border_width);
2991
2992 box = gtk_vbox_new(0,dialog_vert_spacing);
2993 gtk_widget_show(box);
2994 gtk_container_add(GTK_CONTAINER(playing_prefs_dialog),box);
2995
2996 w1 = gtk_label_new("Automatic declarations:");
2997 gtk_widget_show(w1);
2998 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
2999
3000 /* declaring specials */
3001 playing_prefs_auto_specials = but1 =
3002 gtk_check_button_new_with_label("flowers and seasons");
3003 gtk_widget_show(but1);
3004 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
3005
3006 /* declaring losing hands */
3007 playing_prefs_auto_losing = but1 =
3008 gtk_check_button_new_with_label("losing hands");
3009 gtk_widget_show(but1);
3010 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
3011
3012 /* declaring winning hands */
3013 playing_prefs_auto_winning = but1 =
3014 gtk_check_button_new_with_label("winning hands");
3015 gtk_widget_show(but1);
3016 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
3017
3018 /* apply, save and close buttons */
3019 w1 = gtk_hbox_new(0,dialog_button_spacing);
3020 gtk_widget_show(w1);
3021 gtk_box_pack_end(GTK_BOX(box),w1,0,0,0);
3022
3023 w2 = gtk_button_new_with_label("Save & Apply");
3024 gtk_widget_show(w2);
3025 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3026 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(playing_prefs_dialog_save),NULL);
3027
3028 w2 = gtk_button_new_with_label("Apply (no save)");
3029 gtk_widget_show(w2);
3030 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3031 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(playing_prefs_dialog_apply),NULL);
3032
3033 w2 = gtk_button_new_with_label("Cancel");
3034 gtk_widget_show(w2);
3035 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3036 gtk_signal_connect_object(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(playing_prefs_dialog));
3037 }
3038
3039 /* make the playing prefs panel match reality */
playing_prefs_dialog_refresh(void)3040 static void playing_prefs_dialog_refresh(void) {
3041 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playing_prefs_auto_specials),
3042 playing_auto_declare_specials);
3043 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playing_prefs_auto_losing),
3044 playing_auto_declare_losing);
3045 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playing_prefs_auto_winning),
3046 playing_auto_declare_winning);
3047
3048 gtk_widget_hide(playing_prefs_dialog);
3049 }
3050
3051 /* apply the selected playing options */
playing_prefs_dialog_apply(void)3052 static void playing_prefs_dialog_apply(void) {
3053 playing_auto_declare_specials = GTK_TOGGLE_BUTTON(playing_prefs_auto_specials)->active;
3054 playing_auto_declare_losing = GTK_TOGGLE_BUTTON(playing_prefs_auto_losing)->active;
3055 playing_auto_declare_winning = GTK_TOGGLE_BUTTON(playing_prefs_auto_winning)->active;
3056 gtk_widget_hide(playing_prefs_dialog);
3057 }
3058
3059 /* save playing options */
playing_prefs_dialog_save(void)3060 static void playing_prefs_dialog_save(void) {
3061 /* first apply */
3062 playing_prefs_dialog_apply();
3063 /* then save */
3064 if ( read_or_update_rcfile(NULL,XmjrcNone,XmjrcPlaying) == 0 ) {
3065 error_dialog_popup("Error updating rc file");
3066 }
3067 }
3068
3069 /* debug options dialog */
3070
3071 static void debug_options_dialog_apply(void);
3072 static void debug_options_dialog_save(void);
3073 static void debug_options_dialog_refresh(void);
3074
3075 static GtkWidget *debug_options_report_buttons[DebugReportsAlways+1];
3076
3077 static void debug_options_dialog_init(void);
3078
debug_report_query_popup(void)3079 static void debug_report_query_popup(void) {
3080 if ( ! debug_options_dialog ) debug_options_dialog_init();
3081 dialog_popup(debug_options_reporting,DPCentred);
3082 }
3083
debug_options_dialog_init(void)3084 static void debug_options_dialog_init(void) {
3085 GtkWidget *box, *but0, *but1, *but2, *but3, *w1, *w2;
3086
3087 debug_options_dialog = gtk_window_new(GTK_WINDOW_DIALOG);
3088 gtk_signal_connect (GTK_OBJECT (debug_options_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
3089 gtk_container_set_border_width(GTK_CONTAINER(debug_options_dialog),
3090 dialog_border_width);
3091
3092 box = gtk_vbox_new(0,dialog_vert_spacing);
3093 gtk_widget_show(box);
3094 gtk_container_add(GTK_CONTAINER(debug_options_dialog),box);
3095 w1 = gtk_label_new("Fault reporting:\n"
3096 "When certain internal errors occur, this program\n"
3097 "can file a debugging report over the Internet to the author.\n"
3098 "This report includes the current game status; it may include\n"
3099 "the entire game history. Therefore the report may contain\n"
3100 "sensitive information such as your username and password for the\n"
3101 "www.TUMJ.com game server.\n"
3102 "When may a debugging report be sent over the Internet?");
3103 gtk_widget_show(w1);
3104 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
3105
3106 but0 = gtk_radio_button_new_with_label(NULL,"unspecified");
3107 /* gtk_widget_show(but0); */
3108 gtk_box_pack_start(GTK_BOX(box),but0,0,0,0);
3109 debug_options_report_buttons[DebugReportsUnspecified] = but0;
3110
3111 but1 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but0)),"never");
3112 gtk_widget_show(but1);
3113 gtk_box_pack_start(GTK_BOX(box),but1,0,0,0);
3114 debug_options_report_buttons[DebugReportsNever] = but1;
3115
3116 but2 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but0)),"ask each time");
3117 gtk_widget_show(but2);
3118 gtk_box_pack_start(GTK_BOX(box),but2,0,0,0);
3119 debug_options_report_buttons[DebugReportsAsk] = but2;
3120
3121 but3 = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(but0)),"always");
3122 gtk_widget_show(but3);
3123 gtk_box_pack_start(GTK_BOX(box),but3,0,0,0);
3124 debug_options_report_buttons[DebugReportsAlways] = but3;
3125
3126 /* apply, save and close buttons */
3127 w1 = gtk_hbox_new(0,dialog_button_spacing);
3128 gtk_widget_show(w1);
3129 gtk_box_pack_end(GTK_BOX(box),w1,0,0,0);
3130
3131 w2 = gtk_button_new_with_label("Save & Apply");
3132 gtk_widget_show(w2);
3133 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3134 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(debug_options_dialog_save),NULL);
3135
3136 w2 = gtk_button_new_with_label("Apply (no save)");
3137 gtk_widget_show(w2);
3138 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3139 gtk_signal_connect(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(debug_options_dialog_apply),NULL);
3140
3141 w2 = gtk_button_new_with_label("Cancel");
3142 gtk_widget_show(w2);
3143 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3144 gtk_signal_connect_object(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(gtk_widget_hide),GTK_OBJECT(debug_options_dialog));
3145
3146
3147 /* Now create the dialog that is popped up each time (if necessary)
3148 to ask whether to file a report */
3149 if ( debug_options_reporting ) {
3150 gtk_widget_destroy(debug_options_reporting);
3151 }
3152
3153 debug_options_reporting = gtk_window_new(GTK_WINDOW_DIALOG);
3154 gtk_signal_connect (GTK_OBJECT (debug_options_reporting), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
3155 gtk_container_set_border_width(GTK_CONTAINER(debug_options_reporting),
3156 dialog_border_width);
3157
3158 box = gtk_vbox_new(0,dialog_vert_spacing);
3159 gtk_widget_show(box);
3160 gtk_container_add(GTK_CONTAINER(debug_options_reporting),box);
3161 w1 = gtk_label_new("This program has encountered an unexpected error.\n"
3162 "It can file a debugging report over the Internet to the author.\n"
3163 "This report includes the current game status; it may include\n"
3164 "the entire game history. Therefore the report may contain\n"
3165 "sensitive information such as your username and password for the\n"
3166 "www.TUMJ.com game server.\n"
3167 "May the report be sent?");
3168 gtk_widget_show(w1);
3169 gtk_box_pack_start(GTK_BOX(box),w1,0,0,0);
3170
3171 w1 = gtk_hbox_new(0,dialog_button_spacing);
3172 gtk_widget_show(w1);
3173 gtk_box_pack_end(GTK_BOX(box),w1,0,0,0);
3174
3175 w2 = gtk_button_new_with_label("Send report");
3176 gtk_widget_show(w2);
3177 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3178 gtk_signal_connect_object(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(file_report),(gpointer)1);
3179
3180 w2 = gtk_button_new_with_label("Cancel");
3181 gtk_widget_show(w2);
3182 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3183 gtk_signal_connect_object(GTK_OBJECT(w2),"clicked",GTK_SIGNAL_FUNC(file_report),NULL);
3184
3185 }
3186
debug_options_dialog_refresh(void)3187 static void debug_options_dialog_refresh(void) {
3188 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(debug_options_report_buttons[debug_reports]),1);
3189 }
3190
debug_options_dialog_apply(void)3191 static void debug_options_dialog_apply(void) {
3192 int i;
3193 for ( i=DebugReportsNever; i <= DebugReportsAlways; i++ ) {
3194 if ( GTK_TOGGLE_BUTTON(debug_options_report_buttons[i])->active )
3195 debug_reports = i;
3196 }
3197 gtk_widget_hide(debug_options_dialog);
3198 }
3199
debug_options_dialog_save(void)3200 static void debug_options_dialog_save(void) {
3201 /* first apply */
3202 debug_options_dialog_apply();
3203 /* then save */
3204 if ( read_or_update_rcfile(NULL,XmjrcNone,XmjrcMisc) == 0 ) {
3205 error_dialog_popup("Error updating rc file");
3206 }
3207 }
3208
3209
3210
3211 /* callback used below */
enabler_callback(GtkWidget * w UNUSED,gpointer data)3212 static void enabler_callback(GtkWidget *w UNUSED, gpointer data)
3213 {
3214 GameOptionEntry *goe = data;
3215 goe->enabled = ! goe->enabled;
3216 make_or_refresh_option_updater(goe,0);
3217 }
3218
3219 /* ditto */
make_sensitive(GtkWidget * w)3220 static void make_sensitive(GtkWidget *w)
3221 {
3222 gtk_widget_set_sensitive(w,1);
3223 }
3224
3225 /* given a GameOptionEntry, create
3226 or refresh an updater widget, stored in the userdata
3227 field of the entry.
3228 Second arg says if this is preference panel (or option panel)
3229 */
make_or_refresh_option_updater(GameOptionEntry * goe,int prefsp)3230 GtkWidget *make_or_refresh_option_updater(GameOptionEntry *goe,int prefsp)
3231 {
3232 /* description of option
3233 current value new value update
3234 */
3235 GtkWidget *vbox = NULL, *hbox = NULL, *ohbox, *w1 = NULL, *w2,
3236 *old, *lim, *halflim, *nolim, *resetter;
3237 GtkAdjustment *adj;
3238 int dbls, pts;
3239 int centilims;
3240
3241 old = goe->userdata;
3242 if ( ! old ) {
3243 resetter = gtk_button_new_with_label("Reset"); /* needed early */
3244 } else {
3245 resetter = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(old),"reset");
3246 }
3247 if ( ! old ) {
3248 vbox = gtk_vbox_new(0,5);
3249 gtk_widget_show(vbox);
3250 if ( prefsp ) {
3251 w2 = gtk_hbox_new(0,5);
3252 gtk_widget_show(w2);
3253 gtk_box_pack_start(GTK_BOX(vbox),w2,0,0,0);
3254 w1 = gtk_button_new_with_label("Add pref");
3255 GTK_WIDGET_UNSET_FLAGS(w1,GTK_CAN_FOCUS);
3256 gtk_object_set_data(GTK_OBJECT(vbox),"enabled",(gpointer) w1);
3257 gtk_signal_connect(GTK_OBJECT(w1),"clicked",GTK_SIGNAL_FUNC(enabler_callback),(gpointer) goe);
3258 gtk_widget_show(w1);
3259 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
3260 w1 = gtk_label_new(goe->desc);
3261 gtk_widget_show(w1);
3262 gtk_box_pack_start(GTK_BOX(w2),w1,0,0,0);
3263 } else {
3264 w1 = gtk_label_new(goe->desc);
3265 gtk_widget_show(w1);
3266 gtk_box_pack_start(GTK_BOX(vbox),w1,0,0,0);
3267 }
3268 if ( prefsp ) {
3269 ohbox = gtk_hbox_new(0,0);
3270 gtk_widget_show(ohbox);
3271 gtk_box_pack_start(GTK_BOX(vbox),ohbox,0,0,0);
3272 hbox = gtk_hbox_new(0,0);
3273 gtk_object_set_data(GTK_OBJECT(vbox),"hbox",(gpointer) hbox);
3274 gtk_widget_show(hbox);
3275 gtk_box_pack_start(GTK_BOX(ohbox),hbox,1,1,0);
3276 } else {
3277 hbox = gtk_hbox_new(0,0);
3278 gtk_widget_show(hbox);
3279 gtk_box_pack_start(GTK_BOX(vbox),hbox,0,0,0);
3280 }
3281 } else {
3282 vbox = old;
3283 }
3284 switch ( goe->type ) {
3285 case GOTBool:
3286 if ( ! old ) {
3287 w1 = gtk_hbox_new(0,0);
3288 gtk_widget_show(w1);
3289 gtk_box_pack_start(GTK_BOX(hbox),w1,0,0,5);
3290 w2 = gtk_check_button_new_with_label("on/off");
3291 gtk_signal_connect_object(GTK_OBJECT(w2),"toggled",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3292 gtk_widget_show(w2);
3293 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3294 gtk_object_set_data(GTK_OBJECT(vbox),"checkbox",w2);
3295 } else {
3296 w2 = gtk_object_get_data(GTK_OBJECT(vbox),"checkbox");
3297 }
3298 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w2),
3299 goe->value.optbool);
3300 break;
3301 case GOTNat:
3302 case GOTInt:
3303 if ( ! old ) {
3304 w1 = gtk_hbox_new(0,0);
3305 gtk_widget_show(w1);
3306 gtk_box_pack_start(GTK_BOX(hbox),w1,0,0,5);
3307 adj = (GtkAdjustment *)gtk_adjustment_new(goe->value.optint,
3308 (goe->type == GOTNat ) ? 0 : -1000000,1000000,
3309 1,10,0);
3310 w2 = gtk_spin_button_new(adj,1.0,0);
3311 gtk_widget_set_usize(w2,70,0);
3312 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(w2),1);
3313 gtk_signal_connect_object(GTK_OBJECT(w2),"changed",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3314 gtk_widget_show(w2);
3315 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3316 gtk_object_set_data(GTK_OBJECT(vbox),"spinbutton",w2);
3317 } else {
3318 w2 = gtk_object_get_data(GTK_OBJECT(vbox),"spinbutton");
3319 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w2),goe->value.optint);
3320 }
3321 break;
3322 case GOTString:
3323 if ( ! old ) {
3324 w1 = gtk_hbox_new(0,0);
3325 gtk_widget_show(w1);
3326 gtk_box_pack_start(GTK_BOX(hbox),w1,0,0,5);
3327 w2 = gtk_entry_new();
3328 gtk_signal_connect_object(GTK_OBJECT(w2),"changed",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3329 gtk_widget_show(w2);
3330 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3331 gtk_object_set_data(GTK_OBJECT(vbox),"entry",w2);
3332 } else {
3333 w2 = gtk_object_get_data(GTK_OBJECT(vbox),"entry");
3334 }
3335 gtk_entry_set_text(GTK_ENTRY(w2),goe->value.optstring);
3336 break;
3337 case GOTScore:
3338 pts = goe->value.optscore % 10000;
3339 dbls = (goe->value.optscore / 10000) % 100;
3340 centilims = goe->value.optscore/1000000;
3341 if ( ! old ) {
3342 w1 = gtk_hbox_new(0,0);
3343 gtk_widget_show(w1);
3344 gtk_box_pack_start(GTK_BOX(hbox),w1,0,0,5);
3345 lim = w2 = gtk_radio_button_new_with_label(NULL,"lim");
3346 gtk_signal_connect_object(GTK_OBJECT(w2),"toggled",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3347 gtk_widget_show(w2);
3348 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3349 gtk_object_set_data(GTK_OBJECT(vbox),"lim",w2);
3350 halflim = w2 = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON(lim)),"1/2 lim");
3351 gtk_signal_connect_object(GTK_OBJECT(w2),"toggled",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3352 gtk_widget_show(w2);
3353 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3354 gtk_object_set_data(GTK_OBJECT(vbox),"halflim",w2);
3355 nolim = w2 = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON(lim)),"");
3356 gtk_signal_connect_object(GTK_OBJECT(w2),"toggled",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3357 gtk_widget_show(w2);
3358 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3359 gtk_object_set_data(GTK_OBJECT(vbox),"nolim",w2);
3360 } else {
3361 lim = gtk_object_get_data(GTK_OBJECT(vbox),"lim");
3362 halflim = gtk_object_get_data(GTK_OBJECT(vbox),"halflim");
3363 nolim = gtk_object_get_data(GTK_OBJECT(vbox),"nolim");
3364 }
3365 switch ( centilims ) {
3366 case 100:
3367 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lim),1);
3368 break;
3369 case 50:
3370 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(halflim),1);
3371 break;
3372 case 0:
3373 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(nolim),1);
3374 break;
3375 default:
3376 warn("Unexpected fraction (%d) of a limit in score; setting to limit",
3377 centilims);
3378 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lim),1);
3379 break;
3380 }
3381
3382 if ( ! old ) {
3383 adj = (GtkAdjustment *)gtk_adjustment_new(dbls,
3384 0,100,
3385 1,10,0);
3386 w2 = gtk_spin_button_new(adj,1.0,0);
3387 gtk_widget_set_usize(w2,40,0);
3388 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(w2),1);
3389 gtk_signal_connect_object(GTK_OBJECT(w2),"changed",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3390 gtk_widget_show(w2);
3391 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3392 gtk_object_set_data(GTK_OBJECT(vbox),"dbls",w2);
3393 w2 = gtk_label_new("dbls");
3394 gtk_widget_show(w2);
3395 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3396 } else {
3397 w2 = gtk_object_get_data(GTK_OBJECT(vbox),"dbls");
3398 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w2),dbls);
3399 }
3400
3401 if ( ! old ) {
3402 adj = (GtkAdjustment *)gtk_adjustment_new(pts,
3403 0,10000,
3404 1,10,0);
3405 w2 = gtk_spin_button_new(adj,1.0,0);
3406 gtk_widget_set_usize(w2,60,0);
3407 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(w2),1);
3408 gtk_signal_connect_object(GTK_OBJECT(w2),"changed",GTK_SIGNAL_FUNC(make_sensitive),GTK_OBJECT(resetter));
3409 gtk_widget_show(w2);
3410 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,5);
3411 gtk_object_set_data(GTK_OBJECT(vbox),"pts",w2);
3412 w2 = gtk_label_new("pts");
3413 gtk_widget_show(w2);
3414 gtk_box_pack_start(GTK_BOX(w1),w2,0,0,0);
3415 } else {
3416 w2 = gtk_object_get_data(GTK_OBJECT(vbox),"pts");
3417 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w2),pts);
3418 }
3419 break;
3420 }
3421 if ( ! old ) {
3422 /* The button is created at the top so we can feed it to callbacks *
3423 w1 = gtk_button_new_with_label("Reset");
3424 */
3425 w1 = resetter;
3426 gtk_widget_show(w1);
3427 gtk_box_pack_end(GTK_BOX(hbox),w1,0,0,5);
3428 gtk_object_set_data(GTK_OBJECT(vbox),"reset",w1);
3429 gtk_signal_connect(GTK_OBJECT(w1),"clicked",GTK_SIGNAL_FUNC(option_reset_callback),
3430 (gpointer) goe);
3431 }
3432 if ( ! old ) goe->userdata = vbox;
3433 /* If there's an enabled button, deal with it */
3434 w1 = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(vbox),"enabled");
3435 if ( w1 ) {
3436 hbox = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(vbox),"hbox");
3437 if ( goe->enabled ) {
3438 gtk_widget_show(hbox);
3439 gtk_label_set_text(GTK_LABEL(GTK_BIN(w1)->child),"Remove pref");
3440 } else {
3441 gtk_widget_hide(hbox);
3442 gtk_label_set_text(GTK_LABEL(GTK_BIN(w1)->child),"Add pref");
3443 }
3444 }
3445 /* make the reset button insensitive */
3446 gtk_widget_set_sensitive(resetter,0);
3447 return vbox;
3448 }
3449
3450 /* given an optiontable, pack a list of updating widgets into
3451 a vbox; or just refresh if already there (2nd arg)
3452 If third arg is 1, this is prefs panel, else options panel
3453 */
build_or_refresh_optionprefs_panel(GameOptionTable * got,GtkWidget * panel,int prefsp)3454 static GtkWidget *build_or_refresh_optionprefs_panel(GameOptionTable *got, GtkWidget *panel, int prefsp)
3455 {
3456 int i;
3457 GtkWidget *vbox,*hs,*u;
3458 int first = 1;
3459
3460 if ( ! got ) {
3461 /* destroy the panel's children, if any */
3462 if ( panel ) {
3463 gtk_container_foreach(GTK_CONTAINER(panel),(GtkCallback) gtk_widget_destroy,NULL);
3464 }
3465 }
3466
3467 if ( ! panel ) {
3468 vbox = gtk_vbox_new(0,0);
3469 gtk_widget_show(vbox);
3470 } else {
3471 vbox = panel;
3472 }
3473 for ( i = 0 ; got && i < got->numoptions; i++ ) {
3474 /* if this is actually a filler unknown option, skip it */
3475 if ( got->options[i].name[0] == 0 ) continue;
3476 /* likewise for end */
3477 if ( got->options[i].option == GOEnd ) continue;
3478 /* if this is the options panel, and the option is not enabled, skip */
3479 if ( ! prefsp && ! got->options[i].enabled ) continue;
3480 u = got->options[i].userdata;
3481 if ( ! first && u == NULL ) {
3482 hs = gtk_hseparator_new();
3483 gtk_widget_show(hs);
3484 gtk_box_pack_start(GTK_BOX(vbox),hs,0,0,0);
3485 } else first = 0;
3486 if ( u ) {
3487 make_or_refresh_option_updater(&got->options[i],prefsp);
3488 } else {
3489 u = make_or_refresh_option_updater(&got->options[i],prefsp);
3490 gtk_box_pack_start(GTK_BOX(vbox),u,0,0,5);
3491 }
3492 }
3493 return vbox;
3494 }
3495
build_or_refresh_option_panel(GameOptionTable * got,GtkWidget * panel)3496 GtkWidget *build_or_refresh_option_panel(GameOptionTable *got, GtkWidget *panel)
3497 {
3498 return build_or_refresh_optionprefs_panel(got,panel,0);
3499 }
3500
build_or_refresh_prefs_panel(GameOptionTable * got,GtkWidget * panel)3501 GtkWidget *build_or_refresh_prefs_panel(GameOptionTable *got, GtkWidget *panel)
3502 {
3503 return build_or_refresh_optionprefs_panel(got,panel,1);
3504 }
3505
option_reset_callback(GtkWidget * w UNUSED,gpointer data)3506 void option_reset_callback(GtkWidget *w UNUSED, gpointer data)
3507 {
3508 make_or_refresh_option_updater((GameOptionEntry *)data,0);
3509 }
3510
option_updater_callback(GtkWidget * w UNUSED,gpointer data UNUSED)3511 void option_updater_callback(GtkWidget *w UNUSED, gpointer data UNUSED)
3512 {
3513 GameOptionTable *got;
3514 PMsgSetGameOptionMsg psgom;
3515 char buf[1024];
3516 int centilims,dbls,pts;
3517 int i, changed, val;
3518
3519 if ( ! the_game ) return;
3520 got = &the_game->option_table;
3521 for ( i = 0 ; i < got->numoptions ; i++ ) {
3522 w = got->options[i].userdata;
3523 if ( ! w ) continue;
3524 changed = 0;
3525 psgom.type = PMsgSetGameOption;
3526 strncpy(psgom.optname,got->options[i].name,16);
3527 switch ( got->options[i].type ) {
3528 case GOTBool:
3529 val = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"checkbox"))->active;
3530 psgom.optvalue = val ? "1" : "0";
3531 if ( val != got->options[i].value.optbool ) changed = 1;
3532 break;
3533 case GOTNat:
3534 case GOTInt:
3535 gtk_spin_button_update(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"spinbutton")));
3536 val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"spinbutton")));
3537 sprintf(buf,"%d",val);
3538 psgom.optvalue = buf;
3539 if ( val != got->options[i].value.optint ) changed = 1;
3540 break;
3541 case GOTString:
3542 psgom.optvalue =
3543 (char *)gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(w),"entry")));
3544 if ( strcmp(psgom.optvalue,got->options[i].value.optstring) != 0 ) changed = 1;
3545 break;
3546 case GOTScore:
3547 centilims = 100*GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"lim"))->active;
3548 centilims += 50 * GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"halflim"))->active;
3549 gtk_spin_button_update(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"dbls")));
3550 dbls = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"dbls")));
3551 gtk_spin_button_update(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"pts")));
3552 pts = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"pts")));
3553 val = 1000000*centilims + 10000 * dbls + pts;
3554 sprintf(buf,"%d",val);
3555 psgom.optvalue = buf;
3556 if ( val != got->options[i].value.optscore ) changed = 1;
3557 break;
3558 }
3559 if ( changed ) send_packet(&psgom);
3560 }
3561 gtk_widget_hide(game_option_dialog);
3562 }
3563
prefs_updater_callback(GtkWidget * w UNUSED,gpointer data UNUSED)3564 void prefs_updater_callback(GtkWidget *w UNUSED, gpointer data UNUSED)
3565 {
3566 GameOptionTable *got;
3567 char buf[1024];
3568 int centilims,dbls,pts;
3569 int i, changed, val;
3570 char *vals;
3571
3572 got = &prefs_table;
3573 for ( i = 0 ; i < got->numoptions ; i++ ) {
3574 w = got->options[i].userdata;
3575 if ( ! w ) continue;
3576 changed = 0;
3577 switch ( got->options[i].type ) {
3578 case GOTBool:
3579 val = GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"checkbox"))->active;
3580 if ( val != got->options[i].value.optbool ) changed = 1;
3581 got->options[i].value.optbool = val;
3582 break;
3583 case GOTNat:
3584 case GOTInt:
3585 gtk_spin_button_update(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"spinbutton")));
3586 val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"spinbutton")));
3587 sprintf(buf,"%d",val);
3588 if ( val != got->options[i].value.optint ) changed = 1;
3589 got->options[i].value.optint = val;
3590 break;
3591 case GOTString:
3592 vals =
3593 (char *)gtk_entry_get_text(GTK_ENTRY(gtk_object_get_data(GTK_OBJECT(w),"entry")));
3594 if ( strcmp(vals,got->options[i].value.optstring) != 0 ) changed = 1;
3595 strmcpy(got->options[i].value.optstring,vals,128);
3596 break;
3597 case GOTScore:
3598 centilims = 100*GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"lim"))->active;
3599 centilims += 50*GTK_TOGGLE_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"halflim"))->active;
3600 gtk_spin_button_update(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"dbls")));
3601 dbls = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"dbls")));
3602 gtk_spin_button_update(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"pts")));
3603 pts = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(gtk_object_get_data(GTK_OBJECT(w),"pts")));
3604 val = 1000000*centilims + 10000 * dbls + pts;
3605 if ( val != got->options[i].value.optscore ) changed = 1;
3606 got->options[i].value.optscore = val;
3607 break;
3608 }
3609 if ( changed ) make_or_refresh_option_updater(&got->options[i],1);
3610 }
3611 /* now actually save it */
3612 read_or_update_rcfile(NULL,XmjrcNone,XmjrcGame);
3613 /* and close */
3614 gtk_widget_hide(game_prefs_dialog);
3615 }
3616
apply_game_prefs_callback(GtkWidget * w UNUSED,gpointer data UNUSED)3617 static void apply_game_prefs_callback(GtkWidget *w UNUSED, gpointer data UNUSED)
3618 {
3619 apply_game_prefs();
3620 gtk_widget_hide(game_prefs_dialog);
3621 }
3622
3623
game_option_init(void)3624 void game_option_init(void)
3625 {
3626 GtkWidget *sbar, *obox, *bbox, *tmp;
3627
3628 game_option_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3629 gtk_signal_connect (GTK_OBJECT (game_option_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
3630 /* must allow shrinking */
3631 gtk_window_set_policy(GTK_WINDOW(game_option_dialog),TRUE,TRUE,FALSE);
3632 gtk_window_set_title(GTK_WINDOW(game_option_dialog),"Current Game Options");
3633 /* reasonable size is ... */
3634 gtk_window_set_default_size(GTK_WINDOW(game_option_dialog),450,400);
3635
3636 obox = gtk_vbox_new(0,dialog_vert_spacing);
3637 gtk_container_set_border_width(GTK_CONTAINER(obox),dialog_border_width);
3638 gtk_widget_show(obox);
3639 gtk_container_add(GTK_CONTAINER(game_option_dialog),obox);
3640
3641 game_option_panel = build_or_refresh_option_panel(the_game ?
3642 &the_game->option_table : NULL,
3643 game_option_panel);
3644 sbar = gtk_scrolled_window_new(NULL,NULL);
3645 gtk_widget_show(sbar);
3646 gtk_box_pack_start(GTK_BOX(obox),sbar,1,1,0);
3647 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sbar),
3648 game_option_panel);
3649 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sbar),
3650 GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
3651
3652 bbox = gtk_hbox_new(1,dialog_button_spacing);
3653 gtk_widget_show(bbox);
3654 gtk_box_pack_end(GTK_BOX(obox),bbox,0,0,0);
3655
3656 tmp = gtk_button_new_with_label("Close");
3657 GTK_WIDGET_UNSET_FLAGS(tmp,GTK_CAN_FOCUS); /* entry widget shd focus */
3658 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(game_option_dialog));
3659 gtk_widget_show(tmp);
3660 gtk_box_pack_end(GTK_BOX(bbox),tmp,1,1,0);
3661
3662 game_option_prefs_button = tmp = gtk_button_new_with_label("Apply preferences");
3663 GTK_WIDGET_UNSET_FLAGS(tmp,GTK_CAN_FOCUS); /* entry widget shd focus */
3664 gtk_signal_connect(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(apply_game_prefs_callback),NULL);
3665 gtk_widget_show(tmp);
3666 gtk_box_pack_end(GTK_BOX(bbox),tmp,1,1,0);
3667
3668 game_option_apply_button = tmp = gtk_button_new_with_label("Apply changes");
3669 GTK_WIDGET_UNSET_FLAGS(tmp,GTK_CAN_FOCUS); /* entry widget shd focus */
3670 gtk_signal_connect(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(option_updater_callback),NULL);
3671 gtk_widget_show(tmp);
3672 gtk_box_pack_end(GTK_BOX(bbox),tmp,1,1,0);
3673 }
3674
game_prefs_init(void)3675 void game_prefs_init(void)
3676 {
3677 GtkWidget *sbar, *obox, *bbox, *tmp;
3678
3679 game_prefs_dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3680 gtk_signal_connect (GTK_OBJECT (game_prefs_dialog), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
3681 /* must allow shrinking */
3682 gtk_window_set_policy(GTK_WINDOW(game_prefs_dialog),TRUE,TRUE,FALSE);
3683 gtk_window_set_title(GTK_WINDOW(game_prefs_dialog),"Game Preferences");
3684 /* reasonable size is ... */
3685 gtk_window_set_default_size(GTK_WINDOW(game_prefs_dialog),450,400);
3686
3687 obox = gtk_vbox_new(0,dialog_vert_spacing);
3688 gtk_container_set_border_width(GTK_CONTAINER(obox),dialog_border_width);
3689 gtk_widget_show(obox);
3690 gtk_container_add(GTK_CONTAINER(game_prefs_dialog),obox);
3691
3692 game_prefs_panel = build_or_refresh_prefs_panel(&prefs_table,
3693 game_prefs_panel);
3694 sbar = gtk_scrolled_window_new(NULL,NULL);
3695 gtk_widget_show(sbar);
3696 gtk_box_pack_start(GTK_BOX(obox),sbar,1,1,0);
3697 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sbar),
3698 game_prefs_panel);
3699 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sbar),
3700 GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);
3701
3702 bbox = gtk_hbox_new(1,dialog_button_spacing);
3703 gtk_widget_show(bbox);
3704 gtk_box_pack_end(GTK_BOX(obox),bbox,0,0,0);
3705
3706 tmp = gtk_button_new_with_label("Cancel");
3707 GTK_WIDGET_UNSET_FLAGS(tmp,GTK_CAN_FOCUS); /* entry widget shd focus */
3708 gtk_signal_connect_object(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(game_prefs_dialog));
3709 gtk_widget_show(tmp);
3710 gtk_box_pack_end(GTK_BOX(bbox),tmp,1,1,0);
3711
3712 tmp = gtk_button_new_with_label("Save changes");
3713 GTK_WIDGET_UNSET_FLAGS(tmp,GTK_CAN_FOCUS); /* entry widget shd focus */
3714 gtk_signal_connect(GTK_OBJECT(tmp),"clicked",GTK_SIGNAL_FUNC(prefs_updater_callback),NULL);
3715 gtk_widget_show(tmp);
3716 gtk_box_pack_end(GTK_BOX(bbox),tmp,1,1,0);
3717 }
3718
3719 /* set the dialog position, changing if necessary */
set_dialog_posn(DialogPosition p)3720 void set_dialog_posn(DialogPosition p) {
3721 if ( p != dialogs_position ) {
3722 /* if the new position is not below, we need to allow the top
3723 window to shrink down */
3724 if ( p != DialogsBelow ) {
3725 gtk_window_set_policy(GTK_WINDOW(topwindow),1,1,1);
3726 } else {
3727 /* don't let it shrink */
3728 gtk_window_set_policy(GTK_WINDOW(topwindow),0,1,0);
3729 }
3730 dialogs_position = p;
3731 create_dialogs();
3732 }
3733 }
3734
set_animation(int a)3735 void set_animation(int a) {
3736 animate = a;
3737 /* request appropriate pause time */
3738 if ( !monitor && the_game ) {
3739 PMsgSetPlayerOptionMsg spom;
3740 spom.type = PMsgSetPlayerOption;
3741 spom.option = PODelayTime;
3742 spom.ack = 0;
3743 spom.value = animate ? 10 : 5; /* 0.5 or 1 second min delay */
3744 spom.text = NULL;
3745 send_packet(&spom);
3746 }
3747 }
3748 /* do_chow: if there's only one possible chow, do it, otherwise
3749 put up a dialog box to choose. Sneakily, this is defined as
3750 a callback, so that the choosing buttons can call this specifying
3751 the chow pos, and the main program can call it with AnyPos.
3752 */
3753
do_chow(GtkWidget * widg UNUSED,gpointer data)3754 void do_chow(GtkWidget *widg UNUSED, gpointer data) {
3755 ChowPosition cpos = (ChowPosition)data;
3756 PMsgChowMsg cm;
3757 int i,n,j;
3758 static int lastdiscard;
3759 TileSet ts;
3760
3761 cm.type = PMsgChow;
3762 cm.discard = the_game->serial;
3763
3764 if ( !monitor && cpos == AnyPos ) {
3765 /* we want to avoid working and popping up again if
3766 for some reason we're already popped up. (So that
3767 this procedure is idempotent.) */
3768 if ( GTK_WIDGET_VISIBLE(chow_dialog) && cm.discard == lastdiscard )
3769 return;
3770 lastdiscard = cm.discard;
3771 ts.type = Chow;
3772 /* set up the boxes */
3773 for (n=0,i=0,j=0;i<3;i++) {
3774 if ( player_can_chow(our_player,the_game->tile,i) ) {
3775 ts.tile = the_game->tile - i;
3776 tilesetbox_set(&chowtsbs[i],&ts,0);
3777 tilesetbox_highlight_nth(&chowtsbs[i],i);
3778 gtk_widget_show(chowbuttons[i]);
3779 n++; j = i;
3780 } else {
3781 gtk_widget_hide(chowtsbs[i].widget);
3782 gtk_widget_hide(chowbuttons[i]);
3783 }
3784 }
3785 /* if there is only one possibility, don't bother to ask.
3786 Also if there is no possibility: we'll then get an error
3787 from the server, which saves us having to worry about it */
3788 if ( n <= 1 ) {
3789 cpos = j;
3790 } else {
3791 /* pop down the discard dialog */
3792 gtk_widget_hide(discard_dialog->widget);
3793 dialog_popup(chow_dialog,DPCentred);
3794 }
3795 }
3796
3797 /* Now we might have found the position */
3798 if ( cpos != AnyPos ) {
3799 cm.cpos = cpos;
3800 send_packet(&cm);
3801 /* if the chowpending flag isn't set, we must be working with an
3802 old server and be in the mahjonging state. Pop ourselves down,
3803 so that if something goes wrong it's the discard dialog that
3804 comes back up */
3805 if ( ! the_game->chowpending ) gtk_widget_hide(chow_dialog);
3806 }
3807 }
3808
3809 /* Generic popup centered over main window.
3810 Positioning is given by
3811 DPCentred - centered over main window
3812 DPOnDiscard - bottom left corner in same place as discard dialog
3813 DPErrorPos - for error dialogs: centred over top of main window,
3814 and offset by a multiple of num_error_dialogs
3815 DPNone - don't touch the positioning at all '
3816 DPCentredOnce - centre it on first popup, then don't fiddle '
3817 DPOnDiscardOnce - on discard dialog first time, then don't fiddle '
3818 If the widget is not a window, then DPCentredOnce and DPNone
3819 are equivalent to DPCentred, and DPOnDiscardOnce is equivalent to
3820 DPOnDiscard.
3821 */
dialog_popup(GtkWidget * dialog,DPPosn posn)3822 void dialog_popup(GtkWidget *dialog,DPPosn posn) {
3823 gint x,y,w,h;
3824 GtkRequisition r = { 0, 0};
3825
3826 /* So that we don't work if it's already popped up: */
3827 if ( GTK_WIDGET_VISIBLE(dialog) ) return;
3828
3829 /* if the position has been set, don't mess */
3830 if ( GTK_IS_WINDOW(dialog)
3831 && gtk_object_get_data(GTK_OBJECT(dialog),"position-set") ) {
3832 gtk_widget_set_uposition(dialog,
3833 (gint)(intptr_t)gtk_object_get_data(GTK_OBJECT(dialog),"position-x"),
3834 (gint)(intptr_t)gtk_object_get_data(GTK_OBJECT(dialog),"position-y"));
3835 gtk_widget_show(dialog);
3836 // This ought to work, but seems to confuse my wm
3837 //gtk_window_present(GTK_WINDOW(dialog));
3838 return;
3839 }
3840
3841 if ( ! GTK_IS_WINDOW(dialog) ) {
3842 if ( posn == DPCentredOnce ) posn = DPCentred;
3843 if ( posn == DPOnDiscardOnce ) posn = DPOnDiscard;
3844 if ( posn == DPNone ) posn = DPCentred;
3845 }
3846
3847 /* get size of discard widget if necessary */
3848 if ( (posn == DPOnDiscard || posn == DPOnDiscardOnce)
3849 && discard_req.width == 0 ) {
3850 gtk_widget_size_request(discard_dialog->widget,&discard_req);
3851 gtk_widget_set_usize(discard_dialog->widget,
3852 discard_req.width,
3853 discard_req.height);
3854 }
3855
3856 gtk_widget_size_request(dialog,&r);
3857
3858 if ( GTK_IS_WINDOW(dialog) ) {
3859 gdk_window_get_size(topwindow->window,&w,&h);
3860 gdk_window_get_deskrelative_origin(topwindow->window,&x,&y);
3861 } else {
3862 w = discard_area_alloc.width;
3863 h = discard_area_alloc.height;
3864 x = y = 0;
3865 }
3866
3867 if ( dialogs_position != DialogsBelow || GTK_IS_WINDOW(dialog) ) {
3868 if ( posn == DPOnDiscard ) {
3869 if ( GTK_IS_WINDOW(dialog) )
3870 gtk_widget_set_uposition(dialog,
3871 x + w/2 - r.width/2
3872 - (discard_req.width - r.width)/2,
3873 y + h/2 - r.height/2
3874 + (discard_req.height - r.height)/2);
3875 else
3876 gtk_fixed_move(GTK_FIXED(discard_area),dialog,
3877 x + w/2 - r.width/2
3878 - (discard_req.width - r.width)/2,
3879 y + h/2 - r.height/2
3880 + (discard_req.height - r.height)/2);
3881 } else if ( posn == DPOnDiscardOnce ) {
3882 if ( gtk_object_get_data(GTK_OBJECT(dialog),"position-set") ) {
3883 /* do nothing */
3884 } else {
3885 if ( GTK_IS_WINDOW(dialog) )
3886 gtk_widget_set_uposition(dialog,
3887 x + w/2 - r.width/2
3888 - (discard_req.width - r.width)/2,
3889 y + h/2 - r.height/2
3890 + (discard_req.height - r.height)/2);
3891 else
3892 gtk_fixed_move(GTK_FIXED(discard_area),dialog,
3893 x + w/2 - r.width/2
3894 - (discard_req.width - r.width)/2,
3895 y + h/2 - r.height/2
3896 + (discard_req.height - r.height)/2);
3897 gtk_object_set_data(GTK_OBJECT(dialog),"position-set",(gpointer)1);
3898 }
3899 } else if ( posn == DPCentred ) {
3900 if ( GTK_IS_WINDOW(dialog) )
3901 gtk_widget_set_uposition(dialog,
3902 x + w/2 - r.width/2,
3903 y + h/2 - r.height/2);
3904 else
3905 gtk_fixed_move(GTK_FIXED(discard_area),dialog,
3906 x + w/2 - r.width/2,
3907 y + h/2 - r.height/2);
3908 } else if ( posn == DPCentredOnce ) {
3909 if ( gtk_object_get_data(GTK_OBJECT(dialog),"position-set") ) {
3910 /* do nothing */
3911 #ifdef GTK2
3912 if ( GTK_IS_WINDOW(dialog) ) {
3913 gtk_widget_set_uposition(dialog,
3914 (gint)(intptr_t)gtk_object_get_data(GTK_OBJECT(dialog),"position-x"),
3915 (gint)(intptr_t)gtk_object_get_data(GTK_OBJECT(dialog),"position-y"));
3916 }
3917 #endif
3918 } else {
3919 if ( GTK_IS_WINDOW(dialog) )
3920 gtk_widget_set_uposition(dialog,
3921 x + w/2 - r.width/2,
3922 y + h/2 - r.height/2);
3923 else
3924 gtk_fixed_move(GTK_FIXED(discard_area),dialog,
3925 x + w/2 - r.width/2,
3926 y + h/2 - r.height/2);
3927 gtk_object_set_data(GTK_OBJECT(dialog),"position-set",(gpointer)1);
3928 }
3929 } else if ( posn == DPErrorPos ) {
3930 if ( GTK_IS_WINDOW(dialog) )
3931 gtk_widget_set_uposition(dialog,
3932 x + w/2 - r.width/2,
3933 y + h/4 - r.height/2 + 10*num_error_dialogs);
3934 else
3935 gtk_fixed_move(GTK_FIXED(discard_area),dialog,
3936 x + w/2 - r.width/2,
3937 y + h/4 - r.height/2 + 10*num_error_dialogs);
3938 }
3939 }
3940 gtk_widget_show(dialog);
3941 if ( GTK_IS_WINDOW(dialog) ) {
3942 // This ought to work, but seems to confuse my wm
3943 // gtk_window_present(GTK_WINDOW(dialog));
3944 } else {
3945 // This ought to work, but seems to confuse my wm
3946 // gtk_window_present(GTK_WINDOW(topwindow));
3947 }
3948 }
3949
3950 /* window to display game status.
3951 0 1 2... 3....
3952 We are WIND; id: n Name: name
3953 total score: nnn
3954 and for right, opposite, left
3955 */
3956 static char *status_poses[] = { "We are ", "Right is ", "Opp. is ", "Left is " };
3957 static GtkWidget *status_poslabels[4];
3958 static GtkWidget *status_windlabels[4];
3959 static GtkWidget *status_idlabels[4];
3960 static GtkWidget *status_namelabels[4];
3961 static GtkWidget *status_scorelabels[4];
3962 static GtkWidget *status_pwind;
3963 static GtkWidget *status_status;
3964 static GtkWidget *status_suspended;
3965 static GtkWidget *status_tilesleft;
3966 /* and for the short version */
3967 static GtkWidget *status_chairs[4];
3968
status_init(void)3969 void status_init(void) {
3970 int i;
3971 GtkWidget *table, *w;
3972
3973 if ( info_windows_in_main ) {
3974 status_window = gtk_hbox_new(0,0);
3975 gtk_widget_show(status_window);
3976 gtk_box_pack_start(GTK_BOX(info_box),status_window,0,0,0);
3977 } else {
3978 status_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3979 gtk_signal_connect(GTK_OBJECT (status_window), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
3980 gtk_window_set_title(GTK_WINDOW(status_window),"Game information");
3981 }
3982 gtk_container_set_border_width(GTK_CONTAINER(status_window),
3983 dialog_border_width);
3984
3985 /* this is what we used to do, and will still do for separate
3986 windows */
3987 if ( ! info_windows_in_main ) {
3988 table = gtk_table_new(12,4,0);
3989 gtk_widget_show(table);
3990 gtk_container_add(GTK_CONTAINER(status_window),table);
3991 for ( i = 0 ; i < 4 ; i++ ) {
3992 status_poslabels[i] = w = gtk_label_new(status_poses[i]);
3993 gtk_widget_show(w);
3994 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_LEFT);
3995 gtk_table_attach_defaults(GTK_TABLE(table),w,
3996 0,1,2*i,2*i+1);
3997 status_windlabels[i] = w = gtk_label_new("none");
3998 gtk_widget_show(w);
3999 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_LEFT);
4000 gtk_table_attach_defaults(GTK_TABLE(table),w,
4001 1,2,2*i,2*i+1);
4002 status_idlabels[i] = w = gtk_label_new(" ID: 0");
4003 gtk_widget_show(w);
4004 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_LEFT);
4005 gtk_table_attach_defaults(GTK_TABLE(table),w,
4006 2,3,2*i,2*i+1);
4007 status_namelabels[i] = w = gtk_label_new(" Name: unknown");
4008 gtk_widget_show(w);
4009 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_LEFT);
4010 gtk_table_attach_defaults(GTK_TABLE(table),w,
4011 3,4,2*i,2*i+1);
4012 status_scorelabels[i] = w = gtk_label_new("total score: 0");
4013 gtk_widget_show(w);
4014 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_LEFT);
4015 gtk_table_attach_defaults(GTK_TABLE(table),w,
4016 1,4,2*i+1,2*i+2);
4017
4018 }
4019 status_pwind = w = gtk_label_new("Prevailing wind: none");
4020 gtk_widget_show(w);
4021 gtk_table_attach_defaults(GTK_TABLE(table),w,
4022 0,4,8,9);
4023
4024 status_status = w = gtk_label_new("no game");
4025 gtk_widget_show(w);
4026 gtk_table_attach_defaults(GTK_TABLE(table),w,
4027 0,4,9,10);
4028
4029 status_tilesleft = w = gtk_label_new("");
4030 gtk_widget_show(w);
4031 gtk_table_attach_defaults(GTK_TABLE(table),w,
4032 0,4,10,11);
4033
4034 w = gtk_button_new_with_label("Close");
4035 gtk_widget_show(w);
4036 gtk_table_attach_defaults(GTK_TABLE(table),w,
4037 0,4,11,12);
4038 gtk_signal_connect_object(GTK_OBJECT(w),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(status_window));
4039
4040 } else {
4041 /* and this is for the new in-window information */
4042 table = gtk_table_new(4,7,0);
4043 gtk_widget_show(table);
4044 gtk_container_add(GTK_CONTAINER(status_window),table);
4045 /* opposite player */
4046 status_chairs[2] = w = gtk_label_new("(seat empty)");
4047 gtk_widget_show(w);
4048 gtk_table_attach_defaults(GTK_TABLE(table),w,1,4,0,1);
4049 /* left player */
4050 status_chairs[3] = w = gtk_label_new("(seat empty)");
4051 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_LEFT);
4052 gtk_widget_show(w);
4053 gtk_table_attach_defaults(GTK_TABLE(table),w,0,3,1,2);
4054 /* right player */
4055 status_chairs[1] = w = gtk_label_new("(seat empty)");
4056 gtk_label_set_justify(GTK_LABEL(w),GTK_JUSTIFY_RIGHT);
4057 gtk_widget_show(w);
4058 gtk_table_attach_defaults(GTK_TABLE(table),w,2,5,2,3);
4059 /* us */
4060 status_chairs[0] = w = gtk_label_new("(seat empty)");
4061 gtk_widget_show(w);
4062 gtk_table_attach_defaults(GTK_TABLE(table),w,1,4,3,4);
4063 /* spacing */
4064 w = gtk_label_new(" ");
4065 gtk_widget_show(w);
4066 gtk_table_attach_defaults(GTK_TABLE(table),w,5,6,0,1);
4067 /* round */
4068 status_pwind = w = gtk_label_new(" ");
4069 gtk_widget_show(w);
4070 gtk_table_attach_defaults(GTK_TABLE(table),w,6,7,0,1);
4071 /* game status */
4072 status_status = w = gtk_label_new("no game");
4073 gtk_widget_show(w);
4074 gtk_table_attach_defaults(GTK_TABLE(table),w,6,7,1,2);
4075 /* tiles left */
4076 status_tilesleft = w = gtk_label_new("");
4077 gtk_widget_show(w);
4078 gtk_table_attach_defaults(GTK_TABLE(table),w,6,7,2,3);
4079 /* game suspended */
4080 status_suspended = w = gtk_label_new("");
4081 gtk_widget_show(w);
4082 gtk_table_attach_defaults(GTK_TABLE(table),w,6,7,3,4);
4083 }
4084 }
4085
status_update(int game_over)4086 void status_update(int game_over) {
4087 int i,s;
4088 const char *pn;
4089 PlayerP p;
4090 static char buf[256];
4091
4092 if ( ! the_game ) return;
4093
4094 for ( i=0 ; i < 4 ; i++ ) {
4095 s = (our_seat+i)%NUM_SEATS;
4096 p = the_game->players[s];
4097 if ( !info_windows_in_main ) {
4098 gtk_label_set_text(GTK_LABEL(status_windlabels[i]),
4099 windnames[p->wind]);
4100 sprintf(buf," ID: %d",p->id);
4101 gtk_label_set_text(GTK_LABEL(status_idlabels[i]),buf);
4102 snprintf(buf,256," Name: %s",p->name);
4103 gtk_label_set_text(GTK_LABEL(status_namelabels[i]),buf);
4104 sprintf(buf,"total score: %5d",p->cumulative_score);
4105 gtk_label_set_text(GTK_LABEL(status_scorelabels[i]),buf);
4106 } else {
4107 snprintf(buf,256,p->hand_score >= 0 ? "(%s) %s[%d]: %d (%d)"
4108 : "(%s) %s[%d]: %d",
4109 shortwindnames[p->wind],p->name,p->id,p->cumulative_score,
4110 p->hand_score);
4111 gtk_label_set_text(GTK_LABEL(status_chairs[i]),buf);
4112 }
4113 #ifdef GTK2
4114 if ( showwall ) {
4115 snprintf(buf,256,p->hand_score >= 0 ? "%s [%d]\n%s\nTotal: %d\nThis hand: %d" : "%s [%d]\n%s\nTotal: %d\nThis hand: ",
4116 p->name,p->id,windnames[p->wind],p->cumulative_score,
4117 p->hand_score);
4118 gtk_label_set_text(pdisps[i].infolab,buf);
4119 }
4120 #endif
4121 }
4122
4123 sprintf(buf,info_windows_in_main ? "%s round" : "Prevailing wind: %s",
4124 windnames[the_game->round]);
4125 gtk_label_set_text(GTK_LABEL(status_pwind),buf);
4126
4127 pn = (info_windows_in_main ? shortwindnames : windnames)[the_game->player+1]; /* +1 for seat to wind */
4128 switch (the_game->state) {
4129 case Dealing:
4130 sprintf(buf,"Dealing");
4131 break;
4132 case DeclaringSpecials:
4133 sprintf(buf,"%s declaring specials",pn);
4134 break;
4135 case Discarding:
4136 sprintf(buf,"%s to discard",pn);
4137 break;
4138 case Discarded:
4139 sprintf(buf,"%s has discarded",pn);
4140 break;
4141 case MahJonging:
4142 sprintf(buf,"%s has Mah Jong",pn);
4143 break;
4144 case HandComplete:
4145 sprintf(buf,"Hand finished");
4146 break;
4147 }
4148 if ( !info_windows_in_main ) {
4149 if ( !the_game->active ) strcat(buf," (Play suspended)");
4150 }
4151 if ( game_over ) strcpy(buf,"GAME OVER");
4152 gtk_label_set_text(GTK_LABEL(status_status),buf);
4153 if ( ! info_windows_in_main ) {
4154 sprintf(buf,"%3d tiles left + %2d dead tiles",
4155 the_game->wall.live_end-the_game->wall.live_used,
4156 the_game->wall.dead_end-the_game->wall.live_end);
4157 } else {
4158 sprintf(buf,"%3d tiles left + %2d dead tiles",
4159 the_game->wall.live_end-the_game->wall.live_used,
4160 the_game->wall.dead_end-the_game->wall.live_end);
4161 }
4162 gtk_label_set_text(GTK_LABEL(status_tilesleft),buf);
4163 if ( info_windows_in_main ) {
4164 gtk_label_set_text(GTK_LABEL(status_suspended),
4165 the_game->active ? "" : "Play suspended");
4166 }
4167 }
4168
showraise(GtkWidget * w)4169 void showraise(GtkWidget *w) {
4170 if ( GTK_IS_WINDOW(w)
4171 && gtk_object_get_data(GTK_OBJECT(w),"position-set") ) {
4172 gtk_widget_set_uposition(w,
4173 (gint)(intptr_t)gtk_object_get_data(GTK_OBJECT(w),"position-x"),
4174 (gint)(intptr_t)gtk_object_get_data(GTK_OBJECT(w),"position-y"));
4175 }
4176 gtk_widget_show(w);
4177 gdk_window_raise(w->window);
4178 #ifndef GTK2
4179 /* I forget why this is there - but it seems to break position
4180 saving etc. in gtk2 */
4181 gdk_window_show(w->window);
4182 #endif
4183 }
4184
about_init(void)4185 static void about_init(void) {
4186 GtkWidget *closebutton, *textw, *vbox;
4187 static char *abouttxt =
4188 "This is xmj , part of the Mah-Jong for Unix (etc)\n"
4189 "set of programs.\n"
4190 "Copyright (c) J. C. Bradfield 2000-2014.\n"
4191 "Distributed under the Gnu General Public License, version 2.\n"
4192 "This is version " VERSION " (protocol version " STRINGIFY(PROTOCOL_VERSION) ").\n"
4193 "User documentation is in the xmj manual page.\n"
4194 "Latest versions, information etc. may be found at\n"
4195 " http://mahjong.julianbradfield.org/ .\n"
4196 "Comments and suggestions should be mailed to\n"
4197 " mahjong@stevens-bradfield.com" ;
4198
4199 about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4200 gtk_signal_connect (GTK_OBJECT (about_window), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
4201 gtk_window_set_title(GTK_WINDOW(about_window),"About xmj");
4202 gtk_container_set_border_width(GTK_CONTAINER(about_window),
4203 dialog_border_width);
4204
4205 vbox = gtk_vbox_new(0,dialog_vert_spacing);
4206 gtk_widget_show(vbox);
4207 gtk_container_add(GTK_CONTAINER(about_window),vbox);
4208
4209 #ifdef GTK2
4210 GtkTextBuffer *textwbuf;
4211 GtkTextIter textwiter;
4212
4213 textw = gtk_text_view_new();
4214 textwbuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textw));
4215 gtk_text_buffer_get_iter_at_offset (textwbuf, &textwiter, 0);
4216 #else
4217 textw = gtk_text_new(NULL,NULL);
4218 #endif
4219 // let it choose its own
4220 // gtk_widget_set_usize(textw,300,200);
4221 #ifdef GTK2
4222 gtk_text_buffer_insert(textwbuf,&textwiter,abouttxt,-1);
4223 #else
4224 gtk_text_insert(GTK_TEXT(textw),NULL,NULL,NULL,abouttxt,-1);
4225 #endif
4226 gtk_widget_show(textw);
4227 GTK_WIDGET_UNSET_FLAGS(textw,GTK_CAN_FOCUS);
4228 gtk_box_pack_start(GTK_BOX(vbox),textw,0,0,0);
4229
4230 closebutton = gtk_button_new_with_label("Close");
4231 gtk_widget_show(closebutton);
4232 gtk_signal_connect_object(GTK_OBJECT(closebutton),"clicked",GTK_SIGNAL_FUNC(close_saving_posn),GTK_OBJECT(about_window));
4233 gtk_box_pack_start(GTK_BOX(vbox),closebutton,0,0,0);
4234
4235 }
4236
nag_callback(GtkWidget * widg UNUSED,gpointer data)4237 static void nag_callback(GtkWidget *widg UNUSED, gpointer data) {
4238 nag_state = (int)(intptr_t) data;
4239 read_or_update_rcfile(NULL,XmjrcNone,XmjrcMisc);
4240 gtk_widget_hide(nag_window);
4241 }
4242
nag_init(void)4243 static void nag_init(void) {
4244 GtkWidget *yesbutton, *maybebutton, *nobutton, *textw, *vbox;
4245
4246 #ifdef GTK2
4247 GtkTextBuffer *textwbuf;
4248 GtkTextIter textwiter;
4249 #endif
4250
4251 char buf[1024];
4252 static char *nagtxt = ""
4253 "Congratulations: you've completed %d full games using\n"
4254 "this set of programs.\n"
4255 "That suggests that you are getting some enjoyment\n"
4256 "out of them.\n"
4257 "\n"
4258 "If you haven't already, perhaps you would like to\n"
4259 "think about making a small donation to me by way of thanks?\n"
4260 "\n"
4261 "You can do this with a credit card via the home page\n"
4262 "hhtp://www.stevens-bradfield.com/MahJong/";
4263
4264 nag_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4265 gtk_signal_connect (GTK_OBJECT (nag_window), "delete_event",GTK_SIGNAL_FUNC(gtk_widget_hide), NULL);
4266 gtk_window_set_title(GTK_WINDOW(nag_window),"mu4 juan1");
4267 gtk_container_set_border_width(GTK_CONTAINER(nag_window),
4268 dialog_border_width);
4269
4270 vbox = gtk_vbox_new(0,dialog_vert_spacing);
4271 gtk_widget_show(vbox);
4272 gtk_container_add(GTK_CONTAINER(nag_window),vbox);
4273
4274 #ifdef GTK2
4275 textw = gtk_text_view_new();
4276 #else
4277 textw = gtk_text_new(NULL,NULL);
4278 #endif
4279 // Better not to set this, I think
4280 //gtk_widget_set_usize(textw,400,200);
4281 sprintf(buf,nagtxt,completed_games);
4282 #ifdef GTK2
4283 textwbuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textw));
4284 gtk_text_buffer_get_iter_at_offset (textwbuf, &textwiter, 0);
4285 gtk_text_buffer_insert(textwbuf,&textwiter,buf,-1);
4286 #else
4287 gtk_text_insert(GTK_TEXT(textw),NULL,NULL,NULL,buf,-1);
4288 #endif
4289 gtk_widget_show(textw);
4290 GTK_WIDGET_UNSET_FLAGS(textw,GTK_CAN_FOCUS);
4291 gtk_box_pack_start(GTK_BOX(vbox),textw,0,0,0);
4292
4293 yesbutton = gtk_button_new_with_label("Yes, I have/will");
4294 gtk_widget_show(yesbutton);
4295 gtk_signal_connect(GTK_OBJECT(yesbutton),"clicked",GTK_SIGNAL_FUNC(nag_callback),(gpointer)2);
4296 gtk_box_pack_start(GTK_BOX(vbox),yesbutton,0,0,0);
4297
4298 maybebutton = gtk_button_new_with_label("Maybe: remind me again later");
4299 gtk_widget_show(maybebutton);
4300 gtk_signal_connect(GTK_OBJECT(maybebutton),"clicked",GTK_SIGNAL_FUNC(nag_callback),(gpointer)0);
4301 gtk_box_pack_start(GTK_BOX(vbox),maybebutton,0,0,0);
4302
4303 nobutton = gtk_button_new_with_label("No, I won't");
4304 gtk_widget_show(nobutton);
4305 gtk_signal_connect(GTK_OBJECT(nobutton),"clicked",GTK_SIGNAL_FUNC(nag_callback),(gpointer)1);
4306 gtk_box_pack_start(GTK_BOX(vbox),nobutton,0,0,0);
4307
4308 }
4309
nag_popup(void)4310 void nag_popup(void) {
4311 if ( ! nag_window ) nag_init();
4312 dialog_popup(nag_window,DPCentred);
4313 }
4314
4315 /* create the dialogs that depend on --dialog-XXX */
create_dialogs(void)4316 void create_dialogs(void) {
4317
4318 if ( dialogs_position == DialogsBelow ) {
4319 GtkWidget *t;
4320 t = gtk_event_box_new(); /* so there's a window to have a style */
4321 gtk_widget_show(t);
4322 dialoglowerbox = gtk_hbox_new(0,0);
4323 gtk_widget_show(dialoglowerbox);
4324 gtk_container_add(GTK_CONTAINER(t),dialoglowerbox);
4325 gtk_box_pack_end(GTK_BOX(outerframe),t,0,0,0);
4326 gtk_widget_show(dialoglowerbox->parent);
4327 }
4328
4329 /* create the discard dialog */
4330 discard_dialog_init();
4331
4332 /* and the chow dialog */
4333 chow_dialog_init();
4334
4335 /* and the declaring specials dialog */
4336 ds_dialog_init();
4337
4338 /* and create the turn dialog */
4339 turn_dialog_init();
4340
4341 /* now create the scoring dialog */
4342 scoring_dialog_init();
4343
4344 /* and the continue dialog */
4345 continue_dialog_init();
4346
4347 /* and the end dialog */
4348 end_dialog_init();
4349
4350 }
4351
4352 /* and destroy them */
destroy_dialogs(void)4353 void destroy_dialogs(void)
4354 {
4355 #define zapit(w) if ( w ) gtk_widget_destroy(w) ; w = NULL ;
4356 zapit(discard_dialog->widget);
4357 zapit(chow_dialog);
4358 zapit(ds_dialog);
4359 zapit(turn_dialog);
4360 zapit(scoring_dialog);
4361 zapit(continue_dialog);
4362 }
4363
scorehistory_showraise(void)4364 static void scorehistory_showraise(void) {
4365 if ( ! scorehistorywindow ) scorehistory_init();
4366 showraise(scorehistorywindow);
4367 }
scoring_showraise(void)4368 static void scoring_showraise(void) {
4369 if ( ! textwindow ) textwindow_init();
4370 showraise(textwindow);
4371 }
message_showraise(void)4372 static void message_showraise(void) {
4373 if ( ! messagewindow ) messagewindow_init();
4374 showraise(messagewindow);
4375 }
about_showraise(void)4376 static void about_showraise(void) {
4377 if ( ! about_window ) about_init();
4378 showraise(about_window);
4379 }
4380
save_showraise(void)4381 static void save_showraise(void) {
4382 if ( ! save_window ) save_init();
4383 showraise(save_window);
4384 }
4385
password_showraise(void)4386 void password_showraise(void) {
4387 if ( ! password_window ) password_init();
4388 showraise(password_window);
4389 }
4390
status_showraise(void)4391 void status_showraise(void) {
4392 if (!nopopups) {
4393 showraise(status_window);
4394 }
4395 status_update(0) ;
4396 }
4397
display_option_dialog_popup(void)4398 static void display_option_dialog_popup(void) {
4399 if ( ! display_option_dialog ) display_option_dialog_init();
4400 display_option_dialog_refresh();
4401 dialog_popup(display_option_dialog,DPCentredOnce) ;
4402 }
4403
playing_prefs_dialog_popup(void)4404 static void playing_prefs_dialog_popup(void) {
4405 if ( ! playing_prefs_dialog ) playing_prefs_dialog_init();
4406 playing_prefs_dialog_refresh();
4407 dialog_popup(playing_prefs_dialog,DPCentredOnce) ;
4408 }
4409
debug_options_dialog_popup(void)4410 void debug_options_dialog_popup(void) {
4411 if ( ! debug_options_dialog ) debug_options_dialog_init();
4412 debug_options_dialog_refresh();
4413 dialog_popup(debug_options_dialog,DPCentredOnce) ;
4414 }
4415
game_option_popup(void)4416 static void game_option_popup(void) {
4417 int b;
4418 if ( ! the_game ) return;
4419 if ( ! game_option_dialog ) game_option_init();
4420 game_option_panel = build_or_refresh_option_panel(&the_game->option_table,
4421 game_option_panel);
4422 /* we can't apply options if somebody else is the manager */
4423 b = (the_game->manager == 0 || the_game->manager == our_id);
4424 gtk_widget_set_sensitive(game_option_apply_button,b);
4425 gtk_widget_set_sensitive(game_option_prefs_button,b);
4426 dialog_popup(game_option_dialog,DPNone);
4427 }
4428
game_prefs_popup(void)4429 static void game_prefs_popup(void) {
4430 if ( ! game_prefs_dialog ) game_prefs_init();
4431 read_or_update_rcfile(NULL,XmjrcGame,XmjrcNone);
4432 game_prefs_panel = build_or_refresh_prefs_panel(&prefs_table,game_prefs_panel);
4433 dialog_popup(game_prefs_dialog,DPNone);
4434 }
4435
save_state(void)4436 static void save_state(void) {
4437 PMsgSaveStateMsg m;
4438 m.type = PMsgSaveState;
4439 m.filename = NULL;
4440 send_packet(&m);
4441 }
4442
4443 /* see comment at declaration */
grab_focus_if_appropriate(GtkWidget * w)4444 static void grab_focus_if_appropriate(GtkWidget *w) {
4445 if ( info_windows_in_main ) {
4446 if ( GTK_TOGGLE_BUTTON(mfocus)->active ) {
4447 gtk_widget_grab_focus(message_entry);
4448 } else if ( ! (GTK_HAS_FOCUS & GTK_WIDGET_FLAGS(message_entry)) ) {
4449 gtk_widget_grab_focus(w);
4450 }
4451 } else {
4452 gtk_widget_grab_focus(w);
4453 }
4454 }
4455
4456 #ifdef GTK2
4457 #define NULLEX , NULL
4458 #else
4459 #define NULLEX
4460 #endif
4461 /* the menu items */
4462 static GtkItemFactoryEntry menu_items[] = {
4463 { "/_Game", NULL, NULL, 0, "<Branch>" NULLEX},
4464 { "/Game/_New local game...", NULL, GTK_SIGNAL_FUNC(open_dialog_popup), 1, NULL NULLEX},
4465 { "/Game/_Join server...", NULL, GTK_SIGNAL_FUNC(open_dialog_popup), 0, NULL NULLEX},
4466 { "/Game/_Resume game...", NULL, GTK_SIGNAL_FUNC(open_dialog_popup), 2, NULL NULLEX},
4467 { "/Game/_Save", NULL, save_state, 0, NULL NULLEX},
4468 { "/Game/Save _as...", NULL, save_showraise, 0, NULL NULLEX},
4469 { "/Game/_Close", NULL, GTK_SIGNAL_FUNC(close_connection), 0, NULL NULLEX},
4470 { "/Game/_Quit", NULL, GTK_SIGNAL_FUNC(exit), 0, NULL NULLEX},
4471 { "/_Show", NULL, NULL, 0, "<Branch>" NULLEX},
4472 { "/Show/_Scoring info", NULL, scoring_showraise, 0, NULL NULLEX},
4473 { "/Show/_Game info", NULL, status_showraise, 0, NULL NULLEX},
4474 { "/Show/_Messages", NULL, message_showraise, 0, NULL NULLEX},
4475 { "/Show/Scoring _history", NULL, scorehistory_showraise, 0, NULL NULLEX},
4476 { "/Show/_Warnings", NULL, warningraise, 0, NULL NULLEX},
4477 { "/_Options",NULL,NULL,0,"<Branch>" NULLEX},
4478 { "/Options/_Display Options...", NULL, display_option_dialog_popup,0,NULL NULLEX},
4479 { "/Options/_Playing Preferences...",NULL, playing_prefs_dialog_popup,0,NULL NULLEX},
4480 { "/Options/_Game Option Preferences...", NULL, game_prefs_popup,0,NULL NULLEX},
4481 { "/Options/_Current Game Options...", NULL, game_option_popup,0,NULL NULLEX},
4482 { "/Options/_Debugging Options...", NULL, debug_options_dialog_popup,0,NULL NULLEX},
4483 #ifdef GTK2
4484 /* a button in the title bar doesn't quite work properly in gtk2.
4485 It seems somehow to lose a click. But since ItemFactory is deprecated,
4486 there's no chance of a fix. */
4487 { "/Show _Warnings", NULL, NULL,0,"<Branch>" NULLEX},
4488 { "/Show _Warnings/Show _Warnings", NULL, warningraise,0,NULL NULLEX},
4489 #else
4490 { "/Show _Warnings", NULL, warningraise,0,NULL NULLEX},
4491 #endif
4492 { "/_About", NULL, NULL, 0, "<LastBranch>" NULLEX},
4493 { "/About/_About xmj", NULL, about_showraise, 0, NULL NULLEX},
4494 };
4495
4496 static const int nmenu_items = sizeof(menu_items)/sizeof(GtkItemFactoryEntry);
4497
4498 /* create the menubar, and return it */
menubar_create(void)4499 GtkWidget *menubar_create(void) {
4500 GtkItemFactory *item_factory;
4501 GtkAccelGroup *accel;
4502 GtkWidget *m;
4503 int connected = the_game && the_game->fd;
4504
4505 accel = gtk_accel_group_new();
4506 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR,
4507 "<main>",accel);
4508 gtk_item_factory_create_items(item_factory,nmenu_items,
4509 menu_items,NULL);
4510 gtk_window_add_accel_group(GTK_WINDOW(topwindow),accel);
4511
4512 m = gtk_item_factory_get_widget(item_factory,"<main>");
4513 gtk_widget_show(m);
4514 openmenuentry = gtk_item_factory_get_widget(item_factory,
4515 "/Game/Join server...");
4516 assert(openmenuentry);
4517 gtk_widget_set_sensitive(openmenuentry,!connected);
4518 newgamemenuentry = gtk_item_factory_get_widget(item_factory,
4519 "/Game/New local game...");
4520 assert(newgamemenuentry);
4521 gtk_widget_set_sensitive(newgamemenuentry,!connected);
4522 resumegamemenuentry = gtk_item_factory_get_widget(item_factory,
4523 "/Game/Resume game...");
4524 assert(resumegamemenuentry);
4525 gtk_widget_set_sensitive(resumegamemenuentry,!connected);
4526 savemenuentry = gtk_item_factory_get_widget(item_factory,
4527 "/Game/Save");
4528 assert(savemenuentry);
4529 gtk_widget_set_sensitive(savemenuentry,connected);
4530 saveasmenuentry = gtk_item_factory_get_widget(item_factory,
4531 "/Game/Save as...");
4532 assert(saveasmenuentry);
4533 gtk_widget_set_sensitive(saveasmenuentry,connected);
4534 closemenuentry = gtk_item_factory_get_widget(item_factory,"/Game/Close");
4535 assert(closemenuentry);
4536 gtk_widget_set_sensitive(closemenuentry,connected);
4537 gameoptionsmenuentry = gtk_item_factory_get_widget(item_factory,"/Options/Current Game Options...");
4538 gtk_widget_set_sensitive(gameoptionsmenuentry,connected);
4539
4540 warningentry = gtk_item_factory_get_item(item_factory,
4541 "/Show Warnings");
4542 assert(warningentry);
4543 /* This doesn't actually work. But we'll leave it here
4544 in case it works in gtk 2.0 */
4545 gtk_menu_item_right_justify(GTK_MENU_ITEM(warningentry));
4546 gtk_widget_set_name(warningentry,"warningentry");
4547
4548 /* it's very tedious simply to set this to have red text */
4549 {
4550 #ifdef GTK2
4551 GdkColor c;
4552 gdk_color_parse("red",&c);
4553 gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(warningentry)),GTK_STATE_NORMAL,&c);
4554 #else
4555 GtkStyle *s;
4556 s = gtk_style_copy(gtk_widget_get_default_style());
4557 gdk_color_parse("red",&(s->fg[GTK_STATE_NORMAL]));
4558 gtk_widget_set_style(GTK_BIN(warningentry)->child,s);
4559 #endif
4560 }
4561
4562 gtk_widget_hide(warningentry);
4563
4564 /* if the relevant windows are in the main window, zap the menu entries */
4565 if ( info_windows_in_main ) {
4566 gtk_widget_destroy(gtk_item_factory_get_widget(item_factory,"/Show/Game info"));
4567 gtk_widget_destroy(gtk_item_factory_get_widget(item_factory,"/Show/Messages"));
4568 }
4569
4570 return m;
4571 }
4572
4573
4574