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, 2011 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>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
145 #include <X11/Intrinsic.h>
146 #include <X11/StringDefs.h>
147 #include <X11/Shell.h>
148 #include <X11/cursorfont.h>
149 #include <X11/Xatom.h>
150 #include <X11/Xmu/Atoms.h>
152 #include <X11/Xaw3d/Dialog.h>
153 #include <X11/Xaw3d/Form.h>
154 #include <X11/Xaw3d/List.h>
155 #include <X11/Xaw3d/Label.h>
156 #include <X11/Xaw3d/SimpleMenu.h>
157 #include <X11/Xaw3d/SmeBSB.h>
158 #include <X11/Xaw3d/SmeLine.h>
159 #include <X11/Xaw3d/Box.h>
160 #include <X11/Xaw3d/MenuButton.h>
161 #include <X11/Xaw3d/Text.h>
162 #include <X11/Xaw3d/AsciiText.h>
164 #include <X11/Xaw/Dialog.h>
165 #include <X11/Xaw/Form.h>
166 #include <X11/Xaw/List.h>
167 #include <X11/Xaw/Label.h>
168 #include <X11/Xaw/SimpleMenu.h>
169 #include <X11/Xaw/SmeBSB.h>
170 #include <X11/Xaw/SmeLine.h>
171 #include <X11/Xaw/Box.h>
172 #include <X11/Xaw/MenuButton.h>
173 #include <X11/Xaw/Text.h>
174 #include <X11/Xaw/AsciiText.h>
177 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
182 #include "pixmaps/pixmaps.h"
183 #define IMAGE_EXT "xpm"
185 #define IMAGE_EXT "xim"
186 #include "bitmaps/bitmaps.h"
189 #include "bitmaps/icon_white.bm"
190 #include "bitmaps/icon_black.bm"
191 #include "bitmaps/checkmark.bm"
193 #include "frontend.h"
195 #include "backendz.h"
199 #include "xgamelist.h"
200 #include "xhistory.h"
201 #include "xedittags.h"
204 // must be moved to xengineoutput.h
206 void EngineOutputProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
208 void EvalGraphProc P((Widget w, XEvent *event,
209 String *prms, Cardinal *nprms));
216 #define usleep(t) _sleep2(((t)+500)/1000)
220 # define _(s) gettext (s)
221 # define N_(s) gettext_noop (s)
239 int main P((int argc, char **argv));
240 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
241 char *init_path, char *mode, int (*show_entry)(), char **name_return));
242 RETSIGTYPE CmailSigHandler P((int sig));
243 RETSIGTYPE IntSigHandler P((int sig));
244 RETSIGTYPE TermSizeSigHandler P((int sig));
245 void CreateGCs P((int redo));
246 void CreateXIMPieces P((void));
247 void CreateXPMPieces P((void));
248 void CreateXPMBoard P((char *s, int n));
249 void CreatePieces P((void));
250 void CreatePieceMenus P((void));
251 Widget CreateMenuBar P((Menu *mb));
252 Widget CreateButtonBar P ((MenuItem *mi));
253 char *FindFont P((char *pattern, int targetPxlSize));
254 void PieceMenuPopup P((Widget w, XEvent *event,
255 String *params, Cardinal *num_params));
256 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
257 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
258 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
259 u_int wreq, u_int hreq));
260 void CreateGrid P((void));
261 int EventToSquare P((int x, int limit));
262 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
263 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
264 void HandleUserMove P((Widget w, XEvent *event,
265 String *prms, Cardinal *nprms));
266 void AnimateUserMove P((Widget w, XEvent * event,
267 String * params, Cardinal * nParams));
268 void HandlePV P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void SelectPV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void StopPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void WhiteClock P((Widget w, XEvent *event,
275 String *prms, Cardinal *nprms));
276 void BlackClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void DrawPositionProc P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
282 void CommentClick P((Widget w, XEvent * event,
283 String * params, Cardinal * nParams));
284 void CommentPopUp P((char *title, char *label));
285 void CommentPopDown P((void));
286 void CommentCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void ICSInputBoxPopUp P((void));
289 void ICSInputBoxPopDown P((void));
290 void FileNamePopUp P((char *label, char *def,
291 FileProc proc, char *openMode));
292 void FileNamePopDown P((void));
293 void FileNameCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void FileNameAction P((Widget w, XEvent *event,
296 String *prms, Cardinal *nprms));
297 void AskQuestionReplyAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionProc P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionPopDown P((void));
302 void PromotionPopDown P((void));
303 void PromotionCallback P((Widget w, XtPointer client_data,
304 XtPointer call_data));
305 void EditCommentPopDown P((void));
306 void EditCommentCallback P((Widget w, XtPointer client_data,
307 XtPointer call_data));
308 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
309 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
310 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
313 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
315 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
317 void LoadPositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
323 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
325 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
327 void PastePositionProc P((Widget w, XEvent *event, String *prms,
329 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
330 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
331 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void SavePositionProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
337 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
341 void MachineWhiteProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void AnalyzeModeProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeFileProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
349 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void IcsClientProc P((Widget w, XEvent *event, String *prms,
353 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditPositionProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EditCommentProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void IcsInputBoxProc P((Widget w, XEvent *event,
360 String *prms, Cardinal *nprms));
361 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void StopObservingProc P((Widget w, XEvent *event, String *prms,
377 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
379 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
388 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
393 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
395 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
397 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
402 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
405 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
407 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
409 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
414 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
416 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
418 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
420 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
423 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
425 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
427 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
429 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
430 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
431 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
433 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void DisplayMove P((int moveNumber));
441 void DisplayTitle P((char *title));
442 void ICSInitScript P((void));
443 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
444 void ErrorPopUp P((char *title, char *text, int modal));
445 void ErrorPopDown P((void));
446 static char *ExpandPathName P((char *path));
447 static void CreateAnimVars P((void));
448 static void DragPieceMove P((int x, int y));
449 static void DrawDragPiece P((void));
450 char *ModeToWidgetName P((GameMode mode));
451 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
453 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
454 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
455 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
456 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
457 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
458 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
459 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopDown P(());
467 void ShufflePopDown P(());
468 void TimeControlPopDown P(());
469 void GenericPopDown P(());
470 void update_ics_width P(());
471 int get_term_width P(());
472 int CopyMemoProc P(());
473 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
474 Boolean IsDrawArrowEnabled P(());
477 * XBoard depends on Xt R4 or higher
479 int xtVersion = XtSpecificationRelease;
484 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
485 jailSquareColor, highlightSquareColor, premoveHighlightColor;
486 Pixel lowTimeWarningColor;
487 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
488 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
489 wjPieceGC, bjPieceGC, prelineGC, countGC;
490 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
491 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
492 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
493 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
494 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
495 ICSInputShell, fileNameShell, askQuestionShell;
496 Widget historyShell, evalGraphShell, gameListShell;
497 int hOffset; // [HGM] dual
498 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
499 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
500 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
501 Font clockFontID, coordFontID, countFontID;
502 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
503 XtAppContext appContext;
505 char *oldICSInteractionTitle;
509 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
511 Position commentX = -1, commentY = -1;
512 Dimension commentW, commentH;
513 typedef unsigned int BoardSize;
515 Boolean chessProgram;
517 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
518 int squareSize, smallLayout = 0, tinyLayout = 0,
519 marginW, marginH, // [HGM] for run-time resizing
520 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
521 ICSInputBoxUp = False, askQuestionUp = False,
522 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
523 editUp = False, errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
524 Pixel timerForegroundPixel, timerBackgroundPixel;
525 Pixel buttonForegroundPixel, buttonBackgroundPixel;
526 char *chessDir, *programName, *programVersion,
527 *gameCopyFilename, *gamePasteFilename;
528 Boolean alwaysOnTop = False;
529 Boolean saveSettingsOnExit;
530 char *settingsFileName;
531 char *icsTextMenuString;
533 char *firstChessProgramNames;
534 char *secondChessProgramNames;
536 WindowPlacement wpMain;
537 WindowPlacement wpConsole;
538 WindowPlacement wpComment;
539 WindowPlacement wpMoveHistory;
540 WindowPlacement wpEvalGraph;
541 WindowPlacement wpEngineOutput;
542 WindowPlacement wpGameList;
543 WindowPlacement wpTags;
547 Pixmap pieceBitmap[2][(int)BlackPawn];
548 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
549 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
550 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
551 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
552 Pixmap xpmBoardBitmap[2];
553 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
554 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
555 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
556 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
557 XImage *ximLightSquare, *ximDarkSquare;
560 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
561 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
563 #define White(piece) ((int)(piece) < (int)BlackPawn)
565 /* Variables for doing smooth animation. This whole thing
566 would be much easier if the board was double-buffered,
567 but that would require a fairly major rewrite. */
572 GC blitGC, pieceGC, outlineGC;
573 XPoint startSquare, prevFrame, mouseDelta;
577 int startBoardX, startBoardY;
580 /* There can be two pieces being animated at once: a player
581 can begin dragging a piece before the remote opponent has moved. */
583 static AnimState game, player;
585 /* Bitmaps for use as masks when drawing XPM pieces.
586 Need one for each black and white piece. */
587 static Pixmap xpmMask[BlackKing + 1];
589 /* This magic number is the number of intermediate frames used
590 in each half of the animation. For short moves it's reduced
591 by 1. The total number of frames will be factor * 2 + 1. */
594 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
596 MenuItem fileMenu[] = {
597 {N_("New Game Ctrl+N"), "New Game", ResetProc},
598 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
599 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
600 {"----", NULL, NothingProc},
601 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
602 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
603 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
604 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
605 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
606 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
607 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
608 {"----", NULL, NothingProc},
609 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
610 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
611 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
612 {"----", NULL, NothingProc},
613 {N_("Mail Move"), "Mail Move", MailMoveProc},
614 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
615 {"----", NULL, NothingProc},
616 {N_("Quit Ctr+Q"), "Exit", QuitProc},
620 MenuItem editMenu[] = {
621 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
622 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
623 {"----", NULL, NothingProc},
624 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
625 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
626 {"----", NULL, NothingProc},
627 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
628 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
629 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
630 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
631 {"----", NULL, NothingProc},
632 {N_("Revert Home"), "Revert", RevertProc},
633 {N_("Annotate"), "Annotate", AnnotateProc},
634 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
635 {"----", NULL, NothingProc},
636 {N_("Backward Alt+Left"), "Backward", BackwardProc},
637 {N_("Forward Alt+Right"), "Forward", ForwardProc},
638 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
639 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
643 MenuItem viewMenu[] = {
644 {N_("Flip View F2"), "Flip View", FlipViewProc},
645 {"----", NULL, NothingProc},
646 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
647 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
648 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
649 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
650 {N_("ICS text menu"), "ICStex", IcsTextProc},
651 {"----", NULL, NothingProc},
652 {N_("Tags"), "Show Tags", EditTagsProc},
653 {N_("Comments"), "Show Comments", EditCommentProc},
654 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
655 {"----", NULL, NothingProc},
656 {N_("Board..."), "Board Options", BoardOptionsProc},
657 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
661 MenuItem modeMenu[] = {
662 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
663 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
664 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
665 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
666 {N_("Analyze File Ctrl+F"), "Analyze File", AnalyzeFileProc },
667 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
668 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
669 {N_("Training"), "Training", TrainingProc},
670 {N_("ICS Client"), "ICS Client", IcsClientProc},
671 {"----", NULL, NothingProc},
672 {N_("Machine Match"), "Machine Match", MatchProc},
673 {N_("Pause Pause"), "Pause", PauseProc},
677 MenuItem actionMenu[] = {
678 {N_("Accept F3"), "Accept", AcceptProc},
679 {N_("Decline F4"), "Decline", DeclineProc},
680 {N_("Rematch F12"), "Rematch", RematchProc},
681 {"----", NULL, NothingProc},
682 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
683 {N_("Draw F6"), "Draw", DrawProc},
684 {N_("Adjourn F7"), "Adjourn", AdjournProc},
685 {N_("Abort F8"),"Abort", AbortProc},
686 {N_("Resign F9"), "Resign", ResignProc},
687 {"----", NULL, NothingProc},
688 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
689 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
690 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
691 {"----", NULL, NothingProc},
692 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
693 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
694 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
698 MenuItem engineMenu[] = {
699 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
700 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
701 {"----", NULL, NothingProc},
702 {N_("Hint"), "Hint", HintProc},
703 {N_("Book"), "Book", BookProc},
704 {"----", NULL, NothingProc},
705 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
706 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
710 MenuItem optionsMenu[] = {
711 #define OPTIONSDIALOG
713 {N_("General ..."), "General", OptionsProc},
715 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
716 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
717 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
718 {N_("ICS ..."), "ICS", IcsOptionsProc},
719 {N_("Match ..."), "Match", MatchOptionsProc},
720 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
721 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
722 // {N_(" ..."), "", OptionsProc},
723 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
724 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
725 {"----", NULL, NothingProc},
726 #ifndef OPTIONSDIALOG
727 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
728 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
729 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
730 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
731 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
732 {N_("Blindfold"), "Blindfold", BlindfoldProc},
733 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
735 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
737 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
738 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
739 {N_("Move Sound"), "Move Sound", MoveSoundProc},
740 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
741 {N_("One-Click Moving"), "OneClick", OneClickProc},
742 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
743 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
744 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
745 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
746 // {N_("Premove"), "Premove", PremoveProc},
747 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
748 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
749 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
750 {"----", NULL, NothingProc},
752 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
753 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
757 MenuItem helpMenu[] = {
758 {N_("Info XBoard"), "Info XBoard", InfoProc},
759 {N_("Man XBoard F1"), "Man XBoard", ManProc},
760 {"----", NULL, NothingProc},
761 {N_("About XBoard"), "About XBoard", AboutProc},
766 {N_("File"), "File", fileMenu},
767 {N_("Edit"), "Edit", editMenu},
768 {N_("View"), "View", viewMenu},
769 {N_("Mode"), "Mode", modeMenu},
770 {N_("Action"), "Action", actionMenu},
771 {N_("Engine"), "Engine", engineMenu},
772 {N_("Options"), "Options", optionsMenu},
773 {N_("Help"), "Help", helpMenu},
777 #define PAUSE_BUTTON "P"
778 MenuItem buttonBar[] = {
779 {"<<", "<<", ToStartProc},
780 {"<", "<", BackwardProc},
781 {PAUSE_BUTTON, PAUSE_BUTTON, PauseProc},
782 {">", ">", ForwardProc},
783 {">>", ">>", ToEndProc},
787 #define PIECE_MENU_SIZE 18
788 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
789 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
790 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
791 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
792 N_("Empty square"), N_("Clear board") },
793 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
794 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
795 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
796 N_("Empty square"), N_("Clear board") }
798 /* must be in same order as PieceMenuStrings! */
799 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
800 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
801 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
802 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
803 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
804 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
805 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
806 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
807 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
810 #define DROP_MENU_SIZE 6
811 String dropMenuStrings[DROP_MENU_SIZE] = {
812 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
814 /* must be in same order as PieceMenuStrings! */
815 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
816 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
817 WhiteRook, WhiteQueen
825 DropMenuEnables dmEnables[] = {
843 { XtNborderWidth, 0 },
844 { XtNdefaultDistance, 0 },
848 { XtNborderWidth, 0 },
849 { XtNresizable, (XtArgVal) True },
853 { XtNborderWidth, 0 },
859 { XtNjustify, (XtArgVal) XtJustifyRight },
860 { XtNlabel, (XtArgVal) "..." },
861 { XtNresizable, (XtArgVal) True },
862 { XtNresize, (XtArgVal) False }
865 Arg messageArgs[] = {
866 { XtNjustify, (XtArgVal) XtJustifyLeft },
867 { XtNlabel, (XtArgVal) "..." },
868 { XtNresizable, (XtArgVal) True },
869 { XtNresize, (XtArgVal) False }
873 { XtNborderWidth, 0 },
874 { XtNjustify, (XtArgVal) XtJustifyLeft }
877 XtResource clientResources[] = {
878 { "flashCount", "flashCount", XtRInt, sizeof(int),
879 XtOffset(AppDataPtr, flashCount), XtRImmediate,
880 (XtPointer) FLASH_COUNT },
883 XrmOptionDescRec shellOptions[] = {
884 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
885 { "-flash", "flashCount", XrmoptionNoArg, "3" },
886 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
889 XtActionsRec boardActions[] = {
890 { "DrawPosition", DrawPositionProc },
891 { "HandleUserMove", HandleUserMove },
892 { "AnimateUserMove", AnimateUserMove },
893 { "HandlePV", HandlePV },
894 { "SelectPV", SelectPV },
895 { "StopPV", StopPV },
896 { "FileNameAction", FileNameAction },
897 { "AskQuestionProc", AskQuestionProc },
898 { "AskQuestionReplyAction", AskQuestionReplyAction },
899 { "PieceMenuPopup", PieceMenuPopup },
900 { "WhiteClock", WhiteClock },
901 { "BlackClock", BlackClock },
902 { "Iconify", Iconify },
903 { "ResetProc", ResetProc },
904 { "NewVariantProc", NewVariantProc },
905 { "LoadGameProc", LoadGameProc },
906 { "LoadNextGameProc", LoadNextGameProc },
907 { "LoadPrevGameProc", LoadPrevGameProc },
908 { "LoadSelectedProc", LoadSelectedProc },
909 { "SetFilterProc", SetFilterProc },
910 { "ReloadGameProc", ReloadGameProc },
911 { "LoadPositionProc", LoadPositionProc },
912 { "LoadNextPositionProc", LoadNextPositionProc },
913 { "LoadPrevPositionProc", LoadPrevPositionProc },
914 { "ReloadPositionProc", ReloadPositionProc },
915 { "CopyPositionProc", CopyPositionProc },
916 { "PastePositionProc", PastePositionProc },
917 { "CopyGameProc", CopyGameProc },
918 { "PasteGameProc", PasteGameProc },
919 { "SaveGameProc", SaveGameProc },
920 { "SavePositionProc", SavePositionProc },
921 { "MailMoveProc", MailMoveProc },
922 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
923 { "QuitProc", QuitProc },
924 { "MachineWhiteProc", MachineWhiteProc },
925 { "MachineBlackProc", MachineBlackProc },
926 { "AnalysisModeProc", AnalyzeModeProc },
927 { "AnalyzeFileProc", AnalyzeFileProc },
928 { "TwoMachinesProc", TwoMachinesProc },
929 { "IcsClientProc", IcsClientProc },
930 { "EditGameProc", EditGameProc },
931 { "EditPositionProc", EditPositionProc },
932 { "TrainingProc", EditPositionProc },
933 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
934 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
935 { "ShowGameListProc", ShowGameListProc },
936 { "ShowMoveListProc", HistoryShowProc},
937 { "EditTagsProc", EditCommentProc },
938 { "EditCommentProc", EditCommentProc },
939 { "IcsInputBoxProc", IcsInputBoxProc },
940 { "PauseProc", PauseProc },
941 { "AcceptProc", AcceptProc },
942 { "DeclineProc", DeclineProc },
943 { "RematchProc", RematchProc },
944 { "CallFlagProc", CallFlagProc },
945 { "DrawProc", DrawProc },
946 { "AdjournProc", AdjournProc },
947 { "AbortProc", AbortProc },
948 { "ResignProc", ResignProc },
949 { "AdjuWhiteProc", AdjuWhiteProc },
950 { "AdjuBlackProc", AdjuBlackProc },
951 { "AdjuDrawProc", AdjuDrawProc },
952 { "EnterKeyProc", EnterKeyProc },
953 { "UpKeyProc", UpKeyProc },
954 { "DownKeyProc", DownKeyProc },
955 { "StopObservingProc", StopObservingProc },
956 { "StopExaminingProc", StopExaminingProc },
957 { "UploadProc", UploadProc },
958 { "BackwardProc", BackwardProc },
959 { "ForwardProc", ForwardProc },
960 { "ToStartProc", ToStartProc },
961 { "ToEndProc", ToEndProc },
962 { "RevertProc", RevertProc },
963 { "AnnotateProc", AnnotateProc },
964 { "TruncateGameProc", TruncateGameProc },
965 { "MoveNowProc", MoveNowProc },
966 { "RetractMoveProc", RetractMoveProc },
967 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
968 { "UciMenuProc", (XtActionProc) UciMenuProc },
969 { "TimeControlProc", (XtActionProc) TimeControlProc },
970 { "FlipViewProc", FlipViewProc },
971 { "PonderNextMoveProc", PonderNextMoveProc },
972 #ifndef OPTIONSDIALOG
973 { "AlwaysQueenProc", AlwaysQueenProc },
974 { "AnimateDraggingProc", AnimateDraggingProc },
975 { "AnimateMovingProc", AnimateMovingProc },
976 { "AutoflagProc", AutoflagProc },
977 { "AutoflipProc", AutoflipProc },
978 { "BlindfoldProc", BlindfoldProc },
979 { "FlashMovesProc", FlashMovesProc },
981 { "HighlightDraggingProc", HighlightDraggingProc },
983 { "HighlightLastMoveProc", HighlightLastMoveProc },
984 // { "IcsAlarmProc", IcsAlarmProc },
985 { "MoveSoundProc", MoveSoundProc },
986 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
987 { "PopupExitMessageProc", PopupExitMessageProc },
988 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
989 // { "PremoveProc", PremoveProc },
990 { "ShowCoordsProc", ShowCoordsProc },
991 { "ShowThinkingProc", ShowThinkingProc },
992 { "HideThinkingProc", HideThinkingProc },
993 { "TestLegalityProc", TestLegalityProc },
995 { "SaveSettingsProc", SaveSettingsProc },
996 { "SaveOnExitProc", SaveOnExitProc },
997 { "InfoProc", InfoProc },
998 { "ManProc", ManProc },
999 { "HintProc", HintProc },
1000 { "BookProc", BookProc },
1001 { "AboutGameProc", AboutGameProc },
1002 { "AboutProc", AboutProc },
1003 { "DebugProc", DebugProc },
1004 { "NothingProc", NothingProc },
1005 { "CommentClick", (XtActionProc) CommentClick },
1006 { "CommentPopDown", (XtActionProc) CommentPopDown },
1007 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
1008 { "TagsPopDown", (XtActionProc) TagsPopDown },
1009 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1010 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1011 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1012 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1013 { "GameListPopDown", (XtActionProc) GameListPopDown },
1014 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1015 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1016 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1017 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1018 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1019 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1020 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1021 { "GenericPopDown", (XtActionProc) GenericPopDown },
1022 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1025 char globalTranslations[] =
1026 ":<Key>F9: ResignProc() \n \
1027 :Ctrl<Key>n: ResetProc() \n \
1028 :Meta<Key>V: NewVariantProc() \n \
1029 :Ctrl<Key>o: LoadGameProc() \n \
1030 :Meta<Key>Next: LoadNextGameProc() \n \
1031 :Meta<Key>Prior: LoadPrevGameProc() \n \
1032 :Ctrl<Key>s: SaveGameProc() \n \
1033 :Ctrl<Key>c: CopyGameProc() \n \
1034 :Ctrl<Key>v: PasteGameProc() \n \
1035 :Ctrl<Key>O: LoadPositionProc() \n \
1036 :Shift<Key>Next: LoadNextPositionProc() \n \
1037 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1038 :Ctrl<Key>S: SavePositionProc() \n \
1039 :Ctrl<Key>C: CopyPositionProc() \n \
1040 :Ctrl<Key>V: PastePositionProc() \n \
1041 :Ctrl<Key>q: QuitProc() \n \
1042 :Ctrl<Key>w: MachineWhiteProc() \n \
1043 :Ctrl<Key>b: MachineBlackProc() \n \
1044 :Ctrl<Key>t: TwoMachinesProc() \n \
1045 :Ctrl<Key>a: AnalysisModeProc() \n \
1046 :Ctrl<Key>f: AnalyzeFileProc() \n \
1047 :Ctrl<Key>e: EditGameProc() \n \
1048 :Ctrl<Key>E: EditPositionProc() \n \
1049 :Meta<Key>O: EngineOutputProc() \n \
1050 :Meta<Key>E: EvalGraphProc() \n \
1051 :Meta<Key>G: ShowGameListProc() \n \
1052 :Meta<Key>H: ShowMoveListProc() \n \
1053 :<Key>Pause: PauseProc() \n \
1054 :<Key>F3: AcceptProc() \n \
1055 :<Key>F4: DeclineProc() \n \
1056 :<Key>F12: RematchProc() \n \
1057 :<Key>F5: CallFlagProc() \n \
1058 :<Key>F6: DrawProc() \n \
1059 :<Key>F7: AdjournProc() \n \
1060 :<Key>F8: AbortProc() \n \
1061 :<Key>F10: StopObservingProc() \n \
1062 :<Key>F11: StopExaminingProc() \n \
1063 :Meta Ctrl<Key>F12: DebugProc() \n \
1064 :Meta<Key>End: ToEndProc() \n \
1065 :Meta<Key>Right: ForwardProc() \n \
1066 :Meta<Key>Home: ToStartProc() \n \
1067 :Meta<Key>Left: BackwardProc() \n \
1068 :<Key>Home: RevertProc() \n \
1069 :<Key>End: TruncateGameProc() \n \
1070 :Ctrl<Key>m: MoveNowProc() \n \
1071 :Ctrl<Key>x: RetractMoveProc() \n \
1072 :Meta<Key>J: EngineMenuProc() \n \
1073 :Meta<Key>U: UciMenuProc() \n \
1074 :Meta<Key>T: TimeControlProc() \n \
1075 :Ctrl<Key>P: PonderNextMoveProc() \n "
1076 #ifndef OPTIONSDIALOG
1078 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1079 :Ctrl<Key>F: AutoflagProc() \n \
1080 :Ctrl<Key>A: AnimateMovingProc() \n \
1081 :Ctrl<Key>L: TestLegalityProc() \n \
1082 :Ctrl<Key>H: HideThinkingProc() \n "
1085 :<Key>-: Iconify() \n \
1086 :<Key>F1: ManProc() \n \
1087 :<Key>F2: FlipViewProc() \n \
1088 <KeyDown>.: BackwardProc() \n \
1089 <KeyUp>.: ForwardProc() \n \
1090 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1091 \"Send to chess program:\",,1) \n \
1092 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1093 \"Send to second chess program:\",,2) \n";
1095 char boardTranslations[] =
1096 "<Btn1Down>: HandleUserMove(0) \n \
1097 Shift<Btn1Up>: HandleUserMove(1) \n \
1098 <Btn1Up>: HandleUserMove(0) \n \
1099 <Btn1Motion>: AnimateUserMove() \n \
1100 <Btn3Motion>: HandlePV() \n \
1101 <Btn3Up>: PieceMenuPopup(menuB) \n \
1102 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1103 PieceMenuPopup(menuB) \n \
1104 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1105 PieceMenuPopup(menuW) \n \
1106 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1107 PieceMenuPopup(menuW) \n \
1108 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1109 PieceMenuPopup(menuB) \n";
1111 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1112 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1114 char ICSInputTranslations[] =
1115 "<Key>Up: UpKeyProc() \n "
1116 "<Key>Down: DownKeyProc() \n "
1117 "<Key>Return: EnterKeyProc() \n";
1119 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1120 // as the widget is destroyed before the up-click can call extend-end
1121 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1123 String xboardResources[] = {
1124 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1125 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1126 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1131 /* Max possible square size */
1132 #define MAXSQSIZE 256
1134 static int xpm_avail[MAXSQSIZE];
1136 #ifdef HAVE_DIR_STRUCT
1138 /* Extract piece size from filename */
1140 xpm_getsize(name, len, ext)
1151 if ((p=strchr(name, '.')) == NULL ||
1152 StrCaseCmp(p+1, ext) != 0)
1158 while (*p && isdigit(*p))
1165 /* Setup xpm_avail */
1167 xpm_getavail(dirname, ext)
1175 for (i=0; i<MAXSQSIZE; ++i)
1178 if (appData.debugMode)
1179 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1181 dir = opendir(dirname);
1184 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1185 programName, dirname);
1189 while ((ent=readdir(dir)) != NULL) {
1190 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1191 if (i > 0 && i < MAXSQSIZE)
1201 xpm_print_avail(fp, ext)
1207 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1208 for (i=1; i<MAXSQSIZE; ++i) {
1214 /* Return XPM piecesize closest to size */
1216 xpm_closest_to(dirname, size, ext)
1222 int sm_diff = MAXSQSIZE;
1226 xpm_getavail(dirname, ext);
1228 if (appData.debugMode)
1229 xpm_print_avail(stderr, ext);
1231 for (i=1; i<MAXSQSIZE; ++i) {
1234 diff = (diff<0) ? -diff : diff;
1235 if (diff < sm_diff) {
1243 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1249 #else /* !HAVE_DIR_STRUCT */
1250 /* If we are on a system without a DIR struct, we can't
1251 read the directory, so we can't collect a list of
1252 filenames, etc., so we can't do any size-fitting. */
1254 xpm_closest_to(dirname, size, ext)
1259 fprintf(stderr, _("\
1260 Warning: No DIR structure found on this system --\n\
1261 Unable to autosize for XPM/XIM pieces.\n\
1262 Please report this error to frankm@hiwaay.net.\n\
1263 Include system type & operating system in message.\n"));
1266 #endif /* HAVE_DIR_STRUCT */
1268 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1269 "magenta", "cyan", "white" };
1273 TextColors textColors[(int)NColorClasses];
1275 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1277 parse_color(str, which)
1281 char *p, buf[100], *d;
1284 if (strlen(str) > 99) /* watch bounds on buf */
1289 for (i=0; i<which; ++i) {
1296 /* Could be looking at something like:
1298 .. in which case we want to stop on a comma also */
1299 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1303 return -1; /* Use default for empty field */
1306 if (which == 2 || isdigit(*p))
1309 while (*p && isalpha(*p))
1314 for (i=0; i<8; ++i) {
1315 if (!StrCaseCmp(buf, cnames[i]))
1316 return which? (i+40) : (i+30);
1318 if (!StrCaseCmp(buf, "default")) return -1;
1320 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1325 parse_cpair(cc, str)
1329 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1330 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1335 /* bg and attr are optional */
1336 textColors[(int)cc].bg = parse_color(str, 1);
1337 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1338 textColors[(int)cc].attr = 0;
1344 /* Arrange to catch delete-window events */
1345 Atom wm_delete_window;
1347 CatchDeleteWindow(Widget w, String procname)
1350 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1351 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1352 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1359 XtSetArg(args[0], XtNiconic, False);
1360 XtSetValues(shellWidget, args, 1);
1362 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1365 //---------------------------------------------------------------------------------------------------------
1366 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1369 #define CW_USEDEFAULT (1<<31)
1370 #define ICS_TEXT_MENU_SIZE 90
1371 #define DEBUG_FILE "xboard.debug"
1372 #define SetCurrentDirectory chdir
1373 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1377 // these two must some day move to frontend.h, when they are implemented
1378 Boolean GameListIsUp();
1380 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1383 // front-end part of option handling
1385 // [HGM] This platform-dependent table provides the location for storing the color info
1386 extern char *crWhite, * crBlack;
1390 &appData.whitePieceColor,
1391 &appData.blackPieceColor,
1392 &appData.lightSquareColor,
1393 &appData.darkSquareColor,
1394 &appData.highlightSquareColor,
1395 &appData.premoveHighlightColor,
1396 &appData.lowTimeWarningColor,
1407 // [HGM] font: keep a font for each square size, even non-stndard ones
1408 #define NUM_SIZES 18
1409 #define MAX_SIZE 130
1410 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1411 char *fontTable[NUM_FONTS][MAX_SIZE];
1414 ParseFont(char *name, int number)
1415 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1417 if(sscanf(name, "size%d:", &size)) {
1418 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1419 // defer processing it until we know if it matches our board size
1420 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1421 fontTable[number][size] = strdup(strchr(name, ':')+1);
1422 fontValid[number][size] = True;
1427 case 0: // CLOCK_FONT
1428 appData.clockFont = strdup(name);
1430 case 1: // MESSAGE_FONT
1431 appData.font = strdup(name);
1433 case 2: // COORD_FONT
1434 appData.coordFont = strdup(name);
1439 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1444 { // only 2 fonts currently
1445 appData.clockFont = CLOCK_FONT_NAME;
1446 appData.coordFont = COORD_FONT_NAME;
1447 appData.font = DEFAULT_FONT_NAME;
1452 { // no-op, until we identify the code for this already in XBoard and move it here
1456 ParseColor(int n, char *name)
1457 { // in XBoard, just copy the color-name string
1458 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1462 ParseTextAttribs(ColorClass cc, char *s)
1464 (&appData.colorShout)[cc] = strdup(s);
1468 ParseBoardSize(void *addr, char *name)
1470 appData.boardSize = strdup(name);
1475 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1479 SetCommPortDefaults()
1480 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1483 // [HGM] args: these three cases taken out to stay in front-end
1485 SaveFontArg(FILE *f, ArgDescriptor *ad)
1488 int i, n = (int)(intptr_t)ad->argLoc;
1490 case 0: // CLOCK_FONT
1491 name = appData.clockFont;
1493 case 1: // MESSAGE_FONT
1494 name = appData.font;
1496 case 2: // COORD_FONT
1497 name = appData.coordFont;
1502 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1503 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1504 fontTable[n][squareSize] = strdup(name);
1505 fontValid[n][squareSize] = True;
1508 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1509 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1514 { // nothing to do, as the sounds are at all times represented by their text-string names already
1518 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1519 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1520 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1524 SaveColor(FILE *f, ArgDescriptor *ad)
1525 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1526 if(colorVariable[(int)(intptr_t)ad->argLoc])
1527 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1531 SaveBoardSize(FILE *f, char *name, void *addr)
1532 { // wrapper to shield back-end from BoardSize & sizeInfo
1533 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1537 ParseCommPortSettings(char *s)
1538 { // no such option in XBoard (yet)
1541 extern Widget engineOutputShell;
1542 extern Widget tagsShell, editTagsShell;
1544 GetActualPlacement(Widget wg, WindowPlacement *wp)
1554 XtSetArg(args[i], XtNx, &x); i++;
1555 XtSetArg(args[i], XtNy, &y); i++;
1556 XtSetArg(args[i], XtNwidth, &w); i++;
1557 XtSetArg(args[i], XtNheight, &h); i++;
1558 XtGetValues(wg, args, i);
1567 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1568 // In XBoard this will have to wait until awareness of window parameters is implemented
1569 GetActualPlacement(shellWidget, &wpMain);
1570 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1571 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1572 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1573 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1574 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1575 else GetActualPlacement(editShell, &wpComment);
1576 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1577 else GetActualPlacement(editTagsShell, &wpTags);
1581 PrintCommPortSettings(FILE *f, char *name)
1582 { // This option does not exist in XBoard
1586 MySearchPath(char *installDir, char *name, char *fullname)
1587 { // just append installDir and name. Perhaps ExpandPath should be used here?
1588 name = ExpandPathName(name);
1589 if(name && name[0] == '/')
1590 safeStrCpy(fullname, name, MSG_SIZ );
1592 sprintf(fullname, "%s%c%s", installDir, '/', name);
1598 MyGetFullPathName(char *name, char *fullname)
1599 { // should use ExpandPath?
1600 name = ExpandPathName(name);
1601 safeStrCpy(fullname, name, MSG_SIZ );
1606 EnsureOnScreen(int *x, int *y, int minX, int minY)
1613 { // [HGM] args: allows testing if main window is realized from back-end
1614 return xBoardWindow != 0;
1618 PopUpStartupDialog()
1619 { // start menu not implemented in XBoard
1623 ConvertToLine(int argc, char **argv)
1625 static char line[128*1024], buf[1024];
1629 for(i=1; i<argc; i++)
1631 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1632 && argv[i][0] != '{' )
1633 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1635 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1636 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1639 line[strlen(line)-1] = NULLCHAR;
1643 //--------------------------------------------------------------------------------------------
1645 extern Boolean twoBoards, partnerUp;
1648 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1650 #define BoardSize int
1651 void InitDrawingSizes(BoardSize boardSize, int flags)
1652 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1653 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1655 XtGeometryResult gres;
1658 if(!formWidget) return;
1661 * Enable shell resizing.
1663 shellArgs[0].value = (XtArgVal) &w;
1664 shellArgs[1].value = (XtArgVal) &h;
1665 XtGetValues(shellWidget, shellArgs, 2);
1667 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1668 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1669 XtSetValues(shellWidget, &shellArgs[2], 4);
1671 XtSetArg(args[0], XtNdefaultDistance, &sep);
1672 XtGetValues(formWidget, args, 1);
1674 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1675 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1676 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1678 hOffset = boardWidth + 10;
1679 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1680 secondSegments[i] = gridSegments[i];
1681 secondSegments[i].x1 += hOffset;
1682 secondSegments[i].x2 += hOffset;
1685 XtSetArg(args[0], XtNwidth, boardWidth);
1686 XtSetArg(args[1], XtNheight, boardHeight);
1687 XtSetValues(boardWidget, args, 2);
1689 timerWidth = (boardWidth - sep) / 2;
1690 XtSetArg(args[0], XtNwidth, timerWidth);
1691 XtSetValues(whiteTimerWidget, args, 1);
1692 XtSetValues(blackTimerWidget, args, 1);
1694 XawFormDoLayout(formWidget, False);
1696 if (appData.titleInWindow) {
1698 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1699 XtSetArg(args[i], XtNheight, &h); i++;
1700 XtGetValues(titleWidget, args, i);
1702 w = boardWidth - 2*bor;
1704 XtSetArg(args[0], XtNwidth, &w);
1705 XtGetValues(menuBarWidget, args, 1);
1706 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1709 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1710 if (gres != XtGeometryYes && appData.debugMode) {
1712 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1713 programName, gres, w, h, wr, hr);
1717 XawFormDoLayout(formWidget, True);
1720 * Inhibit shell resizing.
1722 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1723 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1724 shellArgs[4].value = shellArgs[2].value = w;
1725 shellArgs[5].value = shellArgs[3].value = h;
1726 XtSetValues(shellWidget, &shellArgs[0], 6);
1728 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1731 for(i=0; i<4; i++) {
1733 for(p=0; p<=(int)WhiteKing; p++)
1734 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1735 if(gameInfo.variant == VariantShogi) {
1736 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1737 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1738 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1739 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1740 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1743 if(gameInfo.variant == VariantGothic) {
1744 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1747 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1748 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1749 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1752 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1753 for(p=0; p<=(int)WhiteKing; p++)
1754 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1755 if(gameInfo.variant == VariantShogi) {
1756 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1757 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1758 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1759 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1760 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1763 if(gameInfo.variant == VariantGothic) {
1764 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1767 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1768 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1769 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1774 for(i=0; i<2; i++) {
1776 for(p=0; p<=(int)WhiteKing; p++)
1777 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1778 if(gameInfo.variant == VariantShogi) {
1779 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1780 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1781 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1782 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1783 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1786 if(gameInfo.variant == VariantGothic) {
1787 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1790 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1791 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1792 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1802 void ParseIcsTextColors()
1803 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1804 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1805 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1806 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1807 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1808 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1809 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1810 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1811 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1812 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1813 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1815 if (appData.colorize) {
1817 _("%s: can't parse color names; disabling colorization\n"),
1820 appData.colorize = FALSE;
1825 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1826 XrmValue vFrom, vTo;
1827 int forceMono = False;
1829 if (!appData.monoMode) {
1830 vFrom.addr = (caddr_t) appData.lightSquareColor;
1831 vFrom.size = strlen(appData.lightSquareColor);
1832 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1833 if (vTo.addr == NULL) {
1834 appData.monoMode = True;
1837 lightSquareColor = *(Pixel *) vTo.addr;
1840 if (!appData.monoMode) {
1841 vFrom.addr = (caddr_t) appData.darkSquareColor;
1842 vFrom.size = strlen(appData.darkSquareColor);
1843 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1844 if (vTo.addr == NULL) {
1845 appData.monoMode = True;
1848 darkSquareColor = *(Pixel *) vTo.addr;
1851 if (!appData.monoMode) {
1852 vFrom.addr = (caddr_t) appData.whitePieceColor;
1853 vFrom.size = strlen(appData.whitePieceColor);
1854 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1855 if (vTo.addr == NULL) {
1856 appData.monoMode = True;
1859 whitePieceColor = *(Pixel *) vTo.addr;
1862 if (!appData.monoMode) {
1863 vFrom.addr = (caddr_t) appData.blackPieceColor;
1864 vFrom.size = strlen(appData.blackPieceColor);
1865 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1866 if (vTo.addr == NULL) {
1867 appData.monoMode = True;
1870 blackPieceColor = *(Pixel *) vTo.addr;
1874 if (!appData.monoMode) {
1875 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1876 vFrom.size = strlen(appData.highlightSquareColor);
1877 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1878 if (vTo.addr == NULL) {
1879 appData.monoMode = True;
1882 highlightSquareColor = *(Pixel *) vTo.addr;
1886 if (!appData.monoMode) {
1887 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1888 vFrom.size = strlen(appData.premoveHighlightColor);
1889 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1890 if (vTo.addr == NULL) {
1891 appData.monoMode = True;
1894 premoveHighlightColor = *(Pixel *) vTo.addr;
1905 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1906 XSetWindowAttributes window_attributes;
1908 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1909 XrmValue vFrom, vTo;
1910 XtGeometryResult gres;
1913 int forceMono = False;
1915 srandom(time(0)); // [HGM] book: make random truly random
1917 setbuf(stdout, NULL);
1918 setbuf(stderr, NULL);
1921 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1922 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1926 programName = strrchr(argv[0], '/');
1927 if (programName == NULL)
1928 programName = argv[0];
1933 XtSetLanguageProc(NULL, NULL, NULL);
1934 bindtextdomain(PACKAGE, LOCALEDIR);
1935 textdomain(PACKAGE);
1939 XtAppInitialize(&appContext, "XBoard", shellOptions,
1940 XtNumber(shellOptions),
1941 &argc, argv, xboardResources, NULL, 0);
1942 appData.boardSize = "";
1943 InitAppData(ConvertToLine(argc, argv));
1945 if (p == NULL) p = "/tmp";
1946 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1947 gameCopyFilename = (char*) malloc(i);
1948 gamePasteFilename = (char*) malloc(i);
1949 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1950 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1952 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1953 clientResources, XtNumber(clientResources),
1956 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1957 static char buf[MSG_SIZ];
1958 EscapeExpand(buf, appData.initString);
1959 appData.initString = strdup(buf);
1960 EscapeExpand(buf, appData.secondInitString);
1961 appData.secondInitString = strdup(buf);
1962 EscapeExpand(buf, appData.firstComputerString);
1963 appData.firstComputerString = strdup(buf);
1964 EscapeExpand(buf, appData.secondComputerString);
1965 appData.secondComputerString = strdup(buf);
1968 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1971 if (chdir(chessDir) != 0) {
1972 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1978 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1979 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1980 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1981 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1984 setbuf(debugFP, NULL);
1987 /* [HGM,HR] make sure board size is acceptable */
1988 if(appData.NrFiles > BOARD_FILES ||
1989 appData.NrRanks > BOARD_RANKS )
1990 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1993 /* This feature does not work; animation needs a rewrite */
1994 appData.highlightDragging = FALSE;
1998 xDisplay = XtDisplay(shellWidget);
1999 xScreen = DefaultScreen(xDisplay);
2000 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2002 gameInfo.variant = StringToVariant(appData.variant);
2003 InitPosition(FALSE);
2006 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2008 if (isdigit(appData.boardSize[0])) {
2009 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2010 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2011 &fontPxlSize, &smallLayout, &tinyLayout);
2013 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2014 programName, appData.boardSize);
2018 /* Find some defaults; use the nearest known size */
2019 SizeDefaults *szd, *nearest;
2020 int distance = 99999;
2021 nearest = szd = sizeDefaults;
2022 while (szd->name != NULL) {
2023 if (abs(szd->squareSize - squareSize) < distance) {
2025 distance = abs(szd->squareSize - squareSize);
2026 if (distance == 0) break;
2030 if (i < 2) lineGap = nearest->lineGap;
2031 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2032 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2033 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2034 if (i < 6) smallLayout = nearest->smallLayout;
2035 if (i < 7) tinyLayout = nearest->tinyLayout;
2038 SizeDefaults *szd = sizeDefaults;
2039 if (*appData.boardSize == NULLCHAR) {
2040 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2041 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2044 if (szd->name == NULL) szd--;
2045 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2047 while (szd->name != NULL &&
2048 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2049 if (szd->name == NULL) {
2050 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2051 programName, appData.boardSize);
2055 squareSize = szd->squareSize;
2056 lineGap = szd->lineGap;
2057 clockFontPxlSize = szd->clockFontPxlSize;
2058 coordFontPxlSize = szd->coordFontPxlSize;
2059 fontPxlSize = szd->fontPxlSize;
2060 smallLayout = szd->smallLayout;
2061 tinyLayout = szd->tinyLayout;
2062 // [HGM] font: use defaults from settings file if available and not overruled
2064 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2065 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2066 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2067 appData.font = fontTable[MESSAGE_FONT][squareSize];
2068 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2069 appData.coordFont = fontTable[COORD_FONT][squareSize];
2071 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2072 if (strlen(appData.pixmapDirectory) > 0) {
2073 p = ExpandPathName(appData.pixmapDirectory);
2075 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2076 appData.pixmapDirectory);
2079 if (appData.debugMode) {
2080 fprintf(stderr, _("\
2081 XBoard square size (hint): %d\n\
2082 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2084 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2085 if (appData.debugMode) {
2086 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2089 defaultLineGap = lineGap;
2090 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2092 /* [HR] height treated separately (hacked) */
2093 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2094 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2095 if (appData.showJail == 1) {
2096 /* Jail on top and bottom */
2097 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2098 XtSetArg(boardArgs[2], XtNheight,
2099 boardHeight + 2*(lineGap + squareSize));
2100 } else if (appData.showJail == 2) {
2102 XtSetArg(boardArgs[1], XtNwidth,
2103 boardWidth + 2*(lineGap + squareSize));
2104 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2107 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2108 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2112 * Determine what fonts to use.
2114 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2115 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2116 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2117 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2118 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2119 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2120 appData.font = FindFont(appData.font, fontPxlSize);
2121 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2122 countFontStruct = XQueryFont(xDisplay, countFontID);
2123 // appData.font = FindFont(appData.font, fontPxlSize);
2125 xdb = XtDatabase(xDisplay);
2126 XrmPutStringResource(&xdb, "*font", appData.font);
2129 * Detect if there are not enough colors available and adapt.
2131 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2132 appData.monoMode = True;
2135 forceMono = MakeColors();
2138 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2141 if (appData.bitmapDirectory == NULL ||
2142 appData.bitmapDirectory[0] == NULLCHAR)
2143 appData.bitmapDirectory = DEF_BITMAP_DIR;
2146 if (appData.lowTimeWarning && !appData.monoMode) {
2147 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2148 vFrom.size = strlen(appData.lowTimeWarningColor);
2149 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2150 if (vTo.addr == NULL)
2151 appData.monoMode = True;
2153 lowTimeWarningColor = *(Pixel *) vTo.addr;
2156 if (appData.monoMode && appData.debugMode) {
2157 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2158 (unsigned long) XWhitePixel(xDisplay, xScreen),
2159 (unsigned long) XBlackPixel(xDisplay, xScreen));
2162 ParseIcsTextColors();
2163 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2164 textColors[ColorNone].attr = 0;
2166 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2172 layoutName = "tinyLayout";
2173 } else if (smallLayout) {
2174 layoutName = "smallLayout";
2176 layoutName = "normalLayout";
2178 /* Outer layoutWidget is there only to provide a name for use in
2179 resources that depend on the layout style */
2181 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2182 layoutArgs, XtNumber(layoutArgs));
2184 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2185 formArgs, XtNumber(formArgs));
2186 XtSetArg(args[0], XtNdefaultDistance, &sep);
2187 XtGetValues(formWidget, args, 1);
2190 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2191 XtSetArg(args[0], XtNtop, XtChainTop);
2192 XtSetArg(args[1], XtNbottom, XtChainTop);
2193 XtSetArg(args[2], XtNright, XtChainLeft);
2194 XtSetValues(menuBarWidget, args, 3);
2196 widgetList[j++] = whiteTimerWidget =
2197 XtCreateWidget("whiteTime", labelWidgetClass,
2198 formWidget, timerArgs, XtNumber(timerArgs));
2199 XtSetArg(args[0], XtNfont, clockFontStruct);
2200 XtSetArg(args[1], XtNtop, XtChainTop);
2201 XtSetArg(args[2], XtNbottom, XtChainTop);
2202 XtSetValues(whiteTimerWidget, args, 3);
2204 widgetList[j++] = blackTimerWidget =
2205 XtCreateWidget("blackTime", labelWidgetClass,
2206 formWidget, timerArgs, XtNumber(timerArgs));
2207 XtSetArg(args[0], XtNfont, clockFontStruct);
2208 XtSetArg(args[1], XtNtop, XtChainTop);
2209 XtSetArg(args[2], XtNbottom, XtChainTop);
2210 XtSetValues(blackTimerWidget, args, 3);
2212 if (appData.titleInWindow) {
2213 widgetList[j++] = titleWidget =
2214 XtCreateWidget("title", labelWidgetClass, formWidget,
2215 titleArgs, XtNumber(titleArgs));
2216 XtSetArg(args[0], XtNtop, XtChainTop);
2217 XtSetArg(args[1], XtNbottom, XtChainTop);
2218 XtSetValues(titleWidget, args, 2);
2221 if (appData.showButtonBar) {
2222 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2223 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2224 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2225 XtSetArg(args[2], XtNtop, XtChainTop);
2226 XtSetArg(args[3], XtNbottom, XtChainTop);
2227 XtSetValues(buttonBarWidget, args, 4);
2230 widgetList[j++] = messageWidget =
2231 XtCreateWidget("message", labelWidgetClass, formWidget,
2232 messageArgs, XtNumber(messageArgs));
2233 XtSetArg(args[0], XtNtop, XtChainTop);
2234 XtSetArg(args[1], XtNbottom, XtChainTop);
2235 XtSetValues(messageWidget, args, 2);
2237 widgetList[j++] = boardWidget =
2238 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2239 XtNumber(boardArgs));
2241 XtManageChildren(widgetList, j);
2243 timerWidth = (boardWidth - sep) / 2;
2244 XtSetArg(args[0], XtNwidth, timerWidth);
2245 XtSetValues(whiteTimerWidget, args, 1);
2246 XtSetValues(blackTimerWidget, args, 1);
2248 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2249 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2250 XtGetValues(whiteTimerWidget, args, 2);
2252 if (appData.showButtonBar) {
2253 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2254 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2255 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2259 * formWidget uses these constraints but they are stored
2263 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2264 XtSetValues(menuBarWidget, args, i);
2265 if (appData.titleInWindow) {
2268 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2269 XtSetValues(whiteTimerWidget, args, i);
2271 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2272 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2273 XtSetValues(blackTimerWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2276 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2277 XtSetValues(titleWidget, args, i);
2279 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2280 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2281 XtSetValues(messageWidget, args, i);
2282 if (appData.showButtonBar) {
2284 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2285 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2286 XtSetValues(buttonBarWidget, args, i);
2290 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2291 XtSetValues(whiteTimerWidget, args, i);
2293 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2294 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2295 XtSetValues(blackTimerWidget, args, i);
2297 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2298 XtSetValues(titleWidget, args, i);
2300 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2301 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2302 XtSetValues(messageWidget, args, i);
2303 if (appData.showButtonBar) {
2305 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2306 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2307 XtSetValues(buttonBarWidget, args, i);
2312 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2313 XtSetValues(whiteTimerWidget, args, i);
2315 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2316 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2317 XtSetValues(blackTimerWidget, args, i);
2319 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2320 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2321 XtSetValues(messageWidget, args, i);
2322 if (appData.showButtonBar) {
2324 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2325 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2326 XtSetValues(buttonBarWidget, args, i);
2330 XtSetArg(args[0], XtNfromVert, messageWidget);
2331 XtSetArg(args[1], XtNtop, XtChainTop);
2332 XtSetArg(args[2], XtNbottom, XtChainBottom);
2333 XtSetArg(args[3], XtNleft, XtChainLeft);
2334 XtSetArg(args[4], XtNright, XtChainRight);
2335 XtSetValues(boardWidget, args, 5);
2337 XtRealizeWidget(shellWidget);
2340 XtSetArg(args[0], XtNx, wpMain.x);
2341 XtSetArg(args[1], XtNy, wpMain.y);
2342 XtSetValues(shellWidget, args, 2);
2346 * Correct the width of the message and title widgets.
2347 * It is not known why some systems need the extra fudge term.
2348 * The value "2" is probably larger than needed.
2350 XawFormDoLayout(formWidget, False);
2352 #define WIDTH_FUDGE 2
2354 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2355 XtSetArg(args[i], XtNheight, &h); i++;
2356 XtGetValues(messageWidget, args, i);
2357 if (appData.showButtonBar) {
2359 XtSetArg(args[i], XtNwidth, &w); i++;
2360 XtGetValues(buttonBarWidget, args, i);
2361 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2363 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2366 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2367 if (gres != XtGeometryYes && appData.debugMode) {
2368 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2369 programName, gres, w, h, wr, hr);
2372 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2373 /* The size used for the child widget in layout lags one resize behind
2374 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2376 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2377 if (gres != XtGeometryYes && appData.debugMode) {
2378 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2379 programName, gres, w, h, wr, hr);
2382 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2383 XtSetArg(args[1], XtNright, XtChainRight);
2384 XtSetValues(messageWidget, args, 2);
2386 if (appData.titleInWindow) {
2388 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2389 XtSetArg(args[i], XtNheight, &h); i++;
2390 XtGetValues(titleWidget, args, i);
2392 w = boardWidth - 2*bor;
2394 XtSetArg(args[0], XtNwidth, &w);
2395 XtGetValues(menuBarWidget, args, 1);
2396 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2399 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2400 if (gres != XtGeometryYes && appData.debugMode) {
2402 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2403 programName, gres, w, h, wr, hr);
2406 XawFormDoLayout(formWidget, True);
2408 xBoardWindow = XtWindow(boardWidget);
2410 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2411 // not need to go into InitDrawingSizes().
2415 * Create X checkmark bitmap and initialize option menu checks.
2417 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2418 checkmark_bits, checkmark_width, checkmark_height);
2419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2420 #ifndef OPTIONSDIALOG
2421 if (appData.alwaysPromoteToQueen) {
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2425 if (appData.animateDragging) {
2426 XtSetValues(XtNameToWidget(menuBarWidget,
2427 "menuOptions.Animate Dragging"),
2430 if (appData.animate) {
2431 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2434 if (appData.autoCallFlag) {
2435 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2438 if (appData.autoFlipView) {
2439 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2442 if (appData.blindfold) {
2443 XtSetValues(XtNameToWidget(menuBarWidget,
2444 "menuOptions.Blindfold"), args, 1);
2446 if (appData.flashCount > 0) {
2447 XtSetValues(XtNameToWidget(menuBarWidget,
2448 "menuOptions.Flash Moves"),
2452 if (appData.highlightDragging) {
2453 XtSetValues(XtNameToWidget(menuBarWidget,
2454 "menuOptions.Highlight Dragging"),
2458 if (appData.highlightLastMove) {
2459 XtSetValues(XtNameToWidget(menuBarWidget,
2460 "menuOptions.Highlight Last Move"),
2463 if (appData.highlightMoveWithArrow) {
2464 XtSetValues(XtNameToWidget(menuBarWidget,
2465 "menuOptions.Arrow"),
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.oneClick) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.OneClick"), 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.showCoords) {
2501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2504 if (appData.hideThinkingFromHuman) {
2505 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2508 if (appData.testLegality) {
2509 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2513 if (saveSettingsOnExit) {
2514 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2521 ReadBitmap(&wIconPixmap, "icon_white.bm",
2522 icon_white_bits, icon_white_width, icon_white_height);
2523 ReadBitmap(&bIconPixmap, "icon_black.bm",
2524 icon_black_bits, icon_black_width, icon_black_height);
2525 iconPixmap = wIconPixmap;
2527 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2528 XtSetValues(shellWidget, args, i);
2531 * Create a cursor for the board widget.
2533 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2534 XChangeWindowAttributes(xDisplay, xBoardWindow,
2535 CWCursor, &window_attributes);
2538 * Inhibit shell resizing.
2540 shellArgs[0].value = (XtArgVal) &w;
2541 shellArgs[1].value = (XtArgVal) &h;
2542 XtGetValues(shellWidget, shellArgs, 2);
2543 shellArgs[4].value = shellArgs[2].value = w;
2544 shellArgs[5].value = shellArgs[3].value = h;
2545 XtSetValues(shellWidget, &shellArgs[2], 4);
2546 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2547 marginH = h - boardHeight;
2549 CatchDeleteWindow(shellWidget, "QuitProc");
2554 if (appData.bitmapDirectory[0] != NULLCHAR) {
2558 CreateXPMBoard(appData.liteBackTextureFile, 1);
2559 CreateXPMBoard(appData.darkBackTextureFile, 0);
2563 /* Create regular pieces */
2564 if (!useImages) CreatePieces();
2569 if (appData.animate || appData.animateDragging)
2572 XtAugmentTranslations(formWidget,
2573 XtParseTranslationTable(globalTranslations));
2574 XtAugmentTranslations(boardWidget,
2575 XtParseTranslationTable(boardTranslations));
2576 XtAugmentTranslations(whiteTimerWidget,
2577 XtParseTranslationTable(whiteTranslations));
2578 XtAugmentTranslations(blackTimerWidget,
2579 XtParseTranslationTable(blackTranslations));
2581 /* Why is the following needed on some versions of X instead
2582 * of a translation? */
2583 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2584 (XtEventHandler) EventProc, NULL);
2587 /* [AS] Restore layout */
2588 if( wpMoveHistory.visible ) {
2592 if( wpEvalGraph.visible )
2597 if( wpEngineOutput.visible ) {
2598 EngineOutputPopUp();
2603 if (errorExitStatus == -1) {
2604 if (appData.icsActive) {
2605 /* We now wait until we see "login:" from the ICS before
2606 sending the logon script (problems with timestamp otherwise) */
2607 /*ICSInitScript();*/
2608 if (appData.icsInputBox) ICSInputBoxPopUp();
2612 signal(SIGWINCH, TermSizeSigHandler);
2614 signal(SIGINT, IntSigHandler);
2615 signal(SIGTERM, IntSigHandler);
2616 if (*appData.cmailGameName != NULLCHAR) {
2617 signal(SIGUSR1, CmailSigHandler);
2620 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2622 XtSetKeyboardFocus(shellWidget, formWidget);
2624 XtAppMainLoop(appContext);
2625 if (appData.debugMode) fclose(debugFP); // [DM] debug
2632 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2633 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2635 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2636 unlink(gameCopyFilename);
2637 unlink(gamePasteFilename);
2640 RETSIGTYPE TermSizeSigHandler(int sig)
2653 CmailSigHandler(sig)
2659 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2661 /* Activate call-back function CmailSigHandlerCallBack() */
2662 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2664 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2668 CmailSigHandlerCallBack(isr, closure, message, count, error)
2676 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2678 /**** end signal code ****/
2684 /* try to open the icsLogon script, either in the location given
2685 * or in the users HOME directory
2692 f = fopen(appData.icsLogon, "r");
2695 homedir = getenv("HOME");
2696 if (homedir != NULL)
2698 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2699 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2700 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2701 f = fopen(buf, "r");
2706 ProcessICSInitScript(f);
2708 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2717 EditCommentPopDown();
2732 if (!menuBarWidget) return;
2733 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2735 DisplayError("menuEdit.Revert", 0);
2737 XtSetSensitive(w, !grey);
2739 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2741 DisplayError("menuEdit.Annotate", 0);
2743 XtSetSensitive(w, !grey);
2748 SetMenuEnables(enab)
2752 if (!menuBarWidget) return;
2753 while (enab->name != NULL) {
2754 w = XtNameToWidget(menuBarWidget, enab->name);
2756 DisplayError(enab->name, 0);
2758 XtSetSensitive(w, enab->value);
2764 Enables icsEnables[] = {
2765 { "menuFile.Mail Move", False },
2766 { "menuFile.Reload CMail Message", False },
2767 { "menuMode.Machine Black", False },
2768 { "menuMode.Machine White", False },
2769 { "menuMode.Analysis Mode", False },
2770 { "menuMode.Analyze File", False },
2771 { "menuMode.Two Machines", False },
2772 { "menuMode.Machine Match", False },
2774 { "menuEngine.Hint", False },
2775 { "menuEngine.Book", False },
2776 { "menuEngine.Move Now", False },
2777 #ifndef OPTIONSDIALOG
2778 { "menuOptions.Periodic Updates", False },
2779 { "menuOptions.Hide Thinking", False },
2780 { "menuOptions.Ponder Next Move", False },
2782 { "menuEngine.Engine #1 Settings", False },
2784 { "menuEngine.Engine #2 Settings", False },
2785 { "menuEdit.Annotate", False },
2789 Enables ncpEnables[] = {
2790 { "menuFile.Mail Move", False },
2791 { "menuFile.Reload CMail Message", False },
2792 { "menuMode.Machine White", False },
2793 { "menuMode.Machine Black", False },
2794 { "menuMode.Analysis Mode", False },
2795 { "menuMode.Analyze File", False },
2796 { "menuMode.Two Machines", False },
2797 { "menuMode.Machine Match", False },
2798 { "menuMode.ICS Client", False },
2799 { "menuView.ICStex", False },
2800 { "menuView.ICS Input Box", False },
2801 { "Action", False },
2802 { "menuEdit.Revert", False },
2803 { "menuEdit.Annotate", False },
2804 { "menuEngine.Engine #1 Settings", False },
2805 { "menuEngine.Engine #2 Settings", False },
2806 { "menuEngine.Move Now", False },
2807 { "menuEngine.Retract Move", False },
2808 { "menuOptions.ICS", False },
2809 #ifndef OPTIONSDIALOG
2810 { "menuOptions.Auto Flag", False },
2811 { "menuOptions.Auto Flip View", False },
2812 // { "menuOptions.ICS Alarm", False },
2813 { "menuOptions.Move Sound", False },
2814 { "menuOptions.Hide Thinking", False },
2815 { "menuOptions.Periodic Updates", False },
2816 { "menuOptions.Ponder Next Move", False },
2818 { "menuEngine.Hint", False },
2819 { "menuEngine.Book", False },
2823 Enables gnuEnables[] = {
2824 { "menuMode.ICS Client", False },
2825 { "menuView.ICStex", False },
2826 { "menuView.ICS Input Box", False },
2827 { "menuAction.Accept", False },
2828 { "menuAction.Decline", False },
2829 { "menuAction.Rematch", False },
2830 { "menuAction.Adjourn", False },
2831 { "menuAction.Stop Examining", False },
2832 { "menuAction.Stop Observing", False },
2833 { "menuAction.Upload to Examine", False },
2834 { "menuEdit.Revert", False },
2835 { "menuEdit.Annotate", False },
2836 { "menuOptions.ICS", False },
2838 /* The next two options rely on SetCmailMode being called *after* */
2839 /* SetGNUMode so that when GNU is being used to give hints these */
2840 /* menu options are still available */
2842 { "menuFile.Mail Move", False },
2843 { "menuFile.Reload CMail Message", False },
2847 Enables cmailEnables[] = {
2849 { "menuAction.Call Flag", False },
2850 { "menuAction.Draw", True },
2851 { "menuAction.Adjourn", False },
2852 { "menuAction.Abort", False },
2853 { "menuAction.Stop Observing", False },
2854 { "menuAction.Stop Examining", False },
2855 { "menuFile.Mail Move", True },
2856 { "menuFile.Reload CMail Message", True },
2860 Enables trainingOnEnables[] = {
2861 { "menuMode.Edit Comment", False },
2862 { "menuMode.Pause", False },
2863 { "menuEdit.Forward", False },
2864 { "menuEdit.Backward", False },
2865 { "menuEdit.Forward to End", False },
2866 { "menuEdit.Back to Start", False },
2867 { "menuEngine.Move Now", False },
2868 { "menuEdit.Truncate Game", False },
2872 Enables trainingOffEnables[] = {
2873 { "menuMode.Edit Comment", True },
2874 { "menuMode.Pause", True },
2875 { "menuEdit.Forward", True },
2876 { "menuEdit.Backward", True },
2877 { "menuEdit.Forward to End", True },
2878 { "menuEdit.Back to Start", True },
2879 { "menuEngine.Move Now", True },
2880 { "menuEdit.Truncate Game", True },
2884 Enables machineThinkingEnables[] = {
2885 { "menuFile.Load Game", False },
2886 // { "menuFile.Load Next Game", False },
2887 // { "menuFile.Load Previous Game", False },
2888 // { "menuFile.Reload Same Game", False },
2889 { "menuEdit.Paste Game", False },
2890 { "menuFile.Load Position", False },
2891 // { "menuFile.Load Next Position", False },
2892 // { "menuFile.Load Previous Position", False },
2893 // { "menuFile.Reload Same Position", False },
2894 { "menuEdit.Paste Position", False },
2895 { "menuMode.Machine White", False },
2896 { "menuMode.Machine Black", False },
2897 { "menuMode.Two Machines", False },
2898 { "menuMode.Machine Match", False },
2899 { "menuEngine.Retract Move", False },
2903 Enables userThinkingEnables[] = {
2904 { "menuFile.Load Game", True },
2905 // { "menuFile.Load Next Game", True },
2906 // { "menuFile.Load Previous Game", True },
2907 // { "menuFile.Reload Same Game", True },
2908 { "menuEdit.Paste Game", True },
2909 { "menuFile.Load Position", True },
2910 // { "menuFile.Load Next Position", True },
2911 // { "menuFile.Load Previous Position", True },
2912 // { "menuFile.Reload Same Position", True },
2913 { "menuEdit.Paste Position", True },
2914 { "menuMode.Machine White", True },
2915 { "menuMode.Machine Black", True },
2916 { "menuMode.Two Machines", True },
2917 { "menuMode.Machine Match", True },
2918 { "menuEngine.Retract Move", True },
2924 SetMenuEnables(icsEnables);
2927 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2928 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2935 SetMenuEnables(ncpEnables);
2941 SetMenuEnables(gnuEnables);
2947 SetMenuEnables(cmailEnables);
2953 SetMenuEnables(trainingOnEnables);
2954 if (appData.showButtonBar) {
2955 XtSetSensitive(buttonBarWidget, False);
2961 SetTrainingModeOff()
2963 SetMenuEnables(trainingOffEnables);
2964 if (appData.showButtonBar) {
2965 XtSetSensitive(buttonBarWidget, True);
2970 SetUserThinkingEnables()
2972 if (appData.noChessProgram) return;
2973 SetMenuEnables(userThinkingEnables);
2977 SetMachineThinkingEnables()
2979 if (appData.noChessProgram) return;
2980 SetMenuEnables(machineThinkingEnables);
2982 case MachinePlaysBlack:
2983 case MachinePlaysWhite:
2984 case TwoMachinesPlay:
2985 XtSetSensitive(XtNameToWidget(menuBarWidget,
2986 ModeToWidgetName(gameMode)), True);
2993 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2994 #define HISTORY_SIZE 64
2995 static char *history[HISTORY_SIZE];
2996 int histIn = 0, histP = 0;
2999 SaveInHistory(char *cmd)
3001 if (history[histIn] != NULL) {
3002 free(history[histIn]);
3003 history[histIn] = NULL;
3005 if (*cmd == NULLCHAR) return;
3006 history[histIn] = StrSave(cmd);
3007 histIn = (histIn + 1) % HISTORY_SIZE;
3008 if (history[histIn] != NULL) {
3009 free(history[histIn]);
3010 history[histIn] = NULL;
3016 PrevInHistory(char *cmd)
3019 if (histP == histIn) {
3020 if (history[histIn] != NULL) free(history[histIn]);
3021 history[histIn] = StrSave(cmd);
3023 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3024 if (newhp == histIn || history[newhp] == NULL) return NULL;
3026 return history[histP];
3032 if (histP == histIn) return NULL;
3033 histP = (histP + 1) % HISTORY_SIZE;
3034 return history[histP];
3036 // end of borrowed code
3038 #define Abs(n) ((n)<0 ? -(n) : (n))
3041 * Find a font that matches "pattern" that is as close as
3042 * possible to the targetPxlSize. Prefer fonts that are k
3043 * pixels smaller to fonts that are k pixels larger. The
3044 * pattern must be in the X Consortium standard format,
3045 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3046 * The return value should be freed with XtFree when no
3050 FindFont(pattern, targetPxlSize)
3054 char **fonts, *p, *best, *scalable, *scalableTail;
3055 int i, j, nfonts, minerr, err, pxlSize;
3058 char **missing_list;
3060 char *def_string, *base_fnt_lst, strInt[3];
3062 XFontStruct **fnt_list;
3064 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3065 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3066 p = strstr(pattern, "--");
3067 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3068 strcat(base_fnt_lst, strInt);
3069 strcat(base_fnt_lst, strchr(p + 2, '-'));
3071 if ((fntSet = XCreateFontSet(xDisplay,
3075 &def_string)) == NULL) {
3077 fprintf(stderr, _("Unable to create font set.\n"));
3081 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3083 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3085 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3086 programName, pattern);
3094 for (i=0; i<nfonts; i++) {
3097 if (*p != '-') continue;
3099 if (*p == NULLCHAR) break;
3100 if (*p++ == '-') j++;
3102 if (j < 7) continue;
3105 scalable = fonts[i];
3108 err = pxlSize - targetPxlSize;
3109 if (Abs(err) < Abs(minerr) ||
3110 (minerr > 0 && err < 0 && -err == minerr)) {
3116 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3117 /* If the error is too big and there is a scalable font,
3118 use the scalable font. */
3119 int headlen = scalableTail - scalable;
3120 p = (char *) XtMalloc(strlen(scalable) + 10);
3121 while (isdigit(*scalableTail)) scalableTail++;
3122 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3124 p = (char *) XtMalloc(strlen(best) + 2);
3125 safeStrCpy(p, best, strlen(best)+1 );
3127 if (appData.debugMode) {
3128 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3129 pattern, targetPxlSize, p);
3132 if (missing_count > 0)
3133 XFreeStringList(missing_list);
3134 XFreeFontSet(xDisplay, fntSet);
3136 XFreeFontNames(fonts);
3142 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3143 // must be called before all non-first callse to CreateGCs()
3144 XtReleaseGC(shellWidget, highlineGC);
3145 XtReleaseGC(shellWidget, lightSquareGC);
3146 XtReleaseGC(shellWidget, darkSquareGC);
3147 XtReleaseGC(shellWidget, lineGC);
3148 if (appData.monoMode) {
3149 if (DefaultDepth(xDisplay, xScreen) == 1) {
3150 XtReleaseGC(shellWidget, wbPieceGC);
3152 XtReleaseGC(shellWidget, bwPieceGC);
3155 XtReleaseGC(shellWidget, prelineGC);
3156 XtReleaseGC(shellWidget, jailSquareGC);
3157 XtReleaseGC(shellWidget, wdPieceGC);
3158 XtReleaseGC(shellWidget, wlPieceGC);
3159 XtReleaseGC(shellWidget, wjPieceGC);
3160 XtReleaseGC(shellWidget, bdPieceGC);
3161 XtReleaseGC(shellWidget, blPieceGC);
3162 XtReleaseGC(shellWidget, bjPieceGC);
3166 void CreateGCs(int redo)
3168 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3169 | GCBackground | GCFunction | GCPlaneMask;
3170 XGCValues gc_values;
3173 gc_values.plane_mask = AllPlanes;
3174 gc_values.line_width = lineGap;
3175 gc_values.line_style = LineSolid;
3176 gc_values.function = GXcopy;
3179 DeleteGCs(); // called a second time; clean up old GCs first
3180 } else { // [HGM] grid and font GCs created on first call only
3181 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3182 gc_values.background = XWhitePixel(xDisplay, xScreen);
3183 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3184 XSetFont(xDisplay, coordGC, coordFontID);
3186 // [HGM] make font for holdings counts (white on black)
3187 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3188 gc_values.background = XBlackPixel(xDisplay, xScreen);
3189 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3190 XSetFont(xDisplay, countGC, countFontID);
3192 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3193 gc_values.background = XBlackPixel(xDisplay, xScreen);
3194 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 if (appData.monoMode) {
3197 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3198 gc_values.background = XWhitePixel(xDisplay, xScreen);
3199 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3201 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3202 gc_values.background = XBlackPixel(xDisplay, xScreen);
3203 lightSquareGC = wbPieceGC
3204 = XtGetGC(shellWidget, value_mask, &gc_values);
3206 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3207 gc_values.background = XWhitePixel(xDisplay, xScreen);
3208 darkSquareGC = bwPieceGC
3209 = XtGetGC(shellWidget, value_mask, &gc_values);
3211 if (DefaultDepth(xDisplay, xScreen) == 1) {
3212 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3213 gc_values.function = GXcopyInverted;
3214 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3215 gc_values.function = GXcopy;
3216 if (XBlackPixel(xDisplay, xScreen) == 1) {
3217 bwPieceGC = darkSquareGC;
3218 wbPieceGC = copyInvertedGC;
3220 bwPieceGC = copyInvertedGC;
3221 wbPieceGC = lightSquareGC;
3225 gc_values.foreground = highlightSquareColor;
3226 gc_values.background = highlightSquareColor;
3227 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3229 gc_values.foreground = premoveHighlightColor;
3230 gc_values.background = premoveHighlightColor;
3231 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3233 gc_values.foreground = lightSquareColor;
3234 gc_values.background = darkSquareColor;
3235 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3237 gc_values.foreground = darkSquareColor;
3238 gc_values.background = lightSquareColor;
3239 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3241 gc_values.foreground = jailSquareColor;
3242 gc_values.background = jailSquareColor;
3243 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3245 gc_values.foreground = whitePieceColor;
3246 gc_values.background = darkSquareColor;
3247 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3249 gc_values.foreground = whitePieceColor;
3250 gc_values.background = lightSquareColor;
3251 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3253 gc_values.foreground = whitePieceColor;
3254 gc_values.background = jailSquareColor;
3255 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3257 gc_values.foreground = blackPieceColor;
3258 gc_values.background = darkSquareColor;
3259 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3261 gc_values.foreground = blackPieceColor;
3262 gc_values.background = lightSquareColor;
3263 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3265 gc_values.foreground = blackPieceColor;
3266 gc_values.background = jailSquareColor;
3267 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3271 void loadXIM(xim, xmask, filename, dest, mask)
3284 fp = fopen(filename, "rb");
3286 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3293 for (y=0; y<h; ++y) {
3294 for (x=0; x<h; ++x) {
3299 XPutPixel(xim, x, y, blackPieceColor);
3301 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3304 XPutPixel(xim, x, y, darkSquareColor);
3306 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3309 XPutPixel(xim, x, y, whitePieceColor);
3311 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3314 XPutPixel(xim, x, y, lightSquareColor);
3316 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3324 /* create Pixmap of piece */
3325 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3327 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3330 /* create Pixmap of clipmask
3331 Note: We assume the white/black pieces have the same
3332 outline, so we make only 6 masks. This is okay
3333 since the XPM clipmask routines do the same. */
3335 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3337 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3340 /* now create the 1-bit version */
3341 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3344 values.foreground = 1;
3345 values.background = 0;
3347 /* Don't use XtGetGC, not read only */
3348 maskGC = XCreateGC(xDisplay, *mask,
3349 GCForeground | GCBackground, &values);
3350 XCopyPlane(xDisplay, temp, *mask, maskGC,
3351 0, 0, squareSize, squareSize, 0, 0, 1);
3352 XFreePixmap(xDisplay, temp);
3357 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3359 void CreateXIMPieces()
3364 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3369 /* The XSynchronize calls were copied from CreatePieces.
3370 Not sure if needed, but can't hurt */
3371 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3374 /* temp needed by loadXIM() */
3375 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3376 0, 0, ss, ss, AllPlanes, XYPixmap);
3378 if (strlen(appData.pixmapDirectory) == 0) {
3382 if (appData.monoMode) {
3383 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3387 fprintf(stderr, _("\nLoading XIMs...\n"));
3389 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3390 fprintf(stderr, "%d", piece+1);
3391 for (kind=0; kind<4; kind++) {
3392 fprintf(stderr, ".");
3393 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3394 ExpandPathName(appData.pixmapDirectory),
3395 piece <= (int) WhiteKing ? "" : "w",
3396 pieceBitmapNames[piece],
3398 ximPieceBitmap[kind][piece] =
3399 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3400 0, 0, ss, ss, AllPlanes, XYPixmap);
3401 if (appData.debugMode)
3402 fprintf(stderr, _("(File:%s:) "), buf);
3403 loadXIM(ximPieceBitmap[kind][piece],
3405 &(xpmPieceBitmap2[kind][piece]),
3406 &(ximMaskPm2[piece]));
3407 if(piece <= (int)WhiteKing)
3408 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3410 fprintf(stderr," ");
3412 /* Load light and dark squares */
3413 /* If the LSQ and DSQ pieces don't exist, we will
3414 draw them with solid squares. */
3415 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3416 if (access(buf, 0) != 0) {
3420 fprintf(stderr, _("light square "));
3422 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3423 0, 0, ss, ss, AllPlanes, XYPixmap);
3424 if (appData.debugMode)
3425 fprintf(stderr, _("(File:%s:) "), buf);
3427 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3428 fprintf(stderr, _("dark square "));
3429 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3430 ExpandPathName(appData.pixmapDirectory), ss);
3431 if (appData.debugMode)
3432 fprintf(stderr, _("(File:%s:) "), buf);
3434 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3435 0, 0, ss, ss, AllPlanes, XYPixmap);
3436 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3437 xpmJailSquare = xpmLightSquare;
3439 fprintf(stderr, _("Done.\n"));
3441 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3444 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3447 void CreateXPMBoard(char *s, int kind)
3451 if(s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3452 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3453 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3457 void FreeXPMPieces()
3458 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3459 // thisroutine has to be called t free the old piece pixmaps
3461 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3462 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3464 XFreePixmap(xDisplay, xpmLightSquare);
3465 XFreePixmap(xDisplay, xpmDarkSquare);
3469 void CreateXPMPieces()
3473 u_int ss = squareSize;
3475 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3476 XpmColorSymbol symbols[4];
3477 static int redo = False;
3479 if(redo) FreeXPMPieces(); else redo = 1;
3481 /* The XSynchronize calls were copied from CreatePieces.
3482 Not sure if needed, but can't hurt */
3483 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3485 /* Setup translations so piece colors match square colors */
3486 symbols[0].name = "light_piece";
3487 symbols[0].value = appData.whitePieceColor;
3488 symbols[1].name = "dark_piece";
3489 symbols[1].value = appData.blackPieceColor;
3490 symbols[2].name = "light_square";
3491 symbols[2].value = appData.lightSquareColor;
3492 symbols[3].name = "dark_square";
3493 symbols[3].value = appData.darkSquareColor;
3495 attr.valuemask = XpmColorSymbols;
3496 attr.colorsymbols = symbols;
3497 attr.numsymbols = 4;
3499 if (appData.monoMode) {
3500 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3504 if (strlen(appData.pixmapDirectory) == 0) {
3505 XpmPieces* pieces = builtInXpms;
3508 while (pieces->size != squareSize && pieces->size) pieces++;
3509 if (!pieces->size) {
3510 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3513 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3514 for (kind=0; kind<4; kind++) {
3516 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3517 pieces->xpm[piece][kind],
3518 &(xpmPieceBitmap2[kind][piece]),
3519 NULL, &attr)) != 0) {
3520 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3524 if(piece <= (int) WhiteKing)
3525 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3529 xpmJailSquare = xpmLightSquare;
3533 fprintf(stderr, _("\nLoading XPMs...\n"));
3536 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3537 fprintf(stderr, "%d ", piece+1);
3538 for (kind=0; kind<4; kind++) {
3539 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3540 ExpandPathName(appData.pixmapDirectory),
3541 piece > (int) WhiteKing ? "w" : "",
3542 pieceBitmapNames[piece],
3544 if (appData.debugMode) {
3545 fprintf(stderr, _("(File:%s:) "), buf);
3547 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3548 &(xpmPieceBitmap2[kind][piece]),
3549 NULL, &attr)) != 0) {
3550 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3551 // [HGM] missing: read of unorthodox piece failed; substitute King.
3552 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3553 ExpandPathName(appData.pixmapDirectory),
3555 if (appData.debugMode) {
3556 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3558 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3559 &(xpmPieceBitmap2[kind][piece]),
3563 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3568 if(piece <= (int) WhiteKing)
3569 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3572 /* Load light and dark squares */
3573 /* If the LSQ and DSQ pieces don't exist, we will
3574 draw them with solid squares. */
3575 fprintf(stderr, _("light square "));
3576 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3577 if (access(buf, 0) != 0) {
3581 if (appData.debugMode)
3582 fprintf(stderr, _("(File:%s:) "), buf);
3584 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3585 &xpmLightSquare, NULL, &attr)) != 0) {
3586 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3589 fprintf(stderr, _("dark square "));
3590 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3591 ExpandPathName(appData.pixmapDirectory), ss);
3592 if (appData.debugMode) {
3593 fprintf(stderr, _("(File:%s:) "), buf);
3595 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3596 &xpmDarkSquare, NULL, &attr)) != 0) {
3597 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3601 xpmJailSquare = xpmLightSquare;
3602 fprintf(stderr, _("Done.\n"));
3604 oldVariant = -1; // kludge to force re-makig of animation masks
3605 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3608 #endif /* HAVE_LIBXPM */
3611 /* No built-in bitmaps */
3616 u_int ss = squareSize;
3618 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3621 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3622 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3623 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3624 pieceBitmapNames[piece],
3625 ss, kind == SOLID ? 's' : 'o');
3626 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3627 if(piece <= (int)WhiteKing)
3628 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3632 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3636 /* With built-in bitmaps */
3639 BuiltInBits* bib = builtInBits;
3642 u_int ss = squareSize;
3644 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3647 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3649 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3650 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3651 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3652 pieceBitmapNames[piece],
3653 ss, kind == SOLID ? 's' : 'o');
3654 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3655 bib->bits[kind][piece], ss, ss);
3656 if(piece <= (int)WhiteKing)
3657 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3661 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3666 void ReadBitmap(pm, name, bits, wreq, hreq)
3669 unsigned char bits[];
3675 char msg[MSG_SIZ], fullname[MSG_SIZ];
3677 if (*appData.bitmapDirectory != NULLCHAR) {
3678 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3679 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3680 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3681 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3682 &w, &h, pm, &x_hot, &y_hot);
3683 fprintf(stderr, "load %s\n", name);
3684 if (errcode != BitmapSuccess) {
3686 case BitmapOpenFailed:
3687 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3689 case BitmapFileInvalid:
3690 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3692 case BitmapNoMemory:
3693 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3697 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3701 fprintf(stderr, _("%s: %s...using built-in\n"),
3703 } else if (w != wreq || h != hreq) {
3705 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3706 programName, fullname, w, h, wreq, hreq);
3712 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3721 if (lineGap == 0) return;
3723 /* [HR] Split this into 2 loops for non-square boards. */
3725 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3726 gridSegments[i].x1 = 0;
3727 gridSegments[i].x2 =
3728 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3729 gridSegments[i].y1 = gridSegments[i].y2
3730 = lineGap / 2 + (i * (squareSize + lineGap));
3733 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3734 gridSegments[j + i].y1 = 0;
3735 gridSegments[j + i].y2 =
3736 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3737 gridSegments[j + i].x1 = gridSegments[j + i].x2
3738 = lineGap / 2 + (j * (squareSize + lineGap));
3742 static void MenuBarSelect(w, addr, index)
3747 XtActionProc proc = (XtActionProc) addr;
3749 (proc)(NULL, NULL, NULL, NULL);
3752 void CreateMenuBarPopup(parent, name, mb)
3762 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3765 XtSetArg(args[j], XtNleftMargin, 20); j++;
3766 XtSetArg(args[j], XtNrightMargin, 20); j++;
3768 while (mi->string != NULL) {
3769 if (strcmp(mi->string, "----") == 0) {
3770 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3773 XtSetArg(args[j], XtNlabel, XtNewString(mi->string));
3774 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3776 XtAddCallback(entry, XtNcallback,
3777 (XtCallbackProc) MenuBarSelect,
3778 (caddr_t) mi->proc);
3784 Widget CreateMenuBar(mb)
3788 Widget anchor, menuBar;
3790 char menuName[MSG_SIZ];
3793 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3794 XtSetArg(args[j], XtNvSpace, 0); j++;
3795 XtSetArg(args[j], XtNborderWidth, 0); j++;
3796 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3797 formWidget, args, j);
3799 while (mb->name != NULL) {
3800 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3801 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3803 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3806 shortName[0] = mb->name[0];
3807 shortName[1] = NULLCHAR;
3808 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3811 XtSetArg(args[j], XtNlabel, XtNewString(mb->name)); j++;
3814 XtSetArg(args[j], XtNborderWidth, 0); j++;
3815 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3817 CreateMenuBarPopup(menuBar, menuName, mb);
3823 Widget CreateButtonBar(mi)
3827 Widget button, buttonBar;
3831 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3833 XtSetArg(args[j], XtNhSpace, 0); j++;
3835 XtSetArg(args[j], XtNborderWidth, 0); j++;
3836 XtSetArg(args[j], XtNvSpace, 0); j++;
3837 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3838 formWidget, args, j);
3840 while (mi->string != NULL) {
3843 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3844 XtSetArg(args[j], XtNborderWidth, 0); j++;
3846 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3847 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3848 buttonBar, args, j);
3849 XtAddCallback(button, XtNcallback,
3850 (XtCallbackProc) MenuBarSelect,
3851 (caddr_t) mi->proc);
3858 CreatePieceMenu(name, color)
3865 ChessSquare selection;
3867 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3868 boardWidget, args, 0);
3870 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3871 String item = pieceMenuStrings[color][i];
3873 if (strcmp(item, "----") == 0) {
3874 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3877 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3878 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3880 selection = pieceMenuTranslation[color][i];
3881 XtAddCallback(entry, XtNcallback,
3882 (XtCallbackProc) PieceMenuSelect,
3883 (caddr_t) selection);
3884 if (selection == WhitePawn || selection == BlackPawn) {
3885 XtSetArg(args[0], XtNpopupOnEntry, entry);
3886 XtSetValues(menu, args, 1);
3899 ChessSquare selection;
3901 whitePieceMenu = CreatePieceMenu("menuW", 0);
3902 blackPieceMenu = CreatePieceMenu("menuB", 1);
3904 XtRegisterGrabAction(PieceMenuPopup, True,
3905 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3906 GrabModeAsync, GrabModeAsync);
3908 XtSetArg(args[0], XtNlabel, _("Drop"));
3909 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3910 boardWidget, args, 1);
3911 for (i = 0; i < DROP_MENU_SIZE; i++) {
3912 String item = dropMenuStrings[i];
3914 if (strcmp(item, "----") == 0) {
3915 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3918 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3919 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3921 selection = dropMenuTranslation[i];
3922 XtAddCallback(entry, XtNcallback,
3923 (XtCallbackProc) DropMenuSelect,
3924 (caddr_t) selection);
3929 void SetupDropMenu()
3937 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3938 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3939 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3940 dmEnables[i].piece);
3941 XtSetSensitive(entry, p != NULL || !appData.testLegality
3942 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3943 && !appData.icsActive));
3945 while (p && *p++ == dmEnables[i].piece) count++;
3946 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3948 XtSetArg(args[j], XtNlabel, label); j++;
3949 XtSetValues(entry, args, j);
3953 void PieceMenuPopup(w, event, params, num_params)
3957 Cardinal *num_params;
3959 String whichMenu; int menuNr;
3960 if (event->type == ButtonRelease)
3961 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3962 else if (event->type == ButtonPress)
3963 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3965 case 0: whichMenu = params[0]; break;
3966 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3968 case -1: if (errorUp) ErrorPopDown();
3971 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3974 static void PieceMenuSelect(w, piece, junk)
3979 if (pmFromX < 0 || pmFromY < 0) return;
3980 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3983 static void DropMenuSelect(w, piece, junk)
3988 if (pmFromX < 0 || pmFromY < 0) return;
3989 DropMenuEvent(piece, pmFromX, pmFromY);
3992 void WhiteClock(w, event, prms, nprms)
4001 void BlackClock(w, event, prms, nprms)
4012 * If the user selects on a border boundary, return -1; if off the board,
4013 * return -2. Otherwise map the event coordinate to the square.
4015 int EventToSquare(x, limit)
4023 if ((x % (squareSize + lineGap)) >= squareSize)
4025 x /= (squareSize + lineGap);
4031 static void do_flash_delay(msec)
4037 static void drawHighlight(file, rank, gc)
4043 if (lineGap == 0) return;
4046 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4047 (squareSize + lineGap);
4048 y = lineGap/2 + rank * (squareSize + lineGap);
4050 x = lineGap/2 + file * (squareSize + lineGap);
4051 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4052 (squareSize + lineGap);
4055 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4056 squareSize+lineGap, squareSize+lineGap);
4059 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4060 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4063 SetHighlights(fromX, fromY, toX, toY)
4064 int fromX, fromY, toX, toY;
4066 if (hi1X != fromX || hi1Y != fromY) {
4067 if (hi1X >= 0 && hi1Y >= 0) {
4068 drawHighlight(hi1X, hi1Y, lineGC);
4070 } // [HGM] first erase both, then draw new!
4071 if (hi2X != toX || hi2Y != toY) {
4072 if (hi2X >= 0 && hi2Y >= 0) {
4073 drawHighlight(hi2X, hi2Y, lineGC);
4076 if (hi1X != fromX || hi1Y != fromY) {
4077 if (fromX >= 0 && fromY >= 0) {
4078 drawHighlight(fromX, fromY, highlineGC);
4081 if (hi2X != toX || hi2Y != toY) {
4082 if (toX >= 0 && toY >= 0) {
4083 drawHighlight(toX, toY, highlineGC);
4095 SetHighlights(-1, -1, -1, -1);
4100 SetPremoveHighlights(fromX, fromY, toX, toY)
4101 int fromX, fromY, toX, toY;
4103 if (pm1X != fromX || pm1Y != fromY) {
4104 if (pm1X >= 0 && pm1Y >= 0) {
4105 drawHighlight(pm1X, pm1Y, lineGC);
4107 if (fromX >= 0 && fromY >= 0) {
4108 drawHighlight(fromX, fromY, prelineGC);
4111 if (pm2X != toX || pm2Y != toY) {
4112 if (pm2X >= 0 && pm2Y >= 0) {
4113 drawHighlight(pm2X, pm2Y, lineGC);
4115 if (toX >= 0 && toY >= 0) {
4116 drawHighlight(toX, toY, prelineGC);
4126 ClearPremoveHighlights()
4128 SetPremoveHighlights(-1, -1, -1, -1);
4131 static int CutOutSquare(x, y, x0, y0, kind)
4132 int x, y, *x0, *y0, kind;
4134 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4135 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4137 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4138 if(textureW[kind] < W*squareSize)
4139 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4141 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4142 if(textureH[kind] < H*squareSize)
4143 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4145 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4149 static void BlankSquare(x, y, color, piece, dest, fac)
4150 int x, y, color, fac;
4153 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4155 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4156 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4157 squareSize, squareSize, x*fac, y*fac);
4159 if (useImages && useImageSqs) {
4163 pm = xpmLightSquare;
4168 case 2: /* neutral */
4173 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4174 squareSize, squareSize, x*fac, y*fac);
4184 case 2: /* neutral */
4189 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4194 I split out the routines to draw a piece so that I could
4195 make a generic flash routine.
4197 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4199 int square_color, x, y;
4202 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4203 switch (square_color) {
4205 case 2: /* neutral */
4207 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4208 ? *pieceToOutline(piece)
4209 : *pieceToSolid(piece),
4210 dest, bwPieceGC, 0, 0,
4211 squareSize, squareSize, x, y);
4214 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4215 ? *pieceToSolid(piece)
4216 : *pieceToOutline(piece),
4217 dest, wbPieceGC, 0, 0,
4218 squareSize, squareSize, x, y);
4223 static void monoDrawPiece(piece, square_color, x, y, dest)
4225 int square_color, x, y;
4228 switch (square_color) {
4230 case 2: /* neutral */
4232 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4233 ? *pieceToOutline(piece)
4234 : *pieceToSolid(piece),
4235 dest, bwPieceGC, 0, 0,
4236 squareSize, squareSize, x, y, 1);
4239 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4240 ? *pieceToSolid(piece)
4241 : *pieceToOutline(piece),
4242 dest, wbPieceGC, 0, 0,
4243 squareSize, squareSize, x, y, 1);
4248 static void colorDrawPiece(piece, square_color, x, y, dest)
4250 int square_color, x, y;
4253 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4254 switch (square_color) {
4256 XCopyPlane(xDisplay, *pieceToSolid(piece),
4257 dest, (int) piece < (int) BlackPawn
4258 ? wlPieceGC : blPieceGC, 0, 0,
4259 squareSize, squareSize, x, y, 1);
4262 XCopyPlane(xDisplay, *pieceToSolid(piece),
4263 dest, (int) piece < (int) BlackPawn
4264 ? wdPieceGC : bdPieceGC, 0, 0,
4265 squareSize, squareSize, x, y, 1);
4267 case 2: /* neutral */
4269 XCopyPlane(xDisplay, *pieceToSolid(piece),