2fce80fded3acea080b4fd556fbe13e4c6e2029d
[xboard.git] / callback.c
1 #include <gtk/gtk.h>
2 #include "common.h"
3 #include <errno.h>
4 #include "backend.h"
5
6 #ifdef ENABLE_NLS
7 # define  _(s) gettext (s)
8 # define N_(s) gettext_noop (s)
9 #else
10 # define  _(s) (s)
11 # define N_(s)  s
12 #endif
13
14
15 extern GtkWidget  *about;
16 extern GtkWidget  *GUI_Window;
17
18 extern char *programVersion;
19 extern int errorExitStatus;
20 extern int promotionUp;
21 extern int fromX;
22 extern int fromY;
23 extern int toX;
24 extern int toY;
25
26 void
27 QuitProc (object, user_data)
28      GtkObject *object;
29      gpointer user_data;
30 {
31   gtk_main_quit();
32   ExitEvent(0);
33 }
34
35 void AboutProc (object, user_data)
36      GtkObject *object;
37      gpointer user_data;
38 {
39   GtkWidget               *about;
40
41   const gchar *authors[] = {"Tim Mann <tim@tim-mann.org>",
42                             "John Chanak",
43                             "Evan Welsh <Evan.Welsh@msdw.com>",
44                             "Elmar Bartel <bartel@informatik.tu-muenchen.de>",
45                             "Jochen Wiedmann",
46                             "Frank McIngvale",
47                             "Hugh Fisher <Hugh.Fisher@cs.anu.edu.au>",
48                             "Allessandro Scotti",
49                             "H.G. Muller <h.g.muller AT hccnet DOT nl>",
50                             "Eric Mullins <emwine AT earthlink DOT net>",
51                             "Arun Persaud <arun@nubati.net>"};
52
53   /* set up about window */
54   about =  GTK_WIDGET(gtk_about_dialog_new());
55
56   /* fill in some information */
57   char buf[MSG_SIZ];
58 #if ZIPPY
59   char *zippy = " (with Zippy code)";
60 #else
61   char *zippy = "";
62 #endif
63   sprintf(buf, "%s%s",  programVersion, zippy);
64
65   gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),buf);
66
67   gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
68                                  "Copyright 1991 Digital Equipment Corporation\n"
69                                  "Enhancements Copyright 1992-2009 Free Software Foundation\n"
70                                  "Enhancements Copyright 2005 Alessandro Scotti");
71   gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),"http://www.gnu.org/software/xboard/");
72   gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about),authors);
73   gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about),
74                                           " A. Alper (turkish)\n"
75                                           " A. Persaud (german)\n");
76
77   /* end set up about window */
78   gtk_dialog_run(GTK_DIALOG (about));
79   gtk_widget_destroy(about);
80 }
81
82 void LoadNextGameProc(object, user_data)
83      GtkObject *object;
84      gpointer user_data;
85 {
86     ReloadGame(1);
87     return;
88 }
89
90 void LoadPrevGameProc(object, user_data)
91      GtkObject *object;
92      gpointer user_data;
93 {
94     ReloadGame(-1);
95     return;
96 }
97
98 void ReloadGameProc(object, user_data)
99      GtkObject *object;
100      gpointer user_data;
101 {
102     ReloadGame(0);
103     return;
104 }
105
106 void MachineWhiteProc(object, user_data)
107      GtkObject *object;
108      gpointer user_data;
109 {
110     MachineWhiteEvent();
111     return;
112 }
113
114 void MachineBlackProc(object, user_data)
115      GtkObject *object;
116      gpointer user_data;
117 {
118     MachineBlackEvent();
119     return;
120 }
121
122 void TwoMachinesProc(object, user_data)
123      GtkObject *object;
124      gpointer user_data;
125 {
126     TwoMachinesEvent();
127     return;
128 }
129
130 void AcceptProc(object, user_data)
131      GtkObject *object;
132      gpointer user_data;
133 {
134     AcceptEvent();
135     return;
136 }
137
138 void DeclineProc(object, user_data)
139      GtkObject *object;
140      gpointer user_data;
141 {
142     DeclineEvent();
143     return;
144 }
145
146 void RematchProc(object, user_data)
147      GtkObject *object;
148      gpointer user_data;
149 {
150     RematchEvent();
151     return;
152 }
153
154 void CallFlagProc(object, user_data)
155      GtkObject *object;
156      gpointer user_data;
157 {
158     CallFlagEvent();
159     return;
160 }
161
162 void DrawProc(object, user_data)
163      GtkObject *object;
164      gpointer user_data;
165 {
166     DrawEvent();
167     return;
168 }
169
170 void AbortProc(object, user_data)
171      GtkObject *object;
172      gpointer user_data;
173 {
174     AbortEvent();
175     return;
176 }
177
178 void AdjournProc(object, user_data)
179      GtkObject *object;
180      gpointer user_data;
181 {
182     AdjournEvent();
183     return;
184 }
185
186 void ResignProc(object, user_data)
187      GtkObject *object;
188      gpointer user_data;
189 {
190     ResignEvent();
191     return;
192 }
193
194
195 void MoveNowProc(object, user_data)
196      GtkObject *object;
197      gpointer user_data;
198 {
199     MoveNowEvent();
200     return;
201 }
202
203
204 gboolean CloseWindowProc(GtkWidget *button)
205 {
206     gtk_widget_destroy(gtk_widget_get_toplevel(button));
207     return TRUE;
208 }
209
210 void
211 ResetProc (object, user_data)
212      GtkObject *object;
213      gpointer user_data;
214 {
215   ResetGameEvent();
216   AnalysisPopDown();
217 }
218
219 void WhiteClockProc(object, user_data)
220      GtkObject *object;
221      gpointer user_data;
222 {
223     if (gameMode == EditPosition || gameMode == IcsExamining) {
224         SetWhiteToPlayEvent();
225     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
226         CallFlagEvent();
227     }
228 }
229
230 void BlackClockProc(object, user_data)
231      GtkObject *object;
232      gpointer user_data;
233 {
234     if (gameMode == EditPosition || gameMode == IcsExamining) {
235         SetBlackToPlayEvent();
236     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
237         CallFlagEvent();
238     }
239 }
240
241
242 void ShowCoordsProc(object, user_data)
243      GtkObject *object;
244      gpointer user_data;
245 {
246     appData.showCoords = !appData.showCoords;
247
248     DrawPosition(True, NULL);
249 }
250
251 void ErrorPopDownProc(object, user_data)
252      GtkObject *object;
253      gpointer user_data;
254 {
255   gtk_widget_destroy(GTK_WIDGET(object));
256   ErrorPopDown();
257 }
258
259 void PauseProc(object, user_data)
260      GtkObject *object;
261      gpointer user_data;
262 {
263     // todo this toggling of the pause button doesn't seem to work?
264     // e.g. select pause from buttonbar doesn't activate menumode.pause
265   PauseEvent();
266 }
267
268
269 void LoadGameProc(object, user_data)
270      GtkObject *object;
271      gpointer user_data;
272 {
273   GtkWidget *dialog;
274   dialog = gtk_file_chooser_dialog_new (_("Load game file name?"),
275                                         GTK_WINDOW(GUI_Window),
276                                         GTK_FILE_CHOOSER_ACTION_OPEN,
277                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
278                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
279                                         NULL);
280   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
281     {
282       char *filename;
283       FILE *f;
284
285       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
286
287       //see loadgamepopup
288       f = fopen(filename, "rb");
289       if (f == NULL) {
290         DisplayError(_("Failed to open file"), errno);
291       } else {
292         /* TODO add indec */
293         (void) LoadGamePopUp(f, 0, filename);
294       }
295       g_free (filename);
296     }
297   gtk_widget_destroy (dialog);
298   ModeHighlight();
299 }
300
301
302 /*************
303  * EVENTS
304  *************/
305
306 void EventProc(window, event, data)
307      GtkWindow *window;
308      GdkEvent *event;
309      gpointer data;
310 {
311   /* todo do we still need this?
312     if (!XtIsRealized(widget))
313       return;
314   */
315
316     switch (event->type) {
317       case GDK_EXPOSE:
318         if (event->expose.count > 0) return;  /* no clipping is done */
319         DrawPosition(True, NULL);
320         break;
321       default:
322         return;
323     }
324 }
325
326
327 /*
328  * event handler for parsing user moves
329  */
330 void UserMoveProc(window, event, data)
331      GtkWindow *window;
332      GdkEvent *event;
333      gpointer data;
334 {
335     int x, y;
336     Boolean saveAnimate;
337     static int second = 0;
338
339     if (errorExitStatus != -1) return;
340
341     if (event->type == GDK_BUTTON_PRESS) ErrorPopDown();
342
343     if (promotionUp)
344       {
345         if (event->type == GDK_BUTTON_PRESS)
346           {
347             /* todo add promotionshellwidget
348                XtPopdown(promotionShell);
349                XtDestroyWidget(promotionShell); */
350             promotionUp = False;
351             ClearHighlights();
352             fromX = fromY = -1;
353           }
354         else
355           {
356             return;
357           }
358       }
359
360     x = EventToSquare( (int)event->button.x, BOARD_WIDTH  );
361     y = EventToSquare( (int)event->button.y, BOARD_HEIGHT );
362     if (!flipView && y >= 0)
363       {
364         y = BOARD_HEIGHT - 1 - y;
365       }
366     if (flipView && x >= 0)
367       {
368         x = BOARD_WIDTH - 1 - x;
369       }
370
371     if (fromX == -1)
372       {
373         if (event->type == ButtonPress)
374           {
375             /* First square */
376             if (OKToStartUserMove(x, y))
377               {
378                 fromX = x;
379                 fromY = y;
380                 second = 0;
381                 DragPieceBegin(event->button.x, event->button.y);
382                 if (appData.highlightDragging)
383                   {
384                     SetHighlights(x, y, -1, -1);
385                   }
386               }
387           }
388         return;
389       }
390
391     /* fromX != -1 */
392     if (event->type == GDK_BUTTON_PRESS && gameMode != EditPosition &&
393         x >= 0 && y >= 0) {
394         ChessSquare fromP;
395         ChessSquare toP;
396         /* Check if clicking again on the same color piece */
397         fromP = boards[currentMove][fromY][fromX];
398         toP = boards[currentMove][y][x];
399         if ((WhitePawn <= fromP && fromP <= WhiteKing &&
400              WhitePawn <= toP && toP <= WhiteKing) ||
401             (BlackPawn <= fromP && fromP <= BlackKing &&
402              BlackPawn <= toP && toP <= BlackKing)) {
403             /* Clicked again on same color piece -- changed his mind */
404             second = (x == fromX && y == fromY);
405             if (appData.highlightDragging) {
406                 SetHighlights(x, y, -1, -1);
407             } else {
408                 ClearHighlights();
409             }
410             if (OKToStartUserMove(x, y)) {
411                 fromX = x;
412                 fromY = y;
413                 DragPieceBegin(event->button.x, event->button.y);
414             }
415             return;
416         }
417     }
418
419     if (event->type == GDK_BUTTON_RELEASE &&    x == fromX && y == fromY)
420       {
421         DragPieceEnd(event->button.x, event->button.y);
422         if (appData.animateDragging)
423           {
424             /* Undo animation damage if any */
425             DrawPosition(FALSE, NULL);
426           }
427         if (second)
428           {
429             /* Second up/down in same square; just abort move */
430             second = 0;
431             fromX = fromY = -1;
432             ClearHighlights();
433             gotPremove = 0;
434             ClearPremoveHighlights();
435           }
436         else
437           {
438             /* First upclick in same square; start click-click mode */
439             SetHighlights(x, y, -1, -1);
440           }
441         return;
442       }
443
444     /* Completed move */
445     toX = x;
446     toY = y;
447     saveAnimate = appData.animate;
448
449     if (event->type == GDK_BUTTON_PRESS)
450       {
451         /* Finish clickclick move */
452         if (appData.animate || appData.highlightLastMove)
453           {
454             SetHighlights(fromX, fromY, toX, toY);
455           }
456         else
457           {
458             ClearHighlights();
459           }
460       }
461     else
462       {
463         /* Finish drag move */
464         if (appData.highlightLastMove)
465           {
466             SetHighlights(fromX, fromY, toX, toY);
467           }
468         else
469           {
470             ClearHighlights();
471           }
472         DragPieceEnd(event->button.x, event->button.y);
473         /* Don't animate move and drag both */
474         appData.animate = FALSE;
475       }
476
477     if (IsPromotion(fromX, fromY, toX, toY))
478       {
479         if (appData.alwaysPromoteToQueen)
480           {
481             UserMoveEvent(fromX, fromY, toX, toY, 'q');
482             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
483             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
484             fromX = fromY = -1;
485           }
486         else
487           {
488             SetHighlights(fromX, fromY, toX, toY);
489             PromotionPopUp();
490           }
491       }
492     else
493       {
494         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
495
496         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
497         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
498         fromX = fromY = -1;
499       }
500
501     appData.animate = saveAnimate;
502     if (appData.animate || appData.animateDragging) {
503         /* Undo animation damage if needed */
504         DrawPosition(FALSE, NULL);
505     }
506
507     return;
508 }
509