2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
190 #include <gdk-pixbuf/gdk-pixbuf.h>
192 #include "bitmaps/icon_white.bm"
193 #include "bitmaps/icon_black.bm"
194 #include "bitmaps/checkmark.bm"
196 #include "frontend.h"
201 #include "xgamelist.h"
202 #include "xhistory.h"
203 #include "xedittags.h"
205 #include "callback.h"
206 #include "interface.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
248 int main P((int argc, char **argv));
249 RETSIGTYPE CmailSigHandler P((int sig));
250 RETSIGTYPE IntSigHandler P((int sig));
251 RETSIGTYPE TermSizeSigHandler P((int sig));
252 void CreateGCs P((void));
253 void CreateXIMPieces P((void));
254 void CreateXPMPieces P((void));
255 void CreatePieces P((void));
256 void CreatePieceMenus P((void));
257 Widget CreateMenuBar P((Menu *mb));
258 char *FindFont P((char *pattern, int targetPxlSize));
259 void PieceMenuPopup P((Widget w, XEvent *event,
260 String *params, Cardinal *num_params));
261 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
262 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
263 int EventToSquare P((int x, int limit));
264 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
265 void AnimateUserMove P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void HandlePV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void CommentPopUp P((char *title, char *label));
270 void CommentPopDown P((void));
271 void CommentCallback P((Widget w, XtPointer client_data,
272 XtPointer call_data));
273 void ICSInputBoxPopUp P((void));
274 void ICSInputBoxPopDown P((void));
275 void AskQuestionReplyAction P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void AskQuestionProc P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void AskQuestionPopDown P((void));
280 void PromotionPopDown P((void));
281 void PromotionCallback P((Widget w, XtPointer client_data,
282 XtPointer call_data));
283 void EditCommentPopDown P((void));
284 void EditCommentCallback P((Widget w, XtPointer client_data,
285 XtPointer call_data));
286 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
287 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
289 void PastePositionProc P((Widget w, XEvent *event, String *prms,
291 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
296 void EditCommentProc P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void IcsInputBoxProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
301 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
302 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
303 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
304 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void DisplayMove P((int moveNumber));
308 void DisplayTitle P((char *title));
309 void ICSInitScript P((void));
310 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
311 void ErrorPopUp P((char *title, char *text, int modal));
312 void ErrorPopDown P((void));
313 static char *ExpandPathName P((char *path));
314 static void CreateAnimVars P((void));
315 static void DragPieceMove P((int x, int y));
316 static void DrawDragPiece P((void));
317 char *ModeToWidgetName P((GameMode mode));
318 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
323 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void GameListOptionsPopDown P(());
327 void PromoPopDown P(());
328 void ShufflePopDown P(());
329 void EnginePopDown P(());
330 void UciPopDown P(());
331 void TimeControlPopDown P(());
332 void NewVariantPopDown P(());
333 void SettingsPopDown P(());
334 void SetMenuEnables P((Enables *enab));
335 void update_ics_width P(());
336 int get_term_width P(());
337 int CopyMemoProc P(());
339 * XBoard depends on Xt R4 or higher
341 int xtVersion = XtSpecificationRelease;
346 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
347 jailSquareColor, highlightSquareColor, premoveHighlightColor;
348 Pixel lowTimeWarningColor;
350 #define LINE_TYPE_NORMAL 0
351 #define LINE_TYPE_HIGHLIGHT 1
352 #define LINE_TYPE_PRE 2
355 GC lightSquareGC, darkSquareGC, jailSquareGC, wdPieceGC, wlPieceGC,
356 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC,
357 wjPieceGC, bjPieceGC;
358 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
359 Widget layoutWidget, formWidget, boardWidget, messageWidget,
360 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
361 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
362 menuBarWidget, editShell, errorShell, analysisShell,
363 ICSInputShell, fileNameShell, askQuestionShell;
365 Widget evalGraphShell, gameListShell;
366 //XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
367 //XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
369 Font clockFontID, coordFontID, countFontID;
370 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
371 XtAppContext appContext;
373 char *oldICSInteractionTitle;
377 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
379 Position commentX = -1, commentY = -1;
380 Dimension commentW, commentH;
381 typedef unsigned int BoardSize;
383 Boolean chessProgram;
385 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
386 int squareSize, smallLayout = 0, tinyLayout = 0,
387 marginW, marginH, // [HGM] for run-time resizing
388 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
389 ICSInputBoxUp = False, askQuestionUp = False,
390 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
391 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
392 Pixel timerForegroundPixel, timerBackgroundPixel;
393 Pixel buttonForegroundPixel, buttonBackgroundPixel;
394 char *chessDir, *programName, *programVersion,
395 *gameCopyFilename, *gamePasteFilename;
396 Boolean alwaysOnTop = False;
397 Boolean saveSettingsOnExit;
398 char *settingsFileName;
399 char *icsTextMenuString;
401 char *firstChessProgramNames;
402 char *secondChessProgramNames;
404 WindowPlacement wpMain;
405 WindowPlacement wpConsole;
406 WindowPlacement wpComment;
407 WindowPlacement wpMoveHistory;
408 WindowPlacement wpEvalGraph;
409 WindowPlacement wpEngineOutput;
410 WindowPlacement wpGameList;
411 WindowPlacement wpTags;
415 Pixmap pieceBitmap[2][(int)BlackPawn];
416 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
417 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
418 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
419 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
420 int useImages=0, useImageSqs;
421 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
422 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
423 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
424 XImage *ximLightSquare, *ximDarkSquare;
427 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
428 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
430 #define White(piece) ((int)(piece) < (int)BlackPawn)
432 /* Variables for doing smooth animation. This whole thing
433 would be much easier if the board was double-buffered,
434 but that would require a fairly major rewrite. */
439 GC blitGC, pieceGC, outlineGC;
440 XPoint startSquare, prevFrame, mouseDelta;
444 int startBoardX, startBoardY;
447 /* There can be two pieces being animated at once: a player
448 can begin dragging a piece before the remote opponent has moved. */
450 static AnimState game, player;
452 /* Bitmaps for use as masks when drawing XPM pieces.
453 Need one for each black and white piece. */
454 static Pixmap xpmMask[BlackKing + 1];
456 /* This magic number is the number of intermediate frames used
457 in each half of the animation. For short moves it's reduced
458 by 1. The total number of frames will be factor * 2 + 1. */
461 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
463 Enables icsEnables[] = {
464 { "menuFile.Mail Move", False },
465 { "menuFile.Reload CMail Message", False },
466 { "menuMode.Machine Black", False },
467 { "menuMode.Machine White", False },
468 { "menuMode.Analysis Mode", False },
469 { "menuMode.Analyze File", False },
470 { "menuMode.Two Machines", False },
472 { "menuHelp.Hint", False },
473 { "menuHelp.Book", False },
474 { "menuStep.Move Now", False },
475 { "menuOptions.Periodic Updates", False },
476 { "menuOptions.Hide Thinking", False },
477 { "menuOptions.Ponder Next Move", False },
482 Enables ncpEnables[] = {
483 { "menuFile.Mail Move", False },
484 { "menuFile.Reload CMail Message", False },
485 { "menuMode.Machine White", False },
486 { "menuMode.Machine Black", False },
487 { "menuMode.Analysis Mode", False },
488 { "menuMode.Analyze File", False },
489 { "menuMode.Two Machines", False },
490 { "menuMode.ICS Client", False },
491 { "menuMode.ICS Input Box", False },
493 { "menuStep.Revert", False },
494 { "menuStep.Move Now", False },
495 { "menuStep.Retract Move", False },
496 { "menuOptions.Auto Comment", False },
497 { "menuOptions.Auto Flag", False },
498 { "menuOptions.Auto Flip View", False },
499 { "menuOptions.Auto Observe", False },
500 { "menuOptions.Auto Raise Board", False },
501 { "menuOptions.Get Move List", False },
502 { "menuOptions.ICS Alarm", False },
503 { "menuOptions.Move Sound", False },
504 { "menuOptions.Quiet Play", False },
505 { "menuOptions.Hide Thinking", False },
506 { "menuOptions.Periodic Updates", False },
507 { "menuOptions.Ponder Next Move", False },
508 { "menuHelp.Hint", False },
509 { "menuHelp.Book", False },
513 Enables gnuEnables[] = {
514 { "menuMode.ICS Client", False },
515 { "menuMode.ICS Input Box", False },
516 { "menuAction.Accept", False },
517 { "menuAction.Decline", False },
518 { "menuAction.Rematch", False },
519 { "menuAction.Adjourn", False },
520 { "menuAction.Stop Examining", False },
521 { "menuAction.Stop Observing", False },
522 { "menuStep.Revert", False },
523 { "menuOptions.Auto Comment", False },
524 { "menuOptions.Auto Observe", False },
525 { "menuOptions.Auto Raise Board", False },
526 { "menuOptions.Get Move List", False },
527 { "menuOptions.Premove", False },
528 { "menuOptions.Quiet Play", False },
530 /* The next two options rely on SetCmailMode being called *after* */
531 /* SetGNUMode so that when GNU is being used to give hints these */
532 /* menu options are still available */
534 { "menuFile.Mail Move", False },
535 { "menuFile.Reload CMail Message", False },
539 Enables cmailEnables[] = {
541 { "menuAction.Call Flag", False },
542 { "menuAction.Draw", True },
543 { "menuAction.Adjourn", False },
544 { "menuAction.Abort", False },
545 { "menuAction.Stop Observing", False },
546 { "menuAction.Stop Examining", False },
547 { "menuFile.Mail Move", True },
548 { "menuFile.Reload CMail Message", True },
552 Enables trainingOnEnables[] = {
553 { "menuMode.Edit Comment", False },
554 { "menuMode.Pause", False },
555 { "menuStep.Forward", False },
556 { "menuStep.Backward", False },
557 { "menuStep.Forward to End", False },
558 { "menuStep.Back to Start", False },
559 { "menuStep.Move Now", False },
560 { "menuStep.Truncate Game", False },
564 Enables trainingOffEnables[] = {
565 { "menuMode.Edit Comment", True },
566 { "menuMode.Pause", True },
567 { "menuStep.Forward", True },
568 { "menuStep.Backward", True },
569 { "menuStep.Forward to End", True },
570 { "menuStep.Back to Start", True },
571 { "menuStep.Move Now", True },
572 { "menuStep.Truncate Game", True },
576 Enables machineThinkingEnables[] = {
577 { "menuFile.Load Game", False },
578 { "menuFile.Load Next Game", False },
579 { "menuFile.Load Previous Game", False },
580 { "menuFile.Reload Same Game", False },
581 { "menuFile.Paste Game", False },
582 { "menuFile.Load Position", False },
583 { "menuFile.Load Next Position", False },
584 { "menuFile.Load Previous Position", False },
585 { "menuFile.Reload Same Position", False },
586 { "menuFile.Paste Position", False },
587 { "menuMode.Machine White", False },
588 { "menuMode.Machine Black", False },
589 { "menuMode.Two Machines", False },
590 { "menuStep.Retract Move", False },
594 Enables userThinkingEnables[] = {
595 { "menuFile.Load Game", True },
596 { "menuFile.Load Next Game", True },
597 { "menuFile.Load Previous Game", True },
598 { "menuFile.Reload Same Game", True },
599 { "menuFile.Paste Game", True },
600 { "menuFile.Load Position", True },
601 { "menuFile.Load Next Position", True },
602 { "menuFile.Load Previous Position", True },
603 { "menuFile.Reload Same Position", True },
604 { "menuFile.Paste Position", True },
605 { "menuMode.Machine White", True },
606 { "menuMode.Machine Black", True },
607 { "menuMode.Two Machines", True },
608 { "menuStep.Retract Move", True },
614 MenuItem fileMenu[] = {
615 {N_("New Shuffle Game ..."), ShuffleMenuProc},
616 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
617 // {"----", NothingProc},
618 // {N_("Save Game"), SaveGameProc},
619 // {"----", NothingProc},
620 {N_("Copy Game"), CopyGameProc},
621 {N_("Paste Game"), PasteGameProc},
622 // {"----", NothingProc},
623 // {N_("Load Position"), LoadPositionProc},
624 // {N_("Load Next Position"), LoadNextPositionProc},
625 // {N_("Load Previous Position"), LoadPrevPositionProc},
626 // {N_("Reload Same Position"), ReloadPositionProc},
627 // {N_("Save Position"), SavePositionProc},
628 // {"----", NothingProc},
629 {N_("Copy Position"), CopyPositionProc},
630 {N_("Paste Position"), PastePositionProc},
631 // {"----", NothingProc},
632 {N_("Mail Move"), MailMoveProc},
633 {N_("Reload CMail Message"), ReloadCmailMsgProc},
634 // {"----", NothingProc},
638 MenuItem modeMenu[] = {
639 // {N_("Machine White"), MachineWhiteProc},
640 // {N_("Machine Black"), MachineBlackProc},
641 // {N_("Two Machines"), TwoMachinesProc},
642 // {N_("Analysis Mode"), AnalyzeModeProc},
643 // {N_("Analyze File"), AnalyzeFileProc },
644 // {N_("ICS Client"), IcsClientProc},
645 // {N_("Edit Game"), EditGameProc},
646 // {N_("Edit Position"), EditPositionProc},
647 // {N_("Training"), TrainingProc},
648 // {"----", NothingProc},
649 {N_("Show Engine Output"), EngineOutputProc},
650 {N_("Show Evaluation Graph"), EvalGraphProc},
651 {N_("Show Game List"), ShowGameListProc},
652 // {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
653 // {"----", NothingProc},
654 // {N_("Edit Tags"), EditTagsProc},
655 {N_("Edit Comment"), EditCommentProc},
656 {N_("ICS Input Box"), IcsInputBoxProc},
660 MenuItem optionsMenu[] = {
661 // {N_("Flip View"), FlipViewProc},
662 // {"----", NothingProc},
663 {N_("Adjudications ..."), EngineMenuProc},
664 {N_("General Settings ..."), UciMenuProc},
665 {N_("Engine #1 Settings ..."), FirstSettingsProc},
666 {N_("Engine #2 Settings ..."), SecondSettingsProc},
667 {N_("Time Control ..."), TimeControlProc},
668 {N_("Game List ..."), GameListOptionsPopUp},
669 {"----", NothingProc},
670 // {N_("Always Queen"), AlwaysQueenProc},
671 // {N_("Animate Dragging"), AnimateDraggingProc},
672 // {N_("Animate Moving"), AnimateMovingProc},
673 // {N_("Auto Comment"), AutocommProc},
674 // {N_("Auto Flag"), AutoflagProc},
675 // {N_("Auto Flip View"), AutoflipProc},
676 // {N_("Auto Observe"), AutobsProc},
677 // {N_("Auto Raise Board"), AutoraiseProc},
678 // {N_("Auto Save"), AutosaveProc},
679 // {N_("Blindfold"), BlindfoldProc},
680 // {N_("Flash Moves"), FlashMovesProc},
681 // {N_("Get Move List"), GetMoveListProc},
683 // {N_("Highlight Dragging"), HighlightDraggingProc},
685 // {N_("Highlight Last Move"), HighlightLastMoveProc},
686 // {N_("Move Sound"), MoveSoundProc},
687 // {N_("ICS Alarm"), IcsAlarmProc},
688 // {N_("Old Save Style"), OldSaveStyleProc},
689 // {N_("Periodic Updates"), PeriodicUpdatesProc},
690 // {N_("Ponder Next Move"), PonderNextMoveProc},
691 // {N_("Popup Exit Message"), PopupExitMessageProc},
692 // {N_("Popup Move Errors"), PopupMoveErrorsProc},
693 // {N_("Premove"), PremoveProc},
694 // {N_("Quiet Play"), QuietPlayProc},
695 // {N_("Hide Thinking"), HideThinkingProc},
696 // {N_("Test Legality"), TestLegalityProc},
697 // {N_("Show Coords"), ShowCoordsProc},
698 {"----", NothingProc},
699 {N_("Save Settings Now"), SaveSettingsProc},
700 {N_("Save Settings on Exit"), SaveOnExitProc},
705 {N_("File"), fileMenu},
706 {N_("Mode"), modeMenu},
707 {N_("Options"), optionsMenu},
711 #define PIECE_MENU_SIZE 18
712 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
713 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
714 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
715 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
716 N_("Empty square"), N_("Clear board") },
717 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
718 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
719 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
720 N_("Empty square"), N_("Clear board") }
722 /* must be in same order as PieceMenuStrings! */
723 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
724 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
725 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
726 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
727 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
728 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
729 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
730 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
731 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
734 #define DROP_MENU_SIZE 6
735 String dropMenuStrings[DROP_MENU_SIZE] = {
736 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
738 /* must be in same order as PieceMenuStrings! */
739 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
740 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
741 WhiteRook, WhiteQueen
749 DropMenuEnables dmEnables[] = {
758 { XtNborderWidth, 0 },
759 { XtNdefaultDistance, 0 },
763 { XtNborderWidth, 0 },
764 { XtNresizable, (XtArgVal) True },
768 { XtNborderWidth, 0 },
773 XtResource clientResources[] = {
774 { "flashCount", "flashCount", XtRInt, sizeof(int),
775 XtOffset(AppDataPtr, flashCount), XtRImmediate,
776 (XtPointer) FLASH_COUNT },
779 XtActionsRec boardActions[] = {
780 // { "HandleUserMove", HandleUserMove },
781 { "AnimateUserMove", AnimateUserMove },
782 // { "FileNameAction", FileNameAction },
783 { "HandlePV", HandlePV },
784 { "UnLoadPV", UnLoadPV },
785 { "AskQuestionProc", AskQuestionProc },
786 { "AskQuestionReplyAction", AskQuestionReplyAction },
787 { "PieceMenuPopup", PieceMenuPopup },
788 // { "WhiteClock", WhiteClock },
789 // { "BlackClock", BlackClock },
790 { "Iconify", Iconify },
791 { "LoadSelectedProc", LoadSelectedProc },
792 // { "LoadPositionProc", LoadPositionProc },
793 // { "LoadNextPositionProc", LoadNextPositionProc },
794 // { "LoadPrevPositionProc", LoadPrevPositionProc },
795 // { "ReloadPositionProc", ReloadPositionProc },
796 { "SetFilterProc", SetFilterProc },
797 { "CopyPositionProc", CopyPositionProc },
798 { "PastePositionProc", PastePositionProc },
799 { "CopyGameProc", CopyGameProc },
800 { "PasteGameProc", PasteGameProc },
801 // { "SaveGameProc", SaveGameProc },
802 // { "SavePositionProc", SavePositionProc },
803 { "MailMoveProc", MailMoveProc },
804 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
805 // { "MachineWhiteProc", MachineWhiteProc },
806 // { "MachineBlackProc", MachineBlackProc },
807 // { "AnalysisModeProc", AnalyzeModeProc },
808 // { "AnalyzeFileProc", AnalyzeFileProc },
809 // { "TwoMachinesProc", TwoMachinesProc },
810 // { "IcsClientProc", IcsClientProc },
811 // { "EditGameProc", EditGameProc },
812 // { "EditPositionProc", EditPositionProc },
813 // { "TrainingProc", EditPositionProc },
814 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
815 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
816 { "ShowGameListProc", ShowGameListProc },
817 // { "ShowMoveListProc", HistoryShowProc},
818 // { "EditTagsProc", EditCommentProc },
819 { "EditCommentProc", EditCommentProc },
820 // { "IcsAlarmProc", IcsAlarmProc },
821 { "IcsInputBoxProc", IcsInputBoxProc },
822 // { "AcceptProc", AcceptProc },
823 // { "DeclineProc", DeclineProc },
824 // { "RematchProc", RematchProc },
825 // { "CallFlagProc", CallFlagProc },
826 // { "DrawProc", DrawProc },
827 // { "AdjournProc", AdjournProc },
828 // { "AbortProc", AbortProc },
829 // { "ResignProc", ResignProc },
830 // { "AdjuWhiteProc", AdjuWhiteProc },
831 // { "AdjuBlackProc", AdjuBlackProc },
832 // { "AdjuDrawProc", AdjuDrawProc },
833 { "EnterKeyProc", EnterKeyProc },
834 // { "StopObservingProc", StopObservingProc },
835 // { "StopExaminingProc", StopExaminingProc },
836 // { "BackwardProc", BackwardProc },
837 // { "ForwardProc", ForwardProc },
838 // { "ToStartProc", ToStartProc },
839 // { "ToEndProc", ToEndProc },
840 // { "RevertProc", RevertProc },
841 // { "TruncateGameProc", TruncateGameProc },
842 // { "MoveNowProc", MoveNowProc },
843 // { "RetractMoveProc", RetractMoveProc },
844 // { "AlwaysQueenProc", AlwaysQueenProc },
845 // { "AnimateDraggingProc", AnimateDraggingProc },
846 // { "AnimateMovingProc", AnimateMovingProc },
847 // { "AutoflagProc", AutoflagProc },
848 // { "AutoflipProc", AutoflipProc },
849 // { "AutobsProc", AutobsProc },
850 // { "AutoraiseProc", AutoraiseProc },
851 // { "AutosaveProc", AutosaveProc },
852 // { "BlindfoldProc", BlindfoldProc },
853 // { "FlashMovesProc", FlashMovesProc },
854 // { "FlipViewProc", FlipViewProc },
855 // { "GetMoveListProc", GetMoveListProc },
857 // { "HighlightDraggingProc", HighlightDraggingProc },
859 // { "HighlightLastMoveProc", HighlightLastMoveProc },
860 // { "IcsAlarmProc", IcsAlarmProc },
861 // { "MoveSoundProc", MoveSoundProc },
862 // { "OldSaveStyleProc", OldSaveStyleProc },
863 // { "PeriodicUpdatesProc", PeriodicUpdatesProc },
864 // { "PonderNextMoveProc", PonderNextMoveProc },
865 // { "PopupExitMessageProc", PopupExitMessageProc },
866 // { "PopupMoveErrorsProc", PopupMoveErrorsProc },
867 // { "PremoveProc", PremoveProc },
868 // { "QuietPlayProc", QuietPlayProc },
869 // { "ShowThinkingProc", ShowThinkingProc },
870 // { "HideThinkingProc", HideThinkingProc },
871 // { "TestLegalityProc", TestLegalityProc },
872 { "SaveSettingsProc", SaveSettingsProc },
873 { "SaveOnExitProc", SaveOnExitProc },
874 // { "InfoProc", InfoProc },
875 // { "ManProc", ManProc },
876 // { "HintProc", HintProc },
877 // { "BookProc", BookProc },
878 { "AboutGameProc", AboutGameProc },
879 { "DebugProc", DebugProc },
880 { "NothingProc", NothingProc },
881 { "CommentPopDown", (XtActionProc) CommentPopDown },
882 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
883 { "TagsPopDown", (XtActionProc) TagsPopDown },
884 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
885 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
886 // { "FileNamePopDown", (XtActionProc) FileNamePopDown },
887 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
888 { "GameListPopDown", (XtActionProc) GameListPopDown },
889 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
890 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
891 // { "HistoryPopDown", (XtActionProc) HistoryPopDown },
892 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
893 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
894 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
895 { "EnginePopDown", (XtActionProc) EnginePopDown },
896 { "UciPopDown", (XtActionProc) UciPopDown },
897 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
898 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
899 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
900 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
903 //char globalTranslations[] =
904 // ":<Key>R: ResignProc() \n \
905 // :<Key>r: ResetProc() \n \
906 // :<Key>g: LoadGameProc() \n \
907 // :<Key>N: LoadNextGameProc() \n \
908 // :<Key>P: LoadPrevGameProc() \n \
909 // :<Key>Q: QuitProc() \n \
910 // :<Key>F: ToEndProc() \n \
911 // :<Key>f: ForwardProc() \n \
912 // :<Key>B: ToStartProc() \n \
913 // :<Key>b: BackwardProc() \n \
914 // :<Key>p: PauseProc() \n \
915 // :<Key>d: DrawProc() \n \
916 // :<Key>t: CallFlagProc() \n \
917 // :<Key>i: Iconify() \n \
918 // :<Key>c: Iconify() \n \
919 // :<Key>v: FlipViewProc() \n \
920 // <KeyDown>Control_L: BackwardProc() \n \
921 // <KeyUp>Control_L: ForwardProc() \n \
922 // <KeyDown>Control_R: BackwardProc() \n \
923 // <KeyUp>Control_R: ForwardProc() \n \
924 // Shift<Key>1: AskQuestionProc(\"Direct command\", \
925 // \"Send to chess program:\",,1) \n \
926 // Shift<Key>2: AskQuestionProc(\"Direct command\", \
927 // \"Send to second chess program:\",,2) \n";
929 //char boardTranslations[] =
930 // "<Btn1Down>: HandleUserMove() \n \
931 // <Btn1Up>: HandleUserMove() \n \
932 // <Btn1Motion>: AnimateUserMove() \n \
933 // <Btn3Motion>: HandlePV() \n \
934 // <Btn3Up>: UnLoadPV() \n \
935 // Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
936 // PieceMenuPopup(menuB) \n \
937 // Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
938 // PieceMenuPopup(menuW) \n \
939 // Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
940 // PieceMenuPopup(menuW) \n \
941 // Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
942 // PieceMenuPopup(menuB) \n";
944 //char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
945 //char blackTranslations[] = "<BtnDown>: BlackClock()\n";
947 char ICSInputTranslations[] =
948 "<Key>Return: EnterKeyProc() \n";
950 String xboardResources[] = {
951 // "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
952 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
953 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
957 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
958 "magenta", "cyan", "white" };
962 TextColors textColors[(int)NColorClasses];
964 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
966 parse_color(str, which)
970 char *p, buf[100], *d;
973 if (strlen(str) > 99) /* watch bounds on buf */
978 for (i=0; i<which; ++i) {
985 /* Could be looking at something like:
987 .. in which case we want to stop on a comma also */
988 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
992 return -1; /* Use default for empty field */
995 if (which == 2 || isdigit(*p))
998 while (*p && isalpha(*p))
1003 for (i=0; i<8; ++i) {
1004 if (!StrCaseCmp(buf, cnames[i]))
1005 return which? (i+40) : (i+30);
1007 if (!StrCaseCmp(buf, "default")) return -1;
1009 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1014 parse_cpair(cc, str)
1018 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1019 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1024 /* bg and attr are optional */
1025 textColors[(int)cc].bg = parse_color(str, 1);
1026 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1027 textColors[(int)cc].attr = 0;
1036 /* this should raise the board to the top */
1037 gtk_window_present(GTK_WINDOW(GUI_Window));
1041 //---------------------------------------------------------------------------------------------------------
1042 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1045 #define CW_USEDEFAULT (1<<31)
1046 #define ICS_TEXT_MENU_SIZE 90
1047 #define DEBUG_FILE "xboard.debug"
1048 #define SetCurrentDirectory chdir
1049 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1053 // these two must some day move to frontend.h, when they are implemented
1054 Boolean GameListIsUp();
1056 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1059 // front-end part of option handling
1061 // [HGM] This platform-dependent table provides the location for storing the color info
1062 extern char *crWhite, * crBlack;
1066 &appData.whitePieceColor,
1067 &appData.blackPieceColor,
1068 &appData.lightSquareColor,
1069 &appData.darkSquareColor,
1070 &appData.highlightSquareColor,
1071 &appData.premoveHighlightColor,
1072 &appData.lowTimeWarningColor,
1083 // [HGM] font: keep a font for each square size, even non-stndard ones
1084 #define NUM_SIZES 18
1085 #define MAX_SIZE 130
1086 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1087 char *fontTable[NUM_FONTS][MAX_SIZE];
1090 ParseFont(char *name, int number)
1091 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1093 if(sscanf(name, "size%d:", &size)) {
1094 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1095 // defer processing it until we know if it matches our board size
1096 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1097 fontTable[number][size] = strdup(strchr(name, ':')+1);
1098 fontValid[number][size] = True;
1103 case 0: // CLOCK_FONT
1104 appData.clockFont = strdup(name);
1106 case 1: // MESSAGE_FONT
1107 appData.font = strdup(name);
1109 case 2: // COORD_FONT
1110 appData.coordFont = strdup(name);
1115 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1120 { // only 2 fonts currently
1121 appData.clockFont = CLOCK_FONT_NAME;
1122 appData.coordFont = COORD_FONT_NAME;
1123 appData.font = DEFAULT_FONT_NAME;
1128 { // no-op, until we identify the code for this already in XBoard and move it here
1132 ParseColor(int n, char *name)
1133 { // in XBoard, just copy the color-name string
1134 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1138 ParseTextAttribs(ColorClass cc, char *s)
1140 (&appData.colorShout)[cc] = strdup(s);
1144 ParseBoardSize(void *addr, char *name)
1146 appData.boardSize = strdup(name);
1151 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1155 SetCommPortDefaults()
1156 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1159 // [HGM] args: these three cases taken out to stay in front-end
1161 SaveFontArg(FILE *f, ArgDescriptor *ad)
1163 char *name, buf[MSG_SIZ];
1164 int i, n = (int)ad->argLoc;
1166 case 0: // CLOCK_FONT
1167 name = appData.clockFont;
1169 case 1: // MESSAGE_FONT
1170 name = appData.font;
1172 case 2: // COORD_FONT
1173 name = appData.coordFont;
1178 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1179 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1180 fontTable[n][squareSize] = strdup(name);
1181 fontValid[n][squareSize] = True;
1184 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1185 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1190 { // nothing to do, as the sounds are at all times represented by their text-string names already
1194 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1195 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1196 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1200 SaveColor(FILE *f, ArgDescriptor *ad)
1201 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1202 if(colorVariable[(int)ad->argLoc])
1203 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1207 SaveBoardSize(FILE *f, char *name, void *addr)
1208 { // wrapper to shield back-end from BoardSize & sizeInfo
1209 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1213 ParseCommPortSettings(char *s)
1214 { // no such option in XBoard (yet)
1217 extern Widget engineOutputShell;
1218 extern Widget tagsShell, editTagsShell;
1221 GetActualPlacement(Widget wg, WindowPlacement *wp)
1231 XtSetArg(args[i], XtNx, &x); i++;
1232 XtSetArg(args[i], XtNy, &y); i++;
1233 XtSetArg(args[i], XtNwidth, &w); i++;
1234 XtSetArg(args[i], XtNheight, &h); i++;
1235 XtGetValues(wg, args, i);
1244 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1245 // In XBoard this will have to wait until awareness of window parameters is implemented
1247 // GetActualPlacement(shellWidget, &wpMain);
1248 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1249 // if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1250 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1251 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1252 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1253 else GetActualPlacement(editShell, &wpComment);
1254 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1255 else GetActualPlacement(editTagsShell, &wpTags);
1259 PrintCommPortSettings(FILE *f, char *name)
1260 { // This option does not exist in XBoard
1264 MySearchPath(char *installDir, char *name, char *fullname)
1265 { // just append installDir and name. Perhaps ExpandPath should be used here?
1266 name = ExpandPathName(name);
1267 if(name && name[0] == '/') strcpy(fullname, name); else {
1268 sprintf(fullname, "%s%c%s", installDir, '/', name);
1274 MyGetFullPathName(char *name, char *fullname)
1275 { // should use ExpandPath?
1276 name = ExpandPathName(name);
1277 strcpy(fullname, name);
1282 EnsureOnScreen(int *x, int *y, int minX, int minY)
1289 { // [HGM] args: allows testing if main window is realized from back-end
1290 return xBoardWindow != 0;
1294 PopUpStartupDialog()
1295 { // start menu not implemented in XBoard
1298 ConvertToLine(int argc, char **argv)
1300 static char line[128*1024], buf[1024];
1304 for(i=1; i<argc; i++) {
1305 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1306 && argv[i][0] != '{' )
1307 sprintf(buf, "{%s} ", argv[i]);
1308 else sprintf(buf, "%s ", argv[i]);
1311 line[strlen(line)-1] = NULLCHAR;
1315 //--------------------------------------------------------------------------------------------
1318 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1321 #define BoardSize int
1322 void InitDrawingSizes(BoardSize boardSize, int flags)
1323 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1324 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1326 XtGeometryResult gres;
1329 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1330 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1332 timerWidth = (boardWidth - sep) / 2;
1334 if (appData.titleInWindow)
1339 w = boardWidth - 2*bor;
1343 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1347 if(!formWidget) return;
1350 * Inhibit shell resizing.
1353 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1356 for(i=0; i<4; i++) {
1358 for(p=0; p<=(int)WhiteKing; p++)
1359 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1360 if(gameInfo.variant == VariantShogi) {
1361 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1362 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1363 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1364 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1365 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1368 if(gameInfo.variant == VariantGothic) {
1369 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1373 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1374 for(p=0; p<=(int)WhiteKing; p++)
1375 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1376 if(gameInfo.variant == VariantShogi) {
1377 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1378 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1379 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1380 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1381 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1384 if(gameInfo.variant == VariantGothic) {
1385 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1391 for(i=0; i<2; i++) {
1393 for(p=0; p<=(int)WhiteKing; p++)
1394 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1395 if(gameInfo.variant == VariantShogi) {
1396 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1397 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1398 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1399 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1400 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1403 if(gameInfo.variant == VariantGothic) {
1404 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1415 void EscapeExpand(char *p, char *q)
1416 { // [HGM] initstring: routine to shape up string arguments
1420 case 'n': p[-1] = '\n'; break;
1421 case 'r': p[-1] = '\r'; break;
1422 case 't': p[-1] = '\t'; break;
1423 case '\\': p[-1] = '\\'; break;
1424 case 0: *p = 0; return;
1425 default: p[-1] = q[-1]; break;
1434 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1435 XSetWindowAttributes window_attributes;
1437 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1438 XrmValue vFrom, vTo;
1439 XtGeometryResult gres;
1442 int forceMono = False;
1444 srandom(time(0)); // [HGM] book: make random truly random
1446 setbuf(stdout, NULL);
1447 setbuf(stderr, NULL);
1450 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1451 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1455 programName = strrchr(argv[0], '/');
1456 if (programName == NULL)
1457 programName = argv[0];
1462 XtSetLanguageProc(NULL, NULL, NULL);
1463 bindtextdomain(PACKAGE, LOCALEDIR);
1464 textdomain(PACKAGE);
1468 gtk_init (&argc, &argv);
1470 /* parse glade file to build widgets */
1472 builder = gtk_builder_new ();
1473 GError *gtkerror=NULL;
1474 if(!gtk_builder_add_from_file (builder, "gtk-interface.xml", >kerror))
1477 printf ("Error: %d %s\n",gtkerror->code,gtkerror->message);
1480 /* test if everything worked ok */
1482 GUI_Window = GTK_WIDGET (gtk_builder_get_object (builder, "MainWindow"));
1483 if(!GUI_Window) printf("Error: gtk_builder didn't work (MainWindow)!\n");
1485 GUI_Aspect = GTK_WIDGET (gtk_builder_get_object (builder, "Aspectframe"));
1486 if(!GUI_Aspect) printf("Error: gtk_builder didn't work (Aspectframe)!\n");
1488 GUI_Menubar = GTK_WIDGET (gtk_builder_get_object (builder, "MenuBar"));
1489 if(!GUI_Menubar) printf("Error: gtk_builder didn't work (MenuBar)!\n");
1490 GUI_Timer = GTK_WIDGET (gtk_builder_get_object (builder, "Timer"));
1491 if(!GUI_Timer) printf("Error: gtk_builder didn't work (Timer)!\n");
1492 GUI_Buttonbar = GTK_WIDGET (gtk_builder_get_object (builder, "ButtonBar"));
1493 if(!GUI_Buttonbar) printf("Error: gtk_builder didn't work (ButtonBar)!\n");
1494 GUI_Board = GTK_WIDGET (gtk_builder_get_object (builder, "Board"));
1495 if(!GUI_Board) printf("Error: gtk_builder didn't work (Board)!\n");
1497 GUI_Whiteclock = GTK_WIDGET (gtk_builder_get_object (builder, "WhiteClock"));
1498 if(!GUI_Whiteclock) printf("Error: gtk_builder didn't work (WhiteClock)!\n");
1500 GUI_Blackclock = GTK_WIDGET (gtk_builder_get_object (builder, "BlackClock"));
1501 if(!GUI_Blackclock) printf("Error: gtk_builder didn't work (BlackClock)!\n");
1503 /* GTK lists stores*/
1504 LIST_MoveHistory = GTK_LIST_STORE (gtk_builder_get_object (builder, "MoveHistoryStore"));
1505 if(!LIST_MoveHistory) printf("Error: gtk_builder didn't work (MoveHistoryStore)!\n");
1507 LIST_GameList = GTK_LIST_STORE (gtk_builder_get_object (builder, "GameListStore"));
1508 if(!LIST_GameList) printf("Error: gtk_builder didn't work (GameListStore)!\n");
1510 /* EditTags window */
1511 GUI_EditTags = GTK_WIDGET (gtk_builder_get_object (builder, "EditTags"));
1512 if(!GUI_EditTags) printf("Error: gtk_builder didn't work (EditTags)!\n");
1514 GUI_EditTagsTextArea = GTK_WIDGET (gtk_builder_get_object (builder, "EditTagsTextArea"));
1515 if(!GUI_EditTagsTextArea) printf("Error: gtk_builder didn't work(EditTagsTextArea)!\n");
1517 /* move history and game list windows */
1518 GUI_History = GTK_WIDGET (gtk_builder_get_object (builder, "MoveHistory"));
1519 if(!GUI_History) printf("Error: gtk_builder didn't work (MoveHistory)!\n");
1521 TREE_History = GTK_TREE_VIEW (gtk_builder_get_object (builder, "MoveHistoryView"));
1522 if(!TREE_History) printf("Error: gtk_builder didn't work (MoveHistoryView)!\n");
1524 GUI_GameList = GTK_WIDGET (gtk_builder_get_object (builder, "GameList"));
1525 if(!GUI_GameList) printf("Error: gtk_builder didn't work (GameList)!\n");
1527 TREE_Game = GTK_TREE_VIEW (gtk_builder_get_object (builder, "GameListView"));
1528 if(!TREE_Game) printf("Error: gtk_builder didn't work (GameListView)!\n");
1531 /* connect lists to views */
1532 gtk_tree_view_set_model(TREE_History, GTK_TREE_MODEL(LIST_MoveHistory));
1533 gtk_tree_view_set_model(TREE_Game, GTK_TREE_MODEL(LIST_GameList));
1535 gtk_builder_connect_signals (builder, NULL);
1537 // don't unref the builder, since we use it to get references to widgets
1538 // g_object_unref (G_OBJECT (builder));
1540 /* end parse glade file */
1542 appData.boardSize = "";
1543 InitAppData(ConvertToLine(argc, argv));
1546 if (p == NULL) p = "/tmp";
1547 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1548 gameCopyFilename = (char*) malloc(i);
1549 gamePasteFilename = (char*) malloc(i);
1550 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1551 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1553 // XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1554 // clientResources, XtNumber(clientResources),
1557 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1558 static char buf[MSG_SIZ];
1559 EscapeExpand(buf, appData.initString);
1560 appData.initString = strdup(buf);
1561 EscapeExpand(buf, appData.secondInitString);
1562 appData.secondInitString = strdup(buf);
1563 EscapeExpand(buf, appData.firstComputerString);
1564 appData.firstComputerString = strdup(buf);
1565 EscapeExpand(buf, appData.secondComputerString);
1566 appData.secondComputerString = strdup(buf);
1569 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1572 if (chdir(chessDir) != 0) {
1573 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1579 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1580 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1581 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1582 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1585 setbuf(debugFP, NULL);
1590 /* This feature does not work; animation needs a rewrite */
1591 appData.highlightDragging = FALSE;
1595 gameInfo.variant = StringToVariant(appData.variant);
1596 InitPosition(FALSE);
1601 clockFontPxlSize = 20;
1602 coordFontPxlSize = 20;
1608 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1609 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1612 * Determine what fonts to use.
1614 // appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1615 // clockFontID = XLoadFont(xDisplay, appData.clockFont);
1616 // clockFontStruct = XQueryFont(xDisplay, clockFontID);
1617 // appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1618 // coordFontID = XLoadFont(xDisplay, appData.coordFont);
1619 // coordFontStruct = XQueryFont(xDisplay, coordFontID);
1620 // appData.font = FindFont(appData.font, fontPxlSize);
1621 // countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1622 // countFontStruct = XQueryFont(xDisplay, countFontID);
1623 // appData.font = FindFont(appData.font, fontPxlSize);
1625 // xdb = XtDatabase(xDisplay);
1626 // XrmPutStringResource(&xdb, "*font", appData.font);
1629 * Detect if there are not enough colors available and adapt.
1631 // if (DefaultDepth(xDisplay, xScreen) <= 2) {
1632 // appData.monoMode = True;
1635 if (!appData.monoMode) {
1636 vFrom.addr = (caddr_t) appData.lightSquareColor;
1637 vFrom.size = strlen(appData.lightSquareColor);
1638 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1639 if (vTo.addr == NULL) {
1640 appData.monoMode = True;
1643 lightSquareColor = *(Pixel *) vTo.addr;
1646 if (!appData.monoMode) {
1647 vFrom.addr = (caddr_t) appData.darkSquareColor;
1648 vFrom.size = strlen(appData.darkSquareColor);
1649 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1650 if (vTo.addr == NULL) {
1651 appData.monoMode = True;
1654 darkSquareColor = *(Pixel *) vTo.addr;
1657 if (!appData.monoMode) {
1658 vFrom.addr = (caddr_t) appData.whitePieceColor;
1659 vFrom.size = strlen(appData.whitePieceColor);
1660 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1661 if (vTo.addr == NULL) {
1662 appData.monoMode = True;
1665 whitePieceColor = *(Pixel *) vTo.addr;
1668 if (!appData.monoMode) {
1669 vFrom.addr = (caddr_t) appData.blackPieceColor;
1670 vFrom.size = strlen(appData.blackPieceColor);
1671 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1672 if (vTo.addr == NULL) {
1673 appData.monoMode = True;
1676 blackPieceColor = *(Pixel *) vTo.addr;
1680 if (!appData.monoMode) {
1681 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1682 vFrom.size = strlen(appData.highlightSquareColor);
1683 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1684 if (vTo.addr == NULL) {
1685 appData.monoMode = True;
1688 highlightSquareColor = *(Pixel *) vTo.addr;
1692 if (!appData.monoMode) {
1693 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1694 vFrom.size = strlen(appData.premoveHighlightColor);
1695 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1696 if (vTo.addr == NULL) {
1697 appData.monoMode = True;
1700 premoveHighlightColor = *(Pixel *) vTo.addr;
1705 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1708 if (appData.bitmapDirectory == NULL ||
1709 appData.bitmapDirectory[0] == NULLCHAR)
1710 appData.bitmapDirectory = DEF_BITMAP_DIR;
1713 if (appData.lowTimeWarning && !appData.monoMode) {
1714 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1715 vFrom.size = strlen(appData.lowTimeWarningColor);
1716 // XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1717 if (vTo.addr == NULL)
1718 appData.monoMode = True;
1720 lowTimeWarningColor = *(Pixel *) vTo.addr;
1723 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1724 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1725 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1726 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1727 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1728 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1729 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1730 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1731 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1732 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1734 if (appData.colorize) {
1736 _("%s: can't parse color names; disabling colorization\n"),
1739 appData.colorize = FALSE;
1741 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1742 textColors[ColorNone].attr = 0;
1744 // XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1750 layoutName = "tinyLayout";
1751 } else if (smallLayout) {
1752 layoutName = "smallLayout";
1754 layoutName = "normalLayout";
1757 if (appData.titleInWindow) {
1758 /* todo check what this appdata does */
1761 if (appData.showButtonBar) {
1762 /* TODO hide button bar if requested */
1766 if (appData.titleInWindow)
1771 if (appData.showButtonBar)
1778 if (appData.showButtonBar)
1788 /* set some checkboxes in the menu according to appData */
1790 if (appData.alwaysPromoteToQueen)
1791 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Always Queen")),TRUE);
1793 if (appData.animateDragging)
1794 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Animate Dragging")),TRUE);
1796 if (appData.animate)
1797 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Animate Moving")),TRUE);
1799 if (appData.autoComment)
1800 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Comment")),TRUE);
1802 if (appData.autoCallFlag)
1803 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Flag")),TRUE);
1805 if (appData.autoFlipView)
1806 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Flip View")),TRUE);
1808 if (appData.autoObserve)
1809 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Observe")),TRUE);
1811 if (appData.autoRaiseBoard)
1812 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Raise Board")),TRUE);
1814 if (appData.autoSaveGames)
1815 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Save")),TRUE);
1817 if (appData.saveGameFile[0] != NULLCHAR)
1819 /* Can't turn this off from menu */
1820 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Auto Save")),TRUE);
1821 gtk_action_set_sensitive(GTK_ACTION (gtk_builder_get_object (builder, "menuOptions.Auto Save")),FALSE);
1824 if (appData.blindfold)
1825 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Blindfold")),TRUE);
1827 if (appData.flashCount > 0)
1828 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Flash Moves")),TRUE);
1830 if (appData.getMoveList)
1831 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Get Move List")),TRUE);
1834 if (appData.highlightDragging)
1835 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Highlight Dragging")),TRUE);
1838 if (appData.highlightLastMove)
1839 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Highlight Last Move")),TRUE);
1841 if (appData.icsAlarm)
1842 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.ICS Alarm")),TRUE);
1844 if (appData.ringBellAfterMoves)
1845 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Move Sound")),TRUE);
1847 if (appData.oldSaveStyle)
1848 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Old Save Style")),TRUE);
1850 if (appData.periodicUpdates)
1851 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Periodic Updates")),TRUE);
1853 if (appData.ponderNextMove)
1854 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Ponder Next Move")),TRUE);
1856 if (appData.popupExitMessage)
1857 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Popup Exit Message")),TRUE);
1859 if (appData.popupMoveErrors)
1860 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Popup Move Errors")),TRUE);
1862 if (appData.premove)
1863 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Premove")),TRUE);
1865 if (appData.quietPlay)
1866 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Quit Play")),TRUE);
1868 if (appData.showCoords)
1869 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Show Coords")),TRUE);
1871 if (appData.showThinking)
1872 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Hide Thinking")),TRUE);
1874 if (appData.testLegality)
1875 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuOptions.Test Legality")),TRUE);
1878 // if (saveSettingsOnExit) {
1879 // XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
1884 /* end setting check boxes */
1886 /* load square colors */
1887 SVGLightSquare = load_pixbuf("svg/LightSquare.svg",squareSize);
1888 SVGDarkSquare = load_pixbuf("svg/DarkSquare.svg",squareSize);
1889 SVGNeutralSquare = load_pixbuf("svg/NeutralSquare.svg",squareSize);
1891 /* use two icons to indicate if it is white's or black's turn */
1892 WhiteIcon = load_pixbuf("svg/icon_white.svg",0);
1893 BlackIcon = load_pixbuf("svg/icon_black.svg",0);
1894 WindowIcon = WhiteIcon;
1895 gtk_window_set_icon(GTK_WINDOW(GUI_Window),WindowIcon);
1898 /* realize window */
1899 gtk_widget_show (GUI_Window);
1901 /* recalc boardsize */
1906 if (appData.animate || appData.animateDragging)
1909 /* [AS] Restore layout */
1910 if( wpMoveHistory.visible ) {
1914 if( wpEvalGraph.visible )
1919 if( wpEngineOutput.visible ) {
1920 EngineOutputPopUp();
1925 if (errorExitStatus == -1) {
1926 if (appData.icsActive) {
1927 /* We now wait until we see "login:" from the ICS before
1928 sending the logon script (problems with timestamp otherwise) */
1929 /*ICSInitScript();*/
1930 if (appData.icsInputBox) ICSInputBoxPopUp();
1934 signal(SIGWINCH, TermSizeSigHandler);
1936 signal(SIGINT, IntSigHandler);
1937 signal(SIGTERM, IntSigHandler);
1938 if (*appData.cmailGameName != NULLCHAR) {
1939 signal(SIGUSR1, CmailSigHandler);
1942 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
1946 * Create a cursor for the board widget.
1947 * (This needs to be called after the window has been created to have access to board-window)
1950 BoardCursor = gdk_cursor_new(GDK_HAND2);
1951 gdk_window_set_cursor(GUI_Board->window, BoardCursor);
1952 gdk_cursor_destroy(BoardCursor);
1957 if (appData.debugMode) fclose(debugFP); // [DM] debug
1964 if (appData.icsActive && oldICSInteractionTitle != NULL) {
1965 DisplayIcsInteractionTitle(oldICSInteractionTitle);
1967 if (saveSettingsOnExit) SaveSettings(settingsFileName);
1968 unlink(gameCopyFilename);
1969 unlink(gamePasteFilename);
1972 RETSIGTYPE TermSizeSigHandler(int sig)
1985 CmailSigHandler(sig)
1991 signal(SIGUSR1, SIG_IGN); /* suspend handler */
1993 /* Activate call-back function CmailSigHandlerCallBack() */
1994 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
1996 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2000 CmailSigHandlerCallBack(isr, closure, message, count, error)
2008 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2010 /**** end signal code ****/
2020 f = fopen(appData.icsLogon, "r");
2026 strcat(buf, appData.icsLogon);
2027 f = fopen(buf, "r");
2031 ProcessICSInitScript(f);
2038 EditCommentPopDown();
2048 if (!menuBarWidget) return;
2049 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2051 DisplayError("menuStep.Revert", 0);
2053 XtSetSensitive(w, !grey);
2058 SetMenuEnables(enab)
2063 if (!builder) return;
2064 while (enab->name != NULL) {
2065 o = gtk_builder_get_object(builder, enab->name);
2066 if(GTK_IS_WIDGET(o))
2067 gtk_widget_set_sensitive(GTK_WIDGET (o),enab->value);
2070 if(GTK_IS_ACTION(o))
2071 gtk_action_set_sensitive(GTK_ACTION (o),enab->value);
2073 DisplayError(enab->name, 0);
2081 SetMenuEnables(icsEnables);
2084 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2085 {}; // XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2092 SetMenuEnables(ncpEnables);
2098 SetMenuEnables(gnuEnables);
2104 SetMenuEnables(cmailEnables);
2110 SetMenuEnables(trainingOnEnables);
2111 if (appData.showButtonBar) {
2112 // XtSetSensitive(buttonBarWidget, False);
2118 SetTrainingModeOff()
2120 SetMenuEnables(trainingOffEnables);
2121 if (appData.showButtonBar) {
2122 // XtSetSensitive(buttonBarWidget, True);
2127 SetUserThinkingEnables()
2129 if (appData.noChessProgram) return;
2130 SetMenuEnables(userThinkingEnables);
2134 SetMachineThinkingEnables()
2136 if (appData.noChessProgram) return;
2137 SetMenuEnables(machineThinkingEnables);
2139 case MachinePlaysBlack:
2140 case MachinePlaysWhite:
2141 case TwoMachinesPlay:
2142 // XtSetSensitive(XtNameToWidget(menuBarWidget,
2143 // ModeToWidgetName(gameMode)), True);
2150 #define Abs(n) ((n)<0 ? -(n) : (n))
2153 * Find a font that matches "pattern" that is as close as
2154 * possible to the targetPxlSize. Prefer fonts that are k
2155 * pixels smaller to fonts that are k pixels larger. The
2156 * pattern must be in the X Consortium standard format,
2157 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2158 * The return value should be freed with XtFree when no
2161 char *FindFont(pattern, targetPxlSize)
2165 char **fonts, *p, *best, *scalable, *scalableTail;
2166 int i, j, nfonts, minerr, err, pxlSize;
2169 char **missing_list;
2171 char *def_string, *base_fnt_lst, strInt[3];
2173 XFontStruct **fnt_list;
2175 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2176 sprintf(strInt, "%d", targetPxlSize);
2177 p = strstr(pattern, "--");
2178 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2179 strcat(base_fnt_lst, strInt);
2180 strcat(base_fnt_lst, strchr(p + 2, '-'));
2182 if ((fntSet = XCreateFontSet(xDisplay,
2186 &def_string)) == NULL) {
2188 fprintf(stderr, _("Unable to create font set.\n"));
2192 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2194 // fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2195 // if (nfonts < 1) {
2196 // fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2197 // programName, pattern);
2205 for (i=0; i<nfonts; i++) {
2208 if (*p != '-') continue;
2210 if (*p == NULLCHAR) break;
2211 if (*p++ == '-') j++;
2213 if (j < 7) continue;
2216 scalable = fonts[i];
2219 err = pxlSize - targetPxlSize;
2220 if (Abs(err) < Abs(minerr) ||
2221 (minerr > 0 && err < 0 && -err == minerr)) {
2227 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2228 /* If the error is too big and there is a scalable font,
2229 use the scalable font. */
2230 int headlen = scalableTail - scalable;
2231 p = (char *) XtMalloc(strlen(scalable) + 10);
2232 while (isdigit(*scalableTail)) scalableTail++;
2233 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2235 p = (char *) XtMalloc(strlen(best) + 1);
2238 if (appData.debugMode) {
2239 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2240 pattern, targetPxlSize, p);
2243 if (missing_count > 0)
2244 XFreeStringList(missing_list);
2245 // XFreeFontSet(xDisplay, fntSet);
2247 XFreeFontNames(fonts);
2254 /* GCs are not needed anymore for GTK just left them in here for the moment, since there is a lot of X-code still around that's wants them*/
2263 for(i=0;i<MAXPIECES;i++)
2267 g_free(SVGpieces[i]);
2274 SVGLightSquare = load_pixbuf("svg/LightSquare.svg",squareSize);
2275 SVGDarkSquare = load_pixbuf("svg/DarkSquare.svg",squareSize);
2276 SVGNeutralSquare = load_pixbuf("svg/NeutralSquare.svg",squareSize);
2279 /* get some defaults going */
2280 for(i=WhitePawn; i<DemotePiece+1; i++)
2281 SVGpieces[i] = load_pixbuf("svg/NeutralSquare.svg",squareSize);
2283 SVGpieces[WhitePawn] = load_pixbuf("svg/WhitePawn.svg",squareSize);
2284 SVGpieces[WhiteKnight] = load_pixbuf("svg/WhiteKnight.svg",squareSize);
2285 SVGpieces[WhiteBishop] = load_pixbuf("svg/WhiteBishop.svg",squareSize);
2286 SVGpieces[WhiteRook] = load_pixbuf("svg/WhiteRook.svg",squareSize);
2287 SVGpieces[WhiteQueen] = load_pixbuf("svg/WhiteQueen.svg",squareSize);
2288 SVGpieces[WhiteKing] = load_pixbuf("svg/WhiteKing.svg",squareSize);
2290 SVGpieces[BlackPawn] = load_pixbuf("svg/BlackPawn.svg",squareSize);
2291 SVGpieces[BlackKnight] = load_pixbuf("svg/BlackKnight.svg",squareSize);
2292 SVGpieces[BlackBishop] = load_pixbuf("svg/BlackBishop.svg",squareSize);
2293 SVGpieces[BlackRook] = load_pixbuf("svg/BlackRook.svg",squareSize);
2294 SVGpieces[BlackQueen] = load_pixbuf("svg/BlackQueen.svg",squareSize);
2295 SVGpieces[BlackKing] = load_pixbuf("svg/BlackKing.svg",squareSize);
2301 static void MenuBarSelect(w, addr, index)
2306 XtActionProc proc = (XtActionProc) addr;
2308 (proc)(NULL, NULL, NULL, NULL);
2311 void CreateMenuBarPopup(parent, name, mb)
2321 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
2324 XtSetArg(args[j], XtNleftMargin, 20); j++;
2325 XtSetArg(args[j], XtNrightMargin, 20); j++;
2327 while (mi->string != NULL) {
2328 if (strcmp(mi->string, "----") == 0) {
2329 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
2332 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
2333 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
2335 XtAddCallback(entry, XtNcallback,
2336 (XtCallbackProc) MenuBarSelect,
2337 (caddr_t) mi->proc);
2348 Widget anchor, menuBar;
2350 char menuName[MSG_SIZ];
2353 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
2354 XtSetArg(args[j], XtNvSpace, 0); j++;
2355 XtSetArg(args[j], XtNborderWidth, 0); j++;
2356 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
2357 formWidget, args, j);
2359 while (mb->name != NULL) {
2360 strcpy(menuName, "menu");
2361 strcat(menuName, mb->name);
2363 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
2366 shortName[0] = _(mb->name)[0];
2367 shortName[1] = NULLCHAR;
2368 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
2371 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
2374 XtSetArg(args[j], XtNborderWidth, 0); j++;
2375 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
2377 CreateMenuBarPopup(menuBar, menuName, mb);
2385 CreatePieceMenu(name, color)
2392 ChessSquare selection;
2394 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
2395 boardWidget, args, 0);
2397 for (i = 0; i < PIECE_MENU_SIZE; i++) {
2398 String item = pieceMenuStrings[color][i];
2400 if (strcmp(item, "----") == 0) {
2401 entry = XtCreateManagedWidget(item, smeLineObjectClass,
2404 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
2405 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2407 selection = pieceMenuTranslation[color][i];
2408 XtAddCallback(entry, XtNcallback,
2409 (XtCallbackProc) PieceMenuSelect,
2410 (caddr_t) selection);
2411 if (selection == WhitePawn || selection == BlackPawn) {
2412 XtSetArg(args[0], XtNpopupOnEntry, entry);
2413 XtSetValues(menu, args, 1);
2426 ChessSquare selection;
2428 // whitePieceMenu = CreatePieceMenu("menuW", 0);
2429 // blackPieceMenu = CreatePieceMenu("menuB", 1);
2431 // XtRegisterGrabAction(PieceMenuPopup, True,
2432 // (unsigned)(ButtonPressMask|ButtonReleaseMask),
2433 // GrabModeAsync, GrabModeAsync);
2435 // XtSetArg(args[0], XtNlabel, _("Drop"));
2436 // dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
2437 // boardWidget, args, 1);
2438 // for (i = 0; i < DROP_MENU_SIZE; i++) {
2439 // String item = dropMenuStrings[i];
2441 // if (strcmp(item, "----") == 0) {
2442 // entry = XtCreateManagedWidget(item, smeLineObjectClass,
2443 // dropMenu, NULL, 0);
2445 // XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
2446 // entry = XtCreateManagedWidget(item, smeBSBObjectClass,
2447 // dropMenu, args, 1);
2448 // selection = dropMenuTranslation[i];
2449 // XtAddCallback(entry, XtNcallback,
2450 // (XtCallbackProc) DropMenuSelect,
2451 // (caddr_t) selection);
2465 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
2466 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
2467 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
2468 dmEnables[i].piece);
2469 XtSetSensitive(entry, p != NULL || !appData.testLegality
2470 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
2471 && !appData.icsActive));
2473 while (p && *p++ == dmEnables[i].piece) count++;
2474 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
2476 XtSetArg(args[j], XtNlabel, label); j++;
2477 XtSetValues(entry, args, j);
2482 PieceMenuPopup(w, event, params, num_params)
2486 Cardinal *num_params;
2488 String whichMenu; int menuNr;
2489 if (event->type == ButtonRelease)
2490 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
2491 else if (event->type == ButtonPress)
2492 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
2494 case 0: whichMenu = params[0]; break;
2495 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
2497 case -1: if (errorUp) ErrorPopDown();
2500 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
2504 PieceMenuSelect(w, piece, junk)
2509 if (pmFromX < 0 || pmFromY < 0) return;
2510 EditPositionMenuEvent(piece, pmFromX, pmFromY);
2514 DropMenuSelect(w, piece, junk)
2519 if (pmFromX < 0 || pmFromY < 0) return;
2520 DropMenuEvent(piece, pmFromX, pmFromY);
2524 * If the user selects on a border boundary, return -1; if off the board,
2525 * return -2. Otherwise map the event coordinate to the square.
2528 EventToSquare(x, limit)
2536 if ((x % (squareSize + lineGap)) >= squareSize)
2538 x /= (squareSize + lineGap);
2545 do_flash_delay(msec)
2552 drawHighlight(file, rank, line_type)
2553 int file, rank, line_type;
2558 if (lineGap == 0 || appData.blindfold) return;
2562 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
2563 (squareSize + lineGap);
2564 y = lineGap/2 + rank * (squareSize + lineGap);
2568 x = lineGap/2 + file * (squareSize + lineGap);
2569 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
2570 (squareSize + lineGap);
2574 cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window));
2576 /* draw the highlight */
2577 cairo_move_to (cr, x, y);
2578 cairo_rel_line_to (cr, 0,squareSize+lineGap);
2579 cairo_rel_line_to (cr, squareSize+lineGap,0);
2580 cairo_rel_line_to (cr, 0,-squareSize-lineGap);
2581 cairo_close_path (cr);
2583 cairo_set_line_width (cr, lineGap);
2586 /* TODO: use appdata colors */
2587 case LINE_TYPE_HIGHLIGHT:
2588 cairo_set_source_rgba (cr, 1, 1, 0, 1.0);
2591 cairo_set_source_rgba (cr, 1, 0, 0, 1.0);
2593 case LINE_TYPE_NORMAL:
2595 cairo_set_source_rgba (cr, 0, 1, 0, 1.0);
2606 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
2607 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
2610 SetHighlights(fromX, fromY, toX, toY)
2611 int fromX, fromY, toX, toY;
2613 if (hi1X != fromX || hi1Y != fromY)
2615 if (hi1X >= 0 && hi1Y >= 0)
2617 drawHighlight(hi1X, hi1Y, LINE_TYPE_NORMAL);
2620 if (hi2X != toX || hi2Y != toY)
2622 if (hi2X >= 0 && hi2Y >= 0)
2624 drawHighlight(hi2X, hi2Y, LINE_TYPE_NORMAL);
2627 if (hi1X != fromX || hi1Y != fromY)
2629 if (fromX >= 0 && fromY >= 0)
2631 drawHighlight(fromX, fromY, LINE_TYPE_HIGHLIGHT);
2634 if (hi2X != toX || hi2Y != toY)
2636 if (toX >= 0 && toY >= 0)
2638 drawHighlight(toX, toY, LINE_TYPE_HIGHLIGHT);
2652 SetHighlights(-1, -1, -1, -1);
2657 SetPremoveHighlights(fromX, fromY, toX, toY)
2658 int fromX, fromY, toX, toY;
2660 if (pm1X != fromX || pm1Y != fromY)
2662 if (pm1X >= 0 && pm1Y >= 0)
2664 drawHighlight(pm1X, pm1Y, LINE_TYPE_NORMAL);
2666 if (fromX >= 0 && fromY >= 0)
2668 drawHighlight(fromX, fromY, LINE_TYPE_PRE);
2671 if (pm2X != toX || pm2Y != toY)
2673 if (pm2X >= 0 && pm2Y >= 0)
2675 drawHighlight(pm2X, pm2Y, LINE_TYPE_NORMAL);
2677 if (toX >= 0 && toY >= 0)
2679 drawHighlight(toX, toY, LINE_TYPE_PRE);
2692 ClearPremoveHighlights()
2694 SetPremoveHighlights(-1, -1, -1, -1);
2697 void BlankSquare(x, y, color, piece, dest)
2710 pb = SVGLightSquare;
2712 case 2: /* neutral */
2714 pb = SVGNeutralSquare;
2717 gdk_draw_pixbuf(GDK_WINDOW(GUI_Board->window),NULL,pb,0,0,x,y,-1,-1, GDK_RGB_DITHER_NORMAL, 0, 0);
2722 DrawPiece(piece, square_color, x, y, dest)
2724 int square_color, x, y;
2727 /* redraw background, since piece might be transparent in some areas */
2728 BlankSquare(x,y,square_color,piece,dest);
2731 gdk_draw_pixbuf(GDK_WINDOW(GUI_Board->window),NULL,
2732 GDK_PIXBUF(SVGpieces[piece]),0,0,x,y,-1,-1,
2733 GDK_RGB_DITHER_NORMAL, 0, 0);
2737 /* [HR] determine square color depending on chess variant. */
2738 static int SquareColor(row, column)
2743 if (gameInfo.variant == VariantXiangqi) {
2744 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
2746 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
2748 } else if (row <= 4) {
2754 square_color = ((column + row) % 2) == 1;
2757 /* [hgm] holdings: next line makes all holdings squares light */
2758 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
2760 return square_color;
2763 void DrawSquare(row, column, piece, do_flash)
2764 int row, column, do_flash;
2767 int square_color, x, y;
2772 /* Calculate delay in milliseconds (2-delays per complete flash) */
2773 flash_delay = 500 / appData.flashRate;
2775 /* calculate x and y coordinates from row and column */
2778 x = lineGap + ((BOARD_WIDTH-1)-column) *
2779 (squareSize + lineGap);
2780 y = lineGap + row * (squareSize + lineGap);
2784 x = lineGap + column * (squareSize + lineGap);
2785 y = lineGap + ((BOARD_HEIGHT-1)-row) *
2786 (squareSize + lineGap);
2789 square_color = SquareColor(row, column);
2791 // [HGM] holdings: blank out area between board and holdings
2792 if ( column == BOARD_LEFT-1 || column == BOARD_RGHT
2793 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
2794 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) )
2796 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
2798 // [HGM] print piece counts next to holdings
2799 string[1] = NULLCHAR;
2802 cairo_text_extents_t extents;
2807 cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window));
2809 string[0] = '0' + piece;
2811 /* TODO this has to go into the font-selection */
2812 cairo_select_font_face (cr, "Sans",
2813 CAIRO_FONT_SLANT_NORMAL,
2814 CAIRO_FONT_WEIGHT_NORMAL);
2816 // switch (event->type) {
2818 // if (event->xexpose.count > 0) return; /* no clipping is done */
2819 // XDrawPosition(widget, True, NULL);
2821 // case MotionNotify:
2822 // if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
2829 cairo_set_font_size (cr, 12.0);
2830 cairo_text_extents (cr, string, &extents);
2832 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) )
2834 xpos= x + squareSize - extents.width - 2;
2835 ypos= y + extents.y_bearing + 1;
2837 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1)
2840 ypos = y + extents.y_bearing + 1;
2843 /* TODO mono mode? */
2844 cairo_move_to (cr, xpos, ypos);
2845 cairo_text_path (cr, string);
2846 cairo_set_source_rgb (cr, 1.0, 1.0, 1);
2847 cairo_fill_preserve (cr);
2848 cairo_set_source_rgb (cr, 0, 0, 0);
2849 cairo_set_line_width (cr, 0.1);
2858 /* square on the board */
2859 if (piece == EmptySquare || appData.blindfold)
2861 BlankSquare(x, y, square_color, piece, xBoardWindow);
2865 if (do_flash && appData.flashCount > 0)
2867 for (i=0; i<appData.flashCount; ++i)
2870 DrawPiece(piece, square_color, x, y, xBoardWindow);
2871 do_flash_delay(flash_delay);
2873 BlankSquare(x, y, square_color, piece, xBoardWindow);
2874 do_flash_delay(flash_delay);
2877 DrawPiece(piece, square_color, x, y, xBoardWindow);
2881 /* show coordinates if necessary */
2882 if(appData.showCoords)
2884 cairo_text_extents_t extents;
2888 /* TODO this has to go into the font-selection */
2889 cairo_select_font_face (cr, "Sans",
2890 CAIRO_FONT_SLANT_NORMAL,
2891 CAIRO_FONT_WEIGHT_NORMAL);
2892 cairo_set_font_size (cr, 12.0);
2894 string[1] = NULLCHAR;
2897 cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window));
2899 if (row == (flipView ? BOARD_HEIGHT-1 : 0) &&
2900 column >= BOARD_LEFT && column < BOARD_RGHT)
2902 string[0] = 'a' + column - BOARD_LEFT;
2903 cairo_text_extents (cr, string, &extents);
2905 xpos = x + squareSize - extents.width - 2;
2906 ypos = y + squareSize - extents.height - extents.y_bearing - 1;
2908 if (appData.monoMode)
2915 cairo_move_to (cr, xpos, ypos);
2916 cairo_text_path (cr, string);
2917 cairo_set_source_rgb (cr, 0.0, 0.0, 0);
2918 cairo_fill_preserve (cr);
2919 cairo_set_source_rgb (cr, 0, 1.0, 0);
2920 cairo_set_line_width (cr, 0.1);
2923 if ( column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT))
2926 string[0] = ONE + row;
2927 cairo_text_extents (cr, string, &extents);
2930 ypos = y + extents.height + 1;
2932 if (appData.monoMode)
2939 cairo_move_to (cr, xpos, ypos);
2940 cairo_text_path (cr, string);
2941 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
2942 cairo_fill_preserve (cr);
2943 cairo_set_source_rgb (cr, 0, 0, 1.0);
2944 cairo_set_line_width (cr, 0.1);
2956 /* Returns 1 if there are "too many" differences between b1 and b2
2957 (i.e. more than 1 move was made) */
2958 static int too_many_diffs(b1, b2)
2964 for (i=0; i<BOARD_HEIGHT; ++i) {
2965 for (j=0; j<BOARD_WIDTH; ++j) {
2966 if (b1[i][j] != b2[i][j]) {
2967 if (++c > 4) /* Castling causes 4 diffs */
2976 /* Matrix describing castling maneuvers */
2977 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
2978 static int castling_matrix[4][5] = {
2979 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
2980 { 0, 7, 4, 5, 6 }, /* 0-0, white */
2981 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
2982 { 7, 7, 4, 5, 6 } /* 0-0, black */
2985 /* Checks whether castling occurred. If it did, *rrow and *rcol
2986 are set to the destination (row,col) of the rook that moved.
2988 Returns 1 if castling occurred, 0 if not.
2990 Note: Only handles a max of 1 castling move, so be sure
2991 to call too_many_diffs() first.
2993 static int check_castle_draw(newb, oldb, rrow, rcol)
3000 /* For each type of castling... */
3001 for (i=0; i<4; ++i) {
3002 r = castling_matrix[i];
3004 /* Check the 4 squares involved in the castling move */
3006 for (j=1; j<=4; ++j) {
3007 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
3014 /* All 4 changed, so it must be a castling move */
3023 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
3025 DrawSeekAxis( int x, int y, int xTo, int yTo )
3027 // XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
3031 DrawSeekBackground( int left, int top, int right, int bottom )
3033 // XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
3037 DrawSeekText(char *buf, int x, int y)
3039 // XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
3043 DrawSeekDot(int x, int y, int colorNr)
3045 int square = colorNr & 0x80;
3048 // color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
3050 // XFillRectangle(xDisplay, xBoardWindow, color,
3051 // x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
3053 // XFillArc(xDisplay, xBoardWindow, color,
3054 // x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
3057 static int damage[BOARD_RANKS][BOARD_FILES];
3060 * event handler for redrawing the board
3062 void DrawPosition( repaint, board)
3063 /*Boolean*/int repaint;
3067 static int lastFlipView = 0;
3068 static int lastBoardValid = 0;
3069 static Board lastBoard;
3072 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
3074 if (board == NULL) {
3075 if (!lastBoardValid) return;
3078 if (!lastBoardValid || lastFlipView != flipView) {
3079 // XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
3080 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
3085 * It would be simpler to clear the window with XClearWindow()
3086 * but this causes a very distracting flicker.
3089 if (!repaint && lastBoardValid && lastFlipView == flipView)
3091 /* If too much changes (begin observing new game, etc.), don't
3093 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
3095 /* Special check for castling so we don't flash both the king
3096 and the rook (just flash the king). */
3099 if (check_castle_draw(board, lastBoard, &rrow, &rcol))
3101 /* Draw rook with NO flashing. King will be drawn flashing later */
3102 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
3103 lastBoard[rrow][rcol] = board[rrow][rcol];
3107 /* First pass -- Draw (newly) empty squares and repair damage.
3108 This prevents you from having a piece show up twice while it
3109 is flashing on its new square */
3110 for (i = 0; i < BOARD_HEIGHT; i++)
3111 for (j = 0; j < BOARD_WIDTH; j++)
3112 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
3115 DrawSquare(i, j, board[i][j], 0);
3116 damage[i][j] = False;
3119 /* Second pass -- Draw piece(s) in new position and flash them */
3120 for (i = 0; i < BOARD_HEIGHT; i++)
3121 for (j = 0; j < BOARD_WIDTH; j++)
3122 if (board[i][j] != lastBoard[i][j])
3124 DrawSquare(i, j, board[i][j], do_flash);
3136 cr = gdk_cairo_create (GDK_WINDOW(GUI_Board->window));
3138 cairo_set_line_width (cr, lineGap);
3140 /* TODO: use appdata colors */
3141 cairo_set_source_rgba (cr, 0, 1, 0, 1.0);
3145 for (i = 0; i < BOARD_HEIGHT + 1; i++)
3148 x2 = lineGap + BOARD_WIDTH * (squareSize + lineGap);
3149 y1 = y2 = lineGap / 2 + (i * (squareSize + lineGap));
3151 cairo_move_to (cr, x1, y1);
3152 cairo_rel_line_to (cr, x2,0);
3156 for (j = 0; j < BOARD_WIDTH + 1; j++)
3159 y2 = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3160 x1 = x2 = lineGap / 2 + (j * (squareSize + lineGap));
3162 cairo_move_to (cr, x1, y1);
3163 cairo_rel_line_to (cr, 0, y2);
3172 for (i = 0; i < BOARD_HEIGHT; i++)
3173 for (j = 0; j < BOARD_WIDTH; j++)
3175 DrawSquare(i, j, board[i][j], 0);
3176 damage[i][j] = False;
3180 CopyBoard(lastBoard, board);
3182 lastFlipView = flipView;
3184 /* Draw highlights */
3185 if (pm1X >= 0 && pm1Y >= 0)
3187 drawHighlight(pm1X, pm1Y, LINE_TYPE_PRE);
3189 if (pm2X >= 0 && pm2Y >= 0)
3191 drawHighlight(pm2X, pm2Y, LINE_TYPE_PRE);
3193 if (hi1X >= 0 && hi1Y >= 0)
3195 drawHighlight(hi1X, hi1Y, LINE_TYPE_HIGHLIGHT);
3197 if (hi2X >= 0 && hi2Y >= 0)
3199 drawHighlight(hi2X, hi2Y, LINE_TYPE_HIGHLIGHT);
3202 /* If piece being dragged around board, must redraw that too */
3208 void AnimateUserMove (Widget w, XEvent * event,
3209 String * params, Cardinal * nParams)
3211 DragPieceMove(event->xmotion.x, event->xmotion.y);
3214 void HandlePV (Widget w, XEvent * event,
3215 String * params, Cardinal * nParams)
3216 { // [HGM] pv: walk PV
3217 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
3220 Widget CommentCreate(name, text, mutable, callback, lines)
3222 int /*Boolean*/ mutable;
3223 XtCallbackProc callback;
3227 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
3232 XtSetArg(args[j], XtNwidth, &bw_width); j++;
3233 XtGetValues(boardWidget, args, j);
3236 XtSetArg(args[j], XtNresizable, True); j++;
3239 // XtCreatePopupShell(name, topLevelShellWidgetClass,
3240 // shellWidget, args, j);
3243 // XtCreatePopupShell(name, transientShellWidgetClass,
3244 // shellWidget, args, j);
3247 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
3248 layoutArgs, XtNumber(layoutArgs));
3250 XtCreateManagedWidget("form", formWidgetClass, layout,
3251 formArgs, XtNumber(formArgs));
3255 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
3256 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
3258 XtSetArg(args[j], XtNstring, text); j++;
3259 XtSetArg(args[j], XtNtop, XtChainTop); j++;
3260 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3261 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3262 XtSetArg(args[j], XtNright, XtChainRight); j++;
3263 XtSetArg(args[j], XtNresizable, True); j++;
3264 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
3265 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
3266 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
3267 XtSetArg(args[j], XtNautoFill, True); j++;
3268 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
3270 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
3274 XtSetArg(args[j], XtNfromVert, edit); j++;
3275 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
3276 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3277 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3278 XtSetArg(args[j], XtNright, XtChainLeft); j++;
3280 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
3281 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
3284 XtSetArg(args[j], XtNfromVert, edit); j++;
3285 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
3286 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
3287 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3288 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3289 XtSetArg(args[j], XtNright, XtChainLeft); j++;
3291 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
3292 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
3295 XtSetArg(args[j], XtNfromVert, edit); j++;
3296 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
3297 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
3298 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3299 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3300 XtSetArg(args[j], XtNright, XtChainLeft); j++;
3302 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
3303 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
3306 XtSetArg(args[j], XtNfromVert, edit); j++;
3307 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
3308 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3309 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3310 XtSetArg(args[j], XtNright, XtChainLeft); j++;
3312 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
3313 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
3316 XtSetArg(args[j], XtNfromVert, edit); j++;
3317 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
3318 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
3319 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3320 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3321 XtSetArg(args[j], XtNright, XtChainLeft); j++;
3323 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
3324 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
3327 XtRealizeWidget(shell);
3329 if (commentX == -1) {
3332 Dimension pw_height;
3333 Dimension ew_height;
3336 XtSetArg(args[j], XtNheight, &ew_height); j++;
3337 XtGetValues(edit, args, j);
3340 XtSetArg(args[j], XtNheight, &pw_height); j++;
3341 XtGetValues(shell, args, j);
3342 commentH = pw_height + (lines - 1) * ew_height;
3343 commentW = bw_width - 16;
3345 // XSync(xDisplay, False);
3347 /* This code seems to tickle an X bug if it is executed too soon
3348 after xboard starts up. The coordinates get transformed as if
3349 the main window was positioned at (0, 0).
3351 // XtTranslateCoords(shellWidget,
3352 // (bw_width - commentW) / 2, 0 - commentH / 2,
3353 // &commentX, &commentY);
3355 // XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
3356 // RootWindowOfScreen(XtScreen(shellWidget)),
3357 // (bw_width - commentW) / 2, 0 - commentH / 2,
3358 // &xx, &yy, &junk);
3362 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
3365 if(wpComment.width > 0) {
3366 commentX = wpComment.x;
3367 commentY = wpComment.y;
3368 commentW = wpComment.width;
3369 commentH = wpComment.height;
3373 XtSetArg(args[j], XtNheight, commentH); j++;
3374 XtSetArg(args[j], XtNwidth, commentW); j++;
3375 XtSetArg(args[j], XtNx, commentX); j++;
3376 XtSetArg(args[j], XtNy, commentY); j++;
3377 XtSetValues(shell, args, j);
3378 XtSetKeyboardFocus(shell, edit);
3383 /* Used for analysis window and ICS input window */
3384 Widget MiscCreate(name, text, mutable, callback, lines)
3386 int /*Boolean*/ mutable;
3387 XtCallbackProc callback;
3391 Widget shell, layout, form, edit;
3393 Dimension bw_width, pw_height, ew_height, w, h;
3399 XtSetArg(args[j], XtNresizable, True); j++;
3402 // XtCreatePopupShell(name, topLevelShellWidgetClass,
3403 // shellWidget, args, j);
3406 // XtCreatePopupShell(name, transientShellWidgetClass,
3407 // shellWidget, args, j);
3410 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
3411 layoutArgs, XtNumber(layoutArgs));
3413 XtCreateManagedWidget("form", formWidgetClass, layout,
3414 formArgs, XtNumber(formArgs));
3418 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
3419 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
3421 XtSetArg(args[j], XtNstring, text); j++;
3422 XtSetArg(args[j], XtNtop, XtChainTop); j++;
3423 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
3424 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
3425 XtSetArg(args[j], XtNright, XtChainRight); j++;
3426 XtSetArg(args[j], XtNresizable, True); j++;
3427 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
3428 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
3429 XtSetArg(args[j], XtNautoFill, True); j++;
3430 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
3432 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
3434 XtRealizeWidget(shell);
3437 XtSetArg(args[j], XtNwidth, &bw_width); j++;
3438 XtGetValues(boardWidget, args, j);
3441 XtSetArg(args[j], XtNheight, &ew_height); j++;
3442 XtGetValues(edit, args, j);
3445 XtSetArg(args[j], XtNheight, &pw_height); j++;
3446 XtGetValues(shell, args, j);
3447 h = pw_height + (lines - 1) * ew_height;
3450 // XSync(xDisplay, False);
3452 /* This code seems to tickle an X bug if it is executed too soon
3453 after xboard starts up. The coordinates get transformed as if
3454 the main window was positioned at (0, 0).
3456 // XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
3458 // XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
3459 // RootWindowOfScreen(XtScreen(shellWidget)),
3460 // (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
3464 if (y < 0) y = 0; /*avoid positioning top offscreen*/
3467 XtSetArg(args[j], XtNheight, h); j++;
3468 XtSetArg(args[j], XtNwidth, w); j++;
3469 XtSetArg(args[j], XtNx, x); j++;
3470 XtSetArg(args[j], XtNy, y); j++;
3471 XtSetValues(shell, args, j);
3477 static int savedIndex; /* gross that this is global */
3479 void EditCommentPopUp(index, title, text)
3488 if (text == NULL) text = "";
3490 if (editShell == NULL) {
3492 CommentCreate(title, text, True, EditCommentCallback, 4);
3493 XtRealizeWidget(editShell);
3494 // CatchDeleteWindow(editShell, "EditCommentPopDown");
3496 edit = XtNameToWidget(editShell, "*form.text");
3498 XtSetArg(args[j], XtNstring, text); j++;
3499 XtSetValues(edit, args, j);
3501 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
3502 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
3503 XtSetValues(editShell, args, j);
3506 XtPopup(editShell, XtGrabNone);
3510 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
3511 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
3515 void EditCommentCallback(w, client_data, call_data)
3517 XtPointer client_data, call_data;
3525 XtSetArg(args[j], XtNlabel, &name); j++;
3526 XtGetValues(w, args, j);
3528 if (strcmp(name, _("ok")) == 0) {
3529 edit = XtNameToWidget(editShell, "*form.text");
3531 XtSetArg(args[j], XtNstring, &val); j++;
3532 XtGetValues(edit, args, j);
3533 ReplaceComment(savedIndex, val);
3534 EditCommentPopDown();
3535 } else if (strcmp(name, _("cancel")) == 0) {
3536 EditCommentPopDown();
3537 } else if (strcmp(name, _("clear")) == 0) {
3538 edit = XtNameToWidget(editShell, "*form.text");
3539 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
3540 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
3544 void EditCommentPopDown()
3549 if (!editUp) return;
3551 XtSetArg(args[j], XtNx, &commentX); j++;
3552 XtSetArg(args[j], XtNy, &commentY); j++;
3553 XtSetArg(args[j], XtNheight, &commentH); j++;
3554 XtSetArg(args[j], XtNwidth, &commentW); j++;
3555 XtGetValues(editShell, args, j);
3556 XtPopdown(editShell);
3559 XtSetArg(args[j], XtNleftBitmap, None); j++;
3560 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
3564 void ICSInputBoxPopUp()
3569 char *title = _("ICS Input");
3572 if (ICSInputShell == NULL) {
3573 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
3574 tr = XtParseTranslationTable(ICSInputTranslations);
3575 edit = XtNameToWidget(ICSInputShell, "*form.text");
3576 XtOverrideTranslations(edit, tr);
3577 XtRealizeWidget(ICSInputShell);
3578 // CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
3581 edit = XtNameToWidget(ICSInputShell, "*form.text");
3583 XtSetArg(args[j], XtNstring, ""); j++;
3584 XtSetValues(edit, args, j);
3586 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
3587 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
3588 XtSetValues(ICSInputShell, args, j);
3591 XtPopup(ICSInputShell, XtGrabNone);
3592 XtSetKeyboardFocus(ICSInputShell, edit);
3594 ICSInputBoxUp = True;
3596 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
3597 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
3601 void ICSInputSendText()
3608 edit = XtNameToWidget(ICSInputShell, "*form.text");
3610 XtSetArg(args[j], XtNstring, &val); j++;
3611 XtGetValues(edit, args, j);
3612 SendMultiLineToICS(val);
3613 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
3614 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
3617 void ICSInputBoxPopDown()
3622 if (!ICSInputBoxUp) return;
3624 XtPopdown(ICSInputShell);
3625 ICSInputBoxUp = False;
3627 XtSetArg(args[j], XtNleftBitmap, None); j++;
3628 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
3632 void CommentPopUp(title, text)
3639 if (commentShell == NULL) {
3641 CommentCreate(title, text, False, CommentCallback, 4);
3642 XtRealizeWidget(commentShell);
3643 // CatchDeleteWindow(commentShell, "CommentPopDown");
3645 edit = XtNameToWidget(commentShell, "*form.text");
3647 XtSetArg(args[j], XtNstring, text); j++;
3648 XtSetValues(edit, args, j);
3650 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
3651 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
3652 XtSetValues(commentShell, args, j);
3655 XtPopup(commentShell, XtGrabNone);
3656 // XSync(xDisplay, False);
3661 void CommentCallback(w, client_data, call_data)
3663 XtPointer client_data, call_data;
3670 XtSetArg(args[j], XtNlabel, &name); j++;
3671 XtGetValues(w, args, j);
3673 if (strcmp(name, _("close")) == 0) {
3675 } else if (strcmp(name, _("edit")) == 0) {
3682 void CommentPopDown()
3687 if (!commentUp) return;
3689 XtSetArg(args[j], XtNx, &commentX); j++;
3690 XtSetArg(args[j], XtNy, &commentY); j++;
3691 XtSetArg(args[j], XtNwidth, &commentW); j++;
3692 XtSetArg(args[j], XtNheight, &commentH); j++;
3693 XtGetValues(commentShell, args, j);
3694 XtPopdown(commentShell);
3695 // XSync(xDisplay, False);
3699 void PromotionPopUp()
3702 Widget dialog, layout;
3704 Dimension bw_width, pw_width;
3708 XtSetArg(args[j], XtNwidth, &bw_width); j++;
3709 XtGetValues(boardWidget, args, j);
3712 XtSetArg(args[j], XtNresizable, True); j++;
3713 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
3715 // XtCreatePopupShell("Promotion", transientShellWidgetClass,
3716 // shellWidget, args, j);
3718 // XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
3719 // layoutArgs, XtNumber(layoutArgs));
3722 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
3723 XtSetArg(args[j], XtNborderWidth, 0); j++;
3724 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
3727 if(gameInfo.variant != VariantShogi) {
3728 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
3729 (XtPointer) dialog);
3730 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
3731 (XtPointer) dialog);
3732 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
3733 (XtPointer) dialog);
3734 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
3735 (XtPointer) dialog);
3736 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
3737 gameInfo.variant == VariantGiveaway) {
3738 XawDialogAddButton(dialog, _("King"), PromotionCallback,
3739 (XtPointer) dialog);
3741 if(gameInfo.variant == VariantCapablanca ||
3742 gameInfo.variant == VariantGothic ||
3743 gameInfo.variant == VariantCapaRandom) {
3744 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
3745 (XtPointer) dialog);
3746 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
3747 (XtPointer) dialog);
3749 } else // [HGM] shogi
3751 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
3752 (XtPointer) dialog);
3753 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
3754 (XtPointer) dialog);
3756 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
3757 (XtPointer) dialog);
3759 XtRealizeWidget(promotionShell);
3760 // CatchDeleteWindow(promotionShell, "PromotionPopDown");
3763 XtSetArg(args[j], XtNwidth, &pw_width); j++;
3764 XtGetValues(promotionShell, args, j);
3766 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
3767 lineGap + squareSize/3 +
3768 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
3769 0 : 6*(squareSize + lineGap)), &x, &y);
3772 XtSetArg(args[j], XtNx, x); j++;
3773 XtSetArg(args[j], XtNy, y); j++;
3774 XtSetValues(promotionShell, args, j);
3776 XtPopup(promotionShell, XtGrabNone);
3781 void PromotionPopDown()
3783 if (!promotionUp) return;
3784 XtPopdown(promotionShell);
3785 XtDestroyWidget(promotionShell);
3786 promotionUp = False;
3789 void PromotionCallback(w, client_data, call_data)
3791 XtPointer client_data, call_data;
3797 XtSetArg(args[0], XtNlabel, &name);
3798 XtGetValues(w, args, 1);
3802 if (fromX == -1) return;
3804 if (strcmp(name, _("cancel")) == 0) {
3808 } else if (strcmp(name, _("Knight")) == 0) {
3810 } else if (strcmp(name, _("Promote")) == 0) {
3812 } else if (strcmp(name, _("Defer")) == 0) {
3815 promoChar = ToLower(name[0]);
3818 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
3820 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
3821 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
3826 void ErrorCallback(w, client_data, call_data)
3828 XtPointer client_data, call_data;
3831 XtPopdown(w = XtParent(XtParent(XtParent(w))));
3833 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
3839 if (!errorUp) return;
3843 gtk_widget_destroy(GTK_WIDGET(GUI_Error));
3845 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
3850 void ErrorPopUp(title, label, modal)
3851 char *title, *label;
3854 GUI_Error = gtk_message_dialog_new(GTK_WINDOW(GUI_Window),
3855 GTK_DIALOG_DESTROY_WITH_PARENT,
3860 gtk_window_set_title(GTK_WINDOW(GUI_Error),(gchar *) title);
3863 gtk_dialog_run(GTK_DIALOG(GUI_Error));
3864 gtk_widget_destroy(GTK_WIDGET(GUI_Error));
3868 g_signal_connect_swapped (GUI_Error, "response",
3869 G_CALLBACK (ErrorPopDownProc),
3872 gtk_widget_show(GTK_WIDGET(GUI_Error));
3878 /* Disable all user input other than deleting the window */
3879 static int frozen = 0;
3883 /* Grab by a widget that doesn't accept input */
3884 // XtAddGrab(messageWidget, TRUE, FALSE);
3888 /* Undo a FreezeUI */
3891 if (!frozen) return;
3892 // XtRemoveGrab(messageWidget);
3896 char *ModeToWidgetName(mode)
3900 case BeginningOfGame:
3901 if (appData.icsActive)
3902 return "menuMode.ICS Client";
3903 else if (appData.noChessProgram ||
3904 *appData.cmailGameName != NULLCHAR)
3905 return "menuMode.Edit Game";
3907 return "menuMode.Machine Black";
3908 case MachinePlaysBlack:
3909 return "menuMode.Machine Black";
3910 case MachinePlaysWhite:
3911 return "menuMode.Machine White";
3913 return "menuMode.Analysis Mode";
3915 return "menuMode.Analyze File";
3916 case TwoMachinesPlay:
3917 return "menuMode.Two Machines";
3919 return "menuMode.Edit Game";
3920 case PlayFromGameFile:
3921 return "menuFile.Load Game";
3923 return "menuMode.Edit Position";
3925 return "menuMode.Training";
3926 case IcsPlayingWhite:
3927 case IcsPlayingBlack:
3931 return "menuMode.ICS Client";
3938 void ModeHighlight()
3940 static int oldPausing = FALSE;
3941 static GameMode oldmode = (GameMode) -1;
3944 // todo this toggling of the pause button doesn't seem to work?
3945 // e.g. select pause from buttonbar doesn't activate menumode.pause
3947 // if (!boardWidget || !XtIsRealized(boardWidget)) return;
3949 if (pausing != oldPausing) {
3950 oldPausing = pausing;
3951 gtk_button_set_relief(GTK_BUTTON (gtk_builder_get_object (builder, "menuMode.Pause")),pausing?GTK_RELIEF_NORMAL:GTK_RELIEF_NONE);
3952 /* toggle background color in showbuttonbar */
3953 if (appData.showButtonBar) {
3955 gtk_button_pressed(GTK_BUTTON (gtk_builder_get_object (builder, "buttonbar.Pause")));
3957 gtk_button_released(GTK_BUTTON (gtk_builder_get_object (builder, "buttonbar.Pause")));
3962 // probably not needed anymore
3963 // wname = ModeToWidgetName(oldmode);
3965 // gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, wname)),True);
3969 /* Maybe all the enables should be handled here, not just this one */
3970 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM (gtk_builder_get_object (builder, "menuMode.Training")),
3971 gameMode == Training || gameMode == PlayFromGameFile);
3976 * Button/menu procedures
3979 int LoadGamePopUp(f, gameNumber, title)
3984 cmailMsgLoaded = FALSE;
3986 if (gameNumber == 0)
3988 int error = GameListBuild(f);
3992 DisplayError(_("Cannot build game list"), error);
3994 else if (!ListEmpty(&gameList)
3995 && ((ListGame *) gameList.tailPred)->number > 1)
3997 /* we need an answer which game to load, so let's make it modal for a while*/
3998 gtk_window_set_modal(GTK_WINDOW(GUI_GameList) , TRUE);
3999 GameListPopUp(f, title);
4000 gtk_window_set_modal(GTK_WINDOW(GUI_GameList) , FALSE);
4009 return LoadGame(f, gameNumber, title, FALSE);
4012 void ReloadCmailMsgProc(w, event, prms, nprms)
4018 ReloadCmailMsgEvent(FALSE);
4021 void MailMoveProc(w, event, prms, nprms)
4030 /* this variable is shared between CopyPositionProc and SendPositionSelection */
4031 char *selected_fen_position=NULL;
4034 SendPositionSelection(Widget w, Atom *selection, Atom *target,
4035 Atom *type_return, XtPointer *value_return,
4036 unsigned long *length_return, int *format_return)
4038 char *selection_tmp;
4040 if (!selected_fen_position) return False; /* should never happen */
4041 // if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
4042 // /* note: since no XtSelectionDoneProc was registered, Xt will
4043 // * automatically call XtFree on the value returned. So have to
4044 // * make a copy of it allocated with XtMalloc */
4045 // selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
4046 // strcpy(selection_tmp, selected_fen_position);
4048 // *value_return=selection_tmp;
4049 // *length_return=strlen(selection_tmp);
4050 // *type_return=*target;
4051 // *format_return = 8; /* bits per byte */
4053 // } else if (*target == XA_TARGETS(xDisplay)) {
4054 // Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
4055 // targets_tmp[0] = XA_UTF8_STRING(xDisplay);
4056 // targets_tmp[1] = XA_STRING;
4057 // *value_return = targets_tmp;
4058 // *type_return = XA_ATOM;
4059 // *length_return = 2;
4060 // *format_return = 8 * sizeof(Atom);
4061 // if (*format_return > 32) {
4062 // *length_return *= *format_return / 32;
4063 // *format_return = 32;
4071 /* note: when called from menu all parameters are NULL, so no clue what the
4072 * Widget which was clicked on was, or what the click event was
4074 void CopyPositionProc(w, event, prms, nprms)
4081 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
4082 * have a notion of a position that is selected but not copied.
4083 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
4085 if(gameMode == EditPosition) EditPositionDone(TRUE);
4086 if (selected_fen_position) free(selected_fen_position);
4087 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
4088 if (!selected_fen_position) return;
4089 // XtOwnSelection(menuBarWidget, XA_PRIMARY,
4091 // SendPositionSelection,
4092 // NULL/* lose_ownership_proc */ ,
4093 // NULL/* transfer_done_proc */);
4094 // XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
4096 // SendPositionSelection,
4097 // NULL/* lose_ownership_proc */ ,
4098 // NULL/* transfer_done_proc */);
4101 /* function called when the data to Paste is ready */
4103 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
4104 Atom *type, XtPointer value, unsigned long *len, int *format)
4107 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
4108 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
4109 EditPositionPasteFEN(fenstr);
4113 /* called when Paste Position button is pressed,
4114 * all parameters will be NULL */
4115 void PastePositionProc(w, event, prms, nprms)
4121 // XtGetSelectionValue(menuBarWidget,
4122 // appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
4123 // /* (XtSelectionCallbackProc) */ PastePositionCB,
4124 // NULL, /* client_data passed to PastePositionCB */
4126 // /* better to use the time field from the event that triggered the
4127 // * call to this function, but that isn't trivial to get
4135 SendGameSelection(Widget w, Atom *selection, Atom *target,
4136 Atom *type_return, XtPointer *value_return,
4137 unsigned long *length_return, int *format_return)
4139 char *selection_tmp;
4141 // if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
4142 // FILE* f = fopen(gameCopyFilename, "r");
4145 // if (f == NULL) return False;
4149 // selection_tmp = XtMalloc(len + 1);
4150 // count = fread(selection_tmp, 1, len, f);
4151 // if (len != count) {
4152 // XtFree(selection_tmp);
4155 // selection_tmp[len] = NULLCHAR;
4156 // *value_return = selection_tmp;
4157 // *length_return = len;
4158 // *type_return = *target;
4159 // *format_return = 8; /* bits per byte */
4161 // } else if (*target == XA_TARGETS(xDisplay)) {
4162 // Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
4163 // targets_tmp[0] = XA_UTF8_STRING(xDisplay);
4164 // targets_tmp[1] = XA_STRING;
4165 // *value_return = targets_tmp;
4166 // *type_return = XA_ATOM;
4167 // *length_return = 2;
4168 // *format_return = 8 * sizeof(Atom);
4169 // if (*format_return > 32) {
4170 // *length_return *= *format_return / 32;
4171 // *format_return = 32;
4179 /* note: when called from menu all parameters are NULL, so no clue what the
4180 * Widget which was clicked on was, or what the click event was
4182 void CopyGameProc(w, event, prms, nprms)
4190 ret = SaveGameToFile(gameCopyFilename, FALSE);
4194 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
4195 * have a notion of a game that is selected but not copied.
4196 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
4198 // XtOwnSelection(menuBarWidget, XA_PRIMARY,
4200 // SendGameSelection,
4201 // NULL/* lose_ownership_proc */ ,
4202 // NULL/* transfer_done_proc */);
4203 // XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
4205 // SendGameSelection,
4206 // NULL/* lose_ownership_proc */ ,
4207 // NULL/* transfer_done_proc */);
4210 /* function called when the data to Paste is ready */
4212 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
4213 Atom *type, XtPointer value, unsigned long *len, int *format)
4216 if (value == NULL || *len == 0) {
4217 return; /* nothing had been selected to copy */
4219 f = fopen(gamePasteFilename, "w");
4221 DisplayError(_("Can't open temp file"), errno);
4224 fwrite(value, 1, *len, f);
4227 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
4230 /* called when Paste Game button is pressed,
4231 * all parameters will be NULL */
4232 void PasteGameProc(w, event, prms, nprms)
4238 // XtGetSelectionValue(menuBarWidget,
4239 // appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
4240 // /* (XtSelectionCallbackProc) */ PasteGameCB,
4241 // NULL, /* client_data passed to PasteGameCB */
4243 // /* better to use the time field from the event that triggered the
4244 // * call to this function, but that isn't trivial to get
4251 void SaveOnExitProc(w, event, prms, nprms)
4259 saveSettingsOnExit = !saveSettingsOnExit;
4261 if (saveSettingsOnExit) {
4262 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
4264 XtSetArg(args[0], XtNleftBitmap, None);
4266 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
4270 void SaveSettingsProc(w, event, prms, nprms)
4276 SaveSettings(settingsFileName);
4282 SaveGameProc(NULL, NULL);
4287 void EditCommentProc(w, event, prms, nprms)
4294 EditCommentPopDown();
4300 void IcsInputBoxProc(w, event, prms, nprms)
4306 if (ICSInputBoxUp) {
4307 ICSInputBoxPopDown();
4314 void EnterKeyProc(w, event, prms, nprms)
4320 if (ICSInputBoxUp == True)
4325 void DebugProc(w, event, prms, nprms)
4331 appData.debugMode = !appData.debugMode;
4334 void AboutGameProc(w, event, prms, nprms)
4343 void NothingProc(w, event, prms, nprms)
4352 void Iconify(w, event, prms, nprms)
4360 // fromX = fromY = -1;
4361 // XtSetArg(args[0], XtNiconic, True);
4362 // XtSetValues(shellWidget, args, 1);
4365 void DisplayMessage(message, extMessage)
4366 gchar *message, *extMessage;
4373 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
4376 message = extMessage;
4379 gtk_label_set_text( GTK_LABEL(gtk_builder_get_object (builder, "Messages")),message);
4384 void DisplayTitle(text)
4387 gchar title[MSG_SIZ];
4389 if (text == NULL) text = "";
4391 if (appData.titleInWindow)
4396 if (*text != NULLCHAR)
4398 strcpy(title, text);
4400 else if (appData.icsActive)
4402 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
4404 else if (appData.cmailGameName[0] != NULLCHAR)
4406 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
4408 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
4410 else if (gameInfo.variant == VariantGothic)
4412 strcpy(title, GOTHIC);
4416 else if (gameInfo.variant == VariantFalcon)
4418 strcpy(title, FALCON);
4421 else if (appData.noChessProgram)
4423 strcpy(title, programName);
4427 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
4429 gtk_window_set_title(GTK_WINDOW(GUI_Window),title);
4435 void DisplayError(message, error)
4442 if (appData.debugMode || appData.matchMode) {
4443 fprintf(stderr, "%s: %s\n", programName, message);
4446 if (appData.debugMode || appData.matchMode) {
4447 fprintf(stderr, "%s: %s: %s\n",
4448 programName, message, strerror(error));
4450 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
4453 ErrorPopUp(_("Error"), message, FALSE);
4457 void DisplayMoveError(message)
4462 DrawPosition(FALSE, NULL);
4463 if (appData.debugMode || appData.matchMode) {
4464 fprintf(stderr, "%s: %s\n", programName, message);
4466 if (appData.popupMoveErrors) {
4467 ErrorPopUp(_("Error"), message, FALSE);
4469 DisplayMessage(message, "");
4474 void DisplayFatalError(message, error, status)
4480 errorExitStatus = status;
4482 fprintf(stderr, "%s: %s\n", programName, message);
4484 fprintf(stderr, "%s: %s: %s\n",
4485 programName, message, strerror(error));
4486 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
4489 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
4490 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
4496 void DisplayInformation(message)
4500 ErrorPopUp(_("Information"), message, TRUE);
4503 void DisplayNote(message)
4507 ErrorPopUp(_("Note"), message, FALSE);
4511 NullXErrorCheck(dpy, error_event)
4513 XErrorEvent *error_event;
4518 void DisplayIcsInteractionTitle(message)
4521 if (oldICSInteractionTitle == NULL) {
4522 /* Magic to find the old window title, adapted from vim */
4523 char *wina = getenv("WINDOWID");
4525 Window win = (Window) atoi(wina);
4526 Window root, parent, *children;
4527 unsigned int nchildren;
4528 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
4530 // if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
4531 // if (!XQueryTree(xDisplay, win, &root, &parent,
4532 // &children, &nchildren)) break;
4533 // if (children) XFree((void *)children);
4534 // if (parent == root || parent == 0) break;
4537 XSetErrorHandler(oldHandler);
4539 if (oldICSInteractionTitle == NULL) {
4540 oldICSInteractionTitle = "xterm";
4543 printf("\033]0;%s\007", message);
4547 char pendingReplyPrefix[MSG_SIZ];
4548 ProcRef pendingReplyPR;
4550 void AskQuestionProc(w, event, prms, nprms)
4557 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
4561 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
4564 void AskQuestionPopDown()
4566 if (!askQuestionUp) return;
4567 XtPopdown(askQuestionShell);
4568 XtDestroyWidget(askQuestionShell);
4569 askQuestionUp = False;
4572 void AskQuestionReplyAction(w, event, prms, nprms)
4582 reply = XawDialogGetValueString(w = XtParent(w));
4583 strcpy(buf, pendingReplyPrefix);
4584 if (*buf) strcat(buf, " ");
4587 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
4588 AskQuestionPopDown();
4590 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
4593 void AskQuestionCallback(w, client_data, call_data)
4595 XtPointer client_data, call_data;
4600 XtSetArg(args[0], XtNlabel, &name);
4601 XtGetValues(w, args, 1);
4603 if (strcmp(name, _("cancel")) == 0) {
4604 AskQuestionPopDown();
4606 AskQuestionReplyAction(w, NULL, NULL, NULL);
4610 void AskQuestion(title, question, replyPrefix, pr)
4611 char *title, *question, *replyPrefix;
4615 Widget popup, layout, dialog, edit;
4621 strcpy(pendingReplyPrefix, replyPrefix);
4622 pendingReplyPR = pr;
4625 XtSetArg(args[i], XtNresizable, True); i++;
4626 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4627 // askQuestionShell = popup =
4628 // XtCreatePopupShell(title, transientShellWidgetClass,
4629 // shellWidget, args, i);
4632 // XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4633 // layoutArgs, XtNumber(layoutArgs));
4636 XtSetArg(args[i], XtNlabel, question); i++;
4637 XtSetArg(args[i], XtNvalue, ""); i++;
4638 XtSetArg(args[i], XtNborderWidth, 0); i++;
4639 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
4642 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
4643 (XtPointer) dialog);
4644 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
4645 (XtPointer) dialog);
4647 XtRealizeWidget(popup);
4648 // CatchDeleteWindow(popup, "AskQuestionPopDown");
4650 // XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4651 // &x, &y, &win_x, &win_y, &mask);
4653 // XtSetArg(args[0], XtNx, x - 10);
4654 // XtSetArg(args[1], XtNy, y - 30);
4655 // XtSetValues(popup, args, 2);
4657 // XtPopup(popup, XtGrabExclusive);
4658 // askQuestionUp = True;
4660 // edit = XtNameToWidget(dialog, "*value");
4661 // XtSetKeyboardFocus(popup, edit);
4669 if (*name == NULLCHAR) {
4671 } else if (strcmp(name, "$") == 0) {
4672 putc(BELLCHAR, stderr);
4675 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
4683 PlaySound(appData.soundMove);
4689 PlaySound(appData.soundIcsWin);
4695 PlaySound(appData.soundIcsLoss);
4701 PlaySound(appData.soundIcsDraw);
4705 PlayIcsUnfinishedSound()
4707 PlaySound(appData.soundIcsUnfinished);
4713 PlaySound(appData.soundIcsAlarm);
4719 system("stty echo");
4725 system("stty -echo");
4729 Colorize(cc, continuation)
4734 int count, outCount, error;
4736 if (textColors[(int)cc].bg > 0) {
4737 if (textColors[(int)cc].fg > 0) {
4738 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
4739 textColors[(int)cc].fg, textColors[(int)cc].bg);
4741 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
4742 textColors[(int)cc].bg);
4745 if (textColors[(int)cc].fg > 0) {
4746 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
4747 textColors[(int)cc].fg);
4749 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
4752 count = strlen(buf);
4753 outCount = OutputToProcess(NoProc, buf, count, &error);
4754 if (outCount < count) {
4755 DisplayFatalError(_("Error writing to display"), error, 1);
4758 if (continuation) return;
4761 PlaySound(appData.soundShout);
4764 PlaySound(appData.soundSShout);
4767 PlaySound(appData.soundChannel1);
4770 PlaySound(appData.soundChannel);
4773 PlaySound(appData.soundKibitz);
4776 PlaySound(appData.soundTell);
4778 case ColorChallenge:
4779 PlaySound(appData.soundChallenge);
4782 PlaySound(appData.soundRequest);
4785 PlaySound(appData.soundSeek);
4796 return getpwuid(getuid())->pw_name;
4799 static char *ExpandPathName(path)
4802 static char static_buf[2000];
4803 char *d, *s, buf[2000];
4809 while (*s && isspace(*s))
4818 if (*(s+1) == '/') {
4819 strcpy(d, getpwuid(getuid())->pw_dir);
4824 *strchr(buf, '/') = 0;
4825 pwd = getpwnam(buf);
4828 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
4832 strcpy(d, pwd->pw_dir);
4833 strcat(d, strchr(s+1, '/'));
4844 static char host_name[MSG_SIZ];
4846 #if HAVE_GETHOSTNAME
4847 gethostname(host_name, MSG_SIZ);
4849 #else /* not HAVE_GETHOSTNAME */
4850 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
4851 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
4853 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
4855 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
4856 #endif /* not HAVE_GETHOSTNAME */
4859 guint delayedEventTimerTag = 0;
4860 DelayedEventCallback delayedEventCallback = 0;
4863 FireDelayedEvent(data)
4867 g_source_remove(delayedEventTimerTag);
4868 delayedEventTimerTag = 0;
4871 delayedEventCallback();
4877 ScheduleDelayedEvent(cb, millisec)
4878 DelayedEventCallback cb; guint millisec;
4880 if(delayedEventTimerTag && delayedEventCallback == cb)
4881 // [HGM] alive: replace, rather than add or flush identical event
4882 g_source_remove(delayedEventTimerTag);
4883 delayedEventCallback = cb;
4884 delayedEventTimerTag = g_timeout_add(millisec,(GSourceFunc) FireDelayedEvent, NULL);
4888 DelayedEventCallback
4891 if (delayedEventTimerTag)
4893 return delayedEventCallback;
4902 CancelDelayedEvent()
4904 if (delayedEventTimerTag)
4906 g_source_remove(delayedEventTimerTag);
4907 delayedEventTimerTag = 0;
4913 guint loadGameTimerTag = 0;
4915 int LoadGameTimerRunning()
4917 return loadGameTimerTag != 0;
4920 int StopLoadGameTimer()
4922 if (loadGameTimerTag != 0) {
4923 g_source_remove(loadGameTimerTag);
4924 loadGameTimerTag = 0;
4932 LoadGameTimerCallback(data)
4936 g_source_remove(loadGameTimerTag);
4937 loadGameTimerTag = 0;
4944 StartLoadGameTimer(millisec)
4948 g_timeout_add( millisec, (GSourceFunc) LoadGameTimerCallback, NULL);
4952 guint analysisClockTag = 0;
4955 AnalysisClockCallback(data)
4958 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
4959 || appData.icsEngineAnalyze)
4961 AnalysisPeriodicEvent(0);
4962 return 1; /* keep on going */
4964 return 0; /* stop timer */
4968 StartAnalysisClock()
4971 g_timeout_add( 2000,(GSourceFunc) AnalysisClockCallback, NULL);
4975 guint clockTimerTag = 0;
4977 int ClockTimerRunning()
4979 return clockTimerTag != 0;
4982 int StopClockTimer()
4984 if (clockTimerTag != 0)
4986 g_source_remove(clockTimerTag);
4997 ClockTimerCallback(data)
5001 g_source_remove(clockTimerTag);
5009 StartClockTimer(millisec)
5012 clockTimerTag = g_timeout_add(millisec,(GSourceFunc) ClockTimerCallback,NULL);
5017 DisplayTimerLabel(w, color, timer, highlight)
5026 if (appData.clockMode) {
5027 sprintf(buf, "%s: %s", color, TimeString(timer));
5029 sprintf(buf, "%s ", color);
5031 gtk_label_set_text(GTK_LABEL(w),buf);
5033 /* check for low time warning */
5034 // Pixel foregroundOrWarningColor = timerForegroundPixel;
5037 // appData.lowTimeWarning &&
5038 // (timer / 1000) < appData.icsAlarmTime)
5039 // foregroundOrWarningColor = lowTimeWarningColor;
5041 // if (appData.clockMode) {
5042 // sprintf(buf, "%s: %s", color, TimeString(timer));
5043 // XtSetArg(args[0], XtNlabel, buf);
5045 // sprintf(buf, "%s ", color);
5046 // XtSetArg(args[0], XtNlabel, buf);
5051 // XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
5052 // XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
5054 // XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
5055 // XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
5058 // XtSetValues(w, args, 3);
5063 DisplayWhiteClock(timeRemaining, highlight)
5067 if(appData.noGUI) return;
5069 DisplayTimerLabel(GUI_Whiteclock, _("White"), timeRemaining, highlight);
5070 if (highlight && WindowIcon == BlackIcon)
5072 WindowIcon = WhiteIcon;
5073 gtk_window_set_icon(GTK_WINDOW(GUI_Window),WindowIcon);
5078 DisplayBlackClock(timeRemaining, highlight)
5082 if(appData.noGUI) return;
5084 DisplayTimerLabel(GUI_Blackclock, _("Black"), timeRemaining, highlight);
5085 if (highlight && WindowIcon == WhiteIcon)
5087 WindowIcon = BlackIcon;
5088 gtk_window_set_icon(GTK_WINDOW(GUI_Window),WindowIcon);
5106 int StartChildProcess(cmdLine, dir, pr)
5113 int to_prog[2], from_prog[2];
5117 if (appData.debugMode) {
5118 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
5121 /* We do NOT feed the cmdLine to the shell; we just
5122 parse it into blank-separated arguments in the
5123 most simple-minded way possible.
5126 strcpy(buf, cmdLine);
5129 while(*p == ' ') p++;
5131 if(*p == '"' || *p == '\'')
5132 p = strchr(++argv[i-1], *p);
5133 else p = strchr(p, ' ');
5134 if (p == NULL) break;
5139 SetUpChildIO(to_prog, from_prog);
5141 if ((pid = fork()) == 0) {
5143 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
5144 close(to_prog[1]); // first close the unused pipe ends
5145 close(from_prog[0]);
5146 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
5147 dup2(from_prog[1], 1);
5148 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
5149 close(from_prog[1]); // and closing again loses one of the pipes!
5150 if(fileno(stderr) >= 2) // better safe than sorry...
5151 dup2(1, fileno(stderr)); /* force stderr to the pipe */
5153 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
5158 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
5160 execvp(argv[0], argv);
5162 /* If we get here, exec failed */
5167 /* Parent process */
5169 close(from_prog[1]);
5171 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
5174 cp->fdFrom = from_prog[0];
5175 cp->fdTo = to_prog[1];
5180 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
5181 static RETSIGTYPE AlarmCallBack(int n)
5187 DestroyChildProcess(pr, signalType)
5191 ChildProc *cp = (ChildProc *) pr;
5193 if (cp->kind != CPReal) return;
5195 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
5196 signal(SIGALRM, AlarmCallBack);
5198 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
5199 kill(cp->pid, SIGKILL); // kill it forcefully
5200 wait((int *) 0); // and wait again
5204 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
5206 /* Process is exiting either because of the kill or because of
5207 a quit command sent by the backend; either way, wait for it to die.
5216 InterruptChildProcess(pr)
5219 ChildProc *cp = (ChildProc *) pr;
5221 if (cp->kind != CPReal) return;
5222 (void) kill(cp->pid, SIGINT); /* stop it thinking */
5225 int OpenTelnet(host, port, pr)
5230 char cmdLine[MSG_SIZ];
5232 if (port[0] == NULLCHAR) {
5233 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
5235 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
5237 return StartChildProcess(cmdLine, "", pr);
5240 int OpenTCP(host, port, pr)
5246 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
5247 #else /* !OMIT_SOCKETS */
5249 struct sockaddr_in sa;
5251 unsigned short uport;
5254 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
5258 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
5259 sa.sin_family = AF_INET;
5260 sa.sin_addr.s_addr = INADDR_ANY;
5261 uport = (unsigned short) 0;
5262 sa.sin_port = htons(uport);
5263 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
5267 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
5268 if (!(hp = gethostbyname(host))) {
5270 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
5271 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
5272 hp->h_addrtype = AF_INET;
5274 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
5275 hp->h_addr_list[0] = (char *) malloc(4);
5276 hp->h_addr_list[0][0] = b0;
5277 hp->h_addr_list[0][1] = b1;
5278 hp->h_addr_list[0][2] = b2;
5279 hp->h_addr_list[0][3] = b3;
5284 sa.sin_family = hp->h_addrtype;
5285 uport = (unsigned short) atoi(port);
5286 sa.sin_port = htons(uport);
5287 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
5289 if (connect(s, (struct sockaddr *) &sa,
5290 sizeof(struct sockaddr_in)) < 0) {
5294 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
5301 #endif /* !OMIT_SOCKETS */
5306 int OpenCommPort(name, pr)
5313 fd = open(name, 2, 0);
5314 if (fd < 0) return errno;
5316 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
5326 int OpenLoopback(pr)
5332 SetUpChildIO(to, from);
5334 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
5337 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
5344 int OpenRcmd(host, user, cmd, pr)
5345 char *host, *user, *cmd;
5348 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
5352 #define INPUT_SOURCE_BUF_SIZE 8192
5361 char buf[INPUT_SOURCE_BUF_SIZE];
5366 DoInputCallback(io,cond,data)
5371 /* read input from one of the input source (for example a chess program, ICS, etc).
5372 * and call a function that will handle the input
5375 int count; /* how many bytes did we read */
5379 /* All information (callback function, file descriptor, etc) is
5380 * saved in an InputSource structure
5382 InputSource *is = (InputSource *) data;
5386 count = read(is->fd, is->unused,
5387 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
5391 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
5394 is->unused += count;
5396 /* break input into lines and call the callback function on each
5399 while (p < is->unused)
5401 q = memchr(p, '\n', is->unused - p);
5402 if (q == NULL) break;
5404 (is->func)(is, is->closure, p, q - p, 0);
5407 /* remember not yet used part of the buffer */
5409 while (p < is->unused)
5417 /* read maximum length of input buffer and send the whole buffer
5418 * to the callback function
5420 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
5425 (is->func)(is, is->closure, is->buf, count, error);
5431 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
5438 GIOChannel *channel;
5439 ChildProc *cp = (ChildProc *) pr;
5441 is = (InputSource *) calloc(1, sizeof(InputSource));
5442 is->lineByLine = lineByLine;
5446 is->fd = fileno(stdin);
5448 is->kind = cp->kind;
5449 is->fd = cp->fdFrom;
5452 is->unused = is->buf;
5456 // is->xid = XtAppAddInput(appContext, is->fd,
5457 // (XtPointer) (XtInputReadMask),
5458 // (XtInputCallbackProc) DoInputCallback,
5462 /* TODO: will this work on windows?*/
5464 channel = g_io_channel_unix_new(is->fd);
5465 g_io_channel_set_close_on_unref (channel, TRUE);
5466 is->sid = g_io_add_watch(channel, G_IO_IN,(GIOFunc) DoInputCallback, is);
5467 is->closure = closure;
5468 return (InputSourceRef) is;
5472 RemoveInputSource(isr)
5475 InputSource *is = (InputSource *) isr;
5477 if (is->sid == 0) return;
5478 g_source_remove(is->sid);
5483 int OutputToProcess(pr, message, count, outError)
5489 static int line = 0;
5490 ChildProc *cp = (ChildProc *) pr;
5495 if (appData.noJoin || !appData.useInternalWrap)
5496 outCount = fwrite(message, 1, count, stdout);
5499 int width = get_term_width();
5500 int len = wrap(NULL, message, count, width, &line);
5501 char *msg = malloc(len);
5505 outCount = fwrite(message, 1, count, stdout);
5508 dbgchk = wrap(msg, message, count, width, &line);
5509 if (dbgchk != len && appData.debugMode)
5510 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
5511 outCount = fwrite(msg, 1, dbgchk, stdout);
5517 outCount = write(cp->fdTo, message, count);
5527 /* Output message to process, with "ms" milliseconds of delay
5528 between each character. This is needed when sending the logon
5529 script to ICC, which for some reason doesn't like the
5530 instantaneous send. */
5531 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
5538 ChildProc *cp = (ChildProc *) pr;
5543 r = write(cp->fdTo, message++, 1);
5556 /**** Animation code by Hugh Fisher, DCS, ANU.
5558 Known problem: if a window overlapping the board is
5559 moved away while a piece is being animated underneath,
5560 the newly exposed area won't be updated properly.
5561 I can live with this.
5563 Known problem: if you look carefully at the animation
5564 of pieces in mono mode, they are being drawn as solid
5565 shapes without interior detail while moving. Fixing
5566 this would be a major complication for minimal return.
5569 /* Masks for XPM pieces. Black and white pieces can have
5570 different shapes, but in the interest of retaining my
5571 sanity pieces must have the same outline on both light
5572 and dark squares, and all pieces must use the same
5573 background square colors/images. */
5575 static int xpmDone = 0;
5578 CreateAnimMasks (pieceDepth)
5585 unsigned long plane;
5588 /* just return for gtk at the moment */
5591 /* Need a bitmap just to get a GC with right depth */
5592 // buf = XCreatePixmap(xDisplay, xBoardWindow,
5594 values.foreground = 1;
5595 values.background = 0;
5596 /* Don't use XtGetGC, not read only */
5597 // maskGC = XCreateGC(xDisplay, buf,
5598 // GCForeground | GCBackground, &values);
5599 // XFreePixmap(xDisplay, buf);
5601 // buf = XCreatePixmap(xDisplay, xBoardWindow,
5602 // squareSize, squareSize, pieceDepth);
5603 // values.foreground = XBlackPixel(xDisplay, xScreen);
5604 // values.background = XWhitePixel(xDisplay, xScreen);
5605 // bufGC = XCreateGC(xDisplay, buf,
5606 // GCForeground | GCBackground, &values);
5608 for (piece = WhitePawn; piece <= BlackKing; piece++) {
5609 /* Begin with empty mask */
5610 // if(!xpmDone) // [HGM] pieces: keep using existing
5611 // xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
5612 // squareSize, squareSize, 1);
5613 // XSetFunction(xDisplay, maskGC, GXclear);
5614 // XFillRectangle(xDisplay, xpmMask[piece], maskGC,
5615 // 0, 0, squareSize, squareSize);
5617 /* Take a copy of the piece */
5622 // XSetFunction(xDisplay, bufGC, GXcopy);
5623 // XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
5625 // 0, 0, squareSize, squareSize, 0, 0);
5627 /* XOR the background (light) over the piece */
5628 // XSetFunction(xDisplay, bufGC, GXxor);
5630 // XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
5631 // 0, 0, squareSize, squareSize, 0, 0);
5633 // XSetForeground(xDisplay, bufGC, lightSquareColor);
5634 // XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
5637 /* We now have an inverted piece image with the background
5638 erased. Construct mask by just selecting all the non-zero
5639 pixels - no need to reconstruct the original image. */
5640 // XSetFunction(xDisplay, maskGC, GXor);
5642 /* Might be quicker to download an XImage and create bitmap
5643 data from it rather than this N copies per piece, but it
5644 only takes a fraction of a second and there is a much
5645 longer delay for loading the pieces. */
5646 // for (n = 0; n < pieceDepth; n ++) {
5647 // XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
5648 // 0, 0, squareSize, squareSize,
5650 // plane = plane << 1;
5654 // XFreePixmap(xDisplay, buf);
5655 // XFreeGC(xDisplay, bufGC);
5656 // XFreeGC(xDisplay, maskGC);
5660 InitAnimState (anim, info)
5662 XWindowAttributes * info;
5667 /* Each buffer is square size, same depth as window */
5668 // anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
5669 // squareSize, squareSize, info->depth);
5670 // anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
5671 // squareSize, squareSize, info->depth);
5673 // /* Create a plain GC for blitting */
5674 // mask = GCForeground | GCBackground | GCFunction |
5675 // GCPlaneMask | GCGraphicsExposures;
5676 // values.foreground = XBlackPixel(xDisplay, xScreen);
5677 // values.background = XWhitePixel(xDisplay, xScreen);
5678 // values.function = GXcopy;
5679 // values.plane_mask = AllPlanes;
5680 // values.graphics_exposures = False;
5681 // anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
5683 // /* Piece will be copied from an existing context at
5684 // the start of each new animation/drag. */
5685 // anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
5687 // /* Outline will be a read-only copy of an existing */
5688 // anim->outlineGC = None;
5694 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
5695 XWindowAttributes info;
5697 /* for gtk at the moment just ... */
5700 if (xpmDone && gameInfo.variant == old) return;
5701 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
5702 // XGetWindowAttributes(xDisplay, xBoardWindow, &info);
5704 // InitAnimState(&game, &info);
5705 // InitAnimState(&player, &info);
5707 /* For XPM pieces, we need bitmaps to use as masks. */
5709 // CreateAnimMasks(info.depth);
5715 static Boolean frameWaiting;
5717 static RETSIGTYPE FrameAlarm (sig)
5720 frameWaiting = False;
5721 /* In case System-V style signals. Needed?? */
5722 signal(SIGALRM, FrameAlarm);
5729 struct itimerval delay;
5731 XSync(xDisplay, False);
5734 frameWaiting = True;
5735 signal(SIGALRM, FrameAlarm);
5736 delay.it_interval.tv_sec =
5737 delay.it_value.tv_sec = time / 1000;
5738 delay.it_interval.tv_usec =
5739 delay.it_value.tv_usec = (time % 1000) * 1000;
5740 setitimer(ITIMER_REAL, &delay, NULL);
5741 while (frameWaiting) pause();
5742 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
5743 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
5744 setitimer(ITIMER_REAL, &delay, NULL);
5754 // XSync(xDisplay, False);
5756 usleep(time * 1000);
5761 /* Convert board position to corner of screen rect and color */
5764 ScreenSquare(column, row, pt, color)
5765 int column; int row; XPoint * pt; int * color;
5768 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
5769 pt->y = lineGap + row * (squareSize + lineGap);
5771 pt->x = lineGap + column * (squareSize + lineGap);
5772 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
5774 *color = SquareColor(row, column);
5777 /* Convert window coords to square */
5780 BoardSquare(x, y, column, row)
5781 int x; int y; int * column; int * row;
5783 *column = EventToSquare(x, BOARD_WIDTH);
5784 if (flipView && *column >= 0)
5785 *column = BOARD_WIDTH - 1 - *column;
5786 *row = EventToSquare(y, BOARD_HEIGHT);
5787 if (!flipView && *row >= 0)
5788 *row = BOARD_HEIGHT - 1 - *row;
5793 #undef Max /* just in case */
5795 #define Max(a, b) ((a) > (b) ? (a) : (b))
5796 #define Min(a, b) ((a) < (b) ? (a) : (b))
5799 SetRect(rect, x, y, width, height)
5800 XRectangle * rect; int x; int y; int width; int height;
5804 rect->width = width;
5805 rect->height = height;
5808 /* Test if two frames overlap. If they do, return
5809 intersection rect within old and location of
5810 that rect within new. */
5813 Intersect(old, new, size, area, pt)
5814 XPoint * old; XPoint * new;
5815 int size; XRectangle * area; XPoint * pt;
5817 if (old->x > new->x + size || new->x > old->x + size ||
5818 old->y > new->y + size || new->y > old->y + size) {
5821 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
5822 size - abs(old->x - new->x), size - abs(old->y - new->y));
5823 pt->x = Max(old->x - new->x, 0);
5824 pt->y = Max(old->y - new->y, 0);
5829 /* For two overlapping frames, return the rect(s)
5830 in the old that do not intersect with the new. */
5833 CalcUpdateRects(old, new, size, update, nUpdates)
5834 XPoint * old; XPoint * new; int size;
5835 XRectangle update[]; int * nUpdates;
5839 /* If old = new (shouldn't happen) then nothing to draw */
5840 if (old->x == new->x && old->y == new->y) {
5844 /* Work out what bits overlap. Since we know the rects
5845 are the same size we don't need a full intersect calc. */
5847 /* Top or bottom edge? */
5848 if (new->y > old->y) {
5849 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
5851 } else if (old->y > new->y) {
5852 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
5853 size, old->y - new->y);
5856 /* Left or right edge - don't overlap any update calculated above. */
5857 if (new->x > old->x) {
5858 SetRect(&(update[count]), old->x, Max(new->y, old->y),
5859 new->x - old->x, size - abs(new->y - old->y));
5861 } else if (old->x > new->x) {
5862 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
5863 old->x - new->x, size - abs(new->y - old->y));
5870 /* Generate a series of frame coords from start->mid->finish.
5871 The movement rate doubles until the half way point is
5872 reached, then halves back down to the final destination,
5873 which gives a nice slow in/out effect. The algorithmn
5874 may seem to generate too many intermediates for short
5875 moves, but remember that the purpose is to attract the
5876 viewers attention to the piece about to be moved and
5877 then to where it ends up. Too few frames would be less
5881 Tween(start, mid, finish, factor, frames, nFrames)
5882 XPoint * start; XPoint * mid;
5883 XPoint * finish; int factor;
5884 XPoint frames[]; int * nFrames;
5886 int fraction, n, count;
5890 /* Slow in, stepping 1/16th, then 1/8th, ... */
5892 for (n = 0; n < factor; n++)
5894 for (n = 0; n < factor; n++) {
5895 frames[count].x = start->x + (mid->x - start->x) / fraction;
5896 frames[count].y = start->y + (mid->y - start->y) / fraction;
5898 fraction = fraction / 2;
5902 frames[count] = *mid;
5905 /* Slow out, stepping 1/2, then 1/4, ... */
5907 for (n = 0; n < factor; n++) {
5908 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
5909 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
5911 fraction = fraction * 2;
5916 /* Draw a piece on the screen without disturbing what's there */
5919 SelectGCMask(piece, clip, outline, mask)
5920 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
5924 /* Bitmap for piece being moved. */
5925 if (appData.monoMode) {
5926 *mask = *pieceToSolid(piece);
5927 } else if (useImages) {
5929 *mask = xpmMask[piece];
5931 *mask = ximMaskPm[piece];
5934 *mask = *pieceToSolid(piece);
5937 /* GC for piece being moved. Square color doesn't matter, but
5938 since it gets modified we make a copy of the original. */
5940 if (appData.monoMode)
5945 if (appData.monoMode)
5950 // XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
5952 /* Outline only used in mono mode and is not modified */
5954 *outline = bwPieceGC;
5956 *outline = wbPieceGC;
5960 OverlayPiece(piece, clip, outline, dest)
5961 ChessSquare piece; GC clip; GC outline; Drawable dest;
5966 /* Draw solid rectangle which will be clipped to shape of piece */
5967 // XFillRectangle(xDisplay, dest, clip,
5968 // 0, 0, squareSize, squareSize)
5970 if (appData.monoMode)
5971 /* Also draw outline in contrasting color for black
5972 on black / white on white cases */
5973 // XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
5974 // 0, 0, squareSize, squareSize, 0, 0, 1)
5977 /* Copy the piece */
5982 // XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
5984 // 0, 0, squareSize, squareSize,
5989 /* Animate the movement of a single piece */
5992 BeginAnimation(anim, piece, startColor, start)
6000 /* The old buffer is initialised with the start square (empty) */
6001 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
6002 anim->prevFrame = *start;
6004 /* The piece will be drawn using its own bitmap as a matte */
6005 // SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
6006 // XSetClipMask(xDisplay, anim->pieceGC, mask);
6010 AnimationFrame(anim, frame, piece)
6015 XRectangle updates[4];
6020 /* Save what we are about to draw into the new buffer */
6021 // XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
6022 // frame->x, frame->y, squareSize, squareSize,
6025 /* Erase bits of the previous frame */
6026 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
6027 /* Where the new frame overlapped the previous,
6028 the contents in newBuf are wrong. */
6029 // XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
6030 // overlap.x, overlap.y,
6031 // overlap.width, overlap.height,
6033 /* Repaint the areas in the old that don't overlap new */
6034 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
6035 for (i = 0; i < count; i++)
6036 // XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
6037 // updates[i].x - anim->prevFrame.x,
6038 // updates[i].y - anim->prevFrame.y,
6039 // updates[i].width, updates[i].height,
6040 // updates[i].x, updates[i].y)
6043 /* Easy when no overlap */
6044 // XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
6045 // 0, 0, squareSize, squareSize,
6046 // anim->prevFrame.x, anim->prevFrame.y);
6049 /* Save this frame for next time round */
6050 // XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
6051 // 0, 0, squareSize, squareSize,
6053 anim->prevFrame = *frame;
6055 /* Draw piece over original screen contents, not current,
6056 and copy entire rect. Wipes out overlapping piece images. */
6057 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
6058 // XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
6059 // 0, 0, squareSize, squareSize,
6060 // frame->x, frame->y);
6064 EndAnimation (anim, finish)
6068 XRectangle updates[4];
6073 /* The main code will redraw the final square, so we
6074 only need to erase the bits that don't overlap. */
6075 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
6076 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
6077 for (i = 0; i < count; i++)
6078 // XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
6079 // updates[i].x - anim->prevFrame.x,
6080 // updates[i].y - anim->prevFrame.y,
6081 // updates[i].width, updates[i].height,
6082 // updates[i].x, updates[i].y)
6085 // XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
6086 // 0, 0, squareSize, squareSize,
6087 // anim->prevFrame.x, anim->prevFrame.y);
6092 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
6094 ChessSquare piece; int startColor;
6095 XPoint * start; XPoint * finish;
6096 XPoint frames[]; int nFrames;
6100 BeginAnimation(anim, piece, startColor, start);
6101 for (n = 0; n < nFrames; n++) {
6102 AnimationFrame(anim, &(frames[n]), piece);
6103 FrameDelay(appData.animSpeed);
6105 EndAnimation(anim, finish);
6108 /* Main control logic for deciding what to animate and how */
6111 AnimateMove(board, fromX, fromY, toX, toY)
6120 XPoint start, finish, mid;
6121 XPoint frames[kFactor * 2 + 1];
6122 int nFrames, startColor, endColor;
6124 /* Are we animating? */
6125 if (!appData.animate || appData.blindfold)
6128 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
6129 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
6130 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
6132 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
6133 piece = board[fromY][fromX];
6134 if (piece >= EmptySquare) return;
6139 hop = (piece == WhiteKnight || piece == BlackKnight);
6142 if (appData.debugMode) {
6143 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
6144 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
6145 piece, fromX, fromY, toX, toY); }
6147 ScreenSquare(fromX, fromY, &start, &startColor);
6148 ScreenSquare(toX, toY, &finish, &endColor);
6151 /* Knight: make diagonal movement then straight */
6152 if (abs(toY - fromY) < abs(toX - fromX)) {
6153 mid.x = start.x + (finish.x - start.x) / 2;
6157 mid.y = start.y + (finish.y - start.y) / 2;
6160 mid.x = start.x + (finish.x - start.x) / 2;
6161 mid.y = start.y + (finish.y - start.y) / 2;
6164 /* Don't use as many frames for very short moves */
6165 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
6166 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
6168 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
6169 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
6171 /* Be sure end square is redrawn */
6172 damage[toY][toX] = True;
6176 DragPieceBegin(x, y)
6179 int boardX, boardY, color;
6182 /* Are we animating? */
6183 if (!appData.animateDragging || appData.blindfold)
6186 /* Figure out which square we start in and the
6187 mouse position relative to top left corner. */
6188 BoardSquare(x, y, &boardX, &boardY);
6189 player.startBoardX = boardX;
6190 player.startBoardY = boardY;
6191 ScreenSquare(boardX, boardY, &corner, &color);
6192 player.startSquare = corner;
6193 player.startColor = color;
6194 /* As soon as we start dragging, the piece will jump slightly to
6195 be centered over the mouse pointer. */
6196 player.mouseDelta.x = squareSize/2;
6197 player.mouseDelta.y = squareSize/2;
6198 /* Initialise animation */
6199 player.dragPiece = PieceForSquare(boardX, boardY);
6201 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
6202 player.dragActive = True;
6203 BeginAnimation(&player, player.dragPiece, color, &corner);
6204 /* Mark this square as needing to be redrawn. Note that
6205 we don't remove the piece though, since logically (ie
6206 as seen by opponent) the move hasn't been made yet. */
6207 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
6208 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
6209 // XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
6210 // corner.x, corner.y, squareSize, squareSize,
6211 // 0, 0); // [HGM] zh: unstack in stead of grab
6212 damage[boardY][boardX] = True;
6214 player.dragActive = False;
6224 /* Are we animating? */
6225 if (!appData.animateDragging || appData.blindfold)
6229 if (! player.dragActive)
6231 /* Move piece, maintaining same relative position
6232 of mouse within square */
6233 corner.x = x - player.mouseDelta.x;
6234 corner.y = y - player.mouseDelta.y;
6235 AnimationFrame(&player, &corner, player.dragPiece);
6237 if (appData.highlightDragging) {
6239 BoardSquare(x, y, &boardX, &boardY);
6240 SetHighlights(fromX, fromY, boardX, boardY);
6249 int boardX, boardY, color;
6252 /* Are we animating? */
6253 if (!appData.animateDragging || appData.blindfold)
6257 if (! player.dragActive)
6259 /* Last frame in sequence is square piece is
6260 placed on, which may not match mouse exactly. */
6261 BoardSquare(x, y, &boardX, &boardY);
6262 ScreenSquare(boardX, boardY, &corner, &color);
6263 EndAnimation(&player, &corner);
6265 /* Be sure end square is redrawn */
6266 damage[boardY][boardX] = True;
6268 /* This prevents weird things happening with fast successive
6269 clicks which on my Sun at least can cause motion events
6270 without corresponding press/release. */
6271 player.dragActive = False;
6274 /* Handle expose event while piece being dragged */
6279 if (!player.dragActive || appData.blindfold)
6282 /* What we're doing: logically, the move hasn't been made yet,
6283 so the piece is still in it's original square. But visually
6284 it's being dragged around the board. So we erase the square
6285 that the piece is on and draw it at the last known drag point. */
6286 BlankSquare(player.startSquare.x, player.startSquare.y,
6287 player.startColor, EmptySquare, xBoardWindow);
6288 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
6289 damage[player.startBoardY][player.startBoardX] = TRUE;
6292 #include <sys/ioctl.h>
6293 int get_term_width()
6295 int fd, default_width;
6298 default_width = 79; // this is FICS default anyway...
6300 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
6302 if (!ioctl(fd, TIOCGSIZE, &win))
6303 default_width = win.ts_cols;
6304 #elif defined(TIOCGWINSZ)
6306 if (!ioctl(fd, TIOCGWINSZ, &win))
6307 default_width = win.ws_col;
6309 return default_width;
6312 void update_ics_width()
6314 static int old_width = 0;
6315 int new_width = get_term_width();
6317 if (old_width != new_width)
6318 ics_printf("set width %d\n", new_width);
6319 old_width = new_width;
6322 void NotifyFrontendLogin()