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 HandlePV P((Widget w, XEvent * event,
260 String * params, Cardinal * nParams));
261 void WhiteClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void BlackClock P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void DrawPositionProc P((Widget w, XEvent *event,
266 String *prms, Cardinal *nprms));
267 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
269 void CommentPopUp P((char *title, char *label));
270 void CommentPopDown P((void));
271 void CommentCallback P((Widget w, XtPointer client_data,
272 XtPointer call_data));
273 void ICSInputBoxPopUp P((void));
274 void ICSInputBoxPopDown P((void));
275 void FileNamePopUp P((char *label, char *def,
276 FileProc proc, char *openMode));
277 void FileNamePopDown P((void));
278 void FileNameCallback P((Widget w, XtPointer client_data,
279 XtPointer call_data));
280 void FileNameAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionReplyAction P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionProc P((Widget w, XEvent *event,
285 String *prms, Cardinal *nprms));
286 void AskQuestionPopDown P((void));
287 void PromotionPopDown P((void));
288 void PromotionCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void EditCommentPopDown P((void));
291 void EditCommentCallback P((Widget w, XtPointer client_data,
292 XtPointer call_data));
293 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
294 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
295 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
296 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
298 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
300 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
302 void LoadPositionProc P((Widget w, XEvent *event,
303 String *prms, Cardinal *nprms));
304 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
306 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
308 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
310 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
312 void PastePositionProc P((Widget w, XEvent *event, String *prms,
314 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void SavePositionProc P((Widget w, XEvent *event,
318 String *prms, Cardinal *nprms));
319 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
322 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
323 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
324 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
326 void MachineWhiteProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeModeProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void AnalyzeFileProc P((Widget w, XEvent *event,
331 String *prms, Cardinal *nprms));
332 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
334 void IcsClientProc P((Widget w, XEvent *event, String *prms,
336 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void EditPositionProc P((Widget w, XEvent *event,
338 String *prms, Cardinal *nprms));
339 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void EditCommentProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void IcsInputBoxProc P((Widget w, XEvent *event,
343 String *prms, Cardinal *nprms));
344 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
355 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
356 void StopObservingProc P((Widget w, XEvent *event, String *prms,
358 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
360 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
367 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
369 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
372 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
374 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
376 void AutocommProc P((Widget w, XEvent *event, String *prms,
378 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AutobsProc P((Widget w, XEvent *event, String *prms,
382 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
387 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
390 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
392 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
394 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
398 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
400 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
402 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
404 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
406 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
407 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
408 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
410 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
412 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
414 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
416 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
426 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
427 void DisplayMove P((int moveNumber));
428 void DisplayTitle P((char *title));
429 void ICSInitScript P((void));
430 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
431 void ErrorPopUp P((char *title, char *text, int modal));
432 void ErrorPopDown P((void));
433 static char *ExpandPathName P((char *path));
434 static void CreateAnimVars P((void));
435 static void DragPieceMove P((int x, int y));
436 static void DrawDragPiece P((void));
437 char *ModeToWidgetName P((GameMode mode));
438 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void ShufflePopDown P(());
446 void EnginePopDown P(());
447 void UciPopDown P(());
448 void TimeControlPopDown P(());
449 void NewVariantPopDown P(());
450 void SettingsPopDown P(());
451 void update_ics_width P(());
452 int get_term_width P(());
453 int CopyMemoProc P(());
455 * XBoard depends on Xt R4 or higher
457 int xtVersion = XtSpecificationRelease;
462 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
463 jailSquareColor, highlightSquareColor, premoveHighlightColor;
464 Pixel lowTimeWarningColor;
465 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
466 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
467 wjPieceGC, bjPieceGC, prelineGC, countGC;
468 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
469 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
470 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
471 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
472 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
473 ICSInputShell, fileNameShell, askQuestionShell;
474 Widget historyShell, evalGraphShell, gameListShell;
475 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
476 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
477 Font clockFontID, coordFontID, countFontID;
478 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
479 XtAppContext appContext;
481 char *oldICSInteractionTitle;
485 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
487 Position commentX = -1, commentY = -1;
488 Dimension commentW, commentH;
489 typedef unsigned int BoardSize;
491 Boolean chessProgram;
493 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
494 int squareSize, smallLayout = 0, tinyLayout = 0,
495 marginW, marginH, // [HGM] for run-time resizing
496 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
497 ICSInputBoxUp = False, askQuestionUp = False,
498 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
499 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
500 Pixel timerForegroundPixel, timerBackgroundPixel;
501 Pixel buttonForegroundPixel, buttonBackgroundPixel;
502 char *chessDir, *programName, *programVersion,
503 *gameCopyFilename, *gamePasteFilename;
504 Boolean alwaysOnTop = False;
505 Boolean saveSettingsOnExit;
506 char *settingsFileName;
507 char *icsTextMenuString;
509 char *firstChessProgramNames;
510 char *secondChessProgramNames;
512 WindowPlacement wpMain;
513 WindowPlacement wpConsole;
514 WindowPlacement wpComment;
515 WindowPlacement wpMoveHistory;
516 WindowPlacement wpEvalGraph;
517 WindowPlacement wpEngineOutput;
518 WindowPlacement wpGameList;
519 WindowPlacement wpTags;
523 Pixmap pieceBitmap[2][(int)BlackPawn];
524 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
525 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
526 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
527 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
528 int useImages, useImageSqs;
529 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
530 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
531 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
532 XImage *ximLightSquare, *ximDarkSquare;
535 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
536 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
538 #define White(piece) ((int)(piece) < (int)BlackPawn)
540 /* Variables for doing smooth animation. This whole thing
541 would be much easier if the board was double-buffered,
542 but that would require a fairly major rewrite. */
547 GC blitGC, pieceGC, outlineGC;
548 XPoint startSquare, prevFrame, mouseDelta;
552 int startBoardX, startBoardY;
555 /* There can be two pieces being animated at once: a player
556 can begin dragging a piece before the remote opponent has moved. */
558 static AnimState game, player;
560 /* Bitmaps for use as masks when drawing XPM pieces.
561 Need one for each black and white piece. */
562 static Pixmap xpmMask[BlackKing + 1];
564 /* This magic number is the number of intermediate frames used
565 in each half of the animation. For short moves it's reduced
566 by 1. The total number of frames will be factor * 2 + 1. */
569 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
571 MenuItem fileMenu[] = {
572 {N_("New Game"), ResetProc},
573 {N_("New Shuffle Game ..."), ShuffleMenuProc},
574 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
575 {"----", NothingProc},
576 {N_("Load Game"), LoadGameProc},
577 {N_("Load Next Game"), LoadNextGameProc},
578 {N_("Load Previous Game"), LoadPrevGameProc},
579 {N_("Reload Same Game"), ReloadGameProc},
580 {N_("Save Game"), SaveGameProc},
581 {"----", NothingProc},
582 {N_("Copy Game"), CopyGameProc},
583 {N_("Paste Game"), PasteGameProc},
584 {"----", NothingProc},
585 {N_("Load Position"), LoadPositionProc},
586 {N_("Load Next Position"), LoadNextPositionProc},
587 {N_("Load Previous Position"), LoadPrevPositionProc},
588 {N_("Reload Same Position"), ReloadPositionProc},
589 {N_("Save Position"), SavePositionProc},
590 {"----", NothingProc},
591 {N_("Copy Position"), CopyPositionProc},
592 {N_("Paste Position"), PastePositionProc},
593 {"----", NothingProc},
594 {N_("Mail Move"), MailMoveProc},
595 {N_("Reload CMail Message"), ReloadCmailMsgProc},
596 {"----", NothingProc},
597 {N_("Exit"), QuitProc},
601 MenuItem modeMenu[] = {
602 {N_("Machine White"), MachineWhiteProc},
603 {N_("Machine Black"), MachineBlackProc},
604 {N_("Two Machines"), TwoMachinesProc},
605 {N_("Analysis Mode"), AnalyzeModeProc},
606 {N_("Analyze File"), AnalyzeFileProc },
607 {N_("ICS Client"), IcsClientProc},
608 {N_("Edit Game"), EditGameProc},
609 {N_("Edit Position"), EditPositionProc},
610 {N_("Training"), TrainingProc},
611 {"----", NothingProc},
612 {N_("Show Engine Output"), EngineOutputProc},
613 {N_("Show Evaluation Graph"), EvalGraphProc},
614 {N_("Show Game List"), ShowGameListProc},
615 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
616 {"----", NothingProc},
617 {N_("Edit Tags"), EditTagsProc},
618 {N_("Edit Comment"), EditCommentProc},
619 {N_("ICS Input Box"), IcsInputBoxProc},
620 {N_("Pause"), PauseProc},
624 MenuItem actionMenu[] = {
625 {N_("Accept"), AcceptProc},
626 {N_("Decline"), DeclineProc},
627 {N_("Rematch"), RematchProc},
628 {"----", NothingProc},
629 {N_("Call Flag"), CallFlagProc},
630 {N_("Draw"), DrawProc},
631 {N_("Adjourn"), AdjournProc},
632 {N_("Abort"), AbortProc},
633 {N_("Resign"), ResignProc},
634 {"----", NothingProc},
635 {N_("Stop Observing"), StopObservingProc},
636 {N_("Stop Examining"), StopExaminingProc},
637 {"----", NothingProc},
638 {N_("Adjudicate to White"), AdjuWhiteProc},
639 {N_("Adjudicate to Black"), AdjuBlackProc},
640 {N_("Adjudicate Draw"), AdjuDrawProc},
644 MenuItem stepMenu[] = {
645 {N_("Backward"), BackwardProc},
646 {N_("Forward"), ForwardProc},
647 {N_("Back to Start"), ToStartProc},
648 {N_("Forward to End"), ToEndProc},
649 {N_("Revert"), RevertProc},
650 {N_("Truncate Game"), TruncateGameProc},
651 {"----", NothingProc},
652 {N_("Move Now"), MoveNowProc},
653 {N_("Retract Move"), RetractMoveProc},
657 MenuItem optionsMenu[] = {
658 {N_("Flip View"), FlipViewProc},
659 {"----", NothingProc},
660 {N_("Adjudications ..."), EngineMenuProc},
661 {N_("General Settings ..."), UciMenuProc},
662 {N_("Engine #1 Settings ..."), FirstSettingsProc},
663 {N_("Engine #2 Settings ..."), SecondSettingsProc},
664 {N_("Time Control ..."), TimeControlProc},
665 {"----", NothingProc},
666 {N_("Always Queen"), AlwaysQueenProc},
667 {N_("Animate Dragging"), AnimateDraggingProc},
668 {N_("Animate Moving"), AnimateMovingProc},
669 {N_("Auto Comment"), AutocommProc},
670 {N_("Auto Flag"), AutoflagProc},
671 {N_("Auto Flip View"), AutoflipProc},
672 {N_("Auto Observe"), AutobsProc},
673 {N_("Auto Raise Board"), AutoraiseProc},
674 {N_("Auto Save"), AutosaveProc},
675 {N_("Blindfold"), BlindfoldProc},
676 {N_("Flash Moves"), FlashMovesProc},
677 {N_("Get Move List"), GetMoveListProc},
679 {N_("Highlight Dragging"), HighlightDraggingProc},
681 {N_("Highlight Last Move"), HighlightLastMoveProc},
682 {N_("Move Sound"), MoveSoundProc},
683 {N_("ICS Alarm"), IcsAlarmProc},
684 {N_("Old Save Style"), OldSaveStyleProc},
685 {N_("Periodic Updates"), PeriodicUpdatesProc},
686 {N_("Ponder Next Move"), PonderNextMoveProc},
687 {N_("Popup Exit Message"), PopupExitMessageProc},
688 {N_("Popup Move Errors"), PopupMoveErrorsProc},
689 {N_("Premove"), PremoveProc},
690 {N_("Quiet Play"), QuietPlayProc},
691 {N_("Show Coords"), ShowCoordsProc},
692 {N_("Hide Thinking"), HideThinkingProc},
693 {N_("Test Legality"), TestLegalityProc},
694 {"----", NothingProc},
695 {N_("Save Settings Now"), SaveSettingsProc},
696 {N_("Save Settings on Exit"), SaveOnExitProc},
700 MenuItem helpMenu[] = {
701 {N_("Info XBoard"), InfoProc},
702 {N_("Man XBoard"), ManProc},
703 {"----", NothingProc},
704 {N_("Hint"), HintProc},
705 {N_("Book"), BookProc},
706 {"----", NothingProc},
707 {N_("About XBoard"), AboutProc},
712 {N_("File"), fileMenu},
713 {N_("Mode"), modeMenu},
714 {N_("Action"), actionMenu},
715 {N_("Step"), stepMenu},
716 {N_("Options"), optionsMenu},
717 {N_("Help"), helpMenu},
721 #define PAUSE_BUTTON N_("P")
722 MenuItem buttonBar[] = {
725 {PAUSE_BUTTON, PauseProc},
731 #define PIECE_MENU_SIZE 18
732 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
733 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
734 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
735 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
736 N_("Empty square"), N_("Clear board") },
737 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
738 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
739 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
740 N_("Empty square"), N_("Clear board") }
742 /* must be in same order as PieceMenuStrings! */
743 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
744 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
745 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
746 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
747 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
748 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
749 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
750 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
751 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
754 #define DROP_MENU_SIZE 6
755 String dropMenuStrings[DROP_MENU_SIZE] = {
756 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
758 /* must be in same order as PieceMenuStrings! */
759 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
760 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
761 WhiteRook, WhiteQueen
769 DropMenuEnables dmEnables[] = {
787 { XtNborderWidth, 0 },
788 { XtNdefaultDistance, 0 },
792 { XtNborderWidth, 0 },
793 { XtNresizable, (XtArgVal) True },
797 { XtNborderWidth, 0 },
803 { XtNjustify, (XtArgVal) XtJustifyRight },
804 { XtNlabel, (XtArgVal) "..." },
805 { XtNresizable, (XtArgVal) True },
806 { XtNresize, (XtArgVal) False }
809 Arg messageArgs[] = {
810 { XtNjustify, (XtArgVal) XtJustifyLeft },
811 { XtNlabel, (XtArgVal) "..." },
812 { XtNresizable, (XtArgVal) True },
813 { XtNresize, (XtArgVal) False }
817 { XtNborderWidth, 0 },
818 { XtNjustify, (XtArgVal) XtJustifyLeft }
821 XtResource clientResources[] = {
822 { "flashCount", "flashCount", XtRInt, sizeof(int),
823 XtOffset(AppDataPtr, flashCount), XtRImmediate,
824 (XtPointer) FLASH_COUNT },
827 XrmOptionDescRec shellOptions[] = {
828 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
829 { "-flash", "flashCount", XrmoptionNoArg, "3" },
830 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
833 XtActionsRec boardActions[] = {
834 { "DrawPosition", DrawPositionProc },
835 { "HandleUserMove", HandleUserMove },
836 { "AnimateUserMove", AnimateUserMove },
837 { "HandlePV", HandlePV },
838 { "UnLoadPV", UnLoadPV },
839 { "FileNameAction", FileNameAction },
840 { "AskQuestionProc", AskQuestionProc },
841 { "AskQuestionReplyAction", AskQuestionReplyAction },
842 { "PieceMenuPopup", PieceMenuPopup },
843 { "WhiteClock", WhiteClock },
844 { "BlackClock", BlackClock },
845 { "Iconify", Iconify },
846 { "ResetProc", ResetProc },
847 { "LoadGameProc", LoadGameProc },
848 { "LoadNextGameProc", LoadNextGameProc },
849 { "LoadPrevGameProc", LoadPrevGameProc },
850 { "LoadSelectedProc", LoadSelectedProc },
851 { "ReloadGameProc", ReloadGameProc },
852 { "LoadPositionProc", LoadPositionProc },
853 { "LoadNextPositionProc", LoadNextPositionProc },
854 { "LoadPrevPositionProc", LoadPrevPositionProc },
855 { "ReloadPositionProc", ReloadPositionProc },
856 { "CopyPositionProc", CopyPositionProc },
857 { "PastePositionProc", PastePositionProc },
858 { "CopyGameProc", CopyGameProc },
859 { "PasteGameProc", PasteGameProc },
860 { "SaveGameProc", SaveGameProc },
861 { "SavePositionProc", SavePositionProc },
862 { "MailMoveProc", MailMoveProc },
863 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
864 { "QuitProc", QuitProc },
865 { "MachineWhiteProc", MachineWhiteProc },
866 { "MachineBlackProc", MachineBlackProc },
867 { "AnalysisModeProc", AnalyzeModeProc },
868 { "AnalyzeFileProc", AnalyzeFileProc },
869 { "TwoMachinesProc", TwoMachinesProc },
870 { "IcsClientProc", IcsClientProc },
871 { "EditGameProc", EditGameProc },
872 { "EditPositionProc", EditPositionProc },
873 { "TrainingProc", EditPositionProc },
874 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
875 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
876 { "ShowGameListProc", ShowGameListProc },
877 { "ShowMoveListProc", HistoryShowProc},
878 { "EditTagsProc", EditCommentProc },
879 { "EditCommentProc", EditCommentProc },
880 { "IcsAlarmProc", IcsAlarmProc },
881 { "IcsInputBoxProc", IcsInputBoxProc },
882 { "PauseProc", PauseProc },
883 { "AcceptProc", AcceptProc },
884 { "DeclineProc", DeclineProc },
885 { "RematchProc", RematchProc },
886 { "CallFlagProc", CallFlagProc },
887 { "DrawProc", DrawProc },
888 { "AdjournProc", AdjournProc },
889 { "AbortProc", AbortProc },
890 { "ResignProc", ResignProc },
891 { "AdjuWhiteProc", AdjuWhiteProc },
892 { "AdjuBlackProc", AdjuBlackProc },
893 { "AdjuDrawProc", AdjuDrawProc },
894 { "EnterKeyProc", EnterKeyProc },
895 { "StopObservingProc", StopObservingProc },
896 { "StopExaminingProc", StopExaminingProc },
897 { "BackwardProc", BackwardProc },
898 { "ForwardProc", ForwardProc },
899 { "ToStartProc", ToStartProc },
900 { "ToEndProc", ToEndProc },
901 { "RevertProc", RevertProc },
902 { "TruncateGameProc", TruncateGameProc },
903 { "MoveNowProc", MoveNowProc },
904 { "RetractMoveProc", RetractMoveProc },
905 { "AlwaysQueenProc", AlwaysQueenProc },
906 { "AnimateDraggingProc", AnimateDraggingProc },
907 { "AnimateMovingProc", AnimateMovingProc },
908 { "AutoflagProc", AutoflagProc },
909 { "AutoflipProc", AutoflipProc },
910 { "AutobsProc", AutobsProc },
911 { "AutoraiseProc", AutoraiseProc },
912 { "AutosaveProc", AutosaveProc },
913 { "BlindfoldProc", BlindfoldProc },
914 { "FlashMovesProc", FlashMovesProc },
915 { "FlipViewProc", FlipViewProc },
916 { "GetMoveListProc", GetMoveListProc },
918 { "HighlightDraggingProc", HighlightDraggingProc },
920 { "HighlightLastMoveProc", HighlightLastMoveProc },
921 { "IcsAlarmProc", IcsAlarmProc },
922 { "MoveSoundProc", MoveSoundProc },
923 { "OldSaveStyleProc", OldSaveStyleProc },
924 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
925 { "PonderNextMoveProc", PonderNextMoveProc },
926 { "PopupExitMessageProc", PopupExitMessageProc },
927 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
928 { "PremoveProc", PremoveProc },
929 { "QuietPlayProc", QuietPlayProc },
930 { "ShowCoordsProc", ShowCoordsProc },
931 { "ShowThinkingProc", ShowThinkingProc },
932 { "HideThinkingProc", HideThinkingProc },
933 { "TestLegalityProc", TestLegalityProc },
934 { "SaveSettingsProc", SaveSettingsProc },
935 { "SaveOnExitProc", SaveOnExitProc },
936 { "InfoProc", InfoProc },
937 { "ManProc", ManProc },
938 { "HintProc", HintProc },
939 { "BookProc", BookProc },
940 { "AboutGameProc", AboutGameProc },
941 { "AboutProc", AboutProc },
942 { "DebugProc", DebugProc },
943 { "NothingProc", NothingProc },
944 { "CommentPopDown", (XtActionProc) CommentPopDown },
945 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
946 { "TagsPopDown", (XtActionProc) TagsPopDown },
947 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
948 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
949 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
950 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
951 { "GameListPopDown", (XtActionProc) GameListPopDown },
952 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
953 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
954 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
955 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
956 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
957 { "EnginePopDown", (XtActionProc) EnginePopDown },
958 { "UciPopDown", (XtActionProc) UciPopDown },
959 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
960 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
961 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
962 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
965 char globalTranslations[] =
966 ":<Key>R: ResignProc() \n \
967 :<Key>r: ResetProc() \n \
968 :<Key>g: LoadGameProc() \n \
969 :<Key>N: LoadNextGameProc() \n \
970 :<Key>P: LoadPrevGameProc() \n \
971 :<Key>Q: QuitProc() \n \
972 :<Key>F: ToEndProc() \n \
973 :<Key>f: ForwardProc() \n \
974 :<Key>B: ToStartProc() \n \
975 :<Key>b: BackwardProc() \n \
976 :<Key>p: PauseProc() \n \
977 :<Key>d: DrawProc() \n \
978 :<Key>t: CallFlagProc() \n \
979 :<Key>i: Iconify() \n \
980 :<Key>c: Iconify() \n \
981 :<Key>v: FlipViewProc() \n \
982 <KeyDown>Control_L: BackwardProc() \n \
983 <KeyUp>Control_L: ForwardProc() \n \
984 <KeyDown>Control_R: BackwardProc() \n \
985 <KeyUp>Control_R: ForwardProc() \n \
986 Shift<Key>1: AskQuestionProc(\"Direct command\",\
987 \"Send to chess program:\",,1) \n \
988 Shift<Key>2: AskQuestionProc(\"Direct command\",\
989 \"Send to second chess program:\",,2) \n";
991 char boardTranslations[] =
992 "<Btn1Down>: HandleUserMove() \n \
993 <Btn1Up>: HandleUserMove() \n \
994 <Btn1Motion>: AnimateUserMove() \n \
995 <Btn3Motion>: HandlePV() \n \
996 <Btn3Up>: UnLoadPV() \n \
997 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
998 PieceMenuPopup(menuB) \n \
999 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1000 PieceMenuPopup(menuW) \n \
1001 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1002 PieceMenuPopup(menuW) \n \
1003 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1004 PieceMenuPopup(menuB) \n";
1006 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1007 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1009 char ICSInputTranslations[] =
1010 "<Key>Return: EnterKeyProc() \n";
1012 String xboardResources[] = {
1013 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1014 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1015 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1020 /* Max possible square size */
1021 #define MAXSQSIZE 256
1023 static int xpm_avail[MAXSQSIZE];
1025 #ifdef HAVE_DIR_STRUCT
1027 /* Extract piece size from filename */
1029 xpm_getsize(name, len, ext)
1040 if ((p=strchr(name, '.')) == NULL ||
1041 StrCaseCmp(p+1, ext) != 0)
1047 while (*p && isdigit(*p))
1054 /* Setup xpm_avail */
1056 xpm_getavail(dirname, ext)
1064 for (i=0; i<MAXSQSIZE; ++i)
1067 if (appData.debugMode)
1068 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1070 dir = opendir(dirname);
1073 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1074 programName, dirname);
1078 while ((ent=readdir(dir)) != NULL) {
1079 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1080 if (i > 0 && i < MAXSQSIZE)
1090 xpm_print_avail(fp, ext)
1096 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1097 for (i=1; i<MAXSQSIZE; ++i) {
1103 /* Return XPM piecesize closest to size */
1105 xpm_closest_to(dirname, size, ext)
1111 int sm_diff = MAXSQSIZE;
1115 xpm_getavail(dirname, ext);
1117 if (appData.debugMode)
1118 xpm_print_avail(stderr, ext);
1120 for (i=1; i<MAXSQSIZE; ++i) {
1123 diff = (diff<0) ? -diff : diff;
1124 if (diff < sm_diff) {
1132 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1138 #else /* !HAVE_DIR_STRUCT */
1139 /* If we are on a system without a DIR struct, we can't
1140 read the directory, so we can't collect a list of
1141 filenames, etc., so we can't do any size-fitting. */
1143 xpm_closest_to(dirname, size, ext)
1148 fprintf(stderr, _("\
1149 Warning: No DIR structure found on this system --\n\
1150 Unable to autosize for XPM/XIM pieces.\n\
1151 Please report this error to frankm@hiwaay.net.\n\
1152 Include system type & operating system in message.\n"));
1155 #endif /* HAVE_DIR_STRUCT */
1157 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1158 "magenta", "cyan", "white" };
1162 TextColors textColors[(int)NColorClasses];
1164 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1166 parse_color(str, which)
1170 char *p, buf[100], *d;
1173 if (strlen(str) > 99) /* watch bounds on buf */
1178 for (i=0; i<which; ++i) {
1185 /* Could be looking at something like:
1187 .. in which case we want to stop on a comma also */
1188 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1192 return -1; /* Use default for empty field */
1195 if (which == 2 || isdigit(*p))
1198 while (*p && isalpha(*p))
1203 for (i=0; i<8; ++i) {
1204 if (!StrCaseCmp(buf, cnames[i]))
1205 return which? (i+40) : (i+30);
1207 if (!StrCaseCmp(buf, "default")) return -1;
1209 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1214 parse_cpair(cc, str)
1218 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1219 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1224 /* bg and attr are optional */
1225 textColors[(int)cc].bg = parse_color(str, 1);
1226 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1227 textColors[(int)cc].attr = 0;
1233 /* Arrange to catch delete-window events */
1234 Atom wm_delete_window;
1236 CatchDeleteWindow(Widget w, String procname)
1239 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1240 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1241 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1248 XtSetArg(args[0], XtNiconic, False);
1249 XtSetValues(shellWidget, args, 1);
1251 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1254 //---------------------------------------------------------------------------------------------------------
1255 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1258 #define CW_USEDEFAULT (1<<31)
1259 #define ICS_TEXT_MENU_SIZE 90
1260 #define DEBUG_FILE "xboard.debug"
1261 #define SetCurrentDirectory chdir
1262 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1266 // these two must some day move to frontend.h, when they are implemented
1267 Boolean GameListIsUp();
1269 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1272 // front-end part of option handling
1274 // [HGM] This platform-dependent table provides the location for storing the color info
1275 extern char *crWhite, * crBlack;
1279 &appData.whitePieceColor,
1280 &appData.blackPieceColor,
1281 &appData.lightSquareColor,
1282 &appData.darkSquareColor,
1283 &appData.highlightSquareColor,
1284 &appData.premoveHighlightColor,
1297 ParseFont(char *name, int number)
1298 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1300 case 0: // CLOCK_FONT
1301 appData.clockFont = strdup(name);
1303 case 1: // MESSAGE_FONT
1304 appData.font = strdup(name);
1306 case 2: // COORD_FONT
1307 appData.coordFont = strdup(name);
1316 { // only 2 fonts currently
1317 appData.clockFont = CLOCK_FONT_NAME;
1318 appData.coordFont = COORD_FONT_NAME;
1319 appData.font = DEFAULT_FONT_NAME;
1324 { // no-op, until we identify the code for this already in XBoard and move it here
1328 ParseColor(int n, char *name)
1329 { // in XBoard, just copy the color-name string
1330 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1334 ParseTextAttribs(ColorClass cc, char *s)
1336 (&appData.colorShout)[cc] = strdup(s);
1340 ParseBoardSize(void *addr, char *name)
1342 appData.boardSize = strdup(name);
1347 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1351 SetCommPortDefaults()
1352 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1355 // [HGM] args: these three cases taken out to stay in front-end
1357 SaveFontArg(FILE *f, ArgDescriptor *ad)
1360 switch((int)ad->argLoc) {
1361 case 0: // CLOCK_FONT
1362 name = appData.clockFont;
1364 case 1: // MESSAGE_FONT
1365 name = appData.font;
1367 case 2: // COORD_FONT
1368 name = appData.coordFont;
1373 // Do not save fonts for now, as the saved font would be board-size specific
1374 // and not suitable for a re-start at another board size
1375 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1380 { // nothing to do, as the sounds are at all times represented by their text-string names already
1384 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1385 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1386 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1390 SaveColor(FILE *f, ArgDescriptor *ad)
1391 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1392 if(colorVariable[(int)ad->argLoc])
1393 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1397 SaveBoardSize(FILE *f, char *name, void *addr)
1398 { // wrapper to shield back-end from BoardSize & sizeInfo
1399 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1403 ParseCommPortSettings(char *s)
1404 { // no such option in XBoard (yet)
1407 extern Widget engineOutputShell;
1408 extern Widget tagsShell, editTagsShell;
1410 GetActualPlacement(Widget wg, WindowPlacement *wp)
1420 XtSetArg(args[i], XtNx, &x); i++;
1421 XtSetArg(args[i], XtNy, &y); i++;
1422 XtSetArg(args[i], XtNwidth, &w); i++;
1423 XtSetArg(args[i], XtNheight, &h); i++;
1424 XtGetValues(wg, args, i);
1433 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1434 // In XBoard this will have to wait until awareness of window parameters is implemented
1435 GetActualPlacement(shellWidget, &wpMain);
1436 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1437 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1438 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1439 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1440 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1441 else GetActualPlacement(editShell, &wpComment);
1442 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1443 else GetActualPlacement(editTagsShell, &wpTags);
1447 PrintCommPortSettings(FILE *f, char *name)
1448 { // This option does not exist in XBoard
1452 MySearchPath(char *installDir, char *name, char *fullname)
1453 { // just append installDir and name. Perhaps ExpandPath should be used here?
1454 name = ExpandPathName(name);
1455 if(name && name[0] == '/') strcpy(fullname, name); else {
1456 sprintf(fullname, "%s%c%s", installDir, '/', name);
1462 MyGetFullPathName(char *name, char *fullname)
1463 { // should use ExpandPath?
1464 name = ExpandPathName(name);
1465 strcpy(fullname, name);
1470 EnsureOnScreen(int *x, int *y, int minX, int minY)
1477 { // [HGM] args: allows testing if main window is realized from back-end
1478 return xBoardWindow != 0;
1482 PopUpStartupDialog()
1483 { // start menu not implemented in XBoard
1486 ConvertToLine(int argc, char **argv)
1488 static char line[128*1024], buf[1024];
1492 for(i=1; i<argc; i++) {
1493 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1494 && argv[i][0] != '{' )
1495 sprintf(buf, "{%s} ", argv[i]);
1496 else sprintf(buf, "%s ", argv[i]);
1499 line[strlen(line)-1] = NULLCHAR;
1503 //--------------------------------------------------------------------------------------------
1506 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1508 #define BoardSize int
1509 void InitDrawingSizes(BoardSize boardSize, int flags)
1510 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1511 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1513 XtGeometryResult gres;
1516 if(!formWidget) return;
1519 * Enable shell resizing.
1521 shellArgs[0].value = (XtArgVal) &w;
1522 shellArgs[1].value = (XtArgVal) &h;
1523 XtGetValues(shellWidget, shellArgs, 2);
1525 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1526 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1527 XtSetValues(shellWidget, &shellArgs[2], 4);
1529 XtSetArg(args[0], XtNdefaultDistance, &sep);
1530 XtGetValues(formWidget, args, 1);
1532 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1533 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1536 XtSetArg(args[0], XtNwidth, boardWidth);
1537 XtSetArg(args[1], XtNheight, boardHeight);
1538 XtSetValues(boardWidget, args, 2);
1540 timerWidth = (boardWidth - sep) / 2;
1541 XtSetArg(args[0], XtNwidth, timerWidth);
1542 XtSetValues(whiteTimerWidget, args, 1);
1543 XtSetValues(blackTimerWidget, args, 1);
1545 XawFormDoLayout(formWidget, False);
1547 if (appData.titleInWindow) {
1549 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1550 XtSetArg(args[i], XtNheight, &h); i++;
1551 XtGetValues(titleWidget, args, i);
1553 w = boardWidth - 2*bor;
1555 XtSetArg(args[0], XtNwidth, &w);
1556 XtGetValues(menuBarWidget, args, 1);
1557 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1560 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1561 if (gres != XtGeometryYes && appData.debugMode) {
1563 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1564 programName, gres, w, h, wr, hr);
1568 XawFormDoLayout(formWidget, True);
1571 * Inhibit shell resizing.
1573 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1574 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1575 shellArgs[4].value = shellArgs[2].value = w;
1576 shellArgs[5].value = shellArgs[3].value = h;
1577 XtSetValues(shellWidget, &shellArgs[0], 6);
1579 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1582 for(i=0; i<4; i++) {
1584 for(p=0; p<=(int)WhiteKing; p++)
1585 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1586 if(gameInfo.variant == VariantShogi) {
1587 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1588 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1589 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1590 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1591 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1594 if(gameInfo.variant == VariantGothic) {
1595 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1599 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1600 for(p=0; p<=(int)WhiteKing; p++)
1601 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1602 if(gameInfo.variant == VariantShogi) {
1603 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1604 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1605 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1606 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1607 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1610 if(gameInfo.variant == VariantGothic) {
1611 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1617 for(i=0; i<2; i++) {
1619 for(p=0; p<=(int)WhiteKing; p++)
1620 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1621 if(gameInfo.variant == VariantShogi) {
1622 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1623 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1624 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1625 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1626 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1629 if(gameInfo.variant == VariantGothic) {
1630 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1641 void EscapeExpand(char *p, char *q)
1642 { // [HGM] initstring: routine to shape up string arguments
1643 while(*p++ = *q++) if(p[-1] == '\\')
1645 case 'n': p[-1] = '\n'; break;
1646 case 'r': p[-1] = '\r'; break;
1647 case 't': p[-1] = '\t'; break;
1648 case '\\': p[-1] = '\\'; break;
1649 case 0: *p = 0; return;
1650 default: p[-1] = q[-1]; break;
1659 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1660 XSetWindowAttributes window_attributes;
1662 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1663 XrmValue vFrom, vTo;
1664 XtGeometryResult gres;
1667 int forceMono = False;
1669 srandom(time(0)); // [HGM] book: make random truly random
1671 setbuf(stdout, NULL);
1672 setbuf(stderr, NULL);
1675 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1676 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1680 programName = strrchr(argv[0], '/');
1681 if (programName == NULL)
1682 programName = argv[0];
1687 XtSetLanguageProc(NULL, NULL, NULL);
1688 bindtextdomain(PACKAGE, LOCALEDIR);
1689 textdomain(PACKAGE);
1693 XtAppInitialize(&appContext, "XBoard", shellOptions,
1694 XtNumber(shellOptions),
1695 &argc, argv, xboardResources, NULL, 0);
1696 appData.boardSize = "";
1697 InitAppData(ConvertToLine(argc, argv));
1699 if (p == NULL) p = "/tmp";
1700 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1701 gameCopyFilename = (char*) malloc(i);
1702 gamePasteFilename = (char*) malloc(i);
1703 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1704 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1706 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1707 clientResources, XtNumber(clientResources),
1710 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1711 static char buf[MSG_SIZ];
1712 EscapeExpand(buf, appData.initString);
1713 appData.initString = strdup(buf);
1714 EscapeExpand(buf, appData.secondInitString);
1715 appData.secondInitString = strdup(buf);
1716 EscapeExpand(buf, appData.firstComputerString);
1717 appData.firstComputerString = strdup(buf);
1718 EscapeExpand(buf, appData.secondComputerString);
1719 appData.secondComputerString = strdup(buf);
1722 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1725 if (chdir(chessDir) != 0) {
1726 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1732 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1733 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1734 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1735 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1738 setbuf(debugFP, NULL);
1741 /* [HGM,HR] make sure board size is acceptable */
1742 if(appData.NrFiles > BOARD_FILES ||
1743 appData.NrRanks > BOARD_RANKS )
1744 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1747 /* This feature does not work; animation needs a rewrite */
1748 appData.highlightDragging = FALSE;
1752 xDisplay = XtDisplay(shellWidget);
1753 xScreen = DefaultScreen(xDisplay);
1754 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1756 gameInfo.variant = StringToVariant(appData.variant);
1757 InitPosition(FALSE);
1760 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1762 if (isdigit(appData.boardSize[0])) {
1763 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1764 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1765 &fontPxlSize, &smallLayout, &tinyLayout);
1767 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1768 programName, appData.boardSize);
1772 /* Find some defaults; use the nearest known size */
1773 SizeDefaults *szd, *nearest;
1774 int distance = 99999;
1775 nearest = szd = sizeDefaults;
1776 while (szd->name != NULL) {
1777 if (abs(szd->squareSize - squareSize) < distance) {
1779 distance = abs(szd->squareSize - squareSize);
1780 if (distance == 0) break;
1784 if (i < 2) lineGap = nearest->lineGap;
1785 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1786 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1787 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1788 if (i < 6) smallLayout = nearest->smallLayout;
1789 if (i < 7) tinyLayout = nearest->tinyLayout;
1792 SizeDefaults *szd = sizeDefaults;
1793 if (*appData.boardSize == NULLCHAR) {
1794 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1795 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1798 if (szd->name == NULL) szd--;
1799 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1801 while (szd->name != NULL &&
1802 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1803 if (szd->name == NULL) {
1804 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1805 programName, appData.boardSize);
1809 squareSize = szd->squareSize;
1810 lineGap = szd->lineGap;
1811 clockFontPxlSize = szd->clockFontPxlSize;
1812 coordFontPxlSize = szd->coordFontPxlSize;
1813 fontPxlSize = szd->fontPxlSize;
1814 smallLayout = szd->smallLayout;
1815 tinyLayout = szd->tinyLayout;
1818 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1819 if (strlen(appData.pixmapDirectory) > 0) {
1820 p = ExpandPathName(appData.pixmapDirectory);
1822 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1823 appData.pixmapDirectory);
1826 if (appData.debugMode) {
1827 fprintf(stderr, _("\
1828 XBoard square size (hint): %d\n\
1829 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1831 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1832 if (appData.debugMode) {
1833 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1837 /* [HR] height treated separately (hacked) */
1838 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1839 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1840 if (appData.showJail == 1) {
1841 /* Jail on top and bottom */
1842 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1843 XtSetArg(boardArgs[2], XtNheight,
1844 boardHeight + 2*(lineGap + squareSize));
1845 } else if (appData.showJail == 2) {
1847 XtSetArg(boardArgs[1], XtNwidth,
1848 boardWidth + 2*(lineGap + squareSize));
1849 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1852 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1853 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1857 * Determine what fonts to use.
1859 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1860 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1861 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1862 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1863 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1864 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1865 appData.font = FindFont(appData.font, fontPxlSize);
1866 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1867 countFontStruct = XQueryFont(xDisplay, countFontID);
1868 // appData.font = FindFont(appData.font, fontPxlSize);
1870 xdb = XtDatabase(xDisplay);
1871 XrmPutStringResource(&xdb, "*font", appData.font);
1874 * Detect if there are not enough colors available and adapt.
1876 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1877 appData.monoMode = True;
1880 if (!appData.monoMode) {
1881 vFrom.addr = (caddr_t) appData.lightSquareColor;
1882 vFrom.size = strlen(appData.lightSquareColor);
1883 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1884 if (vTo.addr == NULL) {
1885 appData.monoMode = True;
1888 lightSquareColor = *(Pixel *) vTo.addr;
1891 if (!appData.monoMode) {
1892 vFrom.addr = (caddr_t) appData.darkSquareColor;
1893 vFrom.size = strlen(appData.darkSquareColor);
1894 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1895 if (vTo.addr == NULL) {
1896 appData.monoMode = True;
1899 darkSquareColor = *(Pixel *) vTo.addr;
1902 if (!appData.monoMode) {
1903 vFrom.addr = (caddr_t) appData.whitePieceColor;
1904 vFrom.size = strlen(appData.whitePieceColor);
1905 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1906 if (vTo.addr == NULL) {
1907 appData.monoMode = True;
1910 whitePieceColor = *(Pixel *) vTo.addr;
1913 if (!appData.monoMode) {
1914 vFrom.addr = (caddr_t) appData.blackPieceColor;
1915 vFrom.size = strlen(appData.blackPieceColor);
1916 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1917 if (vTo.addr == NULL) {
1918 appData.monoMode = True;
1921 blackPieceColor = *(Pixel *) vTo.addr;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1927 vFrom.size = strlen(appData.highlightSquareColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 highlightSquareColor = *(Pixel *) vTo.addr;
1937 if (!appData.monoMode) {
1938 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1939 vFrom.size = strlen(appData.premoveHighlightColor);
1940 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1941 if (vTo.addr == NULL) {
1942 appData.monoMode = True;
1945 premoveHighlightColor = *(Pixel *) vTo.addr;
1950 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1953 if (appData.bitmapDirectory == NULL ||
1954 appData.bitmapDirectory[0] == NULLCHAR)
1955 appData.bitmapDirectory = DEF_BITMAP_DIR;
1958 if (appData.lowTimeWarning && !appData.monoMode) {
1959 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1960 vFrom.size = strlen(appData.lowTimeWarningColor);
1961 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1962 if (vTo.addr == NULL)
1963 appData.monoMode = True;
1965 lowTimeWarningColor = *(Pixel *) vTo.addr;
1968 if (appData.monoMode && appData.debugMode) {
1969 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1970 (unsigned long) XWhitePixel(xDisplay, xScreen),
1971 (unsigned long) XBlackPixel(xDisplay, xScreen));
1974 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1975 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1976 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1977 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1978 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1979 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1980 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1981 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1982 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1983 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1985 if (appData.colorize) {
1987 _("%s: can't parse color names; disabling colorization\n"),
1990 appData.colorize = FALSE;
1992 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1993 textColors[ColorNone].attr = 0;
1995 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2001 layoutName = "tinyLayout";
2002 } else if (smallLayout) {
2003 layoutName = "smallLayout";
2005 layoutName = "normalLayout";
2007 /* Outer layoutWidget is there only to provide a name for use in
2008 resources that depend on the layout style */
2010 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2011 layoutArgs, XtNumber(layoutArgs));
2013 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2014 formArgs, XtNumber(formArgs));
2015 XtSetArg(args[0], XtNdefaultDistance, &sep);
2016 XtGetValues(formWidget, args, 1);
2019 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2020 XtSetArg(args[0], XtNtop, XtChainTop);
2021 XtSetArg(args[1], XtNbottom, XtChainTop);
2022 XtSetArg(args[2], XtNright, XtChainLeft);
2023 XtSetValues(menuBarWidget, args, 3);
2025 widgetList[j++] = whiteTimerWidget =
2026 XtCreateWidget("whiteTime", labelWidgetClass,
2027 formWidget, timerArgs, XtNumber(timerArgs));
2028 XtSetArg(args[0], XtNfont, clockFontStruct);
2029 XtSetArg(args[1], XtNtop, XtChainTop);
2030 XtSetArg(args[2], XtNbottom, XtChainTop);
2031 XtSetValues(whiteTimerWidget, args, 3);
2033 widgetList[j++] = blackTimerWidget =
2034 XtCreateWidget("blackTime", labelWidgetClass,
2035 formWidget, timerArgs, XtNumber(timerArgs));
2036 XtSetArg(args[0], XtNfont, clockFontStruct);
2037 XtSetArg(args[1], XtNtop, XtChainTop);
2038 XtSetArg(args[2], XtNbottom, XtChainTop);
2039 XtSetValues(blackTimerWidget, args, 3);
2041 if (appData.titleInWindow) {
2042 widgetList[j++] = titleWidget =
2043 XtCreateWidget("title", labelWidgetClass, formWidget,
2044 titleArgs, XtNumber(titleArgs));
2045 XtSetArg(args[0], XtNtop, XtChainTop);
2046 XtSetArg(args[1], XtNbottom, XtChainTop);
2047 XtSetValues(titleWidget, args, 2);
2050 if (appData.showButtonBar) {
2051 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2052 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2053 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2054 XtSetArg(args[2], XtNtop, XtChainTop);
2055 XtSetArg(args[3], XtNbottom, XtChainTop);
2056 XtSetValues(buttonBarWidget, args, 4);
2059 widgetList[j++] = messageWidget =
2060 XtCreateWidget("message", labelWidgetClass, formWidget,
2061 messageArgs, XtNumber(messageArgs));
2062 XtSetArg(args[0], XtNtop, XtChainTop);
2063 XtSetArg(args[1], XtNbottom, XtChainTop);
2064 XtSetValues(messageWidget, args, 2);
2066 widgetList[j++] = boardWidget =
2067 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2068 XtNumber(boardArgs));
2070 XtManageChildren(widgetList, j);
2072 timerWidth = (boardWidth - sep) / 2;
2073 XtSetArg(args[0], XtNwidth, timerWidth);
2074 XtSetValues(whiteTimerWidget, args, 1);
2075 XtSetValues(blackTimerWidget, args, 1);
2077 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2078 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2079 XtGetValues(whiteTimerWidget, args, 2);
2081 if (appData.showButtonBar) {
2082 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2083 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2084 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2088 * formWidget uses these constraints but they are stored
2092 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2093 XtSetValues(menuBarWidget, args, i);
2094 if (appData.titleInWindow) {
2097 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2098 XtSetValues(whiteTimerWidget, args, i);
2100 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2101 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2102 XtSetValues(blackTimerWidget, args, i);
2104 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2105 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2106 XtSetValues(titleWidget, args, i);
2108 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2109 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2110 XtSetValues(messageWidget, args, i);
2111 if (appData.showButtonBar) {
2113 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2114 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2115 XtSetValues(buttonBarWidget, args, i);
2119 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2120 XtSetValues(whiteTimerWidget, args, i);
2122 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2123 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2124 XtSetValues(blackTimerWidget, args, i);
2126 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2127 XtSetValues(titleWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2130 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2131 XtSetValues(messageWidget, args, i);
2132 if (appData.showButtonBar) {
2134 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2135 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2136 XtSetValues(buttonBarWidget, args, i);
2141 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2142 XtSetValues(whiteTimerWidget, args, i);
2144 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2145 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2146 XtSetValues(blackTimerWidget, args, i);
2148 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2149 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2150 XtSetValues(messageWidget, args, i);
2151 if (appData.showButtonBar) {
2153 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2154 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2155 XtSetValues(buttonBarWidget, args, i);
2159 XtSetArg(args[0], XtNfromVert, messageWidget);
2160 XtSetArg(args[1], XtNtop, XtChainTop);
2161 XtSetArg(args[2], XtNbottom, XtChainBottom);
2162 XtSetArg(args[3], XtNleft, XtChainLeft);
2163 XtSetArg(args[4], XtNright, XtChainRight);
2164 XtSetValues(boardWidget, args, 5);
2166 XtRealizeWidget(shellWidget);
2169 XtSetArg(args[0], XtNx, wpMain.x);
2170 XtSetArg(args[1], XtNy, wpMain.y);
2171 XtSetValues(shellWidget, args, 2);
2175 * Correct the width of the message and title widgets.
2176 * It is not known why some systems need the extra fudge term.
2177 * The value "2" is probably larger than needed.
2179 XawFormDoLayout(formWidget, False);
2181 #define WIDTH_FUDGE 2
2183 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2184 XtSetArg(args[i], XtNheight, &h); i++;
2185 XtGetValues(messageWidget, args, i);
2186 if (appData.showButtonBar) {
2188 XtSetArg(args[i], XtNwidth, &w); i++;
2189 XtGetValues(buttonBarWidget, args, i);
2190 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2192 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2195 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2196 if (gres != XtGeometryYes && appData.debugMode) {
2197 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2198 programName, gres, w, h, wr, hr);
2201 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2202 /* The size used for the child widget in layout lags one resize behind
2203 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2205 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2206 if (gres != XtGeometryYes && appData.debugMode) {
2207 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2208 programName, gres, w, h, wr, hr);
2211 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2212 XtSetArg(args[1], XtNright, XtChainRight);
2213 XtSetValues(messageWidget, args, 2);
2215 if (appData.titleInWindow) {
2217 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2218 XtSetArg(args[i], XtNheight, &h); i++;
2219 XtGetValues(titleWidget, args, i);
2221 w = boardWidth - 2*bor;
2223 XtSetArg(args[0], XtNwidth, &w);
2224 XtGetValues(menuBarWidget, args, 1);
2225 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2228 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2229 if (gres != XtGeometryYes && appData.debugMode) {
2231 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2232 programName, gres, w, h, wr, hr);
2235 XawFormDoLayout(formWidget, True);
2237 xBoardWindow = XtWindow(boardWidget);
2239 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2240 // not need to go into InitDrawingSizes().
2244 * Create X checkmark bitmap and initialize option menu checks.
2246 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2247 checkmark_bits, checkmark_width, checkmark_height);
2248 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2249 if (appData.alwaysPromoteToQueen) {
2250 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2253 if (appData.animateDragging) {
2254 XtSetValues(XtNameToWidget(menuBarWidget,
2255 "menuOptions.Animate Dragging"),
2258 if (appData.animate) {
2259 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2262 if (appData.autoComment) {
2263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2266 if (appData.autoCallFlag) {
2267 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2270 if (appData.autoFlipView) {
2271 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2274 if (appData.autoObserve) {
2275 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2278 if (appData.autoRaiseBoard) {
2279 XtSetValues(XtNameToWidget(menuBarWidget,
2280 "menuOptions.Auto Raise Board"), args, 1);
2282 if (appData.autoSaveGames) {
2283 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2286 if (appData.saveGameFile[0] != NULLCHAR) {
2287 /* Can't turn this off from menu */
2288 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2290 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2294 if (appData.blindfold) {
2295 XtSetValues(XtNameToWidget(menuBarWidget,
2296 "menuOptions.Blindfold"), args, 1);
2298 if (appData.flashCount > 0) {
2299 XtSetValues(XtNameToWidget(menuBarWidget,
2300 "menuOptions.Flash Moves"),
2303 if (appData.getMoveList) {
2304 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2308 if (appData.highlightDragging) {
2309 XtSetValues(XtNameToWidget(menuBarWidget,
2310 "menuOptions.Highlight Dragging"),
2314 if (appData.highlightLastMove) {
2315 XtSetValues(XtNameToWidget(menuBarWidget,
2316 "menuOptions.Highlight Last Move"),
2319 if (appData.icsAlarm) {
2320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2323 if (appData.ringBellAfterMoves) {
2324 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2327 if (appData.oldSaveStyle) {
2328 XtSetValues(XtNameToWidget(menuBarWidget,
2329 "menuOptions.Old Save Style"), args, 1);
2331 if (appData.periodicUpdates) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Periodic Updates"), args, 1);
2335 if (appData.ponderNextMove) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Ponder Next Move"), args, 1);
2339 if (appData.popupExitMessage) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Popup Exit Message"), args, 1);
2343 if (appData.popupMoveErrors) {
2344 XtSetValues(XtNameToWidget(menuBarWidget,
2345 "menuOptions.Popup Move Errors"), args, 1);
2347 if (appData.premove) {
2348 XtSetValues(XtNameToWidget(menuBarWidget,
2349 "menuOptions.Premove"), args, 1);
2351 if (appData.quietPlay) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,
2353 "menuOptions.Quiet Play"), args, 1);
2355 if (appData.showCoords) {
2356 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2359 if (appData.hideThinkingFromHuman) {
2360 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2363 if (appData.testLegality) {
2364 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2367 if (saveSettingsOnExit) {
2368 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2375 ReadBitmap(&wIconPixmap, "icon_white.bm",
2376 icon_white_bits, icon_white_width, icon_white_height);
2377 ReadBitmap(&bIconPixmap, "icon_black.bm",
2378 icon_black_bits, icon_black_width, icon_black_height);
2379 iconPixmap = wIconPixmap;
2381 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2382 XtSetValues(shellWidget, args, i);
2385 * Create a cursor for the board widget.
2387 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2388 XChangeWindowAttributes(xDisplay, xBoardWindow,
2389 CWCursor, &window_attributes);
2392 * Inhibit shell resizing.
2394 shellArgs[0].value = (XtArgVal) &w;
2395 shellArgs[1].value = (XtArgVal) &h;
2396 XtGetValues(shellWidget, shellArgs, 2);
2397 shellArgs[4].value = shellArgs[2].value = w;
2398 shellArgs[5].value = shellArgs[3].value = h;
2399 XtSetValues(shellWidget, &shellArgs[2], 4);
2400 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2401 marginH = h - boardHeight;
2403 CatchDeleteWindow(shellWidget, "QuitProc");
2408 if (appData.bitmapDirectory[0] != NULLCHAR) {
2415 /* Create regular pieces */
2416 if (!useImages) CreatePieces();
2421 if (appData.animate || appData.animateDragging)
2424 XtAugmentTranslations(formWidget,
2425 XtParseTranslationTable(globalTranslations));
2426 XtAugmentTranslations(boardWidget,
2427 XtParseTranslationTable(boardTranslations));
2428 XtAugmentTranslations(whiteTimerWidget,
2429 XtParseTranslationTable(whiteTranslations));
2430 XtAugmentTranslations(blackTimerWidget,
2431 XtParseTranslationTable(blackTranslations));
2433 /* Why is the following needed on some versions of X instead
2434 * of a translation? */
2435 XtAddEventHandler(boardWidget, ExposureMask, False,
2436 (XtEventHandler) EventProc, NULL);
2439 /* [AS] Restore layout */
2440 if( wpMoveHistory.visible ) {
2444 if( wpEvalGraph.visible )
2449 if( wpEngineOutput.visible ) {
2450 EngineOutputPopUp();
2455 if (errorExitStatus == -1) {
2456 if (appData.icsActive) {
2457 /* We now wait until we see "login:" from the ICS before
2458 sending the logon script (problems with timestamp otherwise) */
2459 /*ICSInitScript();*/
2460 if (appData.icsInputBox) ICSInputBoxPopUp();
2464 signal(SIGWINCH, TermSizeSigHandler);
2466 signal(SIGINT, IntSigHandler);
2467 signal(SIGTERM, IntSigHandler);
2468 if (*appData.cmailGameName != NULLCHAR) {
2469 signal(SIGUSR1, CmailSigHandler);
2472 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2475 XtAppMainLoop(appContext);
2476 if (appData.debugMode) fclose(debugFP); // [DM] debug
2483 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2484 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2486 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2487 unlink(gameCopyFilename);
2488 unlink(gamePasteFilename);
2491 RETSIGTYPE TermSizeSigHandler(int sig)
2504 CmailSigHandler(sig)
2510 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2512 /* Activate call-back function CmailSigHandlerCallBack() */
2513 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2515 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2519 CmailSigHandlerCallBack(isr, closure, message, count, error)
2527 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2529 /**** end signal code ****/
2539 f = fopen(appData.icsLogon, "r");
2545 strcat(buf, appData.icsLogon);
2546 f = fopen(buf, "r");
2550 ProcessICSInitScript(f);
2557 EditCommentPopDown();
2572 if (!menuBarWidget) return;
2573 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2575 DisplayError("menuStep.Revert", 0);
2577 XtSetSensitive(w, !grey);
2582 SetMenuEnables(enab)
2586 if (!menuBarWidget) return;
2587 while (enab->name != NULL) {
2588 w = XtNameToWidget(menuBarWidget, enab->name);
2590 DisplayError(enab->name, 0);
2592 XtSetSensitive(w, enab->value);
2598 Enables icsEnables[] = {
2599 { "menuFile.Mail Move", False },
2600 { "menuFile.Reload CMail Message", False },
2601 { "menuMode.Machine Black", False },
2602 { "menuMode.Machine White", False },
2603 { "menuMode.Analysis Mode", False },
2604 { "menuMode.Analyze File", False },
2605 { "menuMode.Two Machines", False },
2607 { "menuHelp.Hint", False },
2608 { "menuHelp.Book", False },
2609 { "menuStep.Move Now", False },
2610 { "menuOptions.Periodic Updates", False },
2611 { "menuOptions.Hide Thinking", False },
2612 { "menuOptions.Ponder Next Move", False },
2617 Enables ncpEnables[] = {
2618 { "menuFile.Mail Move", False },
2619 { "menuFile.Reload CMail Message", False },
2620 { "menuMode.Machine White", False },
2621 { "menuMode.Machine Black", False },
2622 { "menuMode.Analysis Mode", False },
2623 { "menuMode.Analyze File", False },
2624 { "menuMode.Two Machines", False },
2625 { "menuMode.ICS Client", False },
2626 { "menuMode.ICS Input Box", False },
2627 { "Action", False },
2628 { "menuStep.Revert", False },
2629 { "menuStep.Move Now", False },
2630 { "menuStep.Retract Move", False },
2631 { "menuOptions.Auto Comment", False },
2632 { "menuOptions.Auto Flag", False },
2633 { "menuOptions.Auto Flip View", False },
2634 { "menuOptions.Auto Observe", False },
2635 { "menuOptions.Auto Raise Board", False },
2636 { "menuOptions.Get Move List", False },
2637 { "menuOptions.ICS Alarm", False },
2638 { "menuOptions.Move Sound", False },
2639 { "menuOptions.Quiet Play", False },
2640 { "menuOptions.Hide Thinking", False },
2641 { "menuOptions.Periodic Updates", False },
2642 { "menuOptions.Ponder Next Move", False },
2643 { "menuHelp.Hint", False },
2644 { "menuHelp.Book", False },
2648 Enables gnuEnables[] = {
2649 { "menuMode.ICS Client", False },
2650 { "menuMode.ICS Input Box", False },
2651 { "menuAction.Accept", False },
2652 { "menuAction.Decline", False },
2653 { "menuAction.Rematch", False },
2654 { "menuAction.Adjourn", False },
2655 { "menuAction.Stop Examining", False },
2656 { "menuAction.Stop Observing", False },
2657 { "menuStep.Revert", False },
2658 { "menuOptions.Auto Comment", False },
2659 { "menuOptions.Auto Observe", False },
2660 { "menuOptions.Auto Raise Board", False },
2661 { "menuOptions.Get Move List", False },
2662 { "menuOptions.Premove", False },
2663 { "menuOptions.Quiet Play", False },
2665 /* The next two options rely on SetCmailMode being called *after* */
2666 /* SetGNUMode so that when GNU is being used to give hints these */
2667 /* menu options are still available */
2669 { "menuFile.Mail Move", False },
2670 { "menuFile.Reload CMail Message", False },
2674 Enables cmailEnables[] = {
2676 { "menuAction.Call Flag", False },
2677 { "menuAction.Draw", True },
2678 { "menuAction.Adjourn", False },
2679 { "menuAction.Abort", False },
2680 { "menuAction.Stop Observing", False },
2681 { "menuAction.Stop Examining", False },
2682 { "menuFile.Mail Move", True },
2683 { "menuFile.Reload CMail Message", True },
2687 Enables trainingOnEnables[] = {
2688 { "menuMode.Edit Comment", False },
2689 { "menuMode.Pause", False },
2690 { "menuStep.Forward", False },
2691 { "menuStep.Backward", False },
2692 { "menuStep.Forward to End", False },
2693 { "menuStep.Back to Start", False },
2694 { "menuStep.Move Now", False },
2695 { "menuStep.Truncate Game", False },
2699 Enables trainingOffEnables[] = {
2700 { "menuMode.Edit Comment", True },
2701 { "menuMode.Pause", True },
2702 { "menuStep.Forward", True },
2703 { "menuStep.Backward", True },
2704 { "menuStep.Forward to End", True },
2705 { "menuStep.Back to Start", True },
2706 { "menuStep.Move Now", True },
2707 { "menuStep.Truncate Game", True },
2711 Enables machineThinkingEnables[] = {
2712 { "menuFile.Load Game", False },
2713 { "menuFile.Load Next Game", False },
2714 { "menuFile.Load Previous Game", False },
2715 { "menuFile.Reload Same Game", False },
2716 { "menuFile.Paste Game", False },
2717 { "menuFile.Load Position", False },
2718 { "menuFile.Load Next Position", False },
2719 { "menuFile.Load Previous Position", False },
2720 { "menuFile.Reload Same Position", False },
2721 { "menuFile.Paste Position", False },
2722 { "menuMode.Machine White", False },
2723 { "menuMode.Machine Black", False },
2724 { "menuMode.Two Machines", False },
2725 { "menuStep.Retract Move", False },
2729 Enables userThinkingEnables[] = {
2730 { "menuFile.Load Game", True },
2731 { "menuFile.Load Next Game", True },
2732 { "menuFile.Load Previous Game", True },
2733 { "menuFile.Reload Same Game", True },
2734 { "menuFile.Paste Game", True },
2735 { "menuFile.Load Position", True },
2736 { "menuFile.Load Next Position", True },
2737 { "menuFile.Load Previous Position", True },
2738 { "menuFile.Reload Same Position", True },
2739 { "menuFile.Paste Position", True },
2740 { "menuMode.Machine White", True },
2741 { "menuMode.Machine Black", True },
2742 { "menuMode.Two Machines", True },
2743 { "menuStep.Retract Move", True },
2749 SetMenuEnables(icsEnables);
2752 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2753 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2760 SetMenuEnables(ncpEnables);
2766 SetMenuEnables(gnuEnables);
2772 SetMenuEnables(cmailEnables);
2778 SetMenuEnables(trainingOnEnables);
2779 if (appData.showButtonBar) {
2780 XtSetSensitive(buttonBarWidget, False);
2786 SetTrainingModeOff()
2788 SetMenuEnables(trainingOffEnables);
2789 if (appData.showButtonBar) {
2790 XtSetSensitive(buttonBarWidget, True);
2795 SetUserThinkingEnables()
2797 if (appData.noChessProgram) return;
2798 SetMenuEnables(userThinkingEnables);
2802 SetMachineThinkingEnables()
2804 if (appData.noChessProgram) return;
2805 SetMenuEnables(machineThinkingEnables);
2807 case MachinePlaysBlack:
2808 case MachinePlaysWhite:
2809 case TwoMachinesPlay:
2810 XtSetSensitive(XtNameToWidget(menuBarWidget,
2811 ModeToWidgetName(gameMode)), True);
2818 #define Abs(n) ((n)<0 ? -(n) : (n))
2821 * Find a font that matches "pattern" that is as close as
2822 * possible to the targetPxlSize. Prefer fonts that are k
2823 * pixels smaller to fonts that are k pixels larger. The
2824 * pattern must be in the X Consortium standard format,
2825 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2826 * The return value should be freed with XtFree when no
2829 char *FindFont(pattern, targetPxlSize)
2833 char **fonts, *p, *best, *scalable, *scalableTail;
2834 int i, j, nfonts, minerr, err, pxlSize;
2837 char **missing_list;
2839 char *def_string, *base_fnt_lst, strInt[3];
2841 XFontStruct **fnt_list;
2843 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2844 sprintf(strInt, "%d", targetPxlSize);
2845 p = strstr(pattern, "--");
2846 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2847 strcat(base_fnt_lst, strInt);
2848 strcat(base_fnt_lst, strchr(p + 2, '-'));
2850 if ((fntSet = XCreateFontSet(xDisplay,
2854 &def_string)) == NULL) {
2856 fprintf(stderr, _("Unable to create font set.\n"));
2860 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2862 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2864 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2865 programName, pattern);
2873 for (i=0; i<nfonts; i++) {
2876 if (*p != '-') continue;
2878 if (*p == NULLCHAR) break;
2879 if (*p++ == '-') j++;
2881 if (j < 7) continue;
2884 scalable = fonts[i];
2887 err = pxlSize - targetPxlSize;
2888 if (Abs(err) < Abs(minerr) ||
2889 (minerr > 0 && err < 0 && -err == minerr)) {
2895 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2896 /* If the error is too big and there is a scalable font,
2897 use the scalable font. */
2898 int headlen = scalableTail - scalable;
2899 p = (char *) XtMalloc(strlen(scalable) + 10);
2900 while (isdigit(*scalableTail)) scalableTail++;
2901 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2903 p = (char *) XtMalloc(strlen(best) + 1);
2906 if (appData.debugMode) {
2907 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2908 pattern, targetPxlSize, p);
2911 if (missing_count > 0)
2912 XFreeStringList(missing_list);
2913 XFreeFontSet(xDisplay, fntSet);
2915 XFreeFontNames(fonts);
2922 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2923 | GCBackground | GCFunction | GCPlaneMask;
2924 XGCValues gc_values;
2927 gc_values.plane_mask = AllPlanes;
2928 gc_values.line_width = lineGap;
2929 gc_values.line_style = LineSolid;
2930 gc_values.function = GXcopy;
2932 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2933 gc_values.background = XBlackPixel(xDisplay, xScreen);
2934 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2936 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2937 gc_values.background = XWhitePixel(xDisplay, xScreen);
2938 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2939 XSetFont(xDisplay, coordGC, coordFontID);
2941 // [HGM] make font for holdings counts (white on black0
2942 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2943 gc_values.background = XBlackPixel(xDisplay, xScreen);
2944 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2945 XSetFont(xDisplay, countGC, countFontID);
2947 if (appData.monoMode) {
2948 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2949 gc_values.background = XWhitePixel(xDisplay, xScreen);
2950 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2952 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2953 gc_values.background = XBlackPixel(xDisplay, xScreen);
2954 lightSquareGC = wbPieceGC
2955 = XtGetGC(shellWidget, value_mask, &gc_values);
2957 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2958 gc_values.background = XWhitePixel(xDisplay, xScreen);
2959 darkSquareGC = bwPieceGC
2960 = XtGetGC(shellWidget, value_mask, &gc_values);
2962 if (DefaultDepth(xDisplay, xScreen) == 1) {
2963 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2964 gc_values.function = GXcopyInverted;
2965 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2966 gc_values.function = GXcopy;
2967 if (XBlackPixel(xDisplay, xScreen) == 1) {
2968 bwPieceGC = darkSquareGC;
2969 wbPieceGC = copyInvertedGC;
2971 bwPieceGC = copyInvertedGC;
2972 wbPieceGC = lightSquareGC;
2976 gc_values.foreground = highlightSquareColor;
2977 gc_values.background = highlightSquareColor;
2978 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2980 gc_values.foreground = premoveHighlightColor;
2981 gc_values.background = premoveHighlightColor;
2982 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2984 gc_values.foreground = lightSquareColor;
2985 gc_values.background = darkSquareColor;
2986 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2988 gc_values.foreground = darkSquareColor;
2989 gc_values.background = lightSquareColor;
2990 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2992 gc_values.foreground = jailSquareColor;
2993 gc_values.background = jailSquareColor;
2994 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2996 gc_values.foreground = whitePieceColor;
2997 gc_values.background = darkSquareColor;
2998 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3000 gc_values.foreground = whitePieceColor;
3001 gc_values.background = lightSquareColor;
3002 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3004 gc_values.foreground = whitePieceColor;
3005 gc_values.background = jailSquareColor;
3006 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3008 gc_values.foreground = blackPieceColor;
3009 gc_values.background = darkSquareColor;
3010 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3012 gc_values.foreground = blackPieceColor;
3013 gc_values.background = lightSquareColor;
3014 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3016 gc_values.foreground = blackPieceColor;
3017 gc_values.background = jailSquareColor;
3018 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3022 void loadXIM(xim, xmask, filename, dest, mask)
3035 fp = fopen(filename, "rb");
3037 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3044 for (y=0; y<h; ++y) {
3045 for (x=0; x<h; ++x) {
3050 XPutPixel(xim, x, y, blackPieceColor);
3052 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3055 XPutPixel(xim, x, y, darkSquareColor);
3057 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3060 XPutPixel(xim, x, y, whitePieceColor);
3062 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3065 XPutPixel(xim, x, y, lightSquareColor);
3067 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3073 /* create Pixmap of piece */
3074 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3076 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3079 /* create Pixmap of clipmask
3080 Note: We assume the white/black pieces have the same
3081 outline, so we make only 6 masks. This is okay
3082 since the XPM clipmask routines do the same. */
3084 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3086 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3089 /* now create the 1-bit version */
3090 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3093 values.foreground = 1;
3094 values.background = 0;
3096 /* Don't use XtGetGC, not read only */
3097 maskGC = XCreateGC(xDisplay, *mask,
3098 GCForeground | GCBackground, &values);
3099 XCopyPlane(xDisplay, temp, *mask, maskGC,
3100 0, 0, squareSize, squareSize, 0, 0, 1);
3101 XFreePixmap(xDisplay, temp);
3106 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3108 void CreateXIMPieces()
3113 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3118 /* The XSynchronize calls were copied from CreatePieces.
3119 Not sure if needed, but can't hurt */
3120 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3123 /* temp needed by loadXIM() */
3124 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3125 0, 0, ss, ss, AllPlanes, XYPixmap);
3127 if (strlen(appData.pixmapDirectory) == 0) {
3131 if (appData.monoMode) {
3132 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3136 fprintf(stderr, _("\nLoading XIMs...\n"));
3138 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3139 fprintf(stderr, "%d", piece+1);
3140 for (kind=0; kind<4; kind++) {
3141 fprintf(stderr, ".");
3142 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3143 ExpandPathName(appData.pixmapDirectory),
3144 piece <= (int) WhiteKing ? "" : "w",
3145 pieceBitmapNames[piece],
3147 ximPieceBitmap[kind][piece] =
3148 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3149 0, 0, ss, ss, AllPlanes, XYPixmap);
3150 if (appData.debugMode)
3151 fprintf(stderr, _("(File:%s:) "), buf);
3152 loadXIM(ximPieceBitmap[kind][piece],
3154 &(xpmPieceBitmap2[kind][piece]),
3155 &(ximMaskPm2[piece]));
3156 if(piece <= (int)WhiteKing)
3157 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3159 fprintf(stderr," ");
3161 /* Load light and dark squares */
3162 /* If the LSQ and DSQ pieces don't exist, we will
3163 draw them with solid squares. */
3164 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3165 if (access(buf, 0) != 0) {
3169 fprintf(stderr, _("light square "));
3171 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3172 0, 0, ss, ss, AllPlanes, XYPixmap);
3173 if (appData.debugMode)
3174 fprintf(stderr, _("(File:%s:) "), buf);
3176 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3177 fprintf(stderr, _("dark square "));
3178 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3179 ExpandPathName(appData.pixmapDirectory), ss);
3180 if (appData.debugMode)
3181 fprintf(stderr, _("(File:%s:) "), buf);
3183 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3184 0, 0, ss, ss, AllPlanes, XYPixmap);
3185 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3186 xpmJailSquare = xpmLightSquare;
3188 fprintf(stderr, _("Done.\n"));
3190 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3194 void CreateXPMPieces()
3198 u_int ss = squareSize;
3200 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3201 XpmColorSymbol symbols[4];
3203 /* The XSynchronize calls were copied from CreatePieces.
3204 Not sure if needed, but can't hurt */
3205 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3207 /* Setup translations so piece colors match square colors */
3208 symbols[0].name = "light_piece";
3209 symbols[0].value = appData.whitePieceColor;
3210 symbols[1].name = "dark_piece";
3211 symbols[1].value = appData.blackPieceColor;
3212 symbols[2].name = "light_square";
3213 symbols[2].value = appData.lightSquareColor;
3214 symbols[3].name = "dark_square";
3215 symbols[3].value = appData.darkSquareColor;
3217 attr.valuemask = XpmColorSymbols;
3218 attr.colorsymbols = symbols;
3219 attr.numsymbols = 4;
3221 if (appData.monoMode) {
3222 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3226 if (strlen(appData.pixmapDirectory) == 0) {
3227 XpmPieces* pieces = builtInXpms;
3230 while (pieces->size != squareSize && pieces->size) pieces++;
3231 if (!pieces->size) {
3232 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3235 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3236 for (kind=0; kind<4; kind++) {
3238 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3239 pieces->xpm[piece][kind],
3240 &(xpmPieceBitmap2[kind][piece]),
3241 NULL, &attr)) != 0) {
3242 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3246 if(piece <= (int) WhiteKing)
3247 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3251 xpmJailSquare = xpmLightSquare;
3255 fprintf(stderr, _("\nLoading XPMs...\n"));
3258 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3259 fprintf(stderr, "%d ", piece+1);
3260 for (kind=0; kind<4; kind++) {
3261 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3262 ExpandPathName(appData.pixmapDirectory),
3263 piece > (int) WhiteKing ? "w" : "",
3264 pieceBitmapNames[piece],
3266 if (appData.debugMode) {
3267 fprintf(stderr, _("(File:%s:) "), buf);
3269 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3270 &(xpmPieceBitmap2[kind][piece]),
3271 NULL, &attr)) != 0) {
3272 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3273 // [HGM] missing: read of unorthodox piece failed; substitute King.
3274 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3275 ExpandPathName(appData.pixmapDirectory),
3277 if (appData.debugMode) {
3278 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3280 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3281 &(xpmPieceBitmap2[kind][piece]),
3285 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3290 if(piece <= (int) WhiteKing)
3291 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3294 /* Load light and dark squares */
3295 /* If the LSQ and DSQ pieces don't exist, we will
3296 draw them with solid squares. */
3297 fprintf(stderr, _("light square "));
3298 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3299 if (access(buf, 0) != 0) {
3303 if (appData.debugMode)
3304 fprintf(stderr, _("(File:%s:) "), buf);
3306 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3307 &xpmLightSquare, NULL, &attr)) != 0) {
3308 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3311 fprintf(stderr, _("dark square "));
3312 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3313 ExpandPathName(appData.pixmapDirectory), ss);
3314 if (appData.debugMode) {
3315 fprintf(stderr, _("(File:%s:) "), buf);
3317 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3318 &xpmDarkSquare, NULL, &attr)) != 0) {
3319 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3323 xpmJailSquare = xpmLightSquare;
3324 fprintf(stderr, _("Done.\n"));
3326 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3329 #endif /* HAVE_LIBXPM */
3332 /* No built-in bitmaps */
3337 u_int ss = squareSize;
3339 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3342 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3343 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3344 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3345 pieceBitmapNames[piece],
3346 ss, kind == SOLID ? 's' : 'o');
3347 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3348 if(piece <= (int)WhiteKing)
3349 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3353 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3357 /* With built-in bitmaps */
3360 BuiltInBits* bib = builtInBits;
3363 u_int ss = squareSize;
3365 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3368 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3370 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3371 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3372 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3373 pieceBitmapNames[piece],
3374 ss, kind == SOLID ? 's' : 'o');
3375 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3376 bib->bits[kind][piece], ss, ss);
3377 if(piece <= (int)WhiteKing)
3378 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3382 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3387 void ReadBitmap(pm, name, bits, wreq, hreq)
3390 unsigned char bits[];
3396 char msg[MSG_SIZ], fullname[MSG_SIZ];
3398 if (*appData.bitmapDirectory != NULLCHAR) {
3399 strcpy(fullname, appData.bitmapDirectory);
3400 strcat(fullname, "/");
3401 strcat(fullname, name);
3402 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3403 &w, &h, pm, &x_hot, &y_hot);
3404 fprintf(stderr, "load %s\n", name);
3405 if (errcode != BitmapSuccess) {
3407 case BitmapOpenFailed:
3408 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3410 case BitmapFileInvalid:
3411 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3413 case BitmapNoMemory:
3414 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3418 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3422 fprintf(stderr, _("%s: %s...using built-in\n"),
3424 } else if (w != wreq || h != hreq) {
3426 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3427 programName, fullname, w, h, wreq, hreq);
3433 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3442 if (lineGap == 0) return;
3444 /* [HR] Split this into 2 loops for non-square boards. */
3446 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3447 gridSegments[i].x1 = 0;
3448 gridSegments[i].x2 =
3449 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3450 gridSegments[i].y1 = gridSegments[i].y2
3451 = lineGap / 2 + (i * (squareSize + lineGap));
3454 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3455 gridSegments[j + i].y1 = 0;
3456 gridSegments[j + i].y2 =
3457 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3458 gridSegments[j + i].x1 = gridSegments[j + i].x2
3459 = lineGap / 2 + (j * (squareSize + lineGap));
3463 static void MenuBarSelect(w, addr, index)
3468 XtActionProc proc = (XtActionProc) addr;
3470 (proc)(NULL, NULL, NULL, NULL);
3473 void CreateMenuBarPopup(parent, name, mb)
3483 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3486 XtSetArg(args[j], XtNleftMargin, 20); j++;
3487 XtSetArg(args[j], XtNrightMargin, 20); j++;
3489 while (mi->string != NULL) {
3490 if (strcmp(mi->string, "----") == 0) {
3491 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3494 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3495 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3497 XtAddCallback(entry, XtNcallback,
3498 (XtCallbackProc) MenuBarSelect,
3499 (caddr_t) mi->proc);
3505 Widget CreateMenuBar(mb)
3509 Widget anchor, menuBar;
3511 char menuName[MSG_SIZ];
3514 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3515 XtSetArg(args[j], XtNvSpace, 0); j++;
3516 XtSetArg(args[j], XtNborderWidth, 0); j++;
3517 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3518 formWidget, args, j);
3520 while (mb->name != NULL) {
3521 strcpy(menuName, "menu");
3522 strcat(menuName, mb->name);
3524 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3527 shortName[0] = _(mb->name)[0];
3528 shortName[1] = NULLCHAR;
3529 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3532 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3535 XtSetArg(args[j], XtNborderWidth, 0); j++;
3536 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3538 CreateMenuBarPopup(menuBar, menuName, mb);
3544 Widget CreateButtonBar(mi)
3548 Widget button, buttonBar;
3552 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3554 XtSetArg(args[j], XtNhSpace, 0); j++;
3556 XtSetArg(args[j], XtNborderWidth, 0); j++;
3557 XtSetArg(args[j], XtNvSpace, 0); j++;
3558 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3559 formWidget, args, j);
3561 while (mi->string != NULL) {
3564 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3565 XtSetArg(args[j], XtNborderWidth, 0); j++;
3567 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3568 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3569 buttonBar, args, j);
3570 XtAddCallback(button, XtNcallback,
3571 (XtCallbackProc) MenuBarSelect,
3572 (caddr_t) mi->proc);
3579 CreatePieceMenu(name, color)
3586 ChessSquare selection;
3588 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3589 boardWidget, args, 0);
3591 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3592 String item = pieceMenuStrings[color][i];
3594 if (strcmp(item, "----") == 0) {
3595 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3598 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3599 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3601 selection = pieceMenuTranslation[color][i];
3602 XtAddCallback(entry, XtNcallback,
3603 (XtCallbackProc) PieceMenuSelect,
3604 (caddr_t) selection);
3605 if (selection == WhitePawn || selection == BlackPawn) {
3606 XtSetArg(args[0], XtNpopupOnEntry, entry);
3607 XtSetValues(menu, args, 1);
3620 ChessSquare selection;
3622 whitePieceMenu = CreatePieceMenu("menuW", 0);
3623 blackPieceMenu = CreatePieceMenu("menuB", 1);
3625 XtRegisterGrabAction(PieceMenuPopup, True,
3626 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3627 GrabModeAsync, GrabModeAsync);
3629 XtSetArg(args[0], XtNlabel, _("Drop"));
3630 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3631 boardWidget, args, 1);
3632 for (i = 0; i < DROP_MENU_SIZE; i++) {
3633 String item = dropMenuStrings[i];
3635 if (strcmp(item, "----") == 0) {
3636 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3639 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3640 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3642 selection = dropMenuTranslation[i];
3643 XtAddCallback(entry, XtNcallback,
3644 (XtCallbackProc) DropMenuSelect,
3645 (caddr_t) selection);
3650 void SetupDropMenu()
3658 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3659 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3660 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3661 dmEnables[i].piece);
3662 XtSetSensitive(entry, p != NULL || !appData.testLegality
3663 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3664 && !appData.icsActive));
3666 while (p && *p++ == dmEnables[i].piece) count++;
3667 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3669 XtSetArg(args[j], XtNlabel, label); j++;
3670 XtSetValues(entry, args, j);
3674 void PieceMenuPopup(w, event, params, num_params)
3678 Cardinal *num_params;
3682 if (event->type != ButtonRelease) UnLoadPV(); // [HGM] pv
3683 if (event->type != ButtonPress) return;
3684 if (errorUp) ErrorPopDown();
3688 whichMenu = params[0];
3691 if(!appData.icsEngineAnalyze) return;
3692 case IcsPlayingWhite:
3693 case IcsPlayingBlack:
3694 if(!appData.zippyPlay) goto noZip;
3697 case MachinePlaysWhite:
3698 case MachinePlaysBlack:
3699 case TwoMachinesPlay: // [HGM] pv: use for showing PV
3700 if (!appData.dropMenu) {
3701 LoadPV(event->xbutton.x, event->xbutton.y);
3704 if(gameMode == TwoMachinesPlay || gameMode == AnalyzeMode ||
3705 gameMode == AnalyzeFile || gameMode == IcsObserving) return;
3708 if (!appData.dropMenu || appData.testLegality &&
3709 gameInfo.variant != VariantBughouse &&
3710 gameInfo.variant != VariantCrazyhouse) return;
3712 whichMenu = "menuD";
3718 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3719 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3720 pmFromX = pmFromY = -1;
3724 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3726 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3728 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3731 static void PieceMenuSelect(w, piece, junk)
3736 if (pmFromX < 0 || pmFromY < 0) return;
3737 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3740 static void DropMenuSelect(w, piece, junk)
3745 if (pmFromX < 0 || pmFromY < 0) return;
3746 DropMenuEvent(piece, pmFromX, pmFromY);
3749 void WhiteClock(w, event, prms, nprms)
3755 if (gameMode == EditPosition || gameMode == IcsExamining) {
3756 SetWhiteToPlayEvent();
3757 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3762 void BlackClock(w, event, prms, nprms)
3768 if (gameMode == EditPosition || gameMode == IcsExamining) {
3769 SetBlackToPlayEvent();
3770 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3777 * If the user selects on a border boundary, return -1; if off the board,
3778 * return -2. Otherwise map the event coordinate to the square.
3780 int EventToSquare(x, limit)
3788 if ((x % (squareSize + lineGap)) >= squareSize)
3790 x /= (squareSize + lineGap);
3796 static void do_flash_delay(msec)
3802 static void drawHighlight(file, rank, gc)
3808 if (lineGap == 0 || appData.blindfold) return;
3811 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3812 (squareSize + lineGap);
3813 y = lineGap/2 + rank * (squareSize + lineGap);
3815 x = lineGap/2 + file * (squareSize + lineGap);
3816 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3817 (squareSize + lineGap);
3820 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3821 squareSize+lineGap, squareSize+lineGap);
3824 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3825 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3828 SetHighlights(fromX, fromY, toX, toY)
3829 int fromX, fromY, toX, toY;
3831 if (hi1X != fromX || hi1Y != fromY) {
3832 if (hi1X >= 0 && hi1Y >= 0) {
3833 drawHighlight(hi1X, hi1Y, lineGC);
3835 if (fromX >= 0 && fromY >= 0) {
3836 drawHighlight(fromX, fromY, highlineGC);
3839 if (hi2X != toX || hi2Y != toY) {
3840 if (hi2X >= 0 && hi2Y >= 0) {
3841 drawHighlight(hi2X, hi2Y, lineGC);
3843 if (toX >= 0 && toY >= 0) {
3844 drawHighlight(toX, toY, highlineGC);
3856 SetHighlights(-1, -1, -1, -1);
3861 SetPremoveHighlights(fromX, fromY, toX, toY)
3862 int fromX, fromY, toX, toY;
3864 if (pm1X != fromX || pm1Y != fromY) {
3865 if (pm1X >= 0 && pm1Y >= 0) {
3866 drawHighlight(pm1X, pm1Y, lineGC);
3868 if (fromX >= 0 && fromY >= 0) {
3869 drawHighlight(fromX, fromY, prelineGC);
3872 if (pm2X != toX || pm2Y != toY) {
3873 if (pm2X >= 0 && pm2Y >= 0) {
3874 drawHighlight(pm2X, pm2Y, lineGC);
3876 if (toX >= 0 && toY >= 0) {
3877 drawHighlight(toX, toY, prelineGC);
3887 ClearPremoveHighlights()
3889 SetPremoveHighlights(-1, -1, -1, -1);
3892 static void BlankSquare(x, y, color, piece, dest)
3897 if (useImages && useImageSqs) {
3901 pm = xpmLightSquare;
3906 case 2: /* neutral */
3911 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3912 squareSize, squareSize, x, y);
3922 case 2: /* neutral */
3927 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3932 I split out the routines to draw a piece so that I could
3933 make a generic flash routine.
3935 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3937 int square_color, x, y;
3940 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3941 switch (square_color) {
3943 case 2: /* neutral */
3945 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3946 ? *pieceToOutline(piece)
3947 : *pieceToSolid(piece),
3948 dest, bwPieceGC, 0, 0,
3949 squareSize, squareSize, x, y);
3952 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3953 ? *pieceToSolid(piece)
3954 : *pieceToOutline(piece),
3955 dest, wbPieceGC, 0, 0,
3956 squareSize, squareSize, x, y);
3961 static void monoDrawPiece(piece, square_color, x, y, dest)
3963 int square_color, x, y;
3966 switch (square_color) {
3968 case 2: /* neutral */
3970 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3971 ? *pieceToOutline(piece)
3972 : *pieceToSolid(piece),
3973 dest, bwPieceGC, 0, 0,
3974 squareSize, squareSize, x, y, 1);
3977 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3978 ? *pieceToSolid(piece)
3979 : *pieceToOutline(piece),
3980 dest, wbPieceGC, 0, 0,
3981 squareSize, squareSize, x, y, 1);
3986 static void colorDrawPiece(piece, square_color, x, y, dest)
3988 int square_color, x, y;
3991 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3992 switch (square_color) {
3994 XCopyPlane(xDisplay, *pieceToSolid(piece),
3995 dest, (int) piece < (int) BlackPawn
3996 ? wlPieceGC : blPieceGC, 0, 0,
3997 squareSize, squareSize, x, y, 1);
4000 XCopyPlane(xDisplay, *pieceToSolid(piece),
4001 dest, (int) piece < (int) BlackPawn
4002 ? wdPieceGC : bdPieceGC, 0, 0,
4003 squareSize, squareSize, x, y, 1);
4005 case 2: /* neutral */
4007 XCopyPlane(xDisplay, *pieceToSolid(piece),
4008 dest, (int) piece < (int) BlackPawn
4009 ? wjPieceGC : bjPieceGC, 0, 0,
4010 squareSize, squareSize, x, y, 1);
4015 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4017 int square_color, x, y;
4022 switch (square_color) {
4024 case 2: /* neutral */
4026 if ((int)piece < (int) BlackPawn) {
4034 if ((int)piece < (int) BlackPawn) {
4042 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4043 dest, wlPieceGC, 0, 0,
4044 squareSize, squareSize, x, y);
4047 typedef void (*DrawFunc)();
4049 DrawFunc ChooseDrawFunc()
4051 if (appData.monoMode) {
4052 if (DefaultDepth(xDisplay, xScreen) == 1) {
4053 return monoDrawPiece_1bit;
4055 return monoDrawPiece;
4059 return colorDrawPieceImage;
4061 return colorDrawPiece;
4065 /* [HR] determine square color depending on chess variant. */
4066 static int SquareColor(row, column)
4071 if (gameInfo.variant == VariantXiangqi) {
4072 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4074 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4076 } else if (row <= 4) {
4082 square_color = ((column + row) % 2) == 1;
4085 /* [hgm] holdings: next line makes all holdings squares light */
4086 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4088 return square_color;
4091 void DrawSquare(row, column, piece, do_flash)
4092 int row, column, do_flash;
4095 int square_color, x, y, direction, font_ascent, font_descent;
4098 XCharStruct overall;
4102 /* Calculate delay in milliseconds (2-delays per complete flash) */
4103 flash_delay = 500 / appData.flashRate;
4106 x = lineGap + ((BOARD_WIDTH-1)-column) *
4107 (squareSize + lineGap);
4108 y = lineGap + row * (squareSize + lineGap);
4110 x = lineGap + column * (squareSize + lineGap);
4111 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4112 (squareSize + lineGap);
4115 square_color = SquareColor(row, column);
4117 if ( // [HGM] holdings: blank out area between board and holdings
4118 column == BOARD_LEFT-1 || column == BOARD_RGHT
4119 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4120 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4121 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4123 // [HGM] print piece counts next to holdings
4124 string[1] = NULLCHAR;
4125 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4126 string[0] = '0' + piece;
4127 XTextExtents(countFontStruct, string, 1, &direction,
4128 &font_ascent, &font_descent, &overall);
4129 if (appData.monoMode) {
4130 XDrawImageString(xDisplay, xBoardWindow, countGC,
4131 x + squareSize - overall.width - 2,
4132 y + font_ascent + 1, string, 1);
4134 XDrawString(xDisplay, xBoardWindow, countGC,
4135 x + squareSize - overall.width - 2,
4136 y + font_ascent + 1, string, 1);
4139 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4140 string[0] = '0' + piece;
4141 XTextExtents(countFontStruct, string, 1, &direction,
4142 &font_ascent, &font_descent, &overall);
4143 if (appData.monoMode) {
4144 XDrawImageString(xDisplay, xBoardWindow, countGC,
4145 x + 2, y + font_ascent + 1, string, 1);
4147 XDrawString(xDisplay, xBoardWindow, countGC,
4148 x + 2, y + font_ascent + 1, string, 1);
4152 if (piece == EmptySquare || appData.blindfold) {
4153 BlankSquare(x, y, square_color, piece, xBoardWindow);
4155 drawfunc = ChooseDrawFunc();
4156 if (do_flash && appData.flashCount > 0) {
4157 for (i=0; i<appData.flashCount; ++i) {
4159 drawfunc(piece, square_color, x, y, xBoardWindow);
4160 XSync(xDisplay, False);
4161 do_flash_delay(flash_delay);
4163 BlankSquare(x, y, square_color, piece, xBoardWindow);
4164 XSync(xDisplay, False);
4165 do_flash_delay(flash_delay);
4168 drawfunc(piece, square_color, x, y, xBoardWindow);
4172 string[1] = NULLCHAR;
4173 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4174 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4175 string[0] = 'a' + column - BOARD_LEFT;
4176 XTextExtents(coordFontStruct, string, 1, &direction,
4177 &font_ascent, &font_descent, &overall);
4178 if (appData.monoMode) {
4179 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4180 x + squareSize - overall.width - 2,
4181 y + squareSize - font_descent - 1, string, 1);
4183 XDrawString(xDisplay, xBoardWindow, coordGC,
4184 x + squareSize - overall.width - 2,
4185 y + squareSize - font_descent - 1, string, 1);
4188 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4189 string[0] = ONE + row;
4190 XTextExtents(coordFontStruct, string, 1, &direction,
4191 &font_ascent, &font_descent, &overall);
4192 if (appData.monoMode) {
4193 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4194 x + 2, y + font_ascent + 1, string, 1);
4196 XDrawString(xDisplay, xBoardWindow, coordGC,
4197 x + 2, y + font_ascent + 1, string, 1);
4203 /* Why is this needed on some versions of X? */
4204 void EventProc(widget, unused, event)
4209 if (!XtIsRealized(widget))
4212 switch (event->type) {
4214 if (event->xexpose.count > 0) return; /* no clipping is done */
4215 XDrawPosition(widget, True, NULL);
4223 void DrawPosition(fullRedraw, board)
4224 /*Boolean*/int fullRedraw;
4227 XDrawPosition(boardWidget, fullRedraw, board);
4230 /* Returns 1 if there are "too many" differences between b1 and b2
4231 (i.e. more than 1 move was made) */
4232 static int too_many_diffs(b1, b2)
4238 for (i=0; i<BOARD_HEIGHT; ++i) {
4239 for (j=0; j<BOARD_WIDTH; ++j) {
4240 if (b1[i][j] != b2[i][j]) {
4241 if (++c > 4) /* Castling causes 4 diffs */
4250 /* Matrix describing castling maneuvers */
4251 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4252 static int castling_matrix[4][5] = {
4253 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4254 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4255 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4256 { 7, 7, 4, 5, 6 } /* 0-0, black */
4259 /* Checks whether castling occurred. If it did, *rrow and *rcol
4260 are set to the destination (row,col) of the rook that moved.
4262 Returns 1 if castling occurred, 0 if not.
4264 Note: Only handles a max of 1 castling move, so be sure
4265 to call too_many_diffs() first.
4267 static int check_castle_draw(newb, oldb, rrow, rcol)
4274 /* For each type of castling... */
4275 for (i=0; i<4; ++i) {
4276 r = castling_matrix[i];
4278 /* Check the 4 squares involved in the castling move */
4280 for (j=1; j<=4; ++j) {
4281 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4288 /* All 4 changed, so it must be a castling move */
4297 static int damage[BOARD_RANKS][BOARD_FILES];
4300 * event handler for redrawing the board
4302 void XDrawPosition(w, repaint, board)
4304 /*Boolean*/int repaint;
4308 static int lastFlipView = 0;
4309 static int lastBoardValid = 0;
4310 static Board lastBoard;
4314 if (board == NULL) {
4315 if (!lastBoardValid) return;
4318 if (!lastBoardValid || lastFlipView != flipView) {
4319 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4320 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4325 * It would be simpler to clear the window with XClearWindow()
4326 * but this causes a very distracting flicker.
4329 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4331 /* If too much changes (begin observing new game, etc.), don't
4333 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4335 /* Special check for castling so we don't flash both the king
4336 and the rook (just flash the king). */
4338 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4339 /* Draw rook with NO flashing. King will be drawn flashing later */
4340 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4341 lastBoard[rrow][rcol] = board[rrow][rcol];
4345 /* First pass -- Draw (newly) empty squares and repair damage.
4346 This prevents you from having a piece show up twice while it
4347 is flashing on its new square */
4348 for (i = 0; i < BOARD_HEIGHT; i++)
4349 for (j = 0; j < BOARD_WIDTH; j++)
4350 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4352 DrawSquare(i, j, board[i][j], 0);
4353 damage[i][j] = False;
4356 /* Second pass -- Draw piece(s) in new position and flash them */
4357 for (i = 0; i < BOARD_HEIGHT; i++)
4358 for (j = 0; j < BOARD_WIDTH; j++)
4359 if (board[i][j] != lastBoard[i][j]) {
4360 DrawSquare(i, j, board[i][j], do_flash);
4364 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4365 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4367 for (i = 0; i < BOARD_HEIGHT; i++)
4368 for (j = 0; j < BOARD_WIDTH; j++) {
4369 DrawSquare(i, j, board[i][j], 0);
4370 damage[i][j] = False;
4374 CopyBoard(lastBoard, board);
4376 lastFlipView = flipView;
4378 /* Draw highlights */
4379 if (pm1X >= 0 && pm1Y >= 0) {
4380 drawHighlight(pm1X, pm1Y, prelineGC);
4382 if (pm2X >= 0 && pm2Y >= 0) {
4383 drawHighlight(pm2X, pm2Y, prelineGC);
4385 if (hi1X >= 0 && hi1Y >= 0) {
4386 drawHighlight(hi1X, hi1Y, highlineGC);
4388 if (hi2X >= 0 && hi2Y >= 0) {
4389 drawHighlight(hi2X, hi2Y, highlineGC);
4392 /* If piece being dragged around board, must redraw that too */
4395 XSync(xDisplay, False);
4400 * event handler for redrawing the board
4402 void DrawPositionProc(w, event, prms, nprms)
4408 XDrawPosition(w, True, NULL);
4413 * event handler for parsing user moves
4415 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4416 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4417 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4418 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4419 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4420 // and at the end FinishMove() to perform the move after optional promotion popups.
4421 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4422 void HandleUserMove(w, event, prms, nprms)
4428 if (w != boardWidget || errorExitStatus != -1) return;
4431 if (event->type == ButtonPress) {
4432 XtPopdown(promotionShell);
4433 XtDestroyWidget(promotionShell);
4434 promotionUp = False;
4442 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4443 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4444 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4447 void AnimateUserMove (Widget w, XEvent * event,
4448 String * params, Cardinal * nParams)
4450 DragPieceMove(event->xmotion.x, event->xmotion.y);
4453 void HandlePV (Widget w, XEvent * event,
4454 String * params, Cardinal * nParams)
4455 { // [HGM] pv: walk PV
4456 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
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 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()