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