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 Position"), LoadPositionProc},
599 // {N_("Load Next Game"), LoadNextGameProc},
600 // {N_("Load Previous Game"), LoadPrevGameProc},
601 // {N_("Reload Same Game"), ReloadGameProc},
602 {"----", NothingProc},
603 // {N_("Load Next Position"), LoadNextPositionProc},
604 // {N_("Load Previous Position"), LoadPrevPositionProc},
605 // {N_("Reload Same Position"), ReloadPositionProc},
606 {N_("Save Game"), SaveGameProc},
607 {N_("Save Position"), SavePositionProc},
608 {"----", NothingProc},
609 {N_("Mail Move"), MailMoveProc},
610 {N_("Reload CMail Message"), ReloadCmailMsgProc},
611 {"----", NothingProc},
612 {N_("Exit"), QuitProc},
616 MenuItem editMenu[] = {
617 {N_("Copy Game"), CopyGameProc},
618 {N_("Copy Position"), CopyPositionProc},
619 {"----", NothingProc},
620 {N_("Paste Game"), PasteGameProc},
621 {N_("Paste Position"), PastePositionProc},
622 {"----", NothingProc},
623 {N_("Edit Game"), EditGameProc},
624 {N_("Edit Position"), EditPositionProc},
625 {"----", NothingProc},
626 {N_("Edit Tags"), EditTagsProc},
627 {N_("Edit Comment"), EditCommentProc},
628 {"----", NothingProc},
629 {N_("Revert"), RevertProc},
630 {N_("Annotate"), AnnotateProc},
631 {N_("Truncate Game"), TruncateGameProc},
632 {"----", NothingProc},
633 {N_("Backward"), BackwardProc},
634 {N_("Forward"), ForwardProc},
635 {N_("Back to Start"), ToStartProc},
636 {N_("Forward to End"), ToEndProc},
640 MenuItem viewMenu[] = {
641 {N_("Flip View"), FlipViewProc},
642 {"----", NothingProc},
643 {N_("Show Engine Output"), EngineOutputProc},
644 {N_("Show Evaluation Graph"), EvalGraphProc},
645 {N_("Show Game List"), ShowGameListProc},
646 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
647 {"----", NothingProc},
648 {N_("Show Tags"), EditTagsProc},
649 {N_("Show Comments"), EditCommentProc},
650 {N_("ICS Input Box"), IcsInputBoxProc},
654 MenuItem modeMenu[] = {
655 {N_("Machine White"), MachineWhiteProc},
656 {N_("Machine Black"), MachineBlackProc},
657 {N_("Two Machines"), TwoMachinesProc},
658 {N_("Analysis Mode"), AnalyzeModeProc},
659 {N_("Analyze File"), AnalyzeFileProc },
660 {N_("Edit Game"), EditGameProc},
661 {N_("Edit Position"), EditPositionProc},
662 {N_("Training"), TrainingProc},
663 {N_("ICS Client"), IcsClientProc},
664 {"----", NothingProc},
665 {N_("Pause"), PauseProc},
669 MenuItem actionMenu[] = {
670 {N_("Accept"), AcceptProc},
671 {N_("Decline"), DeclineProc},
672 {N_("Rematch"), RematchProc},
673 {"----", NothingProc},
674 {N_("Call Flag"), CallFlagProc},
675 {N_("Draw"), DrawProc},
676 {N_("Adjourn"), AdjournProc},
677 {N_("Abort"), AbortProc},
678 {N_("Resign"), ResignProc},
679 {"----", NothingProc},
680 {N_("Stop Observing"), StopObservingProc},
681 {N_("Stop Examining"), StopExaminingProc},
682 {N_("Upload to Examine"), UploadProc},
683 {"----", NothingProc},
684 {N_("Adjudicate to White"), AdjuWhiteProc},
685 {N_("Adjudicate to Black"), AdjuBlackProc},
686 {N_("Adjudicate Draw"), AdjuDrawProc},
690 MenuItem engineMenu[] = {
691 {N_("Engine #1 Settings"), FirstSettingsProc},
692 {N_("Engine #2 Settings"), SecondSettingsProc},
693 {"----", NothingProc},
694 {N_("Move Now"), MoveNowProc},
695 {N_("Retract Move"), RetractMoveProc},
699 MenuItem optionsMenu[] = {
700 {N_("Time Control ..."), TimeControlProc},
701 {N_("Common Engine ..."), UciMenuProc},
702 {N_("Adjudications ..."), EngineMenuProc},
703 {N_("Game List ..."), GameListOptionsPopUp},
704 {"----", NothingProc},
705 {N_("Always Queen"), AlwaysQueenProc},
706 {N_("Animate Dragging"), AnimateDraggingProc},
707 {N_("Animate Moving"), AnimateMovingProc},
708 {N_("Auto Comment"), AutocommProc},
709 {N_("Auto Flag"), AutoflagProc},
710 {N_("Auto Flip View"), AutoflipProc},
711 {N_("Auto Observe"), AutobsProc},
712 {N_("Auto Raise Board"), AutoraiseProc},
713 {N_("Auto Save"), AutosaveProc},
714 {N_("Blindfold"), BlindfoldProc},
715 {N_("Flash Moves"), FlashMovesProc},
716 {N_("Get Move List"), GetMoveListProc},
718 {N_("Highlight Dragging"), HighlightDraggingProc},
720 {N_("Highlight Last Move"), HighlightLastMoveProc},
721 {N_("Move Sound"), MoveSoundProc},
722 {N_("ICS Alarm"), IcsAlarmProc},
723 {N_("Old Save Style"), OldSaveStyleProc},
724 {N_("Periodic Updates"), PeriodicUpdatesProc},
725 {N_("Ponder Next Move"), PonderNextMoveProc},
726 {N_("Popup Exit Message"), PopupExitMessageProc},
727 {N_("Popup Move Errors"), PopupMoveErrorsProc},
728 {N_("Premove"), PremoveProc},
729 {N_("Quiet Play"), QuietPlayProc},
730 {N_("Show Coords"), ShowCoordsProc},
731 {N_("Hide Thinking"), HideThinkingProc},
732 {N_("Test Legality"), TestLegalityProc},
733 {"----", NothingProc},
734 {N_("Save Settings Now"), SaveSettingsProc},
735 {N_("Save Settings on Exit"), SaveOnExitProc},
739 MenuItem helpMenu[] = {
740 {N_("Info XBoard"), InfoProc},
741 {N_("Man XBoard"), ManProc},
742 {"----", NothingProc},
743 {N_("Hint"), HintProc},
744 {N_("Book"), BookProc},
745 {"----", NothingProc},
746 {N_("About XBoard"), AboutProc},
751 {N_("File"), fileMenu},
752 {N_("Edit"), editMenu},
753 {N_("View"), viewMenu},
754 {N_("Mode"), modeMenu},
755 {N_("Action"), actionMenu},
756 {N_("Engine"), engineMenu},
757 {N_("Options"), optionsMenu},
758 {N_("Help"), helpMenu},
762 #define PAUSE_BUTTON N_("P")
763 MenuItem buttonBar[] = {
766 {PAUSE_BUTTON, PauseProc},
772 #define PIECE_MENU_SIZE 18
773 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
774 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
775 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
776 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
777 N_("Empty square"), N_("Clear board") },
778 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
779 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
780 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
781 N_("Empty square"), N_("Clear board") }
783 /* must be in same order as PieceMenuStrings! */
784 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
785 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
786 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
787 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
788 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
789 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
790 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
791 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
792 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
795 #define DROP_MENU_SIZE 6
796 String dropMenuStrings[DROP_MENU_SIZE] = {
797 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
799 /* must be in same order as PieceMenuStrings! */
800 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
801 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
802 WhiteRook, WhiteQueen
810 DropMenuEnables dmEnables[] = {
828 { XtNborderWidth, 0 },
829 { XtNdefaultDistance, 0 },
833 { XtNborderWidth, 0 },
834 { XtNresizable, (XtArgVal) True },
838 { XtNborderWidth, 0 },
844 { XtNjustify, (XtArgVal) XtJustifyRight },
845 { XtNlabel, (XtArgVal) "..." },
846 { XtNresizable, (XtArgVal) True },
847 { XtNresize, (XtArgVal) False }
850 Arg messageArgs[] = {
851 { XtNjustify, (XtArgVal) XtJustifyLeft },
852 { XtNlabel, (XtArgVal) "..." },
853 { XtNresizable, (XtArgVal) True },
854 { XtNresize, (XtArgVal) False }
858 { XtNborderWidth, 0 },
859 { XtNjustify, (XtArgVal) XtJustifyLeft }
862 XtResource clientResources[] = {
863 { "flashCount", "flashCount", XtRInt, sizeof(int),
864 XtOffset(AppDataPtr, flashCount), XtRImmediate,
865 (XtPointer) FLASH_COUNT },
868 XrmOptionDescRec shellOptions[] = {
869 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
870 { "-flash", "flashCount", XrmoptionNoArg, "3" },
871 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
874 XtActionsRec boardActions[] = {
875 { "DrawPosition", DrawPositionProc },
876 { "HandleUserMove", HandleUserMove },
877 { "AnimateUserMove", AnimateUserMove },
878 { "HandlePV", HandlePV },
879 { "SelectPV", SelectPV },
880 { "StopPV", StopPV },
881 { "FileNameAction", FileNameAction },
882 { "AskQuestionProc", AskQuestionProc },
883 { "AskQuestionReplyAction", AskQuestionReplyAction },
884 { "PieceMenuPopup", PieceMenuPopup },
885 { "WhiteClock", WhiteClock },
886 { "BlackClock", BlackClock },
887 { "Iconify", Iconify },
888 { "ResetProc", ResetProc },
889 { "NewVariantProc", NewVariantProc },
890 { "LoadGameProc", LoadGameProc },
891 { "LoadNextGameProc", LoadNextGameProc },
892 { "LoadPrevGameProc", LoadPrevGameProc },
893 { "LoadSelectedProc", LoadSelectedProc },
894 { "SetFilterProc", SetFilterProc },
895 { "ReloadGameProc", ReloadGameProc },
896 { "LoadPositionProc", LoadPositionProc },
897 { "LoadNextPositionProc", LoadNextPositionProc },
898 { "LoadPrevPositionProc", LoadPrevPositionProc },
899 { "ReloadPositionProc", ReloadPositionProc },
900 { "CopyPositionProc", CopyPositionProc },
901 { "PastePositionProc", PastePositionProc },
902 { "CopyGameProc", CopyGameProc },
903 { "PasteGameProc", PasteGameProc },
904 { "SaveGameProc", SaveGameProc },
905 { "SavePositionProc", SavePositionProc },
906 { "MailMoveProc", MailMoveProc },
907 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
908 { "QuitProc", QuitProc },
909 { "MachineWhiteProc", MachineWhiteProc },
910 { "MachineBlackProc", MachineBlackProc },
911 { "AnalysisModeProc", AnalyzeModeProc },
912 { "AnalyzeFileProc", AnalyzeFileProc },
913 { "TwoMachinesProc", TwoMachinesProc },
914 { "IcsClientProc", IcsClientProc },
915 { "EditGameProc", EditGameProc },
916 { "EditPositionProc", EditPositionProc },
917 { "TrainingProc", EditPositionProc },
918 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
919 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
920 { "ShowGameListProc", ShowGameListProc },
921 { "ShowMoveListProc", HistoryShowProc},
922 { "EditTagsProc", EditCommentProc },
923 { "EditCommentProc", EditCommentProc },
924 { "IcsAlarmProc", IcsAlarmProc },
925 { "IcsInputBoxProc", IcsInputBoxProc },
926 { "PauseProc", PauseProc },
927 { "AcceptProc", AcceptProc },
928 { "DeclineProc", DeclineProc },
929 { "RematchProc", RematchProc },
930 { "CallFlagProc", CallFlagProc },
931 { "DrawProc", DrawProc },
932 { "AdjournProc", AdjournProc },
933 { "AbortProc", AbortProc },
934 { "ResignProc", ResignProc },
935 { "AdjuWhiteProc", AdjuWhiteProc },
936 { "AdjuBlackProc", AdjuBlackProc },
937 { "AdjuDrawProc", AdjuDrawProc },
938 { "EnterKeyProc", EnterKeyProc },
939 { "UpKeyProc", UpKeyProc },
940 { "DownKeyProc", DownKeyProc },
941 { "StopObservingProc", StopObservingProc },
942 { "StopExaminingProc", StopExaminingProc },
943 { "UploadProc", UploadProc },
944 { "BackwardProc", BackwardProc },
945 { "ForwardProc", ForwardProc },
946 { "ToStartProc", ToStartProc },
947 { "ToEndProc", ToEndProc },
948 { "RevertProc", RevertProc },
949 { "AnnotateProc", AnnotateProc },
950 { "TruncateGameProc", TruncateGameProc },
951 { "MoveNowProc", MoveNowProc },
952 { "RetractMoveProc", RetractMoveProc },
953 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
954 { "UciMenuProc", (XtActionProc) UciMenuProc },
955 { "TimeControlProc", (XtActionProc) TimeControlProc },
956 { "AlwaysQueenProc", AlwaysQueenProc },
957 { "AnimateDraggingProc", AnimateDraggingProc },
958 { "AnimateMovingProc", AnimateMovingProc },
959 { "AutoflagProc", AutoflagProc },
960 { "AutoflipProc", AutoflipProc },
961 { "AutobsProc", AutobsProc },
962 { "AutoraiseProc", AutoraiseProc },
963 { "AutosaveProc", AutosaveProc },
964 { "BlindfoldProc", BlindfoldProc },
965 { "FlashMovesProc", FlashMovesProc },
966 { "FlipViewProc", FlipViewProc },
967 { "GetMoveListProc", GetMoveListProc },
969 { "HighlightDraggingProc", HighlightDraggingProc },
971 { "HighlightLastMoveProc", HighlightLastMoveProc },
972 { "IcsAlarmProc", IcsAlarmProc },
973 { "MoveSoundProc", MoveSoundProc },
974 { "OldSaveStyleProc", OldSaveStyleProc },
975 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
976 { "PonderNextMoveProc", PonderNextMoveProc },
977 { "PopupExitMessageProc", PopupExitMessageProc },
978 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
979 { "PremoveProc", PremoveProc },
980 { "QuietPlayProc", QuietPlayProc },
981 { "ShowCoordsProc", ShowCoordsProc },
982 { "ShowThinkingProc", ShowThinkingProc },
983 { "HideThinkingProc", HideThinkingProc },
984 { "TestLegalityProc", TestLegalityProc },
985 { "SaveSettingsProc", SaveSettingsProc },
986 { "SaveOnExitProc", SaveOnExitProc },
987 { "InfoProc", InfoProc },
988 { "ManProc", ManProc },
989 { "HintProc", HintProc },
990 { "BookProc", BookProc },
991 { "AboutGameProc", AboutGameProc },
992 { "AboutProc", AboutProc },
993 { "DebugProc", DebugProc },
994 { "NothingProc", NothingProc },
995 { "CommentClick", (XtActionProc) CommentClick },
996 { "CommentPopDown", (XtActionProc) CommentPopDown },
997 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
998 { "TagsPopDown", (XtActionProc) TagsPopDown },
999 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1000 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1001 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1002 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1003 { "GameListPopDown", (XtActionProc) GameListPopDown },
1004 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1005 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1006 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1007 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1008 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1009 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1010 { "EnginePopDown", (XtActionProc) EnginePopDown },
1011 { "UciPopDown", (XtActionProc) UciPopDown },
1012 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1013 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1014 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1015 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1018 char globalTranslations[] =
1019 ":<Key>F9: ResignProc() \n \
1020 :Ctrl<Key>n: ResetProc() \n \
1021 :Meta<Key>V: NewVariantProc() \n \
1022 :Ctrl<Key>o: LoadGameProc() \n \
1023 :Meta<Key>Next: LoadNextGameProc() \n \
1024 :Meta<Key>Prior: LoadPrevGameProc() \n \
1025 :Ctrl<Key>s: SaveGameProc() \n \
1026 :Ctrl<Key>c: CopyGameProc() \n \
1027 :Ctrl<Key>v: PasteGameProc() \n \
1028 :Ctrl<Key>O: LoadPositionProc() \n \
1029 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1030 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1031 :Ctrl<Key>S: SavePositionProc() \n \
1032 :Ctrl<Key>C: CopyPositionProc() \n \
1033 :Ctrl<Key>V: PastePositionProc() \n \
1034 :Ctrl<Key>q: QuitProc() \n \
1035 :Ctrl<Key>w: MachineWhiteProc() \n \
1036 :Ctrl<Key>b: MachineBlackProc() \n \
1037 :Ctrl<Key>t: TwoMachinesProc() \n \
1038 :Ctrl<Key>a: AnalysisModeProc() \n \
1039 :Ctrl<Key>f: AnalyzeFileProc() \n \
1040 :Ctrl<Key>e: EditGameProc() \n \
1041 :Ctrl<Key>E: EditPositionProc() \n \
1042 :Meta<Key>O: EngineOutputProc() \n \
1043 :Meta<Key>E: EvalGraphProc() \n \
1044 :Meta<Key>G: ShowGameListProc() \n \
1045 :Meta<Key>H: ShowMoveListProc() \n \
1046 :<Key>Pause: PauseProc() \n \
1047 :<Key>F3: AcceptProc() \n \
1048 :<Key>F4: DeclineProc() \n \
1049 :<Key>F12: RematchProc() \n \
1050 :<Key>F5: CallFlagProc() \n \
1051 :<Key>F6: DrawProc() \n \
1052 :<Key>F7: AdjournProc() \n \
1053 :<Key>F8: AbortProc() \n \
1054 :<Key>F10: StopObservingProc() \n \
1055 :<Key>F11: StopExaminingProc() \n \
1056 :Meta Ctrl<Key>F12: DebugProc() \n \
1057 :Meta<Key>End: ToEndProc() \n \
1058 :Meta<Key>Right: ForwardProc() \n \
1059 :Meta<Key>Home: ToStartProc() \n \
1060 :Meta<Key>Left: BackwardProc() \n \
1061 :Ctrl<Key>m: MoveNowProc() \n \
1062 :Ctrl<Key>x: RetractMoveProc() \n \
1063 :Meta<Key>J: EngineMenuProc() \n \
1064 :Meta<Key>U: UciMenuProc() \n \
1065 :Meta<Key>T: TimeControlProc() \n \
1066 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1067 :Ctrl<Key>F: AutoflagProc() \n \
1068 :Ctrl<Key>A: AnimateMovingProc() \n \
1069 :Ctrl<Key>P: PonderNextMoveProc() \n \
1070 :Ctrl<Key>L: TestLegalityProc() \n \
1071 :Ctrl<Key>H: HideThinkingProc() \n \
1072 :<Key>-: Iconify() \n \
1073 :<Key>F1: ManProc() \n \
1074 :<Key>F2: FlipViewProc() \n \
1075 <KeyDown>.: BackwardProc() \n \
1076 <KeyUp>.: ForwardProc() \n \
1077 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1078 \"Send to chess program:\",,1) \n \
1079 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1080 \"Send to second chess program:\",,2) \n";
1082 char boardTranslations[] =
1083 "<Btn1Down>: HandleUserMove(0) \n \
1084 Shift<Btn1Up>: HandleUserMove(1) \n \
1085 <Btn1Up>: HandleUserMove(0) \n \
1086 <Btn1Motion>: AnimateUserMove() \n \
1087 <Btn3Motion>: HandlePV() \n \
1088 <Btn3Up>: PieceMenuPopup(menuB) \n \
1089 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1090 PieceMenuPopup(menuB) \n \
1091 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1092 PieceMenuPopup(menuW) \n \
1093 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1094 PieceMenuPopup(menuW) \n \
1095 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1096 PieceMenuPopup(menuB) \n";
1098 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1099 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1101 char ICSInputTranslations[] =
1102 "<Key>Up: UpKeyProc() \n "
1103 "<Key>Down: DownKeyProc() \n "
1104 "<Key>Return: EnterKeyProc() \n";
1106 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1107 // as the widget is destroyed before the up-click can call extend-end
1108 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1110 String xboardResources[] = {
1111 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1112 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1113 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1118 /* Max possible square size */
1119 #define MAXSQSIZE 256
1121 static int xpm_avail[MAXSQSIZE];
1123 #ifdef HAVE_DIR_STRUCT
1125 /* Extract piece size from filename */
1127 xpm_getsize(name, len, ext)
1138 if ((p=strchr(name, '.')) == NULL ||
1139 StrCaseCmp(p+1, ext) != 0)
1145 while (*p && isdigit(*p))
1152 /* Setup xpm_avail */
1154 xpm_getavail(dirname, ext)
1162 for (i=0; i<MAXSQSIZE; ++i)
1165 if (appData.debugMode)
1166 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1168 dir = opendir(dirname);
1171 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1172 programName, dirname);
1176 while ((ent=readdir(dir)) != NULL) {
1177 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1178 if (i > 0 && i < MAXSQSIZE)
1188 xpm_print_avail(fp, ext)
1194 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1195 for (i=1; i<MAXSQSIZE; ++i) {
1201 /* Return XPM piecesize closest to size */
1203 xpm_closest_to(dirname, size, ext)
1209 int sm_diff = MAXSQSIZE;
1213 xpm_getavail(dirname, ext);
1215 if (appData.debugMode)
1216 xpm_print_avail(stderr, ext);
1218 for (i=1; i<MAXSQSIZE; ++i) {
1221 diff = (diff<0) ? -diff : diff;
1222 if (diff < sm_diff) {
1230 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1236 #else /* !HAVE_DIR_STRUCT */
1237 /* If we are on a system without a DIR struct, we can't
1238 read the directory, so we can't collect a list of
1239 filenames, etc., so we can't do any size-fitting. */
1241 xpm_closest_to(dirname, size, ext)
1246 fprintf(stderr, _("\
1247 Warning: No DIR structure found on this system --\n\
1248 Unable to autosize for XPM/XIM pieces.\n\
1249 Please report this error to frankm@hiwaay.net.\n\
1250 Include system type & operating system in message.\n"));
1253 #endif /* HAVE_DIR_STRUCT */
1255 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1256 "magenta", "cyan", "white" };
1260 TextColors textColors[(int)NColorClasses];
1262 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1264 parse_color(str, which)
1268 char *p, buf[100], *d;
1271 if (strlen(str) > 99) /* watch bounds on buf */
1276 for (i=0; i<which; ++i) {
1283 /* Could be looking at something like:
1285 .. in which case we want to stop on a comma also */
1286 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1290 return -1; /* Use default for empty field */
1293 if (which == 2 || isdigit(*p))
1296 while (*p && isalpha(*p))
1301 for (i=0; i<8; ++i) {
1302 if (!StrCaseCmp(buf, cnames[i]))
1303 return which? (i+40) : (i+30);
1305 if (!StrCaseCmp(buf, "default")) return -1;
1307 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1312 parse_cpair(cc, str)
1316 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1317 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1322 /* bg and attr are optional */
1323 textColors[(int)cc].bg = parse_color(str, 1);
1324 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1325 textColors[(int)cc].attr = 0;
1331 /* Arrange to catch delete-window events */
1332 Atom wm_delete_window;
1334 CatchDeleteWindow(Widget w, String procname)
1337 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1338 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1339 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1346 XtSetArg(args[0], XtNiconic, False);
1347 XtSetValues(shellWidget, args, 1);
1349 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1352 //---------------------------------------------------------------------------------------------------------
1353 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1356 #define CW_USEDEFAULT (1<<31)
1357 #define ICS_TEXT_MENU_SIZE 90
1358 #define DEBUG_FILE "xboard.debug"
1359 #define SetCurrentDirectory chdir
1360 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1364 // these two must some day move to frontend.h, when they are implemented
1365 Boolean GameListIsUp();
1367 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1370 // front-end part of option handling
1372 // [HGM] This platform-dependent table provides the location for storing the color info
1373 extern char *crWhite, * crBlack;
1377 &appData.whitePieceColor,
1378 &appData.blackPieceColor,
1379 &appData.lightSquareColor,
1380 &appData.darkSquareColor,
1381 &appData.highlightSquareColor,
1382 &appData.premoveHighlightColor,
1383 &appData.lowTimeWarningColor,
1394 // [HGM] font: keep a font for each square size, even non-stndard ones
1395 #define NUM_SIZES 18
1396 #define MAX_SIZE 130
1397 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1398 char *fontTable[NUM_FONTS][MAX_SIZE];
1401 ParseFont(char *name, int number)
1402 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1404 if(sscanf(name, "size%d:", &size)) {
1405 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1406 // defer processing it until we know if it matches our board size
1407 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1408 fontTable[number][size] = strdup(strchr(name, ':')+1);
1409 fontValid[number][size] = True;
1414 case 0: // CLOCK_FONT
1415 appData.clockFont = strdup(name);
1417 case 1: // MESSAGE_FONT
1418 appData.font = strdup(name);
1420 case 2: // COORD_FONT
1421 appData.coordFont = strdup(name);
1426 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1431 { // only 2 fonts currently
1432 appData.clockFont = CLOCK_FONT_NAME;
1433 appData.coordFont = COORD_FONT_NAME;
1434 appData.font = DEFAULT_FONT_NAME;
1439 { // no-op, until we identify the code for this already in XBoard and move it here
1443 ParseColor(int n, char *name)
1444 { // in XBoard, just copy the color-name string
1445 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1449 ParseTextAttribs(ColorClass cc, char *s)
1451 (&appData.colorShout)[cc] = strdup(s);
1455 ParseBoardSize(void *addr, char *name)
1457 appData.boardSize = strdup(name);
1462 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1466 SetCommPortDefaults()
1467 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1470 // [HGM] args: these three cases taken out to stay in front-end
1472 SaveFontArg(FILE *f, ArgDescriptor *ad)
1475 int i, n = (int)ad->argLoc;
1477 case 0: // CLOCK_FONT
1478 name = appData.clockFont;
1480 case 1: // MESSAGE_FONT
1481 name = appData.font;
1483 case 2: // COORD_FONT
1484 name = appData.coordFont;
1489 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1490 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1491 fontTable[n][squareSize] = strdup(name);
1492 fontValid[n][squareSize] = True;
1495 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1496 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1501 { // nothing to do, as the sounds are at all times represented by their text-string names already
1505 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1506 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1507 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1511 SaveColor(FILE *f, ArgDescriptor *ad)
1512 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1513 if(colorVariable[(int)ad->argLoc])
1514 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1518 SaveBoardSize(FILE *f, char *name, void *addr)
1519 { // wrapper to shield back-end from BoardSize & sizeInfo
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1524 ParseCommPortSettings(char *s)
1525 { // no such option in XBoard (yet)
1528 extern Widget engineOutputShell;
1529 extern Widget tagsShell, editTagsShell;
1531 GetActualPlacement(Widget wg, WindowPlacement *wp)
1541 XtSetArg(args[i], XtNx, &x); i++;
1542 XtSetArg(args[i], XtNy, &y); i++;
1543 XtSetArg(args[i], XtNwidth, &w); i++;
1544 XtSetArg(args[i], XtNheight, &h); i++;
1545 XtGetValues(wg, args, i);
1554 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1555 // In XBoard this will have to wait until awareness of window parameters is implemented
1556 GetActualPlacement(shellWidget, &wpMain);
1557 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1558 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1559 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1560 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1561 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1562 else GetActualPlacement(editShell, &wpComment);
1563 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1564 else GetActualPlacement(editTagsShell, &wpTags);
1568 PrintCommPortSettings(FILE *f, char *name)
1569 { // This option does not exist in XBoard
1573 MySearchPath(char *installDir, char *name, char *fullname)
1574 { // just append installDir and name. Perhaps ExpandPath should be used here?
1575 name = ExpandPathName(name);
1576 if(name && name[0] == '/')
1577 safeStrCpy(fullname, name, MSG_SIZ );
1579 sprintf(fullname, "%s%c%s", installDir, '/', name);
1585 MyGetFullPathName(char *name, char *fullname)
1586 { // should use ExpandPath?
1587 name = ExpandPathName(name);
1588 safeStrCpy(fullname, name, MSG_SIZ );
1593 EnsureOnScreen(int *x, int *y, int minX, int minY)
1600 { // [HGM] args: allows testing if main window is realized from back-end
1601 return xBoardWindow != 0;
1605 PopUpStartupDialog()
1606 { // start menu not implemented in XBoard
1610 ConvertToLine(int argc, char **argv)
1612 static char line[128*1024], buf[1024];
1616 for(i=1; i<argc; i++)
1618 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1619 && argv[i][0] != '{' )
1620 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1622 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1623 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1626 line[strlen(line)-1] = NULLCHAR;
1630 //--------------------------------------------------------------------------------------------
1632 extern Boolean twoBoards, partnerUp;
1635 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1637 #define BoardSize int
1638 void InitDrawingSizes(BoardSize boardSize, int flags)
1639 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1640 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1642 XtGeometryResult gres;
1645 if(!formWidget) return;
1648 * Enable shell resizing.
1650 shellArgs[0].value = (XtArgVal) &w;
1651 shellArgs[1].value = (XtArgVal) &h;
1652 XtGetValues(shellWidget, shellArgs, 2);
1654 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1655 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1656 XtSetValues(shellWidget, &shellArgs[2], 4);
1658 XtSetArg(args[0], XtNdefaultDistance, &sep);
1659 XtGetValues(formWidget, args, 1);
1661 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1662 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1664 hOffset = boardWidth + 10;
1665 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1666 secondSegments[i] = gridSegments[i];
1667 secondSegments[i].x1 += hOffset;
1668 secondSegments[i].x2 += hOffset;
1671 XtSetArg(args[0], XtNwidth, boardWidth);
1672 XtSetArg(args[1], XtNheight, boardHeight);
1673 XtSetValues(boardWidget, args, 2);
1675 timerWidth = (boardWidth - sep) / 2;
1676 XtSetArg(args[0], XtNwidth, timerWidth);
1677 XtSetValues(whiteTimerWidget, args, 1);
1678 XtSetValues(blackTimerWidget, args, 1);
1680 XawFormDoLayout(formWidget, False);
1682 if (appData.titleInWindow) {
1684 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1685 XtSetArg(args[i], XtNheight, &h); i++;
1686 XtGetValues(titleWidget, args, i);
1688 w = boardWidth - 2*bor;
1690 XtSetArg(args[0], XtNwidth, &w);
1691 XtGetValues(menuBarWidget, args, 1);
1692 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1695 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1696 if (gres != XtGeometryYes && appData.debugMode) {
1698 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1699 programName, gres, w, h, wr, hr);
1703 XawFormDoLayout(formWidget, True);
1706 * Inhibit shell resizing.
1708 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1709 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1710 shellArgs[4].value = shellArgs[2].value = w;
1711 shellArgs[5].value = shellArgs[3].value = h;
1712 XtSetValues(shellWidget, &shellArgs[0], 6);
1714 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1717 for(i=0; i<4; i++) {
1719 for(p=0; p<=(int)WhiteKing; p++)
1720 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1721 if(gameInfo.variant == VariantShogi) {
1722 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1723 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1724 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1725 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1726 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1729 if(gameInfo.variant == VariantGothic) {
1730 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1733 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1734 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1735 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1738 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1739 for(p=0; p<=(int)WhiteKing; p++)
1740 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1741 if(gameInfo.variant == VariantShogi) {
1742 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1743 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1744 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1745 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1746 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1749 if(gameInfo.variant == VariantGothic) {
1750 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1753 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1754 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1755 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1760 for(i=0; i<2; i++) {
1762 for(p=0; p<=(int)WhiteKing; p++)
1763 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1764 if(gameInfo.variant == VariantShogi) {
1765 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1766 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1767 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1768 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1769 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1772 if(gameInfo.variant == VariantGothic) {
1773 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1776 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1777 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1778 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1793 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1794 XSetWindowAttributes window_attributes;
1796 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1797 XrmValue vFrom, vTo;
1798 XtGeometryResult gres;
1801 int forceMono = False;
1803 srandom(time(0)); // [HGM] book: make random truly random
1805 setbuf(stdout, NULL);
1806 setbuf(stderr, NULL);
1809 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1810 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1814 programName = strrchr(argv[0], '/');
1815 if (programName == NULL)
1816 programName = argv[0];
1821 XtSetLanguageProc(NULL, NULL, NULL);
1822 bindtextdomain(PACKAGE, LOCALEDIR);
1823 textdomain(PACKAGE);
1827 XtAppInitialize(&appContext, "XBoard", shellOptions,
1828 XtNumber(shellOptions),
1829 &argc, argv, xboardResources, NULL, 0);
1830 appData.boardSize = "";
1831 InitAppData(ConvertToLine(argc, argv));
1833 if (p == NULL) p = "/tmp";
1834 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1835 gameCopyFilename = (char*) malloc(i);
1836 gamePasteFilename = (char*) malloc(i);
1837 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1838 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1840 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1841 clientResources, XtNumber(clientResources),
1844 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1845 static char buf[MSG_SIZ];
1846 EscapeExpand(buf, appData.initString);
1847 appData.initString = strdup(buf);
1848 EscapeExpand(buf, appData.secondInitString);
1849 appData.secondInitString = strdup(buf);
1850 EscapeExpand(buf, appData.firstComputerString);
1851 appData.firstComputerString = strdup(buf);
1852 EscapeExpand(buf, appData.secondComputerString);
1853 appData.secondComputerString = strdup(buf);
1856 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1859 if (chdir(chessDir) != 0) {
1860 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1866 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1867 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1868 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1869 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1872 setbuf(debugFP, NULL);
1875 /* [HGM,HR] make sure board size is acceptable */
1876 if(appData.NrFiles > BOARD_FILES ||
1877 appData.NrRanks > BOARD_RANKS )
1878 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1881 /* This feature does not work; animation needs a rewrite */
1882 appData.highlightDragging = FALSE;
1886 xDisplay = XtDisplay(shellWidget);
1887 xScreen = DefaultScreen(xDisplay);
1888 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1890 gameInfo.variant = StringToVariant(appData.variant);
1891 InitPosition(FALSE);
1894 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1896 if (isdigit(appData.boardSize[0])) {
1897 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1898 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1899 &fontPxlSize, &smallLayout, &tinyLayout);
1901 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1902 programName, appData.boardSize);
1906 /* Find some defaults; use the nearest known size */
1907 SizeDefaults *szd, *nearest;
1908 int distance = 99999;
1909 nearest = szd = sizeDefaults;
1910 while (szd->name != NULL) {
1911 if (abs(szd->squareSize - squareSize) < distance) {
1913 distance = abs(szd->squareSize - squareSize);
1914 if (distance == 0) break;
1918 if (i < 2) lineGap = nearest->lineGap;
1919 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1920 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1921 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1922 if (i < 6) smallLayout = nearest->smallLayout;
1923 if (i < 7) tinyLayout = nearest->tinyLayout;
1926 SizeDefaults *szd = sizeDefaults;
1927 if (*appData.boardSize == NULLCHAR) {
1928 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1929 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1932 if (szd->name == NULL) szd--;
1933 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1935 while (szd->name != NULL &&
1936 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1937 if (szd->name == NULL) {
1938 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1939 programName, appData.boardSize);
1943 squareSize = szd->squareSize;
1944 lineGap = szd->lineGap;
1945 clockFontPxlSize = szd->clockFontPxlSize;
1946 coordFontPxlSize = szd->coordFontPxlSize;
1947 fontPxlSize = szd->fontPxlSize;
1948 smallLayout = szd->smallLayout;
1949 tinyLayout = szd->tinyLayout;
1950 // [HGM] font: use defaults from settings file if available and not overruled
1952 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1953 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1954 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1955 appData.font = fontTable[MESSAGE_FONT][squareSize];
1956 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1957 appData.coordFont = fontTable[COORD_FONT][squareSize];
1959 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1960 if (strlen(appData.pixmapDirectory) > 0) {
1961 p = ExpandPathName(appData.pixmapDirectory);
1963 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1964 appData.pixmapDirectory);
1967 if (appData.debugMode) {
1968 fprintf(stderr, _("\
1969 XBoard square size (hint): %d\n\
1970 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1972 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1973 if (appData.debugMode) {
1974 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1977 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1979 /* [HR] height treated separately (hacked) */
1980 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1981 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1982 if (appData.showJail == 1) {
1983 /* Jail on top and bottom */
1984 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1985 XtSetArg(boardArgs[2], XtNheight,
1986 boardHeight + 2*(lineGap + squareSize));
1987 } else if (appData.showJail == 2) {
1989 XtSetArg(boardArgs[1], XtNwidth,
1990 boardWidth + 2*(lineGap + squareSize));
1991 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1994 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1995 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1999 * Determine what fonts to use.
2001 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2002 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2003 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2004 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2005 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2006 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2007 appData.font = FindFont(appData.font, fontPxlSize);
2008 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2009 countFontStruct = XQueryFont(xDisplay, countFontID);
2010 // appData.font = FindFont(appData.font, fontPxlSize);
2012 xdb = XtDatabase(xDisplay);
2013 XrmPutStringResource(&xdb, "*font", appData.font);
2016 * Detect if there are not enough colors available and adapt.
2018 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2019 appData.monoMode = True;
2022 if (!appData.monoMode) {
2023 vFrom.addr = (caddr_t) appData.lightSquareColor;
2024 vFrom.size = strlen(appData.lightSquareColor);
2025 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2026 if (vTo.addr == NULL) {
2027 appData.monoMode = True;
2030 lightSquareColor = *(Pixel *) vTo.addr;
2033 if (!appData.monoMode) {
2034 vFrom.addr = (caddr_t) appData.darkSquareColor;
2035 vFrom.size = strlen(appData.darkSquareColor);
2036 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2037 if (vTo.addr == NULL) {
2038 appData.monoMode = True;
2041 darkSquareColor = *(Pixel *) vTo.addr;
2044 if (!appData.monoMode) {
2045 vFrom.addr = (caddr_t) appData.whitePieceColor;
2046 vFrom.size = strlen(appData.whitePieceColor);
2047 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2048 if (vTo.addr == NULL) {
2049 appData.monoMode = True;
2052 whitePieceColor = *(Pixel *) vTo.addr;
2055 if (!appData.monoMode) {
2056 vFrom.addr = (caddr_t) appData.blackPieceColor;
2057 vFrom.size = strlen(appData.blackPieceColor);
2058 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2059 if (vTo.addr == NULL) {
2060 appData.monoMode = True;
2063 blackPieceColor = *(Pixel *) vTo.addr;
2067 if (!appData.monoMode) {
2068 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2069 vFrom.size = strlen(appData.highlightSquareColor);
2070 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2071 if (vTo.addr == NULL) {
2072 appData.monoMode = True;
2075 highlightSquareColor = *(Pixel *) vTo.addr;
2079 if (!appData.monoMode) {
2080 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2081 vFrom.size = strlen(appData.premoveHighlightColor);
2082 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2083 if (vTo.addr == NULL) {
2084 appData.monoMode = True;
2087 premoveHighlightColor = *(Pixel *) vTo.addr;
2092 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2095 if (appData.bitmapDirectory == NULL ||
2096 appData.bitmapDirectory[0] == NULLCHAR)
2097 appData.bitmapDirectory = DEF_BITMAP_DIR;
2100 if (appData.lowTimeWarning && !appData.monoMode) {
2101 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2102 vFrom.size = strlen(appData.lowTimeWarningColor);
2103 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2104 if (vTo.addr == NULL)
2105 appData.monoMode = True;
2107 lowTimeWarningColor = *(Pixel *) vTo.addr;
2110 if (appData.monoMode && appData.debugMode) {
2111 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2112 (unsigned long) XWhitePixel(xDisplay, xScreen),
2113 (unsigned long) XBlackPixel(xDisplay, xScreen));
2116 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2117 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2118 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2119 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2120 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2121 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2122 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2123 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2124 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2125 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2127 if (appData.colorize) {
2129 _("%s: can't parse color names; disabling colorization\n"),
2132 appData.colorize = FALSE;
2134 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2135 textColors[ColorNone].attr = 0;
2137 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2143 layoutName = "tinyLayout";
2144 } else if (smallLayout) {
2145 layoutName = "smallLayout";
2147 layoutName = "normalLayout";
2149 /* Outer layoutWidget is there only to provide a name for use in
2150 resources that depend on the layout style */
2152 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2153 layoutArgs, XtNumber(layoutArgs));
2155 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2156 formArgs, XtNumber(formArgs));
2157 XtSetArg(args[0], XtNdefaultDistance, &sep);
2158 XtGetValues(formWidget, args, 1);
2161 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2162 XtSetArg(args[0], XtNtop, XtChainTop);
2163 XtSetArg(args[1], XtNbottom, XtChainTop);
2164 XtSetArg(args[2], XtNright, XtChainLeft);
2165 XtSetValues(menuBarWidget, args, 3);
2167 widgetList[j++] = whiteTimerWidget =
2168 XtCreateWidget("whiteTime", labelWidgetClass,
2169 formWidget, timerArgs, XtNumber(timerArgs));
2170 XtSetArg(args[0], XtNfont, clockFontStruct);
2171 XtSetArg(args[1], XtNtop, XtChainTop);
2172 XtSetArg(args[2], XtNbottom, XtChainTop);
2173 XtSetValues(whiteTimerWidget, args, 3);
2175 widgetList[j++] = blackTimerWidget =
2176 XtCreateWidget("blackTime", labelWidgetClass,
2177 formWidget, timerArgs, XtNumber(timerArgs));
2178 XtSetArg(args[0], XtNfont, clockFontStruct);
2179 XtSetArg(args[1], XtNtop, XtChainTop);
2180 XtSetArg(args[2], XtNbottom, XtChainTop);
2181 XtSetValues(blackTimerWidget, args, 3);
2183 if (appData.titleInWindow) {
2184 widgetList[j++] = titleWidget =
2185 XtCreateWidget("title", labelWidgetClass, formWidget,
2186 titleArgs, XtNumber(titleArgs));
2187 XtSetArg(args[0], XtNtop, XtChainTop);
2188 XtSetArg(args[1], XtNbottom, XtChainTop);
2189 XtSetValues(titleWidget, args, 2);
2192 if (appData.showButtonBar) {
2193 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2194 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2195 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2196 XtSetArg(args[2], XtNtop, XtChainTop);
2197 XtSetArg(args[3], XtNbottom, XtChainTop);
2198 XtSetValues(buttonBarWidget, args, 4);
2201 widgetList[j++] = messageWidget =
2202 XtCreateWidget("message", labelWidgetClass, formWidget,
2203 messageArgs, XtNumber(messageArgs));
2204 XtSetArg(args[0], XtNtop, XtChainTop);
2205 XtSetArg(args[1], XtNbottom, XtChainTop);
2206 XtSetValues(messageWidget, args, 2);
2208 widgetList[j++] = boardWidget =
2209 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2210 XtNumber(boardArgs));
2212 XtManageChildren(widgetList, j);
2214 timerWidth = (boardWidth - sep) / 2;
2215 XtSetArg(args[0], XtNwidth, timerWidth);
2216 XtSetValues(whiteTimerWidget, args, 1);
2217 XtSetValues(blackTimerWidget, args, 1);
2219 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2220 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2221 XtGetValues(whiteTimerWidget, args, 2);
2223 if (appData.showButtonBar) {
2224 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2225 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2226 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2230 * formWidget uses these constraints but they are stored
2234 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2235 XtSetValues(menuBarWidget, args, i);
2236 if (appData.titleInWindow) {
2239 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2240 XtSetValues(whiteTimerWidget, args, i);
2242 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2243 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2244 XtSetValues(blackTimerWidget, args, i);
2246 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2247 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2248 XtSetValues(titleWidget, args, i);
2250 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2251 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2252 XtSetValues(messageWidget, args, i);
2253 if (appData.showButtonBar) {
2255 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2257 XtSetValues(buttonBarWidget, args, i);
2261 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2262 XtSetValues(whiteTimerWidget, args, i);
2264 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2265 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2266 XtSetValues(blackTimerWidget, args, i);
2268 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2269 XtSetValues(titleWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2272 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2273 XtSetValues(messageWidget, args, i);
2274 if (appData.showButtonBar) {
2276 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2277 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2278 XtSetValues(buttonBarWidget, args, i);
2283 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2284 XtSetValues(whiteTimerWidget, args, i);
2286 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2287 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2288 XtSetValues(blackTimerWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2291 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2292 XtSetValues(messageWidget, args, i);
2293 if (appData.showButtonBar) {
2295 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2296 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2297 XtSetValues(buttonBarWidget, args, i);
2301 XtSetArg(args[0], XtNfromVert, messageWidget);
2302 XtSetArg(args[1], XtNtop, XtChainTop);
2303 XtSetArg(args[2], XtNbottom, XtChainBottom);
2304 XtSetArg(args[3], XtNleft, XtChainLeft);
2305 XtSetArg(args[4], XtNright, XtChainRight);
2306 XtSetValues(boardWidget, args, 5);
2308 XtRealizeWidget(shellWidget);
2311 XtSetArg(args[0], XtNx, wpMain.x);
2312 XtSetArg(args[1], XtNy, wpMain.y);
2313 XtSetValues(shellWidget, args, 2);
2317 * Correct the width of the message and title widgets.
2318 * It is not known why some systems need the extra fudge term.
2319 * The value "2" is probably larger than needed.
2321 XawFormDoLayout(formWidget, False);
2323 #define WIDTH_FUDGE 2
2325 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2326 XtSetArg(args[i], XtNheight, &h); i++;
2327 XtGetValues(messageWidget, args, i);
2328 if (appData.showButtonBar) {
2330 XtSetArg(args[i], XtNwidth, &w); i++;
2331 XtGetValues(buttonBarWidget, args, i);
2332 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2334 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2337 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2338 if (gres != XtGeometryYes && appData.debugMode) {
2339 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2340 programName, gres, w, h, wr, hr);
2343 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2344 /* The size used for the child widget in layout lags one resize behind
2345 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2347 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2348 if (gres != XtGeometryYes && appData.debugMode) {
2349 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2350 programName, gres, w, h, wr, hr);
2353 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2354 XtSetArg(args[1], XtNright, XtChainRight);
2355 XtSetValues(messageWidget, args, 2);
2357 if (appData.titleInWindow) {
2359 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2360 XtSetArg(args[i], XtNheight, &h); i++;
2361 XtGetValues(titleWidget, args, i);
2363 w = boardWidth - 2*bor;
2365 XtSetArg(args[0], XtNwidth, &w);
2366 XtGetValues(menuBarWidget, args, 1);
2367 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2370 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2371 if (gres != XtGeometryYes && appData.debugMode) {
2373 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2374 programName, gres, w, h, wr, hr);
2377 XawFormDoLayout(formWidget, True);
2379 xBoardWindow = XtWindow(boardWidget);
2381 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2382 // not need to go into InitDrawingSizes().
2386 * Create X checkmark bitmap and initialize option menu checks.
2388 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2389 checkmark_bits, checkmark_width, checkmark_height);
2390 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2391 if (appData.alwaysPromoteToQueen) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2395 if (appData.animateDragging) {
2396 XtSetValues(XtNameToWidget(menuBarWidget,
2397 "menuOptions.Animate Dragging"),
2400 if (appData.animate) {
2401 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2404 if (appData.autoComment) {
2405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2408 if (appData.autoCallFlag) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2412 if (appData.autoFlipView) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2416 if (appData.autoObserve) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2420 if (appData.autoRaiseBoard) {
2421 XtSetValues(XtNameToWidget(menuBarWidget,
2422 "menuOptions.Auto Raise Board"), args, 1);
2424 if (appData.autoSaveGames) {
2425 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2428 if (appData.saveGameFile[0] != NULLCHAR) {
2429 /* Can't turn this off from menu */
2430 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2432 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2436 if (appData.blindfold) {
2437 XtSetValues(XtNameToWidget(menuBarWidget,
2438 "menuOptions.Blindfold"), args, 1);
2440 if (appData.flashCount > 0) {
2441 XtSetValues(XtNameToWidget(menuBarWidget,
2442 "menuOptions.Flash Moves"),
2445 if (appData.getMoveList) {
2446 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2450 if (appData.highlightDragging) {
2451 XtSetValues(XtNameToWidget(menuBarWidget,
2452 "menuOptions.Highlight Dragging"),
2456 if (appData.highlightLastMove) {
2457 XtSetValues(XtNameToWidget(menuBarWidget,
2458 "menuOptions.Highlight Last Move"),
2461 if (appData.icsAlarm) {
2462 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2465 if (appData.ringBellAfterMoves) {
2466 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2469 if (appData.oldSaveStyle) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Old Save Style"), args, 1);
2473 if (appData.periodicUpdates) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Periodic Updates"), args, 1);
2477 if (appData.ponderNextMove) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Ponder Next Move"), args, 1);
2481 if (appData.popupExitMessage) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Popup Exit Message"), args, 1);
2485 if (appData.popupMoveErrors) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Popup Move Errors"), args, 1);
2489 if (appData.premove) {
2490 XtSetValues(XtNameToWidget(menuBarWidget,
2491 "menuOptions.Premove"), args, 1);
2493 if (appData.quietPlay) {
2494 XtSetValues(XtNameToWidget(menuBarWidget,
2495 "menuOptions.Quiet Play"), args, 1);
2497 if (appData.showCoords) {
2498 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2501 if (appData.hideThinkingFromHuman) {
2502 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2505 if (appData.testLegality) {
2506 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2509 if (saveSettingsOnExit) {
2510 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2517 ReadBitmap(&wIconPixmap, "icon_white.bm",
2518 icon_white_bits, icon_white_width, icon_white_height);
2519 ReadBitmap(&bIconPixmap, "icon_black.bm",
2520 icon_black_bits, icon_black_width, icon_black_height);
2521 iconPixmap = wIconPixmap;
2523 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2524 XtSetValues(shellWidget, args, i);
2527 * Create a cursor for the board widget.
2529 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2530 XChangeWindowAttributes(xDisplay, xBoardWindow,
2531 CWCursor, &window_attributes);
2534 * Inhibit shell resizing.
2536 shellArgs[0].value = (XtArgVal) &w;
2537 shellArgs[1].value = (XtArgVal) &h;
2538 XtGetValues(shellWidget, shellArgs, 2);
2539 shellArgs[4].value = shellArgs[2].value = w;
2540 shellArgs[5].value = shellArgs[3].value = h;
2541 XtSetValues(shellWidget, &shellArgs[2], 4);
2542 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2543 marginH = h - boardHeight;
2545 CatchDeleteWindow(shellWidget, "QuitProc");
2550 if (appData.bitmapDirectory[0] != NULLCHAR) {
2554 CreateXPMBoard(appData.liteBackTextureFile, 1);
2555 CreateXPMBoard(appData.darkBackTextureFile, 0);
2559 /* Create regular pieces */
2560 if (!useImages) CreatePieces();
2565 if (appData.animate || appData.animateDragging)
2568 XtAugmentTranslations(formWidget,
2569 XtParseTranslationTable(globalTranslations));
2570 XtAugmentTranslations(boardWidget,
2571 XtParseTranslationTable(boardTranslations));
2572 XtAugmentTranslations(whiteTimerWidget,
2573 XtParseTranslationTable(whiteTranslations));
2574 XtAugmentTranslations(blackTimerWidget,
2575 XtParseTranslationTable(blackTranslations));
2577 /* Why is the following needed on some versions of X instead
2578 * of a translation? */
2579 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2580 (XtEventHandler) EventProc, NULL);
2583 /* [AS] Restore layout */
2584 if( wpMoveHistory.visible ) {
2588 if( wpEvalGraph.visible )
2593 if( wpEngineOutput.visible ) {
2594 EngineOutputPopUp();
2599 if (errorExitStatus == -1) {
2600 if (appData.icsActive) {
2601 /* We now wait until we see "login:" from the ICS before
2602 sending the logon script (problems with timestamp otherwise) */
2603 /*ICSInitScript();*/
2604 if (appData.icsInputBox) ICSInputBoxPopUp();
2608 signal(SIGWINCH, TermSizeSigHandler);
2610 signal(SIGINT, IntSigHandler);
2611 signal(SIGTERM, IntSigHandler);
2612 if (*appData.cmailGameName != NULLCHAR) {
2613 signal(SIGUSR1, CmailSigHandler);
2616 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2618 XtSetKeyboardFocus(shellWidget, formWidget);
2620 XtAppMainLoop(appContext);
2621 if (appData.debugMode) fclose(debugFP); // [DM] debug
2628 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2629 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2631 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2632 unlink(gameCopyFilename);
2633 unlink(gamePasteFilename);
2636 RETSIGTYPE TermSizeSigHandler(int sig)
2649 CmailSigHandler(sig)
2655 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2657 /* Activate call-back function CmailSigHandlerCallBack() */
2658 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2660 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2664 CmailSigHandlerCallBack(isr, closure, message, count, error)
2672 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2674 /**** end signal code ****/
2680 /* try to open the icsLogon script, either in the location given
2681 * or in the users HOME directory
2688 f = fopen(appData.icsLogon, "r");
2691 homedir = getenv("HOME");
2692 if (homedir != NULL)
2694 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2695 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2696 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2697 f = fopen(buf, "r");
2702 ProcessICSInitScript(f);
2704 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2713 EditCommentPopDown();
2728 if (!menuBarWidget) return;
2729 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2731 DisplayError("menuEdit.Revert", 0);
2733 XtSetSensitive(w, !grey);
2735 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2737 DisplayError("menuEdit.Annotate", 0);
2739 XtSetSensitive(w, !grey);
2744 SetMenuEnables(enab)
2748 if (!menuBarWidget) return;
2749 while (enab->name != NULL) {
2750 w = XtNameToWidget(menuBarWidget, enab->name);
2752 DisplayError(enab->name, 0);
2754 XtSetSensitive(w, enab->value);
2760 Enables icsEnables[] = {
2761 { "menuFile.Mail Move", False },
2762 { "menuFile.Reload CMail Message", False },
2763 { "menuMode.Machine Black", False },
2764 { "menuMode.Machine White", False },
2765 { "menuMode.Analysis Mode", False },
2766 { "menuMode.Analyze File", False },
2767 { "menuMode.Two Machines", False },
2769 { "menuHelp.Hint", False },
2770 { "menuHelp.Book", False },
2771 { "menuEngine.Move Now", False },
2772 { "menuOptions.Periodic Updates", False },
2773 { "menuOptions.Hide Thinking", False },
2774 { "menuOptions.Ponder Next Move", False },
2775 { "menuEngine.Engine #1 Settings", False },
2777 { "menuEngine.Engine #2 Settings", False },
2778 { "menuEdit.Annotate", False },
2782 Enables ncpEnables[] = {
2783 { "menuFile.Mail Move", False },
2784 { "menuFile.Reload CMail Message", False },
2785 { "menuMode.Machine White", False },
2786 { "menuMode.Machine Black", False },
2787 { "menuMode.Analysis Mode", False },
2788 { "menuMode.Analyze File", False },
2789 { "menuMode.Two Machines", False },
2790 { "menuMode.ICS Client", False },
2791 { "menuView.ICS Input Box", False },
2792 { "Action", False },
2793 { "menuEdit.Revert", False },
2794 { "menuEdit.Annotate", False },
2795 { "menuEngine.Engine #1 Settings", False },
2796 { "menuEngine.Engine #2 Settings", False },
2797 { "menuEngine.Move Now", False },
2798 { "menuEngine.Retract Move", False },
2799 { "menuOptions.Auto Comment", False },
2800 { "menuOptions.Auto Flag", False },
2801 { "menuOptions.Auto Flip View", False },
2802 { "menuOptions.Auto Observe", False },
2803 { "menuOptions.Auto Raise Board", False },
2804 { "menuOptions.Get Move List", False },
2805 { "menuOptions.ICS Alarm", False },
2806 { "menuOptions.Move Sound", False },
2807 { "menuOptions.Quiet Play", False },
2808 { "menuOptions.Hide Thinking", False },
2809 { "menuOptions.Periodic Updates", False },
2810 { "menuOptions.Ponder Next Move", False },
2811 { "menuHelp.Hint", False },
2812 { "menuHelp.Book", False },
2816 Enables gnuEnables[] = {
2817 { "menuMode.ICS Client", False },
2818 { "menuView.ICS Input Box", False },
2819 { "menuAction.Accept", False },
2820 { "menuAction.Decline", False },
2821 { "menuAction.Rematch", False },
2822 { "menuAction.Adjourn", False },
2823 { "menuAction.Stop Examining", False },
2824 { "menuAction.Stop Observing", False },
2825 { "menuAction.Upload to Examine", False },
2826 { "menuEdit.Revert", False },
2827 { "menuEdit.Annotate", False },
2828 { "menuOptions.Auto Comment", False },
2829 { "menuOptions.Auto Observe", False },
2830 { "menuOptions.Auto Raise Board", False },
2831 { "menuOptions.Get Move List", False },
2832 { "menuOptions.Premove", False },
2833 { "menuOptions.Quiet Play", False },
2835 /* The next two options rely on SetCmailMode being called *after* */
2836 /* SetGNUMode so that when GNU is being used to give hints these */
2837 /* menu options are still available */
2839 { "menuFile.Mail Move", False },
2840 { "menuFile.Reload CMail Message", False },
2844 Enables cmailEnables[] = {
2846 { "menuAction.Call Flag", False },
2847 { "menuAction.Draw", True },
2848 { "menuAction.Adjourn", False },
2849 { "menuAction.Abort", False },
2850 { "menuAction.Stop Observing", False },
2851 { "menuAction.Stop Examining", False },
2852 { "menuFile.Mail Move", True },
2853 { "menuFile.Reload CMail Message", True },
2857 Enables trainingOnEnables[] = {
2858 { "menuMode.Edit Comment", False },
2859 { "menuMode.Pause", False },
2860 { "menuEdit.Forward", False },
2861 { "menuEdit.Backward", False },
2862 { "menuEdit.Forward to End", False },
2863 { "menuEdit.Back to Start", False },
2864 { "menuEngine.Move Now", False },
2865 { "menuEdit.Truncate Game", False },
2869 Enables trainingOffEnables[] = {
2870 { "menuMode.Edit Comment", True },
2871 { "menuMode.Pause", True },
2872 { "menuEdit.Forward", True },
2873 { "menuEdit.Backward", True },
2874 { "menuEdit.Forward to End", True },
2875 { "menuEdit.Back to Start", True },
2876 { "menuEngine.Move Now", True },
2877 { "menuEdit.Truncate Game", True },
2881 Enables machineThinkingEnables[] = {
2882 { "menuFile.Load Game", False },
2883 // { "menuFile.Load Next Game", False },
2884 // { "menuFile.Load Previous Game", False },
2885 // { "menuFile.Reload Same Game", False },
2886 { "menuEdit.Paste Game", False },
2887 { "menuFile.Load Position", False },
2888 // { "menuFile.Load Next Position", False },
2889 // { "menuFile.Load Previous Position", False },
2890 // { "menuFile.Reload Same Position", False },
2891 { "menuEdit.Paste Position", False },
2892 { "menuMode.Machine White", False },
2893 { "menuMode.Machine Black", False },
2894 { "menuMode.Two Machines", False },
2895 { "menuEngine.Retract Move", False },
2899 Enables userThinkingEnables[] = {
2900 { "menuFile.Load Game", True },
2901 // { "menuFile.Load Next Game", True },
2902 // { "menuFile.Load Previous Game", True },
2903 // { "menuFile.Reload Same Game", True },
2904 { "menuEdit.Paste Game", True },
2905 { "menuFile.Load Position", True },
2906 // { "menuFile.Load Next Position", True },
2907 // { "menuFile.Load Previous Position", True },
2908 // { "menuFile.Reload Same Position", True },
2909 { "menuEdit.Paste Position", True },
2910 { "menuMode.Machine White", True },
2911 { "menuMode.Machine Black", True },
2912 { "menuMode.Two Machines", True },
2913 { "menuEngine.Retract Move", True },
2919 SetMenuEnables(icsEnables);
2922 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2923 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2930 SetMenuEnables(ncpEnables);
2936 SetMenuEnables(gnuEnables);
2942 SetMenuEnables(cmailEnables);
2948 SetMenuEnables(trainingOnEnables);
2949 if (appData.showButtonBar) {
2950 XtSetSensitive(buttonBarWidget, False);
2956 SetTrainingModeOff()
2958 SetMenuEnables(trainingOffEnables);
2959 if (appData.showButtonBar) {
2960 XtSetSensitive(buttonBarWidget, True);
2965 SetUserThinkingEnables()
2967 if (appData.noChessProgram) return;
2968 SetMenuEnables(userThinkingEnables);
2972 SetMachineThinkingEnables()
2974 if (appData.noChessProgram) return;
2975 SetMenuEnables(machineThinkingEnables);
2977 case MachinePlaysBlack:
2978 case MachinePlaysWhite:
2979 case TwoMachinesPlay:
2980 XtSetSensitive(XtNameToWidget(menuBarWidget,
2981 ModeToWidgetName(gameMode)), True);
2988 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2989 #define HISTORY_SIZE 64
\r
2990 static char *history[HISTORY_SIZE];
\r
2991 int histIn = 0, histP = 0;
\r
2994 SaveInHistory(char *cmd)
\r
2996 if (history[histIn] != NULL) {
\r
2997 free(history[histIn]);
\r
2998 history[histIn] = NULL;
\r
3000 if (*cmd == NULLCHAR) return;
\r
3001 history[histIn] = StrSave(cmd);
\r
3002 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3003 if (history[histIn] != NULL) {
\r
3004 free(history[histIn]);
\r
3005 history[histIn] = NULL;
\r
3011 PrevInHistory(char *cmd)
\r
3014 if (histP == histIn) {
\r
3015 if (history[histIn] != NULL) free(history[histIn]);
\r
3016 history[histIn] = StrSave(cmd);
\r
3018 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3019 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3021 return history[histP];
\r
3027 if (histP == histIn) return NULL;
\r
3028 histP = (histP + 1) % HISTORY_SIZE;
\r
3029 return history[histP];
\r
3031 // end of borrowed code
\r
3033 #define Abs(n) ((n)<0 ? -(n) : (n))
3036 * Find a font that matches "pattern" that is as close as
3037 * possible to the targetPxlSize. Prefer fonts that are k
3038 * pixels smaller to fonts that are k pixels larger. The
3039 * pattern must be in the X Consortium standard format,
3040 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3041 * The return value should be freed with XtFree when no
3045 FindFont(pattern, targetPxlSize)
3049 char **fonts, *p, *best, *scalable, *scalableTail;
3050 int i, j, nfonts, minerr, err, pxlSize;
3053 char **missing_list;
3055 char *def_string, *base_fnt_lst, strInt[3];
3057 XFontStruct **fnt_list;
3059 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3060 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3061 p = strstr(pattern, "--");
3062 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3063 strcat(base_fnt_lst, strInt);
3064 strcat(base_fnt_lst, strchr(p + 2, '-'));
3066 if ((fntSet = XCreateFontSet(xDisplay,
3070 &def_string)) == NULL) {
3072 fprintf(stderr, _("Unable to create font set.\n"));
3076 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3078 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3080 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3081 programName, pattern);
3089 for (i=0; i<nfonts; i++) {
3092 if (*p != '-') continue;
3094 if (*p == NULLCHAR) break;
3095 if (*p++ == '-') j++;
3097 if (j < 7) continue;
3100 scalable = fonts[i];
3103 err = pxlSize - targetPxlSize;
3104 if (Abs(err) < Abs(minerr) ||
3105 (minerr > 0 && err < 0 && -err == minerr)) {
3111 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3112 /* If the error is too big and there is a scalable font,
3113 use the scalable font. */
3114 int headlen = scalableTail - scalable;
3115 p = (char *) XtMalloc(strlen(scalable) + 10);
3116 while (isdigit(*scalableTail)) scalableTail++;
3117 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3119 p = (char *) XtMalloc(strlen(best) + 2);
3120 safeStrCpy(p, best, strlen(best)+1 );
3122 if (appData.debugMode) {
3123 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3124 pattern, targetPxlSize, p);
3127 if (missing_count > 0)
3128 XFreeStringList(missing_list);
3129 XFreeFontSet(xDisplay, fntSet);
3131 XFreeFontNames(fonts);
3138 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3139 | GCBackground | GCFunction | GCPlaneMask;
3140 XGCValues gc_values;
3143 gc_values.plane_mask = AllPlanes;
3144 gc_values.line_width = lineGap;
3145 gc_values.line_style = LineSolid;
3146 gc_values.function = GXcopy;
3148 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3149 gc_values.background = XBlackPixel(xDisplay, xScreen);
3150 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3152 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3153 gc_values.background = XWhitePixel(xDisplay, xScreen);
3154 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3155 XSetFont(xDisplay, coordGC, coordFontID);
3157 // [HGM] make font for holdings counts (white on black0
3158 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3159 gc_values.background = XBlackPixel(xDisplay, xScreen);
3160 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 XSetFont(xDisplay, countGC, countFontID);
3163 if (appData.monoMode) {
3164 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3165 gc_values.background = XWhitePixel(xDisplay, xScreen);
3166 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XBlackPixel(xDisplay, xScreen);
3170 lightSquareGC = wbPieceGC
3171 = XtGetGC(shellWidget, value_mask, &gc_values);
3173 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3174 gc_values.background = XWhitePixel(xDisplay, xScreen);
3175 darkSquareGC = bwPieceGC
3176 = XtGetGC(shellWidget, value_mask, &gc_values);
3178 if (DefaultDepth(xDisplay, xScreen) == 1) {
3179 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3180 gc_values.function = GXcopyInverted;
3181 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3182 gc_values.function = GXcopy;
3183 if (XBlackPixel(xDisplay, xScreen) == 1) {
3184 bwPieceGC = darkSquareGC;
3185 wbPieceGC = copyInvertedGC;
3187 bwPieceGC = copyInvertedGC;
3188 wbPieceGC = lightSquareGC;
3192 gc_values.foreground = highlightSquareColor;
3193 gc_values.background = highlightSquareColor;
3194 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 gc_values.foreground = premoveHighlightColor;
3197 gc_values.background = premoveHighlightColor;
3198 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = lightSquareColor;
3201 gc_values.background = darkSquareColor;
3202 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = darkSquareColor;
3205 gc_values.background = lightSquareColor;
3206 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = jailSquareColor;
3209 gc_values.background = jailSquareColor;
3210 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = whitePieceColor;
3213 gc_values.background = darkSquareColor;
3214 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = whitePieceColor;
3217 gc_values.background = lightSquareColor;
3218 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = whitePieceColor;
3221 gc_values.background = jailSquareColor;
3222 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = blackPieceColor;
3225 gc_values.background = darkSquareColor;
3226 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3228 gc_values.foreground = blackPieceColor;
3229 gc_values.background = lightSquareColor;
3230 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3232 gc_values.foreground = blackPieceColor;
3233 gc_values.background = jailSquareColor;
3234 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 void loadXIM(xim, xmask, filename, dest, mask)
3251 fp = fopen(filename, "rb");
3253 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3260 for (y=0; y<h; ++y) {
3261 for (x=0; x<h; ++x) {
3266 XPutPixel(xim, x, y, blackPieceColor);
3268 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3271 XPutPixel(xim, x, y, darkSquareColor);
3273 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3276 XPutPixel(xim, x, y, whitePieceColor);
3278 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3281 XPutPixel(xim, x, y, lightSquareColor);
3283 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3289 /* create Pixmap of piece */
3290 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3292 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3295 /* create Pixmap of clipmask
3296 Note: We assume the white/black pieces have the same
3297 outline, so we make only 6 masks. This is okay
3298 since the XPM clipmask routines do the same. */
3300 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3302 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3305 /* now create the 1-bit version */
3306 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3309 values.foreground = 1;
3310 values.background = 0;
3312 /* Don't use XtGetGC, not read only */
3313 maskGC = XCreateGC(xDisplay, *mask,
3314 GCForeground | GCBackground, &values);
3315 XCopyPlane(xDisplay, temp, *mask, maskGC,
3316 0, 0, squareSize, squareSize, 0, 0, 1);
3317 XFreePixmap(xDisplay, temp);
3322 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3324 void CreateXIMPieces()
3329 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3334 /* The XSynchronize calls were copied from CreatePieces.
3335 Not sure if needed, but can't hurt */
3336 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3339 /* temp needed by loadXIM() */
3340 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3341 0, 0, ss, ss, AllPlanes, XYPixmap);
3343 if (strlen(appData.pixmapDirectory) == 0) {
3347 if (appData.monoMode) {
3348 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3352 fprintf(stderr, _("\nLoading XIMs...\n"));
3354 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3355 fprintf(stderr, "%d", piece+1);
3356 for (kind=0; kind<4; kind++) {
3357 fprintf(stderr, ".");
3358 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3359 ExpandPathName(appData.pixmapDirectory),
3360 piece <= (int) WhiteKing ? "" : "w",
3361 pieceBitmapNames[piece],
3363 ximPieceBitmap[kind][piece] =
3364 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3365 0, 0, ss, ss, AllPlanes, XYPixmap);
3366 if (appData.debugMode)
3367 fprintf(stderr, _("(File:%s:) "), buf);
3368 loadXIM(ximPieceBitmap[kind][piece],
3370 &(xpmPieceBitmap2[kind][piece]),
3371 &(ximMaskPm2[piece]));
3372 if(piece <= (int)WhiteKing)
3373 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3375 fprintf(stderr," ");
3377 /* Load light and dark squares */
3378 /* If the LSQ and DSQ pieces don't exist, we will
3379 draw them with solid squares. */
3380 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3381 if (access(buf, 0) != 0) {
3385 fprintf(stderr, _("light square "));
3387 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3388 0, 0, ss, ss, AllPlanes, XYPixmap);
3389 if (appData.debugMode)
3390 fprintf(stderr, _("(File:%s:) "), buf);
3392 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3393 fprintf(stderr, _("dark square "));
3394 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3395 ExpandPathName(appData.pixmapDirectory), ss);
3396 if (appData.debugMode)
3397 fprintf(stderr, _("(File:%s:) "), buf);
3399 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3400 0, 0, ss, ss, AllPlanes, XYPixmap);
3401 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3402 xpmJailSquare = xpmLightSquare;
3404 fprintf(stderr, _("Done.\n"));
3406 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3410 void CreateXPMBoard(char *s, int kind)
3414 if(s == NULL || *s == 0 || *s == '*') return;
3415 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3416 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3420 void CreateXPMPieces()
3424 u_int ss = squareSize;
3426 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3427 XpmColorSymbol symbols[4];
3429 /* The XSynchronize calls were copied from CreatePieces.
3430 Not sure if needed, but can't hurt */
3431 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3433 /* Setup translations so piece colors match square colors */
3434 symbols[0].name = "light_piece";
3435 symbols[0].value = appData.whitePieceColor;
3436 symbols[1].name = "dark_piece";
3437 symbols[1].value = appData.blackPieceColor;
3438 symbols[2].name = "light_square";
3439 symbols[2].value = appData.lightSquareColor;
3440 symbols[3].name = "dark_square";
3441 symbols[3].value = appData.darkSquareColor;
3443 attr.valuemask = XpmColorSymbols;
3444 attr.colorsymbols = symbols;
3445 attr.numsymbols = 4;
3447 if (appData.monoMode) {
3448 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3452 if (strlen(appData.pixmapDirectory) == 0) {
3453 XpmPieces* pieces = builtInXpms;
3456 while (pieces->size != squareSize && pieces->size) pieces++;
3457 if (!pieces->size) {
3458 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3462 for (kind=0; kind<4; kind++) {
3464 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3465 pieces->xpm[piece][kind],
3466 &(xpmPieceBitmap2[kind][piece]),
3467 NULL, &attr)) != 0) {
3468 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3472 if(piece <= (int) WhiteKing)
3473 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3477 xpmJailSquare = xpmLightSquare;
3481 fprintf(stderr, _("\nLoading XPMs...\n"));
3484 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3485 fprintf(stderr, "%d ", piece+1);
3486 for (kind=0; kind<4; kind++) {
3487 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3488 ExpandPathName(appData.pixmapDirectory),
3489 piece > (int) WhiteKing ? "w" : "",
3490 pieceBitmapNames[piece],
3492 if (appData.debugMode) {
3493 fprintf(stderr, _("(File:%s:) "), buf);
3495 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3496 &(xpmPieceBitmap2[kind][piece]),
3497 NULL, &attr)) != 0) {
3498 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3499 // [HGM] missing: read of unorthodox piece failed; substitute King.
3500 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3501 ExpandPathName(appData.pixmapDirectory),
3503 if (appData.debugMode) {
3504 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3506 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3507 &(xpmPieceBitmap2[kind][piece]),
3511 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3516 if(piece <= (int) WhiteKing)
3517 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3520 /* Load light and dark squares */
3521 /* If the LSQ and DSQ pieces don't exist, we will
3522 draw them with solid squares. */
3523 fprintf(stderr, _("light square "));
3524 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3525 if (access(buf, 0) != 0) {
3529 if (appData.debugMode)
3530 fprintf(stderr, _("(File:%s:) "), buf);
3532 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3533 &xpmLightSquare, NULL, &attr)) != 0) {
3534 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3537 fprintf(stderr, _("dark square "));
3538 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3539 ExpandPathName(appData.pixmapDirectory), ss);
3540 if (appData.debugMode) {
3541 fprintf(stderr, _("(File:%s:) "), buf);
3543 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3544 &xpmDarkSquare, NULL, &attr)) != 0) {
3545 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3549 xpmJailSquare = xpmLightSquare;
3550 fprintf(stderr, _("Done.\n"));
3552 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3555 #endif /* HAVE_LIBXPM */
3558 /* No built-in bitmaps */
3563 u_int ss = squareSize;
3565 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3568 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3569 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3570 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3571 pieceBitmapNames[piece],
3572 ss, kind == SOLID ? 's' : 'o');
3573 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3574 if(piece <= (int)WhiteKing)
3575 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3579 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3583 /* With built-in bitmaps */
3586 BuiltInBits* bib = builtInBits;
3589 u_int ss = squareSize;
3591 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3594 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3596 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3597 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3598 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3599 pieceBitmapNames[piece],
3600 ss, kind == SOLID ? 's' : 'o');
3601 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3602 bib->bits[kind][piece], ss, ss);
3603 if(piece <= (int)WhiteKing)
3604 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3608 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3613 void ReadBitmap(pm, name, bits, wreq, hreq)
3616 unsigned char bits[];
3622 char msg[MSG_SIZ], fullname[MSG_SIZ];
3624 if (*appData.bitmapDirectory != NULLCHAR) {
3625 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3626 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3627 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3628 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3629 &w, &h, pm, &x_hot, &y_hot);
3630 fprintf(stderr, "load %s\n", name);
3631 if (errcode != BitmapSuccess) {
3633 case BitmapOpenFailed:
3634 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3636 case BitmapFileInvalid:
3637 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3639 case BitmapNoMemory:
3640 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3644 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3648 fprintf(stderr, _("%s: %s...using built-in\n"),
3650 } else if (w != wreq || h != hreq) {
3652 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3653 programName, fullname, w, h, wreq, hreq);
3659 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3668 if (lineGap == 0) return;
3670 /* [HR] Split this into 2 loops for non-square boards. */
3672 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3673 gridSegments[i].x1 = 0;
3674 gridSegments[i].x2 =
3675 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3676 gridSegments[i].y1 = gridSegments[i].y2
3677 = lineGap / 2 + (i * (squareSize + lineGap));
3680 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3681 gridSegments[j + i].y1 = 0;
3682 gridSegments[j + i].y2 =
3683 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3684 gridSegments[j + i].x1 = gridSegments[j + i].x2
3685 = lineGap / 2 + (j * (squareSize + lineGap));
3689 static void MenuBarSelect(w, addr, index)
3694 XtActionProc proc = (XtActionProc) addr;
3696 (proc)(NULL, NULL, NULL, NULL);
3699 void CreateMenuBarPopup(parent, name, mb)
3709 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3712 XtSetArg(args[j], XtNleftMargin, 20); j++;
3713 XtSetArg(args[j], XtNrightMargin, 20); j++;
3715 while (mi->string != NULL) {
3716 if (strcmp(mi->string, "----") == 0) {
3717 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3720 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3721 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3723 XtAddCallback(entry, XtNcallback,
3724 (XtCallbackProc) MenuBarSelect,
3725 (caddr_t) mi->proc);
3731 Widget CreateMenuBar(mb)
3735 Widget anchor, menuBar;
3737 char menuName[MSG_SIZ];
3740 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3741 XtSetArg(args[j], XtNvSpace, 0); j++;
3742 XtSetArg(args[j], XtNborderWidth, 0); j++;
3743 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3744 formWidget, args, j);
3746 while (mb->name != NULL) {
3747 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3748 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3750 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3753 shortName[0] = _(mb->name)[0];
3754 shortName[1] = NULLCHAR;
3755 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3758 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3761 XtSetArg(args[j], XtNborderWidth, 0); j++;
3762 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3764 CreateMenuBarPopup(menuBar, menuName, mb);
3770 Widget CreateButtonBar(mi)
3774 Widget button, buttonBar;
3778 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3780 XtSetArg(args[j], XtNhSpace, 0); j++;
3782 XtSetArg(args[j], XtNborderWidth, 0); j++;
3783 XtSetArg(args[j], XtNvSpace, 0); j++;
3784 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3785 formWidget, args, j);
3787 while (mi->string != NULL) {
3790 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3791 XtSetArg(args[j], XtNborderWidth, 0); j++;
3793 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3794 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3795 buttonBar, args, j);
3796 XtAddCallback(button, XtNcallback,
3797 (XtCallbackProc) MenuBarSelect,
3798 (caddr_t) mi->proc);
3805 CreatePieceMenu(name, color)
3812 ChessSquare selection;
3814 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3815 boardWidget, args, 0);
3817 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3818 String item = pieceMenuStrings[color][i];
3820 if (strcmp(item, "----") == 0) {
3821 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3824 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3825 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3827 selection = pieceMenuTranslation[color][i];
3828 XtAddCallback(entry, XtNcallback,
3829 (XtCallbackProc) PieceMenuSelect,
3830 (caddr_t) selection);
3831 if (selection == WhitePawn || selection == BlackPawn) {
3832 XtSetArg(args[0], XtNpopupOnEntry, entry);
3833 XtSetValues(menu, args, 1);
3846 ChessSquare selection;
3848 whitePieceMenu = CreatePieceMenu("menuW", 0);
3849 blackPieceMenu = CreatePieceMenu("menuB", 1);
3851 XtRegisterGrabAction(PieceMenuPopup, True,
3852 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3853 GrabModeAsync, GrabModeAsync);
3855 XtSetArg(args[0], XtNlabel, _("Drop"));
3856 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3857 boardWidget, args, 1);
3858 for (i = 0; i < DROP_MENU_SIZE; i++) {
3859 String item = dropMenuStrings[i];
3861 if (strcmp(item, "----") == 0) {
3862 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3865 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3866 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3868 selection = dropMenuTranslation[i];
3869 XtAddCallback(entry, XtNcallback,
3870 (XtCallbackProc) DropMenuSelect,
3871 (caddr_t) selection);
3876 void SetupDropMenu()
3884 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3885 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3886 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3887 dmEnables[i].piece);
3888 XtSetSensitive(entry, p != NULL || !appData.testLegality
3889 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3890 && !appData.icsActive));
3892 while (p && *p++ == dmEnables[i].piece) count++;
3893 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3895 XtSetArg(args[j], XtNlabel, label); j++;
3896 XtSetValues(entry, args, j);
3900 void PieceMenuPopup(w, event, params, num_params)
3904 Cardinal *num_params;
3906 String whichMenu; int menuNr;
3907 if (event->type == ButtonRelease)
3908 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3909 else if (event->type == ButtonPress)
3910 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3912 case 0: whichMenu = params[0]; break;
3913 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3915 case -1: if (errorUp) ErrorPopDown();
3918 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3921 static void PieceMenuSelect(w, piece, junk)
3926 if (pmFromX < 0 || pmFromY < 0) return;
3927 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3930 static void DropMenuSelect(w, piece, junk)
3935 if (pmFromX < 0 || pmFromY < 0) return;
3936 DropMenuEvent(piece, pmFromX, pmFromY);
3939 void WhiteClock(w, event, prms, nprms)
3945 if (gameMode == EditPosition || gameMode == IcsExamining) {
3946 SetWhiteToPlayEvent();
3947 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3952 void BlackClock(w, event, prms, nprms)
3958 if (gameMode == EditPosition || gameMode == IcsExamining) {
3959 SetBlackToPlayEvent();
3960 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3967 * If the user selects on a border boundary, return -1; if off the board,
3968 * return -2. Otherwise map the event coordinate to the square.
3970 int EventToSquare(x, limit)
3978 if ((x % (squareSize + lineGap)) >= squareSize)
3980 x /= (squareSize + lineGap);
3986 static void do_flash_delay(msec)
3992 static void drawHighlight(file, rank, gc)
3998 if (lineGap == 0 || appData.blindfold) return;
4001 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4002 (squareSize + lineGap);
4003 y = lineGap/2 + rank * (squareSize + lineGap);
4005 x = lineGap/2 + file * (squareSize + lineGap);
4006 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4007 (squareSize + lineGap);
4010 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4011 squareSize+lineGap, squareSize+lineGap);
4014 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4015 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4018 SetHighlights(fromX, fromY, toX, toY)
4019 int fromX, fromY, toX, toY;
4021 if (hi1X != fromX || hi1Y != fromY) {
4022 if (hi1X >= 0 && hi1Y >= 0) {
4023 drawHighlight(hi1X, hi1Y, lineGC);
4025 } // [HGM] first erase both, then draw new!
4026 if (hi2X != toX || hi2Y != toY) {
4027 if (hi2X >= 0 && hi2Y >= 0) {
4028 drawHighlight(hi2X, hi2Y, lineGC);
4031 if (hi1X != fromX || hi1Y != fromY) {
4032 if (fromX >= 0 && fromY >= 0) {
4033 drawHighlight(fromX, fromY, highlineGC);
4036 if (hi2X != toX || hi2Y != toY) {
4037 if (toX >= 0 && toY >= 0) {
4038 drawHighlight(toX, toY, highlineGC);
4050 SetHighlights(-1, -1, -1, -1);
4055 SetPremoveHighlights(fromX, fromY, toX, toY)
4056 int fromX, fromY, toX, toY;
4058 if (pm1X != fromX || pm1Y != fromY) {
4059 if (pm1X >= 0 && pm1Y >= 0) {
4060 drawHighlight(pm1X, pm1Y, lineGC);
4062 if (fromX >= 0 && fromY >= 0) {
4063 drawHighlight(fromX, fromY, prelineGC);
4066 if (pm2X != toX || pm2Y != toY) {
4067 if (pm2X >= 0 && pm2Y >= 0) {
4068 drawHighlight(pm2X, pm2Y, lineGC);
4070 if (toX >= 0 && toY >= 0) {
4071 drawHighlight(toX, toY, prelineGC);
4081 ClearPremoveHighlights()
4083 SetPremoveHighlights(-1, -1, -1, -1);
4086 static int CutOutSquare(x, y, x0, y0, kind)
4087 int x, y, *x0, *y0, kind;
4089 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4090 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4092 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4093 if(textureW[kind] < W*squareSize)
4094 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4096 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4097 if(textureH[kind] < H*squareSize)
4098 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4100 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4104 static void BlankSquare(x, y, color, piece, dest, fac)
4105 int x, y, color, fac;
4108 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4110 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4111 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4112 squareSize, squareSize, x*fac, y*fac);
4114 if (useImages && useImageSqs) {
4118 pm = xpmLightSquare;
4123 case 2: /* neutral */
4128 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4129 squareSize, squareSize, x*fac, y*fac);
4139 case 2: /* neutral */
4144 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4149 I split out the routines to draw a piece so that I could
4150 make a generic flash routine.
4152 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4154 int square_color, x, y;
4157 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4158 switch (square_color) {
4160 case 2: /* neutral */
4162 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4163 ? *pieceToOutline(piece)
4164 : *pieceToSolid(piece),
4165 dest, bwPieceGC, 0, 0,
4166 squareSize, squareSize, x, y);
4169 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4170 ? *pieceToSolid(piece)
4171 : *pieceToOutline(piece),
4172 dest, wbPieceGC, 0, 0,
4173 squareSize, squareSize, x, y);
4178 static void monoDrawPiece(piece, square_color, x, y, dest)
4180 int square_color, x, y;
4183 switch (square_color) {
4185 case 2: /* neutral */
4187 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4188 ? *pieceToOutline(piece)
4189 : *pieceToSolid(piece),
4190 dest, bwPieceGC, 0, 0,
4191 squareSize, squareSize, x, y, 1);
4194 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4195 ? *pieceToSolid(piece)
4196 : *pieceToOutline(piece),
4197 dest, wbPieceGC, 0, 0,
4198 squareSize, squareSize, x, y, 1);
4203 static void colorDrawPiece(piece, square_color, x, y, dest)
4205 int square_color, x, y;
4208 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4209 switch (square_color) {
4211 XCopyPlane(xDisplay, *pieceToSolid(piece),
4212 dest, (int) piece < (int) BlackPawn
4213 ? wlPieceGC : blPieceGC, 0, 0,
4214 squareSize, squareSize, x, y, 1);
4217 XCopyPlane(xDisplay, *pieceToSolid(piece),
4218 dest, (int) piece < (int) BlackPawn
4219 ? wdPieceGC : bdPieceGC, 0, 0,
4220 squareSize, squareSize, x, y, 1);
4222 case 2: /* neutral */
4224 XCopyPlane(xDisplay, *pieceToSolid(piece),
4225 dest, (int) piece < (int) BlackPawn
4226 ? wjPieceGC : bjPieceGC, 0, 0,
4227 squareSize, squareSize, x, y, 1);
4232 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4234 int square_color, x, y;
4237 int kind, p = piece;
4239 switch (square_color) {
4241 case 2: /* neutral */
4243 if ((int)piece < (int) BlackPawn) {
4251 if ((int)piece < (int) BlackPawn) {
4259 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4260 if(useTexture & square_color+1) {
4261 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4262 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4263 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4264 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4265 XSetClipMask(xDisplay, wlPieceGC, None);
4266 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4268 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4269 dest, wlPieceGC, 0, 0,
4270 squareSize, squareSize, x, y);