Merge branch 'master' into gtk
[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 AutocommProc(object, user_data)
429      GtkObject *object;
430      gpointer user_data;
431 {
432     appData.autoComment = !appData.autoComment;
433     return;
434 }
435
436 void AutoflagProc(object, user_data)
437      GtkObject *object;
438      gpointer user_data;
439 {
440     appData.autoCallFlag = !appData.autoCallFlag;
441     return;
442 }
443
444 void AutoflipProc(object, user_data)
445      GtkObject *object;
446      gpointer user_data;
447 {
448     appData.autoFlipView = !appData.autoFlipView;
449     return;
450 }
451
452 void ShowThinkingProc(object, user_data)
453      GtkObject *object;
454      gpointer user_data;
455 {
456     appData.showThinking = !appData.showThinking; 
457     ShowThinkingEvent();
458
459     return;
460 }
461
462 void HideThinkingProc(object, user_data)
463      GtkObject *object;
464      gpointer user_data;
465 {
466     appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman;
467     ShowThinkingEvent();
468
469     return;
470 }
471
472 void FlipViewProc(object, user_data)
473      GtkObject *object;
474      gpointer user_data;
475 {
476     flipView = !flipView;
477     DrawPosition(True, NULL);
478     return;
479 }
480
481
482 gboolean CloseWindowProc(GtkWidget *button)
483 {
484     gtk_widget_destroy(gtk_widget_get_toplevel(button));
485     return TRUE;
486 }
487
488 void
489 ResetProc (object, user_data)
490      GtkObject *object;
491      gpointer user_data;
492 {
493   ResetGameEvent();
494   EngineOutputPopDown();
495 }
496
497 void WhiteClockProc(object, user_data)
498      GtkObject *object;
499      gpointer user_data;
500 {
501     if (gameMode == EditPosition || gameMode == IcsExamining) {
502         SetWhiteToPlayEvent();
503     } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
504         CallFlagEvent();
505     }
506 }
507
508 void BlackClockProc(object, user_data)
509      GtkObject *object;
510      gpointer user_data;
511 {
512     if (gameMode == EditPosition || gameMode == IcsExamining) {
513         SetBlackToPlayEvent();
514     } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
515         CallFlagEvent();
516     }
517 }
518
519
520 void ShowCoordsProc(object, user_data)
521      GtkObject *object;
522      gpointer user_data;
523 {
524     appData.showCoords = !appData.showCoords;
525
526     DrawPosition(True, NULL);
527 }
528
529 void ErrorPopDownProc(object, user_data)
530      GtkObject *object;
531      gpointer user_data;
532 {
533   gtk_widget_destroy(GTK_WIDGET(object));
534   ErrorPopDown();
535 }
536
537 void PauseProc(object, user_data)
538      GtkObject *object;
539      gpointer user_data;
540 {
541     // todo this toggling of the pause button doesn't seem to work?
542     // e.g. select pause from buttonbar doesn't activate menumode.pause
543   PauseEvent();
544 }
545
546
547 void LoadGameProc(object, user_data)
548      GtkObject *object;
549      gpointer user_data;
550 {
551   GtkWidget *dialog;
552   dialog = gtk_file_chooser_dialog_new (_("Load game file name?"),
553                                         GTK_WINDOW(GUI_Window),
554                                         GTK_FILE_CHOOSER_ACTION_OPEN,
555                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
556                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
557                                         NULL);
558   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
559     {
560       char *filename;
561       FILE *f;
562
563       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
564
565       //see loadgamepopup
566       f = fopen(filename, "rb");
567       if (f == NULL) 
568         {
569           DisplayError(_("Failed to open file"), errno);
570         }
571       else 
572         {
573           /* TODO add indec */
574           (void) LoadGamePopUp(f, 0, filename);
575         }
576       g_free (filename);
577     };
578   
579   gtk_widget_destroy (dialog);
580   ModeHighlight();
581   
582   return;
583 }
584
585
586 /*************
587  * EVENTS
588  *************/
589
590 void EventProc(window, event, data)
591      GtkWindow *window;
592      GdkEvent *event;
593      gpointer data;
594 {
595   /* todo do we still need this?
596     if (!XtIsRealized(widget))
597       return;
598   */
599
600     switch (event->type) {
601       case GDK_EXPOSE:
602         if (event->expose.count > 0) return;  /* no clipping is done */
603         DrawPosition(True, NULL);
604         break;
605       default:
606         return;
607     }
608 }
609
610
611 /*
612  * event handler for parsing user moves
613  */
614 void UserMoveProc(window, event, data)
615      GtkWindow *window;
616      GdkEvent *event;
617      gpointer data;
618 {
619     int x, y;
620     Boolean saveAnimate;
621     static int second = 0;
622
623     if (errorExitStatus != -1) return;
624
625     if (event->type == GDK_BUTTON_PRESS) ErrorPopDown();
626
627     if (promotionUp)
628       {
629         if (event->type == GDK_BUTTON_PRESS)
630           {
631             /* todo add promotionshellwidget
632                XtPopdown(promotionShell);
633                XtDestroyWidget(promotionShell); */
634             promotionUp = False;
635             ClearHighlights();
636             fromX = fromY = -1;
637           }
638         else
639           {
640             return;
641           }
642       }
643
644     x = EventToSquare( (int)event->button.x, BOARD_WIDTH  );
645     y = EventToSquare( (int)event->button.y, BOARD_HEIGHT );
646     if (!flipView && y >= 0)
647       {
648         y = BOARD_HEIGHT - 1 - y;
649       }
650     if (flipView && x >= 0)
651       {
652         x = BOARD_WIDTH - 1 - x;
653       }
654
655     if (fromX == -1)
656       {
657         if (event->type == ButtonPress)
658           {
659             /* First square */
660             if (OKToStartUserMove(x, y))
661               {
662                 fromX = x;
663                 fromY = y;
664                 second = 0;
665                 DragPieceBegin(event->button.x, event->button.y);
666                 if (appData.highlightDragging)
667                   {
668                     SetHighlights(x, y, -1, -1);
669                   }
670               }
671           }
672         return;
673       }
674
675     /* fromX != -1 */
676     if (event->type == GDK_BUTTON_PRESS && gameMode != EditPosition &&
677         x >= 0 && y >= 0) {
678         ChessSquare fromP;
679         ChessSquare toP;
680         /* Check if clicking again on the same color piece */
681         fromP = boards[currentMove][fromY][fromX];
682         toP = boards[currentMove][y][x];
683         if ((WhitePawn <= fromP && fromP <= WhiteKing &&
684              WhitePawn <= toP && toP <= WhiteKing) ||
685             (BlackPawn <= fromP && fromP <= BlackKing &&
686              BlackPawn <= toP && toP <= BlackKing)) {
687             /* Clicked again on same color piece -- changed his mind */
688             second = (x == fromX && y == fromY);
689             if (appData.highlightDragging) {
690                 SetHighlights(x, y, -1, -1);
691             } else {
692                 ClearHighlights();
693             }
694             if (OKToStartUserMove(x, y)) {
695                 fromX = x;
696                 fromY = y;
697                 DragPieceBegin(event->button.x, event->button.y);
698             }
699             return;
700         }
701     }
702
703     if (event->type == GDK_BUTTON_RELEASE &&    x == fromX && y == fromY)
704       {
705         DragPieceEnd(event->button.x, event->button.y);
706         if (appData.animateDragging)
707           {
708             /* Undo animation damage if any */
709             DrawPosition(FALSE, NULL);
710           }
711         if (second)
712           {
713             /* Second up/down in same square; just abort move */
714             second = 0;
715             fromX = fromY = -1;
716             ClearHighlights();
717             gotPremove = 0;
718             ClearPremoveHighlights();
719           }
720         else
721           {
722             /* First upclick in same square; start click-click mode */
723             SetHighlights(x, y, -1, -1);
724           }
725         return;
726       }
727
728     /* Completed move */
729     toX = x;
730     toY = y;
731     saveAnimate = appData.animate;
732
733     if (event->type == GDK_BUTTON_PRESS)
734       {
735         /* Finish clickclick move */
736         if (appData.animate || appData.highlightLastMove)
737           {
738             SetHighlights(fromX, fromY, toX, toY);
739           }
740         else
741           {
742             ClearHighlights();
743           }
744       }
745     else
746       {
747         /* Finish drag move */
748         if (appData.highlightLastMove)
749           {
750             SetHighlights(fromX, fromY, toX, toY);
751           }
752         else
753           {
754             ClearHighlights();
755           }
756         DragPieceEnd(event->button.x, event->button.y);
757         /* Don't animate move and drag both */
758         appData.animate = FALSE;
759       }
760
761     if (IsPromotion(fromX, fromY, toX, toY))
762       {
763         if (appData.alwaysPromoteToQueen)
764           {
765             UserMoveEvent(fromX, fromY, toX, toY, 'q');
766             if (!appData.highlightLastMove || gotPremove) ClearHighlights();
767             if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
768             fromX = fromY = -1;
769           }
770         else
771           {
772             SetHighlights(fromX, fromY, toX, toY);
773             PromotionPopUp();
774           }
775       }
776     else
777       {
778         UserMoveEvent(fromX, fromY, toX, toY, NULLCHAR);
779
780         if (!appData.highlightLastMove || gotPremove) ClearHighlights();
781         if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
782         fromX = fromY = -1;
783       }
784
785     appData.animate = saveAnimate;
786     if (appData.animate || appData.animateDragging) {
787         /* Undo animation damage if needed */
788         DrawPosition(FALSE, NULL);
789     }
790
791     return;
792 }
793
794 void GetMoveListProc(object, user_data)
795      GtkObject *object;
796      gpointer user_data;
797 {
798   appData.getMoveList = !appData.getMoveList;
799   
800   if (appData.getMoveList) 
801     {
802       GetMoveListEvent();
803     } 
804
805   // gets set automatically? if we set it with set_active we end up in an endless loop switching between 0 and 1
806   //  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (object),(gboolean) appData.getMoveList );
807   
808   return;
809 }