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, 2010 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"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
237 char *init_path, char *mode, int (*show_entry)(), char **name_return));
238 RETSIGTYPE CmailSigHandler P((int sig));
239 RETSIGTYPE IntSigHandler P((int sig));
240 RETSIGTYPE TermSizeSigHandler P((int sig));
241 void CreateGCs P((void));
242 void CreateXIMPieces P((void));
243 void CreateXPMPieces P((void));
244 void CreatePieces P((void));
245 void CreatePieceMenus P((void));
246 Widget CreateMenuBar P((Menu *mb));
247 Widget CreateButtonBar P ((MenuItem *mi));
248 char *FindFont P((char *pattern, int targetPxlSize));
249 void PieceMenuPopup P((Widget w, XEvent *event,
250 String *params, Cardinal *num_params));
251 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
252 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
253 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
254 u_int wreq, u_int hreq));
255 void CreateGrid P((void));
256 int EventToSquare P((int x, int limit));
257 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
258 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
259 void HandleUserMove P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void AnimateUserMove P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void HandlePV P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void SelectPV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void StopPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void WhiteClock P((Widget w, XEvent *event,
270 String *prms, Cardinal *nprms));
271 void BlackClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void DrawPositionProc P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
277 void CommentClick P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void CommentPopUp P((char *title, char *label));
280 void CommentPopDown P((void));
281 void CommentCallback P((Widget w, XtPointer client_data,
282 XtPointer call_data));
283 void ICSInputBoxPopUp P((void));
284 void ICSInputBoxPopDown P((void));
285 void FileNamePopUp P((char *label, char *def,
286 FileProc proc, char *openMode));
287 void FileNamePopDown P((void));
288 void FileNameCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void FileNameAction P((Widget w, XEvent *event,
291 String *prms, Cardinal *nprms));
292 void AskQuestionReplyAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionProc P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionPopDown P((void));
297 void PromotionPopDown P((void));
298 void PromotionCallback P((Widget w, XtPointer client_data,
299 XtPointer call_data));
300 void EditCommentPopDown P((void));
301 void EditCommentCallback P((Widget w, XtPointer client_data,
302 XtPointer call_data));
303 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
304 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
305 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
306 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
310 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
312 void LoadPositionProc P((Widget w, XEvent *event,
313 String *prms, Cardinal *nprms));
314 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
318 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
320 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
322 void PastePositionProc P((Widget w, XEvent *event, String *prms,
324 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void SavePositionProc P((Widget w, XEvent *event,
328 String *prms, Cardinal *nprms));
329 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
332 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
336 void MachineWhiteProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void AnalyzeModeProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeFileProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
344 void IcsClientProc P((Widget w, XEvent *event, String *prms,
346 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void EditPositionProc P((Widget w, XEvent *event,
348 String *prms, Cardinal *nprms));
349 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void EditCommentProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void IcsInputBoxProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void StopObservingProc P((Widget w, XEvent *event, String *prms,
370 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
372 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
381 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
383 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
386 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
388 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
390 void AutocommProc P((Widget w, XEvent *event, String *prms,
392 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void AutobsProc P((Widget w, XEvent *event, String *prms,
396 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
401 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
404 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
406 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
408 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
424 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
426 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
428 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
430 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void DisplayMove P((int moveNumber));
442 void DisplayTitle P((char *title));
443 void ICSInitScript P((void));
444 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
445 void ErrorPopUp P((char *title, char *text, int modal));
446 void ErrorPopDown P((void));
447 static char *ExpandPathName P((char *path));
448 static void CreateAnimVars P((void));
449 static void DragPieceMove P((int x, int y));
450 static void DrawDragPiece P((void));
451 char *ModeToWidgetName P((GameMode mode));
452 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopDown P(());
461 void ShufflePopDown P(());
462 void EnginePopDown P(());
463 void UciPopDown P(());
464 void TimeControlPopDown P(());
465 void NewVariantPopDown P(());
466 void SettingsPopDown P(());
467 void update_ics_width P(());
468 int get_term_width P(());
469 int CopyMemoProc P(());
471 * XBoard depends on Xt R4 or higher
473 int xtVersion = XtSpecificationRelease;
478 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
479 jailSquareColor, highlightSquareColor, premoveHighlightColor;
480 Pixel lowTimeWarningColor;
481 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
482 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
483 wjPieceGC, bjPieceGC, prelineGC, countGC;
484 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
485 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
486 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
487 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
488 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
489 ICSInputShell, fileNameShell, askQuestionShell;
490 Widget historyShell, evalGraphShell, gameListShell;
491 int hOffset; // [HGM] dual
492 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
493 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
494 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
495 Font clockFontID, coordFontID, countFontID;
496 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
497 XtAppContext appContext;
499 char *oldICSInteractionTitle;
503 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
505 Position commentX = -1, commentY = -1;
506 Dimension commentW, commentH;
507 typedef unsigned int BoardSize;
509 Boolean chessProgram;
511 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
512 int squareSize, smallLayout = 0, tinyLayout = 0,
513 marginW, marginH, // [HGM] for run-time resizing
514 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
515 ICSInputBoxUp = False, askQuestionUp = False,
516 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
517 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
518 Pixel timerForegroundPixel, timerBackgroundPixel;
519 Pixel buttonForegroundPixel, buttonBackgroundPixel;
520 char *chessDir, *programName, *programVersion,
521 *gameCopyFilename, *gamePasteFilename;
522 Boolean alwaysOnTop = False;
523 Boolean saveSettingsOnExit;
524 char *settingsFileName;
525 char *icsTextMenuString;
527 char *firstChessProgramNames;
528 char *secondChessProgramNames;
530 WindowPlacement wpMain;
531 WindowPlacement wpConsole;
532 WindowPlacement wpComment;
533 WindowPlacement wpMoveHistory;
534 WindowPlacement wpEvalGraph;
535 WindowPlacement wpEngineOutput;
536 WindowPlacement wpGameList;
537 WindowPlacement wpTags;
541 Pixmap pieceBitmap[2][(int)BlackPawn];
542 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
543 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
544 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
545 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
546 int useImages, useImageSqs;
547 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
548 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
549 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
550 XImage *ximLightSquare, *ximDarkSquare;
553 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
554 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
556 #define White(piece) ((int)(piece) < (int)BlackPawn)
558 /* Variables for doing smooth animation. This whole thing
559 would be much easier if the board was double-buffered,
560 but that would require a fairly major rewrite. */
565 GC blitGC, pieceGC, outlineGC;
566 XPoint startSquare, prevFrame, mouseDelta;
570 int startBoardX, startBoardY;
573 /* There can be two pieces being animated at once: a player
574 can begin dragging a piece before the remote opponent has moved. */
576 static AnimState game, player;
578 /* Bitmaps for use as masks when drawing XPM pieces.
579 Need one for each black and white piece. */
580 static Pixmap xpmMask[BlackKing + 1];
582 /* This magic number is the number of intermediate frames used
583 in each half of the animation. For short moves it's reduced
584 by 1. The total number of frames will be factor * 2 + 1. */
587 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
589 MenuItem fileMenu[] = {
590 {N_("New Game"), ResetProc},
591 {N_("New Shuffle Game ..."), ShuffleMenuProc},
592 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
593 {"----", NothingProc},
594 {N_("Load Game"), LoadGameProc},
595 {N_("Load Next Game"), LoadNextGameProc},
596 {N_("Load Previous Game"), LoadPrevGameProc},
597 {N_("Reload Same Game"), ReloadGameProc},
598 {N_("Save Game"), SaveGameProc},
599 {"----", NothingProc},
600 {N_("Copy Game"), CopyGameProc},
601 {N_("Paste Game"), PasteGameProc},
602 {"----", NothingProc},
603 {N_("Load Position"), LoadPositionProc},
604 {N_("Load Next Position"), LoadNextPositionProc},
605 {N_("Load Previous Position"), LoadPrevPositionProc},
606 {N_("Reload Same Position"), ReloadPositionProc},
607 {N_("Save Position"), SavePositionProc},
608 {"----", NothingProc},
609 {N_("Copy Position"), CopyPositionProc},
610 {N_("Paste Position"), PastePositionProc},
611 {"----", NothingProc},
612 {N_("Mail Move"), MailMoveProc},
613 {N_("Reload CMail Message"), ReloadCmailMsgProc},
614 {"----", NothingProc},
615 {N_("Exit"), QuitProc},
619 MenuItem modeMenu[] = {
620 {N_("Machine White"), MachineWhiteProc},
621 {N_("Machine Black"), MachineBlackProc},
622 {N_("Two Machines"), TwoMachinesProc},
623 {N_("Analysis Mode"), AnalyzeModeProc},
624 {N_("Analyze File"), AnalyzeFileProc },
625 {N_("ICS Client"), IcsClientProc},
626 {N_("Edit Game"), EditGameProc},
627 {N_("Edit Position"), EditPositionProc},
628 {N_("Training"), TrainingProc},
629 {"----", NothingProc},
630 {N_("Show Engine Output"), EngineOutputProc},
631 {N_("Show Evaluation Graph"), EvalGraphProc},
632 {N_("Show Game List"), ShowGameListProc},
633 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
634 {"----", NothingProc},
635 {N_("Edit Tags"), EditTagsProc},
636 {N_("Edit Comment"), EditCommentProc},
637 {N_("ICS Input Box"), IcsInputBoxProc},
638 {N_("Pause"), PauseProc},
642 MenuItem actionMenu[] = {
643 {N_("Accept"), AcceptProc},
644 {N_("Decline"), DeclineProc},
645 {N_("Rematch"), RematchProc},
646 {"----", NothingProc},
647 {N_("Call Flag"), CallFlagProc},
648 {N_("Draw"), DrawProc},
649 {N_("Adjourn"), AdjournProc},
650 {N_("Abort"), AbortProc},
651 {N_("Resign"), ResignProc},
652 {"----", NothingProc},
653 {N_("Stop Observing"), StopObservingProc},
654 {N_("Stop Examining"), StopExaminingProc},
655 {N_("Upload to Examine"), UploadProc},
656 {"----", NothingProc},
657 {N_("Adjudicate to White"), AdjuWhiteProc},
658 {N_("Adjudicate to Black"), AdjuBlackProc},
659 {N_("Adjudicate Draw"), AdjuDrawProc},
663 MenuItem stepMenu[] = {
664 {N_("Backward"), BackwardProc},
665 {N_("Forward"), ForwardProc},
666 {N_("Back to Start"), ToStartProc},
667 {N_("Forward to End"), ToEndProc},
668 {N_("Revert"), RevertProc},
669 {N_("Annotate"), AnnotateProc},
670 {N_("Truncate Game"), TruncateGameProc},
671 {"----", NothingProc},
672 {N_("Move Now"), MoveNowProc},
673 {N_("Retract Move"), RetractMoveProc},
677 MenuItem optionsMenu[] = {
678 {N_("Flip View"), FlipViewProc},
679 {"----", NothingProc},
680 {N_("Adjudications ..."), EngineMenuProc},
681 {N_("General Settings ..."), UciMenuProc},
682 {N_("Engine #1 Settings ..."), FirstSettingsProc},
683 {N_("Engine #2 Settings ..."), SecondSettingsProc},
684 {N_("Time Control ..."), TimeControlProc},
685 {N_("Game List ..."), GameListOptionsPopUp},
686 {"----", NothingProc},
687 {N_("Always Queen"), AlwaysQueenProc},
688 {N_("Animate Dragging"), AnimateDraggingProc},
689 {N_("Animate Moving"), AnimateMovingProc},
690 {N_("Auto Comment"), AutocommProc},
691 {N_("Auto Flag"), AutoflagProc},
692 {N_("Auto Flip View"), AutoflipProc},
693 {N_("Auto Observe"), AutobsProc},
694 {N_("Auto Raise Board"), AutoraiseProc},
695 {N_("Auto Save"), AutosaveProc},
696 {N_("Blindfold"), BlindfoldProc},
697 {N_("Flash Moves"), FlashMovesProc},
698 {N_("Get Move List"), GetMoveListProc},
700 {N_("Highlight Dragging"), HighlightDraggingProc},
702 {N_("Highlight Last Move"), HighlightLastMoveProc},
703 {N_("Move Sound"), MoveSoundProc},
704 {N_("ICS Alarm"), IcsAlarmProc},
705 {N_("Old Save Style"), OldSaveStyleProc},
706 {N_("Periodic Updates"), PeriodicUpdatesProc},
707 {N_("Ponder Next Move"), PonderNextMoveProc},
708 {N_("Popup Exit Message"), PopupExitMessageProc},
709 {N_("Popup Move Errors"), PopupMoveErrorsProc},
710 {N_("Premove"), PremoveProc},
711 {N_("Quiet Play"), QuietPlayProc},
712 {N_("Show Coords"), ShowCoordsProc},
713 {N_("Hide Thinking"), HideThinkingProc},
714 {N_("Test Legality"), TestLegalityProc},
715 {"----", NothingProc},
716 {N_("Save Settings Now"), SaveSettingsProc},
717 {N_("Save Settings on Exit"), SaveOnExitProc},
721 MenuItem helpMenu[] = {
722 {N_("Info XBoard"), InfoProc},
723 {N_("Man XBoard"), ManProc},
724 {"----", NothingProc},
725 {N_("Hint"), HintProc},
726 {N_("Book"), BookProc},
727 {"----", NothingProc},
728 {N_("About XBoard"), AboutProc},
733 {N_("File"), fileMenu},
734 {N_("Mode"), modeMenu},
735 {N_("Action"), actionMenu},
736 {N_("Step"), stepMenu},
737 {N_("Options"), optionsMenu},
738 {N_("Help"), helpMenu},
742 #define PAUSE_BUTTON N_("P")
743 MenuItem buttonBar[] = {
746 {PAUSE_BUTTON, PauseProc},
752 #define PIECE_MENU_SIZE 18
753 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
754 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
755 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
756 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
757 N_("Empty square"), N_("Clear board") },
758 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
759 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
760 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
761 N_("Empty square"), N_("Clear board") }
763 /* must be in same order as PieceMenuStrings! */
764 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
765 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
766 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
767 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
768 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
769 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
770 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
771 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
772 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
775 #define DROP_MENU_SIZE 6
776 String dropMenuStrings[DROP_MENU_SIZE] = {
777 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
779 /* must be in same order as PieceMenuStrings! */
780 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
781 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
782 WhiteRook, WhiteQueen
790 DropMenuEnables dmEnables[] = {
808 { XtNborderWidth, 0 },
809 { XtNdefaultDistance, 0 },
813 { XtNborderWidth, 0 },
814 { XtNresizable, (XtArgVal) True },
818 { XtNborderWidth, 0 },
824 { XtNjustify, (XtArgVal) XtJustifyRight },
825 { XtNlabel, (XtArgVal) "..." },
826 { XtNresizable, (XtArgVal) True },
827 { XtNresize, (XtArgVal) False }
830 Arg messageArgs[] = {
831 { XtNjustify, (XtArgVal) XtJustifyLeft },
832 { XtNlabel, (XtArgVal) "..." },
833 { XtNresizable, (XtArgVal) True },
834 { XtNresize, (XtArgVal) False }
838 { XtNborderWidth, 0 },
839 { XtNjustify, (XtArgVal) XtJustifyLeft }
842 XtResource clientResources[] = {
843 { "flashCount", "flashCount", XtRInt, sizeof(int),
844 XtOffset(AppDataPtr, flashCount), XtRImmediate,
845 (XtPointer) FLASH_COUNT },
848 XrmOptionDescRec shellOptions[] = {
849 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
850 { "-flash", "flashCount", XrmoptionNoArg, "3" },
851 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
854 XtActionsRec boardActions[] = {
855 { "DrawPosition", DrawPositionProc },
856 { "HandleUserMove", HandleUserMove },
857 { "AnimateUserMove", AnimateUserMove },
858 { "HandlePV", HandlePV },
859 { "SelectPV", SelectPV },
860 { "StopPV", StopPV },
861 { "FileNameAction", FileNameAction },
862 { "AskQuestionProc", AskQuestionProc },
863 { "AskQuestionReplyAction", AskQuestionReplyAction },
864 { "PieceMenuPopup", PieceMenuPopup },
865 { "WhiteClock", WhiteClock },
866 { "BlackClock", BlackClock },
867 { "Iconify", Iconify },
868 { "ResetProc", ResetProc },
869 { "NewVariantProc", NewVariantProc },
870 { "LoadGameProc", LoadGameProc },
871 { "LoadNextGameProc", LoadNextGameProc },
872 { "LoadPrevGameProc", LoadPrevGameProc },
873 { "LoadSelectedProc", LoadSelectedProc },
874 { "SetFilterProc", SetFilterProc },
875 { "ReloadGameProc", ReloadGameProc },
876 { "LoadPositionProc", LoadPositionProc },
877 { "LoadNextPositionProc", LoadNextPositionProc },
878 { "LoadPrevPositionProc", LoadPrevPositionProc },
879 { "ReloadPositionProc", ReloadPositionProc },
880 { "CopyPositionProc", CopyPositionProc },
881 { "PastePositionProc", PastePositionProc },
882 { "CopyGameProc", CopyGameProc },
883 { "PasteGameProc", PasteGameProc },
884 { "SaveGameProc", SaveGameProc },
885 { "SavePositionProc", SavePositionProc },
886 { "MailMoveProc", MailMoveProc },
887 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
888 { "QuitProc", QuitProc },
889 { "MachineWhiteProc", MachineWhiteProc },
890 { "MachineBlackProc", MachineBlackProc },
891 { "AnalysisModeProc", AnalyzeModeProc },
892 { "AnalyzeFileProc", AnalyzeFileProc },
893 { "TwoMachinesProc", TwoMachinesProc },
894 { "IcsClientProc", IcsClientProc },
895 { "EditGameProc", EditGameProc },
896 { "EditPositionProc", EditPositionProc },
897 { "TrainingProc", EditPositionProc },
898 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
899 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
900 { "ShowGameListProc", ShowGameListProc },
901 { "ShowMoveListProc", HistoryShowProc},
902 { "EditTagsProc", EditCommentProc },
903 { "EditCommentProc", EditCommentProc },
904 { "IcsAlarmProc", IcsAlarmProc },
905 { "IcsInputBoxProc", IcsInputBoxProc },
906 { "PauseProc", PauseProc },
907 { "AcceptProc", AcceptProc },
908 { "DeclineProc", DeclineProc },
909 { "RematchProc", RematchProc },
910 { "CallFlagProc", CallFlagProc },
911 { "DrawProc", DrawProc },
912 { "AdjournProc", AdjournProc },
913 { "AbortProc", AbortProc },
914 { "ResignProc", ResignProc },
915 { "AdjuWhiteProc", AdjuWhiteProc },
916 { "AdjuBlackProc", AdjuBlackProc },
917 { "AdjuDrawProc", AdjuDrawProc },
918 { "EnterKeyProc", EnterKeyProc },
919 { "UpKeyProc", UpKeyProc },
920 { "DownKeyProc", DownKeyProc },
921 { "StopObservingProc", StopObservingProc },
922 { "StopExaminingProc", StopExaminingProc },
923 { "UploadProc", UploadProc },
924 { "BackwardProc", BackwardProc },
925 { "ForwardProc", ForwardProc },
926 { "ToStartProc", ToStartProc },
927 { "ToEndProc", ToEndProc },
928 { "RevertProc", RevertProc },
929 { "AnnotateProc", AnnotateProc },
930 { "TruncateGameProc", TruncateGameProc },
931 { "MoveNowProc", MoveNowProc },
932 { "RetractMoveProc", RetractMoveProc },
933 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
934 { "UciMenuProc", (XtActionProc) UciMenuProc },
935 { "TimeControlProc", (XtActionProc) TimeControlProc },
936 { "AlwaysQueenProc", AlwaysQueenProc },
937 { "AnimateDraggingProc", AnimateDraggingProc },
938 { "AnimateMovingProc", AnimateMovingProc },
939 { "AutoflagProc", AutoflagProc },
940 { "AutoflipProc", AutoflipProc },
941 { "AutobsProc", AutobsProc },
942 { "AutoraiseProc", AutoraiseProc },
943 { "AutosaveProc", AutosaveProc },
944 { "BlindfoldProc", BlindfoldProc },
945 { "FlashMovesProc", FlashMovesProc },
946 { "FlipViewProc", FlipViewProc },
947 { "GetMoveListProc", GetMoveListProc },
949 { "HighlightDraggingProc", HighlightDraggingProc },
951 { "HighlightLastMoveProc", HighlightLastMoveProc },
952 { "IcsAlarmProc", IcsAlarmProc },
953 { "MoveSoundProc", MoveSoundProc },
954 { "OldSaveStyleProc", OldSaveStyleProc },
955 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
956 { "PonderNextMoveProc", PonderNextMoveProc },
957 { "PopupExitMessageProc", PopupExitMessageProc },
958 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
959 { "PremoveProc", PremoveProc },
960 { "QuietPlayProc", QuietPlayProc },
961 { "ShowCoordsProc", ShowCoordsProc },
962 { "ShowThinkingProc", ShowThinkingProc },
963 { "HideThinkingProc", HideThinkingProc },
964 { "TestLegalityProc", TestLegalityProc },
965 { "SaveSettingsProc", SaveSettingsProc },
966 { "SaveOnExitProc", SaveOnExitProc },
967 { "InfoProc", InfoProc },
968 { "ManProc", ManProc },
969 { "HintProc", HintProc },
970 { "BookProc", BookProc },
971 { "AboutGameProc", AboutGameProc },
972 { "AboutProc", AboutProc },
973 { "DebugProc", DebugProc },
974 { "NothingProc", NothingProc },
975 { "CommentClick", (XtActionProc) CommentClick },
976 { "CommentPopDown", (XtActionProc) CommentPopDown },
977 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
978 { "TagsPopDown", (XtActionProc) TagsPopDown },
979 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
980 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
981 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
982 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
983 { "GameListPopDown", (XtActionProc) GameListPopDown },
984 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
985 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
986 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
987 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
988 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
989 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
990 { "EnginePopDown", (XtActionProc) EnginePopDown },
991 { "UciPopDown", (XtActionProc) UciPopDown },
992 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
993 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
994 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
995 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
998 char globalTranslations[] =
999 ":<Key>F9: ResignProc() \n \
1000 :Ctrl<Key>n: ResetProc() \n \
1001 :Meta<Key>V: NewVariantProc() \n \
1002 :Ctrl<Key>o: LoadGameProc() \n \
1003 :Meta<Key>Next: LoadNextGameProc() \n \
1004 :Meta<Key>Prior: LoadPrevGameProc() \n \
1005 :Ctrl<Key>s: SaveGameProc() \n \
1006 :Ctrl<Key>c: CopyGameProc() \n \
1007 :Ctrl<Key>v: PasteGameProc() \n \
1008 :Ctrl<Key>O: LoadPositionProc() \n \
1009 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1010 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1011 :Ctrl<Key>S: SavePositionProc() \n \
1012 :Ctrl<Key>C: CopyPositionProc() \n \
1013 :Ctrl<Key>V: PastePositionProc() \n \
1014 :Ctrl<Key>q: QuitProc() \n \
1015 :Ctrl<Key>w: MachineWhiteProc() \n \
1016 :Ctrl<Key>b: MachineBlackProc() \n \
1017 :Ctrl<Key>t: TwoMachinesProc() \n \
1018 :Ctrl<Key>a: AnalysisModeProc() \n \
1019 :Ctrl<Key>f: AnalyzeFileProc() \n \
1020 :Ctrl<Key>e: EditGameProc() \n \
1021 :Ctrl<Key>E: EditPositionProc() \n \
1022 :Meta<Key>O: EngineOutputProc() \n \
1023 :Meta<Key>E: EvalGraphProc() \n \
1024 :Meta<Key>G: ShowGameListProc() \n \
1025 :Meta<Key>H: ShowMoveListProc() \n \
1026 :<Key>Pause: PauseProc() \n \
1027 :<Key>F3: AcceptProc() \n \
1028 :<Key>F4: DeclineProc() \n \
1029 :<Key>F12: RematchProc() \n \
1030 :<Key>F5: CallFlagProc() \n \
1031 :<Key>F6: DrawProc() \n \
1032 :<Key>F7: AdjournProc() \n \
1033 :<Key>F8: AbortProc() \n \
1034 :<Key>F10: StopObservingProc() \n \
1035 :<Key>F11: StopExaminingProc() \n \
1036 :Meta Ctrl<Key>F12: DebugProc() \n \
1037 :Meta<Key>End: ToEndProc() \n \
1038 :Meta<Key>Right: ForwardProc() \n \
1039 :Meta<Key>Home: ToStartProc() \n \
1040 :Meta<Key>Left: BackwardProc() \n \
1041 :Ctrl<Key>m: MoveNowProc() \n \
1042 :Ctrl<Key>x: RetractMoveProc() \n \
1043 :Meta<Key>J: EngineMenuProc() \n \
1044 :Meta<Key>U: UciMenuProc() \n \
1045 :Meta<Key>T: TimeControlProc() \n \
1046 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1047 :Ctrl<Key>F: AutoflagProc() \n \
1048 :Ctrl<Key>A: AnimateMovingProc() \n \
1049 :Ctrl<Key>P: PonderNextMoveProc() \n \
1050 :Ctrl<Key>L: TestLegalityProc() \n \
1051 :Ctrl<Key>H: HideThinkingProc() \n \
1052 :<Key>-: Iconify() \n \
1053 :<Key>F1: ManProc() \n \
1054 :<Key>F2: FlipViewProc() \n \
1055 <KeyDown>.: BackwardProc() \n \
1056 <KeyUp>.: ForwardProc() \n \
1057 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1058 \"Send to chess program:\",,1) \n \
1059 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1060 \"Send to second chess program:\",,2) \n";
1062 char boardTranslations[] =
1063 "<Btn1Down>: HandleUserMove() \n \
1064 <Btn1Up>: HandleUserMove() \n \
1065 <Btn1Motion>: AnimateUserMove() \n \
1066 <Btn3Motion>: HandlePV() \n \
1067 <Btn3Up>: PieceMenuPopup(menuB) \n \
1068 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1069 PieceMenuPopup(menuB) \n \
1070 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1071 PieceMenuPopup(menuW) \n \
1072 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1073 PieceMenuPopup(menuW) \n \
1074 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1075 PieceMenuPopup(menuB) \n";
1077 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1078 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1080 char ICSInputTranslations[] =
1081 "<Key>Up: UpKeyProc() \n "
1082 "<Key>Down: DownKeyProc() \n "
1083 "<Key>Return: EnterKeyProc() \n";
1085 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1086 // as the widget is destroyed before the up-click can call extend-end
1087 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1089 String xboardResources[] = {
1090 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1091 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1092 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1097 /* Max possible square size */
1098 #define MAXSQSIZE 256
1100 static int xpm_avail[MAXSQSIZE];
1102 #ifdef HAVE_DIR_STRUCT
1104 /* Extract piece size from filename */
1106 xpm_getsize(name, len, ext)
1117 if ((p=strchr(name, '.')) == NULL ||
1118 StrCaseCmp(p+1, ext) != 0)
1124 while (*p && isdigit(*p))
1131 /* Setup xpm_avail */
1133 xpm_getavail(dirname, ext)
1141 for (i=0; i<MAXSQSIZE; ++i)
1144 if (appData.debugMode)
1145 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1147 dir = opendir(dirname);
1150 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1151 programName, dirname);
1155 while ((ent=readdir(dir)) != NULL) {
1156 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1157 if (i > 0 && i < MAXSQSIZE)
1167 xpm_print_avail(fp, ext)
1173 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1174 for (i=1; i<MAXSQSIZE; ++i) {
1180 /* Return XPM piecesize closest to size */
1182 xpm_closest_to(dirname, size, ext)
1188 int sm_diff = MAXSQSIZE;
1192 xpm_getavail(dirname, ext);
1194 if (appData.debugMode)
1195 xpm_print_avail(stderr, ext);
1197 for (i=1; i<MAXSQSIZE; ++i) {
1200 diff = (diff<0) ? -diff : diff;
1201 if (diff < sm_diff) {
1209 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1215 #else /* !HAVE_DIR_STRUCT */
1216 /* If we are on a system without a DIR struct, we can't
1217 read the directory, so we can't collect a list of
1218 filenames, etc., so we can't do any size-fitting. */
1220 xpm_closest_to(dirname, size, ext)
1225 fprintf(stderr, _("\
1226 Warning: No DIR structure found on this system --\n\
1227 Unable to autosize for XPM/XIM pieces.\n\
1228 Please report this error to frankm@hiwaay.net.\n\
1229 Include system type & operating system in message.\n"));
1232 #endif /* HAVE_DIR_STRUCT */
1234 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1235 "magenta", "cyan", "white" };
1239 TextColors textColors[(int)NColorClasses];
1241 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1243 parse_color(str, which)
1247 char *p, buf[100], *d;
1250 if (strlen(str) > 99) /* watch bounds on buf */
1255 for (i=0; i<which; ++i) {
1262 /* Could be looking at something like:
1264 .. in which case we want to stop on a comma also */
1265 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1269 return -1; /* Use default for empty field */
1272 if (which == 2 || isdigit(*p))
1275 while (*p && isalpha(*p))
1280 for (i=0; i<8; ++i) {
1281 if (!StrCaseCmp(buf, cnames[i]))
1282 return which? (i+40) : (i+30);
1284 if (!StrCaseCmp(buf, "default")) return -1;
1286 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1291 parse_cpair(cc, str)
1295 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1296 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1301 /* bg and attr are optional */
1302 textColors[(int)cc].bg = parse_color(str, 1);
1303 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1304 textColors[(int)cc].attr = 0;
1310 /* Arrange to catch delete-window events */
1311 Atom wm_delete_window;
1313 CatchDeleteWindow(Widget w, String procname)
1316 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1317 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1318 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1325 XtSetArg(args[0], XtNiconic, False);
1326 XtSetValues(shellWidget, args, 1);
1328 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1331 //---------------------------------------------------------------------------------------------------------
1332 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1335 #define CW_USEDEFAULT (1<<31)
1336 #define ICS_TEXT_MENU_SIZE 90
1337 #define DEBUG_FILE "xboard.debug"
1338 #define SetCurrentDirectory chdir
1339 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1343 // these two must some day move to frontend.h, when they are implemented
1344 Boolean GameListIsUp();
1346 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1349 // front-end part of option handling
1351 // [HGM] This platform-dependent table provides the location for storing the color info
1352 extern char *crWhite, * crBlack;
1356 &appData.whitePieceColor,
1357 &appData.blackPieceColor,
1358 &appData.lightSquareColor,
1359 &appData.darkSquareColor,
1360 &appData.highlightSquareColor,
1361 &appData.premoveHighlightColor,
1362 &appData.lowTimeWarningColor,
1373 // [HGM] font: keep a font for each square size, even non-stndard ones
1374 #define NUM_SIZES 18
1375 #define MAX_SIZE 130
1376 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1377 char *fontTable[NUM_FONTS][MAX_SIZE];
1380 ParseFont(char *name, int number)
1381 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1383 if(sscanf(name, "size%d:", &size)) {
1384 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1385 // defer processing it until we know if it matches our board size
1386 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1387 fontTable[number][size] = strdup(strchr(name, ':')+1);
1388 fontValid[number][size] = True;
1393 case 0: // CLOCK_FONT
1394 appData.clockFont = strdup(name);
1396 case 1: // MESSAGE_FONT
1397 appData.font = strdup(name);
1399 case 2: // COORD_FONT
1400 appData.coordFont = strdup(name);
1405 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1410 { // only 2 fonts currently
1411 appData.clockFont = CLOCK_FONT_NAME;
1412 appData.coordFont = COORD_FONT_NAME;
1413 appData.font = DEFAULT_FONT_NAME;
1418 { // no-op, until we identify the code for this already in XBoard and move it here
1422 ParseColor(int n, char *name)
1423 { // in XBoard, just copy the color-name string
1424 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1428 ParseTextAttribs(ColorClass cc, char *s)
1430 (&appData.colorShout)[cc] = strdup(s);
1434 ParseBoardSize(void *addr, char *name)
1436 appData.boardSize = strdup(name);
1441 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1445 SetCommPortDefaults()
1446 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1449 // [HGM] args: these three cases taken out to stay in front-end
1451 SaveFontArg(FILE *f, ArgDescriptor *ad)
1453 char *name, buf[MSG_SIZ];
1454 int i, n = (int)ad->argLoc;
1456 case 0: // CLOCK_FONT
1457 name = appData.clockFont;
1459 case 1: // MESSAGE_FONT
1460 name = appData.font;
1462 case 2: // COORD_FONT
1463 name = appData.coordFont;
1468 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1469 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1470 fontTable[n][squareSize] = strdup(name);
1471 fontValid[n][squareSize] = True;
1474 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1475 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1480 { // nothing to do, as the sounds are at all times represented by their text-string names already
1484 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1485 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1486 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1490 SaveColor(FILE *f, ArgDescriptor *ad)
1491 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1492 if(colorVariable[(int)ad->argLoc])
1493 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1497 SaveBoardSize(FILE *f, char *name, void *addr)
1498 { // wrapper to shield back-end from BoardSize & sizeInfo
1499 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1503 ParseCommPortSettings(char *s)
1504 { // no such option in XBoard (yet)
1507 extern Widget engineOutputShell;
1508 extern Widget tagsShell, editTagsShell;
1510 GetActualPlacement(Widget wg, WindowPlacement *wp)
1520 XtSetArg(args[i], XtNx, &x); i++;
1521 XtSetArg(args[i], XtNy, &y); i++;
1522 XtSetArg(args[i], XtNwidth, &w); i++;
1523 XtSetArg(args[i], XtNheight, &h); i++;
1524 XtGetValues(wg, args, i);
1533 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1534 // In XBoard this will have to wait until awareness of window parameters is implemented
1535 GetActualPlacement(shellWidget, &wpMain);
1536 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1537 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1538 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1539 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1540 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1541 else GetActualPlacement(editShell, &wpComment);
1542 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1543 else GetActualPlacement(editTagsShell, &wpTags);
1547 PrintCommPortSettings(FILE *f, char *name)
1548 { // This option does not exist in XBoard
1552 MySearchPath(char *installDir, char *name, char *fullname)
1553 { // just append installDir and name. Perhaps ExpandPath should be used here?
1554 name = ExpandPathName(name);
1555 if(name && name[0] == '/') strcpy(fullname, name); else {
1556 sprintf(fullname, "%s%c%s", installDir, '/', name);
1562 MyGetFullPathName(char *name, char *fullname)
1563 { // should use ExpandPath?
1564 name = ExpandPathName(name);
1565 strcpy(fullname, name);
1570 EnsureOnScreen(int *x, int *y, int minX, int minY)
1577 { // [HGM] args: allows testing if main window is realized from back-end
1578 return xBoardWindow != 0;
1582 PopUpStartupDialog()
1583 { // start menu not implemented in XBoard
1586 ConvertToLine(int argc, char **argv)
1588 static char line[128*1024], buf[1024];
1592 for(i=1; i<argc; i++) {
1593 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1594 && argv[i][0] != '{' )
1595 sprintf(buf, "{%s} ", argv[i]);
1596 else sprintf(buf, "%s ", argv[i]);
1599 line[strlen(line)-1] = NULLCHAR;
1603 //--------------------------------------------------------------------------------------------
1605 extern Boolean twoBoards, partnerUp;
1608 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1610 #define BoardSize int
1611 void InitDrawingSizes(BoardSize boardSize, int flags)
1612 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1613 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1615 XtGeometryResult gres;
1618 if(!formWidget) return;
1621 * Enable shell resizing.
1623 shellArgs[0].value = (XtArgVal) &w;
1624 shellArgs[1].value = (XtArgVal) &h;
1625 XtGetValues(shellWidget, shellArgs, 2);
1627 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1628 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1629 XtSetValues(shellWidget, &shellArgs[2], 4);
1631 XtSetArg(args[0], XtNdefaultDistance, &sep);
1632 XtGetValues(formWidget, args, 1);
1634 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1635 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1637 hOffset = boardWidth + 10;
1638 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1639 secondSegments[i] = gridSegments[i];
1640 secondSegments[i].x1 += hOffset;
1641 secondSegments[i].x2 += hOffset;
1644 XtSetArg(args[0], XtNwidth, boardWidth);
1645 XtSetArg(args[1], XtNheight, boardHeight);
1646 XtSetValues(boardWidget, args, 2);
1648 timerWidth = (boardWidth - sep) / 2;
1649 XtSetArg(args[0], XtNwidth, timerWidth);
1650 XtSetValues(whiteTimerWidget, args, 1);
1651 XtSetValues(blackTimerWidget, args, 1);
1653 XawFormDoLayout(formWidget, False);
1655 if (appData.titleInWindow) {
1657 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1658 XtSetArg(args[i], XtNheight, &h); i++;
1659 XtGetValues(titleWidget, args, i);
1661 w = boardWidth - 2*bor;
1663 XtSetArg(args[0], XtNwidth, &w);
1664 XtGetValues(menuBarWidget, args, 1);
1665 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1668 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1669 if (gres != XtGeometryYes && appData.debugMode) {
1671 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1672 programName, gres, w, h, wr, hr);
1676 XawFormDoLayout(formWidget, True);
1679 * Inhibit shell resizing.
1681 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1682 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1683 shellArgs[4].value = shellArgs[2].value = w;
1684 shellArgs[5].value = shellArgs[3].value = h;
1685 XtSetValues(shellWidget, &shellArgs[0], 6);
1687 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1690 for(i=0; i<4; i++) {
1692 for(p=0; p<=(int)WhiteKing; p++)
1693 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1694 if(gameInfo.variant == VariantShogi) {
1695 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1696 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1697 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1698 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1699 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1702 if(gameInfo.variant == VariantGothic) {
1703 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1707 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1708 for(p=0; p<=(int)WhiteKing; p++)
1709 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1710 if(gameInfo.variant == VariantShogi) {
1711 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1712 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1713 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1714 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1715 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1718 if(gameInfo.variant == VariantGothic) {
1719 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1725 for(i=0; i<2; i++) {
1727 for(p=0; p<=(int)WhiteKing; p++)
1728 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1729 if(gameInfo.variant == VariantShogi) {
1730 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1731 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1732 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1733 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1734 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1737 if(gameInfo.variant == VariantGothic) {
1738 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1754 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1755 XSetWindowAttributes window_attributes;
1757 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1758 XrmValue vFrom, vTo;
1759 XtGeometryResult gres;
1762 int forceMono = False;
1764 srandom(time(0)); // [HGM] book: make random truly random
1766 setbuf(stdout, NULL);
1767 setbuf(stderr, NULL);
1770 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1771 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1775 programName = strrchr(argv[0], '/');
1776 if (programName == NULL)
1777 programName = argv[0];
1782 XtSetLanguageProc(NULL, NULL, NULL);
1783 bindtextdomain(PACKAGE, LOCALEDIR);
1784 textdomain(PACKAGE);
1788 XtAppInitialize(&appContext, "XBoard", shellOptions,
1789 XtNumber(shellOptions),
1790 &argc, argv, xboardResources, NULL, 0);
1791 appData.boardSize = "";
1792 InitAppData(ConvertToLine(argc, argv));
1794 if (p == NULL) p = "/tmp";
1795 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1796 gameCopyFilename = (char*) malloc(i);
1797 gamePasteFilename = (char*) malloc(i);
1798 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1799 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1801 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1802 clientResources, XtNumber(clientResources),
1805 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1806 static char buf[MSG_SIZ];
1807 EscapeExpand(buf, appData.initString);
1808 appData.initString = strdup(buf);
1809 EscapeExpand(buf, appData.secondInitString);
1810 appData.secondInitString = strdup(buf);
1811 EscapeExpand(buf, appData.firstComputerString);
1812 appData.firstComputerString = strdup(buf);
1813 EscapeExpand(buf, appData.secondComputerString);
1814 appData.secondComputerString = strdup(buf);
1817 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1820 if (chdir(chessDir) != 0) {
1821 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1827 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1828 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1829 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1830 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1833 setbuf(debugFP, NULL);
1836 /* [HGM,HR] make sure board size is acceptable */
1837 if(appData.NrFiles > BOARD_FILES ||
1838 appData.NrRanks > BOARD_RANKS )
1839 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1842 /* This feature does not work; animation needs a rewrite */
1843 appData.highlightDragging = FALSE;
1847 xDisplay = XtDisplay(shellWidget);
1848 xScreen = DefaultScreen(xDisplay);
1849 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1851 gameInfo.variant = StringToVariant(appData.variant);
1852 InitPosition(FALSE);
1855 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1857 if (isdigit(appData.boardSize[0])) {
1858 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1859 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1860 &fontPxlSize, &smallLayout, &tinyLayout);
1862 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1863 programName, appData.boardSize);
1867 /* Find some defaults; use the nearest known size */
1868 SizeDefaults *szd, *nearest;
1869 int distance = 99999;
1870 nearest = szd = sizeDefaults;
1871 while (szd->name != NULL) {
1872 if (abs(szd->squareSize - squareSize) < distance) {
1874 distance = abs(szd->squareSize - squareSize);
1875 if (distance == 0) break;
1879 if (i < 2) lineGap = nearest->lineGap;
1880 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1881 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1882 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1883 if (i < 6) smallLayout = nearest->smallLayout;
1884 if (i < 7) tinyLayout = nearest->tinyLayout;
1887 SizeDefaults *szd = sizeDefaults;
1888 if (*appData.boardSize == NULLCHAR) {
1889 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1890 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1893 if (szd->name == NULL) szd--;
1894 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1896 while (szd->name != NULL &&
1897 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1898 if (szd->name == NULL) {
1899 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1900 programName, appData.boardSize);
1904 squareSize = szd->squareSize;
1905 lineGap = szd->lineGap;
1906 clockFontPxlSize = szd->clockFontPxlSize;
1907 coordFontPxlSize = szd->coordFontPxlSize;
1908 fontPxlSize = szd->fontPxlSize;
1909 smallLayout = szd->smallLayout;
1910 tinyLayout = szd->tinyLayout;
1911 // [HGM] font: use defaults from settings file if available and not overruled
1913 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1914 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1915 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1916 appData.font = fontTable[MESSAGE_FONT][squareSize];
1917 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1918 appData.coordFont = fontTable[COORD_FONT][squareSize];
1920 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1921 if (strlen(appData.pixmapDirectory) > 0) {
1922 p = ExpandPathName(appData.pixmapDirectory);
1924 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1925 appData.pixmapDirectory);
1928 if (appData.debugMode) {
1929 fprintf(stderr, _("\
1930 XBoard square size (hint): %d\n\
1931 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1933 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1934 if (appData.debugMode) {
1935 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1939 /* [HR] height treated separately (hacked) */
1940 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1941 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1942 if (appData.showJail == 1) {
1943 /* Jail on top and bottom */
1944 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1945 XtSetArg(boardArgs[2], XtNheight,
1946 boardHeight + 2*(lineGap + squareSize));
1947 } else if (appData.showJail == 2) {
1949 XtSetArg(boardArgs[1], XtNwidth,
1950 boardWidth + 2*(lineGap + squareSize));
1951 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1954 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1955 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1959 * Determine what fonts to use.
1961 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1962 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1963 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1964 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1965 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1966 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1967 appData.font = FindFont(appData.font, fontPxlSize);
1968 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1969 countFontStruct = XQueryFont(xDisplay, countFontID);
1970 // appData.font = FindFont(appData.font, fontPxlSize);
1972 xdb = XtDatabase(xDisplay);
1973 XrmPutStringResource(&xdb, "*font", appData.font);
1976 * Detect if there are not enough colors available and adapt.
1978 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1979 appData.monoMode = True;
1982 if (!appData.monoMode) {
1983 vFrom.addr = (caddr_t) appData.lightSquareColor;
1984 vFrom.size = strlen(appData.lightSquareColor);
1985 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1986 if (vTo.addr == NULL) {
1987 appData.monoMode = True;
1990 lightSquareColor = *(Pixel *) vTo.addr;
1993 if (!appData.monoMode) {
1994 vFrom.addr = (caddr_t) appData.darkSquareColor;
1995 vFrom.size = strlen(appData.darkSquareColor);
1996 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1997 if (vTo.addr == NULL) {
1998 appData.monoMode = True;
2001 darkSquareColor = *(Pixel *) vTo.addr;
2004 if (!appData.monoMode) {
2005 vFrom.addr = (caddr_t) appData.whitePieceColor;
2006 vFrom.size = strlen(appData.whitePieceColor);
2007 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2008 if (vTo.addr == NULL) {
2009 appData.monoMode = True;
2012 whitePieceColor = *(Pixel *) vTo.addr;
2015 if (!appData.monoMode) {
2016 vFrom.addr = (caddr_t) appData.blackPieceColor;
2017 vFrom.size = strlen(appData.blackPieceColor);
2018 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2019 if (vTo.addr == NULL) {
2020 appData.monoMode = True;
2023 blackPieceColor = *(Pixel *) vTo.addr;
2027 if (!appData.monoMode) {
2028 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2029 vFrom.size = strlen(appData.highlightSquareColor);
2030 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2031 if (vTo.addr == NULL) {
2032 appData.monoMode = True;
2035 highlightSquareColor = *(Pixel *) vTo.addr;
2039 if (!appData.monoMode) {
2040 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2041 vFrom.size = strlen(appData.premoveHighlightColor);
2042 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2043 if (vTo.addr == NULL) {
2044 appData.monoMode = True;
2047 premoveHighlightColor = *(Pixel *) vTo.addr;
2052 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2055 if (appData.bitmapDirectory == NULL ||
2056 appData.bitmapDirectory[0] == NULLCHAR)
2057 appData.bitmapDirectory = DEF_BITMAP_DIR;
2060 if (appData.lowTimeWarning && !appData.monoMode) {
2061 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2062 vFrom.size = strlen(appData.lowTimeWarningColor);
2063 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2064 if (vTo.addr == NULL)
2065 appData.monoMode = True;
2067 lowTimeWarningColor = *(Pixel *) vTo.addr;
2070 if (appData.monoMode && appData.debugMode) {
2071 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2072 (unsigned long) XWhitePixel(xDisplay, xScreen),
2073 (unsigned long) XBlackPixel(xDisplay, xScreen));
2076 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2077 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2078 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2079 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2080 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2081 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2082 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2083 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2084 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2085 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2087 if (appData.colorize) {
2089 _("%s: can't parse color names; disabling colorization\n"),
2092 appData.colorize = FALSE;
2094 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2095 textColors[ColorNone].attr = 0;
2097 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2103 layoutName = "tinyLayout";
2104 } else if (smallLayout) {
2105 layoutName = "smallLayout";
2107 layoutName = "normalLayout";
2109 /* Outer layoutWidget is there only to provide a name for use in
2110 resources that depend on the layout style */
2112 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2113 layoutArgs, XtNumber(layoutArgs));
2115 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2116 formArgs, XtNumber(formArgs));
2117 XtSetArg(args[0], XtNdefaultDistance, &sep);
2118 XtGetValues(formWidget, args, 1);
2121 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2122 XtSetArg(args[0], XtNtop, XtChainTop);
2123 XtSetArg(args[1], XtNbottom, XtChainTop);
2124 XtSetArg(args[2], XtNright, XtChainLeft);
2125 XtSetValues(menuBarWidget, args, 3);
2127 widgetList[j++] = whiteTimerWidget =
2128 XtCreateWidget("whiteTime", labelWidgetClass,
2129 formWidget, timerArgs, XtNumber(timerArgs));
2130 XtSetArg(args[0], XtNfont, clockFontStruct);
2131 XtSetArg(args[1], XtNtop, XtChainTop);
2132 XtSetArg(args[2], XtNbottom, XtChainTop);
2133 XtSetValues(whiteTimerWidget, args, 3);
2135 widgetList[j++] = blackTimerWidget =
2136 XtCreateWidget("blackTime", labelWidgetClass,
2137 formWidget, timerArgs, XtNumber(timerArgs));
2138 XtSetArg(args[0], XtNfont, clockFontStruct);
2139 XtSetArg(args[1], XtNtop, XtChainTop);
2140 XtSetArg(args[2], XtNbottom, XtChainTop);
2141 XtSetValues(blackTimerWidget, args, 3);
2143 if (appData.titleInWindow) {
2144 widgetList[j++] = titleWidget =
2145 XtCreateWidget("title", labelWidgetClass, formWidget,
2146 titleArgs, XtNumber(titleArgs));
2147 XtSetArg(args[0], XtNtop, XtChainTop);
2148 XtSetArg(args[1], XtNbottom, XtChainTop);
2149 XtSetValues(titleWidget, args, 2);
2152 if (appData.showButtonBar) {
2153 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2154 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2155 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2156 XtSetArg(args[2], XtNtop, XtChainTop);
2157 XtSetArg(args[3], XtNbottom, XtChainTop);
2158 XtSetValues(buttonBarWidget, args, 4);
2161 widgetList[j++] = messageWidget =
2162 XtCreateWidget("message", labelWidgetClass, formWidget,
2163 messageArgs, XtNumber(messageArgs));
2164 XtSetArg(args[0], XtNtop, XtChainTop);
2165 XtSetArg(args[1], XtNbottom, XtChainTop);
2166 XtSetValues(messageWidget, args, 2);
2168 widgetList[j++] = boardWidget =
2169 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2170 XtNumber(boardArgs));
2172 XtManageChildren(widgetList, j);
2174 timerWidth = (boardWidth - sep) / 2;
2175 XtSetArg(args[0], XtNwidth, timerWidth);
2176 XtSetValues(whiteTimerWidget, args, 1);
2177 XtSetValues(blackTimerWidget, args, 1);
2179 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2180 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2181 XtGetValues(whiteTimerWidget, args, 2);
2183 if (appData.showButtonBar) {
2184 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2185 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2186 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2190 * formWidget uses these constraints but they are stored
2194 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2195 XtSetValues(menuBarWidget, args, i);
2196 if (appData.titleInWindow) {
2199 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2200 XtSetValues(whiteTimerWidget, args, i);
2202 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2203 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2204 XtSetValues(blackTimerWidget, args, i);
2206 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2207 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2208 XtSetValues(titleWidget, args, i);
2210 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2211 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2212 XtSetValues(messageWidget, args, i);
2213 if (appData.showButtonBar) {
2215 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2216 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2217 XtSetValues(buttonBarWidget, args, i);
2221 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2222 XtSetValues(whiteTimerWidget, args, i);
2224 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2225 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2226 XtSetValues(blackTimerWidget, args, i);
2228 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2229 XtSetValues(titleWidget, args, i);
2231 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2232 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2233 XtSetValues(messageWidget, args, i);
2234 if (appData.showButtonBar) {
2236 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2237 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2238 XtSetValues(buttonBarWidget, args, i);
2243 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2244 XtSetValues(whiteTimerWidget, args, i);
2246 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2247 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2248 XtSetValues(blackTimerWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2251 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2252 XtSetValues(messageWidget, args, i);
2253 if (appData.showButtonBar) {
2255 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2257 XtSetValues(buttonBarWidget, args, i);
2261 XtSetArg(args[0], XtNfromVert, messageWidget);
2262 XtSetArg(args[1], XtNtop, XtChainTop);
2263 XtSetArg(args[2], XtNbottom, XtChainBottom);
2264 XtSetArg(args[3], XtNleft, XtChainLeft);
2265 XtSetArg(args[4], XtNright, XtChainRight);
2266 XtSetValues(boardWidget, args, 5);
2268 XtRealizeWidget(shellWidget);
2271 XtSetArg(args[0], XtNx, wpMain.x);
2272 XtSetArg(args[1], XtNy, wpMain.y);
2273 XtSetValues(shellWidget, args, 2);
2277 * Correct the width of the message and title widgets.
2278 * It is not known why some systems need the extra fudge term.
2279 * The value "2" is probably larger than needed.
2281 XawFormDoLayout(formWidget, False);
2283 #define WIDTH_FUDGE 2
2285 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2286 XtSetArg(args[i], XtNheight, &h); i++;
2287 XtGetValues(messageWidget, args, i);
2288 if (appData.showButtonBar) {
2290 XtSetArg(args[i], XtNwidth, &w); i++;
2291 XtGetValues(buttonBarWidget, args, i);
2292 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2294 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2297 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2298 if (gres != XtGeometryYes && appData.debugMode) {
2299 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2300 programName, gres, w, h, wr, hr);
2303 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2304 /* The size used for the child widget in layout lags one resize behind
2305 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2307 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2308 if (gres != XtGeometryYes && appData.debugMode) {
2309 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2310 programName, gres, w, h, wr, hr);
2313 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2314 XtSetArg(args[1], XtNright, XtChainRight);
2315 XtSetValues(messageWidget, args, 2);
2317 if (appData.titleInWindow) {
2319 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2320 XtSetArg(args[i], XtNheight, &h); i++;
2321 XtGetValues(titleWidget, args, i);
2323 w = boardWidth - 2*bor;
2325 XtSetArg(args[0], XtNwidth, &w);
2326 XtGetValues(menuBarWidget, args, 1);
2327 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2330 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2331 if (gres != XtGeometryYes && appData.debugMode) {
2333 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2334 programName, gres, w, h, wr, hr);
2337 XawFormDoLayout(formWidget, True);
2339 xBoardWindow = XtWindow(boardWidget);
2341 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2342 // not need to go into InitDrawingSizes().
2346 * Create X checkmark bitmap and initialize option menu checks.
2348 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2349 checkmark_bits, checkmark_width, checkmark_height);
2350 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2351 if (appData.alwaysPromoteToQueen) {
2352 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2355 if (appData.animateDragging) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,
2357 "menuOptions.Animate Dragging"),
2360 if (appData.animate) {
2361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2364 if (appData.autoComment) {
2365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2368 if (appData.autoCallFlag) {
2369 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2372 if (appData.autoFlipView) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2376 if (appData.autoObserve) {
2377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2380 if (appData.autoRaiseBoard) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Auto Raise Board"), args, 1);
2384 if (appData.autoSaveGames) {
2385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2388 if (appData.saveGameFile[0] != NULLCHAR) {
2389 /* Can't turn this off from menu */
2390 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2392 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2396 if (appData.blindfold) {
2397 XtSetValues(XtNameToWidget(menuBarWidget,
2398 "menuOptions.Blindfold"), args, 1);
2400 if (appData.flashCount > 0) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,
2402 "menuOptions.Flash Moves"),
2405 if (appData.getMoveList) {
2406 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2410 if (appData.highlightDragging) {
2411 XtSetValues(XtNameToWidget(menuBarWidget,
2412 "menuOptions.Highlight Dragging"),
2416 if (appData.highlightLastMove) {
2417 XtSetValues(XtNameToWidget(menuBarWidget,
2418 "menuOptions.Highlight Last Move"),
2421 if (appData.icsAlarm) {
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2425 if (appData.ringBellAfterMoves) {
2426 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2429 if (appData.oldSaveStyle) {
2430 XtSetValues(XtNameToWidget(menuBarWidget,
2431 "menuOptions.Old Save Style"), args, 1);
2433 if (appData.periodicUpdates) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Periodic Updates"), args, 1);
2437 if (appData.ponderNextMove) {
2438 XtSetValues(XtNameToWidget(menuBarWidget,
2439 "menuOptions.Ponder Next Move"), args, 1);
2441 if (appData.popupExitMessage) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Popup Exit Message"), args, 1);
2445 if (appData.popupMoveErrors) {
2446 XtSetValues(XtNameToWidget(menuBarWidget,
2447 "menuOptions.Popup Move Errors"), args, 1);
2449 if (appData.premove) {
2450 XtSetValues(XtNameToWidget(menuBarWidget,
2451 "menuOptions.Premove"), args, 1);
2453 if (appData.quietPlay) {
2454 XtSetValues(XtNameToWidget(menuBarWidget,
2455 "menuOptions.Quiet Play"), args, 1);
2457 if (appData.showCoords) {
2458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2461 if (appData.hideThinkingFromHuman) {
2462 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2465 if (appData.testLegality) {
2466 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2469 if (saveSettingsOnExit) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2477 ReadBitmap(&wIconPixmap, "icon_white.bm",
2478 icon_white_bits, icon_white_width, icon_white_height);
2479 ReadBitmap(&bIconPixmap, "icon_black.bm",
2480 icon_black_bits, icon_black_width, icon_black_height);
2481 iconPixmap = wIconPixmap;
2483 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2484 XtSetValues(shellWidget, args, i);
2487 * Create a cursor for the board widget.
2489 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2490 XChangeWindowAttributes(xDisplay, xBoardWindow,
2491 CWCursor, &window_attributes);
2494 * Inhibit shell resizing.
2496 shellArgs[0].value = (XtArgVal) &w;
2497 shellArgs[1].value = (XtArgVal) &h;
2498 XtGetValues(shellWidget, shellArgs, 2);
2499 shellArgs[4].value = shellArgs[2].value = w;
2500 shellArgs[5].value = shellArgs[3].value = h;
2501 XtSetValues(shellWidget, &shellArgs[2], 4);
2502 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2503 marginH = h - boardHeight;
2505 CatchDeleteWindow(shellWidget, "QuitProc");
2510 if (appData.bitmapDirectory[0] != NULLCHAR) {
2517 /* Create regular pieces */
2518 if (!useImages) CreatePieces();
2523 if (appData.animate || appData.animateDragging)
2526 XtAugmentTranslations(formWidget,
2527 XtParseTranslationTable(globalTranslations));
2528 XtAugmentTranslations(boardWidget,
2529 XtParseTranslationTable(boardTranslations));
2530 XtAugmentTranslations(whiteTimerWidget,
2531 XtParseTranslationTable(whiteTranslations));
2532 XtAugmentTranslations(blackTimerWidget,
2533 XtParseTranslationTable(blackTranslations));
2535 /* Why is the following needed on some versions of X instead
2536 * of a translation? */
2537 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2538 (XtEventHandler) EventProc, NULL);
2541 /* [AS] Restore layout */
2542 if( wpMoveHistory.visible ) {
2546 if( wpEvalGraph.visible )
2551 if( wpEngineOutput.visible ) {
2552 EngineOutputPopUp();
2557 if (errorExitStatus == -1) {
2558 if (appData.icsActive) {
2559 /* We now wait until we see "login:" from the ICS before
2560 sending the logon script (problems with timestamp otherwise) */
2561 /*ICSInitScript();*/
2562 if (appData.icsInputBox) ICSInputBoxPopUp();
2566 signal(SIGWINCH, TermSizeSigHandler);
2568 signal(SIGINT, IntSigHandler);
2569 signal(SIGTERM, IntSigHandler);
2570 if (*appData.cmailGameName != NULLCHAR) {
2571 signal(SIGUSR1, CmailSigHandler);
2574 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2576 XtSetKeyboardFocus(shellWidget, formWidget);
2578 XtAppMainLoop(appContext);
2579 if (appData.debugMode) fclose(debugFP); // [DM] debug
2586 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2587 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2589 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2590 unlink(gameCopyFilename);
2591 unlink(gamePasteFilename);
2594 RETSIGTYPE TermSizeSigHandler(int sig)
2607 CmailSigHandler(sig)
2613 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2615 /* Activate call-back function CmailSigHandlerCallBack() */
2616 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2618 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2622 CmailSigHandlerCallBack(isr, closure, message, count, error)
2630 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2632 /**** end signal code ****/
2642 f = fopen(appData.icsLogon, "r");
2648 strcat(buf, appData.icsLogon);
2649 f = fopen(buf, "r");
2653 ProcessICSInitScript(f);
2660 EditCommentPopDown();
2675 if (!menuBarWidget) return;
2676 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2678 DisplayError("menuStep.Revert", 0);
2680 XtSetSensitive(w, !grey);
2682 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2684 DisplayError("menuStep.Annotate", 0);
2686 XtSetSensitive(w, !grey);
2691 SetMenuEnables(enab)
2695 if (!menuBarWidget) return;
2696 while (enab->name != NULL) {
2697 w = XtNameToWidget(menuBarWidget, enab->name);
2699 DisplayError(enab->name, 0);
2701 XtSetSensitive(w, enab->value);
2707 Enables icsEnables[] = {
2708 { "menuFile.Mail Move", False },
2709 { "menuFile.Reload CMail Message", False },
2710 { "menuMode.Machine Black", False },
2711 { "menuMode.Machine White", False },
2712 { "menuMode.Analysis Mode", False },
2713 { "menuMode.Analyze File", False },
2714 { "menuMode.Two Machines", False },
2716 { "menuHelp.Hint", False },
2717 { "menuHelp.Book", False },
2718 { "menuStep.Move Now", False },
2719 { "menuOptions.Periodic Updates", False },
2720 { "menuOptions.Hide Thinking", False },
2721 { "menuOptions.Ponder Next Move", False },
2723 { "menuStep.Annotate", False },
2727 Enables ncpEnables[] = {
2728 { "menuFile.Mail Move", False },
2729 { "menuFile.Reload CMail Message", False },
2730 { "menuMode.Machine White", False },
2731 { "menuMode.Machine Black", False },
2732 { "menuMode.Analysis Mode", False },
2733 { "menuMode.Analyze File", False },
2734 { "menuMode.Two Machines", False },
2735 { "menuMode.ICS Client", False },
2736 { "menuMode.ICS Input Box", False },
2737 { "Action", False },
2738 { "menuStep.Revert", False },
2739 { "menuStep.Annotate", False },
2740 { "menuStep.Move Now", False },
2741 { "menuStep.Retract Move", False },
2742 { "menuOptions.Auto Comment", False },
2743 { "menuOptions.Auto Flag", False },
2744 { "menuOptions.Auto Flip View", False },
2745 { "menuOptions.Auto Observe", False },
2746 { "menuOptions.Auto Raise Board", False },
2747 { "menuOptions.Get Move List", False },
2748 { "menuOptions.ICS Alarm", False },
2749 { "menuOptions.Move Sound", False },
2750 { "menuOptions.Quiet Play", False },
2751 { "menuOptions.Hide Thinking", False },
2752 { "menuOptions.Periodic Updates", False },
2753 { "menuOptions.Ponder Next Move", False },
2754 { "menuHelp.Hint", False },
2755 { "menuHelp.Book", False },
2759 Enables gnuEnables[] = {
2760 { "menuMode.ICS Client", False },
2761 { "menuMode.ICS Input Box", False },
2762 { "menuAction.Accept", False },
2763 { "menuAction.Decline", False },
2764 { "menuAction.Rematch", False },
2765 { "menuAction.Adjourn", False },
2766 { "menuAction.Stop Examining", False },
2767 { "menuAction.Stop Observing", False },
2768 { "menuAction.Upload to Examine", False },
2769 { "menuStep.Revert", False },
2770 { "menuStep.Annotate", False },
2771 { "menuOptions.Auto Comment", False },
2772 { "menuOptions.Auto Observe", False },
2773 { "menuOptions.Auto Raise Board", False },
2774 { "menuOptions.Get Move List", False },
2775 { "menuOptions.Premove", False },
2776 { "menuOptions.Quiet Play", False },
2778 /* The next two options rely on SetCmailMode being called *after* */
2779 /* SetGNUMode so that when GNU is being used to give hints these */
2780 /* menu options are still available */
2782 { "menuFile.Mail Move", False },
2783 { "menuFile.Reload CMail Message", False },
2787 Enables cmailEnables[] = {
2789 { "menuAction.Call Flag", False },
2790 { "menuAction.Draw", True },
2791 { "menuAction.Adjourn", False },
2792 { "menuAction.Abort", False },
2793 { "menuAction.Stop Observing", False },
2794 { "menuAction.Stop Examining", False },
2795 { "menuFile.Mail Move", True },
2796 { "menuFile.Reload CMail Message", True },
2800 Enables trainingOnEnables[] = {
2801 { "menuMode.Edit Comment", False },
2802 { "menuMode.Pause", False },
2803 { "menuStep.Forward", False },
2804 { "menuStep.Backward", False },
2805 { "menuStep.Forward to End", False },
2806 { "menuStep.Back to Start", False },
2807 { "menuStep.Move Now", False },
2808 { "menuStep.Truncate Game", False },
2812 Enables trainingOffEnables[] = {
2813 { "menuMode.Edit Comment", True },
2814 { "menuMode.Pause", True },
2815 { "menuStep.Forward", True },
2816 { "menuStep.Backward", True },
2817 { "menuStep.Forward to End", True },
2818 { "menuStep.Back to Start", True },
2819 { "menuStep.Move Now", True },
2820 { "menuStep.Truncate Game", True },
2824 Enables machineThinkingEnables[] = {
2825 { "menuFile.Load Game", False },
2826 { "menuFile.Load Next Game", False },
2827 { "menuFile.Load Previous Game", False },
2828 { "menuFile.Reload Same Game", False },
2829 { "menuFile.Paste Game", False },
2830 { "menuFile.Load Position", False },
2831 { "menuFile.Load Next Position", False },
2832 { "menuFile.Load Previous Position", False },
2833 { "menuFile.Reload Same Position", False },
2834 { "menuFile.Paste Position", False },
2835 { "menuMode.Machine White", False },
2836 { "menuMode.Machine Black", False },
2837 { "menuMode.Two Machines", False },
2838 { "menuStep.Retract Move", False },
2842 Enables userThinkingEnables[] = {
2843 { "menuFile.Load Game", True },
2844 { "menuFile.Load Next Game", True },
2845 { "menuFile.Load Previous Game", True },
2846 { "menuFile.Reload Same Game", True },
2847 { "menuFile.Paste Game", True },
2848 { "menuFile.Load Position", True },
2849 { "menuFile.Load Next Position", True },
2850 { "menuFile.Load Previous Position", True },
2851 { "menuFile.Reload Same Position", True },
2852 { "menuFile.Paste Position", True },
2853 { "menuMode.Machine White", True },
2854 { "menuMode.Machine Black", True },
2855 { "menuMode.Two Machines", True },
2856 { "menuStep.Retract Move", True },
2862 SetMenuEnables(icsEnables);
2865 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2866 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2873 SetMenuEnables(ncpEnables);
2879 SetMenuEnables(gnuEnables);
2885 SetMenuEnables(cmailEnables);
2891 SetMenuEnables(trainingOnEnables);
2892 if (appData.showButtonBar) {
2893 XtSetSensitive(buttonBarWidget, False);
2899 SetTrainingModeOff()
2901 SetMenuEnables(trainingOffEnables);
2902 if (appData.showButtonBar) {
2903 XtSetSensitive(buttonBarWidget, True);
2908 SetUserThinkingEnables()
2910 if (appData.noChessProgram) return;
2911 SetMenuEnables(userThinkingEnables);
2915 SetMachineThinkingEnables()
2917 if (appData.noChessProgram) return;
2918 SetMenuEnables(machineThinkingEnables);
2920 case MachinePlaysBlack:
2921 case MachinePlaysWhite:
2922 case TwoMachinesPlay:
2923 XtSetSensitive(XtNameToWidget(menuBarWidget,
2924 ModeToWidgetName(gameMode)), True);
2931 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2932 #define HISTORY_SIZE 64
\r
2933 static char *history[HISTORY_SIZE];
\r
2934 int histIn = 0, histP = 0;
\r
2937 SaveInHistory(char *cmd)
\r
2939 if (history[histIn] != NULL) {
\r
2940 free(history[histIn]);
\r
2941 history[histIn] = NULL;
\r
2943 if (*cmd == NULLCHAR) return;
\r
2944 history[histIn] = StrSave(cmd);
\r
2945 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2946 if (history[histIn] != NULL) {
\r
2947 free(history[histIn]);
\r
2948 history[histIn] = NULL;
\r
2954 PrevInHistory(char *cmd)
\r
2957 if (histP == histIn) {
\r
2958 if (history[histIn] != NULL) free(history[histIn]);
\r
2959 history[histIn] = StrSave(cmd);
\r
2961 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2962 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
2964 return history[histP];
\r
2970 if (histP == histIn) return NULL;
\r
2971 histP = (histP + 1) % HISTORY_SIZE;
\r
2972 return history[histP];
\r
2974 // end of borrowed code
\r
2976 #define Abs(n) ((n)<0 ? -(n) : (n))
2979 * Find a font that matches "pattern" that is as close as
2980 * possible to the targetPxlSize. Prefer fonts that are k
2981 * pixels smaller to fonts that are k pixels larger. The
2982 * pattern must be in the X Consortium standard format,
2983 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2984 * The return value should be freed with XtFree when no
2987 char *FindFont(pattern, targetPxlSize)
2991 char **fonts, *p, *best, *scalable, *scalableTail;
2992 int i, j, nfonts, minerr, err, pxlSize;
2995 char **missing_list;
2997 char *def_string, *base_fnt_lst, strInt[3];
2999 XFontStruct **fnt_list;
3001 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3002 sprintf(strInt, "%d", targetPxlSize);
3003 p = strstr(pattern, "--");
3004 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3005 strcat(base_fnt_lst, strInt);
3006 strcat(base_fnt_lst, strchr(p + 2, '-'));
3008 if ((fntSet = XCreateFontSet(xDisplay,
3012 &def_string)) == NULL) {
3014 fprintf(stderr, _("Unable to create font set.\n"));
3018 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3020 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3022 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3023 programName, pattern);
3031 for (i=0; i<nfonts; i++) {
3034 if (*p != '-') continue;
3036 if (*p == NULLCHAR) break;
3037 if (*p++ == '-') j++;
3039 if (j < 7) continue;
3042 scalable = fonts[i];
3045 err = pxlSize - targetPxlSize;
3046 if (Abs(err) < Abs(minerr) ||
3047 (minerr > 0 && err < 0 && -err == minerr)) {
3053 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3054 /* If the error is too big and there is a scalable font,
3055 use the scalable font. */
3056 int headlen = scalableTail - scalable;
3057 p = (char *) XtMalloc(strlen(scalable) + 10);
3058 while (isdigit(*scalableTail)) scalableTail++;
3059 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3061 p = (char *) XtMalloc(strlen(best) + 1);
3064 if (appData.debugMode) {
3065 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3066 pattern, targetPxlSize, p);
3069 if (missing_count > 0)
3070 XFreeStringList(missing_list);
3071 XFreeFontSet(xDisplay, fntSet);
3073 XFreeFontNames(fonts);
3080 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3081 | GCBackground | GCFunction | GCPlaneMask;
3082 XGCValues gc_values;
3085 gc_values.plane_mask = AllPlanes;
3086 gc_values.line_width = lineGap;
3087 gc_values.line_style = LineSolid;
3088 gc_values.function = GXcopy;
3090 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3091 gc_values.background = XBlackPixel(xDisplay, xScreen);
3092 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3094 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3095 gc_values.background = XWhitePixel(xDisplay, xScreen);
3096 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3097 XSetFont(xDisplay, coordGC, coordFontID);
3099 // [HGM] make font for holdings counts (white on black0
3100 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3101 gc_values.background = XBlackPixel(xDisplay, xScreen);
3102 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3103 XSetFont(xDisplay, countGC, countFontID);
3105 if (appData.monoMode) {
3106 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3107 gc_values.background = XWhitePixel(xDisplay, xScreen);
3108 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3110 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3111 gc_values.background = XBlackPixel(xDisplay, xScreen);
3112 lightSquareGC = wbPieceGC
3113 = XtGetGC(shellWidget, value_mask, &gc_values);
3115 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3116 gc_values.background = XWhitePixel(xDisplay, xScreen);
3117 darkSquareGC = bwPieceGC
3118 = XtGetGC(shellWidget, value_mask, &gc_values);
3120 if (DefaultDepth(xDisplay, xScreen) == 1) {
3121 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3122 gc_values.function = GXcopyInverted;
3123 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3124 gc_values.function = GXcopy;
3125 if (XBlackPixel(xDisplay, xScreen) == 1) {
3126 bwPieceGC = darkSquareGC;
3127 wbPieceGC = copyInvertedGC;
3129 bwPieceGC = copyInvertedGC;
3130 wbPieceGC = lightSquareGC;
3134 gc_values.foreground = highlightSquareColor;
3135 gc_values.background = highlightSquareColor;
3136 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3138 gc_values.foreground = premoveHighlightColor;
3139 gc_values.background = premoveHighlightColor;
3140 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3142 gc_values.foreground = lightSquareColor;
3143 gc_values.background = darkSquareColor;
3144 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3146 gc_values.foreground = darkSquareColor;
3147 gc_values.background = lightSquareColor;
3148 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3150 gc_values.foreground = jailSquareColor;
3151 gc_values.background = jailSquareColor;
3152 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3154 gc_values.foreground = whitePieceColor;
3155 gc_values.background = darkSquareColor;
3156 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3158 gc_values.foreground = whitePieceColor;
3159 gc_values.background = lightSquareColor;
3160 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3162 gc_values.foreground = whitePieceColor;
3163 gc_values.background = jailSquareColor;
3164 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3166 gc_values.foreground = blackPieceColor;
3167 gc_values.background = darkSquareColor;
3168 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3170 gc_values.foreground = blackPieceColor;
3171 gc_values.background = lightSquareColor;
3172 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.foreground = blackPieceColor;
3175 gc_values.background = jailSquareColor;
3176 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3180 void loadXIM(xim, xmask, filename, dest, mask)
3193 fp = fopen(filename, "rb");
3195 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3202 for (y=0; y<h; ++y) {
3203 for (x=0; x<h; ++x) {
3208 XPutPixel(xim, x, y, blackPieceColor);
3210 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3213 XPutPixel(xim, x, y, darkSquareColor);
3215 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3218 XPutPixel(xim, x, y, whitePieceColor);
3220 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3223 XPutPixel(xim, x, y, lightSquareColor);
3225 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3231 /* create Pixmap of piece */
3232 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3234 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3237 /* create Pixmap of clipmask
3238 Note: We assume the white/black pieces have the same
3239 outline, so we make only 6 masks. This is okay
3240 since the XPM clipmask routines do the same. */
3242 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3244 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3247 /* now create the 1-bit version */
3248 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3251 values.foreground = 1;
3252 values.background = 0;
3254 /* Don't use XtGetGC, not read only */
3255 maskGC = XCreateGC(xDisplay, *mask,
3256 GCForeground | GCBackground, &values);
3257 XCopyPlane(xDisplay, temp, *mask, maskGC,
3258 0, 0, squareSize, squareSize, 0, 0, 1);
3259 XFreePixmap(xDisplay, temp);
3264 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3266 void CreateXIMPieces()
3271 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3276 /* The XSynchronize calls were copied from CreatePieces.
3277 Not sure if needed, but can't hurt */
3278 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3281 /* temp needed by loadXIM() */
3282 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3283 0, 0, ss, ss, AllPlanes, XYPixmap);
3285 if (strlen(appData.pixmapDirectory) == 0) {
3289 if (appData.monoMode) {
3290 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3294 fprintf(stderr, _("\nLoading XIMs...\n"));
3296 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3297 fprintf(stderr, "%d", piece+1);
3298 for (kind=0; kind<4; kind++) {
3299 fprintf(stderr, ".");
3300 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3301 ExpandPathName(appData.pixmapDirectory),
3302 piece <= (int) WhiteKing ? "" : "w",
3303 pieceBitmapNames[piece],
3305 ximPieceBitmap[kind][piece] =
3306 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3307 0, 0, ss, ss, AllPlanes, XYPixmap);
3308 if (appData.debugMode)
3309 fprintf(stderr, _("(File:%s:) "), buf);
3310 loadXIM(ximPieceBitmap[kind][piece],
3312 &(xpmPieceBitmap2[kind][piece]),
3313 &(ximMaskPm2[piece]));
3314 if(piece <= (int)WhiteKing)
3315 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3317 fprintf(stderr," ");
3319 /* Load light and dark squares */
3320 /* If the LSQ and DSQ pieces don't exist, we will
3321 draw them with solid squares. */
3322 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3323 if (access(buf, 0) != 0) {
3327 fprintf(stderr, _("light square "));
3329 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3330 0, 0, ss, ss, AllPlanes, XYPixmap);
3331 if (appData.debugMode)
3332 fprintf(stderr, _("(File:%s:) "), buf);
3334 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3335 fprintf(stderr, _("dark square "));
3336 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3337 ExpandPathName(appData.pixmapDirectory), ss);
3338 if (appData.debugMode)
3339 fprintf(stderr, _("(File:%s:) "), buf);
3341 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3342 0, 0, ss, ss, AllPlanes, XYPixmap);
3343 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3344 xpmJailSquare = xpmLightSquare;
3346 fprintf(stderr, _("Done.\n"));
3348 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3352 void CreateXPMPieces()
3356 u_int ss = squareSize;
3358 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3359 XpmColorSymbol symbols[4];
3361 /* The XSynchronize calls were copied from CreatePieces.
3362 Not sure if needed, but can't hurt */
3363 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3365 /* Setup translations so piece colors match square colors */
3366 symbols[0].name = "light_piece";
3367 symbols[0].value = appData.whitePieceColor;
3368 symbols[1].name = "dark_piece";
3369 symbols[1].value = appData.blackPieceColor;
3370 symbols[2].name = "light_square";
3371 symbols[2].value = appData.lightSquareColor;
3372 symbols[3].name = "dark_square";
3373 symbols[3].value = appData.darkSquareColor;
3375 attr.valuemask = XpmColorSymbols;
3376 attr.colorsymbols = symbols;
3377 attr.numsymbols = 4;
3379 if (appData.monoMode) {
3380 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3384 if (strlen(appData.pixmapDirectory) == 0) {
3385 XpmPieces* pieces = builtInXpms;
3388 while (pieces->size != squareSize && pieces->size) pieces++;
3389 if (!pieces->size) {
3390 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3393 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3394 for (kind=0; kind<4; kind++) {
3396 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3397 pieces->xpm[piece][kind],
3398 &(xpmPieceBitmap2[kind][piece]),
3399 NULL, &attr)) != 0) {
3400 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3404 if(piece <= (int) WhiteKing)
3405 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3409 xpmJailSquare = xpmLightSquare;
3413 fprintf(stderr, _("\nLoading XPMs...\n"));
3416 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3417 fprintf(stderr, "%d ", piece+1);
3418 for (kind=0; kind<4; kind++) {
3419 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3420 ExpandPathName(appData.pixmapDirectory),
3421 piece > (int) WhiteKing ? "w" : "",
3422 pieceBitmapNames[piece],
3424 if (appData.debugMode) {
3425 fprintf(stderr, _("(File:%s:) "), buf);
3427 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3428 &(xpmPieceBitmap2[kind][piece]),
3429 NULL, &attr)) != 0) {
3430 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3431 // [HGM] missing: read of unorthodox piece failed; substitute King.
3432 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3433 ExpandPathName(appData.pixmapDirectory),
3435 if (appData.debugMode) {
3436 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3438 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3439 &(xpmPieceBitmap2[kind][piece]),
3443 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3448 if(piece <= (int) WhiteKing)
3449 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3452 /* Load light and dark squares */
3453 /* If the LSQ and DSQ pieces don't exist, we will
3454 draw them with solid squares. */
3455 fprintf(stderr, _("light square "));
3456 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3457 if (access(buf, 0) != 0) {
3461 if (appData.debugMode)
3462 fprintf(stderr, _("(File:%s:) "), buf);
3464 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3465 &xpmLightSquare, NULL, &attr)) != 0) {
3466 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3469 fprintf(stderr, _("dark square "));
3470 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3471 ExpandPathName(appData.pixmapDirectory), ss);
3472 if (appData.debugMode) {
3473 fprintf(stderr, _("(File:%s:) "), buf);
3475 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3476 &xpmDarkSquare, NULL, &attr)) != 0) {
3477 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3481 xpmJailSquare = xpmLightSquare;
3482 fprintf(stderr, _("Done.\n"));
3484 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3487 #endif /* HAVE_LIBXPM */
3490 /* No built-in bitmaps */
3495 u_int ss = squareSize;
3497 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3500 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3501 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3502 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3503 pieceBitmapNames[piece],
3504 ss, kind == SOLID ? 's' : 'o');
3505 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3506 if(piece <= (int)WhiteKing)
3507 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3511 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3515 /* With built-in bitmaps */
3518 BuiltInBits* bib = builtInBits;
3521 u_int ss = squareSize;
3523 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3526 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3528 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3529 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3530 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3531 pieceBitmapNames[piece],
3532 ss, kind == SOLID ? 's' : 'o');
3533 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3534 bib->bits[kind][piece], ss, ss);
3535 if(piece <= (int)WhiteKing)
3536 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3540 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3545 void ReadBitmap(pm, name, bits, wreq, hreq)
3548 unsigned char bits[];
3554 char msg[MSG_SIZ], fullname[MSG_SIZ];
3556 if (*appData.bitmapDirectory != NULLCHAR) {
3557 strcpy(fullname, appData.bitmapDirectory);
3558 strcat(fullname, "/");
3559 strcat(fullname, name);
3560 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3561 &w, &h, pm, &x_hot, &y_hot);
3562 fprintf(stderr, "load %s\n", name);
3563 if (errcode != BitmapSuccess) {
3565 case BitmapOpenFailed:
3566 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3568 case BitmapFileInvalid:
3569 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3571 case BitmapNoMemory:
3572 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3576 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3580 fprintf(stderr, _("%s: %s...using built-in\n"),
3582 } else if (w != wreq || h != hreq) {
3584 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3585 programName, fullname, w, h, wreq, hreq);
3591 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3600 if (lineGap == 0) return;
3602 /* [HR] Split this into 2 loops for non-square boards. */
3604 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3605 gridSegments[i].x1 = 0;
3606 gridSegments[i].x2 =
3607 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3608 gridSegments[i].y1 = gridSegments[i].y2
3609 = lineGap / 2 + (i * (squareSize + lineGap));
3612 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3613 gridSegments[j + i].y1 = 0;
3614 gridSegments[j + i].y2 =
3615 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3616 gridSegments[j + i].x1 = gridSegments[j + i].x2
3617 = lineGap / 2 + (j * (squareSize + lineGap));
3621 static void MenuBarSelect(w, addr, index)
3626 XtActionProc proc = (XtActionProc) addr;
3628 (proc)(NULL, NULL, NULL, NULL);
3631 void CreateMenuBarPopup(parent, name, mb)
3641 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3644 XtSetArg(args[j], XtNleftMargin, 20); j++;
3645 XtSetArg(args[j], XtNrightMargin, 20); j++;
3647 while (mi->string != NULL) {
3648 if (strcmp(mi->string, "----") == 0) {
3649 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3652 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3653 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3655 XtAddCallback(entry, XtNcallback,
3656 (XtCallbackProc) MenuBarSelect,
3657 (caddr_t) mi->proc);
3663 Widget CreateMenuBar(mb)
3667 Widget anchor, menuBar;
3669 char menuName[MSG_SIZ];
3672 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3673 XtSetArg(args[j], XtNvSpace, 0); j++;
3674 XtSetArg(args[j], XtNborderWidth, 0); j++;
3675 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3676 formWidget, args, j);
3678 while (mb->name != NULL) {
3679 strcpy(menuName, "menu");
3680 strcat(menuName, mb->name);
3682 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3685 shortName[0] = _(mb->name)[0];
3686 shortName[1] = NULLCHAR;
3687 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3690 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3693 XtSetArg(args[j], XtNborderWidth, 0); j++;
3694 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3696 CreateMenuBarPopup(menuBar, menuName, mb);
3702 Widget CreateButtonBar(mi)
3706 Widget button, buttonBar;
3710 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3712 XtSetArg(args[j], XtNhSpace, 0); j++;
3714 XtSetArg(args[j], XtNborderWidth, 0); j++;
3715 XtSetArg(args[j], XtNvSpace, 0); j++;
3716 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3717 formWidget, args, j);
3719 while (mi->string != NULL) {
3722 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3723 XtSetArg(args[j], XtNborderWidth, 0); j++;
3725 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3726 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3727 buttonBar, args, j);
3728 XtAddCallback(button, XtNcallback,
3729 (XtCallbackProc) MenuBarSelect,
3730 (caddr_t) mi->proc);
3737 CreatePieceMenu(name, color)
3744 ChessSquare selection;
3746 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3747 boardWidget, args, 0);
3749 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3750 String item = pieceMenuStrings[color][i];
3752 if (strcmp(item, "----") == 0) {
3753 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3756 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3757 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3759 selection = pieceMenuTranslation[color][i];
3760 XtAddCallback(entry, XtNcallback,
3761 (XtCallbackProc) PieceMenuSelect,
3762 (caddr_t) selection);
3763 if (selection == WhitePawn || selection == BlackPawn) {
3764 XtSetArg(args[0], XtNpopupOnEntry, entry);
3765 XtSetValues(menu, args, 1);
3778 ChessSquare selection;
3780 whitePieceMenu = CreatePieceMenu("menuW", 0);
3781 blackPieceMenu = CreatePieceMenu("menuB", 1);
3783 XtRegisterGrabAction(PieceMenuPopup, True,
3784 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3785 GrabModeAsync, GrabModeAsync);
3787 XtSetArg(args[0], XtNlabel, _("Drop"));
3788 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3789 boardWidget, args, 1);
3790 for (i = 0; i < DROP_MENU_SIZE; i++) {
3791 String item = dropMenuStrings[i];
3793 if (strcmp(item, "----") == 0) {
3794 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3797 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3798 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3800 selection = dropMenuTranslation[i];
3801 XtAddCallback(entry, XtNcallback,
3802 (XtCallbackProc) DropMenuSelect,
3803 (caddr_t) selection);
3808 void SetupDropMenu()
3816 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3817 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3818 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3819 dmEnables[i].piece);
3820 XtSetSensitive(entry, p != NULL || !appData.testLegality
3821 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3822 && !appData.icsActive));
3824 while (p && *p++ == dmEnables[i].piece) count++;
3825 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3827 XtSetArg(args[j], XtNlabel, label); j++;
3828 XtSetValues(entry, args, j);
3832 void PieceMenuPopup(w, event, params, num_params)
3836 Cardinal *num_params;
3838 String whichMenu; int menuNr;
3839 if (event->type == ButtonRelease)
3840 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3841 else if (event->type == ButtonPress)
3842 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3844 case 0: whichMenu = params[0]; break;
3845 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3847 case -1: if (errorUp) ErrorPopDown();
3850 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3853 static void PieceMenuSelect(w, piece, junk)
3858 if (pmFromX < 0 || pmFromY < 0) return;
3859 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3862 static void DropMenuSelect(w, piece, junk)
3867 if (pmFromX < 0 || pmFromY < 0) return;
3868 DropMenuEvent(piece, pmFromX, pmFromY);
3871 void WhiteClock(w, event, prms, nprms)
3877 if (gameMode == EditPosition || gameMode == IcsExamining) {
3878 SetWhiteToPlayEvent();
3879 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3884 void BlackClock(w, event, prms, nprms)
3890 if (gameMode == EditPosition || gameMode == IcsExamining) {
3891 SetBlackToPlayEvent();
3892 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3899 * If the user selects on a border boundary, return -1; if off the board,
3900 * return -2. Otherwise map the event coordinate to the square.
3902 int EventToSquare(x, limit)
3910 if ((x % (squareSize + lineGap)) >= squareSize)
3912 x /= (squareSize + lineGap);
3918 static void do_flash_delay(msec)
3924 static void drawHighlight(file, rank, gc)
3930 if (lineGap == 0 || appData.blindfold) return;
3933 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3934 (squareSize + lineGap);
3935 y = lineGap/2 + rank * (squareSize + lineGap);
3937 x = lineGap/2 + file * (squareSize + lineGap);
3938 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3939 (squareSize + lineGap);
3942 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3943 squareSize+lineGap, squareSize+lineGap);
3946 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3947 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3950 SetHighlights(fromX, fromY, toX, toY)
3951 int fromX, fromY, toX, toY;
3953 if (hi1X != fromX || hi1Y != fromY) {
3954 if (hi1X >= 0 && hi1Y >= 0) {
3955 drawHighlight(hi1X, hi1Y, lineGC);
3957 } // [HGM] first erase both, then draw new!
3958 if (hi2X != toX || hi2Y != toY) {
3959 if (hi2X >= 0 && hi2Y >= 0) {
3960 drawHighlight(hi2X, hi2Y, lineGC);
3963 if (hi1X != fromX || hi1Y != fromY) {
3964 if (fromX >= 0 && fromY >= 0) {
3965 drawHighlight(fromX, fromY, highlineGC);
3968 if (hi2X != toX || hi2Y != toY) {
3969 if (toX >= 0 && toY >= 0) {
3970 drawHighlight(toX, toY, highlineGC);
3982 SetHighlights(-1, -1, -1, -1);
3987 SetPremoveHighlights(fromX, fromY, toX, toY)
3988 int fromX, fromY, toX, toY;
3990 if (pm1X != fromX || pm1Y != fromY) {
3991 if (pm1X >= 0 && pm1Y >= 0) {
3992 drawHighlight(pm1X, pm1Y, lineGC);
3994 if (fromX >= 0 && fromY >= 0) {
3995 drawHighlight(fromX, fromY, prelineGC);
3998 if (pm2X != toX || pm2Y != toY) {
3999 if (pm2X >= 0 && pm2Y >= 0) {
4000 drawHighlight(pm2X, pm2Y, lineGC);
4002 if (toX >= 0 && toY >= 0) {
4003 drawHighlight(toX, toY, prelineGC);
4013 ClearPremoveHighlights()
4015 SetPremoveHighlights(-1, -1, -1, -1);
4018 static void BlankSquare(x, y, color, piece, dest)
4023 if (useImages && useImageSqs) {
4027 pm = xpmLightSquare;
4032 case 2: /* neutral */
4037 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4038 squareSize, squareSize, x, y);
4048 case 2: /* neutral */
4053 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4058 I split out the routines to draw a piece so that I could
4059 make a generic flash routine.
4061 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4063 int square_color, x, y;
4066 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4067 switch (square_color) {
4069 case 2: /* neutral */
4071 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4072 ? *pieceToOutline(piece)
4073 : *pieceToSolid(piece),
4074 dest, bwPieceGC, 0, 0,
4075 squareSize, squareSize, x, y);
4078 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4079 ? *pieceToSolid(piece)
4080 : *pieceToOutline(piece),
4081 dest, wbPieceGC, 0, 0,
4082 squareSize, squareSize, x, y);
4087 static void monoDrawPiece(piece, square_color, x, y, dest)
4089 int square_color, x, y;
4092 switch (square_color) {
4094 case 2: /* neutral */
4096 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4097 ? *pieceToOutline(piece)
4098 : *pieceToSolid(piece),
4099 dest, bwPieceGC, 0, 0,
4100 squareSize, squareSize, x, y, 1);
4103 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4104 ? *pieceToSolid(piece)
4105 : *pieceToOutline(piece),
4106 dest, wbPieceGC, 0, 0,
4107 squareSize, squareSize, x, y, 1);
4112 static void colorDrawPiece(piece, square_color, x, y, dest)
4114 int square_color, x, y;
4117 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4118 switch (square_color) {
4120 XCopyPlane(xDisplay, *pieceToSolid(piece),
4121 dest, (int) piece < (int) BlackPawn
4122 ? wlPieceGC : blPieceGC, 0, 0,
4123 squareSize, squareSize, x, y, 1);
4126 XCopyPlane(xDisplay, *pieceToSolid(piece),
4127 dest, (int) piece < (int) BlackPawn
4128 ? wdPieceGC : bdPieceGC, 0, 0,
4129 squareSize, squareSize, x, y, 1);
4131 case 2: /* neutral */
4133 XCopyPlane(xDisplay, *pieceToSolid(piece),
4134 dest, (int) piece < (int) BlackPawn
4135 ? wjPieceGC : bjPieceGC, 0, 0,
4136 squareSize, squareSize, x, y, 1);
4141 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4143 int square_color, x, y;
4148 switch (square_color) {
4150 case 2: /* neutral */
4152 if ((int)piece < (int) BlackPawn) {
4160 if ((int)piece < (int) BlackPawn) {
4168 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4169 dest, wlPieceGC, 0, 0,
4170 squareSize, squareSize, x, y);
4173 typedef void (*DrawFunc)();
4175 DrawFunc ChooseDrawFunc()
4177 if (appData.monoMode) {
4178 if (DefaultDepth(xDisplay, xScreen) == 1) {
4179 return monoDrawPiece_1bit;
4181 return monoDrawPiece;
4185 return colorDrawPieceImage;
4187 return colorDrawPiece;
4191 /* [HR] determine square color depending on chess variant. */
4192 static int SquareColor(row, column)
4197 if (gameInfo.variant == VariantXiangqi) {
4198 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4200 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4202 } else if (row <= 4) {
4208 square_color = ((column + row) % 2) == 1;
4211 /* [hgm] holdings: next line makes all holdings squares light */
4212 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4214 return square_color;
4217 void DrawSquare(row, column, piece, do_flash)
4218 int row, column, do_flash;
4221 int square_color, x, y, direction, font_ascent, font_descent;
4224 XCharStruct overall;
4228 /* Calculate delay in milliseconds (2-delays per complete flash) */
4229 flash_delay = 500 / appData.flashRate;
4232 x = lineGap + ((BOARD_WIDTH-1)-column) *
4233 (squareSize + lineGap);
4234 y = lineGap + row * (squareSize + lineGap);
4236 x = lineGap + column * (squareSize + lineGap);
4237 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4238 (squareSize + lineGap);
4241 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4243 square_color = SquareColor(row, column);
4245 if ( // [HGM] holdings: blank out area between board and holdings
4246 column == BOARD_LEFT-1 || column == BOARD_RGHT
4247 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4248 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4249 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4251 // [HGM] print piece counts next to holdings
4252 string[1] = NULLCHAR;
4253 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4254 string[0] = '0' + piece;
4255 XTextExtents(countFontStruct, string, 1, &direction,
4256 &font_ascent, &font_descent, &overall);
4257 if (appData.monoMode) {
4258 XDrawImageString(xDisplay, xBoardWindow, countGC,
4259 x + squareSize - overall.width - 2,
4260 y + font_ascent + 1, string, 1);
4262 XDrawString(xDisplay, xBoardWindow, countGC,
4263 x + squareSize - overall.width - 2,
4264 y + font_ascent + 1, string, 1);