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
145 # if HAVE_LIBREADLINE /* add gnu-readline support */
146 #include <readline/readline.h>
147 #include <readline/history.h>
150 #include <X11/Intrinsic.h>
151 #include <X11/StringDefs.h>
152 #include <X11/Shell.h>
153 #include <X11/cursorfont.h>
154 #include <X11/Xatom.h>
155 #include <X11/Xmu/Atoms.h>
157 #include <X11/Xaw3d/Dialog.h>
158 #include <X11/Xaw3d/Form.h>
159 #include <X11/Xaw3d/List.h>
160 #include <X11/Xaw3d/Label.h>
161 #include <X11/Xaw3d/SimpleMenu.h>
162 #include <X11/Xaw3d/SmeBSB.h>
163 #include <X11/Xaw3d/SmeLine.h>
164 #include <X11/Xaw3d/Box.h>
165 #include <X11/Xaw3d/MenuButton.h>
166 #include <X11/Xaw3d/Text.h>
167 #include <X11/Xaw3d/AsciiText.h>
169 #include <X11/Xaw/Dialog.h>
170 #include <X11/Xaw/Form.h>
171 #include <X11/Xaw/List.h>
172 #include <X11/Xaw/Label.h>
173 #include <X11/Xaw/SimpleMenu.h>
174 #include <X11/Xaw/SmeBSB.h>
175 #include <X11/Xaw/SmeLine.h>
176 #include <X11/Xaw/Box.h>
177 #include <X11/Xaw/MenuButton.h>
178 #include <X11/Xaw/Text.h>
179 #include <X11/Xaw/AsciiText.h>
182 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
187 #include "pixmaps/pixmaps.h"
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
191 #include "bitmaps/bitmaps.h"
194 #include "bitmaps/icon_white.bm"
195 #include "bitmaps/icon_black.bm"
196 #include "bitmaps/checkmark.bm"
198 #include "frontend.h"
200 #include "backendz.h"
204 #include "xgamelist.h"
205 #include "xhistory.h"
206 #include "xedittags.h"
209 // must be moved to xengineoutput.h
211 void EngineOutputProc P((Widget w, XEvent *event,
212 String *prms, Cardinal *nprms));
213 void EvalGraphProc P((Widget w, XEvent *event,
214 String *prms, Cardinal *nprms));
221 #define usleep(t) _sleep2(((t)+500)/1000)
225 # define _(s) gettext (s)
226 # define N_(s) gettext_noop (s)
242 int main P((int argc, char **argv));
243 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
244 char *init_path, char *mode, int (*show_entry)(), char **name_return));
245 RETSIGTYPE CmailSigHandler P((int sig));
246 RETSIGTYPE IntSigHandler P((int sig));
247 RETSIGTYPE TermSizeSigHandler P((int sig));
248 void CreateGCs P((void));
249 void CreateXIMPieces P((void));
250 void CreateXPMPieces P((void));
251 void CreateXPMBoard P((char *s, int n));
252 void CreatePieces P((void));
253 void CreatePieceMenus P((void));
254 Widget CreateMenuBar P((Menu *mb));
255 Widget CreateButtonBar P ((MenuItem *mi));
256 char *FindFont P((char *pattern, int targetPxlSize));
257 void PieceMenuPopup P((Widget w, XEvent *event,
258 String *params, Cardinal *num_params));
259 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
260 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
261 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
262 u_int wreq, u_int hreq));
263 void CreateGrid P((void));
264 int EventToSquare P((int x, int limit));
265 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
266 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
267 void HandleUserMove P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void AnimateUserMove P((Widget w, XEvent * event,
270 String * params, Cardinal * nParams));
271 void HandlePV P((Widget w, XEvent * event,
272 String * params, Cardinal * nParams));
273 void SelectPV P((Widget w, XEvent * event,
274 String * params, Cardinal * nParams));
275 void StopPV P((Widget w, XEvent * event,
276 String * params, Cardinal * nParams));
277 void WhiteClock P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void BlackClock P((Widget w, XEvent *event,
280 String *prms, Cardinal *nprms));
281 void DrawPositionProc P((Widget w, XEvent *event,
282 String *prms, Cardinal *nprms));
283 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
285 void CommentClick P((Widget w, XEvent * event,
286 String * params, Cardinal * nParams));
287 void CommentPopUp P((char *title, char *label));
288 void CommentPopDown P((void));
289 void CommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void ICSInputBoxPopUp P((void));
292 void ICSInputBoxPopDown P((void));
293 void FileNamePopUp P((char *label, char *def,
294 FileProc proc, char *openMode));
295 void FileNamePopDown P((void));
296 void FileNameCallback P((Widget w, XtPointer client_data,
297 XtPointer call_data));
298 void FileNameAction P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void AskQuestionReplyAction P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void AskQuestionProc P((Widget w, XEvent *event,
303 String *prms, Cardinal *nprms));
304 void AskQuestionPopDown P((void));
305 void PromotionPopDown P((void));
306 void PromotionCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void EditCommentPopDown P((void));
309 void EditCommentCallback P((Widget w, XtPointer client_data,
310 XtPointer call_data));
311 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
312 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
316 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
318 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
320 void LoadPositionProc P((Widget w, XEvent *event,
321 String *prms, Cardinal *nprms));
322 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
324 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
326 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
328 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
330 void PastePositionProc P((Widget w, XEvent *event, String *prms,
332 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void SavePositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
340 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
344 void MachineWhiteProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AnalyzeModeProc P((Widget w, XEvent *event,
347 String *prms, Cardinal *nprms));
348 void AnalyzeFileProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
352 void IcsClientProc P((Widget w, XEvent *event, String *prms,
354 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EditPositionProc P((Widget w, XEvent *event,
356 String *prms, Cardinal *nprms));
357 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void EditCommentProc P((Widget w, XEvent *event,
359 String *prms, Cardinal *nprms));
360 void IcsInputBoxProc P((Widget w, XEvent *event,
361 String *prms, Cardinal *nprms));
362 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void StopObservingProc P((Widget w, XEvent *event, String *prms,
378 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
380 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
389 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
391 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
394 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
396 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
398 void AutocommProc P((Widget w, XEvent *event, String *prms,
400 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AutobsProc P((Widget w, XEvent *event, String *prms,
404 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
409 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
412 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
414 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
416 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
420 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
422 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
424 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
426 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
428 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
432 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
434 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
436 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
438 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void DisplayMove P((int moveNumber));
450 void DisplayTitle P((char *title));
451 void ICSInitScript P((void));
452 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
453 void ErrorPopUp P((char *title, char *text, int modal));
454 void ErrorPopDown P((void));
455 static char *ExpandPathName P((char *path));
456 static void CreateAnimVars P((void));
457 static void DragPieceMove P((int x, int y));
458 static void DrawDragPiece P((void));
459 char *ModeToWidgetName P((GameMode mode));
460 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void GameListOptionsPopDown P(());
469 void ShufflePopDown P(());
470 void EnginePopDown P(());
471 void UciPopDown P(());
472 void TimeControlPopDown P(());
473 void NewVariantPopDown P(());
474 void SettingsPopDown P(());
475 void update_ics_width P(());
476 int get_term_width P(());
477 int CopyMemoProc P(());
479 # if HAVE_LIBREADLINE /* add gnu-readline support */
480 static void ReadlineCompleteHandler P((char *));
484 * XBoard depends on Xt R4 or higher
486 int xtVersion = XtSpecificationRelease;
491 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
492 jailSquareColor, highlightSquareColor, premoveHighlightColor;
493 Pixel lowTimeWarningColor;
494 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
495 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
496 wjPieceGC, bjPieceGC, prelineGC, countGC;
497 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
498 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
499 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
500 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
501 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
502 ICSInputShell, fileNameShell, askQuestionShell;
503 Widget historyShell, evalGraphShell, gameListShell;
504 int hOffset; // [HGM] dual
505 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
506 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
507 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
508 Font clockFontID, coordFontID, countFontID;
509 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
510 XtAppContext appContext;
512 char *oldICSInteractionTitle;
516 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
518 # if HAVE_LIBREADLINE /* gnu readline support */
519 static char* readline_buffer;
520 static int readline_complete=0;
521 extern int sending_ICS_login;
522 extern int sending_ICS_password;
525 Position commentX = -1, commentY = -1;
526 Dimension commentW, commentH;
527 typedef unsigned int BoardSize;
529 Boolean chessProgram;
531 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
532 int squareSize, smallLayout = 0, tinyLayout = 0,
533 marginW, marginH, // [HGM] for run-time resizing
534 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
535 ICSInputBoxUp = False, askQuestionUp = False,
536 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
537 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
538 Pixel timerForegroundPixel, timerBackgroundPixel;
539 Pixel buttonForegroundPixel, buttonBackgroundPixel;
540 char *chessDir, *programName, *programVersion,
541 *gameCopyFilename, *gamePasteFilename;
542 Boolean alwaysOnTop = False;
543 Boolean saveSettingsOnExit;
544 char *settingsFileName;
545 char *icsTextMenuString;
547 char *firstChessProgramNames;
548 char *secondChessProgramNames;
550 WindowPlacement wpMain;
551 WindowPlacement wpConsole;
552 WindowPlacement wpComment;
553 WindowPlacement wpMoveHistory;
554 WindowPlacement wpEvalGraph;
555 WindowPlacement wpEngineOutput;
556 WindowPlacement wpGameList;
557 WindowPlacement wpTags;
561 Pixmap pieceBitmap[2][(int)BlackPawn];
562 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
563 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
564 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
565 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
566 Pixmap xpmBoardBitmap[2];
567 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
568 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
569 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
570 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
571 XImage *ximLightSquare, *ximDarkSquare;
574 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
575 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
577 #define White(piece) ((int)(piece) < (int)BlackPawn)
579 /* Variables for doing smooth animation. This whole thing
580 would be much easier if the board was double-buffered,
581 but that would require a fairly major rewrite. */
586 GC blitGC, pieceGC, outlineGC;
587 XPoint startSquare, prevFrame, mouseDelta;
591 int startBoardX, startBoardY;
594 /* There can be two pieces being animated at once: a player
595 can begin dragging a piece before the remote opponent has moved. */
597 static AnimState game, player;
599 /* Bitmaps for use as masks when drawing XPM pieces.
600 Need one for each black and white piece. */
601 static Pixmap xpmMask[BlackKing + 1];
603 /* This magic number is the number of intermediate frames used
604 in each half of the animation. For short moves it's reduced
605 by 1. The total number of frames will be factor * 2 + 1. */
608 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
610 MenuItem fileMenu[] = {
611 {N_("New Game"), ResetProc},
612 {N_("New Shuffle Game ..."), ShuffleMenuProc},
613 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
614 {"----", NothingProc},
615 {N_("Load Game"), LoadGameProc},
616 {N_("Load Next Game"), LoadNextGameProc},
617 {N_("Load Previous Game"), LoadPrevGameProc},
618 {N_("Reload Same Game"), ReloadGameProc},
619 {N_("Save Game"), SaveGameProc},
620 {"----", NothingProc},
621 {N_("Copy Game"), CopyGameProc},
622 {N_("Paste Game"), PasteGameProc},
623 {"----", NothingProc},
624 {N_("Load Position"), LoadPositionProc},
625 {N_("Load Next Position"), LoadNextPositionProc},
626 {N_("Load Previous Position"), LoadPrevPositionProc},
627 {N_("Reload Same Position"), ReloadPositionProc},
628 {N_("Save Position"), SavePositionProc},
629 {"----", NothingProc},
630 {N_("Copy Position"), CopyPositionProc},
631 {N_("Paste Position"), PastePositionProc},
632 {"----", NothingProc},
633 {N_("Mail Move"), MailMoveProc},
634 {N_("Reload CMail Message"), ReloadCmailMsgProc},
635 {"----", NothingProc},
636 {N_("Exit"), QuitProc},
640 MenuItem modeMenu[] = {
641 {N_("Machine White"), MachineWhiteProc},
642 {N_("Machine Black"), MachineBlackProc},
643 {N_("Two Machines"), TwoMachinesProc},
644 {N_("Analysis Mode"), AnalyzeModeProc},
645 {N_("Analyze File"), AnalyzeFileProc },
646 {N_("ICS Client"), IcsClientProc},
647 {N_("Edit Game"), EditGameProc},
648 {N_("Edit Position"), EditPositionProc},
649 {N_("Training"), TrainingProc},
650 {"----", NothingProc},
651 {N_("Show Engine Output"), EngineOutputProc},
652 {N_("Show Evaluation Graph"), EvalGraphProc},
653 {N_("Show Game List"), ShowGameListProc},
654 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
655 {"----", NothingProc},
656 {N_("Edit Tags"), EditTagsProc},
657 {N_("Edit Comment"), EditCommentProc},
658 {N_("ICS Input Box"), IcsInputBoxProc},
659 {N_("Pause"), PauseProc},
663 MenuItem actionMenu[] = {
664 {N_("Accept"), AcceptProc},
665 {N_("Decline"), DeclineProc},
666 {N_("Rematch"), RematchProc},
667 {"----", NothingProc},
668 {N_("Call Flag"), CallFlagProc},
669 {N_("Draw"), DrawProc},
670 {N_("Adjourn"), AdjournProc},
671 {N_("Abort"), AbortProc},
672 {N_("Resign"), ResignProc},
673 {"----", NothingProc},
674 {N_("Stop Observing"), StopObservingProc},
675 {N_("Stop Examining"), StopExaminingProc},
676 {N_("Upload to Examine"), UploadProc},
677 {"----", NothingProc},
678 {N_("Adjudicate to White"), AdjuWhiteProc},
679 {N_("Adjudicate to Black"), AdjuBlackProc},
680 {N_("Adjudicate Draw"), AdjuDrawProc},
684 MenuItem stepMenu[] = {
685 {N_("Backward"), BackwardProc},
686 {N_("Forward"), ForwardProc},
687 {N_("Back to Start"), ToStartProc},
688 {N_("Forward to End"), ToEndProc},
689 {N_("Revert"), RevertProc},
690 {N_("Annotate"), AnnotateProc},
691 {N_("Truncate Game"), TruncateGameProc},
692 {"----", NothingProc},
693 {N_("Move Now"), MoveNowProc},
694 {N_("Retract Move"), RetractMoveProc},
698 MenuItem optionsMenu[] = {
699 {N_("Flip View"), FlipViewProc},
700 {"----", NothingProc},
701 {N_("Adjudications ..."), EngineMenuProc},
702 {N_("General Settings ..."), UciMenuProc},
703 {N_("Engine #1 Settings ..."), FirstSettingsProc},
704 {N_("Engine #2 Settings ..."), SecondSettingsProc},
705 {N_("Time Control ..."), TimeControlProc},
706 {N_("Game List ..."), GameListOptionsPopUp},
707 {"----", NothingProc},
708 {N_("Always Queen"), AlwaysQueenProc},
709 {N_("Animate Dragging"), AnimateDraggingProc},
710 {N_("Animate Moving"), AnimateMovingProc},
711 {N_("Auto Comment"), AutocommProc},
712 {N_("Auto Flag"), AutoflagProc},
713 {N_("Auto Flip View"), AutoflipProc},
714 {N_("Auto Observe"), AutobsProc},
715 {N_("Auto Raise Board"), AutoraiseProc},
716 {N_("Auto Save"), AutosaveProc},
717 {N_("Blindfold"), BlindfoldProc},
718 {N_("Flash Moves"), FlashMovesProc},
719 {N_("Get Move List"), GetMoveListProc},
721 {N_("Highlight Dragging"), HighlightDraggingProc},
723 {N_("Highlight Last Move"), HighlightLastMoveProc},
724 {N_("Move Sound"), MoveSoundProc},
725 {N_("ICS Alarm"), IcsAlarmProc},
726 {N_("Old Save Style"), OldSaveStyleProc},
727 {N_("Periodic Updates"), PeriodicUpdatesProc},
728 {N_("Ponder Next Move"), PonderNextMoveProc},
729 {N_("Popup Exit Message"), PopupExitMessageProc},
730 {N_("Popup Move Errors"), PopupMoveErrorsProc},
731 {N_("Premove"), PremoveProc},
732 {N_("Quiet Play"), QuietPlayProc},
733 {N_("Show Coords"), ShowCoordsProc},
734 {N_("Hide Thinking"), HideThinkingProc},
735 {N_("Test Legality"), TestLegalityProc},
736 {"----", NothingProc},
737 {N_("Save Settings Now"), SaveSettingsProc},
738 {N_("Save Settings on Exit"), SaveOnExitProc},
742 MenuItem helpMenu[] = {
743 {N_("Info XBoard"), InfoProc},
744 {N_("Man XBoard"), ManProc},
745 {"----", NothingProc},
746 {N_("Hint"), HintProc},
747 {N_("Book"), BookProc},
748 {"----", NothingProc},
749 {N_("About XBoard"), AboutProc},
754 {N_("File"), fileMenu},
755 {N_("Mode"), modeMenu},
756 {N_("Action"), actionMenu},
757 {N_("Step"), stepMenu},
758 {N_("Options"), optionsMenu},
759 {N_("Help"), helpMenu},
763 #define PAUSE_BUTTON N_("P")
764 MenuItem buttonBar[] = {
767 {PAUSE_BUTTON, PauseProc},
773 #define PIECE_MENU_SIZE 18
774 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
775 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
776 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
777 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
778 N_("Empty square"), N_("Clear board") },
779 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
780 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
781 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
782 N_("Empty square"), N_("Clear board") }
784 /* must be in same order as PieceMenuStrings! */
785 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
786 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
787 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
788 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
789 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
790 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
791 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
792 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
793 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
796 #define DROP_MENU_SIZE 6
797 String dropMenuStrings[DROP_MENU_SIZE] = {
798 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
800 /* must be in same order as PieceMenuStrings! */
801 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
802 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
803 WhiteRook, WhiteQueen
811 DropMenuEnables dmEnables[] = {
829 { XtNborderWidth, 0 },
830 { XtNdefaultDistance, 0 },
834 { XtNborderWidth, 0 },
835 { XtNresizable, (XtArgVal) True },
839 { XtNborderWidth, 0 },
845 { XtNjustify, (XtArgVal) XtJustifyRight },
846 { XtNlabel, (XtArgVal) "..." },
847 { XtNresizable, (XtArgVal) True },
848 { XtNresize, (XtArgVal) False }
851 Arg messageArgs[] = {
852 { XtNjustify, (XtArgVal) XtJustifyLeft },
853 { XtNlabel, (XtArgVal) "..." },
854 { XtNresizable, (XtArgVal) True },
855 { XtNresize, (XtArgVal) False }
859 { XtNborderWidth, 0 },
860 { XtNjustify, (XtArgVal) XtJustifyLeft }
863 XtResource clientResources[] = {
864 { "flashCount", "flashCount", XtRInt, sizeof(int),
865 XtOffset(AppDataPtr, flashCount), XtRImmediate,
866 (XtPointer) FLASH_COUNT },
869 XrmOptionDescRec shellOptions[] = {
870 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
871 { "-flash", "flashCount", XrmoptionNoArg, "3" },
872 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
875 XtActionsRec boardActions[] = {
876 { "DrawPosition", DrawPositionProc },
877 { "HandleUserMove", HandleUserMove },
878 { "AnimateUserMove", AnimateUserMove },
879 { "HandlePV", HandlePV },
880 { "SelectPV", SelectPV },
881 { "StopPV", StopPV },
882 { "FileNameAction", FileNameAction },
883 { "AskQuestionProc", AskQuestionProc },
884 { "AskQuestionReplyAction", AskQuestionReplyAction },
885 { "PieceMenuPopup", PieceMenuPopup },
886 { "WhiteClock", WhiteClock },
887 { "BlackClock", BlackClock },
888 { "Iconify", Iconify },
889 { "ResetProc", ResetProc },
890 { "NewVariantProc", NewVariantProc },
891 { "LoadGameProc", LoadGameProc },
892 { "LoadNextGameProc", LoadNextGameProc },
893 { "LoadPrevGameProc", LoadPrevGameProc },
894 { "LoadSelectedProc", LoadSelectedProc },
895 { "SetFilterProc", SetFilterProc },
896 { "ReloadGameProc", ReloadGameProc },
897 { "LoadPositionProc", LoadPositionProc },
898 { "LoadNextPositionProc", LoadNextPositionProc },
899 { "LoadPrevPositionProc", LoadPrevPositionProc },
900 { "ReloadPositionProc", ReloadPositionProc },
901 { "CopyPositionProc", CopyPositionProc },
902 { "PastePositionProc", PastePositionProc },
903 { "CopyGameProc", CopyGameProc },
904 { "PasteGameProc", PasteGameProc },
905 { "SaveGameProc", SaveGameProc },
906 { "SavePositionProc", SavePositionProc },
907 { "MailMoveProc", MailMoveProc },
908 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
909 { "QuitProc", QuitProc },
910 { "MachineWhiteProc", MachineWhiteProc },
911 { "MachineBlackProc", MachineBlackProc },
912 { "AnalysisModeProc", AnalyzeModeProc },
913 { "AnalyzeFileProc", AnalyzeFileProc },
914 { "TwoMachinesProc", TwoMachinesProc },
915 { "IcsClientProc", IcsClientProc },
916 { "EditGameProc", EditGameProc },
917 { "EditPositionProc", EditPositionProc },
918 { "TrainingProc", EditPositionProc },
919 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
920 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
921 { "ShowGameListProc", ShowGameListProc },
922 { "ShowMoveListProc", HistoryShowProc},
923 { "EditTagsProc", EditCommentProc },
924 { "EditCommentProc", EditCommentProc },
925 { "IcsAlarmProc", IcsAlarmProc },
926 { "IcsInputBoxProc", IcsInputBoxProc },
927 { "PauseProc", PauseProc },
928 { "AcceptProc", AcceptProc },
929 { "DeclineProc", DeclineProc },
930 { "RematchProc", RematchProc },
931 { "CallFlagProc", CallFlagProc },
932 { "DrawProc", DrawProc },
933 { "AdjournProc", AdjournProc },
934 { "AbortProc", AbortProc },
935 { "ResignProc", ResignProc },
936 { "AdjuWhiteProc", AdjuWhiteProc },
937 { "AdjuBlackProc", AdjuBlackProc },
938 { "AdjuDrawProc", AdjuDrawProc },
939 { "EnterKeyProc", EnterKeyProc },
940 { "UpKeyProc", UpKeyProc },
941 { "DownKeyProc", DownKeyProc },
942 { "StopObservingProc", StopObservingProc },
943 { "StopExaminingProc", StopExaminingProc },
944 { "UploadProc", UploadProc },
945 { "BackwardProc", BackwardProc },
946 { "ForwardProc", ForwardProc },
947 { "ToStartProc", ToStartProc },
948 { "ToEndProc", ToEndProc },
949 { "RevertProc", RevertProc },
950 { "AnnotateProc", AnnotateProc },
951 { "TruncateGameProc", TruncateGameProc },
952 { "MoveNowProc", MoveNowProc },
953 { "RetractMoveProc", RetractMoveProc },
954 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
955 { "UciMenuProc", (XtActionProc) UciMenuProc },
956 { "TimeControlProc", (XtActionProc) TimeControlProc },
957 { "AlwaysQueenProc", AlwaysQueenProc },
958 { "AnimateDraggingProc", AnimateDraggingProc },
959 { "AnimateMovingProc", AnimateMovingProc },
960 { "AutoflagProc", AutoflagProc },
961 { "AutoflipProc", AutoflipProc },
962 { "AutobsProc", AutobsProc },
963 { "AutoraiseProc", AutoraiseProc },
964 { "AutosaveProc", AutosaveProc },
965 { "BlindfoldProc", BlindfoldProc },
966 { "FlashMovesProc", FlashMovesProc },
967 { "FlipViewProc", FlipViewProc },
968 { "GetMoveListProc", GetMoveListProc },
970 { "HighlightDraggingProc", HighlightDraggingProc },
972 { "HighlightLastMoveProc", HighlightLastMoveProc },
973 { "IcsAlarmProc", IcsAlarmProc },
974 { "MoveSoundProc", MoveSoundProc },
975 { "OldSaveStyleProc", OldSaveStyleProc },
976 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
977 { "PonderNextMoveProc", PonderNextMoveProc },
978 { "PopupExitMessageProc", PopupExitMessageProc },
979 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
980 { "PremoveProc", PremoveProc },
981 { "QuietPlayProc", QuietPlayProc },
982 { "ShowCoordsProc", ShowCoordsProc },
983 { "ShowThinkingProc", ShowThinkingProc },
984 { "HideThinkingProc", HideThinkingProc },
985 { "TestLegalityProc", TestLegalityProc },
986 { "SaveSettingsProc", SaveSettingsProc },
987 { "SaveOnExitProc", SaveOnExitProc },
988 { "InfoProc", InfoProc },
989 { "ManProc", ManProc },
990 { "HintProc", HintProc },
991 { "BookProc", BookProc },
992 { "AboutGameProc", AboutGameProc },
993 { "AboutProc", AboutProc },
994 { "DebugProc", DebugProc },
995 { "NothingProc", NothingProc },
996 { "CommentClick", (XtActionProc) CommentClick },
997 { "CommentPopDown", (XtActionProc) CommentPopDown },
998 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
999 { "TagsPopDown", (XtActionProc) TagsPopDown },
1000 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1001 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1002 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1003 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1004 { "GameListPopDown", (XtActionProc) GameListPopDown },
1005 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1006 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1007 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1008 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1009 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1010 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1011 { "EnginePopDown", (XtActionProc) EnginePopDown },
1012 { "UciPopDown", (XtActionProc) UciPopDown },
1013 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1014 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1015 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1016 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1019 char globalTranslations[] =
1020 ":<Key>F9: ResignProc() \n \
1021 :Ctrl<Key>n: ResetProc() \n \
1022 :Meta<Key>V: NewVariantProc() \n \
1023 :Ctrl<Key>o: LoadGameProc() \n \
1024 :Meta<Key>Next: LoadNextGameProc() \n \
1025 :Meta<Key>Prior: LoadPrevGameProc() \n \
1026 :Ctrl<Key>s: SaveGameProc() \n \
1027 :Ctrl<Key>c: CopyGameProc() \n \
1028 :Ctrl<Key>v: PasteGameProc() \n \
1029 :Ctrl<Key>O: LoadPositionProc() \n \
1030 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1031 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1032 :Ctrl<Key>S: SavePositionProc() \n \
1033 :Ctrl<Key>C: CopyPositionProc() \n \
1034 :Ctrl<Key>V: PastePositionProc() \n \
1035 :Ctrl<Key>q: QuitProc() \n \
1036 :Ctrl<Key>w: MachineWhiteProc() \n \
1037 :Ctrl<Key>b: MachineBlackProc() \n \
1038 :Ctrl<Key>t: TwoMachinesProc() \n \
1039 :Ctrl<Key>a: AnalysisModeProc() \n \
1040 :Ctrl<Key>f: AnalyzeFileProc() \n \
1041 :Ctrl<Key>e: EditGameProc() \n \
1042 :Ctrl<Key>E: EditPositionProc() \n \
1043 :Meta<Key>O: EngineOutputProc() \n \
1044 :Meta<Key>E: EvalGraphProc() \n \
1045 :Meta<Key>G: ShowGameListProc() \n \
1046 :Meta<Key>H: ShowMoveListProc() \n \
1047 :<Key>Pause: PauseProc() \n \
1048 :<Key>F3: AcceptProc() \n \
1049 :<Key>F4: DeclineProc() \n \
1050 :<Key>F12: RematchProc() \n \
1051 :<Key>F5: CallFlagProc() \n \
1052 :<Key>F6: DrawProc() \n \
1053 :<Key>F7: AdjournProc() \n \
1054 :<Key>F8: AbortProc() \n \
1055 :<Key>F10: StopObservingProc() \n \
1056 :<Key>F11: StopExaminingProc() \n \
1057 :Meta Ctrl<Key>F12: DebugProc() \n \
1058 :Meta<Key>End: ToEndProc() \n \
1059 :Meta<Key>Right: ForwardProc() \n \
1060 :Meta<Key>Home: ToStartProc() \n \
1061 :Meta<Key>Left: BackwardProc() \n \
1062 :Ctrl<Key>m: MoveNowProc() \n \
1063 :Ctrl<Key>x: RetractMoveProc() \n \
1064 :Meta<Key>J: EngineMenuProc() \n \
1065 :Meta<Key>U: UciMenuProc() \n \
1066 :Meta<Key>T: TimeControlProc() \n \
1067 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1068 :Ctrl<Key>F: AutoflagProc() \n \
1069 :Ctrl<Key>A: AnimateMovingProc() \n \
1070 :Ctrl<Key>P: PonderNextMoveProc() \n \
1071 :Ctrl<Key>L: TestLegalityProc() \n \
1072 :Ctrl<Key>H: HideThinkingProc() \n \
1073 :<Key>-: Iconify() \n \
1074 :<Key>F1: ManProc() \n \
1075 :<Key>F2: FlipViewProc() \n \
1076 <KeyDown>.: BackwardProc() \n \
1077 <KeyUp>.: ForwardProc() \n \
1078 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1079 \"Send to chess program:\",,1) \n \
1080 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1081 \"Send to second chess program:\",,2) \n";
1083 char boardTranslations[] =
1084 "<Btn1Down>: HandleUserMove(0) \n \
1085 Shift<Btn1Up>: HandleUserMove(1) \n \
1086 <Btn1Up>: HandleUserMove(0) \n \
1087 <Btn1Motion>: AnimateUserMove() \n \
1088 <Btn3Motion>: HandlePV() \n \
1089 <Btn3Up>: PieceMenuPopup(menuB) \n \
1090 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1091 PieceMenuPopup(menuB) \n \
1092 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1093 PieceMenuPopup(menuW) \n \
1094 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1095 PieceMenuPopup(menuW) \n \
1096 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1097 PieceMenuPopup(menuB) \n";
1099 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1100 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1102 char ICSInputTranslations[] =
1103 "<Key>Up: UpKeyProc() \n "
1104 "<Key>Down: DownKeyProc() \n "
1105 "<Key>Return: EnterKeyProc() \n";
1107 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1108 // as the widget is destroyed before the up-click can call extend-end
1109 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1111 String xboardResources[] = {
1112 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1113 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1114 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1119 /* Max possible square size */
1120 #define MAXSQSIZE 256
1122 static int xpm_avail[MAXSQSIZE];
1124 #ifdef HAVE_DIR_STRUCT
1126 /* Extract piece size from filename */
1128 xpm_getsize(name, len, ext)
1139 if ((p=strchr(name, '.')) == NULL ||
1140 StrCaseCmp(p+1, ext) != 0)
1146 while (*p && isdigit(*p))
1153 /* Setup xpm_avail */
1155 xpm_getavail(dirname, ext)
1163 for (i=0; i<MAXSQSIZE; ++i)
1166 if (appData.debugMode)
1167 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1169 dir = opendir(dirname);
1172 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1173 programName, dirname);
1177 while ((ent=readdir(dir)) != NULL) {
1178 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1179 if (i > 0 && i < MAXSQSIZE)
1189 xpm_print_avail(fp, ext)
1195 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1196 for (i=1; i<MAXSQSIZE; ++i) {
1202 /* Return XPM piecesize closest to size */
1204 xpm_closest_to(dirname, size, ext)
1210 int sm_diff = MAXSQSIZE;
1214 xpm_getavail(dirname, ext);
1216 if (appData.debugMode)
1217 xpm_print_avail(stderr, ext);
1219 for (i=1; i<MAXSQSIZE; ++i) {
1222 diff = (diff<0) ? -diff : diff;
1223 if (diff < sm_diff) {
1231 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1237 #else /* !HAVE_DIR_STRUCT */
1238 /* If we are on a system without a DIR struct, we can't
1239 read the directory, so we can't collect a list of
1240 filenames, etc., so we can't do any size-fitting. */
1242 xpm_closest_to(dirname, size, ext)
1247 fprintf(stderr, _("\
1248 Warning: No DIR structure found on this system --\n\
1249 Unable to autosize for XPM/XIM pieces.\n\
1250 Please report this error to frankm@hiwaay.net.\n\
1251 Include system type & operating system in message.\n"));
1254 #endif /* HAVE_DIR_STRUCT */
1256 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1257 "magenta", "cyan", "white" };
1261 TextColors textColors[(int)NColorClasses];
1263 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1265 parse_color(str, which)
1269 char *p, buf[100], *d;
1272 if (strlen(str) > 99) /* watch bounds on buf */
1277 for (i=0; i<which; ++i) {
1284 /* Could be looking at something like:
1286 .. in which case we want to stop on a comma also */
1287 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1291 return -1; /* Use default for empty field */
1294 if (which == 2 || isdigit(*p))
1297 while (*p && isalpha(*p))
1302 for (i=0; i<8; ++i) {
1303 if (!StrCaseCmp(buf, cnames[i]))
1304 return which? (i+40) : (i+30);
1306 if (!StrCaseCmp(buf, "default")) return -1;
1308 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1313 parse_cpair(cc, str)
1317 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1318 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1323 /* bg and attr are optional */
1324 textColors[(int)cc].bg = parse_color(str, 1);
1325 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1326 textColors[(int)cc].attr = 0;
1332 /* Arrange to catch delete-window events */
1333 Atom wm_delete_window;
1335 CatchDeleteWindow(Widget w, String procname)
1338 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1339 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1340 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1347 XtSetArg(args[0], XtNiconic, False);
1348 XtSetValues(shellWidget, args, 1);
1350 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1353 //---------------------------------------------------------------------------------------------------------
1354 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1357 #define CW_USEDEFAULT (1<<31)
1358 #define ICS_TEXT_MENU_SIZE 90
1359 #define DEBUG_FILE "xboard.debug"
1360 #define SetCurrentDirectory chdir
1361 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1365 // these two must some day move to frontend.h, when they are implemented
1366 Boolean GameListIsUp();
1368 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1371 // front-end part of option handling
1373 // [HGM] This platform-dependent table provides the location for storing the color info
1374 extern char *crWhite, * crBlack;
1378 &appData.whitePieceColor,
1379 &appData.blackPieceColor,
1380 &appData.lightSquareColor,
1381 &appData.darkSquareColor,
1382 &appData.highlightSquareColor,
1383 &appData.premoveHighlightColor,
1384 &appData.lowTimeWarningColor,
1395 // [HGM] font: keep a font for each square size, even non-stndard ones
1396 #define NUM_SIZES 18
1397 #define MAX_SIZE 130
1398 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1399 char *fontTable[NUM_FONTS][MAX_SIZE];
1402 ParseFont(char *name, int number)
1403 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1405 if(sscanf(name, "size%d:", &size)) {
1406 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1407 // defer processing it until we know if it matches our board size
1408 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1409 fontTable[number][size] = strdup(strchr(name, ':')+1);
1410 fontValid[number][size] = True;
1415 case 0: // CLOCK_FONT
1416 appData.clockFont = strdup(name);
1418 case 1: // MESSAGE_FONT
1419 appData.font = strdup(name);
1421 case 2: // COORD_FONT
1422 appData.coordFont = strdup(name);
1427 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1432 { // only 2 fonts currently
1433 appData.clockFont = CLOCK_FONT_NAME;
1434 appData.coordFont = COORD_FONT_NAME;
1435 appData.font = DEFAULT_FONT_NAME;
1440 { // no-op, until we identify the code for this already in XBoard and move it here
1444 ParseColor(int n, char *name)
1445 { // in XBoard, just copy the color-name string
1446 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1450 ParseTextAttribs(ColorClass cc, char *s)
1452 (&appData.colorShout)[cc] = strdup(s);
1456 ParseBoardSize(void *addr, char *name)
1458 appData.boardSize = strdup(name);
1463 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1467 SetCommPortDefaults()
1468 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1471 // [HGM] args: these three cases taken out to stay in front-end
1473 SaveFontArg(FILE *f, ArgDescriptor *ad)
1476 int i, n = (int)ad->argLoc;
1478 case 0: // CLOCK_FONT
1479 name = appData.clockFont;
1481 case 1: // MESSAGE_FONT
1482 name = appData.font;
1484 case 2: // COORD_FONT
1485 name = appData.coordFont;
1490 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1491 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1492 fontTable[n][squareSize] = strdup(name);
1493 fontValid[n][squareSize] = True;
1496 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1497 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1502 { // nothing to do, as the sounds are at all times represented by their text-string names already
1506 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1507 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1508 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1512 SaveColor(FILE *f, ArgDescriptor *ad)
1513 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1514 if(colorVariable[(int)ad->argLoc])
1515 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1519 SaveBoardSize(FILE *f, char *name, void *addr)
1520 { // wrapper to shield back-end from BoardSize & sizeInfo
1521 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1525 ParseCommPortSettings(char *s)
1526 { // no such option in XBoard (yet)
1529 extern Widget engineOutputShell;
1530 extern Widget tagsShell, editTagsShell;
1532 GetActualPlacement(Widget wg, WindowPlacement *wp)
1542 XtSetArg(args[i], XtNx, &x); i++;
1543 XtSetArg(args[i], XtNy, &y); i++;
1544 XtSetArg(args[i], XtNwidth, &w); i++;
1545 XtSetArg(args[i], XtNheight, &h); i++;
1546 XtGetValues(wg, args, i);
1555 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1556 // In XBoard this will have to wait until awareness of window parameters is implemented
1557 GetActualPlacement(shellWidget, &wpMain);
1558 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1559 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1560 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1561 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1562 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1563 else GetActualPlacement(editShell, &wpComment);
1564 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1565 else GetActualPlacement(editTagsShell, &wpTags);
1569 PrintCommPortSettings(FILE *f, char *name)
1570 { // This option does not exist in XBoard
1574 MySearchPath(char *installDir, char *name, char *fullname)
1575 { // just append installDir and name. Perhaps ExpandPath should be used here?
1576 name = ExpandPathName(name);
1577 if(name && name[0] == '/')
1578 safeStrCpy(fullname, name, MSG_SIZ );
1580 sprintf(fullname, "%s%c%s", installDir, '/', name);
1586 MyGetFullPathName(char *name, char *fullname)
1587 { // should use ExpandPath?
1588 name = ExpandPathName(name);
1589 safeStrCpy(fullname, name, MSG_SIZ );
1594 EnsureOnScreen(int *x, int *y, int minX, int minY)
1601 { // [HGM] args: allows testing if main window is realized from back-end
1602 return xBoardWindow != 0;
1606 PopUpStartupDialog()
1607 { // start menu not implemented in XBoard
1611 ConvertToLine(int argc, char **argv)
1613 static char line[128*1024], buf[1024];
1617 for(i=1; i<argc; i++)
1619 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1620 && argv[i][0] != '{' )
1621 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1623 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1624 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1627 line[strlen(line)-1] = NULLCHAR;
1631 //--------------------------------------------------------------------------------------------
1633 extern Boolean twoBoards, partnerUp;
1636 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1638 #define BoardSize int
1639 void InitDrawingSizes(BoardSize boardSize, int flags)
1640 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1641 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1643 XtGeometryResult gres;
1646 if(!formWidget) return;
1649 * Enable shell resizing.
1651 shellArgs[0].value = (XtArgVal) &w;
1652 shellArgs[1].value = (XtArgVal) &h;
1653 XtGetValues(shellWidget, shellArgs, 2);
1655 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1656 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1657 XtSetValues(shellWidget, &shellArgs[2], 4);
1659 XtSetArg(args[0], XtNdefaultDistance, &sep);
1660 XtGetValues(formWidget, args, 1);
1662 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1663 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1665 hOffset = boardWidth + 10;
1666 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1667 secondSegments[i] = gridSegments[i];
1668 secondSegments[i].x1 += hOffset;
1669 secondSegments[i].x2 += hOffset;
1672 XtSetArg(args[0], XtNwidth, boardWidth);
1673 XtSetArg(args[1], XtNheight, boardHeight);
1674 XtSetValues(boardWidget, args, 2);
1676 timerWidth = (boardWidth - sep) / 2;
1677 XtSetArg(args[0], XtNwidth, timerWidth);
1678 XtSetValues(whiteTimerWidget, args, 1);
1679 XtSetValues(blackTimerWidget, args, 1);
1681 XawFormDoLayout(formWidget, False);
1683 if (appData.titleInWindow) {
1685 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1686 XtSetArg(args[i], XtNheight, &h); i++;
1687 XtGetValues(titleWidget, args, i);
1689 w = boardWidth - 2*bor;
1691 XtSetArg(args[0], XtNwidth, &w);
1692 XtGetValues(menuBarWidget, args, 1);
1693 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1696 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1697 if (gres != XtGeometryYes && appData.debugMode) {
1699 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1700 programName, gres, w, h, wr, hr);
1704 XawFormDoLayout(formWidget, True);
1707 * Inhibit shell resizing.
1709 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1710 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1711 shellArgs[4].value = shellArgs[2].value = w;
1712 shellArgs[5].value = shellArgs[3].value = h;
1713 XtSetValues(shellWidget, &shellArgs[0], 6);
1715 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1718 for(i=0; i<4; i++) {
1720 for(p=0; p<=(int)WhiteKing; p++)
1721 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1722 if(gameInfo.variant == VariantShogi) {
1723 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1724 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1725 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1726 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1727 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1730 if(gameInfo.variant == VariantGothic) {
1731 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1734 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1735 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1736 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1739 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1740 for(p=0; p<=(int)WhiteKing; p++)
1741 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1742 if(gameInfo.variant == VariantShogi) {
1743 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1744 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1745 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1746 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1747 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1750 if(gameInfo.variant == VariantGothic) {
1751 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1754 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1755 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1756 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1761 for(i=0; i<2; i++) {
1763 for(p=0; p<=(int)WhiteKing; p++)
1764 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1765 if(gameInfo.variant == VariantShogi) {
1766 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1767 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1768 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1769 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1770 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1773 if(gameInfo.variant == VariantGothic) {
1774 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1777 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1778 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1779 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1794 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1795 XSetWindowAttributes window_attributes;
1797 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1798 XrmValue vFrom, vTo;
1799 XtGeometryResult gres;
1802 int forceMono = False;
1804 srandom(time(0)); // [HGM] book: make random truly random
1806 setbuf(stdout, NULL);
1807 setbuf(stderr, NULL);
1810 # if HAVE_LIBREADLINE
1811 /* install gnu-readline handler */
1812 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1813 rl_readline_name="XBoard";
1816 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1817 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1821 programName = strrchr(argv[0], '/');
1822 if (programName == NULL)
1823 programName = argv[0];
1828 XtSetLanguageProc(NULL, NULL, NULL);
1829 bindtextdomain(PACKAGE, LOCALEDIR);
1830 textdomain(PACKAGE);
1834 XtAppInitialize(&appContext, "XBoard", shellOptions,
1835 XtNumber(shellOptions),
1836 &argc, argv, xboardResources, NULL, 0);
1837 appData.boardSize = "";
1838 InitAppData(ConvertToLine(argc, argv));
1840 if (p == NULL) p = "/tmp";
1841 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1842 gameCopyFilename = (char*) malloc(i);
1843 gamePasteFilename = (char*) malloc(i);
1844 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1845 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1847 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1848 clientResources, XtNumber(clientResources),
1851 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1852 static char buf[MSG_SIZ];
1853 EscapeExpand(buf, appData.initString);
1854 appData.initString = strdup(buf);
1855 EscapeExpand(buf, appData.secondInitString);
1856 appData.secondInitString = strdup(buf);
1857 EscapeExpand(buf, appData.firstComputerString);
1858 appData.firstComputerString = strdup(buf);
1859 EscapeExpand(buf, appData.secondComputerString);
1860 appData.secondComputerString = strdup(buf);
1863 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1866 if (chdir(chessDir) != 0) {
1867 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1873 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1874 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1875 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1876 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1879 setbuf(debugFP, NULL);
1882 /* [HGM,HR] make sure board size is acceptable */
1883 if(appData.NrFiles > BOARD_FILES ||
1884 appData.NrRanks > BOARD_RANKS )
1885 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1888 /* This feature does not work; animation needs a rewrite */
1889 appData.highlightDragging = FALSE;
1893 xDisplay = XtDisplay(shellWidget);
1894 xScreen = DefaultScreen(xDisplay);
1895 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1897 gameInfo.variant = StringToVariant(appData.variant);
1898 InitPosition(FALSE);
1901 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1903 if (isdigit(appData.boardSize[0])) {
1904 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1905 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1906 &fontPxlSize, &smallLayout, &tinyLayout);
1908 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1909 programName, appData.boardSize);
1913 /* Find some defaults; use the nearest known size */
1914 SizeDefaults *szd, *nearest;
1915 int distance = 99999;
1916 nearest = szd = sizeDefaults;
1917 while (szd->name != NULL) {
1918 if (abs(szd->squareSize - squareSize) < distance) {
1920 distance = abs(szd->squareSize - squareSize);
1921 if (distance == 0) break;
1925 if (i < 2) lineGap = nearest->lineGap;
1926 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1927 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1928 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1929 if (i < 6) smallLayout = nearest->smallLayout;
1930 if (i < 7) tinyLayout = nearest->tinyLayout;
1933 SizeDefaults *szd = sizeDefaults;
1934 if (*appData.boardSize == NULLCHAR) {
1935 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1936 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1939 if (szd->name == NULL) szd--;
1940 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1942 while (szd->name != NULL &&
1943 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1944 if (szd->name == NULL) {
1945 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1946 programName, appData.boardSize);
1950 squareSize = szd->squareSize;
1951 lineGap = szd->lineGap;
1952 clockFontPxlSize = szd->clockFontPxlSize;
1953 coordFontPxlSize = szd->coordFontPxlSize;
1954 fontPxlSize = szd->fontPxlSize;
1955 smallLayout = szd->smallLayout;
1956 tinyLayout = szd->tinyLayout;
1957 // [HGM] font: use defaults from settings file if available and not overruled
1959 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1960 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1961 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1962 appData.font = fontTable[MESSAGE_FONT][squareSize];
1963 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1964 appData.coordFont = fontTable[COORD_FONT][squareSize];
1966 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1967 if (strlen(appData.pixmapDirectory) > 0) {
1968 p = ExpandPathName(appData.pixmapDirectory);
1970 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1971 appData.pixmapDirectory);
1974 if (appData.debugMode) {
1975 fprintf(stderr, _("\
1976 XBoard square size (hint): %d\n\
1977 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1979 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1980 if (appData.debugMode) {
1981 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1984 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1986 /* [HR] height treated separately (hacked) */
1987 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1988 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1989 if (appData.showJail == 1) {
1990 /* Jail on top and bottom */
1991 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1992 XtSetArg(boardArgs[2], XtNheight,
1993 boardHeight + 2*(lineGap + squareSize));
1994 } else if (appData.showJail == 2) {
1996 XtSetArg(boardArgs[1], XtNwidth,
1997 boardWidth + 2*(lineGap + squareSize));
1998 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2001 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2002 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2006 * Determine what fonts to use.
2008 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2009 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2010 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2011 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2012 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2013 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2014 appData.font = FindFont(appData.font, fontPxlSize);
2015 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2016 countFontStruct = XQueryFont(xDisplay, countFontID);
2017 // appData.font = FindFont(appData.font, fontPxlSize);
2019 xdb = XtDatabase(xDisplay);
2020 XrmPutStringResource(&xdb, "*font", appData.font);
2023 * Detect if there are not enough colors available and adapt.
2025 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2026 appData.monoMode = True;
2029 if (!appData.monoMode) {
2030 vFrom.addr = (caddr_t) appData.lightSquareColor;
2031 vFrom.size = strlen(appData.lightSquareColor);
2032 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2033 if (vTo.addr == NULL) {
2034 appData.monoMode = True;
2037 lightSquareColor = *(Pixel *) vTo.addr;
2040 if (!appData.monoMode) {
2041 vFrom.addr = (caddr_t) appData.darkSquareColor;
2042 vFrom.size = strlen(appData.darkSquareColor);
2043 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2044 if (vTo.addr == NULL) {
2045 appData.monoMode = True;
2048 darkSquareColor = *(Pixel *) vTo.addr;
2051 if (!appData.monoMode) {
2052 vFrom.addr = (caddr_t) appData.whitePieceColor;
2053 vFrom.size = strlen(appData.whitePieceColor);
2054 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2055 if (vTo.addr == NULL) {
2056 appData.monoMode = True;
2059 whitePieceColor = *(Pixel *) vTo.addr;
2062 if (!appData.monoMode) {
2063 vFrom.addr = (caddr_t) appData.blackPieceColor;
2064 vFrom.size = strlen(appData.blackPieceColor);
2065 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2066 if (vTo.addr == NULL) {
2067 appData.monoMode = True;
2070 blackPieceColor = *(Pixel *) vTo.addr;
2074 if (!appData.monoMode) {
2075 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2076 vFrom.size = strlen(appData.highlightSquareColor);
2077 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2078 if (vTo.addr == NULL) {
2079 appData.monoMode = True;
2082 highlightSquareColor = *(Pixel *) vTo.addr;
2086 if (!appData.monoMode) {
2087 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2088 vFrom.size = strlen(appData.premoveHighlightColor);
2089 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2090 if (vTo.addr == NULL) {
2091 appData.monoMode = True;
2094 premoveHighlightColor = *(Pixel *) vTo.addr;
2099 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2102 if (appData.bitmapDirectory == NULL ||
2103 appData.bitmapDirectory[0] == NULLCHAR)
2104 appData.bitmapDirectory = DEF_BITMAP_DIR;
2107 if (appData.lowTimeWarning && !appData.monoMode) {
2108 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2109 vFrom.size = strlen(appData.lowTimeWarningColor);
2110 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2111 if (vTo.addr == NULL)
2112 appData.monoMode = True;
2114 lowTimeWarningColor = *(Pixel *) vTo.addr;
2117 if (appData.monoMode && appData.debugMode) {
2118 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2119 (unsigned long) XWhitePixel(xDisplay, xScreen),
2120 (unsigned long) XBlackPixel(xDisplay, xScreen));
2123 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2124 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2125 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2126 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2127 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2128 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2129 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2130 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2131 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2132 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2134 if (appData.colorize) {
2136 _("%s: can't parse color names; disabling colorization\n"),
2139 appData.colorize = FALSE;
2141 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2142 textColors[ColorNone].attr = 0;
2144 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2150 layoutName = "tinyLayout";
2151 } else if (smallLayout) {
2152 layoutName = "smallLayout";
2154 layoutName = "normalLayout";
2156 /* Outer layoutWidget is there only to provide a name for use in
2157 resources that depend on the layout style */
2159 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2160 layoutArgs, XtNumber(layoutArgs));
2162 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2163 formArgs, XtNumber(formArgs));
2164 XtSetArg(args[0], XtNdefaultDistance, &sep);
2165 XtGetValues(formWidget, args, 1);
2168 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2169 XtSetArg(args[0], XtNtop, XtChainTop);
2170 XtSetArg(args[1], XtNbottom, XtChainTop);
2171 XtSetArg(args[2], XtNright, XtChainLeft);
2172 XtSetValues(menuBarWidget, args, 3);
2174 widgetList[j++] = whiteTimerWidget =
2175 XtCreateWidget("whiteTime", labelWidgetClass,
2176 formWidget, timerArgs, XtNumber(timerArgs));
2177 XtSetArg(args[0], XtNfont, clockFontStruct);
2178 XtSetArg(args[1], XtNtop, XtChainTop);
2179 XtSetArg(args[2], XtNbottom, XtChainTop);
2180 XtSetValues(whiteTimerWidget, args, 3);
2182 widgetList[j++] = blackTimerWidget =
2183 XtCreateWidget("blackTime", labelWidgetClass,
2184 formWidget, timerArgs, XtNumber(timerArgs));
2185 XtSetArg(args[0], XtNfont, clockFontStruct);
2186 XtSetArg(args[1], XtNtop, XtChainTop);
2187 XtSetArg(args[2], XtNbottom, XtChainTop);
2188 XtSetValues(blackTimerWidget, args, 3);
2190 if (appData.titleInWindow) {
2191 widgetList[j++] = titleWidget =
2192 XtCreateWidget("title", labelWidgetClass, formWidget,
2193 titleArgs, XtNumber(titleArgs));
2194 XtSetArg(args[0], XtNtop, XtChainTop);
2195 XtSetArg(args[1], XtNbottom, XtChainTop);
2196 XtSetValues(titleWidget, args, 2);
2199 if (appData.showButtonBar) {
2200 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2201 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2202 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2203 XtSetArg(args[2], XtNtop, XtChainTop);
2204 XtSetArg(args[3], XtNbottom, XtChainTop);
2205 XtSetValues(buttonBarWidget, args, 4);
2208 widgetList[j++] = messageWidget =
2209 XtCreateWidget("message", labelWidgetClass, formWidget,
2210 messageArgs, XtNumber(messageArgs));
2211 XtSetArg(args[0], XtNtop, XtChainTop);
2212 XtSetArg(args[1], XtNbottom, XtChainTop);
2213 XtSetValues(messageWidget, args, 2);
2215 widgetList[j++] = boardWidget =
2216 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2217 XtNumber(boardArgs));
2219 XtManageChildren(widgetList, j);
2221 timerWidth = (boardWidth - sep) / 2;
2222 XtSetArg(args[0], XtNwidth, timerWidth);
2223 XtSetValues(whiteTimerWidget, args, 1);
2224 XtSetValues(blackTimerWidget, args, 1);
2226 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2227 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2228 XtGetValues(whiteTimerWidget, args, 2);
2230 if (appData.showButtonBar) {
2231 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2232 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2233 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2237 * formWidget uses these constraints but they are stored
2241 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2242 XtSetValues(menuBarWidget, args, i);
2243 if (appData.titleInWindow) {
2246 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2247 XtSetValues(whiteTimerWidget, args, i);
2249 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2250 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2251 XtSetValues(blackTimerWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2254 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2255 XtSetValues(titleWidget, args, i);
2257 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2258 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2259 XtSetValues(messageWidget, args, i);
2260 if (appData.showButtonBar) {
2262 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2263 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2264 XtSetValues(buttonBarWidget, args, i);
2268 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2269 XtSetValues(whiteTimerWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2272 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2273 XtSetValues(blackTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2276 XtSetValues(titleWidget, args, i);
2278 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2279 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2280 XtSetValues(messageWidget, args, i);
2281 if (appData.showButtonBar) {
2283 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2284 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2285 XtSetValues(buttonBarWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2291 XtSetValues(whiteTimerWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2294 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2295 XtSetValues(blackTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2298 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2299 XtSetValues(messageWidget, args, i);
2300 if (appData.showButtonBar) {
2302 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2303 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2304 XtSetValues(buttonBarWidget, args, i);
2308 XtSetArg(args[0], XtNfromVert, messageWidget);
2309 XtSetArg(args[1], XtNtop, XtChainTop);
2310 XtSetArg(args[2], XtNbottom, XtChainBottom);
2311 XtSetArg(args[3], XtNleft, XtChainLeft);
2312 XtSetArg(args[4], XtNright, XtChainRight);
2313 XtSetValues(boardWidget, args, 5);
2315 XtRealizeWidget(shellWidget);
2318 XtSetArg(args[0], XtNx, wpMain.x);
2319 XtSetArg(args[1], XtNy, wpMain.y);
2320 XtSetValues(shellWidget, args, 2);
2324 * Correct the width of the message and title widgets.
2325 * It is not known why some systems need the extra fudge term.
2326 * The value "2" is probably larger than needed.
2328 XawFormDoLayout(formWidget, False);
2330 #define WIDTH_FUDGE 2
2332 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2333 XtSetArg(args[i], XtNheight, &h); i++;
2334 XtGetValues(messageWidget, args, i);
2335 if (appData.showButtonBar) {
2337 XtSetArg(args[i], XtNwidth, &w); i++;
2338 XtGetValues(buttonBarWidget, args, i);
2339 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2341 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2344 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2345 if (gres != XtGeometryYes && appData.debugMode) {
2346 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2347 programName, gres, w, h, wr, hr);
2350 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2351 /* The size used for the child widget in layout lags one resize behind
2352 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2354 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2355 if (gres != XtGeometryYes && appData.debugMode) {
2356 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2357 programName, gres, w, h, wr, hr);
2360 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2361 XtSetArg(args[1], XtNright, XtChainRight);
2362 XtSetValues(messageWidget, args, 2);
2364 if (appData.titleInWindow) {
2366 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2367 XtSetArg(args[i], XtNheight, &h); i++;
2368 XtGetValues(titleWidget, args, i);
2370 w = boardWidth - 2*bor;
2372 XtSetArg(args[0], XtNwidth, &w);
2373 XtGetValues(menuBarWidget, args, 1);
2374 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2377 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2378 if (gres != XtGeometryYes && appData.debugMode) {
2380 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2381 programName, gres, w, h, wr, hr);
2384 XawFormDoLayout(formWidget, True);
2386 xBoardWindow = XtWindow(boardWidget);
2388 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2389 // not need to go into InitDrawingSizes().
2393 * Create X checkmark bitmap and initialize option menu checks.
2395 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2396 checkmark_bits, checkmark_width, checkmark_height);
2397 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2398 if (appData.alwaysPromoteToQueen) {
2399 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2402 if (appData.animateDragging) {
2403 XtSetValues(XtNameToWidget(menuBarWidget,
2404 "menuOptions.Animate Dragging"),
2407 if (appData.animate) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2411 if (appData.autoComment) {
2412 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2415 if (appData.autoCallFlag) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2419 if (appData.autoFlipView) {
2420 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2423 if (appData.autoObserve) {
2424 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2427 if (appData.autoRaiseBoard) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Auto Raise Board"), args, 1);
2431 if (appData.autoSaveGames) {
2432 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2435 if (appData.saveGameFile[0] != NULLCHAR) {
2436 /* Can't turn this off from menu */
2437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2439 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2443 if (appData.blindfold) {
2444 XtSetValues(XtNameToWidget(menuBarWidget,
2445 "menuOptions.Blindfold"), args, 1);
2447 if (appData.flashCount > 0) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Flash Moves"),
2452 if (appData.getMoveList) {
2453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2457 if (appData.highlightDragging) {
2458 XtSetValues(XtNameToWidget(menuBarWidget,
2459 "menuOptions.Highlight Dragging"),
2463 if (appData.highlightLastMove) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Highlight Last Move"),
2468 if (appData.icsAlarm) {
2469 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2472 if (appData.ringBellAfterMoves) {
2473 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2476 if (appData.oldSaveStyle) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Old Save Style"), args, 1);
2480 if (appData.periodicUpdates) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Periodic Updates"), args, 1);
2484 if (appData.ponderNextMove) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Ponder Next Move"), args, 1);
2488 if (appData.popupExitMessage) {
2489 XtSetValues(XtNameToWidget(menuBarWidget,
2490 "menuOptions.Popup Exit Message"), args, 1);
2492 if (appData.popupMoveErrors) {
2493 XtSetValues(XtNameToWidget(menuBarWidget,
2494 "menuOptions.Popup Move Errors"), args, 1);
2496 if (appData.premove) {
2497 XtSetValues(XtNameToWidget(menuBarWidget,
2498 "menuOptions.Premove"), args, 1);
2500 if (appData.quietPlay) {
2501 XtSetValues(XtNameToWidget(menuBarWidget,
2502 "menuOptions.Quiet Play"), args, 1);
2504 if (appData.showCoords) {
2505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2508 if (appData.hideThinkingFromHuman) {
2509 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2512 if (appData.testLegality) {
2513 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2516 if (saveSettingsOnExit) {
2517 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2524 ReadBitmap(&wIconPixmap, "icon_white.bm",
2525 icon_white_bits, icon_white_width, icon_white_height);
2526 ReadBitmap(&bIconPixmap, "icon_black.bm",
2527 icon_black_bits, icon_black_width, icon_black_height);
2528 iconPixmap = wIconPixmap;
2530 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2531 XtSetValues(shellWidget, args, i);
2534 * Create a cursor for the board widget.
2536 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2537 XChangeWindowAttributes(xDisplay, xBoardWindow,
2538 CWCursor, &window_attributes);
2541 * Inhibit shell resizing.
2543 shellArgs[0].value = (XtArgVal) &w;
2544 shellArgs[1].value = (XtArgVal) &h;
2545 XtGetValues(shellWidget, shellArgs, 2);
2546 shellArgs[4].value = shellArgs[2].value = w;
2547 shellArgs[5].value = shellArgs[3].value = h;
2548 XtSetValues(shellWidget, &shellArgs[2], 4);
2549 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2550 marginH = h - boardHeight;
2552 CatchDeleteWindow(shellWidget, "QuitProc");
2557 if (appData.bitmapDirectory[0] != NULLCHAR) {
2561 CreateXPMBoard(appData.liteBackTextureFile, 1);
2562 CreateXPMBoard(appData.darkBackTextureFile, 0);
2566 /* Create regular pieces */
2567 if (!useImages) CreatePieces();
2572 if (appData.animate || appData.animateDragging)
2575 XtAugmentTranslations(formWidget,
2576 XtParseTranslationTable(globalTranslations));
2577 XtAugmentTranslations(boardWidget,
2578 XtParseTranslationTable(boardTranslations));
2579 XtAugmentTranslations(whiteTimerWidget,
2580 XtParseTranslationTable(whiteTranslations));
2581 XtAugmentTranslations(blackTimerWidget,
2582 XtParseTranslationTable(blackTranslations));
2584 /* Why is the following needed on some versions of X instead
2585 * of a translation? */
2586 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2587 (XtEventHandler) EventProc, NULL);
2590 /* [AS] Restore layout */
2591 if( wpMoveHistory.visible ) {
2595 if( wpEvalGraph.visible )
2600 if( wpEngineOutput.visible ) {
2601 EngineOutputPopUp();
2606 if (errorExitStatus == -1) {
2607 if (appData.icsActive) {
2608 /* We now wait until we see "login:" from the ICS before
2609 sending the logon script (problems with timestamp otherwise) */
2610 /*ICSInitScript();*/
2611 if (appData.icsInputBox) ICSInputBoxPopUp();
2615 signal(SIGWINCH, TermSizeSigHandler);
2617 signal(SIGINT, IntSigHandler);
2618 signal(SIGTERM, IntSigHandler);
2619 if (*appData.cmailGameName != NULLCHAR) {
2620 signal(SIGUSR1, CmailSigHandler);
2623 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2625 XtSetKeyboardFocus(shellWidget, formWidget);
2627 XtAppMainLoop(appContext);
2628 if (appData.debugMode) fclose(debugFP); // [DM] debug
2635 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2636 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2638 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2639 unlink(gameCopyFilename);
2640 unlink(gamePasteFilename);
2642 # if HAVE_LIBREADLINE
2643 /* remove gnu-readline handler. */
2644 rl_callback_handler_remove();
2650 RETSIGTYPE TermSizeSigHandler(int sig)
2663 CmailSigHandler(sig)
2669 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2671 /* Activate call-back function CmailSigHandlerCallBack() */
2672 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2674 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2678 CmailSigHandlerCallBack(isr, closure, message, count, error)
2686 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2688 /**** end signal code ****/
2694 /* try to open the icsLogon script, either in the location given
2695 * or in the users HOME directory
2702 f = fopen(appData.icsLogon, "r");
2705 homedir = getenv("HOME");
2706 if (homedir != NULL)
2708 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2709 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2710 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2711 f = fopen(buf, "r");
2716 ProcessICSInitScript(f);
2718 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2727 EditCommentPopDown();
2742 if (!menuBarWidget) return;
2743 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2745 DisplayError("menuStep.Revert", 0);
2747 XtSetSensitive(w, !grey);
2749 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2751 DisplayError("menuStep.Annotate", 0);
2753 XtSetSensitive(w, !grey);
2758 SetMenuEnables(enab)
2762 if (!menuBarWidget) return;
2763 while (enab->name != NULL) {
2764 w = XtNameToWidget(menuBarWidget, enab->name);
2766 DisplayError(enab->name, 0);
2768 XtSetSensitive(w, enab->value);
2774 Enables icsEnables[] = {
2775 { "menuFile.Mail Move", False },
2776 { "menuFile.Reload CMail Message", False },
2777 { "menuMode.Machine Black", False },
2778 { "menuMode.Machine White", False },
2779 { "menuMode.Analysis Mode", False },
2780 { "menuMode.Analyze File", False },
2781 { "menuMode.Two Machines", False },
2783 { "menuHelp.Hint", False },
2784 { "menuHelp.Book", False },
2785 { "menuStep.Move Now", False },
2786 { "menuOptions.Periodic Updates", False },
2787 { "menuOptions.Hide Thinking", False },
2788 { "menuOptions.Ponder Next Move", False },
2790 { "menuStep.Annotate", False },
2794 Enables ncpEnables[] = {
2795 { "menuFile.Mail Move", False },
2796 { "menuFile.Reload CMail Message", False },
2797 { "menuMode.Machine White", False },
2798 { "menuMode.Machine Black", False },
2799 { "menuMode.Analysis Mode", False },
2800 { "menuMode.Analyze File", False },
2801 { "menuMode.Two Machines", False },
2802 { "menuMode.ICS Client", False },
2803 { "menuMode.ICS Input Box", False },
2804 { "Action", False },
2805 { "menuStep.Revert", False },
2806 { "menuStep.Annotate", False },
2807 { "menuStep.Move Now", False },
2808 { "menuStep.Retract Move", False },
2809 { "menuOptions.Auto Comment", False },
2810 { "menuOptions.Auto Flag", False },
2811 { "menuOptions.Auto Flip View", False },
2812 { "menuOptions.Auto Observe", False },
2813 { "menuOptions.Auto Raise Board", False },
2814 { "menuOptions.Get Move List", False },
2815 { "menuOptions.ICS Alarm", False },
2816 { "menuOptions.Move Sound", False },
2817 { "menuOptions.Quiet Play", False },
2818 { "menuOptions.Hide Thinking", False },
2819 { "menuOptions.Periodic Updates", False },
2820 { "menuOptions.Ponder Next Move", False },
2821 { "menuHelp.Hint", False },
2822 { "menuHelp.Book", False },
2826 Enables gnuEnables[] = {
2827 { "menuMode.ICS Client", False },
2828 { "menuMode.ICS Input Box", False },
2829 { "menuAction.Accept", False },
2830 { "menuAction.Decline", False },
2831 { "menuAction.Rematch", False },
2832 { "menuAction.Adjourn", False },
2833 { "menuAction.Stop Examining", False },
2834 { "menuAction.Stop Observing", False },
2835 { "menuAction.Upload to Examine", False },
2836 { "menuStep.Revert", False },
2837 { "menuStep.Annotate", False },
2838 { "menuOptions.Auto Comment", False },
2839 { "menuOptions.Auto Observe", False },
2840 { "menuOptions.Auto Raise Board", False },
2841 { "menuOptions.Get Move List", False },
2842 { "menuOptions.Premove", False },
2843 { "menuOptions.Quiet Play", False },
2845 /* The next two options rely on SetCmailMode being called *after* */
2846 /* SetGNUMode so that when GNU is being used to give hints these */
2847 /* menu options are still available */
2849 { "menuFile.Mail Move", False },
2850 { "menuFile.Reload CMail Message", False },
2854 Enables cmailEnables[] = {
2856 { "menuAction.Call Flag", False },
2857 { "menuAction.Draw", True },
2858 { "menuAction.Adjourn", False },
2859 { "menuAction.Abort", False },
2860 { "menuAction.Stop Observing", False },
2861 { "menuAction.Stop Examining", False },
2862 { "menuFile.Mail Move", True },
2863 { "menuFile.Reload CMail Message", True },
2867 Enables trainingOnEnables[] = {
2868 { "menuMode.Edit Comment", False },
2869 { "menuMode.Pause", False },
2870 { "menuStep.Forward", False },
2871 { "menuStep.Backward", False },
2872 { "menuStep.Forward to End", False },
2873 { "menuStep.Back to Start", False },
2874 { "menuStep.Move Now", False },
2875 { "menuStep.Truncate Game", False },
2879 Enables trainingOffEnables[] = {
2880 { "menuMode.Edit Comment", True },
2881 { "menuMode.Pause", True },
2882 { "menuStep.Forward", True },
2883 { "menuStep.Backward", True },
2884 { "menuStep.Forward to End", True },
2885 { "menuStep.Back to Start", True },
2886 { "menuStep.Move Now", True },
2887 { "menuStep.Truncate Game", True },
2891 Enables machineThinkingEnables[] = {
2892 { "menuFile.Load Game", False },
2893 { "menuFile.Load Next Game", False },
2894 { "menuFile.Load Previous Game", False },
2895 { "menuFile.Reload Same Game", False },
2896 { "menuFile.Paste Game", False },
2897 { "menuFile.Load Position", False },
2898 { "menuFile.Load Next Position", False },
2899 { "menuFile.Load Previous Position", False },
2900 { "menuFile.Reload Same Position", False },
2901 { "menuFile.Paste Position", False },
2902 { "menuMode.Machine White", False },
2903 { "menuMode.Machine Black", False },
2904 { "menuMode.Two Machines", False },
2905 { "menuStep.Retract Move", False },
2909 Enables userThinkingEnables[] = {
2910 { "menuFile.Load Game", True },
2911 { "menuFile.Load Next Game", True },
2912 { "menuFile.Load Previous Game", True },
2913 { "menuFile.Reload Same Game", True },
2914 { "menuFile.Paste Game", True },
2915 { "menuFile.Load Position", True },
2916 { "menuFile.Load Next Position", True },
2917 { "menuFile.Load Previous Position", True },
2918 { "menuFile.Reload Same Position", True },
2919 { "menuFile.Paste Position", True },
2920 { "menuMode.Machine White", True },
2921 { "menuMode.Machine Black", True },
2922 { "menuMode.Two Machines", True },
2923 { "menuStep.Retract Move", True },
2929 SetMenuEnables(icsEnables);
2932 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2933 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2940 SetMenuEnables(ncpEnables);
2946 SetMenuEnables(gnuEnables);
2952 SetMenuEnables(cmailEnables);
2958 SetMenuEnables(trainingOnEnables);
2959 if (appData.showButtonBar) {
2960 XtSetSensitive(buttonBarWidget, False);
2966 SetTrainingModeOff()
2968 SetMenuEnables(trainingOffEnables);
2969 if (appData.showButtonBar) {
2970 XtSetSensitive(buttonBarWidget, True);
2975 SetUserThinkingEnables()
2977 if (appData.noChessProgram) return;
2978 SetMenuEnables(userThinkingEnables);
2982 SetMachineThinkingEnables()
2984 if (appData.noChessProgram) return;
2985 SetMenuEnables(machineThinkingEnables);
2987 case MachinePlaysBlack:
2988 case MachinePlaysWhite:
2989 case TwoMachinesPlay:
2990 XtSetSensitive(XtNameToWidget(menuBarWidget,
2991 ModeToWidgetName(gameMode)), True);
2998 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2999 #define HISTORY_SIZE 64
\r
3000 static char *history[HISTORY_SIZE];
\r
3001 int histIn = 0, histP = 0;
\r
3004 SaveInHistory(char *cmd)
\r
3006 if (history[histIn] != NULL) {
\r
3007 free(history[histIn]);
\r
3008 history[histIn] = NULL;
\r
3010 if (*cmd == NULLCHAR) return;
\r
3011 history[histIn] = StrSave(cmd);
\r
3012 histIn = (histIn + 1) % HISTORY_SIZE;
\r
3013 if (history[histIn] != NULL) {
\r
3014 free(history[histIn]);
\r
3015 history[histIn] = NULL;
\r
3021 PrevInHistory(char *cmd)
\r
3024 if (histP == histIn) {
\r
3025 if (history[histIn] != NULL) free(history[histIn]);
\r
3026 history[histIn] = StrSave(cmd);
\r
3028 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3029 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3031 return history[histP];
\r
3037 if (histP == histIn) return NULL;
\r
3038 histP = (histP + 1) % HISTORY_SIZE;
\r
3039 return history[histP];
\r
3041 // end of borrowed code
\r
3043 #define Abs(n) ((n)<0 ? -(n) : (n))
3046 * Find a font that matches "pattern" that is as close as
3047 * possible to the targetPxlSize. Prefer fonts that are k
3048 * pixels smaller to fonts that are k pixels larger. The
3049 * pattern must be in the X Consortium standard format,
3050 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3051 * The return value should be freed with XtFree when no
3055 FindFont(pattern, targetPxlSize)
3059 char **fonts, *p, *best, *scalable, *scalableTail;
3060 int i, j, nfonts, minerr, err, pxlSize;
3063 char **missing_list;
3065 char *def_string, *base_fnt_lst, strInt[3];
3067 XFontStruct **fnt_list;
3069 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3070 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3071 p = strstr(pattern, "--");
3072 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3073 strcat(base_fnt_lst, strInt);
3074 strcat(base_fnt_lst, strchr(p + 2, '-'));
3076 if ((fntSet = XCreateFontSet(xDisplay,
3080 &def_string)) == NULL) {
3082 fprintf(stderr, _("Unable to create font set.\n"));
3086 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3088 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3090 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3091 programName, pattern);
3099 for (i=0; i<nfonts; i++) {
3102 if (*p != '-') continue;
3104 if (*p == NULLCHAR) break;
3105 if (*p++ == '-') j++;
3107 if (j < 7) continue;
3110 scalable = fonts[i];
3113 err = pxlSize - targetPxlSize;
3114 if (Abs(err) < Abs(minerr) ||
3115 (minerr > 0 && err < 0 && -err == minerr)) {
3121 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3122 /* If the error is too big and there is a scalable font,
3123 use the scalable font. */
3124 int headlen = scalableTail - scalable;
3125 p = (char *) XtMalloc(strlen(scalable) + 10);
3126 while (isdigit(*scalableTail)) scalableTail++;
3127 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3129 p = (char *) XtMalloc(strlen(best) + 2);
3130 safeStrCpy(p, best, strlen(best)+1 );
3132 if (appData.debugMode) {
3133 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3134 pattern, targetPxlSize, p);
3137 if (missing_count > 0)
3138 XFreeStringList(missing_list);
3139 XFreeFontSet(xDisplay, fntSet);
3141 XFreeFontNames(fonts);
3148 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3149 | GCBackground | GCFunction | GCPlaneMask;
3150 XGCValues gc_values;
3153 gc_values.plane_mask = AllPlanes;
3154 gc_values.line_width = lineGap;
3155 gc_values.line_style = LineSolid;
3156 gc_values.function = GXcopy;
3158 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3159 gc_values.background = XBlackPixel(xDisplay, xScreen);
3160 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3162 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3163 gc_values.background = XWhitePixel(xDisplay, xScreen);
3164 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3165 XSetFont(xDisplay, coordGC, coordFontID);
3167 // [HGM] make font for holdings counts (white on black0
3168 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3169 gc_values.background = XBlackPixel(xDisplay, xScreen);
3170 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3171 XSetFont(xDisplay, countGC, countFontID);
3173 if (appData.monoMode) {
3174 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3175 gc_values.background = XWhitePixel(xDisplay, xScreen);
3176 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3178 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3179 gc_values.background = XBlackPixel(xDisplay, xScreen);
3180 lightSquareGC = wbPieceGC
3181 = XtGetGC(shellWidget, value_mask, &gc_values);
3183 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3184 gc_values.background = XWhitePixel(xDisplay, xScreen);
3185 darkSquareGC = bwPieceGC
3186 = XtGetGC(shellWidget, value_mask, &gc_values);
3188 if (DefaultDepth(xDisplay, xScreen) == 1) {
3189 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3190 gc_values.function = GXcopyInverted;
3191 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3192 gc_values.function = GXcopy;
3193 if (XBlackPixel(xDisplay, xScreen) == 1) {
3194 bwPieceGC = darkSquareGC;
3195 wbPieceGC = copyInvertedGC;
3197 bwPieceGC = copyInvertedGC;
3198 wbPieceGC = lightSquareGC;
3202 gc_values.foreground = highlightSquareColor;
3203 gc_values.background = highlightSquareColor;
3204 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = premoveHighlightColor;
3207 gc_values.background = premoveHighlightColor;
3208 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3210 gc_values.foreground = lightSquareColor;
3211 gc_values.background = darkSquareColor;
3212 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3214 gc_values.foreground = darkSquareColor;
3215 gc_values.background = lightSquareColor;
3216 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3218 gc_values.foreground = jailSquareColor;
3219 gc_values.background = jailSquareColor;
3220 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3222 gc_values.foreground = whitePieceColor;
3223 gc_values.background = darkSquareColor;
3224 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3226 gc_values.foreground = whitePieceColor;
3227 gc_values.background = lightSquareColor;
3228 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 gc_values.foreground = whitePieceColor;
3231 gc_values.background = jailSquareColor;
3232 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3234 gc_values.foreground = blackPieceColor;
3235 gc_values.background = darkSquareColor;
3236 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3238 gc_values.foreground = blackPieceColor;
3239 gc_values.background = lightSquareColor;
3240 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3242 gc_values.foreground = blackPieceColor;
3243 gc_values.background = jailSquareColor;
3244 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3248 void loadXIM(xim, xmask, filename, dest, mask)
3261 fp = fopen(filename, "rb");
3263 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3270 for (y=0; y<h; ++y) {
3271 for (x=0; x<h; ++x) {
3276 XPutPixel(xim, x, y, blackPieceColor);
3278 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3281 XPutPixel(xim, x, y, darkSquareColor);
3283 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3286 XPutPixel(xim, x, y, whitePieceColor);
3288 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3291 XPutPixel(xim, x, y, lightSquareColor);
3293 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3299 /* create Pixmap of piece */
3300 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3302 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3305 /* create Pixmap of clipmask
3306 Note: We assume the white/black pieces have the same
3307 outline, so we make only 6 masks. This is okay
3308 since the XPM clipmask routines do the same. */
3310 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3312 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3315 /* now create the 1-bit version */
3316 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3319 values.foreground = 1;
3320 values.background = 0;
3322 /* Don't use XtGetGC, not read only */
3323 maskGC = XCreateGC(xDisplay, *mask,
3324 GCForeground | GCBackground, &values);
3325 XCopyPlane(xDisplay, temp, *mask, maskGC,
3326 0, 0, squareSize, squareSize, 0, 0, 1);
3327 XFreePixmap(xDisplay, temp);
3332 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3334 void CreateXIMPieces()
3339 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3344 /* The XSynchronize calls were copied from CreatePieces.
3345 Not sure if needed, but can't hurt */
3346 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3349 /* temp needed by loadXIM() */
3350 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3351 0, 0, ss, ss, AllPlanes, XYPixmap);
3353 if (strlen(appData.pixmapDirectory) == 0) {
3357 if (appData.monoMode) {
3358 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3362 fprintf(stderr, _("\nLoading XIMs...\n"));
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 fprintf(stderr, "%d", piece+1);
3366 for (kind=0; kind<4; kind++) {
3367 fprintf(stderr, ".");
3368 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3369 ExpandPathName(appData.pixmapDirectory),
3370 piece <= (int) WhiteKing ? "" : "w",
3371 pieceBitmapNames[piece],
3373 ximPieceBitmap[kind][piece] =
3374 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3375 0, 0, ss, ss, AllPlanes, XYPixmap);
3376 if (appData.debugMode)
3377 fprintf(stderr, _("(File:%s:) "), buf);
3378 loadXIM(ximPieceBitmap[kind][piece],
3380 &(xpmPieceBitmap2[kind][piece]),
3381 &(ximMaskPm2[piece]));
3382 if(piece <= (int)WhiteKing)
3383 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3385 fprintf(stderr," ");
3387 /* Load light and dark squares */
3388 /* If the LSQ and DSQ pieces don't exist, we will
3389 draw them with solid squares. */
3390 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3391 if (access(buf, 0) != 0) {
3395 fprintf(stderr, _("light square "));
3397 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3398 0, 0, ss, ss, AllPlanes, XYPixmap);
3399 if (appData.debugMode)
3400 fprintf(stderr, _("(File:%s:) "), buf);
3402 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3403 fprintf(stderr, _("dark square "));
3404 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3405 ExpandPathName(appData.pixmapDirectory), ss);
3406 if (appData.debugMode)
3407 fprintf(stderr, _("(File:%s:) "), buf);
3409 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3410 0, 0, ss, ss, AllPlanes, XYPixmap);
3411 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3412 xpmJailSquare = xpmLightSquare;
3414 fprintf(stderr, _("Done.\n"));
3416 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3420 void CreateXPMBoard(char *s, int kind)
3424 if(s == NULL || *s == 0 || *s == '*') return;
3425 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3426 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3430 void CreateXPMPieces()
3434 u_int ss = squareSize;
3436 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3437 XpmColorSymbol symbols[4];
3439 /* The XSynchronize calls were copied from CreatePieces.
3440 Not sure if needed, but can't hurt */
3441 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3443 /* Setup translations so piece colors match square colors */
3444 symbols[0].name = "light_piece";
3445 symbols[0].value = appData.whitePieceColor;
3446 symbols[1].name = "dark_piece";
3447 symbols[1].value = appData.blackPieceColor;
3448 symbols[2].name = "light_square";
3449 symbols[2].value = appData.lightSquareColor;
3450 symbols[3].name = "dark_square";
3451 symbols[3].value = appData.darkSquareColor;
3453 attr.valuemask = XpmColorSymbols;
3454 attr.colorsymbols = symbols;
3455 attr.numsymbols = 4;
3457 if (appData.monoMode) {
3458 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3462 if (strlen(appData.pixmapDirectory) == 0) {
3463 XpmPieces* pieces = builtInXpms;
3466 while (pieces->size != squareSize && pieces->size) pieces++;
3467 if (!pieces->size) {
3468 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3471 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3472 for (kind=0; kind<4; kind++) {
3474 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3475 pieces->xpm[piece][kind],
3476 &(xpmPieceBitmap2[kind][piece]),
3477 NULL, &attr)) != 0) {
3478 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3482 if(piece <= (int) WhiteKing)
3483 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3487 xpmJailSquare = xpmLightSquare;
3491 fprintf(stderr, _("\nLoading XPMs...\n"));
3494 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3495 fprintf(stderr, "%d ", piece+1);
3496 for (kind=0; kind<4; kind++) {
3497 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3498 ExpandPathName(appData.pixmapDirectory),
3499 piece > (int) WhiteKing ? "w" : "",
3500 pieceBitmapNames[piece],
3502 if (appData.debugMode) {
3503 fprintf(stderr, _("(File:%s:) "), buf);
3505 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3506 &(xpmPieceBitmap2[kind][piece]),
3507 NULL, &attr)) != 0) {
3508 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3509 // [HGM] missing: read of unorthodox piece failed; substitute King.
3510 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3511 ExpandPathName(appData.pixmapDirectory),
3513 if (appData.debugMode) {
3514 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3516 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3517 &(xpmPieceBitmap2[kind][piece]),
3521 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3526 if(piece <= (int) WhiteKing)
3527 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3530 /* Load light and dark squares */
3531 /* If the LSQ and DSQ pieces don't exist, we will
3532 draw them with solid squares. */
3533 fprintf(stderr, _("light square "));
3534 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3535 if (access(buf, 0) != 0) {
3539 if (appData.debugMode)
3540 fprintf(stderr, _("(File:%s:) "), buf);
3542 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3543 &xpmLightSquare, NULL, &attr)) != 0) {
3544 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3547 fprintf(stderr, _("dark square "));
3548 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3549 ExpandPathName(appData.pixmapDirectory), ss);
3550 if (appData.debugMode) {
3551 fprintf(stderr, _("(File:%s:) "), buf);
3553 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3554 &xpmDarkSquare, NULL, &attr)) != 0) {
3555 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3559 xpmJailSquare = xpmLightSquare;
3560 fprintf(stderr, _("Done.\n"));
3562 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3565 #endif /* HAVE_LIBXPM */
3568 /* No built-in bitmaps */
3573 u_int ss = squareSize;
3575 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3578 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3579 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3580 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3581 pieceBitmapNames[piece],
3582 ss, kind == SOLID ? 's' : 'o');
3583 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3584 if(piece <= (int)WhiteKing)
3585 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3589 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3593 /* With built-in bitmaps */
3596 BuiltInBits* bib = builtInBits;
3599 u_int ss = squareSize;
3601 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3604 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3606 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3607 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3608 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3609 pieceBitmapNames[piece],
3610 ss, kind == SOLID ? 's' : 'o');
3611 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3612 bib->bits[kind][piece], ss, ss);
3613 if(piece <= (int)WhiteKing)
3614 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3618 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3623 void ReadBitmap(pm, name, bits, wreq, hreq)
3626 unsigned char bits[];
3632 char msg[MSG_SIZ], fullname[MSG_SIZ];
3634 if (*appData.bitmapDirectory != NULLCHAR) {
3635 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3636 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3637 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3638 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3639 &w, &h, pm, &x_hot, &y_hot);
3640 fprintf(stderr, "load %s\n", name);
3641 if (errcode != BitmapSuccess) {
3643 case BitmapOpenFailed:
3644 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3646 case BitmapFileInvalid:
3647 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3649 case BitmapNoMemory:
3650 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3654 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3658 fprintf(stderr, _("%s: %s...using built-in\n"),
3660 } else if (w != wreq || h != hreq) {
3662 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3663 programName, fullname, w, h, wreq, hreq);
3669 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3678 if (lineGap == 0) return;
3680 /* [HR] Split this into 2 loops for non-square boards. */
3682 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3683 gridSegments[i].x1 = 0;
3684 gridSegments[i].x2 =
3685 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3686 gridSegments[i].y1 = gridSegments[i].y2
3687 = lineGap / 2 + (i * (squareSize + lineGap));
3690 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3691 gridSegments[j + i].y1 = 0;
3692 gridSegments[j + i].y2 =
3693 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3694 gridSegments[j + i].x1 = gridSegments[j + i].x2
3695 = lineGap / 2 + (j * (squareSize + lineGap));
3699 static void MenuBarSelect(w, addr, index)
3704 XtActionProc proc = (XtActionProc) addr;
3706 (proc)(NULL, NULL, NULL, NULL);
3709 void CreateMenuBarPopup(parent, name, mb)
3719 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3722 XtSetArg(args[j], XtNleftMargin, 20); j++;
3723 XtSetArg(args[j], XtNrightMargin, 20); j++;
3725 while (mi->string != NULL) {
3726 if (strcmp(mi->string, "----") == 0) {
3727 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3730 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3731 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3733 XtAddCallback(entry, XtNcallback,
3734 (XtCallbackProc) MenuBarSelect,
3735 (caddr_t) mi->proc);
3741 Widget CreateMenuBar(mb)
3745 Widget anchor, menuBar;
3747 char menuName[MSG_SIZ];
3750 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3751 XtSetArg(args[j], XtNvSpace, 0); j++;
3752 XtSetArg(args[j], XtNborderWidth, 0); j++;
3753 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3754 formWidget, args, j);
3756 while (mb->name != NULL) {
3757 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3758 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3760 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3763 shortName[0] = _(mb->name)[0];
3764 shortName[1] = NULLCHAR;
3765 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3768 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3771 XtSetArg(args[j], XtNborderWidth, 0); j++;
3772 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3774 CreateMenuBarPopup(menuBar, menuName, mb);
3780 Widget CreateButtonBar(mi)
3784 Widget button, buttonBar;
3788 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3790 XtSetArg(args[j], XtNhSpace, 0); j++;
3792 XtSetArg(args[j], XtNborderWidth, 0); j++;
3793 XtSetArg(args[j], XtNvSpace, 0); j++;
3794 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3795 formWidget, args, j);
3797 while (mi->string != NULL) {
3800 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3801 XtSetArg(args[j], XtNborderWidth, 0); j++;
3803 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3804 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3805 buttonBar, args, j);
3806 XtAddCallback(button, XtNcallback,
3807 (XtCallbackProc) MenuBarSelect,
3808 (caddr_t) mi->proc);
3815 CreatePieceMenu(name, color)
3822 ChessSquare selection;
3824 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3825 boardWidget, args, 0);
3827 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3828 String item = pieceMenuStrings[color][i];
3830 if (strcmp(item, "----") == 0) {
3831 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3834 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3835 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3837 selection = pieceMenuTranslation[color][i];
3838 XtAddCallback(entry, XtNcallback,
3839 (XtCallbackProc) PieceMenuSelect,
3840 (caddr_t) selection);
3841 if (selection == WhitePawn || selection == BlackPawn) {
3842 XtSetArg(args[0], XtNpopupOnEntry, entry);
3843 XtSetValues(menu, args, 1);
3856 ChessSquare selection;
3858 whitePieceMenu = CreatePieceMenu("menuW", 0);
3859 blackPieceMenu = CreatePieceMenu("menuB", 1);
3861 XtRegisterGrabAction(PieceMenuPopup, True,
3862 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3863 GrabModeAsync, GrabModeAsync);
3865 XtSetArg(args[0], XtNlabel, _("Drop"));
3866 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3867 boardWidget, args, 1);
3868 for (i = 0; i < DROP_MENU_SIZE; i++) {
3869 String item = dropMenuStrings[i];
3871 if (strcmp(item, "----") == 0) {
3872 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3875 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3876 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3878 selection = dropMenuTranslation[i];
3879 XtAddCallback(entry, XtNcallback,
3880 (XtCallbackProc) DropMenuSelect,
3881 (caddr_t) selection);
3886 void SetupDropMenu()
3894 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3895 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3896 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3897 dmEnables[i].piece);
3898 XtSetSensitive(entry, p != NULL || !appData.testLegality
3899 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3900 && !appData.icsActive));
3902 while (p && *p++ == dmEnables[i].piece) count++;
3903 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3905 XtSetArg(args[j], XtNlabel, label); j++;
3906 XtSetValues(entry, args, j);
3910 void PieceMenuPopup(w, event, params, num_params)
3914 Cardinal *num_params;
3916 String whichMenu; int menuNr;
3917 if (event->type == ButtonRelease)
3918 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3919 else if (event->type == ButtonPress)
3920 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3922 case 0: whichMenu = params[0]; break;
3923 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3925 case -1: if (errorUp) ErrorPopDown();
3928 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3931 static void PieceMenuSelect(w, piece, junk)
3936 if (pmFromX < 0 || pmFromY < 0) return;
3937 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3940 static void DropMenuSelect(w, piece, junk)
3945 if (pmFromX < 0 || pmFromY < 0) return;
3946 DropMenuEvent(piece, pmFromX, pmFromY);
3949 void WhiteClock(w, event, prms, nprms)
3955 if (gameMode == EditPosition || gameMode == IcsExamining) {
3956 SetWhiteToPlayEvent();
3957 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3962 void BlackClock(w, event, prms, nprms)
3968 if (gameMode == EditPosition || gameMode == IcsExamining) {
3969 SetBlackToPlayEvent();
3970 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3977 * If the user selects on a border boundary, return -1; if off the board,
3978 * return -2. Otherwise map the event coordinate to the square.
3980 int EventToSquare(x, limit)
3988 if ((x % (squareSize + lineGap)) >= squareSize)
3990 x /= (squareSize + lineGap);
3996 static void do_flash_delay(msec)
4002 static void drawHighlight(file, rank, gc)
4008 if (lineGap == 0 || appData.blindfold) return;
4011 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4012 (squareSize + lineGap);
4013 y = lineGap/2 + rank * (squareSize + lineGap);
4015 x = lineGap/2 + file * (squareSize + lineGap);
4016 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4017 (squareSize + lineGap);
4020 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4021 squareSize+lineGap, squareSize+lineGap);
4024 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4025 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4028 SetHighlights(fromX, fromY, toX, toY)
4029 int fromX, fromY, toX, toY;
4031 if (hi1X != fromX || hi1Y != fromY) {
4032 if (hi1X >= 0 && hi1Y >= 0) {
4033 drawHighlight(hi1X, hi1Y, lineGC);
4035 } // [HGM] first erase both, then draw new!
4036 if (hi2X != toX || hi2Y != toY) {
4037 if (hi2X >= 0 && hi2Y >= 0) {
4038 drawHighlight(hi2X, hi2Y, lineGC);
4041 if (hi1X != fromX || hi1Y != fromY) {
4042 if (fromX >= 0 && fromY >= 0) {
4043 drawHighlight(fromX, fromY, highlineGC);
4046 if (hi2X != toX || hi2Y != toY) {
4047 if (toX >= 0 && toY >= 0) {
4048 drawHighlight(toX, toY, highlineGC);
4060 SetHighlights(-1, -1, -1, -1);
4065 SetPremoveHighlights(fromX, fromY, toX, toY)
4066 int fromX, fromY, toX, toY;
4068 if (pm1X != fromX || pm1Y != fromY) {
4069 if (pm1X >= 0 && pm1Y >= 0) {
4070 drawHighlight(pm1X, pm1Y, lineGC);
4072 if (fromX >= 0 && fromY >= 0) {
4073 drawHighlight(fromX, fromY, prelineGC);
4076 if (pm2X != toX || pm2Y != toY) {
4077 if (pm2X >= 0 && pm2Y >= 0) {
4078 drawHighlight(pm2X, pm2Y, lineGC);
4080 if (toX >= 0 && toY >= 0) {
4081 drawHighlight(toX, toY, prelineGC);
4091 ClearPremoveHighlights()
4093 SetPremoveHighlights(-1, -1, -1, -1);
4096 static int CutOutSquare(x, y, x0, y0, kind)
4097 int x, y, *x0, *y0, kind;
4099 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4100 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4102 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4103 if(textureW[kind] < W*squareSize)
4104 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4106 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4107 if(textureH[kind] < H*squareSize)
4108 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4110 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4114 static void BlankSquare(x, y, color, piece, dest, fac)
4115 int x, y, color, fac;
4118 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4120 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4121 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4122 squareSize, squareSize, x*fac, y*fac);
4124 if (useImages && useImageSqs) {
4128 pm = xpmLightSquare;
4133 case 2: /* neutral */
4138 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4139 squareSize, squareSize, x*fac, y*fac);
4149 case 2: /* neutral */
4154 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4159 I split out the routines to draw a piece so that I could
4160 make a generic flash routine.
4162 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4164 int square_color, x, y;
4167 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4168 switch (square_color) {
4170 case 2: /* neutral */
4172 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4173 ? *pieceToOutline(piece)
4174 : *pieceToSolid(piece),
4175 dest, bwPieceGC, 0, 0,
4176 squareSize, squareSize, x, y);
4179 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4180 ? *pieceToSolid(piece)
4181 : *pieceToOutline(piece),
4182 dest, wbPieceGC, 0, 0,
4183 squareSize, squareSize, x, y);
4188 static void monoDrawPiece(piece, square_color, x, y, dest)
4190 int square_color, x, y;
4193 switch (square_color) {
4195 case 2: /* neutral */
4197 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4198 ? *pieceToOutline(piece)
4199 : *pieceToSolid(piece),
4200 dest, bwPieceGC, 0, 0,
4201 squareSize, squareSize, x, y, 1);
4204 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4205 ? *pieceToSolid(piece)
4206 : *pieceToOutline(piece),
4207 dest, wbPieceGC, 0, 0,
4208 squareSize, squareSize, x, y, 1);
4213 static void colorDrawPiece(piece, square_color, x, y, dest)
4215 int square_color, x, y;
4218 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4219 switch (square_color) {
4221 XCopyPlane(xDisplay, *pieceToSolid(piece),
4222 dest, (int) piece < (int) BlackPawn
4223 ? wlPieceGC : blPieceGC, 0, 0,
4224 squareSize, squareSize, x, y, 1);
4227 XCopyPlane(xDisplay, *pieceToSolid(piece),
4228 dest, (int) piece < (int) BlackPawn
4229 ? wdPieceGC : bdPieceGC, 0, 0,
4230 squareSize, squareSize, x, y, 1);
4232 case 2: /* neutral */
4234 XCopyPlane(xDisplay, *pieceToSolid(piece),
4235 dest, (int) piece < (int) BlackPawn
4236 ? wjPieceGC : bjPieceGC, 0, 0,
4237 squareSize, squareSize, x, y, 1);
4242 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4244 int square_color, x, y;
4247 int kind, p = piece;
4249 switch (square_color) {
4251 case 2: /* neutral */
4253 if ((int)piece < (int) BlackPawn) {
4261 if ((int)piece < (int) BlackPawn) {
4269 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4270 if(useTexture & square_color+1) {
4271 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4272 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4273 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4274 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);