removed X-version of buttonbar
[xboard.git] / callback.c
1 #include <gtk/gtk.h>
2 #include "common.h"
3 #include "xboard.h"
4 #include <errno.h>
5 #include "backend.h"
6
7 #ifdef ENABLE_NLS
8 # define  _(s) gettext (s)
9 # define N_(s) gettext_noop (s)
10 #else
11 # define  _(s) (s)
12 # define N_(s)  s
13 #endif
14
15 extern GtkWidget  *about;
16 extern GtkWidget  *GUI_Window;
17 extern GtkWidget  *GUI_Menubar;
18 extern GtkWidget  *GUI_Timer;
19 extern GtkWidget  *GUI_Buttonbar;
20 extern GtkWidget  *GUI_Board;
21
22 extern char *programVersion;
23 extern int errorExitStatus;
24 extern int promotionUp;
25 extern int fromX;
26 extern int fromY;
27 extern int toX;
28 extern int toY;
29 extern int squareSize,lineGap;
30
31 gboolean
32 ExposeProc(object, user_data)
33      GtkObject *object;
34      gpointer user_data;
35 {
36   /* do resizing to a fixed aspect ratio */
37   GtkRequisition w;
38   int totalh=0,nw,nh;
39   float ratio;
40   int boardWidth,boardHeight,old,new;
41   
42   nw=GTK_WIDGET(object)->allocation.width;
43   nh=GTK_WIDGET(object)->allocation.height;
44     
45   old=squareSize;
46   squareSize  = nw/(BOARD_WIDTH*1.05+0.05);
47
48   if(old!=squareSize)
49     {
50       lineGap = squareSize*0.05;
51       
52       boardWidth  = lineGap + BOARD_WIDTH  * (squareSize + lineGap);
53       boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
54       
55       /* get the height of the menus, etc. and calculate the aspect ratio */
56       gtk_widget_size_request(GTK_WIDGET(GUI_Menubar),   &w);
57       totalh += w.height;
58       gtk_widget_size_request(GTK_WIDGET(GUI_Timer),   &w);
59       totalh += w.height;
60       gtk_widget_size_request(GTK_WIDGET(GUI_Buttonbar),   &w);
61       totalh += w.height;
62       
63       ratio  = (totalh+boardHeight)/(boardWidth) ;
64             
65       gtk_widget_set_size_request(GTK_WIDGET(GUI_Board),
66                                   boardWidth,boardHeight);
67       
68       GUI_SetAspectRatio(ratio);
69       /* recreate pieces with new size... TODO: keep svg in memory and just recreate pixmap instead of reloading files */
70       CreatePieces();
71     } 
72   return FALSE; /* return false, so that other expose events are called too */
73 }
74
75 void
76 QuitProc (object, user_data)
77      GtkObject *object;
78      gpointer user_data;
79 {
80   gtk_main_quit();
81   ExitEvent(0);
82 }
83
84 /* Help Menu */
85 void InfoProc(object, user_data)
86      GtkObject *object;
87      gpointer user_data;
88 {
89     char buf[MSG_SIZ];
90     snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
91             INFODIR, INFOFILE);
92     system(buf);
93     return;
94 }
95
96 void ManProc(object, user_data)
97      GtkObject *object;
98      gpointer user_data;
99 {
100     char buf[MSG_SIZ];
101     snprintf(buf, sizeof(buf), "xterm -e man xboard &");
102     system(buf);
103     return;
104 }
105
106 void HintProc(object, user_data)
107      GtkObject *object;
108      gpointer user_data;
109 {
110     HintEvent();
111     return;
112 }
113
114 void BookProc(object, user_data)
115      GtkObject *object;
116      gpointer user_data;
117 {
118     BookEvent();
119     return;
120 }
121
122 void AboutProc (object, user_data)
123      GtkObject *object;
124      gpointer user_data;
125 {
126   GtkWidget               *about;
127
128   const gchar *authors[] = {"Tim Mann <tim@tim-mann.org>",
129                             "John Chanak",
130                             "Evan Welsh <Evan.Welsh@msdw.com>",
131                             "Elmar Bartel <bartel@informatik.tu-muenchen.de>",
132                             "Jochen Wiedmann",
133                             "Frank McIngvale",
134                             "Hugh Fisher <Hugh.Fisher@cs.anu.edu.au>",
135                             "Allessandro Scotti",
136                             "H.G. Muller <h.g.muller AT hccnet DOT nl>",
137                             "Eric Mullins <emwine AT earthlink DOT net>",
138                             "Arun Persaud <arun@nubati.net>"};
139
140   /* set up about window */
141   about =  GTK_WIDGET(gtk_about_dialog_new());
142
143   /* fill in some information */
144   char buf[MSG_SIZ];
145 #if ZIPPY
146   char *zippy = " (with Zippy code)";
147 #else
148   char *zippy = "";
149 #endif
150   sprintf(buf, "%s%s",  programVersion, zippy);
151
152   gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about),buf);
153
154   gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about),
155                                  "Copyright 1991 Digital Equipment Corporation\n"
156                                  "Enhancements Copyright 1992-2009 Free Software Foundation\n"
157                                  "Enhancements Copyright 2005 Alessandro Scotti");
158   gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about),"http://www.gnu.org/software/xboard/");
159   gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about),authors);
160   gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about),
161                                           " A. Alper (turkish)\n"
162                                           " A. Persaud (german)\n");
163
164   /* end set up about window */
165   gtk_dialog_run(GTK_DIALOG (about));
166   gtk_widget_destroy(about);
167 }
168
169 /* End Help Menu */
170
171 void IcsClientProc(object, user_data)
172      GtkObject *object;
173      gpointer user_data;
174 {
175     IcsClientEvent();
176     return;
177 }
178
179 /*
180  * File menu
181  */
182
183 void LoadNextGameProc(object, user_data)
184      GtkObject *object;
185      gpointer user_data;
186 {
187     ReloadGame(1);
188     return;
189 }
190
191 void LoadPrevGameProc(object, user_data)
192      GtkObject *object;
193      gpointer user_data;
194 {
195     ReloadGame(-1);
196     return;
197 }
198
199 void ReloadGameProc(object, user_data)
200      GtkObject *object;
201      gpointer user_data;
202 {
203     ReloadGame(0);
204     return;
205 }
206
207
208 void LoadNextPositionProc(object, user_data)
209      GtkObject *object;
210      gpointer user_data;
211 {
212     ReloadPosition(1);
213     return;
214 }
215
216 void LoadPrevPositionProc(object, user_data)
217      GtkObject *object;
218      gpointer user_data;
219 {
220     ReloadPosition(-1);
221     return;
222 }
223
224 void ReloadPositionProc(object, user_data)
225      GtkObject *object;
226      gpointer user_data;
227 {
228     ReloadPosition(0);
229     return;
230 }
231
232
233 /* End File Menu */
234
235 void MachineWhiteProc(object, user_data)
236      GtkObject *object;
237      gpointer user_data;
238 {
239     MachineWhiteEvent();
240     return;
241 }
242
243 void MachineBlackProc(object, user_data)
244      GtkObject *object;
245      gpointer user_data;
246 {
247     MachineBlackEvent();
248     return;
249 }
250
251 void TwoMachinesProc(object, user_data)
252      GtkObject *object;
253      gpointer user_data;
254 {
255     TwoMachinesEvent();
256     return;
257 }
258
259 void AcceptProc(object, user_data)
260      GtkObject *object;
261      gpointer user_data;
262 {
263     AcceptEvent();
264     return;
265 }
266
267 void DeclineProc(object, user_data)
268      GtkObject *object;
269      gpointer user_data;
270 {
271     DeclineEvent();
272     return;
273 }
274
275 void RematchProc(object, user_data)
276      GtkObject *object;
277      gpointer user_data;
278 {
279     RematchEvent();
280     return;
281 }
282
283 void CallFlagProc(object, user_data)
284      GtkObject *object;
285      gpointer user_data;
286 {
287     CallFlagEvent();
288     return;
289 }
290
291 void DrawProc(object, user_data)
292      GtkObject *object;
293      gpointer user_data;
294 {
295     DrawEvent();
296     return;
297 }
298
299 void AbortProc(object, user_data)
300      GtkObject *object;
301      gpointer user_data;
302 {
303     AbortEvent();
304     return;
305 }
306
307 void AdjournProc(object, user_data)
308      GtkObject *object;
309      gpointer user_data;
310 {
311     AdjournEvent();
312     return;
313 }
314
315 void ResignProc(object, user_data)
316      GtkObject *object;
317      gpointer user_data;
318 {
319     ResignEvent();
320     return;
321 }
322
323 void StopObservingProc(object, user_data)
324      GtkObject *object;
325      gpointer user_data;
326 {
327     StopObservingEvent();
328     return;
329 }
330
331 void StopExaminingProc(object, user_data)
332      GtkObject *object;
333      gpointer user_data;
334 {
335     StopExaminingEvent();
336     return;
337 }
338
339 void AdjuWhiteProc(object, user_data)
340      GtkObject *object;
341      gpointer user_data;
342 {
343     UserAdjudicationEvent(+1);
344     return;
345 }
346
347 void AdjuBlackProc(object, user_data)
348      GtkObject *object;
349      gpointer user_data;
350 {
351     UserAdjudicationEvent(-1);
352     return;
353 }
354
355 void AdjuDrawProc(object, user_data)
356      GtkObject *object;
357      gpointer user_data;
358 {
359     UserAdjudicationEvent(0);
360     return;
361 }
362
363 void BackwardProc(object, user_data)
364      GtkObject *object;
365      gpointer user_data;
366 {
367     BackwardEvent();
368     return;
369 }
370
371 void ForwardProc(object, user_data)
372      GtkObject *object;
373      gpointer user_data;
374 {
375     ForwardEvent();
376     return;
377 }
378
379 void ToStartProc(object, user_data)
380      GtkObject *object;
381      gpointer user_data;
382 {
383     ToStartEvent();
384     return;
385 }
386
387 void ToEndProc(object, user_data)
388      GtkObject *object;
389      gpointer user_data;
390 {
391     ToEndEvent();
392     return;
393 }
394
395 void RevertProc(object, user_data)
396      GtkObject *object;
397      gpointer user_data;
398 {
399     RevertEvent();
400     return;
401 }
402
403 void TruncateGameProc(object, user_data)
404      GtkObject *object;
405      gpointer user_data;
406 {
407     TruncateGameEvent();
408     return;
409 }
410
411 void MoveNowProc(object, user_data)
412      GtkObject *object;
413      gpointer user_data;
414 {
415     MoveNowEvent();
416     return;
417 }
418
419 void RetractMoveProc(object, user_data)
420      GtkObject *object;
421      gpointer user_data;
422 {
423     RetractMoveEvent();
424     return;
425 }
426
427 /* Option Menu */
428 void ShowThinkingProc(object, user_data)
429      GtkObject *object;
430      gpointer user_data;
431 {
432     appData.showThinking = !appData.showThinking; 
433     ShowThinkingEvent();
434
435     return;
436 }
437
438 void HideThinkingProc(object, user_data)
439      GtkObject *object;
440      gpointer user_data;
441 {
442     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman;
443     ShowThinkingEvent();
444
445     return;
446 }
447
448 void FlipViewProc(object, user_data)
449      GtkObject *object;
450      gpointer user_data;
451 {
452     flipView = !flipView;
453     DrawPosition(True, NULL);
454     return;
455 }
456
457
458 gboolean CloseWindowProc(GtkWidget *button)
459 {
460     gtk_widget_destroy(gtk_widget_get_toplevel(button));
461     return TRUE;
462 }
463
464 void
465 ResetProc (object, user_data)
466      GtkObject *object;
467      gpointer user_data;
468 {
469   ResetGameEvent();
470   AnalysisPopDown();
471 }
472
473 void WhiteClockProc(object, user_data)
474      GtkObject *object;
475      gpointer user_data;
476 {
477     if (gameMode == EditPosition || gameMode == IcsExamining) {
478         SetWhiteToPlayEvent();
479     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
480         CallFlagEvent();
481     }
482 }
483
484 void BlackClockProc(object, user_data)
485      GtkObject *object;
486      gpointer user_data;
487 {
488     if (gameMode == EditPosition || gameMode == IcsExamining) {
489         SetBlackToPlayEvent();
490     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
491         CallFlagEvent();
492     }
493 }
494
495
496 void ShowCoordsProc(object, user_data)
497      GtkObject *object;
498      gpointer user_data;
499 {
500     appData.showCoords = !appData.showCoords;
501
502     DrawPosition(True, NULL);
503 }
504
505 void ErrorPopDownProc(object, user_data)
506      GtkObject *object;
507      gpointer user_data;
508 {
509   gtk_widget_destroy(GTK_WIDGET(object));
510   ErrorPopDown();
511 }
512
513 void PauseProc(object, user_data)
514      GtkObject *object;
515      gpointer user_data;
516 {
517     // todo this toggling of the pause button doesn't seem to work?
518     // e.g. select pause from buttonbar doesn't activate menumode.pause
519   PauseEvent();
520 }
521
522
523 void LoadGameProc(object, user_data)
524      GtkObject *object;
525      gpointer user_data;
526 {
527   GtkWidget *dialog;
528   dialog = gtk_file_chooser_dialog_new (_("Load game file name?"),
529                                         GTK_WINDOW(GUI_Window),
530                                         GTK_FILE_CHOOSER_ACTION_OPEN,
531                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
532                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
533                                         NULL);
534   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
535     {
536       char *filename;
537       FILE *f;
538
539       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
540
541       //see loadgamepopup
542       f = fopen(filename, "rb");
543       if (f == NULL) 
544         {
545           DisplayError(_("Failed to open file"), errno);
546         }
547       else 
548         {
549           /* TODO add indec */
550           (void) LoadGamePopUp(f, 0, filename);
551         }
552       g_free (filename);
553     };
554   
555   gtk_widget_destroy (dialog);
556   ModeHighlight();
557   
558   return;
559 }
560
561
562 /*************
563  * EVENTS
564  *************/
565
566 void EventProc(window, event, data)
567      GtkWindow *window;
568      GdkEvent *event;
569      gpointer data;
570 {
571   /* todo do we still need this?
572     if (!XtIsRealized(widget))
573       return;
574   */
575
576     switch (event->type) {
577       case GDK_EXPOSE:
578         if (event->expose.count > 0) return;  /* no clipping is done */
579         DrawPosition(True, NULL);
580         break;
581       default:
582         return;
583     }
584 }
585
586
587 /*
588  * event handler for parsing user moves
589  */
590 void UserMoveProc(window, event, data)
591      GtkWindow *window;
592      GdkEvent *event;
593      gpointer data;
594 {
595     int x, y;
596     Boolean saveAnimate;
597     static int second = 0;
598
599     if (errorExitStatus != -1) return;
600
601     if (event->type == GDK_BUTTON_PRESS) ErrorPopDown();
602
603     if (promotionUp)
604       {
605         if (event->type == GDK_BUTTON_PRESS)
606           {
607             /* todo add promotionshellwidget
608                XtPopdown(promotionShell);
609                XtDestroyWidget(promotionShell); */
610             promotionUp = False;
611             ClearHighlights();
612             fromX = fromY = -1;
613           }
614         else
615           {
616             return;
617           }
618       }
619
620     x = EventToSquare( (int)event->button.x, BOARD_WIDTH  );
621     y = EventToSquare( (int)event->button.y, BOARD_HEIGHT );
622     if (!flipView && y >= 0)
623       {
624         y = BOARD_HEIGHT - 1 - y;
625       }
626     if (flipView && x >= 0)
627       {
628         x = BOARD_WIDTH - 1 - x;
629       }
630
631     if (fromX == -1)
632       {
633         if (event->type == ButtonPress)
634           {
635             /* First square */
636             if (OKToStartUserMove(x, y))
637               {
638                 fromX = x;
639                 fromY = y;
640                 second = 0;
641                 DragPieceBegin(event->button.x, event->button.y);
642                 if (appData.highlightDragging)
643                   {
644                     SetHighlights(x, y, -1, -1);
645                   }
646               }
647           }
648         return;
649       }
650
651     /* fromX != -1 */
652     if (event->type == GDK_BUTTON_PRESS && gameMode != EditPosition &&
653         x >= 0 && y >= 0) {
654         ChessSquare fromP;
655         ChessSquare toP;
656         /* Check if clicking again on the same color piece */
657         fromP = boards[currentMove][fromY][fromX];
658         toP = boards[currentMove][y][x];
659         if ((WhitePawn <= fromP && fromP <= WhiteKing &&
660              WhitePawn <= toP && toP <= WhiteKing) ||
661             (BlackPawn <= fromP && fromP <= BlackKing &&
662              BlackPawn <= toP && toP <= BlackKing)) {
663             /* Clicked again on same color piece -- changed his mind */
664             second = (x == fromX && y == fromY);
665             if (appData.highlightDragging) {
666                 SetHighlights(x, y, -1, -1);
667             } else {
668                 ClearHighlights();
669             }
670             if (OKToStartUserMove(x, y)) {
671                 fromX = x;
672                 fromY = y;
673                 DragPieceBegin(event->button.x, event->button.y);
674             }
675             return;
676         }
677     }
678
679     if (event->type == GDK_BUTTON_RELEASE &&    x == fromX && y == fromY)
680       {
681         DragPieceEnd(event->button.x, event->button.y);
682         if (appData.animateDragging)
683           {
684             /* Undo animation damage if any */
685             DrawPosition(FALSE, NULL);
686           }
687         if (second)
688           {
689             /* Second up/down in same square; just abort move */
690             second = 0;
691             fromX = fromY = -1;
692             ClearHighlights();
693             gotPremove = 0;
694             ClearPremoveHighlights();
695           }
696         else
697           {
698             /* First upclick in same square; start click-click mode */
699             SetHighlights(x, y, -1, -1);
700           }
701         return;
702       }
703
704     /* Completed move */
705     toX = x;
706     toY = y;
707     saveAnimate = appData.animate;
708
709     if (event->type == GDK_BUTTON_PRESS)
710       {
711         /* Finish clickclick move */
712         if (appData.animate || appData.highlightLastMove)
713           {
714             SetHighlights(fromX, fromY, toX, toY);
715           }
716         else
717           {
718             ClearHighlights();
719           }
720       }
721     else
722       {
723         /* Finish drag move */
724         if (appData.highlightLastMove)
725           {
726             SetHighlights(fromX, fromY, toX, toY);
727           }
728         else
729           {
730             ClearHighlights();
731           }
732         DragPieceEnd(event->button.x, event->button.y);
733         /* Don't animate move and drag both */
734         appData.animate = FALSE;
735       }
736
737     if (IsPromotion(fromX, fromY, toX, toY))
738       {
739         if (appData.alwaysPromoteToQueen)
740           {
741             UserMoveEvent(fromX, fromY, toX, toY, 'q');
742             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
743             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
744             fromX = fromY = -1;
745           }
746         else
747           {
748             SetHighlights(fromX, fromY, toX, toY);
749             PromotionPopUp();
750           }
751       }
752     else
753       {
754         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
755
756         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
757         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
758         fromX = fromY = -1;
759       }
760
761     appData.animate = saveAnimate;
762     if (appData.animate || appData.animateDragging) {
763         /* Undo animation damage if needed */
764         DrawPosition(FALSE, NULL);
765     }
766
767     return;
768 }
769
770 void GetMoveListProc(object, user_data)
771      GtkObject *object;
772      gpointer user_data;
773 {
774   appData.getMoveList = !appData.getMoveList;
775   
776   if (appData.getMoveList) 
777     {
778       GetMoveListEvent();
779     } 
780
781   // gets set automatically? if we set it with set_active we end up in an endless loop switching between 0 and 1
782   //  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (object),(gboolean) appData.getMoveList );
783   
784   return;
785 }