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 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
144 #include <X11/Intrinsic.h>
145 #include <X11/StringDefs.h>
146 #include <X11/Shell.h>
147 #include <X11/cursorfont.h>
148 #include <X11/Xatom.h>
149 #include <X11/Xmu/Atoms.h>
151 #include <X11/Xaw3d/Dialog.h>
152 #include <X11/Xaw3d/Form.h>
153 #include <X11/Xaw3d/List.h>
154 #include <X11/Xaw3d/Label.h>
155 #include <X11/Xaw3d/SimpleMenu.h>
156 #include <X11/Xaw3d/SmeBSB.h>
157 #include <X11/Xaw3d/SmeLine.h>
158 #include <X11/Xaw3d/Box.h>
159 #include <X11/Xaw3d/MenuButton.h>
160 #include <X11/Xaw3d/Text.h>
161 #include <X11/Xaw3d/AsciiText.h>
163 #include <X11/Xaw/Dialog.h>
164 #include <X11/Xaw/Form.h>
165 #include <X11/Xaw/List.h>
166 #include <X11/Xaw/Label.h>
167 #include <X11/Xaw/SimpleMenu.h>
168 #include <X11/Xaw/SmeBSB.h>
169 #include <X11/Xaw/SmeLine.h>
170 #include <X11/Xaw/Box.h>
171 #include <X11/Xaw/MenuButton.h>
172 #include <X11/Xaw/Text.h>
173 #include <X11/Xaw/AsciiText.h>
176 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
181 #include "pixmaps/pixmaps.h"
182 #define IMAGE_EXT "xpm"
184 #define IMAGE_EXT "xim"
185 #include "bitmaps/bitmaps.h"
188 #include "bitmaps/icon_white.bm"
189 #include "bitmaps/icon_black.bm"
190 #include "bitmaps/checkmark.bm"
192 #include "frontend.h"
197 #include "xgamelist.h"
198 #include "xhistory.h"
199 #include "xedittags.h"
202 // must be moved to xengineoutput.h
204 void EngineOutputProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
206 void EvalGraphProc P((Widget w, XEvent *event,
207 String *prms, Cardinal *nprms));
214 #define usleep(t) _sleep2(((t)+500)/1000)
218 # define _(s) gettext (s)
219 # define N_(s) gettext_noop (s)
235 int main P((int argc, char **argv));
236 RETSIGTYPE CmailSigHandler P((int sig));
237 RETSIGTYPE IntSigHandler P((int sig));
238 RETSIGTYPE TermSizeSigHandler P((int sig));
239 void CreateGCs P((void));
240 void CreateXIMPieces P((void));
241 void CreateXPMPieces P((void));
242 void CreatePieces P((void));
243 void CreatePieceMenus P((void));
244 Widget CreateMenuBar P((Menu *mb));
245 Widget CreateButtonBar P ((MenuItem *mi));
246 char *FindFont P((char *pattern, int targetPxlSize));
247 void PieceMenuPopup P((Widget w, XEvent *event,
248 String *params, Cardinal *num_params));
249 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
250 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
251 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
252 u_int wreq, u_int hreq));
253 void CreateGrid P((void));
254 int EventToSquare P((int x, int limit));
255 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
256 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
257 void HandleUserMove P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void AnimateUserMove P((Widget w, XEvent * event,
260 String * params, Cardinal * nParams));
261 void HandlePV P((Widget w, XEvent * event,
262 String * params, Cardinal * nParams));
263 void WhiteClock P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void BlackClock P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void DrawPositionProc P((Widget w, XEvent *event,
268 String *prms, Cardinal *nprms));
269 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
271 void CommentPopUp P((char *title, char *label));
272 void CommentPopDown P((void));
273 void CommentCallback P((Widget w, XtPointer client_data,
274 XtPointer call_data));
275 void ICSInputBoxPopUp P((void));
276 void ICSInputBoxPopDown P((void));
277 void FileNamePopUp P((char *label, char *def,
278 FileProc proc, char *openMode));
279 void FileNamePopDown P((void));
280 void FileNameCallback P((Widget w, XtPointer client_data,
281 XtPointer call_data));
282 void FileNameAction P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionReplyAction P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionProc P((Widget w, XEvent *event,
287 String *prms, Cardinal *nprms));
288 void AskQuestionPopDown P((void));
289 void PromotionPopDown P((void));
290 void PromotionCallback P((Widget w, XtPointer client_data,
291 XtPointer call_data));
292 void EditCommentPopDown P((void));
293 void EditCommentCallback P((Widget w, XtPointer client_data,
294 XtPointer call_data));
295 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
296 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
297 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
298 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
302 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
304 void LoadPositionProc P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
308 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
310 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
314 void PastePositionProc P((Widget w, XEvent *event, String *prms,
316 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void SavePositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
324 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
325 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
326 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
328 void MachineWhiteProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void AnalyzeModeProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void AnalyzeFileProc P((Widget w, XEvent *event,
333 String *prms, Cardinal *nprms));
334 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
336 void IcsClientProc P((Widget w, XEvent *event, String *prms,
338 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void EditPositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void EditCommentProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void IcsInputBoxProc P((Widget w, XEvent *event,
345 String *prms, Cardinal *nprms));
346 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void StopObservingProc P((Widget w, XEvent *event, String *prms,
360 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
362 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
369 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
371 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
374 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
376 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
378 void AutocommProc P((Widget w, XEvent *event, String *prms,
380 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void AutobsProc P((Widget w, XEvent *event, String *prms,
384 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
387 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
389 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
392 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
394 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
396 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
400 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
402 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
404 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
406 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
408 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
412 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
414 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
416 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
418 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void DisplayMove P((int moveNumber));
430 void DisplayTitle P((char *title));
431 void ICSInitScript P((void));
432 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
433 void ErrorPopUp P((char *title, char *text, int modal));
434 void ErrorPopDown P((void));
435 static char *ExpandPathName P((char *path));
436 static void CreateAnimVars P((void));
437 static void DragPieceMove P((int x, int y));
438 static void DrawDragPiece P((void));
439 char *ModeToWidgetName P((GameMode mode));
440 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void GameListOptionsPopDown P(());
449 void ShufflePopDown P(());
450 void EnginePopDown P(());
451 void UciPopDown P(());
452 void TimeControlPopDown P(());
453 void NewVariantPopDown P(());
454 void SettingsPopDown P(());
455 void update_ics_width P(());
456 int get_term_width P(());
457 int CopyMemoProc P(());
459 * XBoard depends on Xt R4 or higher
461 int xtVersion = XtSpecificationRelease;
466 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
467 jailSquareColor, highlightSquareColor, premoveHighlightColor;
468 Pixel lowTimeWarningColor;
469 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
470 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
471 wjPieceGC, bjPieceGC, prelineGC, countGC;
472 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
473 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
474 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
475 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
476 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
477 ICSInputShell, fileNameShell, askQuestionShell;
478 Widget historyShell, evalGraphShell, gameListShell;
479 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
480 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
481 Font clockFontID, coordFontID, countFontID;
482 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
483 XtAppContext appContext;
485 char *oldICSInteractionTitle;
489 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
491 Position commentX = -1, commentY = -1;
492 Dimension commentW, commentH;
493 typedef unsigned int BoardSize;
495 Boolean chessProgram;
497 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
498 int squareSize, smallLayout = 0, tinyLayout = 0,
499 marginW, marginH, // [HGM] for run-time resizing
500 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
501 ICSInputBoxUp = False, askQuestionUp = False,
502 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
503 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
504 Pixel timerForegroundPixel, timerBackgroundPixel;
505 Pixel buttonForegroundPixel, buttonBackgroundPixel;
506 char *chessDir, *programName, *programVersion,
507 *gameCopyFilename, *gamePasteFilename;
508 Boolean alwaysOnTop = False;
509 Boolean saveSettingsOnExit;
510 char *settingsFileName;
511 char *icsTextMenuString;
513 char *firstChessProgramNames;
514 char *secondChessProgramNames;
516 WindowPlacement wpMain;
517 WindowPlacement wpConsole;
518 WindowPlacement wpComment;
519 WindowPlacement wpMoveHistory;
520 WindowPlacement wpEvalGraph;
521 WindowPlacement wpEngineOutput;
522 WindowPlacement wpGameList;
523 WindowPlacement wpTags;
527 Pixmap pieceBitmap[2][(int)BlackPawn];
528 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
529 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
530 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
531 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
532 int useImages, useImageSqs;
533 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
534 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
535 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
536 XImage *ximLightSquare, *ximDarkSquare;
539 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
540 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
542 #define White(piece) ((int)(piece) < (int)BlackPawn)
544 /* Variables for doing smooth animation. This whole thing
545 would be much easier if the board was double-buffered,
546 but that would require a fairly major rewrite. */
551 GC blitGC, pieceGC, outlineGC;
552 XPoint startSquare, prevFrame, mouseDelta;
556 int startBoardX, startBoardY;
559 /* There can be two pieces being animated at once: a player
560 can begin dragging a piece before the remote opponent has moved. */
562 static AnimState game, player;
564 /* Bitmaps for use as masks when drawing XPM pieces.
565 Need one for each black and white piece. */
566 static Pixmap xpmMask[BlackKing + 1];
568 /* This magic number is the number of intermediate frames used
569 in each half of the animation. For short moves it's reduced
570 by 1. The total number of frames will be factor * 2 + 1. */
573 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
575 MenuItem fileMenu[] = {
576 {N_("New Game"), ResetProc},
577 {N_("New Shuffle Game ..."), ShuffleMenuProc},
578 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
579 {"----", NothingProc},
580 {N_("Load Game"), LoadGameProc},
581 {N_("Load Next Game"), LoadNextGameProc},
582 {N_("Load Previous Game"), LoadPrevGameProc},
583 {N_("Reload Same Game"), ReloadGameProc},
584 {N_("Save Game"), SaveGameProc},
585 {"----", NothingProc},
586 {N_("Copy Game"), CopyGameProc},
587 {N_("Paste Game"), PasteGameProc},
588 {"----", NothingProc},
589 {N_("Load Position"), LoadPositionProc},
590 {N_("Load Next Position"), LoadNextPositionProc},
591 {N_("Load Previous Position"), LoadPrevPositionProc},
592 {N_("Reload Same Position"), ReloadPositionProc},
593 {N_("Save Position"), SavePositionProc},
594 {"----", NothingProc},
595 {N_("Copy Position"), CopyPositionProc},
596 {N_("Paste Position"), PastePositionProc},
597 {"----", NothingProc},
598 {N_("Mail Move"), MailMoveProc},
599 {N_("Reload CMail Message"), ReloadCmailMsgProc},
600 {"----", NothingProc},
601 {N_("Exit"), QuitProc},
605 MenuItem modeMenu[] = {
606 {N_("Machine White"), MachineWhiteProc},
607 {N_("Machine Black"), MachineBlackProc},
608 {N_("Two Machines"), TwoMachinesProc},
609 {N_("Analysis Mode"), AnalyzeModeProc},
610 {N_("Analyze File"), AnalyzeFileProc },
611 {N_("ICS Client"), IcsClientProc},
612 {N_("Edit Game"), EditGameProc},
613 {N_("Edit Position"), EditPositionProc},
614 {N_("Training"), TrainingProc},
615 {"----", NothingProc},
616 {N_("Show Engine Output"), EngineOutputProc},
617 {N_("Show Evaluation Graph"), EvalGraphProc},
618 {N_("Show Game List"), ShowGameListProc},
619 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
620 {"----", NothingProc},
621 {N_("Edit Tags"), EditTagsProc},
622 {N_("Edit Comment"), EditCommentProc},
623 {N_("ICS Input Box"), IcsInputBoxProc},
624 {N_("Pause"), PauseProc},
628 MenuItem actionMenu[] = {
629 {N_("Accept"), AcceptProc},
630 {N_("Decline"), DeclineProc},
631 {N_("Rematch"), RematchProc},
632 {"----", NothingProc},
633 {N_("Call Flag"), CallFlagProc},
634 {N_("Draw"), DrawProc},
635 {N_("Adjourn"), AdjournProc},
636 {N_("Abort"), AbortProc},
637 {N_("Resign"), ResignProc},
638 {"----", NothingProc},
639 {N_("Stop Observing"), StopObservingProc},
640 {N_("Stop Examining"), StopExaminingProc},
641 {"----", NothingProc},
642 {N_("Adjudicate to White"), AdjuWhiteProc},
643 {N_("Adjudicate to Black"), AdjuBlackProc},
644 {N_("Adjudicate Draw"), AdjuDrawProc},
648 MenuItem stepMenu[] = {
649 {N_("Backward"), BackwardProc},
650 {N_("Forward"), ForwardProc},
651 {N_("Back to Start"), ToStartProc},
652 {N_("Forward to End"), ToEndProc},
653 {N_("Revert"), RevertProc},
654 {N_("Truncate Game"), TruncateGameProc},
655 {"----", NothingProc},
656 {N_("Move Now"), MoveNowProc},
657 {N_("Retract Move"), RetractMoveProc},
661 MenuItem optionsMenu[] = {
662 {N_("Flip View"), FlipViewProc},
663 {"----", NothingProc},
664 {N_("Adjudications ..."), EngineMenuProc},
665 {N_("General Settings ..."), UciMenuProc},
666 {N_("Engine #1 Settings ..."), FirstSettingsProc},
667 {N_("Engine #2 Settings ..."), SecondSettingsProc},
668 {N_("Time Control ..."), TimeControlProc},
669 {N_("Game List ..."), GameListOptionsPopUp},
670 {"----", NothingProc},
671 {N_("Always Queen"), AlwaysQueenProc},
672 {N_("Animate Dragging"), AnimateDraggingProc},
673 {N_("Animate Moving"), AnimateMovingProc},
674 {N_("Auto Comment"), AutocommProc},
675 {N_("Auto Flag"), AutoflagProc},
676 {N_("Auto Flip View"), AutoflipProc},
677 {N_("Auto Observe"), AutobsProc},
678 {N_("Auto Raise Board"), AutoraiseProc},
679 {N_("Auto Save"), AutosaveProc},
680 {N_("Blindfold"), BlindfoldProc},
681 {N_("Flash Moves"), FlashMovesProc},
682 {N_("Get Move List"), GetMoveListProc},
684 {N_("Highlight Dragging"), HighlightDraggingProc},
686 {N_("Highlight Last Move"), HighlightLastMoveProc},
687 {N_("Move Sound"), MoveSoundProc},
688 {N_("ICS Alarm"), IcsAlarmProc},
689 {N_("Old Save Style"), OldSaveStyleProc},
690 {N_("Periodic Updates"), PeriodicUpdatesProc},
691 {N_("Ponder Next Move"), PonderNextMoveProc},
692 {N_("Popup Exit Message"), PopupExitMessageProc},
693 {N_("Popup Move Errors"), PopupMoveErrorsProc},
694 {N_("Premove"), PremoveProc},
695 {N_("Quiet Play"), QuietPlayProc},
696 {N_("Show Coords"), ShowCoordsProc},
697 {N_("Hide Thinking"), HideThinkingProc},
698 {N_("Test Legality"), TestLegalityProc},
699 {"----", NothingProc},
700 {N_("Save Settings Now"), SaveSettingsProc},
701 {N_("Save Settings on Exit"), SaveOnExitProc},
705 MenuItem helpMenu[] = {
706 {N_("Info XBoard"), InfoProc},
707 {N_("Man XBoard"), ManProc},
708 {"----", NothingProc},
709 {N_("Hint"), HintProc},
710 {N_("Book"), BookProc},
711 {"----", NothingProc},
712 {N_("About XBoard"), AboutProc},
717 {N_("File"), fileMenu},
718 {N_("Mode"), modeMenu},
719 {N_("Action"), actionMenu},
720 {N_("Step"), stepMenu},
721 {N_("Options"), optionsMenu},
722 {N_("Help"), helpMenu},
726 #define PAUSE_BUTTON N_("P")
727 MenuItem buttonBar[] = {
730 {PAUSE_BUTTON, PauseProc},
736 #define PIECE_MENU_SIZE 18
737 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
738 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
739 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
740 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
741 N_("Empty square"), N_("Clear board") },
742 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
743 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
744 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
745 N_("Empty square"), N_("Clear board") }
747 /* must be in same order as PieceMenuStrings! */
748 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
749 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
750 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
751 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
752 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
753 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
754 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
755 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
756 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
759 #define DROP_MENU_SIZE 6
760 String dropMenuStrings[DROP_MENU_SIZE] = {
761 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
763 /* must be in same order as PieceMenuStrings! */
764 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
765 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
766 WhiteRook, WhiteQueen
774 DropMenuEnables dmEnables[] = {
792 { XtNborderWidth, 0 },
793 { XtNdefaultDistance, 0 },
797 { XtNborderWidth, 0 },
798 { XtNresizable, (XtArgVal) True },
802 { XtNborderWidth, 0 },
808 { XtNjustify, (XtArgVal) XtJustifyRight },
809 { XtNlabel, (XtArgVal) "..." },
810 { XtNresizable, (XtArgVal) True },
811 { XtNresize, (XtArgVal) False }
814 Arg messageArgs[] = {
815 { XtNjustify, (XtArgVal) XtJustifyLeft },
816 { XtNlabel, (XtArgVal) "..." },
817 { XtNresizable, (XtArgVal) True },
818 { XtNresize, (XtArgVal) False }
822 { XtNborderWidth, 0 },
823 { XtNjustify, (XtArgVal) XtJustifyLeft }
826 XtResource clientResources[] = {
827 { "flashCount", "flashCount", XtRInt, sizeof(int),
828 XtOffset(AppDataPtr, flashCount), XtRImmediate,
829 (XtPointer) FLASH_COUNT },
832 XrmOptionDescRec shellOptions[] = {
833 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
834 { "-flash", "flashCount", XrmoptionNoArg, "3" },
835 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
838 XtActionsRec boardActions[] = {
839 { "DrawPosition", DrawPositionProc },
840 { "HandleUserMove", HandleUserMove },
841 { "AnimateUserMove", AnimateUserMove },
842 { "HandlePV", HandlePV },
843 { "UnLoadPV", UnLoadPV },
844 { "FileNameAction", FileNameAction },
845 { "AskQuestionProc", AskQuestionProc },
846 { "AskQuestionReplyAction", AskQuestionReplyAction },
847 { "PieceMenuPopup", PieceMenuPopup },
848 { "WhiteClock", WhiteClock },
849 { "BlackClock", BlackClock },
850 { "Iconify", Iconify },
851 { "ResetProc", ResetProc },
852 { "LoadGameProc", LoadGameProc },
853 { "LoadNextGameProc", LoadNextGameProc },
854 { "LoadPrevGameProc", LoadPrevGameProc },
855 { "LoadSelectedProc", LoadSelectedProc },
856 { "SetFilterProc", SetFilterProc },
857 { "ReloadGameProc", ReloadGameProc },
858 { "LoadPositionProc", LoadPositionProc },
859 { "LoadNextPositionProc", LoadNextPositionProc },
860 { "LoadPrevPositionProc", LoadPrevPositionProc },
861 { "ReloadPositionProc", ReloadPositionProc },
862 { "CopyPositionProc", CopyPositionProc },
863 { "PastePositionProc", PastePositionProc },
864 { "CopyGameProc", CopyGameProc },
865 { "PasteGameProc", PasteGameProc },
866 { "SaveGameProc", SaveGameProc },
867 { "SavePositionProc", SavePositionProc },
868 { "MailMoveProc", MailMoveProc },
869 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
870 { "QuitProc", QuitProc },
871 { "MachineWhiteProc", MachineWhiteProc },
872 { "MachineBlackProc", MachineBlackProc },
873 { "AnalysisModeProc", AnalyzeModeProc },
874 { "AnalyzeFileProc", AnalyzeFileProc },
875 { "TwoMachinesProc", TwoMachinesProc },
876 { "IcsClientProc", IcsClientProc },
877 { "EditGameProc", EditGameProc },
878 { "EditPositionProc", EditPositionProc },
879 { "TrainingProc", EditPositionProc },
880 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
881 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
882 { "ShowGameListProc", ShowGameListProc },
883 { "ShowMoveListProc", HistoryShowProc},
884 { "EditTagsProc", EditCommentProc },
885 { "EditCommentProc", EditCommentProc },
886 { "IcsAlarmProc", IcsAlarmProc },
887 { "IcsInputBoxProc", IcsInputBoxProc },
888 { "PauseProc", PauseProc },
889 { "AcceptProc", AcceptProc },
890 { "DeclineProc", DeclineProc },
891 { "RematchProc", RematchProc },
892 { "CallFlagProc", CallFlagProc },
893 { "DrawProc", DrawProc },
894 { "AdjournProc", AdjournProc },
895 { "AbortProc", AbortProc },
896 { "ResignProc", ResignProc },
897 { "AdjuWhiteProc", AdjuWhiteProc },
898 { "AdjuBlackProc", AdjuBlackProc },
899 { "AdjuDrawProc", AdjuDrawProc },
900 { "EnterKeyProc", EnterKeyProc },
901 { "StopObservingProc", StopObservingProc },
902 { "StopExaminingProc", StopExaminingProc },
903 { "BackwardProc", BackwardProc },
904 { "ForwardProc", ForwardProc },
905 { "ToStartProc", ToStartProc },
906 { "ToEndProc", ToEndProc },
907 { "RevertProc", RevertProc },
908 { "TruncateGameProc", TruncateGameProc },
909 { "MoveNowProc", MoveNowProc },
910 { "RetractMoveProc", RetractMoveProc },
911 { "AlwaysQueenProc", AlwaysQueenProc },
912 { "AnimateDraggingProc", AnimateDraggingProc },
913 { "AnimateMovingProc", AnimateMovingProc },
914 { "AutoflagProc", AutoflagProc },
915 { "AutoflipProc", AutoflipProc },
916 { "AutobsProc", AutobsProc },
917 { "AutoraiseProc", AutoraiseProc },
918 { "AutosaveProc", AutosaveProc },
919 { "BlindfoldProc", BlindfoldProc },
920 { "FlashMovesProc", FlashMovesProc },
921 { "FlipViewProc", FlipViewProc },
922 { "GetMoveListProc", GetMoveListProc },
924 { "HighlightDraggingProc", HighlightDraggingProc },
926 { "HighlightLastMoveProc", HighlightLastMoveProc },
927 { "IcsAlarmProc", IcsAlarmProc },
928 { "MoveSoundProc", MoveSoundProc },
929 { "OldSaveStyleProc", OldSaveStyleProc },
930 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
931 { "PonderNextMoveProc", PonderNextMoveProc },
932 { "PopupExitMessageProc", PopupExitMessageProc },
933 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
934 { "PremoveProc", PremoveProc },
935 { "QuietPlayProc", QuietPlayProc },
936 { "ShowCoordsProc", ShowCoordsProc },
937 { "ShowThinkingProc", ShowThinkingProc },
938 { "HideThinkingProc", HideThinkingProc },
939 { "TestLegalityProc", TestLegalityProc },
940 { "SaveSettingsProc", SaveSettingsProc },
941 { "SaveOnExitProc", SaveOnExitProc },
942 { "InfoProc", InfoProc },
943 { "ManProc", ManProc },
944 { "HintProc", HintProc },
945 { "BookProc", BookProc },
946 { "AboutGameProc", AboutGameProc },
947 { "AboutProc", AboutProc },
948 { "DebugProc", DebugProc },
949 { "NothingProc", NothingProc },
950 { "CommentPopDown", (XtActionProc) CommentPopDown },
951 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
952 { "TagsPopDown", (XtActionProc) TagsPopDown },
953 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
954 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
955 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
956 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
957 { "GameListPopDown", (XtActionProc) GameListPopDown },
958 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
959 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
960 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
961 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
962 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
963 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
964 { "EnginePopDown", (XtActionProc) EnginePopDown },
965 { "UciPopDown", (XtActionProc) UciPopDown },
966 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
967 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
968 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
969 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
972 char globalTranslations[] =
973 ":<Key>R: ResignProc() \n \
974 :<Key>r: ResetProc() \n \
975 :<Key>g: LoadGameProc() \n \
976 :<Key>N: LoadNextGameProc() \n \
977 :<Key>P: LoadPrevGameProc() \n \
978 :<Key>Q: QuitProc() \n \
979 :<Key>F: ToEndProc() \n \
980 :<Key>f: ForwardProc() \n \
981 :<Key>B: ToStartProc() \n \
982 :<Key>b: BackwardProc() \n \
983 :<Key>p: PauseProc() \n \
984 :<Key>d: DrawProc() \n \
985 :<Key>t: CallFlagProc() \n \
986 :<Key>i: Iconify() \n \
987 :<Key>c: Iconify() \n \
988 :<Key>v: FlipViewProc() \n \
989 <KeyDown>Control_L: BackwardProc() \n \
990 <KeyUp>Control_L: ForwardProc() \n \
991 <KeyDown>Control_R: BackwardProc() \n \
992 <KeyUp>Control_R: ForwardProc() \n \
993 Shift<Key>1: AskQuestionProc(\"Direct command\",\
994 \"Send to chess program:\",,1) \n \
995 Shift<Key>2: AskQuestionProc(\"Direct command\",\
996 \"Send to second chess program:\",,2) \n";
998 char boardTranslations[] =
999 "<Btn1Down>: HandleUserMove() \n \
1000 <Btn1Up>: HandleUserMove() \n \
1001 <Btn1Motion>: AnimateUserMove() \n \
1002 <Btn3Motion>: HandlePV() \n \
1003 <Btn3Up>: PieceMenuPopup(menuB) \n \
1004 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1005 PieceMenuPopup(menuB) \n \
1006 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1007 PieceMenuPopup(menuW) \n \
1008 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1009 PieceMenuPopup(menuW) \n \
1010 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1011 PieceMenuPopup(menuB) \n";
1013 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1014 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1016 char ICSInputTranslations[] =
1017 "<Key>Return: EnterKeyProc() \n";
1019 String xboardResources[] = {
1020 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1021 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1022 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1027 /* Max possible square size */
1028 #define MAXSQSIZE 256
1030 static int xpm_avail[MAXSQSIZE];
1032 #ifdef HAVE_DIR_STRUCT
1034 /* Extract piece size from filename */
1036 xpm_getsize(name, len, ext)
1047 if ((p=strchr(name, '.')) == NULL ||
1048 StrCaseCmp(p+1, ext) != 0)
1054 while (*p && isdigit(*p))
1061 /* Setup xpm_avail */
1063 xpm_getavail(dirname, ext)
1071 for (i=0; i<MAXSQSIZE; ++i)
1074 if (appData.debugMode)
1075 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1077 dir = opendir(dirname);
1080 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1081 programName, dirname);
1085 while ((ent=readdir(dir)) != NULL) {
1086 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1087 if (i > 0 && i < MAXSQSIZE)
1097 xpm_print_avail(fp, ext)
1103 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1104 for (i=1; i<MAXSQSIZE; ++i) {
1110 /* Return XPM piecesize closest to size */
1112 xpm_closest_to(dirname, size, ext)
1118 int sm_diff = MAXSQSIZE;
1122 xpm_getavail(dirname, ext);
1124 if (appData.debugMode)
1125 xpm_print_avail(stderr, ext);
1127 for (i=1; i<MAXSQSIZE; ++i) {
1130 diff = (diff<0) ? -diff : diff;
1131 if (diff < sm_diff) {
1139 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1145 #else /* !HAVE_DIR_STRUCT */
1146 /* If we are on a system without a DIR struct, we can't
1147 read the directory, so we can't collect a list of
1148 filenames, etc., so we can't do any size-fitting. */
1150 xpm_closest_to(dirname, size, ext)
1155 fprintf(stderr, _("\
1156 Warning: No DIR structure found on this system --\n\
1157 Unable to autosize for XPM/XIM pieces.\n\
1158 Please report this error to frankm@hiwaay.net.\n\
1159 Include system type & operating system in message.\n"));
1162 #endif /* HAVE_DIR_STRUCT */
1164 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1165 "magenta", "cyan", "white" };
1169 TextColors textColors[(int)NColorClasses];
1171 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1173 parse_color(str, which)
1177 char *p, buf[100], *d;
1180 if (strlen(str) > 99) /* watch bounds on buf */
1185 for (i=0; i<which; ++i) {
1192 /* Could be looking at something like:
1194 .. in which case we want to stop on a comma also */
1195 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1199 return -1; /* Use default for empty field */
1202 if (which == 2 || isdigit(*p))
1205 while (*p && isalpha(*p))
1210 for (i=0; i<8; ++i) {
1211 if (!StrCaseCmp(buf, cnames[i]))
1212 return which? (i+40) : (i+30);
1214 if (!StrCaseCmp(buf, "default")) return -1;
1216 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1221 parse_cpair(cc, str)
1225 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1226 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1231 /* bg and attr are optional */
1232 textColors[(int)cc].bg = parse_color(str, 1);
1233 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1234 textColors[(int)cc].attr = 0;
1240 /* Arrange to catch delete-window events */
1241 Atom wm_delete_window;
1243 CatchDeleteWindow(Widget w, String procname)
1246 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1247 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1248 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1255 XtSetArg(args[0], XtNiconic, False);
1256 XtSetValues(shellWidget, args, 1);
1258 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1261 //---------------------------------------------------------------------------------------------------------
1262 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1265 #define CW_USEDEFAULT (1<<31)
1266 #define ICS_TEXT_MENU_SIZE 90
1267 #define DEBUG_FILE "xboard.debug"
1268 #define SetCurrentDirectory chdir
1269 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1273 // these two must some day move to frontend.h, when they are implemented
1274 Boolean GameListIsUp();
1276 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1279 // front-end part of option handling
1281 // [HGM] This platform-dependent table provides the location for storing the color info
1282 extern char *crWhite, * crBlack;
1286 &appData.whitePieceColor,
1287 &appData.blackPieceColor,
1288 &appData.lightSquareColor,
1289 &appData.darkSquareColor,
1290 &appData.highlightSquareColor,
1291 &appData.premoveHighlightColor,
1292 &appData.lowTimeWarningColor,
1303 // [HGM] font: keep a font for each square size, even non-stndard ones
1304 #define NUM_SIZES 18
1305 #define MAX_SIZE 130
1306 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1307 char *fontTable[NUM_FONTS][MAX_SIZE];
1310 ParseFont(char *name, int number)
1311 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1313 if(sscanf(name, "size%d:", &size)) {
1314 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1315 // defer processing it until we know if it matches our board size
1316 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1317 fontTable[number][size] = strdup(strchr(name, ':')+1);
1318 fontValid[number][size] = True;
1323 case 0: // CLOCK_FONT
1324 appData.clockFont = strdup(name);
1326 case 1: // MESSAGE_FONT
1327 appData.font = strdup(name);
1329 case 2: // COORD_FONT
1330 appData.coordFont = strdup(name);
1335 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1340 { // only 2 fonts currently
1341 appData.clockFont = CLOCK_FONT_NAME;
1342 appData.coordFont = COORD_FONT_NAME;
1343 appData.font = DEFAULT_FONT_NAME;
1348 { // no-op, until we identify the code for this already in XBoard and move it here
1352 ParseColor(int n, char *name)
1353 { // in XBoard, just copy the color-name string
1354 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1358 ParseTextAttribs(ColorClass cc, char *s)
1360 (&appData.colorShout)[cc] = strdup(s);
1364 ParseBoardSize(void *addr, char *name)
1366 appData.boardSize = strdup(name);
1371 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1375 SetCommPortDefaults()
1376 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1379 // [HGM] args: these three cases taken out to stay in front-end
1381 SaveFontArg(FILE *f, ArgDescriptor *ad)
1383 char *name, buf[MSG_SIZ];
1384 int i, n = (int)ad->argLoc;
1386 case 0: // CLOCK_FONT
1387 name = appData.clockFont;
1389 case 1: // MESSAGE_FONT
1390 name = appData.font;
1392 case 2: // COORD_FONT
1393 name = appData.coordFont;
1398 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1399 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1400 fontTable[n][squareSize] = strdup(name);
1401 fontValid[n][squareSize] = True;
1404 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1405 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1410 { // nothing to do, as the sounds are at all times represented by their text-string names already
1414 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1415 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1416 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1420 SaveColor(FILE *f, ArgDescriptor *ad)
1421 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1422 if(colorVariable[(int)ad->argLoc])
1423 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1427 SaveBoardSize(FILE *f, char *name, void *addr)
1428 { // wrapper to shield back-end from BoardSize & sizeInfo
1429 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1433 ParseCommPortSettings(char *s)
1434 { // no such option in XBoard (yet)
1437 extern Widget engineOutputShell;
1438 extern Widget tagsShell, editTagsShell;
1440 GetActualPlacement(Widget wg, WindowPlacement *wp)
1450 XtSetArg(args[i], XtNx, &x); i++;
1451 XtSetArg(args[i], XtNy, &y); i++;
1452 XtSetArg(args[i], XtNwidth, &w); i++;
1453 XtSetArg(args[i], XtNheight, &h); i++;
1454 XtGetValues(wg, args, i);
1463 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1464 // In XBoard this will have to wait until awareness of window parameters is implemented
1465 GetActualPlacement(shellWidget, &wpMain);
1466 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1467 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1468 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1469 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1470 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1471 else GetActualPlacement(editShell, &wpComment);
1472 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1473 else GetActualPlacement(editTagsShell, &wpTags);
1477 PrintCommPortSettings(FILE *f, char *name)
1478 { // This option does not exist in XBoard
1482 MySearchPath(char *installDir, char *name, char *fullname)
1483 { // just append installDir and name. Perhaps ExpandPath should be used here?
1484 name = ExpandPathName(name);
1485 if(name && name[0] == '/') strcpy(fullname, name); else {
1486 sprintf(fullname, "%s%c%s", installDir, '/', name);
1492 MyGetFullPathName(char *name, char *fullname)
1493 { // should use ExpandPath?
1494 name = ExpandPathName(name);
1495 strcpy(fullname, name);
1500 EnsureOnScreen(int *x, int *y, int minX, int minY)
1507 { // [HGM] args: allows testing if main window is realized from back-end
1508 return xBoardWindow != 0;
1512 PopUpStartupDialog()
1513 { // start menu not implemented in XBoard
1516 ConvertToLine(int argc, char **argv)
1518 static char line[128*1024], buf[1024];
1522 for(i=1; i<argc; i++) {
1523 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1524 && argv[i][0] != '{' )
1525 sprintf(buf, "{%s} ", argv[i]);
1526 else sprintf(buf, "%s ", argv[i]);
1529 line[strlen(line)-1] = NULLCHAR;
1533 //--------------------------------------------------------------------------------------------
1536 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1538 #define BoardSize int
1539 void InitDrawingSizes(BoardSize boardSize, int flags)
1540 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1541 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1543 XtGeometryResult gres;
1546 if(!formWidget) return;
1549 * Enable shell resizing.
1551 shellArgs[0].value = (XtArgVal) &w;
1552 shellArgs[1].value = (XtArgVal) &h;
1553 XtGetValues(shellWidget, shellArgs, 2);
1555 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1556 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1557 XtSetValues(shellWidget, &shellArgs[2], 4);
1559 XtSetArg(args[0], XtNdefaultDistance, &sep);
1560 XtGetValues(formWidget, args, 1);
1562 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1563 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1566 XtSetArg(args[0], XtNwidth, boardWidth);
1567 XtSetArg(args[1], XtNheight, boardHeight);
1568 XtSetValues(boardWidget, args, 2);
1570 timerWidth = (boardWidth - sep) / 2;
1571 XtSetArg(args[0], XtNwidth, timerWidth);
1572 XtSetValues(whiteTimerWidget, args, 1);
1573 XtSetValues(blackTimerWidget, args, 1);
1575 XawFormDoLayout(formWidget, False);
1577 if (appData.titleInWindow) {
1579 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1580 XtSetArg(args[i], XtNheight, &h); i++;
1581 XtGetValues(titleWidget, args, i);
1583 w = boardWidth - 2*bor;
1585 XtSetArg(args[0], XtNwidth, &w);
1586 XtGetValues(menuBarWidget, args, 1);
1587 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1590 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1591 if (gres != XtGeometryYes && appData.debugMode) {
1593 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1594 programName, gres, w, h, wr, hr);
1598 XawFormDoLayout(formWidget, True);
1601 * Inhibit shell resizing.
1603 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1604 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1605 shellArgs[4].value = shellArgs[2].value = w;
1606 shellArgs[5].value = shellArgs[3].value = h;
1607 XtSetValues(shellWidget, &shellArgs[0], 6);
1609 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1612 for(i=0; i<4; i++) {
1614 for(p=0; p<=(int)WhiteKing; p++)
1615 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1616 if(gameInfo.variant == VariantShogi) {
1617 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1618 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1619 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1620 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1621 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1624 if(gameInfo.variant == VariantGothic) {
1625 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1629 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1630 for(p=0; p<=(int)WhiteKing; p++)
1631 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1632 if(gameInfo.variant == VariantShogi) {
1633 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1634 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1635 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1636 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1637 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1640 if(gameInfo.variant == VariantGothic) {
1641 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1647 for(i=0; i<2; i++) {
1649 for(p=0; p<=(int)WhiteKing; p++)
1650 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1651 if(gameInfo.variant == VariantShogi) {
1652 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1653 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1654 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1655 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1656 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1659 if(gameInfo.variant == VariantGothic) {
1660 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1671 void EscapeExpand(char *p, char *q)
1672 { // [HGM] initstring: routine to shape up string arguments
1673 while(*p++ = *q++) if(p[-1] == '\\')
1675 case 'n': p[-1] = '\n'; break;
1676 case 'r': p[-1] = '\r'; break;
1677 case 't': p[-1] = '\t'; break;
1678 case '\\': p[-1] = '\\'; break;
1679 case 0: *p = 0; return;
1680 default: p[-1] = q[-1]; break;
1689 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1690 XSetWindowAttributes window_attributes;
1692 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1693 XrmValue vFrom, vTo;
1694 XtGeometryResult gres;
1697 int forceMono = False;
1699 srandom(time(0)); // [HGM] book: make random truly random
1701 setbuf(stdout, NULL);
1702 setbuf(stderr, NULL);
1705 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1706 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1710 programName = strrchr(argv[0], '/');
1711 if (programName == NULL)
1712 programName = argv[0];
1717 XtSetLanguageProc(NULL, NULL, NULL);
1718 bindtextdomain(PACKAGE, LOCALEDIR);
1719 textdomain(PACKAGE);
1723 XtAppInitialize(&appContext, "XBoard", shellOptions,
1724 XtNumber(shellOptions),
1725 &argc, argv, xboardResources, NULL, 0);
1726 appData.boardSize = "";
1727 InitAppData(ConvertToLine(argc, argv));
1729 if (p == NULL) p = "/tmp";
1730 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1731 gameCopyFilename = (char*) malloc(i);
1732 gamePasteFilename = (char*) malloc(i);
1733 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1734 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1736 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1737 clientResources, XtNumber(clientResources),
1740 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1741 static char buf[MSG_SIZ];
1742 EscapeExpand(buf, appData.initString);
1743 appData.initString = strdup(buf);
1744 EscapeExpand(buf, appData.secondInitString);
1745 appData.secondInitString = strdup(buf);
1746 EscapeExpand(buf, appData.firstComputerString);
1747 appData.firstComputerString = strdup(buf);
1748 EscapeExpand(buf, appData.secondComputerString);
1749 appData.secondComputerString = strdup(buf);
1752 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1755 if (chdir(chessDir) != 0) {
1756 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1762 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1763 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1764 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1765 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1768 setbuf(debugFP, NULL);
1771 /* [HGM,HR] make sure board size is acceptable */
1772 if(appData.NrFiles > BOARD_FILES ||
1773 appData.NrRanks > BOARD_RANKS )
1774 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1777 /* This feature does not work; animation needs a rewrite */
1778 appData.highlightDragging = FALSE;
1782 xDisplay = XtDisplay(shellWidget);
1783 xScreen = DefaultScreen(xDisplay);
1784 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1786 gameInfo.variant = StringToVariant(appData.variant);
1787 InitPosition(FALSE);
1790 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1792 if (isdigit(appData.boardSize[0])) {
1793 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1794 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1795 &fontPxlSize, &smallLayout, &tinyLayout);
1797 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1798 programName, appData.boardSize);
1802 /* Find some defaults; use the nearest known size */
1803 SizeDefaults *szd, *nearest;
1804 int distance = 99999;
1805 nearest = szd = sizeDefaults;
1806 while (szd->name != NULL) {
1807 if (abs(szd->squareSize - squareSize) < distance) {
1809 distance = abs(szd->squareSize - squareSize);
1810 if (distance == 0) break;
1814 if (i < 2) lineGap = nearest->lineGap;
1815 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1816 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1817 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1818 if (i < 6) smallLayout = nearest->smallLayout;
1819 if (i < 7) tinyLayout = nearest->tinyLayout;
1822 SizeDefaults *szd = sizeDefaults;
1823 if (*appData.boardSize == NULLCHAR) {
1824 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1825 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1828 if (szd->name == NULL) szd--;
1829 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1831 while (szd->name != NULL &&
1832 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1833 if (szd->name == NULL) {
1834 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1835 programName, appData.boardSize);
1839 squareSize = szd->squareSize;
1840 lineGap = szd->lineGap;
1841 clockFontPxlSize = szd->clockFontPxlSize;
1842 coordFontPxlSize = szd->coordFontPxlSize;
1843 fontPxlSize = szd->fontPxlSize;
1844 smallLayout = szd->smallLayout;
1845 tinyLayout = szd->tinyLayout;
1846 // [HGM] font: use defaults from settings file if available and not overruled
1848 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1849 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1850 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1851 appData.font = fontTable[MESSAGE_FONT][squareSize];
1852 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1853 appData.coordFont = fontTable[COORD_FONT][squareSize];
1855 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1856 if (strlen(appData.pixmapDirectory) > 0) {
1857 p = ExpandPathName(appData.pixmapDirectory);
1859 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1860 appData.pixmapDirectory);
1863 if (appData.debugMode) {
1864 fprintf(stderr, _("\
1865 XBoard square size (hint): %d\n\
1866 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1868 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1869 if (appData.debugMode) {
1870 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1874 /* [HR] height treated separately (hacked) */
1875 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1876 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1877 if (appData.showJail == 1) {
1878 /* Jail on top and bottom */
1879 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1880 XtSetArg(boardArgs[2], XtNheight,
1881 boardHeight + 2*(lineGap + squareSize));
1882 } else if (appData.showJail == 2) {
1884 XtSetArg(boardArgs[1], XtNwidth,
1885 boardWidth + 2*(lineGap + squareSize));
1886 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1889 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1890 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1894 * Determine what fonts to use.
1896 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1897 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1898 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1899 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1900 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1901 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1902 appData.font = FindFont(appData.font, fontPxlSize);
1903 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1904 countFontStruct = XQueryFont(xDisplay, countFontID);
1905 // appData.font = FindFont(appData.font, fontPxlSize);
1907 xdb = XtDatabase(xDisplay);
1908 XrmPutStringResource(&xdb, "*font", appData.font);
1911 * Detect if there are not enough colors available and adapt.
1913 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1914 appData.monoMode = True;
1917 if (!appData.monoMode) {
1918 vFrom.addr = (caddr_t) appData.lightSquareColor;
1919 vFrom.size = strlen(appData.lightSquareColor);
1920 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1921 if (vTo.addr == NULL) {
1922 appData.monoMode = True;
1925 lightSquareColor = *(Pixel *) vTo.addr;
1928 if (!appData.monoMode) {
1929 vFrom.addr = (caddr_t) appData.darkSquareColor;
1930 vFrom.size = strlen(appData.darkSquareColor);
1931 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1932 if (vTo.addr == NULL) {
1933 appData.monoMode = True;
1936 darkSquareColor = *(Pixel *) vTo.addr;
1939 if (!appData.monoMode) {
1940 vFrom.addr = (caddr_t) appData.whitePieceColor;
1941 vFrom.size = strlen(appData.whitePieceColor);
1942 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1943 if (vTo.addr == NULL) {
1944 appData.monoMode = True;
1947 whitePieceColor = *(Pixel *) vTo.addr;
1950 if (!appData.monoMode) {
1951 vFrom.addr = (caddr_t) appData.blackPieceColor;
1952 vFrom.size = strlen(appData.blackPieceColor);
1953 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1954 if (vTo.addr == NULL) {
1955 appData.monoMode = True;
1958 blackPieceColor = *(Pixel *) vTo.addr;
1962 if (!appData.monoMode) {
1963 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1964 vFrom.size = strlen(appData.highlightSquareColor);
1965 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1966 if (vTo.addr == NULL) {
1967 appData.monoMode = True;
1970 highlightSquareColor = *(Pixel *) vTo.addr;
1974 if (!appData.monoMode) {
1975 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1976 vFrom.size = strlen(appData.premoveHighlightColor);
1977 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1978 if (vTo.addr == NULL) {
1979 appData.monoMode = True;
1982 premoveHighlightColor = *(Pixel *) vTo.addr;
1987 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1990 if (appData.bitmapDirectory == NULL ||
1991 appData.bitmapDirectory[0] == NULLCHAR)
1992 appData.bitmapDirectory = DEF_BITMAP_DIR;
1995 if (appData.lowTimeWarning && !appData.monoMode) {
1996 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1997 vFrom.size = strlen(appData.lowTimeWarningColor);
1998 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1999 if (vTo.addr == NULL)
2000 appData.monoMode = True;
2002 lowTimeWarningColor = *(Pixel *) vTo.addr;
2005 if (appData.monoMode && appData.debugMode) {
2006 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2007 (unsigned long) XWhitePixel(xDisplay, xScreen),
2008 (unsigned long) XBlackPixel(xDisplay, xScreen));
2011 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2012 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2013 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2014 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2015 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2016 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2017 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2018 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2019 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2020 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2022 if (appData.colorize) {
2024 _("%s: can't parse color names; disabling colorization\n"),
2027 appData.colorize = FALSE;
2029 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2030 textColors[ColorNone].attr = 0;
2032 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2038 layoutName = "tinyLayout";
2039 } else if (smallLayout) {
2040 layoutName = "smallLayout";
2042 layoutName = "normalLayout";
2044 /* Outer layoutWidget is there only to provide a name for use in
2045 resources that depend on the layout style */
2047 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2048 layoutArgs, XtNumber(layoutArgs));
2050 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2051 formArgs, XtNumber(formArgs));
2052 XtSetArg(args[0], XtNdefaultDistance, &sep);
2053 XtGetValues(formWidget, args, 1);
2056 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2057 XtSetArg(args[0], XtNtop, XtChainTop);
2058 XtSetArg(args[1], XtNbottom, XtChainTop);
2059 XtSetArg(args[2], XtNright, XtChainLeft);
2060 XtSetValues(menuBarWidget, args, 3);
2062 widgetList[j++] = whiteTimerWidget =
2063 XtCreateWidget("whiteTime", labelWidgetClass,
2064 formWidget, timerArgs, XtNumber(timerArgs));
2065 XtSetArg(args[0], XtNfont, clockFontStruct);
2066 XtSetArg(args[1], XtNtop, XtChainTop);
2067 XtSetArg(args[2], XtNbottom, XtChainTop);
2068 XtSetValues(whiteTimerWidget, args, 3);
2070 widgetList[j++] = blackTimerWidget =
2071 XtCreateWidget("blackTime", labelWidgetClass,
2072 formWidget, timerArgs, XtNumber(timerArgs));
2073 XtSetArg(args[0], XtNfont, clockFontStruct);
2074 XtSetArg(args[1], XtNtop, XtChainTop);
2075 XtSetArg(args[2], XtNbottom, XtChainTop);
2076 XtSetValues(blackTimerWidget, args, 3);
2078 if (appData.titleInWindow) {
2079 widgetList[j++] = titleWidget =
2080 XtCreateWidget("title", labelWidgetClass, formWidget,
2081 titleArgs, XtNumber(titleArgs));
2082 XtSetArg(args[0], XtNtop, XtChainTop);
2083 XtSetArg(args[1], XtNbottom, XtChainTop);
2084 XtSetValues(titleWidget, args, 2);
2087 if (appData.showButtonBar) {
2088 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2089 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2090 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2091 XtSetArg(args[2], XtNtop, XtChainTop);
2092 XtSetArg(args[3], XtNbottom, XtChainTop);
2093 XtSetValues(buttonBarWidget, args, 4);
2096 widgetList[j++] = messageWidget =
2097 XtCreateWidget("message", labelWidgetClass, formWidget,
2098 messageArgs, XtNumber(messageArgs));
2099 XtSetArg(args[0], XtNtop, XtChainTop);
2100 XtSetArg(args[1], XtNbottom, XtChainTop);
2101 XtSetValues(messageWidget, args, 2);
2103 widgetList[j++] = boardWidget =
2104 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2105 XtNumber(boardArgs));
2107 XtManageChildren(widgetList, j);
2109 timerWidth = (boardWidth - sep) / 2;
2110 XtSetArg(args[0], XtNwidth, timerWidth);
2111 XtSetValues(whiteTimerWidget, args, 1);
2112 XtSetValues(blackTimerWidget, args, 1);
2114 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2115 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2116 XtGetValues(whiteTimerWidget, args, 2);
2118 if (appData.showButtonBar) {
2119 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2120 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2121 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2125 * formWidget uses these constraints but they are stored
2129 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2130 XtSetValues(menuBarWidget, args, i);
2131 if (appData.titleInWindow) {
2134 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2135 XtSetValues(whiteTimerWidget, args, i);
2137 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2138 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2139 XtSetValues(blackTimerWidget, args, i);
2141 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2142 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2143 XtSetValues(titleWidget, args, i);
2145 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2146 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2147 XtSetValues(messageWidget, args, i);
2148 if (appData.showButtonBar) {
2150 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2151 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2152 XtSetValues(buttonBarWidget, args, i);
2156 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2157 XtSetValues(whiteTimerWidget, args, i);
2159 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2160 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2161 XtSetValues(blackTimerWidget, args, i);
2163 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2164 XtSetValues(titleWidget, args, i);
2166 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2167 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2168 XtSetValues(messageWidget, args, i);
2169 if (appData.showButtonBar) {
2171 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2172 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2173 XtSetValues(buttonBarWidget, args, i);
2178 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2179 XtSetValues(whiteTimerWidget, args, i);
2181 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2182 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2183 XtSetValues(blackTimerWidget, args, i);
2185 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2186 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2187 XtSetValues(messageWidget, args, i);
2188 if (appData.showButtonBar) {
2190 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2191 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2192 XtSetValues(buttonBarWidget, args, i);
2196 XtSetArg(args[0], XtNfromVert, messageWidget);
2197 XtSetArg(args[1], XtNtop, XtChainTop);
2198 XtSetArg(args[2], XtNbottom, XtChainBottom);
2199 XtSetArg(args[3], XtNleft, XtChainLeft);
2200 XtSetArg(args[4], XtNright, XtChainRight);
2201 XtSetValues(boardWidget, args, 5);
2203 XtRealizeWidget(shellWidget);
2206 XtSetArg(args[0], XtNx, wpMain.x);
2207 XtSetArg(args[1], XtNy, wpMain.y);
2208 XtSetValues(shellWidget, args, 2);
2212 * Correct the width of the message and title widgets.
2213 * It is not known why some systems need the extra fudge term.
2214 * The value "2" is probably larger than needed.
2216 XawFormDoLayout(formWidget, False);
2218 #define WIDTH_FUDGE 2
2220 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2221 XtSetArg(args[i], XtNheight, &h); i++;
2222 XtGetValues(messageWidget, args, i);
2223 if (appData.showButtonBar) {
2225 XtSetArg(args[i], XtNwidth, &w); i++;
2226 XtGetValues(buttonBarWidget, args, i);
2227 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2229 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2232 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2233 if (gres != XtGeometryYes && appData.debugMode) {
2234 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2235 programName, gres, w, h, wr, hr);
2238 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2239 /* The size used for the child widget in layout lags one resize behind
2240 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2242 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2243 if (gres != XtGeometryYes && appData.debugMode) {
2244 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2245 programName, gres, w, h, wr, hr);
2248 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2249 XtSetArg(args[1], XtNright, XtChainRight);
2250 XtSetValues(messageWidget, args, 2);
2252 if (appData.titleInWindow) {
2254 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2255 XtSetArg(args[i], XtNheight, &h); i++;
2256 XtGetValues(titleWidget, args, i);
2258 w = boardWidth - 2*bor;
2260 XtSetArg(args[0], XtNwidth, &w);
2261 XtGetValues(menuBarWidget, args, 1);
2262 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2265 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2266 if (gres != XtGeometryYes && appData.debugMode) {
2268 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2269 programName, gres, w, h, wr, hr);
2272 XawFormDoLayout(formWidget, True);
2274 xBoardWindow = XtWindow(boardWidget);
2276 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2277 // not need to go into InitDrawingSizes().
2281 * Create X checkmark bitmap and initialize option menu checks.
2283 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2284 checkmark_bits, checkmark_width, checkmark_height);
2285 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2286 if (appData.alwaysPromoteToQueen) {
2287 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2290 if (appData.animateDragging) {
2291 XtSetValues(XtNameToWidget(menuBarWidget,
2292 "menuOptions.Animate Dragging"),
2295 if (appData.animate) {
2296 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2299 if (appData.autoComment) {
2300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2303 if (appData.autoCallFlag) {
2304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2307 if (appData.autoFlipView) {
2308 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2311 if (appData.autoObserve) {
2312 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2315 if (appData.autoRaiseBoard) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,
2317 "menuOptions.Auto Raise Board"), args, 1);
2319 if (appData.autoSaveGames) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2323 if (appData.saveGameFile[0] != NULLCHAR) {
2324 /* Can't turn this off from menu */
2325 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2327 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2331 if (appData.blindfold) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Blindfold"), args, 1);
2335 if (appData.flashCount > 0) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Flash Moves"),
2340 if (appData.getMoveList) {
2341 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2345 if (appData.highlightDragging) {
2346 XtSetValues(XtNameToWidget(menuBarWidget,
2347 "menuOptions.Highlight Dragging"),
2351 if (appData.highlightLastMove) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,
2353 "menuOptions.Highlight Last Move"),
2356 if (appData.icsAlarm) {
2357 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2360 if (appData.ringBellAfterMoves) {
2361 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2364 if (appData.oldSaveStyle) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Old Save Style"), args, 1);
2368 if (appData.periodicUpdates) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Periodic Updates"), args, 1);
2372 if (appData.ponderNextMove) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Ponder Next Move"), args, 1);
2376 if (appData.popupExitMessage) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,
2378 "menuOptions.Popup Exit Message"), args, 1);
2380 if (appData.popupMoveErrors) {
2381 XtSetValues(XtNameToWidget(menuBarWidget,
2382 "menuOptions.Popup Move Errors"), args, 1);
2384 if (appData.premove) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,
2386 "menuOptions.Premove"), args, 1);
2388 if (appData.quietPlay) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,
2390 "menuOptions.Quiet Play"), args, 1);
2392 if (appData.showCoords) {
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2396 if (appData.hideThinkingFromHuman) {
2397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2400 if (appData.testLegality) {
2401 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2404 if (saveSettingsOnExit) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2412 ReadBitmap(&wIconPixmap, "icon_white.bm",
2413 icon_white_bits, icon_white_width, icon_white_height);
2414 ReadBitmap(&bIconPixmap, "icon_black.bm",
2415 icon_black_bits, icon_black_width, icon_black_height);
2416 iconPixmap = wIconPixmap;
2418 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2419 XtSetValues(shellWidget, args, i);
2422 * Create a cursor for the board widget.
2424 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2425 XChangeWindowAttributes(xDisplay, xBoardWindow,
2426 CWCursor, &window_attributes);
2429 * Inhibit shell resizing.
2431 shellArgs[0].value = (XtArgVal) &w;
2432 shellArgs[1].value = (XtArgVal) &h;
2433 XtGetValues(shellWidget, shellArgs, 2);
2434 shellArgs[4].value = shellArgs[2].value = w;
2435 shellArgs[5].value = shellArgs[3].value = h;
2436 XtSetValues(shellWidget, &shellArgs[2], 4);
2437 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2438 marginH = h - boardHeight;
2440 CatchDeleteWindow(shellWidget, "QuitProc");
2445 if (appData.bitmapDirectory[0] != NULLCHAR) {
2452 /* Create regular pieces */
2453 if (!useImages) CreatePieces();
2458 if (appData.animate || appData.animateDragging)
2461 XtAugmentTranslations(formWidget,
2462 XtParseTranslationTable(globalTranslations));
2463 XtAugmentTranslations(boardWidget,
2464 XtParseTranslationTable(boardTranslations));
2465 XtAugmentTranslations(whiteTimerWidget,
2466 XtParseTranslationTable(whiteTranslations));
2467 XtAugmentTranslations(blackTimerWidget,
2468 XtParseTranslationTable(blackTranslations));
2470 /* Why is the following needed on some versions of X instead
2471 * of a translation? */
2472 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2473 (XtEventHandler) EventProc, NULL);
2476 /* [AS] Restore layout */
2477 if( wpMoveHistory.visible ) {
2481 if( wpEvalGraph.visible )
2486 if( wpEngineOutput.visible ) {
2487 EngineOutputPopUp();
2492 if (errorExitStatus == -1) {
2493 if (appData.icsActive) {
2494 /* We now wait until we see "login:" from the ICS before
2495 sending the logon script (problems with timestamp otherwise) */
2496 /*ICSInitScript();*/
2497 if (appData.icsInputBox) ICSInputBoxPopUp();
2501 signal(SIGWINCH, TermSizeSigHandler);
2503 signal(SIGINT, IntSigHandler);
2504 signal(SIGTERM, IntSigHandler);
2505 if (*appData.cmailGameName != NULLCHAR) {
2506 signal(SIGUSR1, CmailSigHandler);
2509 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2512 XtAppMainLoop(appContext);
2513 if (appData.debugMode) fclose(debugFP); // [DM] debug
2520 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2521 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2523 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2524 unlink(gameCopyFilename);
2525 unlink(gamePasteFilename);
2528 RETSIGTYPE TermSizeSigHandler(int sig)
2541 CmailSigHandler(sig)
2547 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2549 /* Activate call-back function CmailSigHandlerCallBack() */
2550 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2552 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2556 CmailSigHandlerCallBack(isr, closure, message, count, error)
2564 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2566 /**** end signal code ****/
2576 f = fopen(appData.icsLogon, "r");
2582 strcat(buf, appData.icsLogon);
2583 f = fopen(buf, "r");
2587 ProcessICSInitScript(f);
2594 EditCommentPopDown();
2609 if (!menuBarWidget) return;
2610 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2612 DisplayError("menuStep.Revert", 0);
2614 XtSetSensitive(w, !grey);
2619 SetMenuEnables(enab)
2623 if (!menuBarWidget) return;
2624 while (enab->name != NULL) {
2625 w = XtNameToWidget(menuBarWidget, enab->name);
2627 DisplayError(enab->name, 0);
2629 XtSetSensitive(w, enab->value);
2635 Enables icsEnables[] = {
2636 { "menuFile.Mail Move", False },
2637 { "menuFile.Reload CMail Message", False },
2638 { "menuMode.Machine Black", False },
2639 { "menuMode.Machine White", False },
2640 { "menuMode.Analysis Mode", False },
2641 { "menuMode.Analyze File", False },
2642 { "menuMode.Two Machines", False },
2644 { "menuHelp.Hint", False },
2645 { "menuHelp.Book", False },
2646 { "menuStep.Move Now", False },
2647 { "menuOptions.Periodic Updates", False },
2648 { "menuOptions.Hide Thinking", False },
2649 { "menuOptions.Ponder Next Move", False },
2654 Enables ncpEnables[] = {
2655 { "menuFile.Mail Move", False },
2656 { "menuFile.Reload CMail Message", False },
2657 { "menuMode.Machine White", False },
2658 { "menuMode.Machine Black", False },
2659 { "menuMode.Analysis Mode", False },
2660 { "menuMode.Analyze File", False },
2661 { "menuMode.Two Machines", False },
2662 { "menuMode.ICS Client", False },
2663 { "menuMode.ICS Input Box", False },
2664 { "Action", False },
2665 { "menuStep.Revert", False },
2666 { "menuStep.Move Now", False },
2667 { "menuStep.Retract Move", False },
2668 { "menuOptions.Auto Comment", False },
2669 { "menuOptions.Auto Flag", False },
2670 { "menuOptions.Auto Flip View", False },
2671 { "menuOptions.Auto Observe", False },
2672 { "menuOptions.Auto Raise Board", False },
2673 { "menuOptions.Get Move List", False },
2674 { "menuOptions.ICS Alarm", False },
2675 { "menuOptions.Move Sound", False },
2676 { "menuOptions.Quiet Play", False },
2677 { "menuOptions.Hide Thinking", False },
2678 { "menuOptions.Periodic Updates", False },
2679 { "menuOptions.Ponder Next Move", False },
2680 { "menuHelp.Hint", False },
2681 { "menuHelp.Book", False },
2685 Enables gnuEnables[] = {
2686 { "menuMode.ICS Client", False },
2687 { "menuMode.ICS Input Box", False },
2688 { "menuAction.Accept", False },
2689 { "menuAction.Decline", False },
2690 { "menuAction.Rematch", False },
2691 { "menuAction.Adjourn", False },
2692 { "menuAction.Stop Examining", False },
2693 { "menuAction.Stop Observing", False },
2694 { "menuStep.Revert", False },
2695 { "menuOptions.Auto Comment", False },
2696 { "menuOptions.Auto Observe", False },
2697 { "menuOptions.Auto Raise Board", False },
2698 { "menuOptions.Get Move List", False },
2699 { "menuOptions.Premove", False },
2700 { "menuOptions.Quiet Play", False },
2702 /* The next two options rely on SetCmailMode being called *after* */
2703 /* SetGNUMode so that when GNU is being used to give hints these */
2704 /* menu options are still available */
2706 { "menuFile.Mail Move", False },
2707 { "menuFile.Reload CMail Message", False },
2711 Enables cmailEnables[] = {
2713 { "menuAction.Call Flag", False },
2714 { "menuAction.Draw", True },
2715 { "menuAction.Adjourn", False },
2716 { "menuAction.Abort", False },
2717 { "menuAction.Stop Observing", False },
2718 { "menuAction.Stop Examining", False },
2719 { "menuFile.Mail Move", True },
2720 { "menuFile.Reload CMail Message", True },
2724 Enables trainingOnEnables[] = {
2725 { "menuMode.Edit Comment", False },
2726 { "menuMode.Pause", False },
2727 { "menuStep.Forward", False },
2728 { "menuStep.Backward", False },
2729 { "menuStep.Forward to End", False },
2730 { "menuStep.Back to Start", False },
2731 { "menuStep.Move Now", False },
2732 { "menuStep.Truncate Game", False },
2736 Enables trainingOffEnables[] = {
2737 { "menuMode.Edit Comment", True },
2738 { "menuMode.Pause", True },
2739 { "menuStep.Forward", True },
2740 { "menuStep.Backward", True },
2741 { "menuStep.Forward to End", True },
2742 { "menuStep.Back to Start", True },
2743 { "menuStep.Move Now", True },
2744 { "menuStep.Truncate Game", True },
2748 Enables machineThinkingEnables[] = {
2749 { "menuFile.Load Game", False },
2750 { "menuFile.Load Next Game", False },
2751 { "menuFile.Load Previous Game", False },
2752 { "menuFile.Reload Same Game", False },
2753 { "menuFile.Paste Game", False },
2754 { "menuFile.Load Position", False },
2755 { "menuFile.Load Next Position", False },
2756 { "menuFile.Load Previous Position", False },
2757 { "menuFile.Reload Same Position", False },
2758 { "menuFile.Paste Position", False },
2759 { "menuMode.Machine White", False },
2760 { "menuMode.Machine Black", False },
2761 { "menuMode.Two Machines", False },
2762 { "menuStep.Retract Move", False },
2766 Enables userThinkingEnables[] = {
2767 { "menuFile.Load Game", True },
2768 { "menuFile.Load Next Game", True },
2769 { "menuFile.Load Previous Game", True },
2770 { "menuFile.Reload Same Game", True },
2771 { "menuFile.Paste Game", True },
2772 { "menuFile.Load Position", True },
2773 { "menuFile.Load Next Position", True },
2774 { "menuFile.Load Previous Position", True },
2775 { "menuFile.Reload Same Position", True },
2776 { "menuFile.Paste Position", True },
2777 { "menuMode.Machine White", True },
2778 { "menuMode.Machine Black", True },
2779 { "menuMode.Two Machines", True },
2780 { "menuStep.Retract Move", True },
2786 SetMenuEnables(icsEnables);
2789 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2790 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2797 SetMenuEnables(ncpEnables);
2803 SetMenuEnables(gnuEnables);
2809 SetMenuEnables(cmailEnables);
2815 SetMenuEnables(trainingOnEnables);
2816 if (appData.showButtonBar) {
2817 XtSetSensitive(buttonBarWidget, False);
2823 SetTrainingModeOff()
2825 SetMenuEnables(trainingOffEnables);
2826 if (appData.showButtonBar) {
2827 XtSetSensitive(buttonBarWidget, True);
2832 SetUserThinkingEnables()
2834 if (appData.noChessProgram) return;
2835 SetMenuEnables(userThinkingEnables);
2839 SetMachineThinkingEnables()
2841 if (appData.noChessProgram) return;
2842 SetMenuEnables(machineThinkingEnables);
2844 case MachinePlaysBlack:
2845 case MachinePlaysWhite:
2846 case TwoMachinesPlay:
2847 XtSetSensitive(XtNameToWidget(menuBarWidget,
2848 ModeToWidgetName(gameMode)), True);
2855 #define Abs(n) ((n)<0 ? -(n) : (n))
2858 * Find a font that matches "pattern" that is as close as
2859 * possible to the targetPxlSize. Prefer fonts that are k
2860 * pixels smaller to fonts that are k pixels larger. The
2861 * pattern must be in the X Consortium standard format,
2862 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2863 * The return value should be freed with XtFree when no
2866 char *FindFont(pattern, targetPxlSize)
2870 char **fonts, *p, *best, *scalable, *scalableTail;
2871 int i, j, nfonts, minerr, err, pxlSize;
2874 char **missing_list;
2876 char *def_string, *base_fnt_lst, strInt[3];
2878 XFontStruct **fnt_list;
2880 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2881 sprintf(strInt, "%d", targetPxlSize);
2882 p = strstr(pattern, "--");
2883 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2884 strcat(base_fnt_lst, strInt);
2885 strcat(base_fnt_lst, strchr(p + 2, '-'));
2887 if ((fntSet = XCreateFontSet(xDisplay,
2891 &def_string)) == NULL) {
2893 fprintf(stderr, _("Unable to create font set.\n"));
2897 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2899 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2901 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2902 programName, pattern);
2910 for (i=0; i<nfonts; i++) {
2913 if (*p != '-') continue;
2915 if (*p == NULLCHAR) break;
2916 if (*p++ == '-') j++;
2918 if (j < 7) continue;
2921 scalable = fonts[i];
2924 err = pxlSize - targetPxlSize;
2925 if (Abs(err) < Abs(minerr) ||
2926 (minerr > 0 && err < 0 && -err == minerr)) {
2932 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2933 /* If the error is too big and there is a scalable font,
2934 use the scalable font. */
2935 int headlen = scalableTail - scalable;
2936 p = (char *) XtMalloc(strlen(scalable) + 10);
2937 while (isdigit(*scalableTail)) scalableTail++;
2938 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2940 p = (char *) XtMalloc(strlen(best) + 1);
2943 if (appData.debugMode) {
2944 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2945 pattern, targetPxlSize, p);
2948 if (missing_count > 0)
2949 XFreeStringList(missing_list);
2950 XFreeFontSet(xDisplay, fntSet);
2952 XFreeFontNames(fonts);
2959 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2960 | GCBackground | GCFunction | GCPlaneMask;
2961 XGCValues gc_values;
2964 gc_values.plane_mask = AllPlanes;
2965 gc_values.line_width = lineGap;
2966 gc_values.line_style = LineSolid;
2967 gc_values.function = GXcopy;
2969 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2970 gc_values.background = XBlackPixel(xDisplay, xScreen);
2971 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2973 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2974 gc_values.background = XWhitePixel(xDisplay, xScreen);
2975 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2976 XSetFont(xDisplay, coordGC, coordFontID);
2978 // [HGM] make font for holdings counts (white on black0
2979 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2980 gc_values.background = XBlackPixel(xDisplay, xScreen);
2981 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2982 XSetFont(xDisplay, countGC, countFontID);
2984 if (appData.monoMode) {
2985 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2986 gc_values.background = XWhitePixel(xDisplay, xScreen);
2987 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2989 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2990 gc_values.background = XBlackPixel(xDisplay, xScreen);
2991 lightSquareGC = wbPieceGC
2992 = XtGetGC(shellWidget, value_mask, &gc_values);
2994 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2995 gc_values.background = XWhitePixel(xDisplay, xScreen);
2996 darkSquareGC = bwPieceGC
2997 = XtGetGC(shellWidget, value_mask, &gc_values);
2999 if (DefaultDepth(xDisplay, xScreen) == 1) {
3000 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3001 gc_values.function = GXcopyInverted;
3002 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.function = GXcopy;
3004 if (XBlackPixel(xDisplay, xScreen) == 1) {
3005 bwPieceGC = darkSquareGC;
3006 wbPieceGC = copyInvertedGC;
3008 bwPieceGC = copyInvertedGC;
3009 wbPieceGC = lightSquareGC;
3013 gc_values.foreground = highlightSquareColor;
3014 gc_values.background = highlightSquareColor;
3015 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 gc_values.foreground = premoveHighlightColor;
3018 gc_values.background = premoveHighlightColor;
3019 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3021 gc_values.foreground = lightSquareColor;
3022 gc_values.background = darkSquareColor;
3023 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 gc_values.foreground = darkSquareColor;
3026 gc_values.background = lightSquareColor;
3027 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3029 gc_values.foreground = jailSquareColor;
3030 gc_values.background = jailSquareColor;
3031 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 gc_values.foreground = whitePieceColor;
3034 gc_values.background = darkSquareColor;
3035 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3037 gc_values.foreground = whitePieceColor;
3038 gc_values.background = lightSquareColor;
3039 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3041 gc_values.foreground = whitePieceColor;
3042 gc_values.background = jailSquareColor;
3043 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3045 gc_values.foreground = blackPieceColor;
3046 gc_values.background = darkSquareColor;
3047 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3049 gc_values.foreground = blackPieceColor;
3050 gc_values.background = lightSquareColor;
3051 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3053 gc_values.foreground = blackPieceColor;
3054 gc_values.background = jailSquareColor;
3055 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3059 void loadXIM(xim, xmask, filename, dest, mask)
3072 fp = fopen(filename, "rb");
3074 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3081 for (y=0; y<h; ++y) {
3082 for (x=0; x<h; ++x) {
3087 XPutPixel(xim, x, y, blackPieceColor);
3089 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3092 XPutPixel(xim, x, y, darkSquareColor);
3094 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3097 XPutPixel(xim, x, y, whitePieceColor);
3099 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3102 XPutPixel(xim, x, y, lightSquareColor);
3104 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3110 /* create Pixmap of piece */
3111 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3113 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3116 /* create Pixmap of clipmask
3117 Note: We assume the white/black pieces have the same
3118 outline, so we make only 6 masks. This is okay
3119 since the XPM clipmask routines do the same. */
3121 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3123 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3126 /* now create the 1-bit version */
3127 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3130 values.foreground = 1;
3131 values.background = 0;
3133 /* Don't use XtGetGC, not read only */
3134 maskGC = XCreateGC(xDisplay, *mask,
3135 GCForeground | GCBackground, &values);
3136 XCopyPlane(xDisplay, temp, *mask, maskGC,
3137 0, 0, squareSize, squareSize, 0, 0, 1);
3138 XFreePixmap(xDisplay, temp);
3143 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3145 void CreateXIMPieces()
3150 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3155 /* The XSynchronize calls were copied from CreatePieces.
3156 Not sure if needed, but can't hurt */
3157 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3160 /* temp needed by loadXIM() */
3161 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3162 0, 0, ss, ss, AllPlanes, XYPixmap);
3164 if (strlen(appData.pixmapDirectory) == 0) {
3168 if (appData.monoMode) {
3169 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3173 fprintf(stderr, _("\nLoading XIMs...\n"));
3175 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3176 fprintf(stderr, "%d", piece+1);
3177 for (kind=0; kind<4; kind++) {
3178 fprintf(stderr, ".");
3179 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3180 ExpandPathName(appData.pixmapDirectory),
3181 piece <= (int) WhiteKing ? "" : "w",
3182 pieceBitmapNames[piece],
3184 ximPieceBitmap[kind][piece] =
3185 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3186 0, 0, ss, ss, AllPlanes, XYPixmap);
3187 if (appData.debugMode)
3188 fprintf(stderr, _("(File:%s:) "), buf);
3189 loadXIM(ximPieceBitmap[kind][piece],
3191 &(xpmPieceBitmap2[kind][piece]),
3192 &(ximMaskPm2[piece]));
3193 if(piece <= (int)WhiteKing)
3194 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3196 fprintf(stderr," ");
3198 /* Load light and dark squares */
3199 /* If the LSQ and DSQ pieces don't exist, we will
3200 draw them with solid squares. */
3201 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3202 if (access(buf, 0) != 0) {
3206 fprintf(stderr, _("light square "));
3208 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3209 0, 0, ss, ss, AllPlanes, XYPixmap);
3210 if (appData.debugMode)
3211 fprintf(stderr, _("(File:%s:) "), buf);
3213 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3214 fprintf(stderr, _("dark square "));
3215 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3216 ExpandPathName(appData.pixmapDirectory), ss);
3217 if (appData.debugMode)
3218 fprintf(stderr, _("(File:%s:) "), buf);
3220 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3221 0, 0, ss, ss, AllPlanes, XYPixmap);
3222 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3223 xpmJailSquare = xpmLightSquare;
3225 fprintf(stderr, _("Done.\n"));
3227 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3231 void CreateXPMPieces()
3235 u_int ss = squareSize;
3237 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3238 XpmColorSymbol symbols[4];
3240 /* The XSynchronize calls were copied from CreatePieces.
3241 Not sure if needed, but can't hurt */
3242 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3244 /* Setup translations so piece colors match square colors */
3245 symbols[0].name = "light_piece";
3246 symbols[0].value = appData.whitePieceColor;
3247 symbols[1].name = "dark_piece";
3248 symbols[1].value = appData.blackPieceColor;
3249 symbols[2].name = "light_square";
3250 symbols[2].value = appData.lightSquareColor;
3251 symbols[3].name = "dark_square";
3252 symbols[3].value = appData.darkSquareColor;
3254 attr.valuemask = XpmColorSymbols;
3255 attr.colorsymbols = symbols;
3256 attr.numsymbols = 4;
3258 if (appData.monoMode) {
3259 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3263 if (strlen(appData.pixmapDirectory) == 0) {
3264 XpmPieces* pieces = builtInXpms;
3267 while (pieces->size != squareSize && pieces->size) pieces++;
3268 if (!pieces->size) {
3269 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3272 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3273 for (kind=0; kind<4; kind++) {
3275 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3276 pieces->xpm[piece][kind],
3277 &(xpmPieceBitmap2[kind][piece]),
3278 NULL, &attr)) != 0) {
3279 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3283 if(piece <= (int) WhiteKing)
3284 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3288 xpmJailSquare = xpmLightSquare;
3292 fprintf(stderr, _("\nLoading XPMs...\n"));
3295 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3296 fprintf(stderr, "%d ", piece+1);
3297 for (kind=0; kind<4; kind++) {
3298 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3299 ExpandPathName(appData.pixmapDirectory),
3300 piece > (int) WhiteKing ? "w" : "",
3301 pieceBitmapNames[piece],
3303 if (appData.debugMode) {
3304 fprintf(stderr, _("(File:%s:) "), buf);
3306 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3307 &(xpmPieceBitmap2[kind][piece]),
3308 NULL, &attr)) != 0) {
3309 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3310 // [HGM] missing: read of unorthodox piece failed; substitute King.
3311 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3312 ExpandPathName(appData.pixmapDirectory),
3314 if (appData.debugMode) {
3315 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3317 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3318 &(xpmPieceBitmap2[kind][piece]),
3322 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3327 if(piece <= (int) WhiteKing)
3328 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3331 /* Load light and dark squares */
3332 /* If the LSQ and DSQ pieces don't exist, we will
3333 draw them with solid squares. */
3334 fprintf(stderr, _("light square "));
3335 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3336 if (access(buf, 0) != 0) {
3340 if (appData.debugMode)
3341 fprintf(stderr, _("(File:%s:) "), buf);
3343 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3344 &xpmLightSquare, NULL, &attr)) != 0) {
3345 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3348 fprintf(stderr, _("dark square "));
3349 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3350 ExpandPathName(appData.pixmapDirectory), ss);
3351 if (appData.debugMode) {
3352 fprintf(stderr, _("(File:%s:) "), buf);
3354 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3355 &xpmDarkSquare, NULL, &attr)) != 0) {
3356 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3360 xpmJailSquare = xpmLightSquare;
3361 fprintf(stderr, _("Done.\n"));
3363 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3366 #endif /* HAVE_LIBXPM */
3369 /* No built-in bitmaps */
3374 u_int ss = squareSize;
3376 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3379 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3380 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3381 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3382 pieceBitmapNames[piece],
3383 ss, kind == SOLID ? 's' : 'o');
3384 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3385 if(piece <= (int)WhiteKing)
3386 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3390 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3394 /* With built-in bitmaps */
3397 BuiltInBits* bib = builtInBits;
3400 u_int ss = squareSize;
3402 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3405 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3407 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3408 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3409 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3410 pieceBitmapNames[piece],
3411 ss, kind == SOLID ? 's' : 'o');
3412 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3413 bib->bits[kind][piece], ss, ss);
3414 if(piece <= (int)WhiteKing)
3415 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3419 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3424 void ReadBitmap(pm, name, bits, wreq, hreq)
3427 unsigned char bits[];
3433 char msg[MSG_SIZ], fullname[MSG_SIZ];
3435 if (*appData.bitmapDirectory != NULLCHAR) {
3436 strcpy(fullname, appData.bitmapDirectory);
3437 strcat(fullname, "/");
3438 strcat(fullname, name);
3439 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3440 &w, &h, pm, &x_hot, &y_hot);
3441 fprintf(stderr, "load %s\n", name);
3442 if (errcode != BitmapSuccess) {
3444 case BitmapOpenFailed:
3445 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3447 case BitmapFileInvalid:
3448 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3450 case BitmapNoMemory:
3451 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3455 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3459 fprintf(stderr, _("%s: %s...using built-in\n"),
3461 } else if (w != wreq || h != hreq) {
3463 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3464 programName, fullname, w, h, wreq, hreq);
3470 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3479 if (lineGap == 0) return;
3481 /* [HR] Split this into 2 loops for non-square boards. */
3483 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3484 gridSegments[i].x1 = 0;
3485 gridSegments[i].x2 =
3486 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3487 gridSegments[i].y1 = gridSegments[i].y2
3488 = lineGap / 2 + (i * (squareSize + lineGap));
3491 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3492 gridSegments[j + i].y1 = 0;
3493 gridSegments[j + i].y2 =
3494 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3495 gridSegments[j + i].x1 = gridSegments[j + i].x2
3496 = lineGap / 2 + (j * (squareSize + lineGap));
3500 static void MenuBarSelect(w, addr, index)
3505 XtActionProc proc = (XtActionProc) addr;
3507 (proc)(NULL, NULL, NULL, NULL);
3510 void CreateMenuBarPopup(parent, name, mb)
3520 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3523 XtSetArg(args[j], XtNleftMargin, 20); j++;
3524 XtSetArg(args[j], XtNrightMargin, 20); j++;
3526 while (mi->string != NULL) {
3527 if (strcmp(mi->string, "----") == 0) {
3528 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3531 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3532 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3534 XtAddCallback(entry, XtNcallback,
3535 (XtCallbackProc) MenuBarSelect,
3536 (caddr_t) mi->proc);
3542 Widget CreateMenuBar(mb)
3546 Widget anchor, menuBar;
3548 char menuName[MSG_SIZ];
3551 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3552 XtSetArg(args[j], XtNvSpace, 0); j++;
3553 XtSetArg(args[j], XtNborderWidth, 0); j++;
3554 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3555 formWidget, args, j);
3557 while (mb->name != NULL) {
3558 strcpy(menuName, "menu");
3559 strcat(menuName, mb->name);
3561 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3564 shortName[0] = _(mb->name)[0];
3565 shortName[1] = NULLCHAR;
3566 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3569 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3572 XtSetArg(args[j], XtNborderWidth, 0); j++;
3573 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3575 CreateMenuBarPopup(menuBar, menuName, mb);
3581 Widget CreateButtonBar(mi)
3585 Widget button, buttonBar;
3589 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3591 XtSetArg(args[j], XtNhSpace, 0); j++;
3593 XtSetArg(args[j], XtNborderWidth, 0); j++;
3594 XtSetArg(args[j], XtNvSpace, 0); j++;
3595 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3596 formWidget, args, j);
3598 while (mi->string != NULL) {
3601 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3602 XtSetArg(args[j], XtNborderWidth, 0); j++;
3604 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3605 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3606 buttonBar, args, j);
3607 XtAddCallback(button, XtNcallback,
3608 (XtCallbackProc) MenuBarSelect,
3609 (caddr_t) mi->proc);
3616 CreatePieceMenu(name, color)
3623 ChessSquare selection;
3625 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3626 boardWidget, args, 0);
3628 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3629 String item = pieceMenuStrings[color][i];
3631 if (strcmp(item, "----") == 0) {
3632 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3635 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3636 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3638 selection = pieceMenuTranslation[color][i];
3639 XtAddCallback(entry, XtNcallback,
3640 (XtCallbackProc) PieceMenuSelect,
3641 (caddr_t) selection);
3642 if (selection == WhitePawn || selection == BlackPawn) {
3643 XtSetArg(args[0], XtNpopupOnEntry, entry);
3644 XtSetValues(menu, args, 1);
3657 ChessSquare selection;
3659 whitePieceMenu = CreatePieceMenu("menuW", 0);
3660 blackPieceMenu = CreatePieceMenu("menuB", 1);
3662 XtRegisterGrabAction(PieceMenuPopup, True,
3663 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3664 GrabModeAsync, GrabModeAsync);
3666 XtSetArg(args[0], XtNlabel, _("Drop"));
3667 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3668 boardWidget, args, 1);
3669 for (i = 0; i < DROP_MENU_SIZE; i++) {
3670 String item = dropMenuStrings[i];
3672 if (strcmp(item, "----") == 0) {
3673 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3676 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3677 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3679 selection = dropMenuTranslation[i];
3680 XtAddCallback(entry, XtNcallback,
3681 (XtCallbackProc) DropMenuSelect,
3682 (caddr_t) selection);
3687 void SetupDropMenu()
3695 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3696 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3697 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3698 dmEnables[i].piece);
3699 XtSetSensitive(entry, p != NULL || !appData.testLegality
3700 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3701 && !appData.icsActive));
3703 while (p && *p++ == dmEnables[i].piece) count++;
3704 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3706 XtSetArg(args[j], XtNlabel, label); j++;
3707 XtSetValues(entry, args, j);
3711 void PieceMenuPopup(w, event, params, num_params)
3715 Cardinal *num_params;
3717 String whichMenu; int menuNr;
3718 if (event->type == ButtonRelease)
3719 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3720 else if (event->type == ButtonPress)
3721 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3723 case 0: whichMenu = params[0]; break;
3724 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3726 case -1: if (errorUp) ErrorPopDown();
3729 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3732 static void PieceMenuSelect(w, piece, junk)
3737 if (pmFromX < 0 || pmFromY < 0) return;
3738 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3741 static void DropMenuSelect(w, piece, junk)
3746 if (pmFromX < 0 || pmFromY < 0) return;
3747 DropMenuEvent(piece, pmFromX, pmFromY);
3750 void WhiteClock(w, event, prms, nprms)
3756 if (gameMode == EditPosition || gameMode == IcsExamining) {
3757 SetWhiteToPlayEvent();
3758 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3763 void BlackClock(w, event, prms, nprms)
3769 if (gameMode == EditPosition || gameMode == IcsExamining) {
3770 SetBlackToPlayEvent();
3771 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3778 * If the user selects on a border boundary, return -1; if off the board,
3779 * return -2. Otherwise map the event coordinate to the square.
3781 int EventToSquare(x, limit)
3789 if ((x % (squareSize + lineGap)) >= squareSize)
3791 x /= (squareSize + lineGap);
3797 static void do_flash_delay(msec)
3803 static void drawHighlight(file, rank, gc)
3809 if (lineGap == 0 || appData.blindfold) return;
3812 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3813 (squareSize + lineGap);
3814 y = lineGap/2 + rank * (squareSize + lineGap);
3816 x = lineGap/2 + file * (squareSize + lineGap);
3817 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3818 (squareSize + lineGap);
3821 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3822 squareSize+lineGap, squareSize+lineGap);
3825 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3826 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3829 SetHighlights(fromX, fromY, toX, toY)
3830 int fromX, fromY, toX, toY;
3832 if (hi1X != fromX || hi1Y != fromY) {
3833 if (hi1X >= 0 && hi1Y >= 0) {
3834 drawHighlight(hi1X, hi1Y, lineGC);
3836 } // [HGM] first erase both, then draw new!
3837 if (hi2X != toX || hi2Y != toY) {
3838 if (hi2X >= 0 && hi2Y >= 0) {
3839 drawHighlight(hi2X, hi2Y, lineGC);
3842 if (hi1X != fromX || hi1Y != fromY) {
3843 if (fromX >= 0 && fromY >= 0) {
3844 drawHighlight(fromX, fromY, highlineGC);
3847 if (hi2X != toX || hi2Y != toY) {
3848 if (toX >= 0 && toY >= 0) {
3849 drawHighlight(toX, toY, highlineGC);
3861 SetHighlights(-1, -1, -1, -1);
3866 SetPremoveHighlights(fromX, fromY, toX, toY)
3867 int fromX, fromY, toX, toY;
3869 if (pm1X != fromX || pm1Y != fromY) {
3870 if (pm1X >= 0 && pm1Y >= 0) {
3871 drawHighlight(pm1X, pm1Y, lineGC);
3873 if (fromX >= 0 && fromY >= 0) {
3874 drawHighlight(fromX, fromY, prelineGC);
3877 if (pm2X != toX || pm2Y != toY) {
3878 if (pm2X >= 0 && pm2Y >= 0) {
3879 drawHighlight(pm2X, pm2Y, lineGC);
3881 if (toX >= 0 && toY >= 0) {
3882 drawHighlight(toX, toY, prelineGC);
3892 ClearPremoveHighlights()
3894 SetPremoveHighlights(-1, -1, -1, -1);
3897 static void BlankSquare(x, y, color, piece, dest)
3902 if (useImages && useImageSqs) {
3906 pm = xpmLightSquare;
3911 case 2: /* neutral */
3916 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3917 squareSize, squareSize, x, y);
3927 case 2: /* neutral */
3932 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3937 I split out the routines to draw a piece so that I could
3938 make a generic flash routine.
3940 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3942 int square_color, x, y;
3945 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3946 switch (square_color) {
3948 case 2: /* neutral */
3950 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3951 ? *pieceToOutline(piece)
3952 : *pieceToSolid(piece),
3953 dest, bwPieceGC, 0, 0,
3954 squareSize, squareSize, x, y);
3957 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3958 ? *pieceToSolid(piece)
3959 : *pieceToOutline(piece),
3960 dest, wbPieceGC, 0, 0,
3961 squareSize, squareSize, x, y);
3966 static void monoDrawPiece(piece, square_color, x, y, dest)
3968 int square_color, x, y;
3971 switch (square_color) {
3973 case 2: /* neutral */
3975 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3976 ? *pieceToOutline(piece)
3977 : *pieceToSolid(piece),
3978 dest, bwPieceGC, 0, 0,
3979 squareSize, squareSize, x, y, 1);
3982 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3983 ? *pieceToSolid(piece)
3984 : *pieceToOutline(piece),
3985 dest, wbPieceGC, 0, 0,
3986 squareSize, squareSize, x, y, 1);
3991 static void colorDrawPiece(piece, square_color, x, y, dest)
3993 int square_color, x, y;
3996 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3997 switch (square_color) {
3999 XCopyPlane(xDisplay, *pieceToSolid(piece),
4000 dest, (int) piece < (int) BlackPawn
4001 ? wlPieceGC : blPieceGC, 0, 0,
4002 squareSize, squareSize, x, y, 1);
4005 XCopyPlane(xDisplay, *pieceToSolid(piece),
4006 dest, (int) piece < (int) BlackPawn
4007 ? wdPieceGC : bdPieceGC, 0, 0,
4008 squareSize, squareSize, x, y, 1);
4010 case 2: /* neutral */
4012 XCopyPlane(xDisplay, *pieceToSolid(piece),
4013 dest, (int) piece < (int) BlackPawn
4014 ? wjPieceGC : bjPieceGC, 0, 0,
4015 squareSize, squareSize, x, y, 1);
4020 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4022 int square_color, x, y;
4027 switch (square_color) {
4029 case 2: /* neutral */
4031 if ((int)piece < (int) BlackPawn) {
4039 if ((int)piece < (int) BlackPawn) {
4047 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4048 dest, wlPieceGC, 0, 0,
4049 squareSize, squareSize, x, y);
4052 typedef void (*DrawFunc)();
4054 DrawFunc ChooseDrawFunc()
4056 if (appData.monoMode) {
4057 if (DefaultDepth(xDisplay, xScreen) == 1) {
4058 return monoDrawPiece_1bit;
4060 return monoDrawPiece;
4064 return colorDrawPieceImage;
4066 return colorDrawPiece;
4070 /* [HR] determine square color depending on chess variant. */
4071 static int SquareColor(row, column)
4076 if (gameInfo.variant == VariantXiangqi) {
4077 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4079 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4081 } else if (row <= 4) {
4087 square_color = ((column + row) % 2) == 1;
4090 /* [hgm] holdings: next line makes all holdings squares light */
4091 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4093 return square_color;
4096 void DrawSquare(row, column, piece, do_flash)
4097 int row, column, do_flash;
4100 int square_color, x, y, direction, font_ascent, font_descent;
4103 XCharStruct overall;
4107 /* Calculate delay in milliseconds (2-delays per complete flash) */
4108 flash_delay = 500 / appData.flashRate;
4111 x = lineGap + ((BOARD_WIDTH-1)-column) *
4112 (squareSize + lineGap);
4113 y = lineGap + row * (squareSize + lineGap);
4115 x = lineGap + column * (squareSize + lineGap);
4116 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4117 (squareSize + lineGap);
4120 square_color = SquareColor(row, column);
4122 if ( // [HGM] holdings: blank out area between board and holdings
4123 column == BOARD_LEFT-1 || column == BOARD_RGHT
4124 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4125 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4126 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4128 // [HGM] print piece counts next to holdings
4129 string[1] = NULLCHAR;
4130 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4131 string[0] = '0' + piece;
4132 XTextExtents(countFontStruct, string, 1, &direction,
4133 &font_ascent, &font_descent, &overall);
4134 if (appData.monoMode) {
4135 XDrawImageString(xDisplay, xBoardWindow, countGC,
4136 x + squareSize - overall.width - 2,
4137 y + font_ascent + 1, string, 1);
4139 XDrawString(xDisplay, xBoardWindow, countGC,
4140 x + squareSize - overall.width - 2,
4141 y + font_ascent + 1, string, 1);
4144 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4145 string[0] = '0' + piece;
4146 XTextExtents(countFontStruct, string, 1, &direction,
4147 &font_ascent, &font_descent, &overall);
4148 if (appData.monoMode) {
4149 XDrawImageString(xDisplay, xBoardWindow, countGC,
4150 x + 2, y + font_ascent + 1, string, 1);
4152 XDrawString(xDisplay, xBoardWindow, countGC,
4153 x + 2, y + font_ascent + 1, string, 1);
4157 if (piece == EmptySquare || appData.blindfold) {
4158 BlankSquare(x, y, square_color, piece, xBoardWindow);
4160 drawfunc = ChooseDrawFunc();
4161 if (do_flash && appData.flashCount > 0) {
4162 for (i=0; i<appData.flashCount; ++i) {
4164 drawfunc(piece, square_color, x, y, xBoardWindow);
4165 XSync(xDisplay, False);
4166 do_flash_delay(flash_delay);
4168 BlankSquare(x, y, square_color, piece, xBoardWindow);
4169 XSync(xDisplay, False);
4170 do_flash_delay(flash_delay);
4173 drawfunc(piece, square_color, x, y, xBoardWindow);
4177 string[1] = NULLCHAR;
4178 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4179 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4180 string[0] = 'a' + column - BOARD_LEFT;
4181 XTextExtents(coordFontStruct, string, 1, &direction,
4182 &font_ascent, &font_descent, &overall);
4183 if (appData.monoMode) {
4184 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4185 x + squareSize - overall.width - 2,
4186 y + squareSize - font_descent - 1, string, 1);
4188 XDrawString(xDisplay, xBoardWindow, coordGC,
4189 x + squareSize - overall.width - 2,
4190 y + squareSize - font_descent - 1, string, 1);
4193 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4194 string[0] = ONE + row;
4195 XTextExtents(coordFontStruct, string, 1, &direction,
4196 &font_ascent, &font_descent, &overall);
4197 if (appData.monoMode) {
4198 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4199 x + 2, y + font_ascent + 1, string, 1);
4201 XDrawString(xDisplay, xBoardWindow, coordGC,
4202 x + 2, y + font_ascent + 1, string, 1);
4205 if(marker[row][column]) {
4206 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4207 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4212 /* Why is this needed on some versions of X? */
4213 void EventProc(widget, unused, event)
4218 if (!XtIsRealized(widget))
4221 switch (event->type) {
4223 if (event->xexpose.count > 0) return; /* no clipping is done */
4224 XDrawPosition(widget, True, NULL);
4227 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4234 void DrawPosition(fullRedraw, board)
4235 /*Boolean*/int fullRedraw;
4238 XDrawPosition(boardWidget, fullRedraw, board);
4241 /* Returns 1 if there are "too many" differences between b1 and b2
4242 (i.e. more than 1 move was made) */
4243 static int too_many_diffs(b1, b2)
4249 for (i=0; i<BOARD_HEIGHT; ++i) {
4250 for (j=0; j<BOARD_WIDTH; ++j) {
4251 if (b1[i][j] != b2[i][j]) {
4252 if (++c > 4) /* Castling causes 4 diffs */
4261 /* Matrix describing castling maneuvers */
4262 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4263 static int castling_matrix[4][5] = {
4264 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4265 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4266 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4267 { 7, 7, 4, 5, 6 } /* 0-0, black */
4270 /* Checks whether castling occurred. If it did, *rrow and *rcol
4271 are set to the destination (row,col) of the rook that moved.
4273 Returns 1 if castling occurred, 0 if not.
4275 Note: Only handles a max of 1 castling move, so be sure
4276 to call too_many_diffs() first.
4278 static int check_castle_draw(newb, oldb, rrow, rcol)
4285 /* For each type of castling... */
4286 for (i=0; i<4; ++i) {
4287 r = castling_matrix[i];
4289 /* Check the 4 squares involved in the castling move */
4291 for (j=1; j<=4; ++j) {
4292 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4299 /* All 4 changed, so it must be a castling move */
4308 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4309 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4311 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4314 void DrawSeekBackground( int left, int top, int right, int bottom )
4316 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4319 void DrawSeekText(char *buf, int x, int y)
4321 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4324 void DrawSeekDot(int x, int y, int colorNr)
4326 int square = colorNr & 0x80;
4329 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4331 XFillRectangle(xDisplay, xBoardWindow, color,
4332 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4334 XFillArc(xDisplay, xBoardWindow, color,
4335 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4338 static int damage[BOARD_RANKS][BOARD_FILES];
4341 * event handler for redrawing the board
4343 void XDrawPosition(w, repaint, board)
4345 /*Boolean*/int repaint;
4349 static int lastFlipView = 0;
4350 static int lastBoardValid = 0;
4351 static Board lastBoard;
4355 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4357 if (board == NULL) {
4358 if (!lastBoardValid) return;
4361 if (!lastBoardValid || lastFlipView != flipView) {
4362 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4363 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4368 * It would be simpler to clear the window with XClearWindow()
4369 * but this causes a very distracting flicker.
4372 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4374 /* If too much changes (begin observing new game, etc.), don't
4376 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4378 /* Special check for castling so we don't flash both the king
4379 and the rook (just flash the king). */
4381 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4382 /* Draw rook with NO flashing. King will be drawn flashing later */
4383 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4384 lastBoard[rrow][rcol] = board[rrow][rcol];
4388 /* First pass -- Draw (newly) empty squares and repair damage.
4389 This prevents you from having a piece show up twice while it
4390 is flashing on its new square */
4391 for (i = 0; i < BOARD_HEIGHT; i++)
4392 for (j = 0; j < BOARD_WIDTH; j++)
4393 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4395 DrawSquare(i, j, board[i][j], 0);
4396 damage[i][j] = False;
4399 /* Second pass -- Draw piece(s) in new position and flash them */
4400 for (i = 0; i < BOARD_HEIGHT; i++)
4401 for (j = 0; j < BOARD_WIDTH; j++)
4402 if (board[i][j] != lastBoard[i][j]) {
4403 DrawSquare(i, j, board[i][j], do_flash);
4407 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4408 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4410 for (i = 0; i < BOARD_HEIGHT; i++)
4411 for (j = 0; j < BOARD_WIDTH; j++) {
4412 DrawSquare(i, j, board[i][j], 0);
4413 damage[i][j] = False;
4417 CopyBoard(lastBoard, board);
4419 lastFlipView = flipView;
4421 /* Draw highlights */
4422 if (pm1X >= 0 && pm1Y >= 0) {
4423 drawHighlight(pm1X, pm1Y, prelineGC);
4425 if (pm2X >= 0 && pm2Y >= 0) {
4426 drawHighlight(pm2X, pm2Y, prelineGC);
4428 if (hi1X >= 0 && hi1Y >= 0) {
4429 drawHighlight(hi1X, hi1Y, highlineGC);
4431 if (hi2X >= 0 && hi2Y >= 0) {
4432 drawHighlight(hi2X, hi2Y, highlineGC);
4435 /* If piece being dragged around board, must redraw that too */
4438 XSync(xDisplay, False);
4443 * event handler for redrawing the board
4445 void DrawPositionProc(w, event, prms, nprms)
4451 XDrawPosition(w, True, NULL);
4456 * event handler for parsing user moves
4458 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4459 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4460 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4461 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4462 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4463 // and at the end FinishMove() to perform the move after optional promotion popups.
4464 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4465 void HandleUserMove(w, event, prms, nprms)
4471 if (w != boardWidget || errorExitStatus != -1) return;
4474 if (event->type == ButtonPress) {
4475 XtPopdown(promotionShell);
4476 XtDestroyWidget(promotionShell);
4477 promotionUp = False;
4485 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4486 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4487 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4490 void AnimateUserMove (Widget w, XEvent * event,
4491 String * params, Cardinal * nParams)
4493 DragPieceMove(event->xmotion.x, event->xmotion.y);
4496 void HandlePV (Widget w, XEvent * event,
4497 String * params, Cardinal * nParams)
4498 { // [HGM] pv: walk PV
4499 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4502 Widget CommentCreate(name, text, mutable, callback, lines)
4504 int /*Boolean*/ mutable;
4505 XtCallbackProc callback;
4509 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4514 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4515 XtGetValues(boardWidget, args, j);
4518 XtSetArg(args[j], XtNresizable, True); j++;
4521 XtCreatePopupShell(name, topLevelShellWidgetClass,
4522 shellWidget, args, j);
4525 XtCreatePopupShell(name, transientShellWidgetClass,
4526 shellWidget, args, j);
4529 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4530 layoutArgs, XtNumber(layoutArgs));
4532 XtCreateManagedWidget("form", formWidgetClass, layout,
4533 formArgs, XtNumber(formArgs));
4537 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4538 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4540 XtSetArg(args[j], XtNstring, text); j++;
4541 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4542 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4543 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4544 XtSetArg(args[j], XtNright, XtChainRight); j++;
4545 XtSetArg(args[j], XtNresizable, True); j++;
4546 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4547 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4548 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4549 XtSetArg(args[j], XtNautoFill, True); j++;
4550 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4552 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4556 XtSetArg(args[j], XtNfromVert, edit); j++;
4557 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4558 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4559 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4560 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4562 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4563 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4566 XtSetArg(args[j], XtNfromVert, edit); j++;
4567 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4568 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4569 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4570 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4571 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4573 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4574 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4577 XtSetArg(args[j], XtNfromVert, edit); j++;
4578 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4579 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4580 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4581 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4582 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4584 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4585 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4588 XtSetArg(args[j], XtNfromVert, edit); j++;
4589 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4590 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4591 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4592 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4594 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4595 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4598 XtSetArg(args[j], XtNfromVert, edit); j++;
4599 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4600 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4601 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4602 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4603 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4605 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4606 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4609 XtRealizeWidget(shell);
4611 if (commentX == -1) {
4614 Dimension pw_height;
4615 Dimension ew_height;
4618 XtSetArg(args[j], XtNheight, &ew_height); j++;
4619 XtGetValues(edit, args, j);
4622 XtSetArg(args[j], XtNheight, &pw_height); j++;
4623 XtGetValues(shell, args, j);
4624 commentH = pw_height + (lines - 1) * ew_height;
4625 commentW = bw_width - 16;
4627 XSync(xDisplay, False);
4629 /* This code seems to tickle an X bug if it is executed too soon
4630 after xboard starts up. The coordinates get transformed as if
4631 the main window was positioned at (0, 0).
4633 XtTranslateCoords(shellWidget,
4634 (bw_width - commentW) / 2, 0 - commentH / 2,
4635 &commentX, &commentY);
4637 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4638 RootWindowOfScreen(XtScreen(shellWidget)),
4639 (bw_width - commentW) / 2, 0 - commentH / 2,
4644 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4647 if(wpComment.width > 0) {
4648 commentX = wpComment.x;
4649 commentY = wpComment.y;
4650 commentW = wpComment.width;
4651 commentH = wpComment.height;
4655 XtSetArg(args[j], XtNheight, commentH); j++;
4656 XtSetArg(args[j], XtNwidth, commentW); j++;
4657 XtSetArg(args[j], XtNx, commentX); j++;
4658 XtSetArg(args[j], XtNy, commentY); j++;
4659 XtSetValues(shell, args, j);
4660 XtSetKeyboardFocus(shell, edit);
4665 /* Used for analysis window and ICS input window */
4666 Widget MiscCreate(name, text, mutable, callback, lines)
4668 int /*Boolean*/ mutable;
4669 XtCallbackProc callback;
4673 Widget shell, layout, form, edit;
4675 Dimension bw_width, pw_height, ew_height, w, h;
4681 XtSetArg(args[j], XtNresizable, True); j++;
4684 XtCreatePopupShell(name, topLevelShellWidgetClass,
4685 shellWidget, args, j);
4688 XtCreatePopupShell(name, transientShellWidgetClass,
4689 shellWidget, args, j);
4692 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4693 layoutArgs, XtNumber(layoutArgs));
4695 XtCreateManagedWidget("form", formWidgetClass, layout,
4696 formArgs, XtNumber(formArgs));
4700 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4701 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4703 XtSetArg(args[j], XtNstring, text); j++;
4704 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4705 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4706 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4707 XtSetArg(args[j], XtNright, XtChainRight); j++;
4708 XtSetArg(args[j], XtNresizable, True); j++;
4709 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4710 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4711 XtSetArg(args[j], XtNautoFill, True); j++;
4712 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4714 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4716 XtRealizeWidget(shell);
4719 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4720 XtGetValues(boardWidget, args, j);
4723 XtSetArg(args[j], XtNheight, &ew_height); j++;
4724 XtGetValues(edit, args, j);
4727 XtSetArg(args[j], XtNheight, &pw_height); j++;
4728 XtGetValues(shell, args, j);
4729 h = pw_height + (lines - 1) * ew_height;
4732 XSync(xDisplay, False);
4734 /* This code seems to tickle an X bug if it is executed too soon
4735 after xboard starts up. The coordinates get transformed as if
4736 the main window was positioned at (0, 0).
4738 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4740 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4741 RootWindowOfScreen(XtScreen(shellWidget)),
4742 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4746 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4749 XtSetArg(args[j], XtNheight, h); j++;
4750 XtSetArg(args[j], XtNwidth, w); j++;
4751 XtSetArg(args[j], XtNx, x); j++;
4752 XtSetArg(args[j], XtNy, y); j++;
4753 XtSetValues(shell, args, j);
4759 static int savedIndex; /* gross that this is global */
4761 void EditCommentPopUp(index, title, text)
4770 if (text == NULL) text = "";
4772 if (editShell == NULL) {
4774 CommentCreate(title, text, True, EditCommentCallback, 4);
4775 XtRealizeWidget(editShell);
4776 CatchDeleteWindow(editShell, "EditCommentPopDown");
4778 edit = XtNameToWidget(editShell, "*form.text");
4780 XtSetArg(args[j], XtNstring, text); j++;
4781 XtSetValues(edit, args, j);
4783 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4784 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4785 XtSetValues(editShell, args, j);
4788 XtPopup(editShell, XtGrabNone);
4792 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4793 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4797 void EditCommentCallback(w, client_data, call_data)
4799 XtPointer client_data, call_data;
4807 XtSetArg(args[j], XtNlabel, &name); j++;
4808 XtGetValues(w, args, j);
4810 if (strcmp(name, _("ok")) == 0) {
4811 edit = XtNameToWidget(editShell, "*form.text");
4813 XtSetArg(args[j], XtNstring, &val); j++;
4814 XtGetValues(edit, args, j);
4815 ReplaceComment(savedIndex, val);
4816 EditCommentPopDown();
4817 } else if (strcmp(name, _("cancel")) == 0) {
4818 EditCommentPopDown();
4819 } else if (strcmp(name, _("clear")) == 0) {
4820 edit = XtNameToWidget(editShell, "*form.text");
4821 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4822 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4826 void EditCommentPopDown()
4831 if (!editUp) return;
4833 XtSetArg(args[j], XtNx, &commentX); j++;
4834 XtSetArg(args[j], XtNy, &commentY); j++;
4835 XtSetArg(args[j], XtNheight, &commentH); j++;
4836 XtSetArg(args[j], XtNwidth, &commentW); j++;
4837 XtGetValues(editShell, args, j);
4838 XtPopdown(editShell);
4841 XtSetArg(args[j], XtNleftBitmap, None); j++;
4842 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4846 void ICSInputBoxPopUp()
4851 char *title = _("ICS Input");
4854 if (ICSInputShell == NULL) {
4855 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4856 tr = XtParseTranslationTable(ICSInputTranslations);
4857 edit = XtNameToWidget(ICSInputShell, "*form.text");
4858 XtOverrideTranslations(edit, tr);
4859 XtRealizeWidget(ICSInputShell);
4860 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4863 edit = XtNameToWidget(ICSInputShell, "*form.text");
4865 XtSetArg(args[j], XtNstring, ""); j++;
4866 XtSetValues(edit, args, j);
4868 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4869 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4870 XtSetValues(ICSInputShell, args, j);
4873 XtPopup(ICSInputShell, XtGrabNone);
4874 XtSetKeyboardFocus(ICSInputShell, edit);
4876 ICSInputBoxUp = True;
4878 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4879 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4883 void ICSInputSendText()
4890 edit = XtNameToWidget(ICSInputShell, "*form.text");
4892 XtSetArg(args[j], XtNstring, &val); j++;
4893 XtGetValues(edit, args, j);
4894 SendMultiLineToICS(val);
4895 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4896 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4899 void ICSInputBoxPopDown()
4904 if (!ICSInputBoxUp) return;
4906 XtPopdown(ICSInputShell);
4907 ICSInputBoxUp = False;
4909 XtSetArg(args[j], XtNleftBitmap, None); j++;
4910 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4914 void CommentPopUp(title, text)
4921 if (commentShell == NULL) {
4923 CommentCreate(title, text, False, CommentCallback, 4);
4924 XtRealizeWidget(commentShell);
4925 CatchDeleteWindow(commentShell, "CommentPopDown");
4927 edit = XtNameToWidget(commentShell, "*form.text");
4929 XtSetArg(args[j], XtNstring, text); j++;
4930 XtSetValues(edit, args, j);
4932 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4933 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4934 XtSetValues(commentShell, args, j);
4937 XtPopup(commentShell, XtGrabNone);
4938 XSync(xDisplay, False);
4943 void CommentCallback(w, client_data, call_data)
4945 XtPointer client_data, call_data;
4952 XtSetArg(args[j], XtNlabel, &name); j++;
4953 XtGetValues(w, args, j);
4955 if (strcmp(name, _("close")) == 0) {
4957 } else if (strcmp(name, _("edit")) == 0) {
4964 void CommentPopDown()
4969 if (!commentUp) return;
4971 XtSetArg(args[j], XtNx, &commentX); j++;
4972 XtSetArg(args[j], XtNy, &commentY); j++;
4973 XtSetArg(args[j], XtNwidth, &commentW); j++;
4974 XtSetArg(args[j], XtNheight, &commentH); j++;
4975 XtGetValues(commentShell, args, j);
4976 XtPopdown(commentShell);
4977 XSync(xDisplay, False);
4981 void FileNamePopUp(label, def, proc, openMode)
4988 Widget popup, layout, dialog, edit;
4994 fileProc = proc; /* I can't see a way not */
4995 fileOpenMode = openMode; /* to use globals here */
4998 XtSetArg(args[i], XtNresizable, True); i++;
4999 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
5000 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
5001 fileNameShell = popup =
5002 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
5003 shellWidget, args, i);
5006 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
5007 layoutArgs, XtNumber(layoutArgs));
5010 XtSetArg(args[i], XtNlabel, label); i++;
5011 XtSetArg(args[i], XtNvalue, def); i++;
5012 XtSetArg(args[i], XtNborderWidth, 0); i++;
5013 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
5016 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
5017 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
5018 (XtPointer) dialog);
5020 XtRealizeWidget(popup);
5021 CatchDeleteWindow(popup, "FileNamePopDown");
5023 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
5024 &x, &y, &win_x, &win_y, &mask);
5026 XtSetArg(args[0], XtNx, x - 10);
5027 XtSetArg(args[1], XtNy, y - 30);
5028 XtSetValues(popup, args, 2);
5030 XtPopup(popup, XtGrabExclusive);
5033 edit = XtNameToWidget(dialog, "*value");
5034 XtSetKeyboardFocus(popup, edit);
5037 void FileNamePopDown()
5039 if (!filenameUp) return;
5040 XtPopdown(fileNameShell);
5041 XtDestroyWidget(fileNameShell);
5046 void FileNameCallback(w, client_data, call_data)
5048 XtPointer client_data, call_data;
5053 XtSetArg(args[0], XtNlabel, &name);
5054 XtGetValues(w, args, 1);
5056 if (strcmp(name, _("cancel")) == 0) {
5061 FileNameAction(w, NULL, NULL, NULL);
5064 void FileNameAction(w, event, prms, nprms)
5076 name = XawDialogGetValueString(w = XtParent(w));
5078 if ((name != NULL) && (*name != NULLCHAR)) {
5080 XtPopdown(w = XtParent(XtParent(w)));
5084 p = strrchr(buf, ' ');
5091 fullname = ExpandPathName(buf);
5093 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5096 f = fopen(fullname, fileOpenMode);
5098 DisplayError(_("Failed to open file"), errno);
5100 (void) (*fileProc)(f, index, buf);
5107 XtPopdown(w = XtParent(XtParent(w)));
5113 void PromotionPopUp()
5116 Widget dialog, layout;
5118 Dimension bw_width, pw_width;
5122 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5123 XtGetValues(boardWidget, args, j);
5126 XtSetArg(args[j], XtNresizable, True); j++;
5127 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5129 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5130 shellWidget, args, j);
5132 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5133 layoutArgs, XtNumber(layoutArgs));
5136 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5137 XtSetArg(args[j], XtNborderWidth, 0); j++;
5138 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5141 if(gameInfo.variant != VariantShogi) {
5142 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5143 (XtPointer) dialog);
5144 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5145 (XtPointer) dialog);
5146 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5147 (XtPointer) dialog);
5148 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5149 (XtPointer) dialog);
5150 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5151 gameInfo.variant == VariantGiveaway) {
5152 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5153 (XtPointer) dialog);
5155 if(gameInfo.variant == VariantCapablanca ||
5156 gameInfo.variant == VariantGothic ||
5157 gameInfo.variant == VariantCapaRandom) {
5158 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5159 (XtPointer) dialog);
5160 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5161 (XtPointer) dialog);
5163 } else // [HGM] shogi
5165 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5166 (XtPointer) dialog);
5167 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5168 (XtPointer) dialog);
5170 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5171 (XtPointer) dialog);
5173 XtRealizeWidget(promotionShell);
5174 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5177 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5178 XtGetValues(promotionShell, args, j);
5180 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5181 lineGap + squareSize/3 +
5182 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5183 0 : 6*(squareSize + lineGap)), &x, &y);
5186 XtSetArg(args[j], XtNx, x); j++;
5187 XtSetArg(args[j], XtNy, y); j++;
5188 XtSetValues(promotionShell, args, j);
5190 XtPopup(promotionShell, XtGrabNone);
5195 void PromotionPopDown()
5197 if (!promotionUp) return;
5198 XtPopdown(promotionShell);
5199 XtDestroyWidget(promotionShell);
5200 promotionUp = False;
5203 void PromotionCallback(w, client_data, call_data)
5205 XtPointer client_data, call_data;
5211 XtSetArg(args[0], XtNlabel, &name);
5212 XtGetValues(w, args, 1);
5216 if (fromX == -1) return;
5218 if (strcmp(name, _("cancel")) == 0) {
5222 } else if (strcmp(name, _("Knight")) == 0) {
5224 } else if (strcmp(name, _("Promote")) == 0) {
5226 } else if (strcmp(name, _("Defer")) == 0) {
5229 promoChar = ToLower(name[0]);
5232 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5234 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5235 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5240 void ErrorCallback(w, client_data, call_data)
5242 XtPointer client_data, call_data;
5245 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5247 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5253 if (!errorUp) return;
5255 XtPopdown(errorShell);
5256 XtDestroyWidget(errorShell);
5257 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5260 void ErrorPopUp(title, label, modal)
5261 char *title, *label;
5265 Widget dialog, layout;
5269 Dimension bw_width, pw_width;
5270 Dimension pw_height;
5274 XtSetArg(args[i], XtNresizable, True); i++;
5275 XtSetArg(args[i], XtNtitle, title); i++;
5277 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5278 shellWidget, args, i);
5280 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5281 layoutArgs, XtNumber(layoutArgs));
5284 XtSetArg(args[i], XtNlabel, label); i++;
5285 XtSetArg(args[i], XtNborderWidth, 0); i++;
5286 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5289 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5291 XtRealizeWidget(errorShell);
5292 CatchDeleteWindow(errorShell, "ErrorPopDown");
5295 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5296 XtGetValues(boardWidget, args, i);
5298 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5299 XtSetArg(args[i], XtNheight, &pw_height); i++;
5300 XtGetValues(errorShell, args, i);
5303 /* This code seems to tickle an X bug if it is executed too soon
5304 after xboard starts up. The coordinates get transformed as if
5305 the main window was positioned at (0, 0).
5307 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5308 0 - pw_height + squareSize / 3, &x, &y);
5310 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5311 RootWindowOfScreen(XtScreen(boardWidget)),
5312 (bw_width - pw_width) / 2,
5313 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5317 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5320 XtSetArg(args[i], XtNx, x); i++;
5321 XtSetArg(args[i], XtNy, y); i++;
5322 XtSetValues(errorShell, args, i);
5325 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5328 /* Disable all user input other than deleting the window */
5329 static int frozen = 0;
5333 /* Grab by a widget that doesn't accept input */
5334 XtAddGrab(messageWidget, TRUE, FALSE);
5338 /* Undo a FreezeUI */
5341 if (!frozen) return;
5342 XtRemoveGrab(messageWidget);
5346 char *ModeToWidgetName(mode)
5350 case BeginningOfGame:
5351 if (appData.icsActive)
5352 return "menuMode.ICS Client";
5353 else if (appData.noChessProgram ||
5354 *appData.cmailGameName != NULLCHAR)
5355 return "menuMode.Edit Game";
5357 return "menuMode.Machine Black";
5358 case MachinePlaysBlack:
5359 return "menuMode.Machine Black";
5360 case MachinePlaysWhite:
5361 return "menuMode.Machine White";
5363 return "menuMode.Analysis Mode";
5365 return "menuMode.Analyze File";
5366 case TwoMachinesPlay:
5367 return "menuMode.Two Machines";
5369 return "menuMode.Edit Game";
5370 case PlayFromGameFile:
5371 return "menuFile.Load Game";
5373 return "menuMode.Edit Position";
5375 return "menuMode.Training";
5376 case IcsPlayingWhite:
5377 case IcsPlayingBlack:
5381 return "menuMode.ICS Client";
5388 void ModeHighlight()
5391 static int oldPausing = FALSE;
5392 static GameMode oldmode = (GameMode) -1;
5395 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5397 if (pausing != oldPausing) {
5398 oldPausing = pausing;
5400 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5402 XtSetArg(args[0], XtNleftBitmap, None);
5404 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5407 if (appData.showButtonBar) {
5408 /* Always toggle, don't set. Previous code messes up when
5409 invoked while the button is pressed, as releasing it
5410 toggles the state again. */
5413 XtSetArg(args[0], XtNbackground, &oldbg);
5414 XtSetArg(args[1], XtNforeground, &oldfg);
5415 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5417 XtSetArg(args[0], XtNbackground, oldfg);
5418 XtSetArg(args[1], XtNforeground, oldbg);
5420 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5424 wname = ModeToWidgetName(oldmode);
5425 if (wname != NULL) {
5426 XtSetArg(args[0], XtNleftBitmap, None);
5427 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5429 wname = ModeToWidgetName(gameMode);
5430 if (wname != NULL) {
5431 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5432 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5436 /* Maybe all the enables should be handled here, not just this one */
5437 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5438 gameMode == Training || gameMode == PlayFromGameFile);
5443 * Button/menu procedures
5445 void ResetProc(w, event, prms, nprms)
5454 int LoadGamePopUp(f, gameNumber, title)
5459 cmailMsgLoaded = FALSE;
5460 if (gameNumber == 0) {
5461 int error = GameListBuild(f);
5463 DisplayError(_("Cannot build game list"), error);
5464 } else if (!ListEmpty(&gameList) &&
5465 ((ListGame *) gameList.tailPred)->number > 1) {
5466 GameListPopUp(f, title);
5472 return LoadGame(f, gameNumber, title, FALSE);
5475 void LoadGameProc(w, event, prms, nprms)
5481 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5484 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5487 void LoadNextGameProc(w, event, prms, nprms)
5496 void LoadPrevGameProc(w, event, prms, nprms)
5505 void ReloadGameProc(w, event, prms, nprms)
5514 void LoadNextPositionProc(w, event, prms, nprms)
5523 void LoadPrevPositionProc(w, event, prms, nprms)
5532 void ReloadPositionProc(w, event, prms, nprms)
5541 void LoadPositionProc(w, event, prms, nprms)
5547 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5550 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5553 void SaveGameProc(w, event, prms, nprms)
5559 FileNamePopUp(_("Save game file name?"),
5560 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5564 void SavePositionProc(w, event, prms, nprms)
5570 FileNamePopUp(_("Save position file name?"),
5571 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5575 void ReloadCmailMsgProc(w, event, prms, nprms)
5581 ReloadCmailMsgEvent(FALSE);
5584 void MailMoveProc(w, event, prms, nprms)
5593 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5594 char *selected_fen_position=NULL;
5597 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5598 Atom *type_return, XtPointer *value_return,
5599 unsigned long *length_return, int *format_return)
5601 char *selection_tmp;
5603 if (!selected_fen_position) return False; /* should never happen */
5604 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5605 /* note: since no XtSelectionDoneProc was registered, Xt will
5606 * automatically call XtFree on the value returned. So have to
5607 * make a copy of it allocated with XtMalloc */
5608 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5609 strcpy(selection_tmp, selected_fen_position);
5611 *value_return=selection_tmp;
5612 *length_return=strlen(selection_tmp);
5613 *type_return=*target;
5614 *format_return = 8; /* bits per byte */
5616 } else if (*target == XA_TARGETS(xDisplay)) {
5617 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5618 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5619 targets_tmp[1] = XA_STRING;
5620 *value_return = targets_tmp;
5621 *type_return = XA_ATOM;
5623 *format_return = 8 * sizeof(Atom);
5624 if (*format_return > 32) {
5625 *length_return *= *format_return / 32;
5626 *format_return = 32;
5634 /* note: when called from menu all parameters are NULL, so no clue what the
5635 * Widget which was clicked on was, or what the click event was
5637 void CopyPositionProc(w, event, prms, nprms)
5644 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5645 * have a notion of a position that is selected but not copied.
5646 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5648 if(gameMode == EditPosition) EditPositionDone(TRUE);
5649 if (selected_fen_position) free(selected_fen_position);
5650 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5651 if (!selected_fen_position) return;
5652 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5654 SendPositionSelection,
5655 NULL/* lose_ownership_proc */ ,
5656 NULL/* transfer_done_proc */);
5657 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5659 SendPositionSelection,
5660 NULL/* lose_ownership_proc */ ,
5661 NULL/* transfer_done_proc */);
5664 /* function called when the data to Paste is ready */
5666 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5667 Atom *type, XtPointer value, unsigned long *len, int *format)
5670 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5671 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5672 EditPositionPasteFEN(fenstr);
5676 /* called when Paste Position button is pressed,
5677 * all parameters will be NULL */
5678 void PastePositionProc(w, event, prms, nprms)
5684 XtGetSelectionValue(menuBarWidget,
5685 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5686 /* (XtSelectionCallbackProc) */ PastePositionCB,
5687 NULL, /* client_data passed to PastePositionCB */
5689 /* better to use the time field from the event that triggered the
5690 * call to this function, but that isn't trivial to get
5698 SendGameSelection(Widget w, Atom *selection, Atom *target,
5699 Atom *type_return, XtPointer *value_return,
5700 unsigned long *length_return, int *format_return)
5702 char *selection_tmp;
5704 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5705 FILE* f = fopen(gameCopyFilename, "r");
5708 if (f == NULL) return False;
5712 selection_tmp = XtMalloc(len + 1);
5713 count = fread(selection_tmp, 1, len, f);
5715 XtFree(selection_tmp);
5718 selection_tmp[len] = NULLCHAR;
5719 *value_return = selection_tmp;
5720 *length_return = len;
5721 *type_return = *target;
5722 *format_return = 8; /* bits per byte */
5724 } else if (*target == XA_TARGETS(xDisplay)) {
5725 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5726 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5727 targets_tmp[1] = XA_STRING;
5728 *value_return = targets_tmp;
5729 *type_return = XA_ATOM;
5731 *format_return = 8 * sizeof(Atom);
5732 if (*format_return > 32) {
5733 *length_return *= *format_return / 32;
5734 *format_return = 32;
5742 /* note: when called from menu all parameters are NULL, so no clue what the
5743 * Widget which was clicked on was, or what the click event was
5745 void CopyGameProc(w, event, prms, nprms)
5753 ret = SaveGameToFile(gameCopyFilename, FALSE);
5757 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5758 * have a notion of a game that is selected but not copied.
5759 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5761 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5764 NULL/* lose_ownership_proc */ ,
5765 NULL/* transfer_done_proc */);
5766 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5769 NULL/* lose_ownership_proc */ ,
5770 NULL/* transfer_done_proc */);
5773 /* function called when the data to Paste is ready */
5775 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5776 Atom *type, XtPointer value, unsigned long *len, int *format)
5779 if (value == NULL || *len == 0) {
5780 return; /* nothing had been selected to copy */
5782 f = fopen(gamePasteFilename, "w");
5784 DisplayError(_("Can't open temp file"), errno);
5787 fwrite(value, 1, *len, f);
5790 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5793 /* called when Paste Game button is pressed,
5794 * all parameters will be NULL */
5795 void PasteGameProc(w, event, prms, nprms)
5801 XtGetSelectionValue(menuBarWidget,
5802 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5803 /* (XtSelectionCallbackProc) */ PasteGameCB,
5804 NULL, /* client_data passed to PasteGameCB */
5806 /* better to use the time field from the event that triggered the
5807 * call to this function, but that isn't trivial to get
5817 SaveGameProc(NULL, NULL, NULL, NULL);
5821 void QuitProc(w, event, prms, nprms)
5830 void PauseProc(w, event, prms, nprms)
5840 void MachineBlackProc(w, event, prms, nprms)
5846 MachineBlackEvent();
5849 void MachineWhiteProc(w, event, prms, nprms)
5855 MachineWhiteEvent();
5858 void AnalyzeModeProc(w, event, prms, nprms)
5866 if (!first.analysisSupport) {
5867 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5868 DisplayError(buf, 0);
5871 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5872 if (appData.icsActive) {
5873 if (gameMode != IcsObserving) {
5874 sprintf(buf,_("You are not observing a game"));
5875 DisplayError(buf, 0);
5877 if (appData.icsEngineAnalyze) {
5878 if (appData.debugMode)
5879 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5885 /* if enable, use want disable icsEngineAnalyze */
5886 if (appData.icsEngineAnalyze) {
5891 appData.icsEngineAnalyze = TRUE;
5892 if (appData.debugMode)
5893 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5895 if (!appData.showThinking)
5896 ShowThinkingProc(w,event,prms,nprms);
5901 void AnalyzeFileProc(w, event, prms, nprms)
5907 if (!first.analysisSupport) {
5909 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5910 DisplayError(buf, 0);
5915 if (!appData.showThinking)
5916 ShowThinkingProc(w,event,prms,nprms);
5919 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5920 AnalysisPeriodicEvent(1);
5923 void TwoMachinesProc(w, event, prms, nprms)
5932 void IcsClientProc(w, event, prms, nprms)
5941 void EditGameProc(w, event, prms, nprms)
5950 void EditPositionProc(w, event, prms, nprms)
5956 EditPositionEvent();
5959 void TrainingProc(w, event, prms, nprms)
5968 void EditCommentProc(w, event, prms, nprms)
5975 EditCommentPopDown();
5981 void IcsInputBoxProc(w, event, prms, nprms)
5987 if (ICSInputBoxUp) {
5988 ICSInputBoxPopDown();
5994 void AcceptProc(w, event, prms, nprms)
6003 void DeclineProc(w, event, prms, nprms)
6012 void RematchProc(w, event, prms, nprms)
6021 void CallFlagProc(w, event, prms, nprms)
6030 void DrawProc(w, event, prms, nprms)
6039 void AbortProc(w, event, prms, nprms)
6048 void AdjournProc(w, event, prms, nprms)
6057 void ResignProc(w, event, prms, nprms)
6066 void AdjuWhiteProc(w, event, prms, nprms)
6072 UserAdjudicationEvent(+1);
6075 void AdjuBlackProc(w, event, prms, nprms)
6081 UserAdjudicationEvent(-1);
6084 void AdjuDrawProc(w, event, prms, nprms)
6090 UserAdjudicationEvent(0);
6093 void EnterKeyProc(w, event, prms, nprms)
6099 if (ICSInputBoxUp == True)
6103 void StopObservingProc(w, event, prms, nprms)
6109 StopObservingEvent();
6112 void StopExaminingProc(w, event, prms, nprms)
6118 StopExaminingEvent();
6122 void ForwardProc(w, event, prms, nprms)
6132 void BackwardProc(w, event, prms, nprms)
6141 void ToStartProc(w, event, prms, nprms)
6150 void ToEndProc(w, event, prms, nprms)
6159 void RevertProc(w, event, prms, nprms)
6168 void TruncateGameProc(w, event, prms, nprms)
6174 TruncateGameEvent();
6176 void RetractMoveProc(w, event, prms, nprms)
6185 void MoveNowProc(w, event, prms, nprms)
6195 void AlwaysQueenProc(w, event, prms, nprms)
6203 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6205 if (appData.alwaysPromoteToQueen) {
6206 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6208 XtSetArg(args[0], XtNleftBitmap, None);
6210 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6214 void AnimateDraggingProc(w, event, prms, nprms)
6222 appData.animateDragging = !appData.animateDragging;
6224 if (appData.animateDragging) {
6225 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6228 XtSetArg(args[0], XtNleftBitmap, None);
6230 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6234 void AnimateMovingProc(w, event, prms, nprms)
6242 appData.animate = !appData.animate;
6244 if (appData.animate) {
6245 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6248 XtSetArg(args[0], XtNleftBitmap, None);
6250 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6254 void AutocommProc(w, event, prms, nprms)
6262 appData.autoComment = !appData.autoComment;
6264 if (appData.autoComment) {
6265 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6267 XtSetArg(args[0], XtNleftBitmap, None);
6269 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6274 void AutoflagProc(w, event, prms, nprms)
6282 appData.autoCallFlag = !appData.autoCallFlag;
6284 if (appData.autoCallFlag) {
6285 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6287 XtSetArg(args[0], XtNleftBitmap, None);
6289 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6293 void AutoflipProc(w, event, prms, nprms)
6301 appData.autoFlipView = !appData.autoFlipView;
6303 if (appData.autoFlipView) {
6304 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6306 XtSetArg(args[0], XtNleftBitmap, None);
6308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6312 void AutobsProc(w, event, prms, nprms)
6320 appData.autoObserve = !appData.autoObserve;
6322 if (appData.autoObserve) {
6323 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6325 XtSetArg(args[0], XtNleftBitmap, None);
6327 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6331 void AutoraiseProc(w, event, prms, nprms)
6339 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6341 if (appData.autoRaiseBoard) {
6342 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6344 XtSetArg(args[0], XtNleftBitmap, None);
6346 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6350 void AutosaveProc(w, event, prms, nprms)
6358 appData.autoSaveGames = !appData.autoSaveGames;
6360 if (appData.autoSaveGames) {
6361 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6363 XtSetArg(args[0], XtNleftBitmap, None);
6365 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6369 void BlindfoldProc(w, event, prms, nprms)
6377 appData.blindfold = !appData.blindfold;
6379 if (appData.blindfold) {
6380 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6382 XtSetArg(args[0], XtNleftBitmap, None);
6384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6387 DrawPosition(True, NULL);
6390 void TestLegalityProc(w, event, prms, nprms)
6398 appData.testLegality = !appData.testLegality;
6400 if (appData.testLegality) {
6401 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6403 XtSetArg(args[0], XtNleftBitmap, None);
6405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6410 void FlashMovesProc(w, event, prms, nprms)
6418 if (appData.flashCount == 0) {
6419 appData.flashCount = 3;
6421 appData.flashCount = -appData.flashCount;
6424 if (appData.flashCount > 0) {
6425 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6427 XtSetArg(args[0], XtNleftBitmap, None);
6429 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6433 void FlipViewProc(w, event, prms, nprms)
6439 flipView = !flipView;
6440 DrawPosition(True, NULL);
6443 void GetMoveListProc(w, event, prms, nprms)
6451 appData.getMoveList = !appData.getMoveList;
6453 if (appData.getMoveList) {
6454 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6457 XtSetArg(args[0], XtNleftBitmap, None);
6459 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6464 void HighlightDraggingProc(w, event, prms, nprms)
6472 appData.highlightDragging = !appData.highlightDragging;
6474 if (appData.highlightDragging) {
6475 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6477 XtSetArg(args[0], XtNleftBitmap, None);
6479 XtSetValues(XtNameToWidget(menuBarWidget,
6480 "menuOptions.Highlight Dragging"), args, 1);
6484 void HighlightLastMoveProc(w, event, prms, nprms)
6492 appData.highlightLastMove = !appData.highlightLastMove;
6494 if (appData.highlightLastMove) {
6495 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6497 XtSetArg(args[0], XtNleftBitmap, None);
6499 XtSetValues(XtNameToWidget(menuBarWidget,
6500 "menuOptions.Highlight Last Move"), args, 1);
6503 void IcsAlarmProc(w, event, prms, nprms)
6511 appData.icsAlarm = !appData.icsAlarm;
6513 if (appData.icsAlarm) {
6514 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6516 XtSetArg(args[0], XtNleftBitmap, None);
6518 XtSetValues(XtNameToWidget(menuBarWidget,
6519 "menuOptions.ICS Alarm"), args, 1);
6522 void MoveSoundProc(w, event, prms, nprms)
6530 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6532 if (appData.ringBellAfterMoves) {
6533 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6535 XtSetArg(args[0], XtNleftBitmap, None);
6537 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6542 void OldSaveStyleProc(w, event, prms, nprms)
6550 appData.oldSaveStyle = !appData.oldSaveStyle;
6552 if (appData.oldSaveStyle) {
6553 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6555 XtSetArg(args[0], XtNleftBitmap, None);
6557 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6561 void PeriodicUpdatesProc(w, event, prms, nprms)
6569 PeriodicUpdatesEvent(!appData.periodicUpdates);
6571 if (appData.periodicUpdates) {
6572 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6574 XtSetArg(args[0], XtNleftBitmap, None);
6576 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6580 void PonderNextMoveProc(w, event, prms, nprms)
6588 PonderNextMoveEvent(!appData.ponderNextMove);
6590 if (appData.ponderNextMove) {
6591 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6593 XtSetArg(args[0], XtNleftBitmap, None);
6595 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6599 void PopupExitMessageProc(w, event, prms, nprms)
6607 appData.popupExitMessage = !appData.popupExitMessage;
6609 if (appData.popupExitMessage) {
6610 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6612 XtSetArg(args[0], XtNleftBitmap, None);
6614 XtSetValues(XtNameToWidget(menuBarWidget,
6615 "menuOptions.Popup Exit Message"), args, 1);
6618 void PopupMoveErrorsProc(w, event, prms, nprms)
6626 appData.popupMoveErrors = !appData.popupMoveErrors;
6628 if (appData.popupMoveErrors) {
6629 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6631 XtSetArg(args[0], XtNleftBitmap, None);
6633 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6637 void PremoveProc(w, event, prms, nprms)
6645 appData.premove = !appData.premove;
6647 if (appData.premove) {
6648 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6650 XtSetArg(args[0], XtNleftBitmap, None);
6652 XtSetValues(XtNameToWidget(menuBarWidget,
6653 "menuOptions.Premove"), args, 1);
6656 void QuietPlayProc(w, event, prms, nprms)
6664 appData.quietPlay = !appData.quietPlay;
6666 if (appData.quietPlay) {
6667 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6669 XtSetArg(args[0], XtNleftBitmap, None);
6671 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6675 void ShowCoordsProc(w, event, prms, nprms)
6683 appData.showCoords = !appData.showCoords;
6685 if (appData.showCoords) {
6686 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6688 XtSetArg(args[0], XtNleftBitmap, None);
6690 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6693 DrawPosition(True, NULL);
6696 void ShowThinkingProc(w, event, prms, nprms)
6702 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6703 ShowThinkingEvent();
6706 void HideThinkingProc(w, event, prms, nprms)
6714 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6715 ShowThinkingEvent();
6717 if (appData.hideThinkingFromHuman) {
6718 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6720 XtSetArg(args[0], XtNleftBitmap, None);
6722 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6726 void SaveOnExitProc(w, event, prms, nprms)
6734 saveSettingsOnExit = !saveSettingsOnExit;
6736 if (saveSettingsOnExit) {
6737 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6739 XtSetArg(args[0], XtNleftBitmap, None);
6741 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6745 void SaveSettingsProc(w, event, prms, nprms)
6751 SaveSettings(settingsFileName);
6754 void InfoProc(w, event, prms, nprms)
6761 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6766 void ManProc(w, event, prms, nprms)
6774 if (nprms && *nprms > 0)
6778 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6782 void HintProc(w, event, prms, nprms)
6791 void BookProc(w, event, prms, nprms)
6800 void AboutProc(w, event, prms, nprms)
6808 char *zippy = " (with Zippy code)";
6812 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6813 programVersion, zippy,
6814 "Copyright 1991 Digital Equipment Corporation",
6815 "Enhancements Copyright 1992-2009 Free Software Foundation",
6816 "Enhancements Copyright 2005 Alessandro Scotti",
6817 PACKAGE, " is free software and carries NO WARRANTY;",
6818 "see the file COPYING for more information.");
6819 ErrorPopUp(_("About XBoard"), buf, FALSE);
6822 void DebugProc(w, event, prms, nprms)
6828 appData.debugMode = !appData.debugMode;
6831 void AboutGameProc(w, event, prms, nprms)
6840 void NothingProc(w, event, prms, nprms)
6849 void Iconify(w, event, prms, nprms)
6858 XtSetArg(args[0], XtNiconic, True);
6859 XtSetValues(shellWidget, args, 1);
6862 void DisplayMessage(message, extMessage)
6863 char *message, *extMessage;
6865 /* display a message in the message widget */
6874 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6879 message = extMessage;
6883 /* need to test if messageWidget already exists, since this function
6884 can also be called during the startup, if for example a Xresource
6885 is not set up correctly */
6888 XtSetArg(arg, XtNlabel, message);
6889 XtSetValues(messageWidget, &arg, 1);
6895 void DisplayTitle(text)
6900 char title[MSG_SIZ];
6903 if (text == NULL) text = "";
6905 if (appData.titleInWindow) {
6907 XtSetArg(args[i], XtNlabel, text); i++;
6908 XtSetValues(titleWidget, args, i);
6911 if (*text != NULLCHAR) {
6913 strcpy(title, text);
6914 } else if (appData.icsActive) {
6915 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6916 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6917 } else if (appData.cmailGameName[0] != NULLCHAR) {
6918 snprintf(icon, sizeof(icon), "%s", "CMail");
6919 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6921 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6922 } else if (gameInfo.variant == VariantGothic) {
6923 strcpy(icon, programName);
6924 strcpy(title, GOTHIC);
6927 } else if (gameInfo.variant == VariantFalcon) {
6928 strcpy(icon, programName);
6929 strcpy(title, FALCON);
6931 } else if (appData.noChessProgram) {
6932 strcpy(icon, programName);
6933 strcpy(title, programName);
6935 strcpy(icon, first.tidy);
6936 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6939 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6940 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6941 XtSetValues(shellWidget, args, i);
6945 void DisplayError(message, error)
6952 if (appData.debugMode || appData.matchMode) {
6953 fprintf(stderr, "%s: %s\n", programName, message);
6956 if (appData.debugMode || appData.matchMode) {
6957 fprintf(stderr, "%s: %s: %s\n",
6958 programName, message, strerror(error));
6960 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6963 ErrorPopUp(_("Error"), message, FALSE);
6967 void DisplayMoveError(message)
6972 DrawPosition(FALSE, NULL);
6973 if (appData.debugMode || appData.matchMode) {
6974 fprintf(stderr, "%s: %s\n", programName, message);
6976 if (appData.popupMoveErrors) {
6977 ErrorPopUp(_("Error"), message, FALSE);
6979 DisplayMessage(message, "");
6984 void DisplayFatalError(message, error, status)
6990 errorExitStatus = status;
6992 fprintf(stderr, "%s: %s\n", programName, message);
6994 fprintf(stderr, "%s: %s: %s\n",
6995 programName, message, strerror(error));
6996 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6999 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7000 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7006 void DisplayInformation(message)
7010 ErrorPopUp(_("Information"), message, TRUE);
7013 void DisplayNote(message)
7017 ErrorPopUp(_("Note"), message, FALSE);
7021 NullXErrorCheck(dpy, error_event)
7023 XErrorEvent *error_event;
7028 void DisplayIcsInteractionTitle(message)
7031 if (oldICSInteractionTitle == NULL) {
7032 /* Magic to find the old window title, adapted from vim */
7033 char *wina = getenv("WINDOWID");
7035 Window win = (Window) atoi(wina);
7036 Window root, parent, *children;
7037 unsigned int nchildren;
7038 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7040 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7041 if (!XQueryTree(xDisplay, win, &root, &parent,
7042 &children, &nchildren)) break;
7043 if (children) XFree((void *)children);
7044 if (parent == root || parent == 0) break;
7047 XSetErrorHandler(oldHandler);
7049 if (oldICSInteractionTitle == NULL) {
7050 oldICSInteractionTitle = "xterm";
7053 printf("\033]0;%s\007", message);
7057 char pendingReplyPrefix[MSG_SIZ];
7058 ProcRef pendingReplyPR;
7060 void AskQuestionProc(w, event, prms, nprms)
7067 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7071 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7074 void AskQuestionPopDown()
7076 if (!askQuestionUp) return;
7077 XtPopdown(askQuestionShell);
7078 XtDestroyWidget(askQuestionShell);
7079 askQuestionUp = False;
7082 void AskQuestionReplyAction(w, event, prms, nprms)
7092 reply = XawDialogGetValueString(w = XtParent(w));
7093 strcpy(buf, pendingReplyPrefix);
7094 if (*buf) strcat(buf, " ");
7097 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7098 AskQuestionPopDown();
7100 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7103 void AskQuestionCallback(w, client_data, call_data)
7105 XtPointer client_data, call_data;
7110 XtSetArg(args[0], XtNlabel, &name);
7111 XtGetValues(w, args, 1);
7113 if (strcmp(name, _("cancel")) == 0) {
7114 AskQuestionPopDown();
7116 AskQuestionReplyAction(w, NULL, NULL, NULL);
7120 void AskQuestion(title, question, replyPrefix, pr)
7121 char *title, *question, *replyPrefix;
7125 Widget popup, layout, dialog, edit;
7131 strcpy(pendingReplyPrefix, replyPrefix);
7132 pendingReplyPR = pr;
7135 XtSetArg(args[i], XtNresizable, True); i++;
7136 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7137 askQuestionShell = popup =
7138 XtCreatePopupShell(title, transientShellWidgetClass,
7139 shellWidget, args, i);
7142 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7143 layoutArgs, XtNumber(layoutArgs));
7146 XtSetArg(args[i], XtNlabel, question); i++;
7147 XtSetArg(args[i], XtNvalue, ""); i++;
7148 XtSetArg(args[i], XtNborderWidth, 0); i++;
7149 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7152 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7153 (XtPointer) dialog);
7154 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7155 (XtPointer) dialog);
7157 XtRealizeWidget(popup);
7158 CatchDeleteWindow(popup, "AskQuestionPopDown");
7160 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7161 &x, &y, &win_x, &win_y, &mask);
7163 XtSetArg(args[0], XtNx, x - 10);
7164 XtSetArg(args[1], XtNy, y - 30);
7165 XtSetValues(popup, args, 2);
7167 XtPopup(popup, XtGrabExclusive);
7168 askQuestionUp = True;
7170 edit = XtNameToWidget(dialog, "*value");
7171 XtSetKeyboardFocus(popup, edit);
7179 if (*name == NULLCHAR) {
7181 } else if (strcmp(name, "$") == 0) {
7182 putc(BELLCHAR, stderr);
7185 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7193 PlaySound(appData.soundMove);
7199 PlaySound(appData.soundIcsWin);
7205 PlaySound(appData.soundIcsLoss);
7211 PlaySound(appData.soundIcsDraw);
7215 PlayIcsUnfinishedSound()
7217 PlaySound(appData.soundIcsUnfinished);
7223 PlaySound(appData.soundIcsAlarm);
7229 system("stty echo");
7235 system("stty -echo");
7239 Colorize(cc, continuation)
7244 int count, outCount, error;
7246 if (textColors[(int)cc].bg > 0) {
7247 if (textColors[(int)cc].fg > 0) {
7248 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7249 textColors[(int)cc].fg, textColors[(int)cc].bg);
7251 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7252 textColors[(int)cc].bg);
7255 if (textColors[(int)cc].fg > 0) {
7256 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7257 textColors[(int)cc].fg);
7259 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7262 count = strlen(buf);
7263 outCount = OutputToProcess(NoProc, buf, count, &error);
7264 if (outCount < count) {
7265 DisplayFatalError(_("Error writing to display"), error, 1);
7268 if (continuation) return;
7271 PlaySound(appData.soundShout);
7274 PlaySound(appData.soundSShout);
7277 PlaySound(appData.soundChannel1);
7280 PlaySound(appData.soundChannel);
7283 PlaySound(appData.soundKibitz);
7286 PlaySound(appData.soundTell);
7288 case ColorChallenge:
7289 PlaySound(appData.soundChallenge);
7292 PlaySound(appData.soundRequest);
7295 PlaySound(appData.soundSeek);
7306 return getpwuid(getuid())->pw_name;
7309 static char *ExpandPathName(path)
7312 static char static_buf[2000];
7313 char *d, *s, buf[2000];
7319 while (*s && isspace(*s))
7328 if (*(s+1) == '/') {
7329 strcpy(d, getpwuid(getuid())->pw_dir);
7334 *strchr(buf, '/') = 0;
7335 pwd = getpwnam(buf);
7338 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7342 strcpy(d, pwd->pw_dir);
7343 strcat(d, strchr(s+1, '/'));
7354 static char host_name[MSG_SIZ];
7356 #if HAVE_GETHOSTNAME
7357 gethostname(host_name, MSG_SIZ);
7359 #else /* not HAVE_GETHOSTNAME */
7360 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7361 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7363 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7365 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7366 #endif /* not HAVE_GETHOSTNAME */
7369 XtIntervalId delayedEventTimerXID = 0;
7370 DelayedEventCallback delayedEventCallback = 0;
7375 delayedEventTimerXID = 0;
7376 delayedEventCallback();
7380 ScheduleDelayedEvent(cb, millisec)
7381 DelayedEventCallback cb; long millisec;
7383 if(delayedEventTimerXID && delayedEventCallback == cb)
7384 // [HGM] alive: replace, rather than add or flush identical event
7385 XtRemoveTimeOut(delayedEventTimerXID);
7386 delayedEventCallback = cb;
7387 delayedEventTimerXID =
7388 XtAppAddTimeOut(appContext, millisec,
7389 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7392 DelayedEventCallback
7395 if (delayedEventTimerXID) {
7396 return delayedEventCallback;
7403 CancelDelayedEvent()
7405 if (delayedEventTimerXID) {
7406 XtRemoveTimeOut(delayedEventTimerXID);
7407 delayedEventTimerXID = 0;
7411 XtIntervalId loadGameTimerXID = 0;
7413 int LoadGameTimerRunning()
7415 return loadGameTimerXID != 0;
7418 int StopLoadGameTimer()
7420 if (loadGameTimerXID != 0) {
7421 XtRemoveTimeOut(loadGameTimerXID);
7422 loadGameTimerXID = 0;
7430 LoadGameTimerCallback(arg, id)
7434 loadGameTimerXID = 0;
7439 StartLoadGameTimer(millisec)
7443 XtAppAddTimeOut(appContext, millisec,
7444 (XtTimerCallbackProc) LoadGameTimerCallback,
7448 XtIntervalId analysisClockXID = 0;
7451 AnalysisClockCallback(arg, id)
7455 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7456 || appData.icsEngineAnalyze) { // [DM]
7457 AnalysisPeriodicEvent(0);
7458 StartAnalysisClock();
7463 StartAnalysisClock()
7466 XtAppAddTimeOut(appContext, 2000,
7467 (XtTimerCallbackProc) AnalysisClockCallback,
7471 XtIntervalId clockTimerXID = 0;
7473 int ClockTimerRunning()
7475 return clockTimerXID != 0;
7478 int StopClockTimer()
7480 if (clockTimerXID != 0) {
7481 XtRemoveTimeOut(clockTimerXID);
7490 ClockTimerCallback(arg, id)
7499 StartClockTimer(millisec)
7503 XtAppAddTimeOut(appContext, millisec,
7504 (XtTimerCallbackProc) ClockTimerCallback,
7509 DisplayTimerLabel(w, color, timer, highlight)
7518 /* check for low time warning */
7519 Pixel foregroundOrWarningColor = timerForegroundPixel;
7522 appData.lowTimeWarning &&
7523 (timer / 1000) < appData.icsAlarmTime)
7524 foregroundOrWarningColor = lowTimeWarningColor;
7526 if (appData.clockMode) {
7527 sprintf(buf, "%s: %s", color, TimeString(timer));
7528 XtSetArg(args[0], XtNlabel, buf);
7530 sprintf(buf, "%s ", color);
7531 XtSetArg(args[0], XtNlabel, buf);
7536 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7537 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7539 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7540 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7543 XtSetValues(w, args, 3);
7547 DisplayWhiteClock(timeRemaining, highlight)
7553 if(appData.noGUI) return;
7554 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7555 if (highlight && iconPixmap == bIconPixmap) {
7556 iconPixmap = wIconPixmap;
7557 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7558 XtSetValues(shellWidget, args, 1);
7563 DisplayBlackClock(timeRemaining, highlight)
7569 if(appData.noGUI) return;
7570 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7571 if (highlight && iconPixmap == wIconPixmap) {
7572 iconPixmap = bIconPixmap;
7573 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7574 XtSetValues(shellWidget, args, 1);
7592 int StartChildProcess(cmdLine, dir, pr)
7599 int to_prog[2], from_prog[2];
7603 if (appData.debugMode) {
7604 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7607 /* We do NOT feed the cmdLine to the shell; we just
7608 parse it into blank-separated arguments in the
7609 most simple-minded way possible.
7612 strcpy(buf, cmdLine);
7615 while(*p == ' ') p++;
7617 if(*p == '"' || *p == '\'')
7618 p = strchr(++argv[i-1], *p);
7619 else p = strchr(p, ' ');
7620 if (p == NULL) break;
7625 SetUpChildIO(to_prog, from_prog);
7627 if ((pid = fork()) == 0) {
7629 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7630 close(to_prog[1]); // first close the unused pipe ends
7631 close(from_prog[0]);
7632 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7633 dup2(from_prog[1], 1);
7634 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7635 close(from_prog[1]); // and closing again loses one of the pipes!
7636 if(fileno(stderr) >= 2) // better safe than sorry...
7637 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7639 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7644 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7646 execvp(argv[0], argv);
7648 /* If we get here, exec failed */
7653 /* Parent process */
7655 close(from_prog[1]);
7657 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7660 cp->fdFrom = from_prog[0];
7661 cp->fdTo = to_prog[1];
7666 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7667 static RETSIGTYPE AlarmCallBack(int n)
7673 DestroyChildProcess(pr, signalType)
7677 ChildProc *cp = (ChildProc *) pr;
7679 if (cp->kind != CPReal) return;
7681 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7682 signal(SIGALRM, AlarmCallBack);
7684 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7685 kill(cp->pid, SIGKILL); // kill it forcefully
7686 wait((int *) 0); // and wait again
7690 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7692 /* Process is exiting either because of the kill or because of
7693 a quit command sent by the backend; either way, wait for it to die.
7702 InterruptChildProcess(pr)
7705 ChildProc *cp = (ChildProc *) pr;
7707 if (cp->kind != CPReal) return;
7708 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7711 int OpenTelnet(host, port, pr)
7716 char cmdLine[MSG_SIZ];
7718 if (port[0] == NULLCHAR) {
7719 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7721 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7723 return StartChildProcess(cmdLine, "", pr);
7726 int OpenTCP(host, port, pr)
7732 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7733 #else /* !OMIT_SOCKETS */
7735 struct sockaddr_in sa;
7737 unsigned short uport;
7740 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7744 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7745 sa.sin_family = AF_INET;
7746 sa.sin_addr.s_addr = INADDR_ANY;
7747 uport = (unsigned short) 0;
7748 sa.sin_port = htons(uport);
7749 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7753 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7754 if (!(hp = gethostbyname(host))) {
7756 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7757 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7758 hp->h_addrtype = AF_INET;
7760 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7761 hp->h_addr_list[0] = (char *) malloc(4);
7762 hp->h_addr_list[0][0] = b0;
7763 hp->h_addr_list[0][1] = b1;
7764 hp->h_addr_list[0][2] = b2;
7765 hp->h_addr_list[0][3] = b3;
7770 sa.sin_family = hp->h_addrtype;
7771 uport = (unsigned short) atoi(port);
7772 sa.sin_port = htons(uport);
7773 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7775 if (connect(s, (struct sockaddr *) &sa,
7776 sizeof(struct sockaddr_in)) < 0) {
7780 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7787 #endif /* !OMIT_SOCKETS */
7792 int OpenCommPort(name, pr)
7799 fd = open(name, 2, 0);
7800 if (fd < 0) return errno;
7802 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7812 int OpenLoopback(pr)
7818 SetUpChildIO(to, from);
7820 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7823 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7830 int OpenRcmd(host, user, cmd, pr)
7831 char *host, *user, *cmd;
7834 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7838 #define INPUT_SOURCE_BUF_SIZE 8192
7847 char buf[INPUT_SOURCE_BUF_SIZE];
7852 DoInputCallback(closure, source, xid)
7857 InputSource *is = (InputSource *) closure;
7862 if (is->lineByLine) {
7863 count = read(is->fd, is->unused,
7864 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7866 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7869 is->unused += count;
7871 while (p < is->unused) {
7872 q = memchr(p, '\n', is->unused - p);
7873 if (q == NULL) break;
7875 (is->func)(is, is->closure, p, q - p, 0);
7879 while (p < is->unused) {
7884 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7889 (is->func)(is, is->closure, is->buf, count, error);
7893 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7900 ChildProc *cp = (ChildProc *) pr;
7902 is = (InputSource *) calloc(1, sizeof(InputSource));
7903 is->lineByLine = lineByLine;
7907 is->fd = fileno(stdin);
7909 is->kind = cp->kind;
7910 is->fd = cp->fdFrom;
7913 is->unused = is->buf;
7916 is->xid = XtAppAddInput(appContext, is->fd,
7917 (XtPointer) (XtInputReadMask),
7918 (XtInputCallbackProc) DoInputCallback,
7920 is->closure = closure;
7921 return (InputSourceRef) is;
7925 RemoveInputSource(isr)
7928 InputSource *is = (InputSource *) isr;
7930 if (is->xid == 0) return;
7931 XtRemoveInput(is->xid);
7935 int OutputToProcess(pr, message, count, outError)
7941 static int line = 0;
7942 ChildProc *cp = (ChildProc *) pr;
7947 if (appData.noJoin || !appData.useInternalWrap)
7948 outCount = fwrite(message, 1, count, stdout);
7951 int width = get_term_width();
7952 int len = wrap(NULL, message, count, width, &line);
7953 char *msg = malloc(len);
7957 outCount = fwrite(message, 1, count, stdout);
7960 dbgchk = wrap(msg, message, count, width, &line);
7961 if (dbgchk != len && appData.debugMode)
7962 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7963 outCount = fwrite(msg, 1, dbgchk, stdout);
7969 outCount = write(cp->fdTo, message, count);
7979 /* Output message to process, with "ms" milliseconds of delay
7980 between each character. This is needed when sending the logon
7981 script to ICC, which for some reason doesn't like the
7982 instantaneous send. */
7983 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7990 ChildProc *cp = (ChildProc *) pr;
7995 r = write(cp->fdTo, message++, 1);
8008 /**** Animation code by Hugh Fisher, DCS, ANU.
8010 Known problem: if a window overlapping the board is
8011 moved away while a piece is being animated underneath,
8012 the newly exposed area won't be updated properly.
8013 I can live with this.
8015 Known problem: if you look carefully at the animation
8016 of pieces in mono mode, they are being drawn as solid
8017 shapes without interior detail while moving. Fixing
8018 this would be a major complication for minimal return.
8021 /* Masks for XPM pieces. Black and white pieces can have
8022 different shapes, but in the interest of retaining my
8023 sanity pieces must have the same outline on both light
8024 and dark squares, and all pieces must use the same
8025 background square colors/images. */
8027 static int xpmDone = 0;
8030 CreateAnimMasks (pieceDepth)
8037 unsigned long plane;
8040 /* Need a bitmap just to get a GC with right depth */
8041 buf = XCreatePixmap(xDisplay, xBoardWindow,
8043 values.foreground = 1;
8044 values.background = 0;
8045 /* Don't use XtGetGC, not read only */
8046 maskGC = XCreateGC(xDisplay, buf,
8047 GCForeground | GCBackground, &values);
8048 XFreePixmap(xDisplay, buf);
8050 buf = XCreatePixmap(xDisplay, xBoardWindow,
8051 squareSize, squareSize, pieceDepth);
8052 values.foreground = XBlackPixel(xDisplay, xScreen);
8053 values.background = XWhitePixel(xDisplay, xScreen);
8054 bufGC = XCreateGC(xDisplay, buf,
8055 GCForeground | GCBackground, &values);
8057 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8058 /* Begin with empty mask */
8059 if(!xpmDone) // [HGM] pieces: keep using existing
8060 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8061 squareSize, squareSize, 1);
8062 XSetFunction(xDisplay, maskGC, GXclear);
8063 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8064 0, 0, squareSize, squareSize);
8066 /* Take a copy of the piece */
8071 XSetFunction(xDisplay, bufGC, GXcopy);
8072 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8074 0, 0, squareSize, squareSize, 0, 0);
8076 /* XOR the background (light) over the piece */
8077 XSetFunction(xDisplay, bufGC, GXxor);
8079 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8080 0, 0, squareSize, squareSize, 0, 0);
8082 XSetForeground(xDisplay, bufGC, lightSquareColor);
8083 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8086 /* We now have an inverted piece image with the background
8087 erased. Construct mask by just selecting all the non-zero
8088 pixels - no need to reconstruct the original image. */
8089 XSetFunction(xDisplay, maskGC, GXor);
8091 /* Might be quicker to download an XImage and create bitmap
8092 data from it rather than this N copies per piece, but it
8093 only takes a fraction of a second and there is a much
8094 longer delay for loading the pieces. */
8095 for (n = 0; n < pieceDepth; n ++) {
8096 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8097 0, 0, squareSize, squareSize,
8103 XFreePixmap(xDisplay, buf);
8104 XFreeGC(xDisplay, bufGC);
8105 XFreeGC(xDisplay, maskGC);
8109 InitAnimState (anim, info)
8111 XWindowAttributes * info;
8116 /* Each buffer is square size, same depth as window */
8117 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8118 squareSize, squareSize, info->depth);
8119 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8120 squareSize, squareSize, info->depth);
8122 /* Create a plain GC for blitting */
8123 mask = GCForeground | GCBackground | GCFunction |
8124 GCPlaneMask | GCGraphicsExposures;
8125 values.foreground = XBlackPixel(xDisplay, xScreen);
8126 values.background = XWhitePixel(xDisplay, xScreen);
8127 values.function = GXcopy;
8128 values.plane_mask = AllPlanes;
8129 values.graphics_exposures = False;
8130 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8132 /* Piece will be copied from an existing context at
8133 the start of each new animation/drag. */
8134 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8136 /* Outline will be a read-only copy of an existing */
8137 anim->outlineGC = None;
8143 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8144 XWindowAttributes info;
8146 if (xpmDone && gameInfo.variant == old) return;
8147 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8148 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8150 InitAnimState(&game, &info);
8151 InitAnimState(&player, &info);
8153 /* For XPM pieces, we need bitmaps to use as masks. */
8155 CreateAnimMasks(info.depth);
8161 static Boolean frameWaiting;
8163 static RETSIGTYPE FrameAlarm (sig)
8166 frameWaiting = False;
8167 /* In case System-V style signals. Needed?? */
8168 signal(SIGALRM, FrameAlarm);
8175 struct itimerval delay;
8177 XSync(xDisplay, False);
8180 frameWaiting = True;
8181 signal(SIGALRM, FrameAlarm);
8182 delay.it_interval.tv_sec =
8183 delay.it_value.tv_sec = time / 1000;
8184 delay.it_interval.tv_usec =
8185 delay.it_value.tv_usec = (time % 1000) * 1000;
8186 setitimer(ITIMER_REAL, &delay, NULL);
8187 while (frameWaiting) pause();
8188 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8189 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8190 setitimer(ITIMER_REAL, &delay, NULL);
8200 XSync(xDisplay, False);
8202 usleep(time * 1000);
8207 /* Convert board position to corner of screen rect and color */
8210 ScreenSquare(column, row, pt, color)
8211 int column; int row; XPoint * pt; int * color;
8214 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8215 pt->y = lineGap + row * (squareSize + lineGap);
8217 pt->x = lineGap + column * (squareSize + lineGap);
8218 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8220 *color = SquareColor(row, column);
8223 /* Convert window coords to square */
8226 BoardSquare(x, y, column, row)
8227 int x; int y; int * column; int * row;
8229 *column = EventToSquare(x, BOARD_WIDTH);
8230 if (flipView && *column >= 0)
8231 *column = BOARD_WIDTH - 1 - *column;
8232 *row = EventToSquare(y, BOARD_HEIGHT);
8233 if (!flipView && *row >= 0)
8234 *row = BOARD_HEIGHT - 1 - *row;
8239 #undef Max /* just in case */
8241 #define Max(a, b) ((a) > (b) ? (a) : (b))
8242 #define Min(a, b) ((a) < (b) ? (a) : (b))
8245 SetRect(rect, x, y, width, height)
8246 XRectangle * rect; int x; int y; int width; int height;
8250 rect->width = width;
8251 rect->height = height;
8254 /* Test if two frames overlap. If they do, return
8255 intersection rect within old and location of
8256 that rect within new. */
8259 Intersect(old, new, size, area, pt)
8260 XPoint * old; XPoint * new;
8261 int size; XRectangle * area; XPoint * pt;
8263 if (old->x > new->x + size || new->x > old->x + size ||
8264 old->y > new->y + size || new->y > old->y + size) {
8267 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8268 size - abs(old->x - new->x), size - abs(old->y - new->y));
8269 pt->x = Max(old->x - new->x, 0);
8270 pt->y = Max(old->y - new->y, 0);
8275 /* For two overlapping frames, return the rect(s)
8276 in the old that do not intersect with the new. */
8279 CalcUpdateRects(old, new, size, update, nUpdates)
8280 XPoint * old; XPoint * new; int size;
8281 XRectangle update[]; int * nUpdates;
8285 /* If old = new (shouldn't happen) then nothing to draw */
8286 if (old->x == new->x && old->y == new->y) {
8290 /* Work out what bits overlap. Since we know the rects
8291 are the same size we don't need a full intersect calc. */
8293 /* Top or bottom edge? */
8294 if (new->y > old->y) {
8295 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8297 } else if (old->y > new->y) {
8298 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8299 size, old->y - new->y);
8302 /* Left or right edge - don't overlap any update calculated above. */
8303 if (new->x > old->x) {
8304 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8305 new->x - old->x, size - abs(new->y - old->y));
8307 } else if (old->x > new->x) {
8308 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8309 old->x - new->x, size - abs(new->y - old->y));
8316 /* Generate a series of frame coords from start->mid->finish.
8317 The movement rate doubles until the half way point is
8318 reached, then halves back down to the final destination,
8319 which gives a nice slow in/out effect. The algorithmn
8320 may seem to generate too many intermediates for short
8321 moves, but remember that the purpose is to attract the
8322 viewers attention to the piece about to be moved and
8323 then to where it ends up. Too few frames would be less
8327 Tween(start, mid, finish, factor, frames, nFrames)
8328 XPoint * start; XPoint * mid;
8329 XPoint * finish; int factor;
8330 XPoint frames[]; int * nFrames;
8332 int fraction, n, count;
8336 /* Slow in, stepping 1/16th, then 1/8th, ... */
8338 for (n = 0; n < factor; n++)
8340 for (n = 0; n < factor; n++) {
8341 frames[count].x = start->x + (mid->x - start->x) / fraction;
8342 frames[count].y = start->y + (mid->y - start->y) / fraction;
8344 fraction = fraction / 2;
8348 frames[count] = *mid;
8351 /* Slow out, stepping 1/2, then 1/4, ... */
8353 for (n = 0; n < factor; n++) {
8354 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8355 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8357 fraction = fraction * 2;
8362 /* Draw a piece on the screen without disturbing what's there */
8365 SelectGCMask(piece, clip, outline, mask)
8366 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8370 /* Bitmap for piece being moved. */
8371 if (appData.monoMode) {
8372 *mask = *pieceToSolid(piece);
8373 } else if (useImages) {
8375 *mask = xpmMask[piece];
8377 *mask = ximMaskPm[piece];
8380 *mask = *pieceToSolid(piece);
8383 /* GC for piece being moved. Square color doesn't matter, but
8384 since it gets modified we make a copy of the original. */
8386 if (appData.monoMode)
8391 if (appData.monoMode)
8396 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8398 /* Outline only used in mono mode and is not modified */
8400 *outline = bwPieceGC;
8402 *outline = wbPieceGC;
8406 OverlayPiece(piece, clip, outline, dest)
8407 ChessSquare piece; GC clip; GC outline; Drawable dest;
8412 /* Draw solid rectangle which will be clipped to shape of piece */
8413 XFillRectangle(xDisplay, dest, clip,
8414 0, 0, squareSize, squareSize);
8415 if (appData.monoMode)
8416 /* Also draw outline in contrasting color for black
8417 on black / white on white cases */
8418 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8419 0, 0, squareSize, squareSize, 0, 0, 1);
8421 /* Copy the piece */
8426 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8428 0, 0, squareSize, squareSize,
8433 /* Animate the movement of a single piece */
8436 BeginAnimation(anim, piece, startColor, start)
8444 /* The old buffer is initialised with the start square (empty) */
8445 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8446 anim->prevFrame = *start;
8448 /* The piece will be drawn using its own bitmap as a matte */
8449 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8450 XSetClipMask(xDisplay, anim->pieceGC, mask);
8454 AnimationFrame(anim, frame, piece)
8459 XRectangle updates[4];
8464 /* Save what we are about to draw into the new buffer */
8465 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8466 frame->x, frame->y, squareSize, squareSize,
8469 /* Erase bits of the previous frame */
8470 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8471 /* Where the new frame overlapped the previous,
8472 the contents in newBuf are wrong. */
8473 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8474 overlap.x, overlap.y,
8475 overlap.width, overlap.height,
8477 /* Repaint the areas in the old that don't overlap new */
8478 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8479 for (i = 0; i < count; i++)
8480 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8481 updates[i].x - anim->prevFrame.x,
8482 updates[i].y - anim->prevFrame.y,
8483 updates[i].width, updates[i].height,
8484 updates[i].x, updates[i].y);
8486 /* Easy when no overlap */
8487 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8488 0, 0, squareSize, squareSize,
8489 anim->prevFrame.x, anim->prevFrame.y);
8492 /* Save this frame for next time round */
8493 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8494 0, 0, squareSize, squareSize,
8496 anim->prevFrame = *frame;
8498 /* Draw piece over original screen contents, not current,
8499 and copy entire rect. Wipes out overlapping piece images. */
8500 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8501 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8502 0, 0, squareSize, squareSize,
8503 frame->x, frame->y);
8507 EndAnimation (anim, finish)
8511 XRectangle updates[4];
8516 /* The main code will redraw the final square, so we
8517 only need to erase the bits that don't overlap. */
8518 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8519 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8520 for (i = 0; i < count; i++)
8521 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8522 updates[i].x - anim->prevFrame.x,
8523 updates[i].y - anim->prevFrame.y,
8524 updates[i].width, updates[i].height,
8525 updates[i].x, updates[i].y);
8527 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8528 0, 0, squareSize, squareSize,
8529 anim->prevFrame.x, anim->prevFrame.y);
8534 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8536 ChessSquare piece; int startColor;
8537 XPoint * start; XPoint * finish;
8538 XPoint frames[]; int nFrames;
8542 BeginAnimation(anim, piece, startColor, start);
8543 for (n = 0; n < nFrames; n++) {
8544 AnimationFrame(anim, &(frames[n]), piece);
8545 FrameDelay(appData.animSpeed);
8547 EndAnimation(anim, finish);
8550 /* Main control logic for deciding what to animate and how */
8553 AnimateMove(board, fromX, fromY, toX, toY)
8562 XPoint start, finish, mid;
8563 XPoint frames[kFactor * 2 + 1];
8564 int nFrames, startColor, endColor;
8566 /* Are we animating? */
8567 if (!appData.animate || appData.blindfold)
8570 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8571 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8572 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8574 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8575 piece = board[fromY][fromX];
8576 if (piece >= EmptySquare) return;
8581 hop = (piece == WhiteKnight || piece == BlackKnight);
8584 if (appData.debugMode) {
8585 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8586 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8587 piece, fromX, fromY, toX, toY); }
8589 ScreenSquare(fromX, fromY, &start, &startColor);
8590 ScreenSquare(toX, toY, &finish, &endColor);
8593 /* Knight: make diagonal movement then straight */
8594 if (abs(toY - fromY) < abs(toX - fromX)) {
8595 mid.x = start.x + (finish.x - start.x) / 2;
8599 mid.y = start.y + (finish.y - start.y) / 2;
8602 mid.x = start.x + (finish.x - start.x) / 2;
8603 mid.y = start.y + (finish.y - start.y) / 2;
8606 /* Don't use as many frames for very short moves */
8607 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8608 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8610 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8611 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8613 /* Be sure end square is redrawn */
8614 damage[toY][toX] = True;
8618 DragPieceBegin(x, y)
8621 int boardX, boardY, color;
8624 /* Are we animating? */
8625 if (!appData.animateDragging || appData.blindfold)
8628 /* Figure out which square we start in and the
8629 mouse position relative to top left corner. */
8630 BoardSquare(x, y, &boardX, &boardY);
8631 player.startBoardX = boardX;
8632 player.startBoardY = boardY;
8633 ScreenSquare(boardX, boardY, &corner, &color);
8634 player.startSquare = corner;
8635 player.startColor = color;
8636 /* As soon as we start dragging, the piece will jump slightly to
8637 be centered over the mouse pointer. */
8638 player.mouseDelta.x = squareSize/2;
8639 player.mouseDelta.y = squareSize/2;
8640 /* Initialise animation */
8641 player.dragPiece = PieceForSquare(boardX, boardY);
8643 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8644 player.dragActive = True;
8645 BeginAnimation(&player, player.dragPiece, color, &corner);
8646 /* Mark this square as needing to be redrawn. Note that
8647 we don't remove the piece though, since logically (ie
8648 as seen by opponent) the move hasn't been made yet. */
8649 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8650 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8651 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8652 corner.x, corner.y, squareSize, squareSize,
8653 0, 0); // [HGM] zh: unstack in stead of grab
8654 damage[boardY][boardX] = True;
8656 player.dragActive = False;
8666 /* Are we animating? */
8667 if (!appData.animateDragging || appData.blindfold)
8671 if (! player.dragActive)
8673 /* Move piece, maintaining same relative position
8674 of mouse within square */
8675 corner.x = x - player.mouseDelta.x;
8676 corner.y = y - player.mouseDelta.y;
8677 AnimationFrame(&player, &corner, player.dragPiece);
8679 if (appData.highlightDragging) {
8681 BoardSquare(x, y, &boardX, &boardY);
8682 SetHighlights(fromX, fromY, boardX, boardY);
8691 int boardX, boardY, color;
8694 /* Are we animating? */
8695 if (!appData.animateDragging || appData.blindfold)
8699 if (! player.dragActive)
8701 /* Last frame in sequence is square piece is
8702 placed on, which may not match mouse exactly. */
8703 BoardSquare(x, y, &boardX, &boardY);
8704 ScreenSquare(boardX, boardY, &corner, &color);
8705 EndAnimation(&player, &corner);
8707 /* Be sure end square is redrawn */
8708 damage[boardY][boardX] = True;
8710 /* This prevents weird things happening with fast successive
8711 clicks which on my Sun at least can cause motion events
8712 without corresponding press/release. */
8713 player.dragActive = False;
8716 /* Handle expose event while piece being dragged */
8721 if (!player.dragActive || appData.blindfold)
8724 /* What we're doing: logically, the move hasn't been made yet,
8725 so the piece is still in it's original square. But visually
8726 it's being dragged around the board. So we erase the square
8727 that the piece is on and draw it at the last known drag point. */
8728 BlankSquare(player.startSquare.x, player.startSquare.y,
8729 player.startColor, EmptySquare, xBoardWindow);
8730 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8731 damage[player.startBoardY][player.startBoardX] = TRUE;
8734 #include <sys/ioctl.h>
8735 int get_term_width()
8737 int fd, default_width;
8740 default_width = 79; // this is FICS default anyway...
8742 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8744 if (!ioctl(fd, TIOCGSIZE, &win))
8745 default_width = win.ts_cols;
8746 #elif defined(TIOCGWINSZ)
8748 if (!ioctl(fd, TIOCGWINSZ, &win))
8749 default_width = win.ws_col;
8751 return default_width;
8754 void update_ics_width()
8756 static int old_width = 0;
8757 int new_width = get_term_width();
8759 if (old_width != new_width)
8760 ics_printf("set width %d\n", new_width);
8761 old_width = new_width;
8764 void NotifyFrontendLogin()