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. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define SetCurrentDirectory chdir
1253 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1257 // these two must some day move to frontend.h, when they are implemented
1258 Boolean MoveHistoryIsUp();
1259 Boolean GameListIsUp();
1261 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1264 // front-end part of option handling
1266 // [HGM] This platform-dependent table provides the location for storing the color info
1267 extern char *crWhite, * crBlack;
1271 &appData.whitePieceColor,
1272 &appData.blackPieceColor,
1273 &appData.lightSquareColor,
1274 &appData.darkSquareColor,
1275 &appData.highlightSquareColor,
1276 &appData.premoveHighlightColor,
1289 ParseFont(char *name, int number)
1290 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1292 case 0: // CLOCK_FONT
1293 appData.clockFont = strdup(name);
1295 case 1: // MESSAGE_FONT
1296 appData.font = strdup(name);
1298 case 2: // COORD_FONT
1299 appData.coordFont = strdup(name);
1308 { // only 2 fonts currently
1309 appData.clockFont = CLOCK_FONT_NAME;
1310 appData.coordFont = COORD_FONT_NAME;
1311 appData.font = DEFAULT_FONT_NAME;
1316 { // no-op, until we identify the code for this already in XBoard and move it here
1320 ParseColor(int n, char *name)
1321 { // in XBoard, just copy the color-name string
1322 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1326 ParseTextAttribs(ColorClass cc, char *s)
1328 (&appData.colorShout)[cc] = strdup(s);
1332 ParseBoardSize(void *addr, char *name)
1334 appData.boardSize = strdup(name);
1339 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1343 SetCommPortDefaults()
1344 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1347 // [HGM] args: these three cases taken out to stay in front-end
1349 SaveFontArg(FILE *f, ArgDescriptor *ad)
1352 switch((int)ad->argLoc) {
1353 case 0: // CLOCK_FONT
1354 name = appData.clockFont;
1356 case 1: // MESSAGE_FONT
1357 name = appData.font;
1359 case 2: // COORD_FONT
1360 name = appData.coordFont;
1365 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1370 { // nothing to do, as the sounds are at all times represented by their text-string names already
1374 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1375 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1376 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1380 SaveColor(FILE *f, ArgDescriptor *ad)
1381 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1382 if(colorVariable[(int)ad->argLoc])
1383 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1387 SaveBoardSize(FILE *f, char *name, void *addr)
1388 { // wrapper to shield back-end from BoardSize & sizeInfo
1389 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1393 ParseCommPortSettings(char *s)
1394 { // no such option in XBoard (yet)
1397 extern Widget engineOutputShell;
1398 extern Widget tagsShell, editTagsShell;
1400 GetActualPlacement(Widget wg, WindowPlacement *wp)
1410 XtSetArg(args[i], XtNx, &x); i++;
1411 XtSetArg(args[i], XtNy, &y); i++;
1412 XtSetArg(args[i], XtNwidth, &w); i++;
1413 XtSetArg(args[i], XtNheight, &h); i++;
1414 XtGetValues(wg, args, i);
1423 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1424 // In XBoard this will have to wait until awareness of window parameters is implemented
1425 GetActualPlacement(shellWidget, &wpMain);
1426 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1427 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1428 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1429 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1430 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1431 else GetActualPlacement(editShell, &wpComment);
1432 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1433 else GetActualPlacement(editTagsShell, &wpTags);
1437 PrintCommPortSettings(FILE *f, char *name)
1438 { // This option does not exist in XBoard
1442 MySearchPath(char *installDir, char *name, char *fullname)
1443 { // just append installDir and name. Perhaps ExpandPath should be used here?
1444 name = ExpandPathName(name);
1445 if(name && name[0] == '/') strcpy(fullname, name); else {
1446 sprintf(fullname, "%s%c%s", installDir, '/', name);
1452 MyGetFullPathName(char *name, char *fullname)
1453 { // should use ExpandPath?
1454 name = ExpandPathName(name);
1455 strcpy(fullname, name);
1460 EnsureOnScreen(int *x, int *y, int minX, int minY)
1467 { // [HGM] args: allows testing if main window is realized from back-end
1468 return xBoardWindow != 0;
1472 PopUpStartupDialog()
1473 { // start menu not implemented in XBoard
1476 ConvertToLine(int argc, char **argv)
1478 static char line[128*1024], buf[1024];
1482 for(i=1; i<argc; i++) {
1483 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1484 && argv[i][0] != '{' )
1485 sprintf(buf, "{%s} ", argv[i]);
1486 else sprintf(buf, "%s ", argv[i]);
1489 line[strlen(line)-1] = NULLCHAR;
1493 //--------------------------------------------------------------------------------------------
1496 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1498 #define BoardSize int
1499 void InitDrawingSizes(BoardSize boardSize, int flags)
1500 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1501 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1503 XtGeometryResult gres;
1506 if(!formWidget) return;
1509 * Enable shell resizing.
1511 shellArgs[0].value = (XtArgVal) &w;
1512 shellArgs[1].value = (XtArgVal) &h;
1513 XtGetValues(shellWidget, shellArgs, 2);
1515 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1516 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1517 XtSetValues(shellWidget, &shellArgs[2], 4);
1519 XtSetArg(args[0], XtNdefaultDistance, &sep);
1520 XtGetValues(formWidget, args, 1);
1522 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1523 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1526 XtSetArg(args[0], XtNwidth, boardWidth);
1527 XtSetArg(args[1], XtNheight, boardHeight);
1528 XtSetValues(boardWidget, args, 2);
1530 timerWidth = (boardWidth - sep) / 2;
1531 XtSetArg(args[0], XtNwidth, timerWidth);
1532 XtSetValues(whiteTimerWidget, args, 1);
1533 XtSetValues(blackTimerWidget, args, 1);
1535 XawFormDoLayout(formWidget, False);
1537 if (appData.titleInWindow) {
1539 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1540 XtSetArg(args[i], XtNheight, &h); i++;
1541 XtGetValues(titleWidget, args, i);
1543 w = boardWidth - 2*bor;
1545 XtSetArg(args[0], XtNwidth, &w);
1546 XtGetValues(menuBarWidget, args, 1);
1547 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1550 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1551 if (gres != XtGeometryYes && appData.debugMode) {
1553 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1554 programName, gres, w, h, wr, hr);
1558 XawFormDoLayout(formWidget, True);
1561 * Inhibit shell resizing.
1563 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1564 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1565 shellArgs[4].value = shellArgs[2].value = w;
1566 shellArgs[5].value = shellArgs[3].value = h;
1567 XtSetValues(shellWidget, &shellArgs[0], 6);
1569 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1572 for(i=0; i<4; i++) {
1574 for(p=0; p<=(int)WhiteKing; p++)
1575 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1576 if(gameInfo.variant == VariantShogi) {
1577 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1578 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1579 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1580 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1581 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1584 if(gameInfo.variant == VariantGothic) {
1585 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1589 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1590 for(p=0; p<=(int)WhiteKing; p++)
1591 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1592 if(gameInfo.variant == VariantShogi) {
1593 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1594 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1595 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1596 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1597 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1600 if(gameInfo.variant == VariantGothic) {
1601 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1607 for(i=0; i<2; i++) {
1609 for(p=0; p<=(int)WhiteKing; p++)
1610 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1611 if(gameInfo.variant == VariantShogi) {
1612 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1613 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1614 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1615 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1616 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1619 if(gameInfo.variant == VariantGothic) {
1620 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1631 void EscapeExpand(char *p, char *q)
1632 { // [HGM] initstring: routine to shape up string arguments
1633 while(*p++ = *q++) if(p[-1] == '\\')
1635 case 'n': p[-1] = '\n'; break;
1636 case 'r': p[-1] = '\r'; break;
1637 case 't': p[-1] = '\t'; break;
1638 case '\\': p[-1] = '\\'; break;
1639 case 0: *p = 0; return;
1640 default: p[-1] = q[-1]; break;
1649 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1650 XSetWindowAttributes window_attributes;
1652 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1653 XrmValue vFrom, vTo;
1654 XtGeometryResult gres;
1657 int forceMono = False;
1658 //define INDIRECTION
1660 // [HGM] before anything else, expand any indirection files amongst options
1661 char *argvCopy[1000]; // 1000 seems enough
1662 char newArgs[10000]; // holds actual characters
1665 srandom(time(0)); // [HGM] book: make random truly random
1668 for(i=0; i<argc; i++) {
1669 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1670 //fprintf(stderr, "arg %s\n", argv[i]);
1671 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1673 FILE *f = fopen(argv[i]+1, "rb");
1674 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1675 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1676 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1678 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1679 newArgs[k++] = 0; // terminate current arg
1680 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1681 argvCopy[j++] = newArgs + k; // get ready for next
1683 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1697 setbuf(stdout, NULL);
1698 setbuf(stderr, NULL);
1701 programName = strrchr(argv[0], '/');
1702 if (programName == NULL)
1703 programName = argv[0];
1708 XtSetLanguageProc(NULL, NULL, NULL);
1709 bindtextdomain(PACKAGE, LOCALEDIR);
1710 textdomain(PACKAGE);
1714 XtAppInitialize(&appContext, "XBoard", shellOptions,
1715 XtNumber(shellOptions),
1716 &argc, argv, xboardResources, NULL, 0);
1717 appData.boardSize = "";
1718 InitAppData(ConvertToLine(argc, argv));
1720 if (p == NULL) p = "/tmp";
1721 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1722 gameCopyFilename = (char*) malloc(i);
1723 gamePasteFilename = (char*) malloc(i);
1724 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1725 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1727 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1728 clientResources, XtNumber(clientResources),
1731 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1732 static char buf[MSG_SIZ];
1733 EscapeExpand(buf, appData.initString);
1734 appData.initString = strdup(buf);
1735 EscapeExpand(buf, appData.secondInitString);
1736 appData.secondInitString = strdup(buf);
1737 EscapeExpand(buf, appData.firstComputerString);
1738 appData.firstComputerString = strdup(buf);
1739 EscapeExpand(buf, appData.secondComputerString);
1740 appData.secondComputerString = strdup(buf);
1743 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1746 if (chdir(chessDir) != 0) {
1747 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1753 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1754 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1755 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1756 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1759 setbuf(debugFP, NULL);
1762 /* [HGM,HR] make sure board size is acceptable */
1763 if(appData.NrFiles > BOARD_FILES ||
1764 appData.NrRanks > BOARD_RANKS )
1765 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1768 /* This feature does not work; animation needs a rewrite */
1769 appData.highlightDragging = FALSE;
1773 xDisplay = XtDisplay(shellWidget);
1774 xScreen = DefaultScreen(xDisplay);
1775 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1777 gameInfo.variant = StringToVariant(appData.variant);
1778 InitPosition(FALSE);
1781 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1783 if (isdigit(appData.boardSize[0])) {
1784 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1785 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1786 &fontPxlSize, &smallLayout, &tinyLayout);
1788 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1789 programName, appData.boardSize);
1793 /* Find some defaults; use the nearest known size */
1794 SizeDefaults *szd, *nearest;
1795 int distance = 99999;
1796 nearest = szd = sizeDefaults;
1797 while (szd->name != NULL) {
1798 if (abs(szd->squareSize - squareSize) < distance) {
1800 distance = abs(szd->squareSize - squareSize);
1801 if (distance == 0) break;
1805 if (i < 2) lineGap = nearest->lineGap;
1806 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1807 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1808 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1809 if (i < 6) smallLayout = nearest->smallLayout;
1810 if (i < 7) tinyLayout = nearest->tinyLayout;
1813 SizeDefaults *szd = sizeDefaults;
1814 if (*appData.boardSize == NULLCHAR) {
1815 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1816 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1819 if (szd->name == NULL) szd--;
1820 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1822 while (szd->name != NULL &&
1823 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1824 if (szd->name == NULL) {
1825 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1826 programName, appData.boardSize);
1830 squareSize = szd->squareSize;
1831 lineGap = szd->lineGap;
1832 clockFontPxlSize = szd->clockFontPxlSize;
1833 coordFontPxlSize = szd->coordFontPxlSize;
1834 fontPxlSize = szd->fontPxlSize;
1835 smallLayout = szd->smallLayout;
1836 tinyLayout = szd->tinyLayout;
1839 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1840 if (strlen(appData.pixmapDirectory) > 0) {
1841 p = ExpandPathName(appData.pixmapDirectory);
1843 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1844 appData.pixmapDirectory);
1847 if (appData.debugMode) {
1848 fprintf(stderr, _("\
1849 XBoard square size (hint): %d\n\
1850 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1852 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1853 if (appData.debugMode) {
1854 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1858 /* [HR] height treated separately (hacked) */
1859 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1860 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1861 if (appData.showJail == 1) {
1862 /* Jail on top and bottom */
1863 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1864 XtSetArg(boardArgs[2], XtNheight,
1865 boardHeight + 2*(lineGap + squareSize));
1866 } else if (appData.showJail == 2) {
1868 XtSetArg(boardArgs[1], XtNwidth,
1869 boardWidth + 2*(lineGap + squareSize));
1870 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1873 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1874 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1878 * Determine what fonts to use.
1880 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1881 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1882 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1883 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1884 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1885 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1886 appData.font = FindFont(appData.font, fontPxlSize);
1887 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1888 countFontStruct = XQueryFont(xDisplay, countFontID);
1889 // appData.font = FindFont(appData.font, fontPxlSize);
1891 xdb = XtDatabase(xDisplay);
1892 XrmPutStringResource(&xdb, "*font", appData.font);
1895 * Detect if there are not enough colors available and adapt.
1897 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1898 appData.monoMode = True;
1901 if (!appData.monoMode) {
1902 vFrom.addr = (caddr_t) appData.lightSquareColor;
1903 vFrom.size = strlen(appData.lightSquareColor);
1904 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1905 if (vTo.addr == NULL) {
1906 appData.monoMode = True;
1909 lightSquareColor = *(Pixel *) vTo.addr;
1912 if (!appData.monoMode) {
1913 vFrom.addr = (caddr_t) appData.darkSquareColor;
1914 vFrom.size = strlen(appData.darkSquareColor);
1915 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1916 if (vTo.addr == NULL) {
1917 appData.monoMode = True;
1920 darkSquareColor = *(Pixel *) vTo.addr;
1923 if (!appData.monoMode) {
1924 vFrom.addr = (caddr_t) appData.whitePieceColor;
1925 vFrom.size = strlen(appData.whitePieceColor);
1926 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1927 if (vTo.addr == NULL) {
1928 appData.monoMode = True;
1931 whitePieceColor = *(Pixel *) vTo.addr;
1934 if (!appData.monoMode) {
1935 vFrom.addr = (caddr_t) appData.blackPieceColor;
1936 vFrom.size = strlen(appData.blackPieceColor);
1937 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1938 if (vTo.addr == NULL) {
1939 appData.monoMode = True;
1942 blackPieceColor = *(Pixel *) vTo.addr;
1946 if (!appData.monoMode) {
1947 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1948 vFrom.size = strlen(appData.highlightSquareColor);
1949 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1950 if (vTo.addr == NULL) {
1951 appData.monoMode = True;
1954 highlightSquareColor = *(Pixel *) vTo.addr;
1958 if (!appData.monoMode) {
1959 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1960 vFrom.size = strlen(appData.premoveHighlightColor);
1961 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1962 if (vTo.addr == NULL) {
1963 appData.monoMode = True;
1966 premoveHighlightColor = *(Pixel *) vTo.addr;
1971 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1974 if (appData.bitmapDirectory == NULL ||
1975 appData.bitmapDirectory[0] == NULLCHAR)
1976 appData.bitmapDirectory = DEF_BITMAP_DIR;
1979 if (appData.lowTimeWarning && !appData.monoMode) {
1980 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1981 vFrom.size = strlen(appData.lowTimeWarningColor);
1982 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1983 if (vTo.addr == NULL)
1984 appData.monoMode = True;
1986 lowTimeWarningColor = *(Pixel *) vTo.addr;
1989 if (appData.monoMode && appData.debugMode) {
1990 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1991 (unsigned long) XWhitePixel(xDisplay, xScreen),
1992 (unsigned long) XBlackPixel(xDisplay, xScreen));
1995 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1996 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1997 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1998 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1999 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2000 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2001 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2002 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2003 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2004 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2006 if (appData.colorize) {
2008 _("%s: can't parse color names; disabling colorization\n"),
2011 appData.colorize = FALSE;
2013 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2014 textColors[ColorNone].attr = 0;
2016 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2022 layoutName = "tinyLayout";
2023 } else if (smallLayout) {
2024 layoutName = "smallLayout";
2026 layoutName = "normalLayout";
2028 /* Outer layoutWidget is there only to provide a name for use in
2029 resources that depend on the layout style */
2031 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2032 layoutArgs, XtNumber(layoutArgs));
2034 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2035 formArgs, XtNumber(formArgs));
2036 XtSetArg(args[0], XtNdefaultDistance, &sep);
2037 XtGetValues(formWidget, args, 1);
2040 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2041 XtSetArg(args[0], XtNtop, XtChainTop);
2042 XtSetArg(args[1], XtNbottom, XtChainTop);
2043 XtSetArg(args[2], XtNright, XtChainLeft);
2044 XtSetValues(menuBarWidget, args, 3);
2046 widgetList[j++] = whiteTimerWidget =
2047 XtCreateWidget("whiteTime", labelWidgetClass,
2048 formWidget, timerArgs, XtNumber(timerArgs));
2049 XtSetArg(args[0], XtNfont, clockFontStruct);
2050 XtSetArg(args[1], XtNtop, XtChainTop);
2051 XtSetArg(args[2], XtNbottom, XtChainTop);
2052 XtSetValues(whiteTimerWidget, args, 3);
2054 widgetList[j++] = blackTimerWidget =
2055 XtCreateWidget("blackTime", labelWidgetClass,
2056 formWidget, timerArgs, XtNumber(timerArgs));
2057 XtSetArg(args[0], XtNfont, clockFontStruct);
2058 XtSetArg(args[1], XtNtop, XtChainTop);
2059 XtSetArg(args[2], XtNbottom, XtChainTop);
2060 XtSetValues(blackTimerWidget, args, 3);
2062 if (appData.titleInWindow) {
2063 widgetList[j++] = titleWidget =
2064 XtCreateWidget("title", labelWidgetClass, formWidget,
2065 titleArgs, XtNumber(titleArgs));
2066 XtSetArg(args[0], XtNtop, XtChainTop);
2067 XtSetArg(args[1], XtNbottom, XtChainTop);
2068 XtSetValues(titleWidget, args, 2);
2071 if (appData.showButtonBar) {
2072 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2073 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2074 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2075 XtSetArg(args[2], XtNtop, XtChainTop);
2076 XtSetArg(args[3], XtNbottom, XtChainTop);
2077 XtSetValues(buttonBarWidget, args, 4);
2080 widgetList[j++] = messageWidget =
2081 XtCreateWidget("message", labelWidgetClass, formWidget,
2082 messageArgs, XtNumber(messageArgs));
2083 XtSetArg(args[0], XtNtop, XtChainTop);
2084 XtSetArg(args[1], XtNbottom, XtChainTop);
2085 XtSetValues(messageWidget, args, 2);
2087 widgetList[j++] = boardWidget =
2088 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2089 XtNumber(boardArgs));
2091 XtManageChildren(widgetList, j);
2093 timerWidth = (boardWidth - sep) / 2;
2094 XtSetArg(args[0], XtNwidth, timerWidth);
2095 XtSetValues(whiteTimerWidget, args, 1);
2096 XtSetValues(blackTimerWidget, args, 1);
2098 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2099 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2100 XtGetValues(whiteTimerWidget, args, 2);
2102 if (appData.showButtonBar) {
2103 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2104 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2105 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2109 * formWidget uses these constraints but they are stored
2113 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2114 XtSetValues(menuBarWidget, args, i);
2115 if (appData.titleInWindow) {
2118 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2119 XtSetValues(whiteTimerWidget, args, i);
2121 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2122 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2123 XtSetValues(blackTimerWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2126 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2127 XtSetValues(titleWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2130 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2131 XtSetValues(messageWidget, args, i);
2132 if (appData.showButtonBar) {
2134 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2135 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2136 XtSetValues(buttonBarWidget, args, i);
2140 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2141 XtSetValues(whiteTimerWidget, args, i);
2143 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2144 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2145 XtSetValues(blackTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2148 XtSetValues(titleWidget, args, i);
2150 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2151 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2152 XtSetValues(messageWidget, args, i);
2153 if (appData.showButtonBar) {
2155 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2156 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2157 XtSetValues(buttonBarWidget, args, i);
2162 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2163 XtSetValues(whiteTimerWidget, args, i);
2165 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2166 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2167 XtSetValues(blackTimerWidget, args, i);
2169 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2170 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2171 XtSetValues(messageWidget, args, i);
2172 if (appData.showButtonBar) {
2174 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2175 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2176 XtSetValues(buttonBarWidget, args, i);
2180 XtSetArg(args[0], XtNfromVert, messageWidget);
2181 XtSetArg(args[1], XtNtop, XtChainTop);
2182 XtSetArg(args[2], XtNbottom, XtChainBottom);
2183 XtSetArg(args[3], XtNleft, XtChainLeft);
2184 XtSetArg(args[4], XtNright, XtChainRight);
2185 XtSetValues(boardWidget, args, 5);
2187 XtRealizeWidget(shellWidget);
2190 XtSetArg(args[0], XtNx, wpMain.x);
2191 XtSetArg(args[1], XtNy, wpMain.y);
2192 XtSetValues(shellWidget, args, 2);
2196 * Correct the width of the message and title widgets.
2197 * It is not known why some systems need the extra fudge term.
2198 * The value "2" is probably larger than needed.
2200 XawFormDoLayout(formWidget, False);
2202 #define WIDTH_FUDGE 2
2204 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2205 XtSetArg(args[i], XtNheight, &h); i++;
2206 XtGetValues(messageWidget, args, i);
2207 if (appData.showButtonBar) {
2209 XtSetArg(args[i], XtNwidth, &w); i++;
2210 XtGetValues(buttonBarWidget, args, i);
2211 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2213 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2216 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2217 if (gres != XtGeometryYes && appData.debugMode) {
2218 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2219 programName, gres, w, h, wr, hr);
2222 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2223 /* The size used for the child widget in layout lags one resize behind
2224 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2226 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2227 if (gres != XtGeometryYes && appData.debugMode) {
2228 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2229 programName, gres, w, h, wr, hr);
2232 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2233 XtSetArg(args[1], XtNright, XtChainRight);
2234 XtSetValues(messageWidget, args, 2);
2236 if (appData.titleInWindow) {
2238 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2239 XtSetArg(args[i], XtNheight, &h); i++;
2240 XtGetValues(titleWidget, args, i);
2242 w = boardWidth - 2*bor;
2244 XtSetArg(args[0], XtNwidth, &w);
2245 XtGetValues(menuBarWidget, args, 1);
2246 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2249 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2250 if (gres != XtGeometryYes && appData.debugMode) {
2252 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2253 programName, gres, w, h, wr, hr);
2256 XawFormDoLayout(formWidget, True);
2258 xBoardWindow = XtWindow(boardWidget);
2260 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2261 // not need to go into InitDrawingSizes().
2265 * Create X checkmark bitmap and initialize option menu checks.
2267 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2268 checkmark_bits, checkmark_width, checkmark_height);
2269 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2270 if (appData.alwaysPromoteToQueen) {
2271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2274 if (appData.animateDragging) {
2275 XtSetValues(XtNameToWidget(menuBarWidget,
2276 "menuOptions.Animate Dragging"),
2279 if (appData.animate) {
2280 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2283 if (appData.autoComment) {
2284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2287 if (appData.autoCallFlag) {
2288 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2291 if (appData.autoFlipView) {
2292 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2295 if (appData.autoObserve) {
2296 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2299 if (appData.autoRaiseBoard) {
2300 XtSetValues(XtNameToWidget(menuBarWidget,
2301 "menuOptions.Auto Raise Board"), args, 1);
2303 if (appData.autoSaveGames) {
2304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2307 if (appData.saveGameFile[0] != NULLCHAR) {
2308 /* Can't turn this off from menu */
2309 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2311 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2315 if (appData.blindfold) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,
2317 "menuOptions.Blindfold"), args, 1);
2319 if (appData.flashCount > 0) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Flash Moves"),
2324 if (appData.getMoveList) {
2325 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2329 if (appData.highlightDragging) {
2330 XtSetValues(XtNameToWidget(menuBarWidget,
2331 "menuOptions.Highlight Dragging"),
2335 if (appData.highlightLastMove) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Highlight Last Move"),
2340 if (appData.icsAlarm) {
2341 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2344 if (appData.ringBellAfterMoves) {
2345 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2348 if (appData.oldSaveStyle) {
2349 XtSetValues(XtNameToWidget(menuBarWidget,
2350 "menuOptions.Old Save Style"), args, 1);
2352 if (appData.periodicUpdates) {
2353 XtSetValues(XtNameToWidget(menuBarWidget,
2354 "menuOptions.Periodic Updates"), args, 1);
2356 if (appData.ponderNextMove) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,
2358 "menuOptions.Ponder Next Move"), args, 1);
2360 if (appData.popupExitMessage) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,
2362 "menuOptions.Popup Exit Message"), args, 1);
2364 if (appData.popupMoveErrors) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Popup Move Errors"), args, 1);
2368 if (appData.premove) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Premove"), args, 1);
2372 if (appData.quietPlay) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Quiet Play"), args, 1);
2376 if (appData.showCoords) {
2377 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2380 if (appData.hideThinkingFromHuman) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2384 if (appData.testLegality) {
2385 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2388 if (saveSettingsOnExit) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2396 ReadBitmap(&wIconPixmap, "icon_white.bm",
2397 icon_white_bits, icon_white_width, icon_white_height);
2398 ReadBitmap(&bIconPixmap, "icon_black.bm",
2399 icon_black_bits, icon_black_width, icon_black_height);
2400 iconPixmap = wIconPixmap;
2402 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2403 XtSetValues(shellWidget, args, i);
2406 * Create a cursor for the board widget.
2408 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2409 XChangeWindowAttributes(xDisplay, xBoardWindow,
2410 CWCursor, &window_attributes);
2413 * Inhibit shell resizing.
2415 shellArgs[0].value = (XtArgVal) &w;
2416 shellArgs[1].value = (XtArgVal) &h;
2417 XtGetValues(shellWidget, shellArgs, 2);
2418 shellArgs[4].value = shellArgs[2].value = w;
2419 shellArgs[5].value = shellArgs[3].value = h;
2420 XtSetValues(shellWidget, &shellArgs[2], 4);
2421 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2422 marginH = h - boardHeight;
2424 CatchDeleteWindow(shellWidget, "QuitProc");
2429 if (appData.bitmapDirectory[0] != NULLCHAR) {
2436 /* Create regular pieces */
2437 if (!useImages) CreatePieces();
2442 if (appData.animate || appData.animateDragging)
2445 XtAugmentTranslations(formWidget,
2446 XtParseTranslationTable(globalTranslations));
2447 XtAugmentTranslations(boardWidget,
2448 XtParseTranslationTable(boardTranslations));
2449 XtAugmentTranslations(whiteTimerWidget,
2450 XtParseTranslationTable(whiteTranslations));
2451 XtAugmentTranslations(blackTimerWidget,
2452 XtParseTranslationTable(blackTranslations));
2454 /* Why is the following needed on some versions of X instead
2455 * of a translation? */
2456 XtAddEventHandler(boardWidget, ExposureMask, False,
2457 (XtEventHandler) EventProc, NULL);
2460 /* [AS] Restore layout */
2461 if( wpMoveHistory.visible ) {
2465 if( wpEvalGraph.visible )
2470 if( wpEngineOutput.visible ) {
2471 EngineOutputPopUp();
2476 if (errorExitStatus == -1) {
2477 if (appData.icsActive) {
2478 /* We now wait until we see "login:" from the ICS before
2479 sending the logon script (problems with timestamp otherwise) */
2480 /*ICSInitScript();*/
2481 if (appData.icsInputBox) ICSInputBoxPopUp();
2485 signal(SIGWINCH, TermSizeSigHandler);
2487 signal(SIGINT, IntSigHandler);
2488 signal(SIGTERM, IntSigHandler);
2489 if (*appData.cmailGameName != NULLCHAR) {
2490 signal(SIGUSR1, CmailSigHandler);
2493 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2496 XtAppMainLoop(appContext);
2497 if (appData.debugMode) fclose(debugFP); // [DM] debug
2504 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2505 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2507 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2508 unlink(gameCopyFilename);
2509 unlink(gamePasteFilename);
2512 RETSIGTYPE TermSizeSigHandler(int sig)
2525 CmailSigHandler(sig)
2531 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2533 /* Activate call-back function CmailSigHandlerCallBack() */
2534 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2536 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2540 CmailSigHandlerCallBack(isr, closure, message, count, error)
2548 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2550 /**** end signal code ****/
2560 f = fopen(appData.icsLogon, "r");
2566 strcat(buf, appData.icsLogon);
2567 f = fopen(buf, "r");
2571 ProcessICSInitScript(f);
2578 EditCommentPopDown();
2593 if (!menuBarWidget) return;
2594 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2596 DisplayError("menuStep.Revert", 0);
2598 XtSetSensitive(w, !grey);
2603 SetMenuEnables(enab)
2607 if (!menuBarWidget) return;
2608 while (enab->name != NULL) {
2609 w = XtNameToWidget(menuBarWidget, enab->name);
2611 DisplayError(enab->name, 0);
2613 XtSetSensitive(w, enab->value);
2619 Enables icsEnables[] = {
2620 { "menuFile.Mail Move", False },
2621 { "menuFile.Reload CMail Message", False },
2622 { "menuMode.Machine Black", False },
2623 { "menuMode.Machine White", False },
2624 { "menuMode.Analysis Mode", False },
2625 { "menuMode.Analyze File", False },
2626 { "menuMode.Two Machines", False },
2628 { "menuHelp.Hint", False },
2629 { "menuHelp.Book", False },
2630 { "menuStep.Move Now", False },
2631 { "menuOptions.Periodic Updates", False },
2632 { "menuOptions.Hide Thinking", False },
2633 { "menuOptions.Ponder Next Move", False },
2638 Enables ncpEnables[] = {
2639 { "menuFile.Mail Move", False },
2640 { "menuFile.Reload CMail Message", False },
2641 { "menuMode.Machine White", False },
2642 { "menuMode.Machine Black", False },
2643 { "menuMode.Analysis Mode", False },
2644 { "menuMode.Analyze File", False },
2645 { "menuMode.Two Machines", False },
2646 { "menuMode.ICS Client", False },
2647 { "menuMode.ICS Input Box", False },
2648 { "Action", False },
2649 { "menuStep.Revert", False },
2650 { "menuStep.Move Now", False },
2651 { "menuStep.Retract Move", False },
2652 { "menuOptions.Auto Comment", False },
2653 { "menuOptions.Auto Flag", False },
2654 { "menuOptions.Auto Flip View", False },
2655 { "menuOptions.Auto Observe", False },
2656 { "menuOptions.Auto Raise Board", False },
2657 { "menuOptions.Get Move List", False },
2658 { "menuOptions.ICS Alarm", False },
2659 { "menuOptions.Move Sound", False },
2660 { "menuOptions.Quiet Play", False },
2661 { "menuOptions.Hide Thinking", False },
2662 { "menuOptions.Periodic Updates", False },
2663 { "menuOptions.Ponder Next Move", False },
2664 { "menuHelp.Hint", False },
2665 { "menuHelp.Book", False },
2669 Enables gnuEnables[] = {
2670 { "menuMode.ICS Client", False },
2671 { "menuMode.ICS Input Box", False },
2672 { "menuAction.Accept", False },
2673 { "menuAction.Decline", False },
2674 { "menuAction.Rematch", False },
2675 { "menuAction.Adjourn", False },
2676 { "menuAction.Stop Examining", False },
2677 { "menuAction.Stop Observing", False },
2678 { "menuStep.Revert", False },
2679 { "menuOptions.Auto Comment", False },
2680 { "menuOptions.Auto Observe", False },
2681 { "menuOptions.Auto Raise Board", False },
2682 { "menuOptions.Get Move List", False },
2683 { "menuOptions.Premove", False },
2684 { "menuOptions.Quiet Play", False },
2686 /* The next two options rely on SetCmailMode being called *after* */
2687 /* SetGNUMode so that when GNU is being used to give hints these */
2688 /* menu options are still available */
2690 { "menuFile.Mail Move", False },
2691 { "menuFile.Reload CMail Message", False },
2695 Enables cmailEnables[] = {
2697 { "menuAction.Call Flag", False },
2698 { "menuAction.Draw", True },
2699 { "menuAction.Adjourn", False },
2700 { "menuAction.Abort", False },
2701 { "menuAction.Stop Observing", False },
2702 { "menuAction.Stop Examining", False },
2703 { "menuFile.Mail Move", True },
2704 { "menuFile.Reload CMail Message", True },
2708 Enables trainingOnEnables[] = {
2709 { "menuMode.Edit Comment", False },
2710 { "menuMode.Pause", False },
2711 { "menuStep.Forward", False },
2712 { "menuStep.Backward", False },
2713 { "menuStep.Forward to End", False },
2714 { "menuStep.Back to Start", False },
2715 { "menuStep.Move Now", False },
2716 { "menuStep.Truncate Game", False },
2720 Enables trainingOffEnables[] = {
2721 { "menuMode.Edit Comment", True },
2722 { "menuMode.Pause", True },
2723 { "menuStep.Forward", True },
2724 { "menuStep.Backward", True },
2725 { "menuStep.Forward to End", True },
2726 { "menuStep.Back to Start", True },
2727 { "menuStep.Move Now", True },
2728 { "menuStep.Truncate Game", True },
2732 Enables machineThinkingEnables[] = {
2733 { "menuFile.Load Game", False },
2734 { "menuFile.Load Next Game", False },
2735 { "menuFile.Load Previous Game", False },
2736 { "menuFile.Reload Same Game", False },
2737 { "menuFile.Paste Game", False },
2738 { "menuFile.Load Position", False },
2739 { "menuFile.Load Next Position", False },
2740 { "menuFile.Load Previous Position", False },
2741 { "menuFile.Reload Same Position", False },
2742 { "menuFile.Paste Position", False },
2743 { "menuMode.Machine White", False },
2744 { "menuMode.Machine Black", False },
2745 { "menuMode.Two Machines", False },
2746 { "menuStep.Retract Move", False },
2750 Enables userThinkingEnables[] = {
2751 { "menuFile.Load Game", True },
2752 { "menuFile.Load Next Game", True },
2753 { "menuFile.Load Previous Game", True },
2754 { "menuFile.Reload Same Game", True },
2755 { "menuFile.Paste Game", True },
2756 { "menuFile.Load Position", True },
2757 { "menuFile.Load Next Position", True },
2758 { "menuFile.Load Previous Position", True },
2759 { "menuFile.Reload Same Position", True },
2760 { "menuFile.Paste Position", True },
2761 { "menuMode.Machine White", True },
2762 { "menuMode.Machine Black", True },
2763 { "menuMode.Two Machines", True },
2764 { "menuStep.Retract Move", True },
2770 SetMenuEnables(icsEnables);
2773 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2774 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2781 SetMenuEnables(ncpEnables);
2787 SetMenuEnables(gnuEnables);
2793 SetMenuEnables(cmailEnables);
2799 SetMenuEnables(trainingOnEnables);
2800 if (appData.showButtonBar) {
2801 XtSetSensitive(buttonBarWidget, False);
2807 SetTrainingModeOff()
2809 SetMenuEnables(trainingOffEnables);
2810 if (appData.showButtonBar) {
2811 XtSetSensitive(buttonBarWidget, True);
2816 SetUserThinkingEnables()
2818 if (appData.noChessProgram) return;
2819 SetMenuEnables(userThinkingEnables);
2823 SetMachineThinkingEnables()
2825 if (appData.noChessProgram) return;
2826 SetMenuEnables(machineThinkingEnables);
2828 case MachinePlaysBlack:
2829 case MachinePlaysWhite:
2830 case TwoMachinesPlay:
2831 XtSetSensitive(XtNameToWidget(menuBarWidget,
2832 ModeToWidgetName(gameMode)), True);
2839 #define Abs(n) ((n)<0 ? -(n) : (n))
2842 * Find a font that matches "pattern" that is as close as
2843 * possible to the targetPxlSize. Prefer fonts that are k
2844 * pixels smaller to fonts that are k pixels larger. The
2845 * pattern must be in the X Consortium standard format,
2846 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2847 * The return value should be freed with XtFree when no
2850 char *FindFont(pattern, targetPxlSize)
2854 char **fonts, *p, *best, *scalable, *scalableTail;
2855 int i, j, nfonts, minerr, err, pxlSize;
2858 char **missing_list;
2860 char *def_string, *base_fnt_lst, strInt[3];
2862 XFontStruct **fnt_list;
2864 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2865 sprintf(strInt, "%d", targetPxlSize);
2866 p = strstr(pattern, "--");
2867 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2868 strcat(base_fnt_lst, strInt);
2869 strcat(base_fnt_lst, strchr(p + 2, '-'));
2871 if ((fntSet = XCreateFontSet(xDisplay,
2875 &def_string)) == NULL) {
2877 fprintf(stderr, _("Unable to create font set.\n"));
2881 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2883 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2885 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2886 programName, pattern);
2894 for (i=0; i<nfonts; i++) {
2897 if (*p != '-') continue;
2899 if (*p == NULLCHAR) break;
2900 if (*p++ == '-') j++;
2902 if (j < 7) continue;
2905 scalable = fonts[i];
2908 err = pxlSize - targetPxlSize;
2909 if (Abs(err) < Abs(minerr) ||
2910 (minerr > 0 && err < 0 && -err == minerr)) {
2916 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2917 /* If the error is too big and there is a scalable font,
2918 use the scalable font. */
2919 int headlen = scalableTail - scalable;
2920 p = (char *) XtMalloc(strlen(scalable) + 10);
2921 while (isdigit(*scalableTail)) scalableTail++;
2922 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2924 p = (char *) XtMalloc(strlen(best) + 1);
2927 if (appData.debugMode) {
2928 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2929 pattern, targetPxlSize, p);
2932 if (missing_count > 0)
2933 XFreeStringList(missing_list);
2934 XFreeFontSet(xDisplay, fntSet);
2936 XFreeFontNames(fonts);
2943 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2944 | GCBackground | GCFunction | GCPlaneMask;
2945 XGCValues gc_values;
2948 gc_values.plane_mask = AllPlanes;
2949 gc_values.line_width = lineGap;
2950 gc_values.line_style = LineSolid;
2951 gc_values.function = GXcopy;
2953 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2954 gc_values.background = XBlackPixel(xDisplay, xScreen);
2955 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2957 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2958 gc_values.background = XWhitePixel(xDisplay, xScreen);
2959 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2960 XSetFont(xDisplay, coordGC, coordFontID);
2962 // [HGM] make font for holdings counts (white on black0
2963 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2964 gc_values.background = XBlackPixel(xDisplay, xScreen);
2965 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2966 XSetFont(xDisplay, countGC, countFontID);
2968 if (appData.monoMode) {
2969 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2970 gc_values.background = XWhitePixel(xDisplay, xScreen);
2971 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2973 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2974 gc_values.background = XBlackPixel(xDisplay, xScreen);
2975 lightSquareGC = wbPieceGC
2976 = XtGetGC(shellWidget, value_mask, &gc_values);
2978 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2979 gc_values.background = XWhitePixel(xDisplay, xScreen);
2980 darkSquareGC = bwPieceGC
2981 = XtGetGC(shellWidget, value_mask, &gc_values);
2983 if (DefaultDepth(xDisplay, xScreen) == 1) {
2984 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2985 gc_values.function = GXcopyInverted;
2986 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2987 gc_values.function = GXcopy;
2988 if (XBlackPixel(xDisplay, xScreen) == 1) {
2989 bwPieceGC = darkSquareGC;
2990 wbPieceGC = copyInvertedGC;
2992 bwPieceGC = copyInvertedGC;
2993 wbPieceGC = lightSquareGC;
2997 gc_values.foreground = highlightSquareColor;
2998 gc_values.background = highlightSquareColor;
2999 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3001 gc_values.foreground = premoveHighlightColor;
3002 gc_values.background = premoveHighlightColor;
3003 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3005 gc_values.foreground = lightSquareColor;
3006 gc_values.background = darkSquareColor;
3007 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3009 gc_values.foreground = darkSquareColor;
3010 gc_values.background = lightSquareColor;
3011 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3013 gc_values.foreground = jailSquareColor;
3014 gc_values.background = jailSquareColor;
3015 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3017 gc_values.foreground = whitePieceColor;
3018 gc_values.background = darkSquareColor;
3019 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3021 gc_values.foreground = whitePieceColor;
3022 gc_values.background = lightSquareColor;
3023 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3025 gc_values.foreground = whitePieceColor;
3026 gc_values.background = jailSquareColor;
3027 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3029 gc_values.foreground = blackPieceColor;
3030 gc_values.background = darkSquareColor;
3031 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 gc_values.foreground = blackPieceColor;
3034 gc_values.background = lightSquareColor;
3035 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3037 gc_values.foreground = blackPieceColor;
3038 gc_values.background = jailSquareColor;
3039 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3043 void loadXIM(xim, xmask, filename, dest, mask)
3056 fp = fopen(filename, "rb");
3058 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3065 for (y=0; y<h; ++y) {
3066 for (x=0; x<h; ++x) {
3071 XPutPixel(xim, x, y, blackPieceColor);
3073 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3076 XPutPixel(xim, x, y, darkSquareColor);
3078 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3081 XPutPixel(xim, x, y, whitePieceColor);
3083 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3086 XPutPixel(xim, x, y, lightSquareColor);
3088 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3094 /* create Pixmap of piece */
3095 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3097 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3100 /* create Pixmap of clipmask
3101 Note: We assume the white/black pieces have the same
3102 outline, so we make only 6 masks. This is okay
3103 since the XPM clipmask routines do the same. */
3105 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3107 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3110 /* now create the 1-bit version */
3111 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3114 values.foreground = 1;
3115 values.background = 0;
3117 /* Don't use XtGetGC, not read only */
3118 maskGC = XCreateGC(xDisplay, *mask,
3119 GCForeground | GCBackground, &values);
3120 XCopyPlane(xDisplay, temp, *mask, maskGC,
3121 0, 0, squareSize, squareSize, 0, 0, 1);
3122 XFreePixmap(xDisplay, temp);
3127 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3129 void CreateXIMPieces()
3134 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3139 /* The XSynchronize calls were copied from CreatePieces.
3140 Not sure if needed, but can't hurt */
3141 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3144 /* temp needed by loadXIM() */
3145 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3146 0, 0, ss, ss, AllPlanes, XYPixmap);
3148 if (strlen(appData.pixmapDirectory) == 0) {
3152 if (appData.monoMode) {
3153 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3157 fprintf(stderr, _("\nLoading XIMs...\n"));
3159 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3160 fprintf(stderr, "%d", piece+1);
3161 for (kind=0; kind<4; kind++) {
3162 fprintf(stderr, ".");
3163 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3164 ExpandPathName(appData.pixmapDirectory),
3165 piece <= (int) WhiteKing ? "" : "w",
3166 pieceBitmapNames[piece],
3168 ximPieceBitmap[kind][piece] =
3169 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3170 0, 0, ss, ss, AllPlanes, XYPixmap);
3171 if (appData.debugMode)
3172 fprintf(stderr, _("(File:%s:) "), buf);
3173 loadXIM(ximPieceBitmap[kind][piece],
3175 &(xpmPieceBitmap2[kind][piece]),
3176 &(ximMaskPm2[piece]));
3177 if(piece <= (int)WhiteKing)
3178 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3180 fprintf(stderr," ");
3182 /* Load light and dark squares */
3183 /* If the LSQ and DSQ pieces don't exist, we will
3184 draw them with solid squares. */
3185 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3186 if (access(buf, 0) != 0) {
3190 fprintf(stderr, _("light square "));
3192 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3193 0, 0, ss, ss, AllPlanes, XYPixmap);
3194 if (appData.debugMode)
3195 fprintf(stderr, _("(File:%s:) "), buf);
3197 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3198 fprintf(stderr, _("dark square "));
3199 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3200 ExpandPathName(appData.pixmapDirectory), ss);
3201 if (appData.debugMode)
3202 fprintf(stderr, _("(File:%s:) "), buf);
3204 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3205 0, 0, ss, ss, AllPlanes, XYPixmap);
3206 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3207 xpmJailSquare = xpmLightSquare;
3209 fprintf(stderr, _("Done.\n"));
3211 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3215 void CreateXPMPieces()
3219 u_int ss = squareSize;
3221 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3222 XpmColorSymbol symbols[4];
3224 /* The XSynchronize calls were copied from CreatePieces.
3225 Not sure if needed, but can't hurt */
3226 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3228 /* Setup translations so piece colors match square colors */
3229 symbols[0].name = "light_piece";
3230 symbols[0].value = appData.whitePieceColor;
3231 symbols[1].name = "dark_piece";
3232 symbols[1].value = appData.blackPieceColor;
3233 symbols[2].name = "light_square";
3234 symbols[2].value = appData.lightSquareColor;
3235 symbols[3].name = "dark_square";
3236 symbols[3].value = appData.darkSquareColor;
3238 attr.valuemask = XpmColorSymbols;
3239 attr.colorsymbols = symbols;
3240 attr.numsymbols = 4;
3242 if (appData.monoMode) {
3243 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3247 if (strlen(appData.pixmapDirectory) == 0) {
3248 XpmPieces* pieces = builtInXpms;
3251 while (pieces->size != squareSize && pieces->size) pieces++;
3252 if (!pieces->size) {
3253 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3256 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3257 for (kind=0; kind<4; kind++) {
3259 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3260 pieces->xpm[piece][kind],
3261 &(xpmPieceBitmap2[kind][piece]),
3262 NULL, &attr)) != 0) {
3263 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3267 if(piece <= (int) WhiteKing)
3268 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3272 xpmJailSquare = xpmLightSquare;
3276 fprintf(stderr, _("\nLoading XPMs...\n"));
3279 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3280 fprintf(stderr, "%d ", piece+1);
3281 for (kind=0; kind<4; kind++) {
3282 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3283 ExpandPathName(appData.pixmapDirectory),
3284 piece > (int) WhiteKing ? "w" : "",
3285 pieceBitmapNames[piece],
3287 if (appData.debugMode) {
3288 fprintf(stderr, _("(File:%s:) "), buf);
3290 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3291 &(xpmPieceBitmap2[kind][piece]),
3292 NULL, &attr)) != 0) {
3293 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3294 // [HGM] missing: read of unorthodox piece failed; substitute King.
3295 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3296 ExpandPathName(appData.pixmapDirectory),
3298 if (appData.debugMode) {
3299 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3301 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3302 &(xpmPieceBitmap2[kind][piece]),
3306 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3311 if(piece <= (int) WhiteKing)
3312 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3315 /* Load light and dark squares */
3316 /* If the LSQ and DSQ pieces don't exist, we will
3317 draw them with solid squares. */
3318 fprintf(stderr, _("light square "));
3319 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3320 if (access(buf, 0) != 0) {
3324 if (appData.debugMode)
3325 fprintf(stderr, _("(File:%s:) "), buf);
3327 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3328 &xpmLightSquare, NULL, &attr)) != 0) {
3329 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3332 fprintf(stderr, _("dark square "));
3333 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3334 ExpandPathName(appData.pixmapDirectory), ss);
3335 if (appData.debugMode) {
3336 fprintf(stderr, _("(File:%s:) "), buf);
3338 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3339 &xpmDarkSquare, NULL, &attr)) != 0) {
3340 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3344 xpmJailSquare = xpmLightSquare;
3345 fprintf(stderr, _("Done.\n"));
3347 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3350 #endif /* HAVE_LIBXPM */
3353 /* No built-in bitmaps */
3358 u_int ss = squareSize;
3360 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3363 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3364 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3365 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3366 pieceBitmapNames[piece],
3367 ss, kind == SOLID ? 's' : 'o');
3368 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3369 if(piece <= (int)WhiteKing)
3370 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3374 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3378 /* With built-in bitmaps */
3381 BuiltInBits* bib = builtInBits;
3384 u_int ss = squareSize;
3386 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3389 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3391 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3392 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3393 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3394 pieceBitmapNames[piece],
3395 ss, kind == SOLID ? 's' : 'o');
3396 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3397 bib->bits[kind][piece], ss, ss);
3398 if(piece <= (int)WhiteKing)
3399 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3403 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3408 void ReadBitmap(pm, name, bits, wreq, hreq)
3411 unsigned char bits[];
3417 char msg[MSG_SIZ], fullname[MSG_SIZ];
3419 if (*appData.bitmapDirectory != NULLCHAR) {
3420 strcpy(fullname, appData.bitmapDirectory);
3421 strcat(fullname, "/");
3422 strcat(fullname, name);
3423 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3424 &w, &h, pm, &x_hot, &y_hot);
3425 fprintf(stderr, "load %s\n", name);
3426 if (errcode != BitmapSuccess) {
3428 case BitmapOpenFailed:
3429 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3431 case BitmapFileInvalid:
3432 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3434 case BitmapNoMemory:
3435 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3439 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3443 fprintf(stderr, _("%s: %s...using built-in\n"),
3445 } else if (w != wreq || h != hreq) {
3447 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3448 programName, fullname, w, h, wreq, hreq);
3454 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3463 if (lineGap == 0) return;
3465 /* [HR] Split this into 2 loops for non-square boards. */
3467 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3468 gridSegments[i].x1 = 0;
3469 gridSegments[i].x2 =
3470 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3471 gridSegments[i].y1 = gridSegments[i].y2
3472 = lineGap / 2 + (i * (squareSize + lineGap));
3475 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3476 gridSegments[j + i].y1 = 0;
3477 gridSegments[j + i].y2 =
3478 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3479 gridSegments[j + i].x1 = gridSegments[j + i].x2
3480 = lineGap / 2 + (j * (squareSize + lineGap));
3484 static void MenuBarSelect(w, addr, index)
3489 XtActionProc proc = (XtActionProc) addr;
3491 (proc)(NULL, NULL, NULL, NULL);
3494 void CreateMenuBarPopup(parent, name, mb)
3504 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3507 XtSetArg(args[j], XtNleftMargin, 20); j++;
3508 XtSetArg(args[j], XtNrightMargin, 20); j++;
3510 while (mi->string != NULL) {
3511 if (strcmp(mi->string, "----") == 0) {
3512 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3515 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3516 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3518 XtAddCallback(entry, XtNcallback,
3519 (XtCallbackProc) MenuBarSelect,
3520 (caddr_t) mi->proc);
3526 Widget CreateMenuBar(mb)
3530 Widget anchor, menuBar;
3532 char menuName[MSG_SIZ];
3535 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3536 XtSetArg(args[j], XtNvSpace, 0); j++;
3537 XtSetArg(args[j], XtNborderWidth, 0); j++;
3538 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3539 formWidget, args, j);
3541 while (mb->name != NULL) {
3542 strcpy(menuName, "menu");
3543 strcat(menuName, mb->name);
3545 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3548 shortName[0] = _(mb->name)[0];
3549 shortName[1] = NULLCHAR;
3550 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3553 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3556 XtSetArg(args[j], XtNborderWidth, 0); j++;
3557 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3559 CreateMenuBarPopup(menuBar, menuName, mb);
3565 Widget CreateButtonBar(mi)
3569 Widget button, buttonBar;
3573 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3575 XtSetArg(args[j], XtNhSpace, 0); j++;
3577 XtSetArg(args[j], XtNborderWidth, 0); j++;
3578 XtSetArg(args[j], XtNvSpace, 0); j++;
3579 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3580 formWidget, args, j);
3582 while (mi->string != NULL) {
3585 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3586 XtSetArg(args[j], XtNborderWidth, 0); j++;
3588 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3589 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3590 buttonBar, args, j);
3591 XtAddCallback(button, XtNcallback,
3592 (XtCallbackProc) MenuBarSelect,
3593 (caddr_t) mi->proc);
3600 CreatePieceMenu(name, color)
3607 ChessSquare selection;
3609 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3610 boardWidget, args, 0);
3612 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3613 String item = pieceMenuStrings[color][i];
3615 if (strcmp(item, "----") == 0) {
3616 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3619 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3620 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3622 selection = pieceMenuTranslation[color][i];
3623 XtAddCallback(entry, XtNcallback,
3624 (XtCallbackProc) PieceMenuSelect,
3625 (caddr_t) selection);
3626 if (selection == WhitePawn || selection == BlackPawn) {
3627 XtSetArg(args[0], XtNpopupOnEntry, entry);
3628 XtSetValues(menu, args, 1);
3641 ChessSquare selection;
3643 whitePieceMenu = CreatePieceMenu("menuW", 0);
3644 blackPieceMenu = CreatePieceMenu("menuB", 1);
3646 XtRegisterGrabAction(PieceMenuPopup, True,
3647 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3648 GrabModeAsync, GrabModeAsync);
3650 XtSetArg(args[0], XtNlabel, _("Drop"));
3651 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3652 boardWidget, args, 1);
3653 for (i = 0; i < DROP_MENU_SIZE; i++) {
3654 String item = dropMenuStrings[i];
3656 if (strcmp(item, "----") == 0) {
3657 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3660 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3661 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3663 selection = dropMenuTranslation[i];
3664 XtAddCallback(entry, XtNcallback,
3665 (XtCallbackProc) DropMenuSelect,
3666 (caddr_t) selection);
3671 void SetupDropMenu()
3679 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3680 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3681 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3682 dmEnables[i].piece);
3683 XtSetSensitive(entry, p != NULL || !appData.testLegality
3684 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3685 && !appData.icsActive));
3687 while (p && *p++ == dmEnables[i].piece) count++;
3688 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3690 XtSetArg(args[j], XtNlabel, label); j++;
3691 XtSetValues(entry, args, j);
3695 void PieceMenuPopup(w, event, params, num_params)
3699 Cardinal *num_params;
3702 if (event->type != ButtonPress) return;
3703 if (errorUp) ErrorPopDown();
3707 whichMenu = params[0];
3709 case IcsPlayingWhite:
3710 case IcsPlayingBlack:
3712 case MachinePlaysWhite:
3713 case MachinePlaysBlack:
3714 if (appData.testLegality &&
3715 gameInfo.variant != VariantBughouse &&
3716 gameInfo.variant != VariantCrazyhouse) return;
3718 whichMenu = "menuD";
3724 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3725 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3726 pmFromX = pmFromY = -1;
3730 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3732 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3734 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3737 static void PieceMenuSelect(w, piece, junk)
3742 if (pmFromX < 0 || pmFromY < 0) return;
3743 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3746 static void DropMenuSelect(w, piece, junk)
3751 if (pmFromX < 0 || pmFromY < 0) return;
3752 DropMenuEvent(piece, pmFromX, pmFromY);
3755 void WhiteClock(w, event, prms, nprms)
3761 if (gameMode == EditPosition || gameMode == IcsExamining) {
3762 SetWhiteToPlayEvent();
3763 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3768 void BlackClock(w, event, prms, nprms)
3774 if (gameMode == EditPosition || gameMode == IcsExamining) {
3775 SetBlackToPlayEvent();
3776 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3783 * If the user selects on a border boundary, return -1; if off the board,
3784 * return -2. Otherwise map the event coordinate to the square.
3786 int EventToSquare(x, limit)
3794 if ((x % (squareSize + lineGap)) >= squareSize)
3796 x /= (squareSize + lineGap);
3802 static void do_flash_delay(msec)
3808 static void drawHighlight(file, rank, gc)
3814 if (lineGap == 0 || appData.blindfold) return;
3817 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3818 (squareSize + lineGap);
3819 y = lineGap/2 + rank * (squareSize + lineGap);
3821 x = lineGap/2 + file * (squareSize + lineGap);
3822 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3823 (squareSize + lineGap);
3826 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3827 squareSize+lineGap, squareSize+lineGap);
3830 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3831 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3834 SetHighlights(fromX, fromY, toX, toY)
3835 int fromX, fromY, toX, toY;
3837 if (hi1X != fromX || hi1Y != fromY) {
3838 if (hi1X >= 0 && hi1Y >= 0) {
3839 drawHighlight(hi1X, hi1Y, lineGC);
3841 if (fromX >= 0 && fromY >= 0) {
3842 drawHighlight(fromX, fromY, highlineGC);
3845 if (hi2X != toX || hi2Y != toY) {
3846 if (hi2X >= 0 && hi2Y >= 0) {
3847 drawHighlight(hi2X, hi2Y, lineGC);
3849 if (toX >= 0 && toY >= 0) {
3850 drawHighlight(toX, toY, highlineGC);
3862 SetHighlights(-1, -1, -1, -1);
3867 SetPremoveHighlights(fromX, fromY, toX, toY)
3868 int fromX, fromY, toX, toY;
3870 if (pm1X != fromX || pm1Y != fromY) {
3871 if (pm1X >= 0 && pm1Y >= 0) {
3872 drawHighlight(pm1X, pm1Y, lineGC);
3874 if (fromX >= 0 && fromY >= 0) {
3875 drawHighlight(fromX, fromY, prelineGC);
3878 if (pm2X != toX || pm2Y != toY) {
3879 if (pm2X >= 0 && pm2Y >= 0) {
3880 drawHighlight(pm2X, pm2Y, lineGC);
3882 if (toX >= 0 && toY >= 0) {
3883 drawHighlight(toX, toY, prelineGC);
3893 ClearPremoveHighlights()
3895 SetPremoveHighlights(-1, -1, -1, -1);
3898 static void BlankSquare(x, y, color, piece, dest)
3903 if (useImages && useImageSqs) {
3907 pm = xpmLightSquare;
3912 case 2: /* neutral */
3917 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3918 squareSize, squareSize, x, y);
3928 case 2: /* neutral */
3933 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3938 I split out the routines to draw a piece so that I could
3939 make a generic flash routine.
3941 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3943 int square_color, x, y;
3946 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3947 switch (square_color) {
3949 case 2: /* neutral */
3951 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3952 ? *pieceToOutline(piece)
3953 : *pieceToSolid(piece),
3954 dest, bwPieceGC, 0, 0,
3955 squareSize, squareSize, x, y);
3958 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3959 ? *pieceToSolid(piece)
3960 : *pieceToOutline(piece),
3961 dest, wbPieceGC, 0, 0,
3962 squareSize, squareSize, x, y);
3967 static void monoDrawPiece(piece, square_color, x, y, dest)
3969 int square_color, x, y;
3972 switch (square_color) {
3974 case 2: /* neutral */
3976 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3977 ? *pieceToOutline(piece)
3978 : *pieceToSolid(piece),
3979 dest, bwPieceGC, 0, 0,
3980 squareSize, squareSize, x, y, 1);
3983 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3984 ? *pieceToSolid(piece)
3985 : *pieceToOutline(piece),
3986 dest, wbPieceGC, 0, 0,
3987 squareSize, squareSize, x, y, 1);
3992 static void colorDrawPiece(piece, square_color, x, y, dest)
3994 int square_color, x, y;
3997 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3998 switch (square_color) {
4000 XCopyPlane(xDisplay, *pieceToSolid(piece),
4001 dest, (int) piece < (int) BlackPawn
4002 ? wlPieceGC : blPieceGC, 0, 0,
4003 squareSize, squareSize, x, y, 1);
4006 XCopyPlane(xDisplay, *pieceToSolid(piece),
4007 dest, (int) piece < (int) BlackPawn
4008 ? wdPieceGC : bdPieceGC, 0, 0,
4009 squareSize, squareSize, x, y, 1);
4011 case 2: /* neutral */
4013 XCopyPlane(xDisplay, *pieceToSolid(piece),
4014 dest, (int) piece < (int) BlackPawn
4015 ? wjPieceGC : bjPieceGC, 0, 0,
4016 squareSize, squareSize, x, y, 1);
4021 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4023 int square_color, x, y;
4028 switch (square_color) {
4030 case 2: /* neutral */
4032 if ((int)piece < (int) BlackPawn) {
4040 if ((int)piece < (int) BlackPawn) {
4048 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4049 dest, wlPieceGC, 0, 0,
4050 squareSize, squareSize, x, y);
4053 typedef void (*DrawFunc)();
4055 DrawFunc ChooseDrawFunc()
4057 if (appData.monoMode) {
4058 if (DefaultDepth(xDisplay, xScreen) == 1) {
4059 return monoDrawPiece_1bit;
4061 return monoDrawPiece;
4065 return colorDrawPieceImage;
4067 return colorDrawPiece;
4071 /* [HR] determine square color depending on chess variant. */
4072 static int SquareColor(row, column)
4077 if (gameInfo.variant == VariantXiangqi) {
4078 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4080 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4082 } else if (row <= 4) {
4088 square_color = ((column + row) % 2) == 1;
4091 /* [hgm] holdings: next line makes all holdings squares light */
4092 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4094 return square_color;
4097 void DrawSquare(row, column, piece, do_flash)
4098 int row, column, do_flash;
4101 int square_color, x, y, direction, font_ascent, font_descent;
4104 XCharStruct overall;
4108 /* Calculate delay in milliseconds (2-delays per complete flash) */
4109 flash_delay = 500 / appData.flashRate;
4112 x = lineGap + ((BOARD_WIDTH-1)-column) *
4113 (squareSize + lineGap);
4114 y = lineGap + row * (squareSize + lineGap);
4116 x = lineGap + column * (squareSize + lineGap);
4117 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4118 (squareSize + lineGap);
4121 square_color = SquareColor(row, column);
4123 if ( // [HGM] holdings: blank out area between board and holdings
4124 column == BOARD_LEFT-1 || column == BOARD_RGHT
4125 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4126 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4127 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4129 // [HGM] print piece counts next to holdings
4130 string[1] = NULLCHAR;
4131 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4132 string[0] = '0' + piece;
4133 XTextExtents(countFontStruct, string, 1, &direction,
4134 &font_ascent, &font_descent, &overall);
4135 if (appData.monoMode) {
4136 XDrawImageString(xDisplay, xBoardWindow, countGC,
4137 x + squareSize - overall.width - 2,
4138 y + font_ascent + 1, string, 1);
4140 XDrawString(xDisplay, xBoardWindow, countGC,
4141 x + squareSize - overall.width - 2,
4142 y + font_ascent + 1, string, 1);
4145 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4146 string[0] = '0' + piece;
4147 XTextExtents(countFontStruct, string, 1, &direction,
4148 &font_ascent, &font_descent, &overall);
4149 if (appData.monoMode) {
4150 XDrawImageString(xDisplay, xBoardWindow, countGC,
4151 x + 2, y + font_ascent + 1, string, 1);
4153 XDrawString(xDisplay, xBoardWindow, countGC,
4154 x + 2, y + font_ascent + 1, string, 1);
4158 if (piece == EmptySquare || appData.blindfold) {
4159 BlankSquare(x, y, square_color, piece, xBoardWindow);
4161 drawfunc = ChooseDrawFunc();
4162 if (do_flash && appData.flashCount > 0) {
4163 for (i=0; i<appData.flashCount; ++i) {
4165 drawfunc(piece, square_color, x, y, xBoardWindow);
4166 XSync(xDisplay, False);
4167 do_flash_delay(flash_delay);
4169 BlankSquare(x, y, square_color, piece, xBoardWindow);
4170 XSync(xDisplay, False);
4171 do_flash_delay(flash_delay);
4174 drawfunc(piece, square_color, x, y, xBoardWindow);
4178 string[1] = NULLCHAR;
4179 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4180 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4181 string[0] = 'a' + column - BOARD_LEFT;
4182 XTextExtents(coordFontStruct, string, 1, &direction,
4183 &font_ascent, &font_descent, &overall);
4184 if (appData.monoMode) {
4185 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4186 x + squareSize - overall.width - 2,
4187 y + squareSize - font_descent - 1, string, 1);
4189 XDrawString(xDisplay, xBoardWindow, coordGC,
4190 x + squareSize - overall.width - 2,
4191 y + squareSize - font_descent - 1, string, 1);
4194 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4195 string[0] = ONE + row;
4196 XTextExtents(coordFontStruct, string, 1, &direction,
4197 &font_ascent, &font_descent, &overall);
4198 if (appData.monoMode) {
4199 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4200 x + 2, y + font_ascent + 1, string, 1);
4202 XDrawString(xDisplay, xBoardWindow, coordGC,
4203 x + 2, y + font_ascent + 1, string, 1);
4209 /* Why is this needed on some versions of X? */
4210 void EventProc(widget, unused, event)
4215 if (!XtIsRealized(widget))
4218 switch (event->type) {
4220 if (event->xexpose.count > 0) return; /* no clipping is done */
4221 XDrawPosition(widget, True, NULL);
4229 void DrawPosition(fullRedraw, board)
4230 /*Boolean*/int fullRedraw;
4233 XDrawPosition(boardWidget, fullRedraw, board);
4236 /* Returns 1 if there are "too many" differences between b1 and b2
4237 (i.e. more than 1 move was made) */
4238 static int too_many_diffs(b1, b2)
4244 for (i=0; i<BOARD_HEIGHT; ++i) {
4245 for (j=0; j<BOARD_WIDTH; ++j) {
4246 if (b1[i][j] != b2[i][j]) {
4247 if (++c > 4) /* Castling causes 4 diffs */
4256 /* Matrix describing castling maneuvers */
4257 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4258 static int castling_matrix[4][5] = {
4259 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4260 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4261 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4262 { 7, 7, 4, 5, 6 } /* 0-0, black */
4265 /* Checks whether castling occurred. If it did, *rrow and *rcol
4266 are set to the destination (row,col) of the rook that moved.
4268 Returns 1 if castling occurred, 0 if not.
4270 Note: Only handles a max of 1 castling move, so be sure
4271 to call too_many_diffs() first.
4273 static int check_castle_draw(newb, oldb, rrow, rcol)
4280 /* For each type of castling... */
4281 for (i=0; i<4; ++i) {
4282 r = castling_matrix[i];
4284 /* Check the 4 squares involved in the castling move */
4286 for (j=1; j<=4; ++j) {
4287 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4294 /* All 4 changed, so it must be a castling move */
4303 static int damage[BOARD_RANKS][BOARD_FILES];
4306 * event handler for redrawing the board
4308 void XDrawPosition(w, repaint, board)
4310 /*Boolean*/int repaint;
4314 static int lastFlipView = 0;
4315 static int lastBoardValid = 0;
4316 static Board lastBoard;
4320 if (board == NULL) {
4321 if (!lastBoardValid) return;
4324 if (!lastBoardValid || lastFlipView != flipView) {
4325 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4326 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4331 * It would be simpler to clear the window with XClearWindow()
4332 * but this causes a very distracting flicker.
4335 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4337 /* If too much changes (begin observing new game, etc.), don't
4339 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4341 /* Special check for castling so we don't flash both the king
4342 and the rook (just flash the king). */
4344 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4345 /* Draw rook with NO flashing. King will be drawn flashing later */
4346 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4347 lastBoard[rrow][rcol] = board[rrow][rcol];
4351 /* First pass -- Draw (newly) empty squares and repair damage.
4352 This prevents you from having a piece show up twice while it
4353 is flashing on its new square */
4354 for (i = 0; i < BOARD_HEIGHT; i++)
4355 for (j = 0; j < BOARD_WIDTH; j++)
4356 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4358 DrawSquare(i, j, board[i][j], 0);
4359 damage[i][j] = False;
4362 /* Second pass -- Draw piece(s) in new position and flash them */
4363 for (i = 0; i < BOARD_HEIGHT; i++)
4364 for (j = 0; j < BOARD_WIDTH; j++)
4365 if (board[i][j] != lastBoard[i][j]) {
4366 DrawSquare(i, j, board[i][j], do_flash);
4370 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4371 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4373 for (i = 0; i < BOARD_HEIGHT; i++)
4374 for (j = 0; j < BOARD_WIDTH; j++) {
4375 DrawSquare(i, j, board[i][j], 0);
4376 damage[i][j] = False;
4380 CopyBoard(lastBoard, board);
4382 lastFlipView = flipView;
4384 /* Draw highlights */
4385 if (pm1X >= 0 && pm1Y >= 0) {
4386 drawHighlight(pm1X, pm1Y, prelineGC);
4388 if (pm2X >= 0 && pm2Y >= 0) {
4389 drawHighlight(pm2X, pm2Y, prelineGC);
4391 if (hi1X >= 0 && hi1Y >= 0) {
4392 drawHighlight(hi1X, hi1Y, highlineGC);
4394 if (hi2X >= 0 && hi2Y >= 0) {
4395 drawHighlight(hi2X, hi2Y, highlineGC);
4398 /* If piece being dragged around board, must redraw that too */
4401 XSync(xDisplay, False);
4406 * event handler for redrawing the board
4408 void DrawPositionProc(w, event, prms, nprms)
4414 XDrawPosition(w, True, NULL);
4419 * event handler for parsing user moves
4421 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4422 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4423 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4424 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4425 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4426 // and at the end FinishMove() to perform the move after optional promotion popups.
4427 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4428 void HandleUserMove(w, event, prms, nprms)
4434 if (w != boardWidget || errorExitStatus != -1) return;
4437 if (event->type == ButtonPress) {
4438 XtPopdown(promotionShell);
4439 XtDestroyWidget(promotionShell);
4440 promotionUp = False;
4448 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4449 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4450 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4453 void AnimateUserMove (Widget w, XEvent * event,
4454 String * params, Cardinal * nParams)
4456 DragPieceMove(event->xmotion.x, event->xmotion.y);
4459 Widget CommentCreate(name, text, mutable, callback, lines)
4461 int /*Boolean*/ mutable;
4462 XtCallbackProc callback;
4466 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4471 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4472 XtGetValues(boardWidget, args, j);
4475 XtSetArg(args[j], XtNresizable, True); j++;
4478 XtCreatePopupShell(name, topLevelShellWidgetClass,
4479 shellWidget, args, j);
4482 XtCreatePopupShell(name, transientShellWidgetClass,
4483 shellWidget, args, j);
4486 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4487 layoutArgs, XtNumber(layoutArgs));
4489 XtCreateManagedWidget("form", formWidgetClass, layout,
4490 formArgs, XtNumber(formArgs));
4494 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4495 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4497 XtSetArg(args[j], XtNstring, text); j++;
4498 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4499 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4500 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4501 XtSetArg(args[j], XtNright, XtChainRight); j++;
4502 XtSetArg(args[j], XtNresizable, True); j++;
4503 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4504 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4505 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4506 XtSetArg(args[j], XtNautoFill, True); j++;
4507 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4509 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4513 XtSetArg(args[j], XtNfromVert, edit); j++;
4514 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4515 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4516 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4517 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4519 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4520 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4523 XtSetArg(args[j], XtNfromVert, edit); j++;
4524 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4525 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4526 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4527 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4528 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4530 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4531 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4534 XtSetArg(args[j], XtNfromVert, edit); j++;
4535 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4536 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4537 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4538 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4539 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4541 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4542 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4545 XtSetArg(args[j], XtNfromVert, edit); j++;
4546 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4547 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4548 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4549 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4551 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4552 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4555 XtSetArg(args[j], XtNfromVert, edit); j++;
4556 XtSetArg(args[j], XtNfromHoriz, b_close); 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(_("edit"), commandWidgetClass, form, args, j);
4563 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4566 XtRealizeWidget(shell);
4568 if (commentX == -1) {
4571 Dimension pw_height;
4572 Dimension ew_height;
4575 XtSetArg(args[j], XtNheight, &ew_height); j++;
4576 XtGetValues(edit, args, j);
4579 XtSetArg(args[j], XtNheight, &pw_height); j++;
4580 XtGetValues(shell, args, j);
4581 commentH = pw_height + (lines - 1) * ew_height;
4582 commentW = bw_width - 16;
4584 XSync(xDisplay, False);
4586 /* This code seems to tickle an X bug if it is executed too soon
4587 after xboard starts up. The coordinates get transformed as if
4588 the main window was positioned at (0, 0).
4590 XtTranslateCoords(shellWidget,
4591 (bw_width - commentW) / 2, 0 - commentH / 2,
4592 &commentX, &commentY);
4594 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4595 RootWindowOfScreen(XtScreen(shellWidget)),
4596 (bw_width - commentW) / 2, 0 - commentH / 2,
4601 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4604 if(wpComment.width > 0) {
4605 commentX = wpComment.x;
4606 commentY = wpComment.y;
4607 commentW = wpComment.width;
4608 commentH = wpComment.height;
4612 XtSetArg(args[j], XtNheight, commentH); j++;
4613 XtSetArg(args[j], XtNwidth, commentW); j++;
4614 XtSetArg(args[j], XtNx, commentX); j++;
4615 XtSetArg(args[j], XtNy, commentY); j++;
4616 XtSetValues(shell, args, j);
4617 XtSetKeyboardFocus(shell, edit);
4622 /* Used for analysis window and ICS input window */
4623 Widget MiscCreate(name, text, mutable, callback, lines)
4625 int /*Boolean*/ mutable;
4626 XtCallbackProc callback;
4630 Widget shell, layout, form, edit;
4632 Dimension bw_width, pw_height, ew_height, w, h;
4638 XtSetArg(args[j], XtNresizable, True); j++;
4641 XtCreatePopupShell(name, topLevelShellWidgetClass,
4642 shellWidget, args, j);
4645 XtCreatePopupShell(name, transientShellWidgetClass,
4646 shellWidget, args, j);
4649 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4650 layoutArgs, XtNumber(layoutArgs));
4652 XtCreateManagedWidget("form", formWidgetClass, layout,
4653 formArgs, XtNumber(formArgs));
4657 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4658 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4660 XtSetArg(args[j], XtNstring, text); j++;
4661 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4662 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4663 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4664 XtSetArg(args[j], XtNright, XtChainRight); j++;
4665 XtSetArg(args[j], XtNresizable, True); j++;
4666 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4667 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4668 XtSetArg(args[j], XtNautoFill, True); j++;
4669 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4671 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4673 XtRealizeWidget(shell);
4676 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4677 XtGetValues(boardWidget, args, j);
4680 XtSetArg(args[j], XtNheight, &ew_height); j++;
4681 XtGetValues(edit, args, j);
4684 XtSetArg(args[j], XtNheight, &pw_height); j++;
4685 XtGetValues(shell, args, j);
4686 h = pw_height + (lines - 1) * ew_height;
4689 XSync(xDisplay, False);
4691 /* This code seems to tickle an X bug if it is executed too soon
4692 after xboard starts up. The coordinates get transformed as if
4693 the main window was positioned at (0, 0).
4695 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4697 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4698 RootWindowOfScreen(XtScreen(shellWidget)),
4699 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4703 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4706 XtSetArg(args[j], XtNheight, h); j++;
4707 XtSetArg(args[j], XtNwidth, w); j++;
4708 XtSetArg(args[j], XtNx, x); j++;
4709 XtSetArg(args[j], XtNy, y); j++;
4710 XtSetValues(shell, args, j);
4716 static int savedIndex; /* gross that this is global */
4718 void EditCommentPopUp(index, title, text)
4727 if (text == NULL) text = "";
4729 if (editShell == NULL) {
4731 CommentCreate(title, text, True, EditCommentCallback, 4);
4732 XtRealizeWidget(editShell);
4733 CatchDeleteWindow(editShell, "EditCommentPopDown");
4735 edit = XtNameToWidget(editShell, "*form.text");
4737 XtSetArg(args[j], XtNstring, text); j++;
4738 XtSetValues(edit, args, j);
4740 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4741 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4742 XtSetValues(editShell, args, j);
4745 XtPopup(editShell, XtGrabNone);
4749 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4750 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4754 void EditCommentCallback(w, client_data, call_data)
4756 XtPointer client_data, call_data;
4764 XtSetArg(args[j], XtNlabel, &name); j++;
4765 XtGetValues(w, args, j);
4767 if (strcmp(name, _("ok")) == 0) {
4768 edit = XtNameToWidget(editShell, "*form.text");
4770 XtSetArg(args[j], XtNstring, &val); j++;
4771 XtGetValues(edit, args, j);
4772 ReplaceComment(savedIndex, val);
4773 EditCommentPopDown();
4774 } else if (strcmp(name, _("cancel")) == 0) {
4775 EditCommentPopDown();
4776 } else if (strcmp(name, _("clear")) == 0) {
4777 edit = XtNameToWidget(editShell, "*form.text");
4778 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4779 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4783 void EditCommentPopDown()
4788 if (!editUp) return;
4790 XtSetArg(args[j], XtNx, &commentX); j++;
4791 XtSetArg(args[j], XtNy, &commentY); j++;
4792 XtSetArg(args[j], XtNheight, &commentH); j++;
4793 XtSetArg(args[j], XtNwidth, &commentW); j++;
4794 XtGetValues(editShell, args, j);
4795 XtPopdown(editShell);
4798 XtSetArg(args[j], XtNleftBitmap, None); j++;
4799 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4803 void ICSInputBoxPopUp()
4808 char *title = _("ICS Input");
4811 if (ICSInputShell == NULL) {
4812 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4813 tr = XtParseTranslationTable(ICSInputTranslations);
4814 edit = XtNameToWidget(ICSInputShell, "*form.text");
4815 XtOverrideTranslations(edit, tr);
4816 XtRealizeWidget(ICSInputShell);
4817 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4820 edit = XtNameToWidget(ICSInputShell, "*form.text");
4822 XtSetArg(args[j], XtNstring, ""); j++;
4823 XtSetValues(edit, args, j);
4825 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4826 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4827 XtSetValues(ICSInputShell, args, j);
4830 XtPopup(ICSInputShell, XtGrabNone);
4831 XtSetKeyboardFocus(ICSInputShell, edit);
4833 ICSInputBoxUp = True;
4835 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4836 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4840 void ICSInputSendText()
4847 edit = XtNameToWidget(ICSInputShell, "*form.text");
4849 XtSetArg(args[j], XtNstring, &val); j++;
4850 XtGetValues(edit, args, j);
4851 SendMultiLineToICS(val);
4852 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4853 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4856 void ICSInputBoxPopDown()
4861 if (!ICSInputBoxUp) return;
4863 XtPopdown(ICSInputShell);
4864 ICSInputBoxUp = False;
4866 XtSetArg(args[j], XtNleftBitmap, None); j++;
4867 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4871 void CommentPopUp(title, text)
4878 if (commentShell == NULL) {
4880 CommentCreate(title, text, False, CommentCallback, 4);
4881 XtRealizeWidget(commentShell);
4882 CatchDeleteWindow(commentShell, "CommentPopDown");
4884 edit = XtNameToWidget(commentShell, "*form.text");
4886 XtSetArg(args[j], XtNstring, text); j++;
4887 XtSetValues(edit, args, j);
4889 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4890 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4891 XtSetValues(commentShell, args, j);
4894 XtPopup(commentShell, XtGrabNone);
4895 XSync(xDisplay, False);
4900 void CommentCallback(w, client_data, call_data)
4902 XtPointer client_data, call_data;
4909 XtSetArg(args[j], XtNlabel, &name); j++;
4910 XtGetValues(w, args, j);
4912 if (strcmp(name, _("close")) == 0) {
4914 } else if (strcmp(name, _("edit")) == 0) {
4921 void CommentPopDown()
4926 if (!commentUp) return;
4928 XtSetArg(args[j], XtNx, &commentX); j++;
4929 XtSetArg(args[j], XtNy, &commentY); j++;
4930 XtSetArg(args[j], XtNwidth, &commentW); j++;
4931 XtSetArg(args[j], XtNheight, &commentH); j++;
4932 XtGetValues(commentShell, args, j);
4933 XtPopdown(commentShell);
4934 XSync(xDisplay, False);
4938 void FileNamePopUp(label, def, proc, openMode)
4945 Widget popup, layout, dialog, edit;
4951 fileProc = proc; /* I can't see a way not */
4952 fileOpenMode = openMode; /* to use globals here */
4955 XtSetArg(args[i], XtNresizable, True); i++;
4956 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4957 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4958 fileNameShell = popup =
4959 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4960 shellWidget, args, i);
4963 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4964 layoutArgs, XtNumber(layoutArgs));
4967 XtSetArg(args[i], XtNlabel, label); i++;
4968 XtSetArg(args[i], XtNvalue, def); i++;
4969 XtSetArg(args[i], XtNborderWidth, 0); i++;
4970 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4973 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4974 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4975 (XtPointer) dialog);
4977 XtRealizeWidget(popup);
4978 CatchDeleteWindow(popup, "FileNamePopDown");
4980 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4981 &x, &y, &win_x, &win_y, &mask);
4983 XtSetArg(args[0], XtNx, x - 10);
4984 XtSetArg(args[1], XtNy, y - 30);
4985 XtSetValues(popup, args, 2);
4987 XtPopup(popup, XtGrabExclusive);
4990 edit = XtNameToWidget(dialog, "*value");
4991 XtSetKeyboardFocus(popup, edit);
4994 void FileNamePopDown()
4996 if (!filenameUp) return;
4997 XtPopdown(fileNameShell);
4998 XtDestroyWidget(fileNameShell);
5003 void FileNameCallback(w, client_data, call_data)
5005 XtPointer client_data, call_data;
5010 XtSetArg(args[0], XtNlabel, &name);
5011 XtGetValues(w, args, 1);
5013 if (strcmp(name, _("cancel")) == 0) {
5018 FileNameAction(w, NULL, NULL, NULL);
5021 void FileNameAction(w, event, prms, nprms)
5033 name = XawDialogGetValueString(w = XtParent(w));
5035 if ((name != NULL) && (*name != NULLCHAR)) {
5037 XtPopdown(w = XtParent(XtParent(w)));
5041 p = strrchr(buf, ' ');
5048 fullname = ExpandPathName(buf);
5050 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5053 f = fopen(fullname, fileOpenMode);
5055 DisplayError(_("Failed to open file"), errno);
5057 (void) (*fileProc)(f, index, buf);
5064 XtPopdown(w = XtParent(XtParent(w)));
5070 void PromotionPopUp()
5073 Widget dialog, layout;
5075 Dimension bw_width, pw_width;
5079 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5080 XtGetValues(boardWidget, args, j);
5083 XtSetArg(args[j], XtNresizable, True); j++;
5084 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5086 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5087 shellWidget, args, j);
5089 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5090 layoutArgs, XtNumber(layoutArgs));
5093 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5094 XtSetArg(args[j], XtNborderWidth, 0); j++;
5095 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5098 if(gameInfo.variant != VariantShogi) {
5099 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5100 (XtPointer) dialog);
5101 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5102 (XtPointer) dialog);
5103 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5104 (XtPointer) dialog);
5105 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5106 (XtPointer) dialog);
5107 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5108 gameInfo.variant == VariantGiveaway) {
5109 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5110 (XtPointer) dialog);
5112 if(gameInfo.variant == VariantCapablanca ||
5113 gameInfo.variant == VariantGothic ||
5114 gameInfo.variant == VariantCapaRandom) {
5115 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5116 (XtPointer) dialog);
5117 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5118 (XtPointer) dialog);
5120 } else // [HGM] shogi
5122 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5123 (XtPointer) dialog);
5124 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5125 (XtPointer) dialog);
5127 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5128 (XtPointer) dialog);
5130 XtRealizeWidget(promotionShell);
5131 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5134 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5135 XtGetValues(promotionShell, args, j);
5137 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5138 lineGap + squareSize/3 +
5139 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5140 0 : 6*(squareSize + lineGap)), &x, &y);
5143 XtSetArg(args[j], XtNx, x); j++;
5144 XtSetArg(args[j], XtNy, y); j++;
5145 XtSetValues(promotionShell, args, j);
5147 XtPopup(promotionShell, XtGrabNone);
5152 void PromotionPopDown()
5154 if (!promotionUp) return;
5155 XtPopdown(promotionShell);
5156 XtDestroyWidget(promotionShell);
5157 promotionUp = False;
5160 void PromotionCallback(w, client_data, call_data)
5162 XtPointer client_data, call_data;
5168 XtSetArg(args[0], XtNlabel, &name);
5169 XtGetValues(w, args, 1);
5173 if (fromX == -1) return;
5175 if (strcmp(name, _("cancel")) == 0) {
5179 } else if (strcmp(name, _("Knight")) == 0) {
5181 } else if (strcmp(name, _("Promote")) == 0) {
5183 } else if (strcmp(name, _("Defer")) == 0) {
5186 promoChar = ToLower(name[0]);
5189 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5191 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5192 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5197 void ErrorCallback(w, client_data, call_data)
5199 XtPointer client_data, call_data;
5202 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5204 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5210 if (!errorUp) return;
5212 XtPopdown(errorShell);
5213 XtDestroyWidget(errorShell);
5214 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5217 void ErrorPopUp(title, label, modal)
5218 char *title, *label;
5222 Widget dialog, layout;
5226 Dimension bw_width, pw_width;
5227 Dimension pw_height;
5231 XtSetArg(args[i], XtNresizable, True); i++;
5232 XtSetArg(args[i], XtNtitle, title); i++;
5234 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5235 shellWidget, args, i);
5237 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5238 layoutArgs, XtNumber(layoutArgs));
5241 XtSetArg(args[i], XtNlabel, label); i++;
5242 XtSetArg(args[i], XtNborderWidth, 0); i++;
5243 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5246 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5248 XtRealizeWidget(errorShell);
5249 CatchDeleteWindow(errorShell, "ErrorPopDown");
5252 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5253 XtGetValues(boardWidget, args, i);
5255 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5256 XtSetArg(args[i], XtNheight, &pw_height); i++;
5257 XtGetValues(errorShell, args, i);
5260 /* This code seems to tickle an X bug if it is executed too soon
5261 after xboard starts up. The coordinates get transformed as if
5262 the main window was positioned at (0, 0).
5264 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5265 0 - pw_height + squareSize / 3, &x, &y);
5267 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5268 RootWindowOfScreen(XtScreen(boardWidget)),
5269 (bw_width - pw_width) / 2,
5270 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5274 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5277 XtSetArg(args[i], XtNx, x); i++;
5278 XtSetArg(args[i], XtNy, y); i++;
5279 XtSetValues(errorShell, args, i);
5282 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5285 /* Disable all user input other than deleting the window */
5286 static int frozen = 0;
5290 /* Grab by a widget that doesn't accept input */
5291 XtAddGrab(messageWidget, TRUE, FALSE);
5295 /* Undo a FreezeUI */
5298 if (!frozen) return;
5299 XtRemoveGrab(messageWidget);
5303 char *ModeToWidgetName(mode)
5307 case BeginningOfGame:
5308 if (appData.icsActive)
5309 return "menuMode.ICS Client";
5310 else if (appData.noChessProgram ||
5311 *appData.cmailGameName != NULLCHAR)
5312 return "menuMode.Edit Game";
5314 return "menuMode.Machine Black";
5315 case MachinePlaysBlack:
5316 return "menuMode.Machine Black";
5317 case MachinePlaysWhite:
5318 return "menuMode.Machine White";
5320 return "menuMode.Analysis Mode";
5322 return "menuMode.Analyze File";
5323 case TwoMachinesPlay:
5324 return "menuMode.Two Machines";
5326 return "menuMode.Edit Game";
5327 case PlayFromGameFile:
5328 return "menuFile.Load Game";
5330 return "menuMode.Edit Position";
5332 return "menuMode.Training";
5333 case IcsPlayingWhite:
5334 case IcsPlayingBlack:
5338 return "menuMode.ICS Client";
5345 void ModeHighlight()
5348 static int oldPausing = FALSE;
5349 static GameMode oldmode = (GameMode) -1;
5352 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5354 if (pausing != oldPausing) {
5355 oldPausing = pausing;
5357 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5359 XtSetArg(args[0], XtNleftBitmap, None);
5361 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5364 if (appData.showButtonBar) {
5365 /* Always toggle, don't set. Previous code messes up when
5366 invoked while the button is pressed, as releasing it
5367 toggles the state again. */
5370 XtSetArg(args[0], XtNbackground, &oldbg);
5371 XtSetArg(args[1], XtNforeground, &oldfg);
5372 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5374 XtSetArg(args[0], XtNbackground, oldfg);
5375 XtSetArg(args[1], XtNforeground, oldbg);
5377 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5381 wname = ModeToWidgetName(oldmode);
5382 if (wname != NULL) {
5383 XtSetArg(args[0], XtNleftBitmap, None);
5384 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5386 wname = ModeToWidgetName(gameMode);
5387 if (wname != NULL) {
5388 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5389 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5393 /* Maybe all the enables should be handled here, not just this one */
5394 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5395 gameMode == Training || gameMode == PlayFromGameFile);
5400 * Button/menu procedures
5402 void ResetProc(w, event, prms, nprms)
5411 int LoadGamePopUp(f, gameNumber, title)
5416 cmailMsgLoaded = FALSE;
5417 if (gameNumber == 0) {
5418 int error = GameListBuild(f);
5420 DisplayError(_("Cannot build game list"), error);
5421 } else if (!ListEmpty(&gameList) &&
5422 ((ListGame *) gameList.tailPred)->number > 1) {
5423 GameListPopUp(f, title);
5429 return LoadGame(f, gameNumber, title, FALSE);
5432 void LoadGameProc(w, event, prms, nprms)
5438 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5441 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5444 void LoadNextGameProc(w, event, prms, nprms)
5453 void LoadPrevGameProc(w, event, prms, nprms)
5462 void ReloadGameProc(w, event, prms, nprms)
5471 void LoadNextPositionProc(w, event, prms, nprms)
5480 void LoadPrevPositionProc(w, event, prms, nprms)
5489 void ReloadPositionProc(w, event, prms, nprms)
5498 void LoadPositionProc(w, event, prms, nprms)
5504 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5507 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5510 void SaveGameProc(w, event, prms, nprms)
5516 FileNamePopUp(_("Save game file name?"),
5517 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5521 void SavePositionProc(w, event, prms, nprms)
5527 FileNamePopUp(_("Save position file name?"),
5528 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5532 void ReloadCmailMsgProc(w, event, prms, nprms)
5538 ReloadCmailMsgEvent(FALSE);
5541 void MailMoveProc(w, event, prms, nprms)
5550 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5551 static char *selected_fen_position=NULL;
5554 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5555 Atom *type_return, XtPointer *value_return,
5556 unsigned long *length_return, int *format_return)
5558 char *selection_tmp;
5560 if (!selected_fen_position) return False; /* should never happen */
5561 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5562 /* note: since no XtSelectionDoneProc was registered, Xt will
5563 * automatically call XtFree on the value returned. So have to
5564 * make a copy of it allocated with XtMalloc */
5565 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5566 strcpy(selection_tmp, selected_fen_position);
5568 *value_return=selection_tmp;
5569 *length_return=strlen(selection_tmp);
5570 *type_return=*target;
5571 *format_return = 8; /* bits per byte */
5573 } else if (*target == XA_TARGETS(xDisplay)) {
5574 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5575 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5576 targets_tmp[1] = XA_STRING;
5577 *value_return = targets_tmp;
5578 *type_return = XA_ATOM;
5580 *format_return = 8 * sizeof(Atom);
5581 if (*format_return > 32) {
5582 *length_return *= *format_return / 32;
5583 *format_return = 32;
5591 /* note: when called from menu all parameters are NULL, so no clue what the
5592 * Widget which was clicked on was, or what the click event was
5594 void CopyPositionProc(w, event, prms, nprms)
5601 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5602 * have a notion of a position that is selected but not copied.
5603 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5605 if(gameMode == EditPosition) EditPositionDone(TRUE);
5606 if (selected_fen_position) free(selected_fen_position);
5607 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5608 if (!selected_fen_position) return;
5609 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5611 SendPositionSelection,
5612 NULL/* lose_ownership_proc */ ,
5613 NULL/* transfer_done_proc */);
5614 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5616 SendPositionSelection,
5617 NULL/* lose_ownership_proc */ ,
5618 NULL/* transfer_done_proc */);
5621 /* function called when the data to Paste is ready */
5623 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5624 Atom *type, XtPointer value, unsigned long *len, int *format)
5627 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5628 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5629 EditPositionPasteFEN(fenstr);
5633 /* called when Paste Position button is pressed,
5634 * all parameters will be NULL */
5635 void PastePositionProc(w, event, prms, nprms)
5641 XtGetSelectionValue(menuBarWidget,
5642 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5643 /* (XtSelectionCallbackProc) */ PastePositionCB,
5644 NULL, /* client_data passed to PastePositionCB */
5646 /* better to use the time field from the event that triggered the
5647 * call to this function, but that isn't trivial to get
5655 SendGameSelection(Widget w, Atom *selection, Atom *target,
5656 Atom *type_return, XtPointer *value_return,
5657 unsigned long *length_return, int *format_return)
5659 char *selection_tmp;
5661 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5662 FILE* f = fopen(gameCopyFilename, "r");
5665 if (f == NULL) return False;
5669 selection_tmp = XtMalloc(len + 1);
5670 count = fread(selection_tmp, 1, len, f);
5672 XtFree(selection_tmp);
5675 selection_tmp[len] = NULLCHAR;
5676 *value_return = selection_tmp;
5677 *length_return = len;
5678 *type_return = *target;
5679 *format_return = 8; /* bits per byte */
5681 } else if (*target == XA_TARGETS(xDisplay)) {
5682 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5683 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5684 targets_tmp[1] = XA_STRING;
5685 *value_return = targets_tmp;
5686 *type_return = XA_ATOM;
5688 *format_return = 8 * sizeof(Atom);
5689 if (*format_return > 32) {
5690 *length_return *= *format_return / 32;
5691 *format_return = 32;
5699 /* note: when called from menu all parameters are NULL, so no clue what the
5700 * Widget which was clicked on was, or what the click event was
5702 void CopyGameProc(w, event, prms, nprms)
5710 ret = SaveGameToFile(gameCopyFilename, FALSE);
5714 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5715 * have a notion of a game that is selected but not copied.
5716 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5718 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5721 NULL/* lose_ownership_proc */ ,
5722 NULL/* transfer_done_proc */);
5723 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5726 NULL/* lose_ownership_proc */ ,
5727 NULL/* transfer_done_proc */);
5730 /* function called when the data to Paste is ready */
5732 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5733 Atom *type, XtPointer value, unsigned long *len, int *format)
5736 if (value == NULL || *len == 0) {
5737 return; /* nothing had been selected to copy */
5739 f = fopen(gamePasteFilename, "w");
5741 DisplayError(_("Can't open temp file"), errno);
5744 fwrite(value, 1, *len, f);
5747 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5750 /* called when Paste Game button is pressed,
5751 * all parameters will be NULL */
5752 void PasteGameProc(w, event, prms, nprms)
5758 XtGetSelectionValue(menuBarWidget,
5759 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5760 /* (XtSelectionCallbackProc) */ PasteGameCB,
5761 NULL, /* client_data passed to PasteGameCB */
5763 /* better to use the time field from the event that triggered the
5764 * call to this function, but that isn't trivial to get
5774 SaveGameProc(NULL, NULL, NULL, NULL);
5778 void QuitProc(w, event, prms, nprms)
5787 void PauseProc(w, event, prms, nprms)
5797 void MachineBlackProc(w, event, prms, nprms)
5803 MachineBlackEvent();
5806 void MachineWhiteProc(w, event, prms, nprms)
5812 MachineWhiteEvent();
5815 void AnalyzeModeProc(w, event, prms, nprms)
5823 if (!first.analysisSupport) {
5824 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5825 DisplayError(buf, 0);
5828 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5829 if (appData.icsActive) {
5830 if (gameMode != IcsObserving) {
5831 sprintf(buf,_("You are not observing a game"));
5832 DisplayError(buf, 0);
5834 if (appData.icsEngineAnalyze) {
5835 if (appData.debugMode)
5836 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5842 /* if enable, use want disable icsEngineAnalyze */
5843 if (appData.icsEngineAnalyze) {
5848 appData.icsEngineAnalyze = TRUE;
5849 if (appData.debugMode)
5850 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5852 if (!appData.showThinking)
5853 ShowThinkingProc(w,event,prms,nprms);
5858 void AnalyzeFileProc(w, event, prms, nprms)
5864 if (!first.analysisSupport) {
5866 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5867 DisplayError(buf, 0);
5872 if (!appData.showThinking)
5873 ShowThinkingProc(w,event,prms,nprms);
5876 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5877 AnalysisPeriodicEvent(1);
5880 void TwoMachinesProc(w, event, prms, nprms)
5889 void IcsClientProc(w, event, prms, nprms)
5898 void EditGameProc(w, event, prms, nprms)
5907 void EditPositionProc(w, event, prms, nprms)
5913 EditPositionEvent();
5916 void TrainingProc(w, event, prms, nprms)
5925 void EditCommentProc(w, event, prms, nprms)
5932 EditCommentPopDown();
5938 void IcsInputBoxProc(w, event, prms, nprms)
5944 if (ICSInputBoxUp) {
5945 ICSInputBoxPopDown();
5951 void AcceptProc(w, event, prms, nprms)
5960 void DeclineProc(w, event, prms, nprms)
5969 void RematchProc(w, event, prms, nprms)
5978 void CallFlagProc(w, event, prms, nprms)
5987 void DrawProc(w, event, prms, nprms)
5996 void AbortProc(w, event, prms, nprms)
6005 void AdjournProc(w, event, prms, nprms)
6014 void ResignProc(w, event, prms, nprms)
6023 void AdjuWhiteProc(w, event, prms, nprms)
6029 UserAdjudicationEvent(+1);
6032 void AdjuBlackProc(w, event, prms, nprms)
6038 UserAdjudicationEvent(-1);
6041 void AdjuDrawProc(w, event, prms, nprms)
6047 UserAdjudicationEvent(0);
6050 void EnterKeyProc(w, event, prms, nprms)
6056 if (ICSInputBoxUp == True)
6060 void StopObservingProc(w, event, prms, nprms)
6066 StopObservingEvent();
6069 void StopExaminingProc(w, event, prms, nprms)
6075 StopExaminingEvent();
6079 void ForwardProc(w, event, prms, nprms)
6089 void BackwardProc(w, event, prms, nprms)
6098 void ToStartProc(w, event, prms, nprms)
6107 void ToEndProc(w, event, prms, nprms)
6116 void RevertProc(w, event, prms, nprms)
6125 void TruncateGameProc(w, event, prms, nprms)
6131 TruncateGameEvent();
6133 void RetractMoveProc(w, event, prms, nprms)
6142 void MoveNowProc(w, event, prms, nprms)
6152 void AlwaysQueenProc(w, event, prms, nprms)
6160 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6162 if (appData.alwaysPromoteToQueen) {
6163 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6165 XtSetArg(args[0], XtNleftBitmap, None);
6167 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6171 void AnimateDraggingProc(w, event, prms, nprms)
6179 appData.animateDragging = !appData.animateDragging;
6181 if (appData.animateDragging) {
6182 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6185 XtSetArg(args[0], XtNleftBitmap, None);
6187 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6191 void AnimateMovingProc(w, event, prms, nprms)
6199 appData.animate = !appData.animate;
6201 if (appData.animate) {
6202 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6205 XtSetArg(args[0], XtNleftBitmap, None);
6207 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6211 void AutocommProc(w, event, prms, nprms)
6219 appData.autoComment = !appData.autoComment;
6221 if (appData.autoComment) {
6222 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6224 XtSetArg(args[0], XtNleftBitmap, None);
6226 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6231 void AutoflagProc(w, event, prms, nprms)
6239 appData.autoCallFlag = !appData.autoCallFlag;
6241 if (appData.autoCallFlag) {
6242 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6244 XtSetArg(args[0], XtNleftBitmap, None);
6246 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6250 void AutoflipProc(w, event, prms, nprms)
6258 appData.autoFlipView = !appData.autoFlipView;
6260 if (appData.autoFlipView) {
6261 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6263 XtSetArg(args[0], XtNleftBitmap, None);
6265 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6269 void AutobsProc(w, event, prms, nprms)
6277 appData.autoObserve = !appData.autoObserve;
6279 if (appData.autoObserve) {
6280 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6282 XtSetArg(args[0], XtNleftBitmap, None);
6284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6288 void AutoraiseProc(w, event, prms, nprms)
6296 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6298 if (appData.autoRaiseBoard) {
6299 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6301 XtSetArg(args[0], XtNleftBitmap, None);
6303 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6307 void AutosaveProc(w, event, prms, nprms)
6315 appData.autoSaveGames = !appData.autoSaveGames;
6317 if (appData.autoSaveGames) {
6318 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6320 XtSetArg(args[0], XtNleftBitmap, None);
6322 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6326 void BlindfoldProc(w, event, prms, nprms)
6334 appData.blindfold = !appData.blindfold;
6336 if (appData.blindfold) {
6337 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6339 XtSetArg(args[0], XtNleftBitmap, None);
6341 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6344 DrawPosition(True, NULL);
6347 void TestLegalityProc(w, event, prms, nprms)
6355 appData.testLegality = !appData.testLegality;
6357 if (appData.testLegality) {
6358 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6360 XtSetArg(args[0], XtNleftBitmap, None);
6362 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6367 void FlashMovesProc(w, event, prms, nprms)
6375 if (appData.flashCount == 0) {
6376 appData.flashCount = 3;
6378 appData.flashCount = -appData.flashCount;
6381 if (appData.flashCount > 0) {
6382 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6384 XtSetArg(args[0], XtNleftBitmap, None);
6386 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6390 void FlipViewProc(w, event, prms, nprms)
6396 flipView = !flipView;
6397 DrawPosition(True, NULL);
6400 void GetMoveListProc(w, event, prms, nprms)
6408 appData.getMoveList = !appData.getMoveList;
6410 if (appData.getMoveList) {
6411 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6414 XtSetArg(args[0], XtNleftBitmap, None);
6416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6421 void HighlightDraggingProc(w, event, prms, nprms)
6429 appData.highlightDragging = !appData.highlightDragging;
6431 if (appData.highlightDragging) {
6432 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6434 XtSetArg(args[0], XtNleftBitmap, None);
6436 XtSetValues(XtNameToWidget(menuBarWidget,
6437 "menuOptions.Highlight Dragging"), args, 1);
6441 void HighlightLastMoveProc(w, event, prms, nprms)
6449 appData.highlightLastMove = !appData.highlightLastMove;
6451 if (appData.highlightLastMove) {
6452 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6454 XtSetArg(args[0], XtNleftBitmap, None);
6456 XtSetValues(XtNameToWidget(menuBarWidget,
6457 "menuOptions.Highlight Last Move"), args, 1);
6460 void IcsAlarmProc(w, event, prms, nprms)
6468 appData.icsAlarm = !appData.icsAlarm;
6470 if (appData.icsAlarm) {
6471 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6473 XtSetArg(args[0], XtNleftBitmap, None);
6475 XtSetValues(XtNameToWidget(menuBarWidget,
6476 "menuOptions.ICS Alarm"), args, 1);
6479 void MoveSoundProc(w, event, prms, nprms)
6487 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6489 if (appData.ringBellAfterMoves) {
6490 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6492 XtSetArg(args[0], XtNleftBitmap, None);
6494 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6499 void OldSaveStyleProc(w, event, prms, nprms)
6507 appData.oldSaveStyle = !appData.oldSaveStyle;
6509 if (appData.oldSaveStyle) {
6510 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6512 XtSetArg(args[0], XtNleftBitmap, None);
6514 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6518 void PeriodicUpdatesProc(w, event, prms, nprms)
6526 PeriodicUpdatesEvent(!appData.periodicUpdates);
6528 if (appData.periodicUpdates) {
6529 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6531 XtSetArg(args[0], XtNleftBitmap, None);
6533 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6537 void PonderNextMoveProc(w, event, prms, nprms)
6545 PonderNextMoveEvent(!appData.ponderNextMove);
6547 if (appData.ponderNextMove) {
6548 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6550 XtSetArg(args[0], XtNleftBitmap, None);
6552 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6556 void PopupExitMessageProc(w, event, prms, nprms)
6564 appData.popupExitMessage = !appData.popupExitMessage;
6566 if (appData.popupExitMessage) {
6567 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6569 XtSetArg(args[0], XtNleftBitmap, None);
6571 XtSetValues(XtNameToWidget(menuBarWidget,
6572 "menuOptions.Popup Exit Message"), args, 1);
6575 void PopupMoveErrorsProc(w, event, prms, nprms)
6583 appData.popupMoveErrors = !appData.popupMoveErrors;
6585 if (appData.popupMoveErrors) {
6586 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6588 XtSetArg(args[0], XtNleftBitmap, None);
6590 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6594 void PremoveProc(w, event, prms, nprms)
6602 appData.premove = !appData.premove;
6604 if (appData.premove) {
6605 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6607 XtSetArg(args[0], XtNleftBitmap, None);
6609 XtSetValues(XtNameToWidget(menuBarWidget,
6610 "menuOptions.Premove"), args, 1);
6613 void QuietPlayProc(w, event, prms, nprms)
6621 appData.quietPlay = !appData.quietPlay;
6623 if (appData.quietPlay) {
6624 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6626 XtSetArg(args[0], XtNleftBitmap, None);
6628 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6632 void ShowCoordsProc(w, event, prms, nprms)
6640 appData.showCoords = !appData.showCoords;
6642 if (appData.showCoords) {
6643 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6645 XtSetArg(args[0], XtNleftBitmap, None);
6647 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6650 DrawPosition(True, NULL);
6653 void ShowThinkingProc(w, event, prms, nprms)
6659 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6660 ShowThinkingEvent();
6663 void HideThinkingProc(w, event, prms, nprms)
6671 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6672 ShowThinkingEvent();
6674 if (appData.hideThinkingFromHuman) {
6675 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6677 XtSetArg(args[0], XtNleftBitmap, None);
6679 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6683 void SaveOnExitProc(w, event, prms, nprms)
6691 saveSettingsOnExit = !saveSettingsOnExit;
6693 if (saveSettingsOnExit) {
6694 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6696 XtSetArg(args[0], XtNleftBitmap, None);
6698 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6702 void SaveSettingsProc(w, event, prms, nprms)
6708 SaveSettings(settingsFileName);
6711 void InfoProc(w, event, prms, nprms)
6718 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6723 void ManProc(w, event, prms, nprms)
6731 if (nprms && *nprms > 0)
6735 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6739 void HintProc(w, event, prms, nprms)
6748 void BookProc(w, event, prms, nprms)
6757 void AboutProc(w, event, prms, nprms)
6765 char *zippy = " (with Zippy code)";
6769 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6770 programVersion, zippy,
6771 "Copyright 1991 Digital Equipment Corporation",
6772 "Enhancements Copyright 1992-2009 Free Software Foundation",
6773 "Enhancements Copyright 2005 Alessandro Scotti",
6774 PACKAGE, " is free software and carries NO WARRANTY;",
6775 "see the file COPYING for more information.");
6776 ErrorPopUp(_("About XBoard"), buf, FALSE);
6779 void DebugProc(w, event, prms, nprms)
6785 appData.debugMode = !appData.debugMode;
6788 void AboutGameProc(w, event, prms, nprms)
6797 void NothingProc(w, event, prms, nprms)
6806 void Iconify(w, event, prms, nprms)
6815 XtSetArg(args[0], XtNiconic, True);
6816 XtSetValues(shellWidget, args, 1);
6819 void DisplayMessage(message, extMessage)
6820 char *message, *extMessage;
6822 /* display a message in the message widget */
6831 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6836 message = extMessage;
6840 /* need to test if messageWidget already exists, since this function
6841 can also be called during the startup, if for example a Xresource
6842 is not set up correctly */
6845 XtSetArg(arg, XtNlabel, message);
6846 XtSetValues(messageWidget, &arg, 1);
6852 void DisplayTitle(text)
6857 char title[MSG_SIZ];
6860 if (text == NULL) text = "";
6862 if (appData.titleInWindow) {
6864 XtSetArg(args[i], XtNlabel, text); i++;
6865 XtSetValues(titleWidget, args, i);
6868 if (*text != NULLCHAR) {
6870 strcpy(title, text);
6871 } else if (appData.icsActive) {
6872 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6873 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6874 } else if (appData.cmailGameName[0] != NULLCHAR) {
6875 snprintf(icon, sizeof(icon), "%s", "CMail");
6876 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6878 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6879 } else if (gameInfo.variant == VariantGothic) {
6880 strcpy(icon, programName);
6881 strcpy(title, GOTHIC);
6884 } else if (gameInfo.variant == VariantFalcon) {
6885 strcpy(icon, programName);
6886 strcpy(title, FALCON);
6888 } else if (appData.noChessProgram) {
6889 strcpy(icon, programName);
6890 strcpy(title, programName);
6892 strcpy(icon, first.tidy);
6893 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6896 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6897 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6898 XtSetValues(shellWidget, args, i);
6902 void DisplayError(message, error)
6909 if (appData.debugMode || appData.matchMode) {
6910 fprintf(stderr, "%s: %s\n", programName, message);
6913 if (appData.debugMode || appData.matchMode) {
6914 fprintf(stderr, "%s: %s: %s\n",
6915 programName, message, strerror(error));
6917 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6920 ErrorPopUp(_("Error"), message, FALSE);
6924 void DisplayMoveError(message)
6929 DrawPosition(FALSE, NULL);
6930 if (appData.debugMode || appData.matchMode) {
6931 fprintf(stderr, "%s: %s\n", programName, message);
6933 if (appData.popupMoveErrors) {
6934 ErrorPopUp(_("Error"), message, FALSE);
6936 DisplayMessage(message, "");
6941 void DisplayFatalError(message, error, status)
6947 errorExitStatus = status;
6949 fprintf(stderr, "%s: %s\n", programName, message);
6951 fprintf(stderr, "%s: %s: %s\n",
6952 programName, message, strerror(error));
6953 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6956 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6957 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6963 void DisplayInformation(message)
6967 ErrorPopUp(_("Information"), message, TRUE);
6970 void DisplayNote(message)
6974 ErrorPopUp(_("Note"), message, FALSE);
6978 NullXErrorCheck(dpy, error_event)
6980 XErrorEvent *error_event;
6985 void DisplayIcsInteractionTitle(message)
6988 if (oldICSInteractionTitle == NULL) {
6989 /* Magic to find the old window title, adapted from vim */
6990 char *wina = getenv("WINDOWID");
6992 Window win = (Window) atoi(wina);
6993 Window root, parent, *children;
6994 unsigned int nchildren;
6995 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6997 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6998 if (!XQueryTree(xDisplay, win, &root, &parent,
6999 &children, &nchildren)) break;
7000 if (children) XFree((void *)children);
7001 if (parent == root || parent == 0) break;
7004 XSetErrorHandler(oldHandler);
7006 if (oldICSInteractionTitle == NULL) {
7007 oldICSInteractionTitle = "xterm";
7010 printf("\033]0;%s\007", message);
7014 char pendingReplyPrefix[MSG_SIZ];
7015 ProcRef pendingReplyPR;
7017 void AskQuestionProc(w, event, prms, nprms)
7024 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7028 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7031 void AskQuestionPopDown()
7033 if (!askQuestionUp) return;
7034 XtPopdown(askQuestionShell);
7035 XtDestroyWidget(askQuestionShell);
7036 askQuestionUp = False;
7039 void AskQuestionReplyAction(w, event, prms, nprms)
7049 reply = XawDialogGetValueString(w = XtParent(w));
7050 strcpy(buf, pendingReplyPrefix);
7051 if (*buf) strcat(buf, " ");
7054 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7055 AskQuestionPopDown();
7057 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7060 void AskQuestionCallback(w, client_data, call_data)
7062 XtPointer client_data, call_data;
7067 XtSetArg(args[0], XtNlabel, &name);
7068 XtGetValues(w, args, 1);
7070 if (strcmp(name, _("cancel")) == 0) {
7071 AskQuestionPopDown();
7073 AskQuestionReplyAction(w, NULL, NULL, NULL);
7077 void AskQuestion(title, question, replyPrefix, pr)
7078 char *title, *question, *replyPrefix;
7082 Widget popup, layout, dialog, edit;
7088 strcpy(pendingReplyPrefix, replyPrefix);
7089 pendingReplyPR = pr;
7092 XtSetArg(args[i], XtNresizable, True); i++;
7093 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7094 askQuestionShell = popup =
7095 XtCreatePopupShell(title, transientShellWidgetClass,
7096 shellWidget, args, i);
7099 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7100 layoutArgs, XtNumber(layoutArgs));
7103 XtSetArg(args[i], XtNlabel, question); i++;
7104 XtSetArg(args[i], XtNvalue, ""); i++;
7105 XtSetArg(args[i], XtNborderWidth, 0); i++;
7106 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7109 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7110 (XtPointer) dialog);
7111 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7112 (XtPointer) dialog);
7114 XtRealizeWidget(popup);
7115 CatchDeleteWindow(popup, "AskQuestionPopDown");
7117 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7118 &x, &y, &win_x, &win_y, &mask);
7120 XtSetArg(args[0], XtNx, x - 10);
7121 XtSetArg(args[1], XtNy, y - 30);
7122 XtSetValues(popup, args, 2);
7124 XtPopup(popup, XtGrabExclusive);
7125 askQuestionUp = True;
7127 edit = XtNameToWidget(dialog, "*value");
7128 XtSetKeyboardFocus(popup, edit);
7136 if (*name == NULLCHAR) {
7138 } else if (strcmp(name, "$") == 0) {
7139 putc(BELLCHAR, stderr);
7142 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7150 PlaySound(appData.soundMove);
7156 PlaySound(appData.soundIcsWin);
7162 PlaySound(appData.soundIcsLoss);
7168 PlaySound(appData.soundIcsDraw);
7172 PlayIcsUnfinishedSound()
7174 PlaySound(appData.soundIcsUnfinished);
7180 PlaySound(appData.soundIcsAlarm);
7186 system("stty echo");
7192 system("stty -echo");
7196 Colorize(cc, continuation)
7201 int count, outCount, error;
7203 if (textColors[(int)cc].bg > 0) {
7204 if (textColors[(int)cc].fg > 0) {
7205 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7206 textColors[(int)cc].fg, textColors[(int)cc].bg);
7208 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7209 textColors[(int)cc].bg);
7212 if (textColors[(int)cc].fg > 0) {
7213 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7214 textColors[(int)cc].fg);
7216 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7219 count = strlen(buf);
7220 outCount = OutputToProcess(NoProc, buf, count, &error);
7221 if (outCount < count) {
7222 DisplayFatalError(_("Error writing to display"), error, 1);
7225 if (continuation) return;
7228 PlaySound(appData.soundShout);
7231 PlaySound(appData.soundSShout);
7234 PlaySound(appData.soundChannel1);
7237 PlaySound(appData.soundChannel);
7240 PlaySound(appData.soundKibitz);
7243 PlaySound(appData.soundTell);
7245 case ColorChallenge:
7246 PlaySound(appData.soundChallenge);
7249 PlaySound(appData.soundRequest);
7252 PlaySound(appData.soundSeek);
7263 return getpwuid(getuid())->pw_name;
7266 static char *ExpandPathName(path)
7269 static char static_buf[2000];
7270 char *d, *s, buf[2000];
7276 while (*s && isspace(*s))
7285 if (*(s+1) == '/') {
7286 strcpy(d, getpwuid(getuid())->pw_dir);
7291 *strchr(buf, '/') = 0;
7292 pwd = getpwnam(buf);
7295 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7299 strcpy(d, pwd->pw_dir);
7300 strcat(d, strchr(s+1, '/'));
7311 static char host_name[MSG_SIZ];
7313 #if HAVE_GETHOSTNAME
7314 gethostname(host_name, MSG_SIZ);
7316 #else /* not HAVE_GETHOSTNAME */
7317 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7318 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7320 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7322 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7323 #endif /* not HAVE_GETHOSTNAME */
7326 XtIntervalId delayedEventTimerXID = 0;
7327 DelayedEventCallback delayedEventCallback = 0;
7332 delayedEventTimerXID = 0;
7333 delayedEventCallback();
7337 ScheduleDelayedEvent(cb, millisec)
7338 DelayedEventCallback cb; long millisec;
7340 if(delayedEventTimerXID && delayedEventCallback == cb)
7341 // [HGM] alive: replace, rather than add or flush identical event
7342 XtRemoveTimeOut(delayedEventTimerXID);
7343 delayedEventCallback = cb;
7344 delayedEventTimerXID =
7345 XtAppAddTimeOut(appContext, millisec,
7346 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7349 DelayedEventCallback
7352 if (delayedEventTimerXID) {
7353 return delayedEventCallback;
7360 CancelDelayedEvent()
7362 if (delayedEventTimerXID) {
7363 XtRemoveTimeOut(delayedEventTimerXID);
7364 delayedEventTimerXID = 0;
7368 XtIntervalId loadGameTimerXID = 0;
7370 int LoadGameTimerRunning()
7372 return loadGameTimerXID != 0;
7375 int StopLoadGameTimer()
7377 if (loadGameTimerXID != 0) {
7378 XtRemoveTimeOut(loadGameTimerXID);
7379 loadGameTimerXID = 0;
7387 LoadGameTimerCallback(arg, id)
7391 loadGameTimerXID = 0;
7396 StartLoadGameTimer(millisec)
7400 XtAppAddTimeOut(appContext, millisec,
7401 (XtTimerCallbackProc) LoadGameTimerCallback,
7405 XtIntervalId analysisClockXID = 0;
7408 AnalysisClockCallback(arg, id)
7412 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7413 || appData.icsEngineAnalyze) { // [DM]
7414 AnalysisPeriodicEvent(0);
7415 StartAnalysisClock();
7420 StartAnalysisClock()
7423 XtAppAddTimeOut(appContext, 2000,
7424 (XtTimerCallbackProc) AnalysisClockCallback,
7428 XtIntervalId clockTimerXID = 0;
7430 int ClockTimerRunning()
7432 return clockTimerXID != 0;
7435 int StopClockTimer()
7437 if (clockTimerXID != 0) {
7438 XtRemoveTimeOut(clockTimerXID);
7447 ClockTimerCallback(arg, id)
7456 StartClockTimer(millisec)
7460 XtAppAddTimeOut(appContext, millisec,
7461 (XtTimerCallbackProc) ClockTimerCallback,
7466 DisplayTimerLabel(w, color, timer, highlight)
7475 /* check for low time warning */
7476 Pixel foregroundOrWarningColor = timerForegroundPixel;
7479 appData.lowTimeWarning &&
7480 (timer / 1000) < appData.icsAlarmTime)
7481 foregroundOrWarningColor = lowTimeWarningColor;
7483 if (appData.clockMode) {
7484 sprintf(buf, "%s: %s", color, TimeString(timer));
7485 XtSetArg(args[0], XtNlabel, buf);
7487 sprintf(buf, "%s ", color);
7488 XtSetArg(args[0], XtNlabel, buf);
7493 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7494 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7496 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7497 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7500 XtSetValues(w, args, 3);
7504 DisplayWhiteClock(timeRemaining, highlight)
7510 if(appData.noGUI) return;
7511 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7512 if (highlight && iconPixmap == bIconPixmap) {
7513 iconPixmap = wIconPixmap;
7514 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7515 XtSetValues(shellWidget, args, 1);
7520 DisplayBlackClock(timeRemaining, highlight)
7526 if(appData.noGUI) return;
7527 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7528 if (highlight && iconPixmap == wIconPixmap) {
7529 iconPixmap = bIconPixmap;
7530 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7531 XtSetValues(shellWidget, args, 1);
7549 int StartChildProcess(cmdLine, dir, pr)
7556 int to_prog[2], from_prog[2];
7560 if (appData.debugMode) {
7561 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7564 /* We do NOT feed the cmdLine to the shell; we just
7565 parse it into blank-separated arguments in the
7566 most simple-minded way possible.
7569 strcpy(buf, cmdLine);
7572 while(*p == ' ') p++;
7574 if(*p == '"' || *p == '\'')
7575 p = strchr(++argv[i-1], *p);
7576 else p = strchr(p, ' ');
7577 if (p == NULL) break;
7582 SetUpChildIO(to_prog, from_prog);
7584 if ((pid = fork()) == 0) {
7586 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7587 close(to_prog[1]); // first close the unused pipe ends
7588 close(from_prog[0]);
7589 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7590 dup2(from_prog[1], 1);
7591 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7592 close(from_prog[1]); // and closing again loses one of the pipes!
7593 if(fileno(stderr) >= 2) // better safe than sorry...
7594 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7596 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7601 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7603 execvp(argv[0], argv);
7605 /* If we get here, exec failed */
7610 /* Parent process */
7612 close(from_prog[1]);
7614 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7617 cp->fdFrom = from_prog[0];
7618 cp->fdTo = to_prog[1];
7623 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7624 static RETSIGTYPE AlarmCallBack(int n)
7630 DestroyChildProcess(pr, signalType)
7634 ChildProc *cp = (ChildProc *) pr;
7636 if (cp->kind != CPReal) return;
7638 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7639 signal(SIGALRM, AlarmCallBack);
7641 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7642 kill(cp->pid, SIGKILL); // kill it forcefully
7643 wait((int *) 0); // and wait again
7647 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7649 /* Process is exiting either because of the kill or because of
7650 a quit command sent by the backend; either way, wait for it to die.
7659 InterruptChildProcess(pr)
7662 ChildProc *cp = (ChildProc *) pr;
7664 if (cp->kind != CPReal) return;
7665 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7668 int OpenTelnet(host, port, pr)
7673 char cmdLine[MSG_SIZ];
7675 if (port[0] == NULLCHAR) {
7676 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7678 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7680 return StartChildProcess(cmdLine, "", pr);
7683 int OpenTCP(host, port, pr)
7689 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7690 #else /* !OMIT_SOCKETS */
7692 struct sockaddr_in sa;
7694 unsigned short uport;
7697 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7701 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7702 sa.sin_family = AF_INET;
7703 sa.sin_addr.s_addr = INADDR_ANY;
7704 uport = (unsigned short) 0;
7705 sa.sin_port = htons(uport);
7706 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7710 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7711 if (!(hp = gethostbyname(host))) {
7713 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7714 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7715 hp->h_addrtype = AF_INET;
7717 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7718 hp->h_addr_list[0] = (char *) malloc(4);
7719 hp->h_addr_list[0][0] = b0;
7720 hp->h_addr_list[0][1] = b1;
7721 hp->h_addr_list[0][2] = b2;
7722 hp->h_addr_list[0][3] = b3;
7727 sa.sin_family = hp->h_addrtype;
7728 uport = (unsigned short) atoi(port);
7729 sa.sin_port = htons(uport);
7730 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7732 if (connect(s, (struct sockaddr *) &sa,
7733 sizeof(struct sockaddr_in)) < 0) {
7737 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7744 #endif /* !OMIT_SOCKETS */
7749 int OpenCommPort(name, pr)
7756 fd = open(name, 2, 0);
7757 if (fd < 0) return errno;
7759 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7769 int OpenLoopback(pr)
7775 SetUpChildIO(to, from);
7777 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7780 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7787 int OpenRcmd(host, user, cmd, pr)
7788 char *host, *user, *cmd;
7791 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7795 #define INPUT_SOURCE_BUF_SIZE 8192
7804 char buf[INPUT_SOURCE_BUF_SIZE];
7809 DoInputCallback(closure, source, xid)
7814 InputSource *is = (InputSource *) closure;
7819 if (is->lineByLine) {
7820 count = read(is->fd, is->unused,
7821 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7823 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7826 is->unused += count;
7828 while (p < is->unused) {
7829 q = memchr(p, '\n', is->unused - p);
7830 if (q == NULL) break;
7832 (is->func)(is, is->closure, p, q - p, 0);
7836 while (p < is->unused) {
7841 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7846 (is->func)(is, is->closure, is->buf, count, error);
7850 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7857 ChildProc *cp = (ChildProc *) pr;
7859 is = (InputSource *) calloc(1, sizeof(InputSource));
7860 is->lineByLine = lineByLine;
7864 is->fd = fileno(stdin);
7866 is->kind = cp->kind;
7867 is->fd = cp->fdFrom;
7870 is->unused = is->buf;
7873 is->xid = XtAppAddInput(appContext, is->fd,
7874 (XtPointer) (XtInputReadMask),
7875 (XtInputCallbackProc) DoInputCallback,
7877 is->closure = closure;
7878 return (InputSourceRef) is;
7882 RemoveInputSource(isr)
7885 InputSource *is = (InputSource *) isr;
7887 if (is->xid == 0) return;
7888 XtRemoveInput(is->xid);
7892 int OutputToProcess(pr, message, count, outError)
7898 static int line = 0;
7899 ChildProc *cp = (ChildProc *) pr;
7904 if (appData.noJoin || !appData.useInternalWrap)
7905 outCount = fwrite(message, 1, count, stdout);
7908 int width = get_term_width();
7909 int len = wrap(NULL, message, count, width, &line);
7910 char *msg = malloc(len);
7914 outCount = fwrite(message, 1, count, stdout);
7917 dbgchk = wrap(msg, message, count, width, &line);
7918 if (dbgchk != len && appData.debugMode)
7919 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7920 outCount = fwrite(msg, 1, dbgchk, stdout);
7926 outCount = write(cp->fdTo, message, count);
7936 /* Output message to process, with "ms" milliseconds of delay
7937 between each character. This is needed when sending the logon
7938 script to ICC, which for some reason doesn't like the
7939 instantaneous send. */
7940 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7947 ChildProc *cp = (ChildProc *) pr;
7952 r = write(cp->fdTo, message++, 1);
7965 /**** Animation code by Hugh Fisher, DCS, ANU.
7967 Known problem: if a window overlapping the board is
7968 moved away while a piece is being animated underneath,
7969 the newly exposed area won't be updated properly.
7970 I can live with this.
7972 Known problem: if you look carefully at the animation
7973 of pieces in mono mode, they are being drawn as solid
7974 shapes without interior detail while moving. Fixing
7975 this would be a major complication for minimal return.
7978 /* Masks for XPM pieces. Black and white pieces can have
7979 different shapes, but in the interest of retaining my
7980 sanity pieces must have the same outline on both light
7981 and dark squares, and all pieces must use the same
7982 background square colors/images. */
7984 static int xpmDone = 0;
7987 CreateAnimMasks (pieceDepth)
7994 unsigned long plane;
7997 /* Need a bitmap just to get a GC with right depth */
7998 buf = XCreatePixmap(xDisplay, xBoardWindow,
8000 values.foreground = 1;
8001 values.background = 0;
8002 /* Don't use XtGetGC, not read only */
8003 maskGC = XCreateGC(xDisplay, buf,
8004 GCForeground | GCBackground, &values);
8005 XFreePixmap(xDisplay, buf);
8007 buf = XCreatePixmap(xDisplay, xBoardWindow,
8008 squareSize, squareSize, pieceDepth);
8009 values.foreground = XBlackPixel(xDisplay, xScreen);
8010 values.background = XWhitePixel(xDisplay, xScreen);
8011 bufGC = XCreateGC(xDisplay, buf,
8012 GCForeground | GCBackground, &values);
8014 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8015 /* Begin with empty mask */
8016 if(!xpmDone) // [HGM] pieces: keep using existing
8017 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8018 squareSize, squareSize, 1);
8019 XSetFunction(xDisplay, maskGC, GXclear);
8020 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8021 0, 0, squareSize, squareSize);
8023 /* Take a copy of the piece */
8028 XSetFunction(xDisplay, bufGC, GXcopy);
8029 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8031 0, 0, squareSize, squareSize, 0, 0);
8033 /* XOR the background (light) over the piece */
8034 XSetFunction(xDisplay, bufGC, GXxor);
8036 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8037 0, 0, squareSize, squareSize, 0, 0);
8039 XSetForeground(xDisplay, bufGC, lightSquareColor);
8040 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8043 /* We now have an inverted piece image with the background
8044 erased. Construct mask by just selecting all the non-zero
8045 pixels - no need to reconstruct the original image. */
8046 XSetFunction(xDisplay, maskGC, GXor);
8048 /* Might be quicker to download an XImage and create bitmap
8049 data from it rather than this N copies per piece, but it
8050 only takes a fraction of a second and there is a much
8051 longer delay for loading the pieces. */
8052 for (n = 0; n < pieceDepth; n ++) {
8053 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8054 0, 0, squareSize, squareSize,
8060 XFreePixmap(xDisplay, buf);
8061 XFreeGC(xDisplay, bufGC);
8062 XFreeGC(xDisplay, maskGC);
8066 InitAnimState (anim, info)
8068 XWindowAttributes * info;
8073 /* Each buffer is square size, same depth as window */
8074 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8075 squareSize, squareSize, info->depth);
8076 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8077 squareSize, squareSize, info->depth);
8079 /* Create a plain GC for blitting */
8080 mask = GCForeground | GCBackground | GCFunction |
8081 GCPlaneMask | GCGraphicsExposures;
8082 values.foreground = XBlackPixel(xDisplay, xScreen);
8083 values.background = XWhitePixel(xDisplay, xScreen);
8084 values.function = GXcopy;
8085 values.plane_mask = AllPlanes;
8086 values.graphics_exposures = False;
8087 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8089 /* Piece will be copied from an existing context at
8090 the start of each new animation/drag. */
8091 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8093 /* Outline will be a read-only copy of an existing */
8094 anim->outlineGC = None;
8100 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8101 XWindowAttributes info;
8103 if (xpmDone && gameInfo.variant == old) return;
8104 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8105 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8107 InitAnimState(&game, &info);
8108 InitAnimState(&player, &info);
8110 /* For XPM pieces, we need bitmaps to use as masks. */
8112 CreateAnimMasks(info.depth);
8118 static Boolean frameWaiting;
8120 static RETSIGTYPE FrameAlarm (sig)
8123 frameWaiting = False;
8124 /* In case System-V style signals. Needed?? */
8125 signal(SIGALRM, FrameAlarm);
8132 struct itimerval delay;
8134 XSync(xDisplay, False);
8137 frameWaiting = True;
8138 signal(SIGALRM, FrameAlarm);
8139 delay.it_interval.tv_sec =
8140 delay.it_value.tv_sec = time / 1000;
8141 delay.it_interval.tv_usec =
8142 delay.it_value.tv_usec = (time % 1000) * 1000;
8143 setitimer(ITIMER_REAL, &delay, NULL);
8144 while (frameWaiting) pause();
8145 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8146 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8147 setitimer(ITIMER_REAL, &delay, NULL);
8157 XSync(xDisplay, False);
8159 usleep(time * 1000);
8164 /* Convert board position to corner of screen rect and color */
8167 ScreenSquare(column, row, pt, color)
8168 int column; int row; XPoint * pt; int * color;
8171 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8172 pt->y = lineGap + row * (squareSize + lineGap);
8174 pt->x = lineGap + column * (squareSize + lineGap);
8175 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8177 *color = SquareColor(row, column);
8180 /* Convert window coords to square */
8183 BoardSquare(x, y, column, row)
8184 int x; int y; int * column; int * row;
8186 *column = EventToSquare(x, BOARD_WIDTH);
8187 if (flipView && *column >= 0)
8188 *column = BOARD_WIDTH - 1 - *column;
8189 *row = EventToSquare(y, BOARD_HEIGHT);
8190 if (!flipView && *row >= 0)
8191 *row = BOARD_HEIGHT - 1 - *row;
8196 #undef Max /* just in case */
8198 #define Max(a, b) ((a) > (b) ? (a) : (b))
8199 #define Min(a, b) ((a) < (b) ? (a) : (b))
8202 SetRect(rect, x, y, width, height)
8203 XRectangle * rect; int x; int y; int width; int height;
8207 rect->width = width;
8208 rect->height = height;
8211 /* Test if two frames overlap. If they do, return
8212 intersection rect within old and location of
8213 that rect within new. */
8216 Intersect(old, new, size, area, pt)
8217 XPoint * old; XPoint * new;
8218 int size; XRectangle * area; XPoint * pt;
8220 if (old->x > new->x + size || new->x > old->x + size ||
8221 old->y > new->y + size || new->y > old->y + size) {
8224 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8225 size - abs(old->x - new->x), size - abs(old->y - new->y));
8226 pt->x = Max(old->x - new->x, 0);
8227 pt->y = Max(old->y - new->y, 0);
8232 /* For two overlapping frames, return the rect(s)
8233 in the old that do not intersect with the new. */
8236 CalcUpdateRects(old, new, size, update, nUpdates)
8237 XPoint * old; XPoint * new; int size;
8238 XRectangle update[]; int * nUpdates;
8242 /* If old = new (shouldn't happen) then nothing to draw */
8243 if (old->x == new->x && old->y == new->y) {
8247 /* Work out what bits overlap. Since we know the rects
8248 are the same size we don't need a full intersect calc. */
8250 /* Top or bottom edge? */
8251 if (new->y > old->y) {
8252 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8254 } else if (old->y > new->y) {
8255 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8256 size, old->y - new->y);
8259 /* Left or right edge - don't overlap any update calculated above. */
8260 if (new->x > old->x) {
8261 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8262 new->x - old->x, size - abs(new->y - old->y));
8264 } else if (old->x > new->x) {
8265 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8266 old->x - new->x, size - abs(new->y - old->y));
8273 /* Generate a series of frame coords from start->mid->finish.
8274 The movement rate doubles until the half way point is
8275 reached, then halves back down to the final destination,
8276 which gives a nice slow in/out effect. The algorithmn
8277 may seem to generate too many intermediates for short
8278 moves, but remember that the purpose is to attract the
8279 viewers attention to the piece about to be moved and
8280 then to where it ends up. Too few frames would be less
8284 Tween(start, mid, finish, factor, frames, nFrames)
8285 XPoint * start; XPoint * mid;
8286 XPoint * finish; int factor;
8287 XPoint frames[]; int * nFrames;
8289 int fraction, n, count;
8293 /* Slow in, stepping 1/16th, then 1/8th, ... */
8295 for (n = 0; n < factor; n++)
8297 for (n = 0; n < factor; n++) {
8298 frames[count].x = start->x + (mid->x - start->x) / fraction;
8299 frames[count].y = start->y + (mid->y - start->y) / fraction;
8301 fraction = fraction / 2;
8305 frames[count] = *mid;
8308 /* Slow out, stepping 1/2, then 1/4, ... */
8310 for (n = 0; n < factor; n++) {
8311 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8312 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8314 fraction = fraction * 2;
8319 /* Draw a piece on the screen without disturbing what's there */
8322 SelectGCMask(piece, clip, outline, mask)
8323 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8327 /* Bitmap for piece being moved. */
8328 if (appData.monoMode) {
8329 *mask = *pieceToSolid(piece);
8330 } else if (useImages) {
8332 *mask = xpmMask[piece];
8334 *mask = ximMaskPm[piece];
8337 *mask = *pieceToSolid(piece);
8340 /* GC for piece being moved. Square color doesn't matter, but
8341 since it gets modified we make a copy of the original. */
8343 if (appData.monoMode)
8348 if (appData.monoMode)
8353 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8355 /* Outline only used in mono mode and is not modified */
8357 *outline = bwPieceGC;
8359 *outline = wbPieceGC;
8363 OverlayPiece(piece, clip, outline, dest)
8364 ChessSquare piece; GC clip; GC outline; Drawable dest;
8369 /* Draw solid rectangle which will be clipped to shape of piece */
8370 XFillRectangle(xDisplay, dest, clip,
8371 0, 0, squareSize, squareSize);
8372 if (appData.monoMode)
8373 /* Also draw outline in contrasting color for black
8374 on black / white on white cases */
8375 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8376 0, 0, squareSize, squareSize, 0, 0, 1);
8378 /* Copy the piece */
8383 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8385 0, 0, squareSize, squareSize,
8390 /* Animate the movement of a single piece */
8393 BeginAnimation(anim, piece, startColor, start)
8401 /* The old buffer is initialised with the start square (empty) */
8402 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8403 anim->prevFrame = *start;
8405 /* The piece will be drawn using its own bitmap as a matte */
8406 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8407 XSetClipMask(xDisplay, anim->pieceGC, mask);
8411 AnimationFrame(anim, frame, piece)
8416 XRectangle updates[4];
8421 /* Save what we are about to draw into the new buffer */
8422 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8423 frame->x, frame->y, squareSize, squareSize,
8426 /* Erase bits of the previous frame */
8427 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8428 /* Where the new frame overlapped the previous,
8429 the contents in newBuf are wrong. */
8430 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8431 overlap.x, overlap.y,
8432 overlap.width, overlap.height,
8434 /* Repaint the areas in the old that don't overlap new */
8435 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8436 for (i = 0; i < count; i++)
8437 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8438 updates[i].x - anim->prevFrame.x,
8439 updates[i].y - anim->prevFrame.y,
8440 updates[i].width, updates[i].height,
8441 updates[i].x, updates[i].y);
8443 /* Easy when no overlap */
8444 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8445 0, 0, squareSize, squareSize,
8446 anim->prevFrame.x, anim->prevFrame.y);
8449 /* Save this frame for next time round */
8450 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8451 0, 0, squareSize, squareSize,
8453 anim->prevFrame = *frame;
8455 /* Draw piece over original screen contents, not current,
8456 and copy entire rect. Wipes out overlapping piece images. */
8457 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8458 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8459 0, 0, squareSize, squareSize,
8460 frame->x, frame->y);
8464 EndAnimation (anim, finish)
8468 XRectangle updates[4];
8473 /* The main code will redraw the final square, so we
8474 only need to erase the bits that don't overlap. */
8475 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8476 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8477 for (i = 0; i < count; i++)
8478 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8479 updates[i].x - anim->prevFrame.x,
8480 updates[i].y - anim->prevFrame.y,
8481 updates[i].width, updates[i].height,
8482 updates[i].x, updates[i].y);
8484 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8485 0, 0, squareSize, squareSize,
8486 anim->prevFrame.x, anim->prevFrame.y);
8491 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8493 ChessSquare piece; int startColor;
8494 XPoint * start; XPoint * finish;
8495 XPoint frames[]; int nFrames;
8499 BeginAnimation(anim, piece, startColor, start);
8500 for (n = 0; n < nFrames; n++) {
8501 AnimationFrame(anim, &(frames[n]), piece);
8502 FrameDelay(appData.animSpeed);
8504 EndAnimation(anim, finish);
8507 /* Main control logic for deciding what to animate and how */
8510 AnimateMove(board, fromX, fromY, toX, toY)
8519 XPoint start, finish, mid;
8520 XPoint frames[kFactor * 2 + 1];
8521 int nFrames, startColor, endColor;
8523 /* Are we animating? */
8524 if (!appData.animate || appData.blindfold)
8527 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8528 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8529 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8531 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8532 piece = board[fromY][fromX];
8533 if (piece >= EmptySquare) return;
8538 hop = (piece == WhiteKnight || piece == BlackKnight);
8541 if (appData.debugMode) {
8542 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8543 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8544 piece, fromX, fromY, toX, toY); }
8546 ScreenSquare(fromX, fromY, &start, &startColor);
8547 ScreenSquare(toX, toY, &finish, &endColor);
8550 /* Knight: make diagonal movement then straight */
8551 if (abs(toY - fromY) < abs(toX - fromX)) {
8552 mid.x = start.x + (finish.x - start.x) / 2;
8556 mid.y = start.y + (finish.y - start.y) / 2;
8559 mid.x = start.x + (finish.x - start.x) / 2;
8560 mid.y = start.y + (finish.y - start.y) / 2;
8563 /* Don't use as many frames for very short moves */
8564 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8565 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8567 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8568 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8570 /* Be sure end square is redrawn */
8571 damage[toY][toX] = True;
8575 DragPieceBegin(x, y)
8578 int boardX, boardY, color;
8581 /* Are we animating? */
8582 if (!appData.animateDragging || appData.blindfold)
8585 /* Figure out which square we start in and the
8586 mouse position relative to top left corner. */
8587 BoardSquare(x, y, &boardX, &boardY);
8588 player.startBoardX = boardX;
8589 player.startBoardY = boardY;
8590 ScreenSquare(boardX, boardY, &corner, &color);
8591 player.startSquare = corner;
8592 player.startColor = color;
8593 /* As soon as we start dragging, the piece will jump slightly to
8594 be centered over the mouse pointer. */
8595 player.mouseDelta.x = squareSize/2;
8596 player.mouseDelta.y = squareSize/2;
8597 /* Initialise animation */
8598 player.dragPiece = PieceForSquare(boardX, boardY);
8600 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8601 player.dragActive = True;
8602 BeginAnimation(&player, player.dragPiece, color, &corner);
8603 /* Mark this square as needing to be redrawn. Note that
8604 we don't remove the piece though, since logically (ie
8605 as seen by opponent) the move hasn't been made yet. */
8606 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8607 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8608 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8609 corner.x, corner.y, squareSize, squareSize,
8610 0, 0); // [HGM] zh: unstack in stead of grab
8611 damage[boardY][boardX] = True;
8613 player.dragActive = False;
8623 /* Are we animating? */
8624 if (!appData.animateDragging || appData.blindfold)
8628 if (! player.dragActive)
8630 /* Move piece, maintaining same relative position
8631 of mouse within square */
8632 corner.x = x - player.mouseDelta.x;
8633 corner.y = y - player.mouseDelta.y;
8634 AnimationFrame(&player, &corner, player.dragPiece);
8636 if (appData.highlightDragging) {
8638 BoardSquare(x, y, &boardX, &boardY);
8639 SetHighlights(fromX, fromY, boardX, boardY);
8648 int boardX, boardY, color;
8651 /* Are we animating? */
8652 if (!appData.animateDragging || appData.blindfold)
8656 if (! player.dragActive)
8658 /* Last frame in sequence is square piece is
8659 placed on, which may not match mouse exactly. */
8660 BoardSquare(x, y, &boardX, &boardY);
8661 ScreenSquare(boardX, boardY, &corner, &color);
8662 EndAnimation(&player, &corner);
8664 /* Be sure end square is redrawn */
8665 damage[boardY][boardX] = True;
8667 /* This prevents weird things happening with fast successive
8668 clicks which on my Sun at least can cause motion events
8669 without corresponding press/release. */
8670 player.dragActive = False;
8673 /* Handle expose event while piece being dragged */
8678 if (!player.dragActive || appData.blindfold)
8681 /* What we're doing: logically, the move hasn't been made yet,
8682 so the piece is still in it's original square. But visually
8683 it's being dragged around the board. So we erase the square
8684 that the piece is on and draw it at the last known drag point. */
8685 BlankSquare(player.startSquare.x, player.startSquare.y,
8686 player.startColor, EmptySquare, xBoardWindow);
8687 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8688 damage[player.startBoardY][player.startBoardX] = TRUE;
8691 #include <sys/ioctl.h>
8692 int get_term_width()
8694 int fd, default_width;
8697 default_width = 79; // this is FICS default anyway...
8699 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8701 if (!ioctl(fd, TIOCGSIZE, &win))
8702 default_width = win.ts_cols;
8703 #elif defined(TIOCGWINSZ)
8705 if (!ioctl(fd, TIOCGWINSZ, &win))
8706 default_width = win.ws_col;
8708 return default_width;
8711 void update_ics_width()
8713 static int old_width = 0;
8714 int new_width = get_term_width();
8716 if (old_width != new_width)
8717 ics_printf("set width %d\n", new_width);
8718 old_width = new_width;
8721 void NotifyFrontendLogin()