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"
194 #include "backendz.h"
198 #include "xgamelist.h"
199 #include "xhistory.h"
200 #include "xedittags.h"
203 // must be moved to xengineoutput.h
205 void EngineOutputProc P((Widget w, XEvent *event,
206 String *prms, Cardinal *nprms));
207 void EvalGraphProc P((Widget w, XEvent *event,
208 String *prms, Cardinal *nprms));
215 #define usleep(t) _sleep2(((t)+500)/1000)
219 # define _(s) gettext (s)
220 # define N_(s) gettext_noop (s)
236 int main P((int argc, char **argv));
237 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
238 char *init_path, char *mode, int (*show_entry)(), char **name_return));
239 RETSIGTYPE CmailSigHandler P((int sig));
240 RETSIGTYPE IntSigHandler P((int sig));
241 RETSIGTYPE TermSizeSigHandler P((int sig));
242 void CreateGCs P((void));
243 void CreateXIMPieces P((void));
244 void CreateXPMPieces P((void));
245 void CreateXPMBoard P((char *s, int n));
246 void CreatePieces P((void));
247 void CreatePieceMenus P((void));
248 Widget CreateMenuBar P((Menu *mb));
249 Widget CreateButtonBar P ((MenuItem *mi));
250 char *FindFont P((char *pattern, int targetPxlSize));
251 void PieceMenuPopup P((Widget w, XEvent *event,
252 String *params, Cardinal *num_params));
253 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
254 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
255 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
256 u_int wreq, u_int hreq));
257 void CreateGrid P((void));
258 int EventToSquare P((int x, int limit));
259 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
260 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
261 void HandleUserMove P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void AnimateUserMove P((Widget w, XEvent * event,
264 String * params, Cardinal * nParams));
265 void HandlePV P((Widget w, XEvent * event,
266 String * params, Cardinal * nParams));
267 void SelectPV P((Widget w, XEvent * event,
268 String * params, Cardinal * nParams));
269 void StopPV P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void WhiteClock P((Widget w, XEvent *event,
272 String *prms, Cardinal *nprms));
273 void BlackClock P((Widget w, XEvent *event,
274 String *prms, Cardinal *nprms));
275 void DrawPositionProc P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
279 void CommentClick P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void CommentPopUp P((char *title, char *label));
282 void CommentPopDown P((void));
283 void CommentCallback P((Widget w, XtPointer client_data,
284 XtPointer call_data));
285 void ICSInputBoxPopUp P((void));
286 void ICSInputBoxPopDown P((void));
287 void FileNamePopUp P((char *label, char *def,
288 FileProc proc, char *openMode));
289 void FileNamePopDown P((void));
290 void FileNameCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void FileNameAction P((Widget w, XEvent *event,
293 String *prms, Cardinal *nprms));
294 void AskQuestionReplyAction P((Widget w, XEvent *event,
295 String *prms, Cardinal *nprms));
296 void AskQuestionProc P((Widget w, XEvent *event,
297 String *prms, Cardinal *nprms));
298 void AskQuestionPopDown P((void));
299 void PromotionPopDown P((void));
300 void PromotionCallback P((Widget w, XtPointer client_data,
301 XtPointer call_data));
302 void EditCommentPopDown P((void));
303 void EditCommentCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
306 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
307 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
308 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
310 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
312 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
314 void LoadPositionProc P((Widget w, XEvent *event,
315 String *prms, Cardinal *nprms));
316 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
318 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
320 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
322 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
324 void PastePositionProc P((Widget w, XEvent *event, String *prms,
326 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
327 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
328 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
329 void SavePositionProc P((Widget w, XEvent *event,
330 String *prms, Cardinal *nprms));
331 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
334 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
338 void MachineWhiteProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AnalyzeModeProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AnalyzeFileProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
346 void IcsClientProc P((Widget w, XEvent *event, String *prms,
348 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void EditPositionProc P((Widget w, XEvent *event,
350 String *prms, Cardinal *nprms));
351 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void EditCommentProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void IcsInputBoxProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void StopObservingProc P((Widget w, XEvent *event, String *prms,
372 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
374 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
383 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
385 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
388 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
390 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
392 void AutocommProc P((Widget w, XEvent *event, String *prms,
394 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AutobsProc P((Widget w, XEvent *event, String *prms,
398 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
403 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
406 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
408 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
410 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
414 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
416 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
418 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
420 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
422 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
426 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
428 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
430 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
432 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void DisplayMove P((int moveNumber));
444 void DisplayTitle P((char *title));
445 void ICSInitScript P((void));
446 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
447 void ErrorPopUp P((char *title, char *text, int modal));
448 void ErrorPopDown P((void));
449 static char *ExpandPathName P((char *path));
450 static void CreateAnimVars P((void));
451 static void DragPieceMove P((int x, int y));
452 static void DrawDragPiece P((void));
453 char *ModeToWidgetName P((GameMode mode));
454 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void GameListOptionsPopDown P(());
463 void ShufflePopDown P(());
464 void EnginePopDown P(());
465 void UciPopDown P(());
466 void TimeControlPopDown P(());
467 void NewVariantPopDown P(());
468 void SettingsPopDown P(());
469 void update_ics_width P(());
470 int get_term_width P(());
471 int CopyMemoProc P(());
473 * XBoard depends on Xt R4 or higher
475 int xtVersion = XtSpecificationRelease;
480 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
481 jailSquareColor, highlightSquareColor, premoveHighlightColor;
482 Pixel lowTimeWarningColor;
483 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
484 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
485 wjPieceGC, bjPieceGC, prelineGC, countGC;
486 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
487 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
488 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
489 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
490 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
491 ICSInputShell, fileNameShell, askQuestionShell;
492 Widget historyShell, evalGraphShell, gameListShell;
493 int hOffset; // [HGM] dual
494 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
495 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
496 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
497 Font clockFontID, coordFontID, countFontID;
498 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
499 XtAppContext appContext;
501 char *oldICSInteractionTitle;
505 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
507 Position commentX = -1, commentY = -1;
508 Dimension commentW, commentH;
509 typedef unsigned int BoardSize;
511 Boolean chessProgram;
513 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
514 int squareSize, smallLayout = 0, tinyLayout = 0,
515 marginW, marginH, // [HGM] for run-time resizing
516 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
517 ICSInputBoxUp = False, askQuestionUp = False,
518 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
519 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
520 Pixel timerForegroundPixel, timerBackgroundPixel;
521 Pixel buttonForegroundPixel, buttonBackgroundPixel;
522 char *chessDir, *programName, *programVersion,
523 *gameCopyFilename, *gamePasteFilename;
524 Boolean alwaysOnTop = False;
525 Boolean saveSettingsOnExit;
526 char *settingsFileName;
527 char *icsTextMenuString;
529 char *firstChessProgramNames;
530 char *secondChessProgramNames;
532 WindowPlacement wpMain;
533 WindowPlacement wpConsole;
534 WindowPlacement wpComment;
535 WindowPlacement wpMoveHistory;
536 WindowPlacement wpEvalGraph;
537 WindowPlacement wpEngineOutput;
538 WindowPlacement wpGameList;
539 WindowPlacement wpTags;
543 Pixmap pieceBitmap[2][(int)BlackPawn];
544 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
545 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
546 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
547 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
548 Pixmap xpmBoardBitmap[2];
549 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
550 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
551 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
552 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
553 XImage *ximLightSquare, *ximDarkSquare;
556 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
557 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
559 #define White(piece) ((int)(piece) < (int)BlackPawn)
561 /* Variables for doing smooth animation. This whole thing
562 would be much easier if the board was double-buffered,
563 but that would require a fairly major rewrite. */
568 GC blitGC, pieceGC, outlineGC;
569 XPoint startSquare, prevFrame, mouseDelta;
573 int startBoardX, startBoardY;
576 /* There can be two pieces being animated at once: a player
577 can begin dragging a piece before the remote opponent has moved. */
579 static AnimState game, player;
581 /* Bitmaps for use as masks when drawing XPM pieces.
582 Need one for each black and white piece. */
583 static Pixmap xpmMask[BlackKing + 1];
585 /* This magic number is the number of intermediate frames used
586 in each half of the animation. For short moves it's reduced
587 by 1. The total number of frames will be factor * 2 + 1. */
590 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
592 MenuItem fileMenu[] = {
593 {N_("New Game"), ResetProc},
594 {N_("New Shuffle Game ..."), ShuffleMenuProc},
595 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
596 {"----", NothingProc},
597 {N_("Load Game"), LoadGameProc},
598 {N_("Load Next Game"), LoadNextGameProc},
599 {N_("Load Previous Game"), LoadPrevGameProc},
600 {N_("Reload Same Game"), ReloadGameProc},
601 {N_("Save Game"), SaveGameProc},
602 {"----", NothingProc},
603 {N_("Copy Game"), CopyGameProc},
604 {N_("Paste Game"), PasteGameProc},
605 {"----", NothingProc},
606 {N_("Load Position"), LoadPositionProc},
607 {N_("Load Next Position"), LoadNextPositionProc},
608 {N_("Load Previous Position"), LoadPrevPositionProc},
609 {N_("Reload Same Position"), ReloadPositionProc},
610 {N_("Save Position"), SavePositionProc},
611 {"----", NothingProc},
612 {N_("Copy Position"), CopyPositionProc},
613 {N_("Paste Position"), PastePositionProc},
614 {"----", NothingProc},
615 {N_("Mail Move"), MailMoveProc},
616 {N_("Reload CMail Message"), ReloadCmailMsgProc},
617 {"----", NothingProc},
618 {N_("Exit"), QuitProc},
622 MenuItem modeMenu[] = {
623 {N_("Machine White"), MachineWhiteProc},
624 {N_("Machine Black"), MachineBlackProc},
625 {N_("Two Machines"), TwoMachinesProc},
626 {N_("Analysis Mode"), AnalyzeModeProc},
627 {N_("Analyze File"), AnalyzeFileProc },
628 {N_("ICS Client"), IcsClientProc},
629 {N_("Edit Game"), EditGameProc},
630 {N_("Edit Position"), EditPositionProc},
631 {N_("Training"), TrainingProc},
632 {"----", NothingProc},
633 {N_("Show Engine Output"), EngineOutputProc},
634 {N_("Show Evaluation Graph"), EvalGraphProc},
635 {N_("Show Game List"), ShowGameListProc},
636 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
637 {"----", NothingProc},
638 {N_("Edit Tags"), EditTagsProc},
639 {N_("Edit Comment"), EditCommentProc},
640 {N_("ICS Input Box"), IcsInputBoxProc},
641 {N_("Pause"), PauseProc},
645 MenuItem actionMenu[] = {
646 {N_("Accept"), AcceptProc},
647 {N_("Decline"), DeclineProc},
648 {N_("Rematch"), RematchProc},
649 {"----", NothingProc},
650 {N_("Call Flag"), CallFlagProc},
651 {N_("Draw"), DrawProc},
652 {N_("Adjourn"), AdjournProc},
653 {N_("Abort"), AbortProc},
654 {N_("Resign"), ResignProc},
655 {"----", NothingProc},
656 {N_("Stop Observing"), StopObservingProc},
657 {N_("Stop Examining"), StopExaminingProc},
658 {N_("Upload to Examine"), UploadProc},
659 {"----", NothingProc},
660 {N_("Adjudicate to White"), AdjuWhiteProc},
661 {N_("Adjudicate to Black"), AdjuBlackProc},
662 {N_("Adjudicate Draw"), AdjuDrawProc},
666 MenuItem stepMenu[] = {
667 {N_("Backward"), BackwardProc},
668 {N_("Forward"), ForwardProc},
669 {N_("Back to Start"), ToStartProc},
670 {N_("Forward to End"), ToEndProc},
671 {N_("Revert"), RevertProc},
672 {N_("Annotate"), AnnotateProc},
673 {N_("Truncate Game"), TruncateGameProc},
674 {"----", NothingProc},
675 {N_("Move Now"), MoveNowProc},
676 {N_("Retract Move"), RetractMoveProc},
680 MenuItem optionsMenu[] = {
681 {N_("Flip View"), FlipViewProc},
682 {"----", NothingProc},
683 {N_("Adjudications ..."), EngineMenuProc},
684 {N_("General Settings ..."), UciMenuProc},
685 {N_("Engine #1 Settings ..."), FirstSettingsProc},
686 {N_("Engine #2 Settings ..."), SecondSettingsProc},
687 {N_("Time Control ..."), TimeControlProc},
688 {N_("Game List ..."), GameListOptionsPopUp},
689 {"----", NothingProc},
690 {N_("Always Queen"), AlwaysQueenProc},
691 {N_("Animate Dragging"), AnimateDraggingProc},
692 {N_("Animate Moving"), AnimateMovingProc},
693 {N_("Auto Comment"), AutocommProc},
694 {N_("Auto Flag"), AutoflagProc},
695 {N_("Auto Flip View"), AutoflipProc},
696 {N_("Auto Observe"), AutobsProc},
697 {N_("Auto Raise Board"), AutoraiseProc},
698 {N_("Auto Save"), AutosaveProc},
699 {N_("Blindfold"), BlindfoldProc},
700 {N_("Flash Moves"), FlashMovesProc},
701 {N_("Get Move List"), GetMoveListProc},
703 {N_("Highlight Dragging"), HighlightDraggingProc},
705 {N_("Highlight Last Move"), HighlightLastMoveProc},
706 {N_("Move Sound"), MoveSoundProc},
707 {N_("ICS Alarm"), IcsAlarmProc},
708 {N_("Old Save Style"), OldSaveStyleProc},
709 {N_("Periodic Updates"), PeriodicUpdatesProc},
710 {N_("Ponder Next Move"), PonderNextMoveProc},
711 {N_("Popup Exit Message"), PopupExitMessageProc},
712 {N_("Popup Move Errors"), PopupMoveErrorsProc},
713 {N_("Premove"), PremoveProc},
714 {N_("Quiet Play"), QuietPlayProc},
715 {N_("Show Coords"), ShowCoordsProc},
716 {N_("Hide Thinking"), HideThinkingProc},
717 {N_("Test Legality"), TestLegalityProc},
718 {"----", NothingProc},
719 {N_("Save Settings Now"), SaveSettingsProc},
720 {N_("Save Settings on Exit"), SaveOnExitProc},
724 MenuItem helpMenu[] = {
725 {N_("Info XBoard"), InfoProc},
726 {N_("Man XBoard"), ManProc},
727 {"----", NothingProc},
728 {N_("Hint"), HintProc},
729 {N_("Book"), BookProc},
730 {"----", NothingProc},
731 {N_("About XBoard"), AboutProc},
736 {N_("File"), fileMenu},
737 {N_("Mode"), modeMenu},
738 {N_("Action"), actionMenu},
739 {N_("Step"), stepMenu},
740 {N_("Options"), optionsMenu},
741 {N_("Help"), helpMenu},
745 #define PAUSE_BUTTON N_("P")
746 MenuItem buttonBar[] = {
749 {PAUSE_BUTTON, PauseProc},
755 #define PIECE_MENU_SIZE 18
756 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
757 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
758 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
759 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
760 N_("Empty square"), N_("Clear board") },
761 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
762 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
763 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
764 N_("Empty square"), N_("Clear board") }
766 /* must be in same order as PieceMenuStrings! */
767 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
768 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
769 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
770 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
771 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
772 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
773 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
774 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
775 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
778 #define DROP_MENU_SIZE 6
779 String dropMenuStrings[DROP_MENU_SIZE] = {
780 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
782 /* must be in same order as PieceMenuStrings! */
783 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
784 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
785 WhiteRook, WhiteQueen
793 DropMenuEnables dmEnables[] = {
811 { XtNborderWidth, 0 },
812 { XtNdefaultDistance, 0 },
816 { XtNborderWidth, 0 },
817 { XtNresizable, (XtArgVal) True },
821 { XtNborderWidth, 0 },
827 { XtNjustify, (XtArgVal) XtJustifyRight },
828 { XtNlabel, (XtArgVal) "..." },
829 { XtNresizable, (XtArgVal) True },
830 { XtNresize, (XtArgVal) False }
833 Arg messageArgs[] = {
834 { XtNjustify, (XtArgVal) XtJustifyLeft },
835 { XtNlabel, (XtArgVal) "..." },
836 { XtNresizable, (XtArgVal) True },
837 { XtNresize, (XtArgVal) False }
841 { XtNborderWidth, 0 },
842 { XtNjustify, (XtArgVal) XtJustifyLeft }
845 XtResource clientResources[] = {
846 { "flashCount", "flashCount", XtRInt, sizeof(int),
847 XtOffset(AppDataPtr, flashCount), XtRImmediate,
848 (XtPointer) FLASH_COUNT },
851 XrmOptionDescRec shellOptions[] = {
852 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
853 { "-flash", "flashCount", XrmoptionNoArg, "3" },
854 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
857 XtActionsRec boardActions[] = {
858 { "DrawPosition", DrawPositionProc },
859 { "HandleUserMove", HandleUserMove },
860 { "AnimateUserMove", AnimateUserMove },
861 { "HandlePV", HandlePV },
862 { "SelectPV", SelectPV },
863 { "StopPV", StopPV },
864 { "FileNameAction", FileNameAction },
865 { "AskQuestionProc", AskQuestionProc },
866 { "AskQuestionReplyAction", AskQuestionReplyAction },
867 { "PieceMenuPopup", PieceMenuPopup },
868 { "WhiteClock", WhiteClock },
869 { "BlackClock", BlackClock },
870 { "Iconify", Iconify },
871 { "ResetProc", ResetProc },
872 { "NewVariantProc", NewVariantProc },
873 { "LoadGameProc", LoadGameProc },
874 { "LoadNextGameProc", LoadNextGameProc },
875 { "LoadPrevGameProc", LoadPrevGameProc },
876 { "LoadSelectedProc", LoadSelectedProc },
877 { "SetFilterProc", SetFilterProc },
878 { "ReloadGameProc", ReloadGameProc },
879 { "LoadPositionProc", LoadPositionProc },
880 { "LoadNextPositionProc", LoadNextPositionProc },
881 { "LoadPrevPositionProc", LoadPrevPositionProc },
882 { "ReloadPositionProc", ReloadPositionProc },
883 { "CopyPositionProc", CopyPositionProc },
884 { "PastePositionProc", PastePositionProc },
885 { "CopyGameProc", CopyGameProc },
886 { "PasteGameProc", PasteGameProc },
887 { "SaveGameProc", SaveGameProc },
888 { "SavePositionProc", SavePositionProc },
889 { "MailMoveProc", MailMoveProc },
890 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
891 { "QuitProc", QuitProc },
892 { "MachineWhiteProc", MachineWhiteProc },
893 { "MachineBlackProc", MachineBlackProc },
894 { "AnalysisModeProc", AnalyzeModeProc },
895 { "AnalyzeFileProc", AnalyzeFileProc },
896 { "TwoMachinesProc", TwoMachinesProc },
897 { "IcsClientProc", IcsClientProc },
898 { "EditGameProc", EditGameProc },
899 { "EditPositionProc", EditPositionProc },
900 { "TrainingProc", EditPositionProc },
901 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
902 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
903 { "ShowGameListProc", ShowGameListProc },
904 { "ShowMoveListProc", HistoryShowProc},
905 { "EditTagsProc", EditCommentProc },
906 { "EditCommentProc", EditCommentProc },
907 { "IcsAlarmProc", IcsAlarmProc },
908 { "IcsInputBoxProc", IcsInputBoxProc },
909 { "PauseProc", PauseProc },
910 { "AcceptProc", AcceptProc },
911 { "DeclineProc", DeclineProc },
912 { "RematchProc", RematchProc },
913 { "CallFlagProc", CallFlagProc },
914 { "DrawProc", DrawProc },
915 { "AdjournProc", AdjournProc },
916 { "AbortProc", AbortProc },
917 { "ResignProc", ResignProc },
918 { "AdjuWhiteProc", AdjuWhiteProc },
919 { "AdjuBlackProc", AdjuBlackProc },
920 { "AdjuDrawProc", AdjuDrawProc },
921 { "EnterKeyProc", EnterKeyProc },
922 { "UpKeyProc", UpKeyProc },
923 { "DownKeyProc", DownKeyProc },
924 { "StopObservingProc", StopObservingProc },
925 { "StopExaminingProc", StopExaminingProc },
926 { "UploadProc", UploadProc },
927 { "BackwardProc", BackwardProc },
928 { "ForwardProc", ForwardProc },
929 { "ToStartProc", ToStartProc },
930 { "ToEndProc", ToEndProc },
931 { "RevertProc", RevertProc },
932 { "AnnotateProc", AnnotateProc },
933 { "TruncateGameProc", TruncateGameProc },
934 { "MoveNowProc", MoveNowProc },
935 { "RetractMoveProc", RetractMoveProc },
936 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
937 { "UciMenuProc", (XtActionProc) UciMenuProc },
938 { "TimeControlProc", (XtActionProc) TimeControlProc },
939 { "AlwaysQueenProc", AlwaysQueenProc },
940 { "AnimateDraggingProc", AnimateDraggingProc },
941 { "AnimateMovingProc", AnimateMovingProc },
942 { "AutoflagProc", AutoflagProc },
943 { "AutoflipProc", AutoflipProc },
944 { "AutobsProc", AutobsProc },
945 { "AutoraiseProc", AutoraiseProc },
946 { "AutosaveProc", AutosaveProc },
947 { "BlindfoldProc", BlindfoldProc },
948 { "FlashMovesProc", FlashMovesProc },
949 { "FlipViewProc", FlipViewProc },
950 { "GetMoveListProc", GetMoveListProc },
952 { "HighlightDraggingProc", HighlightDraggingProc },
954 { "HighlightLastMoveProc", HighlightLastMoveProc },
955 { "IcsAlarmProc", IcsAlarmProc },
956 { "MoveSoundProc", MoveSoundProc },
957 { "OldSaveStyleProc", OldSaveStyleProc },
958 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
959 { "PonderNextMoveProc", PonderNextMoveProc },
960 { "PopupExitMessageProc", PopupExitMessageProc },
961 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
962 { "PremoveProc", PremoveProc },
963 { "QuietPlayProc", QuietPlayProc },
964 { "ShowCoordsProc", ShowCoordsProc },
965 { "ShowThinkingProc", ShowThinkingProc },
966 { "HideThinkingProc", HideThinkingProc },
967 { "TestLegalityProc", TestLegalityProc },
968 { "SaveSettingsProc", SaveSettingsProc },
969 { "SaveOnExitProc", SaveOnExitProc },
970 { "InfoProc", InfoProc },
971 { "ManProc", ManProc },
972 { "HintProc", HintProc },
973 { "BookProc", BookProc },
974 { "AboutGameProc", AboutGameProc },
975 { "AboutProc", AboutProc },
976 { "DebugProc", DebugProc },
977 { "NothingProc", NothingProc },
978 { "CommentClick", (XtActionProc) CommentClick },
979 { "CommentPopDown", (XtActionProc) CommentPopDown },
980 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
981 { "TagsPopDown", (XtActionProc) TagsPopDown },
982 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
983 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
984 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
985 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
986 { "GameListPopDown", (XtActionProc) GameListPopDown },
987 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
988 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
989 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
990 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
991 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
992 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
993 { "EnginePopDown", (XtActionProc) EnginePopDown },
994 { "UciPopDown", (XtActionProc) UciPopDown },
995 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
996 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
997 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
998 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1001 char globalTranslations[] =
1002 ":<Key>F9: ResignProc() \n \
1003 :Ctrl<Key>n: ResetProc() \n \
1004 :Meta<Key>V: NewVariantProc() \n \
1005 :Ctrl<Key>o: LoadGameProc() \n \
1006 :Meta<Key>Next: LoadNextGameProc() \n \
1007 :Meta<Key>Prior: LoadPrevGameProc() \n \
1008 :Ctrl<Key>s: SaveGameProc() \n \
1009 :Ctrl<Key>c: CopyGameProc() \n \
1010 :Ctrl<Key>v: PasteGameProc() \n \
1011 :Ctrl<Key>O: LoadPositionProc() \n \
1012 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1013 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1014 :Ctrl<Key>S: SavePositionProc() \n \
1015 :Ctrl<Key>C: CopyPositionProc() \n \
1016 :Ctrl<Key>V: PastePositionProc() \n \
1017 :Ctrl<Key>q: QuitProc() \n \
1018 :Ctrl<Key>w: MachineWhiteProc() \n \
1019 :Ctrl<Key>b: MachineBlackProc() \n \
1020 :Ctrl<Key>t: TwoMachinesProc() \n \
1021 :Ctrl<Key>a: AnalysisModeProc() \n \
1022 :Ctrl<Key>f: AnalyzeFileProc() \n \
1023 :Ctrl<Key>e: EditGameProc() \n \
1024 :Ctrl<Key>E: EditPositionProc() \n \
1025 :Meta<Key>O: EngineOutputProc() \n \
1026 :Meta<Key>E: EvalGraphProc() \n \
1027 :Meta<Key>G: ShowGameListProc() \n \
1028 :Meta<Key>H: ShowMoveListProc() \n \
1029 :<Key>Pause: PauseProc() \n \
1030 :<Key>F3: AcceptProc() \n \
1031 :<Key>F4: DeclineProc() \n \
1032 :<Key>F12: RematchProc() \n \
1033 :<Key>F5: CallFlagProc() \n \
1034 :<Key>F6: DrawProc() \n \
1035 :<Key>F7: AdjournProc() \n \
1036 :<Key>F8: AbortProc() \n \
1037 :<Key>F10: StopObservingProc() \n \
1038 :<Key>F11: StopExaminingProc() \n \
1039 :Meta Ctrl<Key>F12: DebugProc() \n \
1040 :Meta<Key>End: ToEndProc() \n \
1041 :Meta<Key>Right: ForwardProc() \n \
1042 :Meta<Key>Home: ToStartProc() \n \
1043 :Meta<Key>Left: BackwardProc() \n \
1044 :Ctrl<Key>m: MoveNowProc() \n \
1045 :Ctrl<Key>x: RetractMoveProc() \n \
1046 :Meta<Key>J: EngineMenuProc() \n \
1047 :Meta<Key>U: UciMenuProc() \n \
1048 :Meta<Key>T: TimeControlProc() \n \
1049 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1050 :Ctrl<Key>F: AutoflagProc() \n \
1051 :Ctrl<Key>A: AnimateMovingProc() \n \
1052 :Ctrl<Key>P: PonderNextMoveProc() \n \
1053 :Ctrl<Key>L: TestLegalityProc() \n \
1054 :Ctrl<Key>H: HideThinkingProc() \n \
1055 :<Key>-: Iconify() \n \
1056 :<Key>F1: ManProc() \n \
1057 :<Key>F2: FlipViewProc() \n \
1058 <KeyDown>.: BackwardProc() \n \
1059 <KeyUp>.: ForwardProc() \n \
1060 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1061 \"Send to chess program:\",,1) \n \
1062 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1063 \"Send to second chess program:\",,2) \n";
1065 char boardTranslations[] =
1066 "<Btn1Down>: HandleUserMove(0) \n \
1067 Shift<Btn1Up>: HandleUserMove(1) \n \
1068 <Btn1Up>: HandleUserMove(0) \n \
1069 <Btn1Motion>: AnimateUserMove() \n \
1070 <Btn3Motion>: HandlePV() \n \
1071 <Btn3Up>: PieceMenuPopup(menuB) \n \
1072 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1073 PieceMenuPopup(menuB) \n \
1074 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1075 PieceMenuPopup(menuW) \n \
1076 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1077 PieceMenuPopup(menuW) \n \
1078 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1079 PieceMenuPopup(menuB) \n";
1081 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1082 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1084 char ICSInputTranslations[] =
1085 "<Key>Up: UpKeyProc() \n "
1086 "<Key>Down: DownKeyProc() \n "
1087 "<Key>Return: EnterKeyProc() \n";
1089 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1090 // as the widget is destroyed before the up-click can call extend-end
1091 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1093 String xboardResources[] = {
1094 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1095 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1096 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1101 /* Max possible square size */
1102 #define MAXSQSIZE 256
1104 static int xpm_avail[MAXSQSIZE];
1106 #ifdef HAVE_DIR_STRUCT
1108 /* Extract piece size from filename */
1110 xpm_getsize(name, len, ext)
1121 if ((p=strchr(name, '.')) == NULL ||
1122 StrCaseCmp(p+1, ext) != 0)
1128 while (*p && isdigit(*p))
1135 /* Setup xpm_avail */
1137 xpm_getavail(dirname, ext)
1145 for (i=0; i<MAXSQSIZE; ++i)
1148 if (appData.debugMode)
1149 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1151 dir = opendir(dirname);
1154 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1155 programName, dirname);
1159 while ((ent=readdir(dir)) != NULL) {
1160 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1161 if (i > 0 && i < MAXSQSIZE)
1171 xpm_print_avail(fp, ext)
1177 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1178 for (i=1; i<MAXSQSIZE; ++i) {
1184 /* Return XPM piecesize closest to size */
1186 xpm_closest_to(dirname, size, ext)
1192 int sm_diff = MAXSQSIZE;
1196 xpm_getavail(dirname, ext);
1198 if (appData.debugMode)
1199 xpm_print_avail(stderr, ext);
1201 for (i=1; i<MAXSQSIZE; ++i) {
1204 diff = (diff<0) ? -diff : diff;
1205 if (diff < sm_diff) {
1213 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1219 #else /* !HAVE_DIR_STRUCT */
1220 /* If we are on a system without a DIR struct, we can't
1221 read the directory, so we can't collect a list of
1222 filenames, etc., so we can't do any size-fitting. */
1224 xpm_closest_to(dirname, size, ext)
1229 fprintf(stderr, _("\
1230 Warning: No DIR structure found on this system --\n\
1231 Unable to autosize for XPM/XIM pieces.\n\
1232 Please report this error to frankm@hiwaay.net.\n\
1233 Include system type & operating system in message.\n"));
1236 #endif /* HAVE_DIR_STRUCT */
1238 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1239 "magenta", "cyan", "white" };
1243 TextColors textColors[(int)NColorClasses];
1245 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1247 parse_color(str, which)
1251 char *p, buf[100], *d;
1254 if (strlen(str) > 99) /* watch bounds on buf */
1259 for (i=0; i<which; ++i) {
1266 /* Could be looking at something like:
1268 .. in which case we want to stop on a comma also */
1269 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1273 return -1; /* Use default for empty field */
1276 if (which == 2 || isdigit(*p))
1279 while (*p && isalpha(*p))
1284 for (i=0; i<8; ++i) {
1285 if (!StrCaseCmp(buf, cnames[i]))
1286 return which? (i+40) : (i+30);
1288 if (!StrCaseCmp(buf, "default")) return -1;
1290 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1295 parse_cpair(cc, str)
1299 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1300 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1305 /* bg and attr are optional */
1306 textColors[(int)cc].bg = parse_color(str, 1);
1307 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1308 textColors[(int)cc].attr = 0;
1314 /* Arrange to catch delete-window events */
1315 Atom wm_delete_window;
1317 CatchDeleteWindow(Widget w, String procname)
1320 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1321 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1322 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1329 XtSetArg(args[0], XtNiconic, False);
1330 XtSetValues(shellWidget, args, 1);
1332 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1335 //---------------------------------------------------------------------------------------------------------
1336 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1339 #define CW_USEDEFAULT (1<<31)
1340 #define ICS_TEXT_MENU_SIZE 90
1341 #define DEBUG_FILE "xboard.debug"
1342 #define SetCurrentDirectory chdir
1343 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1347 // these two must some day move to frontend.h, when they are implemented
1348 Boolean GameListIsUp();
1350 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1353 // front-end part of option handling
1355 // [HGM] This platform-dependent table provides the location for storing the color info
1356 extern char *crWhite, * crBlack;
1360 &appData.whitePieceColor,
1361 &appData.blackPieceColor,
1362 &appData.lightSquareColor,
1363 &appData.darkSquareColor,
1364 &appData.highlightSquareColor,
1365 &appData.premoveHighlightColor,
1366 &appData.lowTimeWarningColor,
1377 // [HGM] font: keep a font for each square size, even non-stndard ones
1378 #define NUM_SIZES 18
1379 #define MAX_SIZE 130
1380 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1381 char *fontTable[NUM_FONTS][MAX_SIZE];
1384 ParseFont(char *name, int number)
1385 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1387 if(sscanf(name, "size%d:", &size)) {
1388 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1389 // defer processing it until we know if it matches our board size
1390 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1391 fontTable[number][size] = strdup(strchr(name, ':')+1);
1392 fontValid[number][size] = True;
1397 case 0: // CLOCK_FONT
1398 appData.clockFont = strdup(name);
1400 case 1: // MESSAGE_FONT
1401 appData.font = strdup(name);
1403 case 2: // COORD_FONT
1404 appData.coordFont = strdup(name);
1409 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1414 { // only 2 fonts currently
1415 appData.clockFont = CLOCK_FONT_NAME;
1416 appData.coordFont = COORD_FONT_NAME;
1417 appData.font = DEFAULT_FONT_NAME;
1422 { // no-op, until we identify the code for this already in XBoard and move it here
1426 ParseColor(int n, char *name)
1427 { // in XBoard, just copy the color-name string
1428 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1432 ParseTextAttribs(ColorClass cc, char *s)
1434 (&appData.colorShout)[cc] = strdup(s);
1438 ParseBoardSize(void *addr, char *name)
1440 appData.boardSize = strdup(name);
1445 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1449 SetCommPortDefaults()
1450 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1453 // [HGM] args: these three cases taken out to stay in front-end
1455 SaveFontArg(FILE *f, ArgDescriptor *ad)
1458 int i, n = (int)ad->argLoc;
1460 case 0: // CLOCK_FONT
1461 name = appData.clockFont;
1463 case 1: // MESSAGE_FONT
1464 name = appData.font;
1466 case 2: // COORD_FONT
1467 name = appData.coordFont;
1472 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1473 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1474 fontTable[n][squareSize] = strdup(name);
1475 fontValid[n][squareSize] = True;
1478 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1479 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1484 { // nothing to do, as the sounds are at all times represented by their text-string names already
1488 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1489 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1490 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1494 SaveColor(FILE *f, ArgDescriptor *ad)
1495 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1496 if(colorVariable[(int)ad->argLoc])
1497 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1501 SaveBoardSize(FILE *f, char *name, void *addr)
1502 { // wrapper to shield back-end from BoardSize & sizeInfo
1503 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1507 ParseCommPortSettings(char *s)
1508 { // no such option in XBoard (yet)
1511 extern Widget engineOutputShell;
1512 extern Widget tagsShell, editTagsShell;
1514 GetActualPlacement(Widget wg, WindowPlacement *wp)
1524 XtSetArg(args[i], XtNx, &x); i++;
1525 XtSetArg(args[i], XtNy, &y); i++;
1526 XtSetArg(args[i], XtNwidth, &w); i++;
1527 XtSetArg(args[i], XtNheight, &h); i++;
1528 XtGetValues(wg, args, i);
1537 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1538 // In XBoard this will have to wait until awareness of window parameters is implemented
1539 GetActualPlacement(shellWidget, &wpMain);
1540 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1541 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1542 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1543 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1544 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1545 else GetActualPlacement(editShell, &wpComment);
1546 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1547 else GetActualPlacement(editTagsShell, &wpTags);
1551 PrintCommPortSettings(FILE *f, char *name)
1552 { // This option does not exist in XBoard
1556 MySearchPath(char *installDir, char *name, char *fullname)
1557 { // just append installDir and name. Perhaps ExpandPath should be used here?
1558 name = ExpandPathName(name);
1559 if(name && name[0] == '/')
1560 safeStrCpy(fullname, name, MSG_SIZ );
1562 sprintf(fullname, "%s%c%s", installDir, '/', name);
1568 MyGetFullPathName(char *name, char *fullname)
1569 { // should use ExpandPath?
1570 name = ExpandPathName(name);
1571 safeStrCpy(fullname, name, MSG_SIZ );
1576 EnsureOnScreen(int *x, int *y, int minX, int minY)
1583 { // [HGM] args: allows testing if main window is realized from back-end
1584 return xBoardWindow != 0;
1588 PopUpStartupDialog()
1589 { // start menu not implemented in XBoard
1593 ConvertToLine(int argc, char **argv)
1595 static char line[128*1024], buf[1024];
1599 for(i=1; i<argc; i++)
1601 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1602 && argv[i][0] != '{' )
1603 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1605 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1606 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1609 line[strlen(line)-1] = NULLCHAR;
1613 //--------------------------------------------------------------------------------------------
1615 extern Boolean twoBoards, partnerUp;
1618 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1620 #define BoardSize int
1621 void InitDrawingSizes(BoardSize boardSize, int flags)
1622 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1623 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1625 XtGeometryResult gres;
1628 if(!formWidget) return;
1631 * Enable shell resizing.
1633 shellArgs[0].value = (XtArgVal) &w;
1634 shellArgs[1].value = (XtArgVal) &h;
1635 XtGetValues(shellWidget, shellArgs, 2);
1637 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1638 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1639 XtSetValues(shellWidget, &shellArgs[2], 4);
1641 XtSetArg(args[0], XtNdefaultDistance, &sep);
1642 XtGetValues(formWidget, args, 1);
1644 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1645 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1647 hOffset = boardWidth + 10;
1648 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1649 secondSegments[i] = gridSegments[i];
1650 secondSegments[i].x1 += hOffset;
1651 secondSegments[i].x2 += hOffset;
1654 XtSetArg(args[0], XtNwidth, boardWidth);
1655 XtSetArg(args[1], XtNheight, boardHeight);
1656 XtSetValues(boardWidget, args, 2);
1658 timerWidth = (boardWidth - sep) / 2;
1659 XtSetArg(args[0], XtNwidth, timerWidth);
1660 XtSetValues(whiteTimerWidget, args, 1);
1661 XtSetValues(blackTimerWidget, args, 1);
1663 XawFormDoLayout(formWidget, False);
1665 if (appData.titleInWindow) {
1667 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1668 XtSetArg(args[i], XtNheight, &h); i++;
1669 XtGetValues(titleWidget, args, i);
1671 w = boardWidth - 2*bor;
1673 XtSetArg(args[0], XtNwidth, &w);
1674 XtGetValues(menuBarWidget, args, 1);
1675 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1678 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1679 if (gres != XtGeometryYes && appData.debugMode) {
1681 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1682 programName, gres, w, h, wr, hr);
1686 XawFormDoLayout(formWidget, True);
1689 * Inhibit shell resizing.
1691 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1692 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1693 shellArgs[4].value = shellArgs[2].value = w;
1694 shellArgs[5].value = shellArgs[3].value = h;
1695 XtSetValues(shellWidget, &shellArgs[0], 6);
1697 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1700 for(i=0; i<4; i++) {
1702 for(p=0; p<=(int)WhiteKing; p++)
1703 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1704 if(gameInfo.variant == VariantShogi) {
1705 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1706 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1707 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1708 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1709 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1712 if(gameInfo.variant == VariantGothic) {
1713 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1716 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1717 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1718 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1721 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1722 for(p=0; p<=(int)WhiteKing; p++)
1723 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1724 if(gameInfo.variant == VariantShogi) {
1725 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1726 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1727 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1728 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1729 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1732 if(gameInfo.variant == VariantGothic) {
1733 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1736 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1737 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1738 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1743 for(i=0; i<2; i++) {
1745 for(p=0; p<=(int)WhiteKing; p++)
1746 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1747 if(gameInfo.variant == VariantShogi) {
1748 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1749 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1750 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1751 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1752 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1755 if(gameInfo.variant == VariantGothic) {
1756 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1759 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1760 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1761 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1776 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1777 XSetWindowAttributes window_attributes;
1779 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1780 XrmValue vFrom, vTo;
1781 XtGeometryResult gres;
1784 int forceMono = False;
1786 srandom(time(0)); // [HGM] book: make random truly random
1788 setbuf(stdout, NULL);
1789 setbuf(stderr, NULL);
1792 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1793 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1797 programName = strrchr(argv[0], '/');
1798 if (programName == NULL)
1799 programName = argv[0];
1804 XtSetLanguageProc(NULL, NULL, NULL);
1805 bindtextdomain(PACKAGE, LOCALEDIR);
1806 textdomain(PACKAGE);
1810 XtAppInitialize(&appContext, "XBoard", shellOptions,
1811 XtNumber(shellOptions),
1812 &argc, argv, xboardResources, NULL, 0);
1813 appData.boardSize = "";
1814 InitAppData(ConvertToLine(argc, argv));
1816 if (p == NULL) p = "/tmp";
1817 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1818 gameCopyFilename = (char*) malloc(i);
1819 gamePasteFilename = (char*) malloc(i);
1820 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1821 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1823 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1824 clientResources, XtNumber(clientResources),
1827 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1828 static char buf[MSG_SIZ];
1829 EscapeExpand(buf, appData.initString);
1830 appData.initString = strdup(buf);
1831 EscapeExpand(buf, appData.secondInitString);
1832 appData.secondInitString = strdup(buf);
1833 EscapeExpand(buf, appData.firstComputerString);
1834 appData.firstComputerString = strdup(buf);
1835 EscapeExpand(buf, appData.secondComputerString);
1836 appData.secondComputerString = strdup(buf);
1839 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1842 if (chdir(chessDir) != 0) {
1843 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1849 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1850 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1851 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1852 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1855 setbuf(debugFP, NULL);
1858 /* [HGM,HR] make sure board size is acceptable */
1859 if(appData.NrFiles > BOARD_FILES ||
1860 appData.NrRanks > BOARD_RANKS )
1861 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1864 /* This feature does not work; animation needs a rewrite */
1865 appData.highlightDragging = FALSE;
1869 xDisplay = XtDisplay(shellWidget);
1870 xScreen = DefaultScreen(xDisplay);
1871 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1873 gameInfo.variant = StringToVariant(appData.variant);
1874 InitPosition(FALSE);
1877 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1879 if (isdigit(appData.boardSize[0])) {
1880 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1881 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1882 &fontPxlSize, &smallLayout, &tinyLayout);
1884 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1885 programName, appData.boardSize);
1889 /* Find some defaults; use the nearest known size */
1890 SizeDefaults *szd, *nearest;
1891 int distance = 99999;
1892 nearest = szd = sizeDefaults;
1893 while (szd->name != NULL) {
1894 if (abs(szd->squareSize - squareSize) < distance) {
1896 distance = abs(szd->squareSize - squareSize);
1897 if (distance == 0) break;
1901 if (i < 2) lineGap = nearest->lineGap;
1902 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1903 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1904 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1905 if (i < 6) smallLayout = nearest->smallLayout;
1906 if (i < 7) tinyLayout = nearest->tinyLayout;
1909 SizeDefaults *szd = sizeDefaults;
1910 if (*appData.boardSize == NULLCHAR) {
1911 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1912 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1915 if (szd->name == NULL) szd--;
1916 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1918 while (szd->name != NULL &&
1919 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1920 if (szd->name == NULL) {
1921 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1922 programName, appData.boardSize);
1926 squareSize = szd->squareSize;
1927 lineGap = szd->lineGap;
1928 clockFontPxlSize = szd->clockFontPxlSize;
1929 coordFontPxlSize = szd->coordFontPxlSize;
1930 fontPxlSize = szd->fontPxlSize;
1931 smallLayout = szd->smallLayout;
1932 tinyLayout = szd->tinyLayout;
1933 // [HGM] font: use defaults from settings file if available and not overruled
1935 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1936 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1937 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1938 appData.font = fontTable[MESSAGE_FONT][squareSize];
1939 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1940 appData.coordFont = fontTable[COORD_FONT][squareSize];
1942 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1943 if (strlen(appData.pixmapDirectory) > 0) {
1944 p = ExpandPathName(appData.pixmapDirectory);
1946 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1947 appData.pixmapDirectory);
1950 if (appData.debugMode) {
1951 fprintf(stderr, _("\
1952 XBoard square size (hint): %d\n\
1953 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1955 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1956 if (appData.debugMode) {
1957 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1960 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1962 /* [HR] height treated separately (hacked) */
1963 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1964 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1965 if (appData.showJail == 1) {
1966 /* Jail on top and bottom */
1967 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1968 XtSetArg(boardArgs[2], XtNheight,
1969 boardHeight + 2*(lineGap + squareSize));
1970 } else if (appData.showJail == 2) {
1972 XtSetArg(boardArgs[1], XtNwidth,
1973 boardWidth + 2*(lineGap + squareSize));
1974 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1977 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1978 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1982 * Determine what fonts to use.
1984 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1985 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1986 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1987 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1988 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1989 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1990 appData.font = FindFont(appData.font, fontPxlSize);
1991 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1992 countFontStruct = XQueryFont(xDisplay, countFontID);
1993 // appData.font = FindFont(appData.font, fontPxlSize);
1995 xdb = XtDatabase(xDisplay);
1996 XrmPutStringResource(&xdb, "*font", appData.font);
1999 * Detect if there are not enough colors available and adapt.
2001 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2002 appData.monoMode = True;
2005 if (!appData.monoMode) {
2006 vFrom.addr = (caddr_t) appData.lightSquareColor;
2007 vFrom.size = strlen(appData.lightSquareColor);
2008 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2009 if (vTo.addr == NULL) {
2010 appData.monoMode = True;
2013 lightSquareColor = *(Pixel *) vTo.addr;
2016 if (!appData.monoMode) {
2017 vFrom.addr = (caddr_t) appData.darkSquareColor;
2018 vFrom.size = strlen(appData.darkSquareColor);
2019 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2020 if (vTo.addr == NULL) {
2021 appData.monoMode = True;
2024 darkSquareColor = *(Pixel *) vTo.addr;
2027 if (!appData.monoMode) {
2028 vFrom.addr = (caddr_t) appData.whitePieceColor;
2029 vFrom.size = strlen(appData.whitePieceColor);
2030 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2031 if (vTo.addr == NULL) {
2032 appData.monoMode = True;
2035 whitePieceColor = *(Pixel *) vTo.addr;
2038 if (!appData.monoMode) {
2039 vFrom.addr = (caddr_t) appData.blackPieceColor;
2040 vFrom.size = strlen(appData.blackPieceColor);
2041 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2042 if (vTo.addr == NULL) {
2043 appData.monoMode = True;
2046 blackPieceColor = *(Pixel *) vTo.addr;
2050 if (!appData.monoMode) {
2051 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2052 vFrom.size = strlen(appData.highlightSquareColor);
2053 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2054 if (vTo.addr == NULL) {
2055 appData.monoMode = True;
2058 highlightSquareColor = *(Pixel *) vTo.addr;
2062 if (!appData.monoMode) {
2063 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2064 vFrom.size = strlen(appData.premoveHighlightColor);
2065 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2066 if (vTo.addr == NULL) {
2067 appData.monoMode = True;
2070 premoveHighlightColor = *(Pixel *) vTo.addr;
2075 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2078 if (appData.bitmapDirectory == NULL ||
2079 appData.bitmapDirectory[0] == NULLCHAR)
2080 appData.bitmapDirectory = DEF_BITMAP_DIR;
2083 if (appData.lowTimeWarning && !appData.monoMode) {
2084 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2085 vFrom.size = strlen(appData.lowTimeWarningColor);
2086 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2087 if (vTo.addr == NULL)
2088 appData.monoMode = True;
2090 lowTimeWarningColor = *(Pixel *) vTo.addr;
2093 if (appData.monoMode && appData.debugMode) {
2094 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2095 (unsigned long) XWhitePixel(xDisplay, xScreen),
2096 (unsigned long) XBlackPixel(xDisplay, xScreen));
2099 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2100 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2101 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2102 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2103 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2104 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2105 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2106 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2107 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2108 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2110 if (appData.colorize) {
2112 _("%s: can't parse color names; disabling colorization\n"),
2115 appData.colorize = FALSE;
2117 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2118 textColors[ColorNone].attr = 0;
2120 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2126 layoutName = "tinyLayout";
2127 } else if (smallLayout) {
2128 layoutName = "smallLayout";
2130 layoutName = "normalLayout";
2132 /* Outer layoutWidget is there only to provide a name for use in
2133 resources that depend on the layout style */
2135 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2136 layoutArgs, XtNumber(layoutArgs));
2138 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2139 formArgs, XtNumber(formArgs));
2140 XtSetArg(args[0], XtNdefaultDistance, &sep);
2141 XtGetValues(formWidget, args, 1);
2144 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2145 XtSetArg(args[0], XtNtop, XtChainTop);
2146 XtSetArg(args[1], XtNbottom, XtChainTop);
2147 XtSetArg(args[2], XtNright, XtChainLeft);
2148 XtSetValues(menuBarWidget, args, 3);
2150 widgetList[j++] = whiteTimerWidget =
2151 XtCreateWidget("whiteTime", labelWidgetClass,
2152 formWidget, timerArgs, XtNumber(timerArgs));
2153 XtSetArg(args[0], XtNfont, clockFontStruct);
2154 XtSetArg(args[1], XtNtop, XtChainTop);
2155 XtSetArg(args[2], XtNbottom, XtChainTop);
2156 XtSetValues(whiteTimerWidget, args, 3);
2158 widgetList[j++] = blackTimerWidget =
2159 XtCreateWidget("blackTime", labelWidgetClass,
2160 formWidget, timerArgs, XtNumber(timerArgs));
2161 XtSetArg(args[0], XtNfont, clockFontStruct);
2162 XtSetArg(args[1], XtNtop, XtChainTop);
2163 XtSetArg(args[2], XtNbottom, XtChainTop);
2164 XtSetValues(blackTimerWidget, args, 3);
2166 if (appData.titleInWindow) {
2167 widgetList[j++] = titleWidget =
2168 XtCreateWidget("title", labelWidgetClass, formWidget,
2169 titleArgs, XtNumber(titleArgs));
2170 XtSetArg(args[0], XtNtop, XtChainTop);
2171 XtSetArg(args[1], XtNbottom, XtChainTop);
2172 XtSetValues(titleWidget, args, 2);
2175 if (appData.showButtonBar) {
2176 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2177 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2178 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2179 XtSetArg(args[2], XtNtop, XtChainTop);
2180 XtSetArg(args[3], XtNbottom, XtChainTop);
2181 XtSetValues(buttonBarWidget, args, 4);
2184 widgetList[j++] = messageWidget =
2185 XtCreateWidget("message", labelWidgetClass, formWidget,
2186 messageArgs, XtNumber(messageArgs));
2187 XtSetArg(args[0], XtNtop, XtChainTop);
2188 XtSetArg(args[1], XtNbottom, XtChainTop);
2189 XtSetValues(messageWidget, args, 2);
2191 widgetList[j++] = boardWidget =
2192 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2193 XtNumber(boardArgs));
2195 XtManageChildren(widgetList, j);
2197 timerWidth = (boardWidth - sep) / 2;
2198 XtSetArg(args[0], XtNwidth, timerWidth);
2199 XtSetValues(whiteTimerWidget, args, 1);
2200 XtSetValues(blackTimerWidget, args, 1);
2202 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2203 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2204 XtGetValues(whiteTimerWidget, args, 2);
2206 if (appData.showButtonBar) {
2207 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2208 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2209 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2213 * formWidget uses these constraints but they are stored
2217 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2218 XtSetValues(menuBarWidget, args, i);
2219 if (appData.titleInWindow) {
2222 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2223 XtSetValues(whiteTimerWidget, args, i);
2225 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2226 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2227 XtSetValues(blackTimerWidget, args, i);
2229 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2230 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2231 XtSetValues(titleWidget, args, i);
2233 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2234 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2235 XtSetValues(messageWidget, args, i);
2236 if (appData.showButtonBar) {
2238 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2239 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2240 XtSetValues(buttonBarWidget, args, i);
2244 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2245 XtSetValues(whiteTimerWidget, args, i);
2247 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2248 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2249 XtSetValues(blackTimerWidget, args, i);
2251 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2252 XtSetValues(titleWidget, args, i);
2254 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2255 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2256 XtSetValues(messageWidget, args, i);
2257 if (appData.showButtonBar) {
2259 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2260 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2261 XtSetValues(buttonBarWidget, args, i);
2266 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2267 XtSetValues(whiteTimerWidget, args, i);
2269 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2270 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2271 XtSetValues(blackTimerWidget, args, i);
2273 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2274 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2275 XtSetValues(messageWidget, args, i);
2276 if (appData.showButtonBar) {
2278 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2279 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2280 XtSetValues(buttonBarWidget, args, i);
2284 XtSetArg(args[0], XtNfromVert, messageWidget);
2285 XtSetArg(args[1], XtNtop, XtChainTop);
2286 XtSetArg(args[2], XtNbottom, XtChainBottom);
2287 XtSetArg(args[3], XtNleft, XtChainLeft);
2288 XtSetArg(args[4], XtNright, XtChainRight);
2289 XtSetValues(boardWidget, args, 5);
2291 XtRealizeWidget(shellWidget);
2294 XtSetArg(args[0], XtNx, wpMain.x);
2295 XtSetArg(args[1], XtNy, wpMain.y);
2296 XtSetValues(shellWidget, args, 2);
2300 * Correct the width of the message and title widgets.
2301 * It is not known why some systems need the extra fudge term.
2302 * The value "2" is probably larger than needed.
2304 XawFormDoLayout(formWidget, False);
2306 #define WIDTH_FUDGE 2
2308 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2309 XtSetArg(args[i], XtNheight, &h); i++;
2310 XtGetValues(messageWidget, args, i);
2311 if (appData.showButtonBar) {
2313 XtSetArg(args[i], XtNwidth, &w); i++;
2314 XtGetValues(buttonBarWidget, args, i);
2315 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2317 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2320 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2321 if (gres != XtGeometryYes && appData.debugMode) {
2322 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2323 programName, gres, w, h, wr, hr);
2326 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2327 /* The size used for the child widget in layout lags one resize behind
2328 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2330 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2331 if (gres != XtGeometryYes && appData.debugMode) {
2332 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2333 programName, gres, w, h, wr, hr);
2336 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2337 XtSetArg(args[1], XtNright, XtChainRight);
2338 XtSetValues(messageWidget, args, 2);
2340 if (appData.titleInWindow) {
2342 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2343 XtSetArg(args[i], XtNheight, &h); i++;
2344 XtGetValues(titleWidget, args, i);
2346 w = boardWidth - 2*bor;
2348 XtSetArg(args[0], XtNwidth, &w);
2349 XtGetValues(menuBarWidget, args, 1);
2350 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2353 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2354 if (gres != XtGeometryYes && appData.debugMode) {
2356 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2357 programName, gres, w, h, wr, hr);
2360 XawFormDoLayout(formWidget, True);
2362 xBoardWindow = XtWindow(boardWidget);
2364 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2365 // not need to go into InitDrawingSizes().
2369 * Create X checkmark bitmap and initialize option menu checks.
2371 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2372 checkmark_bits, checkmark_width, checkmark_height);
2373 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2374 if (appData.alwaysPromoteToQueen) {
2375 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2378 if (appData.animateDragging) {
2379 XtSetValues(XtNameToWidget(menuBarWidget,
2380 "menuOptions.Animate Dragging"),
2383 if (appData.animate) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2387 if (appData.autoComment) {
2388 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2391 if (appData.autoCallFlag) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2395 if (appData.autoFlipView) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2399 if (appData.autoObserve) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2403 if (appData.autoRaiseBoard) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,
2405 "menuOptions.Auto Raise Board"), args, 1);
2407 if (appData.autoSaveGames) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2411 if (appData.saveGameFile[0] != NULLCHAR) {
2412 /* Can't turn this off from menu */
2413 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2415 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2419 if (appData.blindfold) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,
2421 "menuOptions.Blindfold"), args, 1);
2423 if (appData.flashCount > 0) {
2424 XtSetValues(XtNameToWidget(menuBarWidget,
2425 "menuOptions.Flash Moves"),
2428 if (appData.getMoveList) {
2429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2433 if (appData.highlightDragging) {
2434 XtSetValues(XtNameToWidget(menuBarWidget,
2435 "menuOptions.Highlight Dragging"),
2439 if (appData.highlightLastMove) {
2440 XtSetValues(XtNameToWidget(menuBarWidget,
2441 "menuOptions.Highlight Last Move"),
2444 if (appData.icsAlarm) {
2445 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2448 if (appData.ringBellAfterMoves) {
2449 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2452 if (appData.oldSaveStyle) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Old Save Style"), args, 1);
2456 if (appData.periodicUpdates) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Periodic Updates"), args, 1);
2460 if (appData.ponderNextMove) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Ponder Next Move"), args, 1);
2464 if (appData.popupExitMessage) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Popup Exit Message"), args, 1);
2468 if (appData.popupMoveErrors) {
2469 XtSetValues(XtNameToWidget(menuBarWidget,
2470 "menuOptions.Popup Move Errors"), args, 1);
2472 if (appData.premove) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,
2474 "menuOptions.Premove"), args, 1);
2476 if (appData.quietPlay) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Quiet Play"), args, 1);
2480 if (appData.showCoords) {
2481 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2484 if (appData.hideThinkingFromHuman) {
2485 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2488 if (appData.testLegality) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2492 if (saveSettingsOnExit) {
2493 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2500 ReadBitmap(&wIconPixmap, "icon_white.bm",
2501 icon_white_bits, icon_white_width, icon_white_height);
2502 ReadBitmap(&bIconPixmap, "icon_black.bm",
2503 icon_black_bits, icon_black_width, icon_black_height);
2504 iconPixmap = wIconPixmap;
2506 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2507 XtSetValues(shellWidget, args, i);
2510 * Create a cursor for the board widget.
2512 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2513 XChangeWindowAttributes(xDisplay, xBoardWindow,
2514 CWCursor, &window_attributes);
2517 * Inhibit shell resizing.
2519 shellArgs[0].value = (XtArgVal) &w;
2520 shellArgs[1].value = (XtArgVal) &h;
2521 XtGetValues(shellWidget, shellArgs, 2);
2522 shellArgs[4].value = shellArgs[2].value = w;
2523 shellArgs[5].value = shellArgs[3].value = h;
2524 XtSetValues(shellWidget, &shellArgs[2], 4);
2525 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2526 marginH = h - boardHeight;
2528 CatchDeleteWindow(shellWidget, "QuitProc");
2533 if (appData.bitmapDirectory[0] != NULLCHAR) {
2537 CreateXPMBoard(appData.liteBackTextureFile, 1);
2538 CreateXPMBoard(appData.darkBackTextureFile, 0);
2542 /* Create regular pieces */
2543 if (!useImages) CreatePieces();
2548 if (appData.animate || appData.animateDragging)
2551 XtAugmentTranslations(formWidget,
2552 XtParseTranslationTable(globalTranslations));
2553 XtAugmentTranslations(boardWidget,
2554 XtParseTranslationTable(boardTranslations));
2555 XtAugmentTranslations(whiteTimerWidget,
2556 XtParseTranslationTable(whiteTranslations));
2557 XtAugmentTranslations(blackTimerWidget,
2558 XtParseTranslationTable(blackTranslations));
2560 /* Why is the following needed on some versions of X instead
2561 * of a translation? */
2562 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2563 (XtEventHandler) EventProc, NULL);
2566 /* [AS] Restore layout */
2567 if( wpMoveHistory.visible ) {
2571 if( wpEvalGraph.visible )
2576 if( wpEngineOutput.visible ) {
2577 EngineOutputPopUp();
2582 if (errorExitStatus == -1) {
2583 if (appData.icsActive) {
2584 /* We now wait until we see "login:" from the ICS before
2585 sending the logon script (problems with timestamp otherwise) */
2586 /*ICSInitScript();*/
2587 if (appData.icsInputBox) ICSInputBoxPopUp();
2591 signal(SIGWINCH, TermSizeSigHandler);
2593 signal(SIGINT, IntSigHandler);
2594 signal(SIGTERM, IntSigHandler);
2595 if (*appData.cmailGameName != NULLCHAR) {
2596 signal(SIGUSR1, CmailSigHandler);
2599 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2601 XtSetKeyboardFocus(shellWidget, formWidget);
2603 XtAppMainLoop(appContext);
2604 if (appData.debugMode) fclose(debugFP); // [DM] debug
2611 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2612 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2614 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2615 unlink(gameCopyFilename);
2616 unlink(gamePasteFilename);
2619 RETSIGTYPE TermSizeSigHandler(int sig)
2632 CmailSigHandler(sig)
2638 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2640 /* Activate call-back function CmailSigHandlerCallBack() */
2641 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2643 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2647 CmailSigHandlerCallBack(isr, closure, message, count, error)
2655 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2657 /**** end signal code ****/
2663 /* try to open the icsLogon script, either in the location given
2664 * or in the users HOME directory
2671 f = fopen(appData.icsLogon, "r");
2674 homedir = getenv("HOME");
2675 if (homedir != NULL)
2677 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2678 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2679 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2680 f = fopen(buf, "r");
2685 ProcessICSInitScript(f);
2687 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2696 EditCommentPopDown();
2711 if (!menuBarWidget) return;
2712 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2714 DisplayError("menuStep.Revert", 0);
2716 XtSetSensitive(w, !grey);
2718 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2720 DisplayError("menuStep.Annotate", 0);
2722 XtSetSensitive(w, !grey);
2727 SetMenuEnables(enab)
2731 if (!menuBarWidget) return;
2732 while (enab->name != NULL) {
2733 w = XtNameToWidget(menuBarWidget, enab->name);
2735 DisplayError(enab->name, 0);
2737 XtSetSensitive(w, enab->value);
2743 Enables icsEnables[] = {
2744 { "menuFile.Mail Move", False },
2745 { "menuFile.Reload CMail Message", False },
2746 { "menuMode.Machine Black", False },
2747 { "menuMode.Machine White", False },
2748 { "menuMode.Analysis Mode", False },
2749 { "menuMode.Analyze File", False },
2750 { "menuMode.Two Machines", False },
2752 { "menuHelp.Hint", False },
2753 { "menuHelp.Book", False },
2754 { "menuStep.Move Now", False },
2755 { "menuOptions.Periodic Updates", False },
2756 { "menuOptions.Hide Thinking", False },
2757 { "menuOptions.Ponder Next Move", False },
2759 { "menuStep.Annotate", False },
2763 Enables ncpEnables[] = {
2764 { "menuFile.Mail Move", False },
2765 { "menuFile.Reload CMail Message", False },
2766 { "menuMode.Machine White", False },
2767 { "menuMode.Machine Black", False },
2768 { "menuMode.Analysis Mode", False },
2769 { "menuMode.Analyze File", False },
2770 { "menuMode.Two Machines", False },
2771 { "menuMode.ICS Client", False },
2772 { "menuMode.ICS Input Box", False },
2773 { "Action", False },
2774 { "menuStep.Revert", False },
2775 { "menuStep.Annotate", False },
2776 { "menuStep.Move Now", False },
2777 { "menuStep.Retract Move", False },
2778 { "menuOptions.Auto Comment", False },
2779 { "menuOptions.Auto Flag", False },
2780 { "menuOptions.Auto Flip View", False },
2781 { "menuOptions.Auto Observe", False },
2782 { "menuOptions.Auto Raise Board", False },
2783 { "menuOptions.Get Move List", False },
2784 { "menuOptions.ICS Alarm", False },
2785 { "menuOptions.Move Sound", False },
2786 { "menuOptions.Quiet Play", False },
2787 { "menuOptions.Hide Thinking", False },
2788 { "menuOptions.Periodic Updates", False },
2789 { "menuOptions.Ponder Next Move", False },
2790 { "menuHelp.Hint", False },
2791 { "menuHelp.Book", False },
2795 Enables gnuEnables[] = {
2796 { "menuMode.ICS Client", False },
2797 { "menuMode.ICS Input Box", False },
2798 { "menuAction.Accept", False },
2799 { "menuAction.Decline", False },
2800 { "menuAction.Rematch", False },
2801 { "menuAction.Adjourn", False },
2802 { "menuAction.Stop Examining", False },
2803 { "menuAction.Stop Observing", False },
2804 { "menuAction.Upload to Examine", False },
2805 { "menuStep.Revert", False },
2806 { "menuStep.Annotate", False },
2807 { "menuOptions.Auto Comment", False },
2808 { "menuOptions.Auto Observe", False },
2809 { "menuOptions.Auto Raise Board", False },
2810 { "menuOptions.Get Move List", False },
2811 { "menuOptions.Premove", False },
2812 { "menuOptions.Quiet Play", False },
2814 /* The next two options rely on SetCmailMode being called *after* */
2815 /* SetGNUMode so that when GNU is being used to give hints these */
2816 /* menu options are still available */
2818 { "menuFile.Mail Move", False },
2819 { "menuFile.Reload CMail Message", False },
2823 Enables cmailEnables[] = {
2825 { "menuAction.Call Flag", False },
2826 { "menuAction.Draw", True },
2827 { "menuAction.Adjourn", False },
2828 { "menuAction.Abort", False },
2829 { "menuAction.Stop Observing", False },
2830 { "menuAction.Stop Examining", False },
2831 { "menuFile.Mail Move", True },
2832 { "menuFile.Reload CMail Message", True },
2836 Enables trainingOnEnables[] = {
2837 { "menuMode.Edit Comment", False },
2838 { "menuMode.Pause", False },
2839 { "menuStep.Forward", False },
2840 { "menuStep.Backward", False },
2841 { "menuStep.Forward to End", False },
2842 { "menuStep.Back to Start", False },
2843 { "menuStep.Move Now", False },
2844 { "menuStep.Truncate Game", False },
2848 Enables trainingOffEnables[] = {
2849 { "menuMode.Edit Comment", True },
2850 { "menuMode.Pause", True },
2851 { "menuStep.Forward", True },
2852 { "menuStep.Backward", True },
2853 { "menuStep.Forward to End", True },
2854 { "menuStep.Back to Start", True },
2855 { "menuStep.Move Now", True },
2856 { "menuStep.Truncate Game", True },
2860 Enables machineThinkingEnables[] = {
2861 { "menuFile.Load Game", False },
2862 { "menuFile.Load Next Game", False },
2863 { "menuFile.Load Previous Game", False },
2864 { "menuFile.Reload Same Game", False },
2865 { "menuFile.Paste Game", False },
2866 { "menuFile.Load Position", False },
2867 { "menuFile.Load Next Position", False },
2868 { "menuFile.Load Previous Position", False },
2869 { "menuFile.Reload Same Position", False },
2870 { "menuFile.Paste Position", False },
2871 { "menuMode.Machine White", False },
2872 { "menuMode.Machine Black", False },
2873 { "menuMode.Two Machines", False },
2874 { "menuStep.Retract Move", False },
2878 Enables userThinkingEnables[] = {
2879 { "menuFile.Load Game", True },
2880 { "menuFile.Load Next Game", True },
2881 { "menuFile.Load Previous Game", True },
2882 { "menuFile.Reload Same Game", True },
2883 { "menuFile.Paste Game", True },
2884 { "menuFile.Load Position", True },
2885 { "menuFile.Load Next Position", True },
2886 { "menuFile.Load Previous Position", True },
2887 { "menuFile.Reload Same Position", True },
2888 { "menuFile.Paste Position", True },
2889 { "menuMode.Machine White", True },
2890 { "menuMode.Machine Black", True },
2891 { "menuMode.Two Machines", True },
2892 { "menuStep.Retract Move", True },
2898 SetMenuEnables(icsEnables);
2901 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2902 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2909 SetMenuEnables(ncpEnables);
2915 SetMenuEnables(gnuEnables);
2921 SetMenuEnables(cmailEnables);
2927 SetMenuEnables(trainingOnEnables);
2928 if (appData.showButtonBar) {
2929 XtSetSensitive(buttonBarWidget, False);
2935 SetTrainingModeOff()
2937 SetMenuEnables(trainingOffEnables);
2938 if (appData.showButtonBar) {
2939 XtSetSensitive(buttonBarWidget, True);
2944 SetUserThinkingEnables()
2946 if (appData.noChessProgram) return;
2947 SetMenuEnables(userThinkingEnables);
2951 SetMachineThinkingEnables()
2953 if (appData.noChessProgram) return;
2954 SetMenuEnables(machineThinkingEnables);
2956 case MachinePlaysBlack:
2957 case MachinePlaysWhite:
2958 case TwoMachinesPlay:
2959 XtSetSensitive(XtNameToWidget(menuBarWidget,
2960 ModeToWidgetName(gameMode)), True);
2967 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2968 #define HISTORY_SIZE 64
\r
2969 static char *history[HISTORY_SIZE];
\r
2970 int histIn = 0, histP = 0;
\r
2973 SaveInHistory(char *cmd)
\r
2975 if (history[histIn] != NULL) {
\r
2976 free(history[histIn]);
\r
2977 history[histIn] = NULL;
\r
2979 if (*cmd == NULLCHAR) return;
\r
2980 history[histIn] = StrSave(cmd);
\r
2981 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2982 if (history[histIn] != NULL) {
\r
2983 free(history[histIn]);
\r
2984 history[histIn] = NULL;
\r
2990 PrevInHistory(char *cmd)
\r
2993 if (histP == histIn) {
\r
2994 if (history[histIn] != NULL) free(history[histIn]);
\r
2995 history[histIn] = StrSave(cmd);
\r
2997 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
2998 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3000 return history[histP];
\r
3006 if (histP == histIn) return NULL;
\r
3007 histP = (histP + 1) % HISTORY_SIZE;
\r
3008 return history[histP];
\r
3010 // end of borrowed code
\r
3012 #define Abs(n) ((n)<0 ? -(n) : (n))
3015 * Find a font that matches "pattern" that is as close as
3016 * possible to the targetPxlSize. Prefer fonts that are k
3017 * pixels smaller to fonts that are k pixels larger. The
3018 * pattern must be in the X Consortium standard format,
3019 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3020 * The return value should be freed with XtFree when no
3024 FindFont(pattern, targetPxlSize)
3028 char **fonts, *p, *best, *scalable, *scalableTail;
3029 int i, j, nfonts, minerr, err, pxlSize;
3032 char **missing_list;
3034 char *def_string, *base_fnt_lst, strInt[3];
3036 XFontStruct **fnt_list;
3038 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3039 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3040 p = strstr(pattern, "--");
3041 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3042 strcat(base_fnt_lst, strInt);
3043 strcat(base_fnt_lst, strchr(p + 2, '-'));
3045 if ((fntSet = XCreateFontSet(xDisplay,
3049 &def_string)) == NULL) {
3051 fprintf(stderr, _("Unable to create font set.\n"));
3055 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3057 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3059 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3060 programName, pattern);
3068 for (i=0; i<nfonts; i++) {
3071 if (*p != '-') continue;
3073 if (*p == NULLCHAR) break;
3074 if (*p++ == '-') j++;
3076 if (j < 7) continue;
3079 scalable = fonts[i];
3082 err = pxlSize - targetPxlSize;
3083 if (Abs(err) < Abs(minerr) ||
3084 (minerr > 0 && err < 0 && -err == minerr)) {
3090 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3091 /* If the error is too big and there is a scalable font,
3092 use the scalable font. */
3093 int headlen = scalableTail - scalable;
3094 p = (char *) XtMalloc(strlen(scalable) + 10);
3095 while (isdigit(*scalableTail)) scalableTail++;
3096 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3098 p = (char *) XtMalloc(strlen(best) + 2);
3099 safeStrCpy(p, best, strlen(best)+1 );
3101 if (appData.debugMode) {
3102 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3103 pattern, targetPxlSize, p);
3106 if (missing_count > 0)
3107 XFreeStringList(missing_list);
3108 XFreeFontSet(xDisplay, fntSet);
3110 XFreeFontNames(fonts);
3117 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3118 | GCBackground | GCFunction | GCPlaneMask;
3119 XGCValues gc_values;
3122 gc_values.plane_mask = AllPlanes;
3123 gc_values.line_width = lineGap;
3124 gc_values.line_style = LineSolid;
3125 gc_values.function = GXcopy;
3127 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3128 gc_values.background = XBlackPixel(xDisplay, xScreen);
3129 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3131 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3132 gc_values.background = XWhitePixel(xDisplay, xScreen);
3133 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3134 XSetFont(xDisplay, coordGC, coordFontID);
3136 // [HGM] make font for holdings counts (white on black0
3137 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3138 gc_values.background = XBlackPixel(xDisplay, xScreen);
3139 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3140 XSetFont(xDisplay, countGC, countFontID);
3142 if (appData.monoMode) {
3143 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3144 gc_values.background = XWhitePixel(xDisplay, xScreen);
3145 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3147 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3148 gc_values.background = XBlackPixel(xDisplay, xScreen);
3149 lightSquareGC = wbPieceGC
3150 = XtGetGC(shellWidget, value_mask, &gc_values);
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XWhitePixel(xDisplay, xScreen);
3154 darkSquareGC = bwPieceGC
3155 = XtGetGC(shellWidget, value_mask, &gc_values);
3157 if (DefaultDepth(xDisplay, xScreen) == 1) {
3158 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3159 gc_values.function = GXcopyInverted;
3160 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 gc_values.function = GXcopy;
3162 if (XBlackPixel(xDisplay, xScreen) == 1) {
3163 bwPieceGC = darkSquareGC;
3164 wbPieceGC = copyInvertedGC;
3166 bwPieceGC = copyInvertedGC;
3167 wbPieceGC = lightSquareGC;
3171 gc_values.foreground = highlightSquareColor;
3172 gc_values.background = highlightSquareColor;
3173 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3175 gc_values.foreground = premoveHighlightColor;
3176 gc_values.background = premoveHighlightColor;
3177 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3179 gc_values.foreground = lightSquareColor;
3180 gc_values.background = darkSquareColor;
3181 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3183 gc_values.foreground = darkSquareColor;
3184 gc_values.background = lightSquareColor;
3185 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3187 gc_values.foreground = jailSquareColor;
3188 gc_values.background = jailSquareColor;
3189 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3191 gc_values.foreground = whitePieceColor;
3192 gc_values.background = darkSquareColor;
3193 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3195 gc_values.foreground = whitePieceColor;
3196 gc_values.background = lightSquareColor;
3197 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3199 gc_values.foreground = whitePieceColor;
3200 gc_values.background = jailSquareColor;
3201 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3203 gc_values.foreground = blackPieceColor;
3204 gc_values.background = darkSquareColor;
3205 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3207 gc_values.foreground = blackPieceColor;
3208 gc_values.background = lightSquareColor;
3209 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3211 gc_values.foreground = blackPieceColor;
3212 gc_values.background = jailSquareColor;
3213 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3217 void loadXIM(xim, xmask, filename, dest, mask)
3230 fp = fopen(filename, "rb");
3232 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3239 for (y=0; y<h; ++y) {
3240 for (x=0; x<h; ++x) {
3245 XPutPixel(xim, x, y, blackPieceColor);
3247 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3250 XPutPixel(xim, x, y, darkSquareColor);
3252 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3255 XPutPixel(xim, x, y, whitePieceColor);
3257 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3260 XPutPixel(xim, x, y, lightSquareColor);
3262 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3268 /* create Pixmap of piece */
3269 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3271 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3274 /* create Pixmap of clipmask
3275 Note: We assume the white/black pieces have the same
3276 outline, so we make only 6 masks. This is okay
3277 since the XPM clipmask routines do the same. */
3279 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3281 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3284 /* now create the 1-bit version */
3285 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3288 values.foreground = 1;
3289 values.background = 0;
3291 /* Don't use XtGetGC, not read only */
3292 maskGC = XCreateGC(xDisplay, *mask,
3293 GCForeground | GCBackground, &values);
3294 XCopyPlane(xDisplay, temp, *mask, maskGC,
3295 0, 0, squareSize, squareSize, 0, 0, 1);
3296 XFreePixmap(xDisplay, temp);
3301 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3303 void CreateXIMPieces()
3308 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3313 /* The XSynchronize calls were copied from CreatePieces.
3314 Not sure if needed, but can't hurt */
3315 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3318 /* temp needed by loadXIM() */
3319 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3320 0, 0, ss, ss, AllPlanes, XYPixmap);
3322 if (strlen(appData.pixmapDirectory) == 0) {
3326 if (appData.monoMode) {
3327 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3331 fprintf(stderr, _("\nLoading XIMs...\n"));
3333 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3334 fprintf(stderr, "%d", piece+1);
3335 for (kind=0; kind<4; kind++) {
3336 fprintf(stderr, ".");
3337 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3338 ExpandPathName(appData.pixmapDirectory),
3339 piece <= (int) WhiteKing ? "" : "w",
3340 pieceBitmapNames[piece],
3342 ximPieceBitmap[kind][piece] =
3343 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3344 0, 0, ss, ss, AllPlanes, XYPixmap);
3345 if (appData.debugMode)
3346 fprintf(stderr, _("(File:%s:) "), buf);
3347 loadXIM(ximPieceBitmap[kind][piece],
3349 &(xpmPieceBitmap2[kind][piece]),
3350 &(ximMaskPm2[piece]));
3351 if(piece <= (int)WhiteKing)
3352 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3354 fprintf(stderr," ");
3356 /* Load light and dark squares */
3357 /* If the LSQ and DSQ pieces don't exist, we will
3358 draw them with solid squares. */
3359 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3360 if (access(buf, 0) != 0) {
3364 fprintf(stderr, _("light square "));
3366 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3367 0, 0, ss, ss, AllPlanes, XYPixmap);
3368 if (appData.debugMode)
3369 fprintf(stderr, _("(File:%s:) "), buf);
3371 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3372 fprintf(stderr, _("dark square "));
3373 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3374 ExpandPathName(appData.pixmapDirectory), ss);
3375 if (appData.debugMode)
3376 fprintf(stderr, _("(File:%s:) "), buf);
3378 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3379 0, 0, ss, ss, AllPlanes, XYPixmap);
3380 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3381 xpmJailSquare = xpmLightSquare;
3383 fprintf(stderr, _("Done.\n"));
3385 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3389 void CreateXPMBoard(char *s, int kind)
3393 if(s == NULL || *s == 0 || *s == '*') return;
3394 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3395 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3399 void CreateXPMPieces()
3403 u_int ss = squareSize;
3405 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3406 XpmColorSymbol symbols[4];
3408 /* The XSynchronize calls were copied from CreatePieces.
3409 Not sure if needed, but can't hurt */
3410 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3412 /* Setup translations so piece colors match square colors */
3413 symbols[0].name = "light_piece";
3414 symbols[0].value = appData.whitePieceColor;
3415 symbols[1].name = "dark_piece";
3416 symbols[1].value = appData.blackPieceColor;
3417 symbols[2].name = "light_square";
3418 symbols[2].value = appData.lightSquareColor;
3419 symbols[3].name = "dark_square";
3420 symbols[3].value = appData.darkSquareColor;
3422 attr.valuemask = XpmColorSymbols;
3423 attr.colorsymbols = symbols;
3424 attr.numsymbols = 4;
3426 if (appData.monoMode) {
3427 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3431 if (strlen(appData.pixmapDirectory) == 0) {
3432 XpmPieces* pieces = builtInXpms;
3435 while (pieces->size != squareSize && pieces->size) pieces++;
3436 if (!pieces->size) {
3437 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3440 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3441 for (kind=0; kind<4; kind++) {
3443 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3444 pieces->xpm[piece][kind],
3445 &(xpmPieceBitmap2[kind][piece]),
3446 NULL, &attr)) != 0) {
3447 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3451 if(piece <= (int) WhiteKing)
3452 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3456 xpmJailSquare = xpmLightSquare;
3460 fprintf(stderr, _("\nLoading XPMs...\n"));
3463 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3464 fprintf(stderr, "%d ", piece+1);
3465 for (kind=0; kind<4; kind++) {
3466 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3467 ExpandPathName(appData.pixmapDirectory),
3468 piece > (int) WhiteKing ? "w" : "",
3469 pieceBitmapNames[piece],
3471 if (appData.debugMode) {
3472 fprintf(stderr, _("(File:%s:) "), buf);
3474 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3475 &(xpmPieceBitmap2[kind][piece]),
3476 NULL, &attr)) != 0) {
3477 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3478 // [HGM] missing: read of unorthodox piece failed; substitute King.
3479 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3480 ExpandPathName(appData.pixmapDirectory),
3482 if (appData.debugMode) {
3483 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3485 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3486 &(xpmPieceBitmap2[kind][piece]),
3490 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3495 if(piece <= (int) WhiteKing)
3496 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3499 /* Load light and dark squares */
3500 /* If the LSQ and DSQ pieces don't exist, we will
3501 draw them with solid squares. */
3502 fprintf(stderr, _("light square "));
3503 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3504 if (access(buf, 0) != 0) {
3508 if (appData.debugMode)
3509 fprintf(stderr, _("(File:%s:) "), buf);
3511 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3512 &xpmLightSquare, NULL, &attr)) != 0) {
3513 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3516 fprintf(stderr, _("dark square "));
3517 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3518 ExpandPathName(appData.pixmapDirectory), ss);
3519 if (appData.debugMode) {
3520 fprintf(stderr, _("(File:%s:) "), buf);
3522 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3523 &xpmDarkSquare, NULL, &attr)) != 0) {
3524 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3528 xpmJailSquare = xpmLightSquare;
3529 fprintf(stderr, _("Done.\n"));
3531 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3534 #endif /* HAVE_LIBXPM */
3537 /* No built-in bitmaps */
3542 u_int ss = squareSize;
3544 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3547 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3548 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3549 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3550 pieceBitmapNames[piece],
3551 ss, kind == SOLID ? 's' : 'o');
3552 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3553 if(piece <= (int)WhiteKing)
3554 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3558 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3562 /* With built-in bitmaps */
3565 BuiltInBits* bib = builtInBits;
3568 u_int ss = squareSize;
3570 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3573 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3575 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3576 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3577 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3578 pieceBitmapNames[piece],
3579 ss, kind == SOLID ? 's' : 'o');
3580 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3581 bib->bits[kind][piece], ss, ss);
3582 if(piece <= (int)WhiteKing)
3583 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3587 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3592 void ReadBitmap(pm, name, bits, wreq, hreq)
3595 unsigned char bits[];
3601 char msg[MSG_SIZ], fullname[MSG_SIZ];
3603 if (*appData.bitmapDirectory != NULLCHAR) {
3604 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3605 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3606 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3607 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3608 &w, &h, pm, &x_hot, &y_hot);
3609 fprintf(stderr, "load %s\n", name);
3610 if (errcode != BitmapSuccess) {
3612 case BitmapOpenFailed:
3613 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3615 case BitmapFileInvalid:
3616 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3618 case BitmapNoMemory:
3619 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3623 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3627 fprintf(stderr, _("%s: %s...using built-in\n"),
3629 } else if (w != wreq || h != hreq) {
3631 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3632 programName, fullname, w, h, wreq, hreq);
3638 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3647 if (lineGap == 0) return;
3649 /* [HR] Split this into 2 loops for non-square boards. */
3651 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3652 gridSegments[i].x1 = 0;
3653 gridSegments[i].x2 =
3654 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3655 gridSegments[i].y1 = gridSegments[i].y2
3656 = lineGap / 2 + (i * (squareSize + lineGap));
3659 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3660 gridSegments[j + i].y1 = 0;
3661 gridSegments[j + i].y2 =
3662 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3663 gridSegments[j + i].x1 = gridSegments[j + i].x2
3664 = lineGap / 2 + (j * (squareSize + lineGap));
3668 static void MenuBarSelect(w, addr, index)
3673 XtActionProc proc = (XtActionProc) addr;
3675 (proc)(NULL, NULL, NULL, NULL);
3678 void CreateMenuBarPopup(parent, name, mb)
3688 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3691 XtSetArg(args[j], XtNleftMargin, 20); j++;
3692 XtSetArg(args[j], XtNrightMargin, 20); j++;
3694 while (mi->string != NULL) {
3695 if (strcmp(mi->string, "----") == 0) {
3696 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3699 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3700 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3702 XtAddCallback(entry, XtNcallback,
3703 (XtCallbackProc) MenuBarSelect,
3704 (caddr_t) mi->proc);
3710 Widget CreateMenuBar(mb)
3714 Widget anchor, menuBar;
3716 char menuName[MSG_SIZ];
3719 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3720 XtSetArg(args[j], XtNvSpace, 0); j++;
3721 XtSetArg(args[j], XtNborderWidth, 0); j++;
3722 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3723 formWidget, args, j);
3725 while (mb->name != NULL) {
3726 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3727 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3729 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3732 shortName[0] = _(mb->name)[0];
3733 shortName[1] = NULLCHAR;
3734 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3737 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3740 XtSetArg(args[j], XtNborderWidth, 0); j++;
3741 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3743 CreateMenuBarPopup(menuBar, menuName, mb);
3749 Widget CreateButtonBar(mi)
3753 Widget button, buttonBar;
3757 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3759 XtSetArg(args[j], XtNhSpace, 0); j++;
3761 XtSetArg(args[j], XtNborderWidth, 0); j++;
3762 XtSetArg(args[j], XtNvSpace, 0); j++;
3763 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3764 formWidget, args, j);
3766 while (mi->string != NULL) {
3769 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3770 XtSetArg(args[j], XtNborderWidth, 0); j++;
3772 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3773 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3774 buttonBar, args, j);
3775 XtAddCallback(button, XtNcallback,
3776 (XtCallbackProc) MenuBarSelect,
3777 (caddr_t) mi->proc);
3784 CreatePieceMenu(name, color)
3791 ChessSquare selection;
3793 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3794 boardWidget, args, 0);
3796 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3797 String item = pieceMenuStrings[color][i];
3799 if (strcmp(item, "----") == 0) {
3800 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3803 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3804 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3806 selection = pieceMenuTranslation[color][i];
3807 XtAddCallback(entry, XtNcallback,
3808 (XtCallbackProc) PieceMenuSelect,
3809 (caddr_t) selection);
3810 if (selection == WhitePawn || selection == BlackPawn) {
3811 XtSetArg(args[0], XtNpopupOnEntry, entry);
3812 XtSetValues(menu, args, 1);
3825 ChessSquare selection;
3827 whitePieceMenu = CreatePieceMenu("menuW", 0);
3828 blackPieceMenu = CreatePieceMenu("menuB", 1);
3830 XtRegisterGrabAction(PieceMenuPopup, True,
3831 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3832 GrabModeAsync, GrabModeAsync);
3834 XtSetArg(args[0], XtNlabel, _("Drop"));
3835 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3836 boardWidget, args, 1);
3837 for (i = 0; i < DROP_MENU_SIZE; i++) {
3838 String item = dropMenuStrings[i];
3840 if (strcmp(item, "----") == 0) {
3841 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3844 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3845 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3847 selection = dropMenuTranslation[i];
3848 XtAddCallback(entry, XtNcallback,
3849 (XtCallbackProc) DropMenuSelect,
3850 (caddr_t) selection);
3855 void SetupDropMenu()
3863 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3864 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3865 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3866 dmEnables[i].piece);
3867 XtSetSensitive(entry, p != NULL || !appData.testLegality
3868 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3869 && !appData.icsActive));
3871 while (p && *p++ == dmEnables[i].piece) count++;
3872 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3874 XtSetArg(args[j], XtNlabel, label); j++;
3875 XtSetValues(entry, args, j);
3879 void PieceMenuPopup(w, event, params, num_params)
3883 Cardinal *num_params;
3885 String whichMenu; int menuNr;
3886 if (event->type == ButtonRelease)
3887 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3888 else if (event->type == ButtonPress)
3889 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3891 case 0: whichMenu = params[0]; break;
3892 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3894 case -1: if (errorUp) ErrorPopDown();
3897 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3900 static void PieceMenuSelect(w, piece, junk)
3905 if (pmFromX < 0 || pmFromY < 0) return;
3906 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3909 static void DropMenuSelect(w, piece, junk)
3914 if (pmFromX < 0 || pmFromY < 0) return;
3915 DropMenuEvent(piece, pmFromX, pmFromY);
3918 void WhiteClock(w, event, prms, nprms)
3924 if (gameMode == EditPosition || gameMode == IcsExamining) {
3925 SetWhiteToPlayEvent();
3926 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3931 void BlackClock(w, event, prms, nprms)
3937 if (gameMode == EditPosition || gameMode == IcsExamining) {
3938 SetBlackToPlayEvent();
3939 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3946 * If the user selects on a border boundary, return -1; if off the board,
3947 * return -2. Otherwise map the event coordinate to the square.
3949 int EventToSquare(x, limit)
3957 if ((x % (squareSize + lineGap)) >= squareSize)
3959 x /= (squareSize + lineGap);
3965 static void do_flash_delay(msec)
3971 static void drawHighlight(file, rank, gc)
3977 if (lineGap == 0 || appData.blindfold) return;
3980 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3981 (squareSize + lineGap);
3982 y = lineGap/2 + rank * (squareSize + lineGap);
3984 x = lineGap/2 + file * (squareSize + lineGap);
3985 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3986 (squareSize + lineGap);
3989 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3990 squareSize+lineGap, squareSize+lineGap);
3993 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3994 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3997 SetHighlights(fromX, fromY, toX, toY)
3998 int fromX, fromY, toX, toY;
4000 if (hi1X != fromX || hi1Y != fromY) {
4001 if (hi1X >= 0 && hi1Y >= 0) {
4002 drawHighlight(hi1X, hi1Y, lineGC);
4004 } // [HGM] first erase both, then draw new!
4005 if (hi2X != toX || hi2Y != toY) {
4006 if (hi2X >= 0 && hi2Y >= 0) {
4007 drawHighlight(hi2X, hi2Y, lineGC);
4010 if (hi1X != fromX || hi1Y != fromY) {
4011 if (fromX >= 0 && fromY >= 0) {
4012 drawHighlight(fromX, fromY, highlineGC);
4015 if (hi2X != toX || hi2Y != toY) {
4016 if (toX >= 0 && toY >= 0) {
4017 drawHighlight(toX, toY, highlineGC);
4029 SetHighlights(-1, -1, -1, -1);
4034 SetPremoveHighlights(fromX, fromY, toX, toY)
4035 int fromX, fromY, toX, toY;
4037 if (pm1X != fromX || pm1Y != fromY) {
4038 if (pm1X >= 0 && pm1Y >= 0) {
4039 drawHighlight(pm1X, pm1Y, lineGC);
4041 if (fromX >= 0 && fromY >= 0) {
4042 drawHighlight(fromX, fromY, prelineGC);
4045 if (pm2X != toX || pm2Y != toY) {
4046 if (pm2X >= 0 && pm2Y >= 0) {
4047 drawHighlight(pm2X, pm2Y, lineGC);
4049 if (toX >= 0 && toY >= 0) {
4050 drawHighlight(toX, toY, prelineGC);
4060 ClearPremoveHighlights()
4062 SetPremoveHighlights(-1, -1, -1, -1);
4065 static int CutOutSquare(x, y, x0, y0, kind)
4066 int x, y, *x0, *y0, kind;
4068 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4069 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4071 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4072 if(textureW[kind] < W*squareSize)
4073 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4075 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4076 if(textureH[kind] < H*squareSize)
4077 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4079 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4083 static void BlankSquare(x, y, color, piece, dest, fac)
4084 int x, y, color, fac;
4087 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4089 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4090 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4091 squareSize, squareSize, x*fac, y*fac);
4093 if (useImages && useImageSqs) {
4097 pm = xpmLightSquare;
4102 case 2: /* neutral */
4107 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4108 squareSize, squareSize, x*fac, y*fac);
4118 case 2: /* neutral */
4123 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4128 I split out the routines to draw a piece so that I could
4129 make a generic flash routine.
4131 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4133 int square_color, x, y;
4136 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4137 switch (square_color) {
4139 case 2: /* neutral */
4141 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4142 ? *pieceToOutline(piece)
4143 : *pieceToSolid(piece),
4144 dest, bwPieceGC, 0, 0,
4145 squareSize, squareSize, x, y);
4148 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4149 ? *pieceToSolid(piece)
4150 : *pieceToOutline(piece),
4151 dest, wbPieceGC, 0, 0,
4152 squareSize, squareSize, x, y);
4157 static void monoDrawPiece(piece, square_color, x, y, dest)
4159 int square_color, x, y;
4162 switch (square_color) {
4164 case 2: /* neutral */
4166 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4167 ? *pieceToOutline(piece)
4168 : *pieceToSolid(piece),
4169 dest, bwPieceGC, 0, 0,
4170 squareSize, squareSize, x, y, 1);
4173 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4174 ? *pieceToSolid(piece)
4175 : *pieceToOutline(piece),
4176 dest, wbPieceGC, 0, 0,
4177 squareSize, squareSize, x, y, 1);
4182 static void colorDrawPiece(piece, square_color, x, y, dest)
4184 int square_color, x, y;
4187 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4188 switch (square_color) {
4190 XCopyPlane(xDisplay, *pieceToSolid(piece),
4191 dest, (int) piece < (int) BlackPawn
4192 ? wlPieceGC : blPieceGC, 0, 0,
4193 squareSize, squareSize, x, y, 1);
4196 XCopyPlane(xDisplay, *pieceToSolid(piece),
4197 dest, (int) piece < (int) BlackPawn
4198 ? wdPieceGC : bdPieceGC, 0, 0,
4199 squareSize, squareSize, x, y, 1);
4201 case 2: /* neutral */
4203 XCopyPlane(xDisplay, *pieceToSolid(piece),
4204 dest, (int) piece < (int) BlackPawn
4205 ? wjPieceGC : bjPieceGC, 0, 0,
4206 squareSize, squareSize, x, y, 1);
4211 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4213 int square_color, x, y;
4216 int kind, p = piece;
4218 switch (square_color) {
4220 case 2: /* neutral */
4222 if ((int)piece < (int) BlackPawn) {
4230 if ((int)piece < (int) BlackPawn) {
4238 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4239 if(useTexture & square_color+1) {
4240 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4241 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4242 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4243 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4244 XSetClipMask(xDisplay, wlPieceGC, None);
4245 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4247 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4248 dest, wlPieceGC, 0, 0,
4249 squareSize, squareSize, x, y);
4252 typedef void (*DrawFunc)();
4254 DrawFunc ChooseDrawFunc()
4256 if (appData.monoMode) {
4257 if (DefaultDepth(xDisplay, xScreen) == 1) {
4258 return monoDrawPiece_1bit;
4260 return monoDrawPiece;
4264 return colorDrawPieceImage;
4266 return colorDrawPiece;
4270 /* [HR] determine square color depending on chess variant. */
4271 static int SquareColor(row, column)