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