2 * xboard.c -- X front end for XBoard
4 * Copyright 1991 by Digital Equipment Corporation, Maynard,
7 * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8 * 2007, 2008, 2009 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
58 #include <sys/types.h>
63 # if HAVE_SYS_SOCKET_H
64 # include <sys/socket.h>
65 # include <netinet/in.h>
67 # else /* not HAVE_SYS_SOCKET_H */
68 # if HAVE_LAN_SOCKET_H
69 # include <lan/socket.h>
71 # include <lan/netdb.h>
72 # else /* not HAVE_LAN_SOCKET_H */
73 # define OMIT_SOCKETS 1
74 # endif /* not HAVE_LAN_SOCKET_H */
75 # endif /* not HAVE_SYS_SOCKET_H */
76 #endif /* !OMIT_SOCKETS */
81 #else /* not STDC_HEADERS */
82 extern char *getenv();
85 # else /* not HAVE_STRING_H */
87 # endif /* not HAVE_STRING_H */
88 #endif /* not STDC_HEADERS */
91 # include <sys/fcntl.h>
92 #else /* not HAVE_SYS_FCNTL_H */
95 # endif /* HAVE_FCNTL_H */
96 #endif /* not HAVE_SYS_FCNTL_H */
98 #if HAVE_SYS_SYSTEMINFO_H
99 # include <sys/systeminfo.h>
100 #endif /* HAVE_SYS_SYSTEMINFO_H */
102 #if TIME_WITH_SYS_TIME
103 # include <sys/time.h>
107 # include <sys/time.h>
118 # include <sys/wait.h>
123 # define NAMLEN(dirent) strlen((dirent)->d_name)
124 # define HAVE_DIR_STRUCT
126 # define dirent direct
127 # define NAMLEN(dirent) (dirent)->d_namlen
129 # include <sys/ndir.h>
130 # define HAVE_DIR_STRUCT
133 # include <sys/dir.h>
134 # define HAVE_DIR_STRUCT
138 # define HAVE_DIR_STRUCT
142 #include <X11/Intrinsic.h>
143 #include <X11/StringDefs.h>
144 #include <X11/Shell.h>
145 #include <X11/cursorfont.h>
146 #include <X11/Xatom.h>
147 #include <X11/Xmu/Atoms.h>
149 #include <X11/Xaw3d/Dialog.h>
150 #include <X11/Xaw3d/Form.h>
151 #include <X11/Xaw3d/List.h>
152 #include <X11/Xaw3d/Label.h>
153 #include <X11/Xaw3d/SimpleMenu.h>
154 #include <X11/Xaw3d/SmeBSB.h>
155 #include <X11/Xaw3d/SmeLine.h>
156 #include <X11/Xaw3d/Box.h>
157 #include <X11/Xaw3d/MenuButton.h>
158 #include <X11/Xaw3d/Text.h>
159 #include <X11/Xaw3d/AsciiText.h>
161 #include <X11/Xaw/Dialog.h>
162 #include <X11/Xaw/Form.h>
163 #include <X11/Xaw/List.h>
164 #include <X11/Xaw/Label.h>
165 #include <X11/Xaw/SimpleMenu.h>
166 #include <X11/Xaw/SmeBSB.h>
167 #include <X11/Xaw/SmeLine.h>
168 #include <X11/Xaw/Box.h>
169 #include <X11/Xaw/MenuButton.h>
170 #include <X11/Xaw/Text.h>
171 #include <X11/Xaw/AsciiText.h>
174 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
179 #include "pixmaps/pixmaps.h"
180 #define IMAGE_EXT "xpm"
182 #define IMAGE_EXT "xim"
183 #include "bitmaps/bitmaps.h"
186 #include "bitmaps/icon_white.bm"
187 #include "bitmaps/icon_black.bm"
188 #include "bitmaps/checkmark.bm"
190 #include "frontend.h"
195 #include "xgamelist.h"
196 #include "xhistory.h"
197 #include "xedittags.h"
200 // must be moved to xengineoutput.h
202 void EngineOutputProc P((Widget w, XEvent *event,
203 String *prms, Cardinal *nprms));
204 void EvalGraphProc P((Widget w, XEvent *event,
205 String *prms, Cardinal *nprms));
212 #define usleep(t) _sleep2(((t)+500)/1000)
216 # define _(s) gettext (s)
217 # define N_(s) gettext_noop (s)
233 int main P((int argc, char **argv));
234 RETSIGTYPE CmailSigHandler P((int sig));
235 RETSIGTYPE IntSigHandler P((int sig));
236 RETSIGTYPE TermSizeSigHandler P((int sig));
237 void CreateGCs P((void));
238 void CreateXIMPieces P((void));
239 void CreateXPMPieces P((void));
240 void CreatePieces P((void));
241 void CreatePieceMenus P((void));
242 Widget CreateMenuBar P((Menu *mb));
243 Widget CreateButtonBar P ((MenuItem *mi));
244 char *FindFont P((char *pattern, int targetPxlSize));
245 void PieceMenuPopup P((Widget w, XEvent *event,
246 String *params, Cardinal *num_params));
247 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
248 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
249 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
250 u_int wreq, u_int hreq));
251 void CreateGrid P((void));
252 int EventToSquare P((int x, int limit));
253 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
254 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
255 void HandleUserMove P((Widget w, XEvent *event,
256 String *prms, Cardinal *nprms));
257 void AnimateUserMove P((Widget w, XEvent * event,
258 String * params, Cardinal * nParams));
259 void WhiteClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void BlackClock P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void DrawPositionProc P((Widget w, XEvent *event,
264 String *prms, Cardinal *nprms));
265 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
267 void CommentPopUp P((char *title, char *label));
268 void CommentPopDown P((void));
269 void CommentCallback P((Widget w, XtPointer client_data,
270 XtPointer call_data));
271 void ICSInputBoxPopUp P((void));
272 void ICSInputBoxPopDown P((void));
273 void FileNamePopUp P((char *label, char *def,
274 FileProc proc, char *openMode));
275 void FileNamePopDown P((void));
276 void FileNameCallback P((Widget w, XtPointer client_data,
277 XtPointer call_data));
278 void FileNameAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionReplyAction P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionProc P((Widget w, XEvent *event,
283 String *prms, Cardinal *nprms));
284 void AskQuestionPopDown P((void));
285 void PromotionPopDown P((void));
286 void PromotionCallback P((Widget w, XtPointer client_data,
287 XtPointer call_data));
288 void EditCommentPopDown P((void));
289 void EditCommentCallback P((Widget w, XtPointer client_data,
290 XtPointer call_data));
291 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
292 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
293 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
294 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
296 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
298 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
300 void LoadPositionProc P((Widget w, XEvent *event,
301 String *prms, Cardinal *nprms));
302 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
304 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
306 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
308 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
310 void PastePositionProc P((Widget w, XEvent *event, String *prms,
312 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
314 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
315 void SavePositionProc P((Widget w, XEvent *event,
316 String *prms, Cardinal *nprms));
317 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
320 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
321 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
322 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
324 void MachineWhiteProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeModeProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void AnalyzeFileProc P((Widget w, XEvent *event,
329 String *prms, Cardinal *nprms));
330 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
332 void IcsClientProc P((Widget w, XEvent *event, String *prms,
334 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
335 void EditPositionProc P((Widget w, XEvent *event,
336 String *prms, Cardinal *nprms));
337 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void EditCommentProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void IcsInputBoxProc P((Widget w, XEvent *event,
341 String *prms, Cardinal *nprms));
342 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
353 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void StopObservingProc P((Widget w, XEvent *event, String *prms,
356 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
358 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
365 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
367 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
370 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
372 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
374 void AutocommProc P((Widget w, XEvent *event, String *prms,
376 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AutobsProc P((Widget w, XEvent *event, String *prms,
380 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
385 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
388 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
390 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
392 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
396 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
398 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
400 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
402 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
404 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
408 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
410 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
412 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
414 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void DisplayMove P((int moveNumber));
426 void DisplayTitle P((char *title));
427 void ICSInitScript P((void));
428 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
429 void ErrorPopUp P((char *title, char *text, int modal));
430 void ErrorPopDown P((void));
431 static char *ExpandPathName P((char *path));
432 static void CreateAnimVars P((void));
433 static void DragPieceMove P((int x, int y));
434 static void DrawDragPiece P((void));
435 char *ModeToWidgetName P((GameMode mode));
436 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ShufflePopDown P(());
444 void EnginePopDown P(());
445 void UciPopDown P(());
446 void TimeControlPopDown P(());
447 void NewVariantPopDown P(());
448 void SettingsPopDown P(());
449 void update_ics_width P(());
450 int get_term_width P(());
452 * XBoard depends on Xt R4 or higher
454 int xtVersion = XtSpecificationRelease;
459 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
460 jailSquareColor, highlightSquareColor, premoveHighlightColor;
461 Pixel lowTimeWarningColor;
462 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
463 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
464 wjPieceGC, bjPieceGC, prelineGC, countGC;
465 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
466 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
467 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
468 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
469 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
470 ICSInputShell, fileNameShell, askQuestionShell;
471 Widget historyShell, evalGraphShell, gameListShell;
472 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
473 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
474 Font clockFontID, coordFontID, countFontID;
475 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
476 XtAppContext appContext;
478 char *oldICSInteractionTitle;
482 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
484 Position commentX = -1, commentY = -1;
485 Dimension commentW, commentH;
486 typedef unsigned int BoardSize;
488 Boolean chessProgram;
490 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
491 int squareSize, smallLayout = 0, tinyLayout = 0,
492 marginW, marginH, // [HGM] for run-time resizing
493 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
494 ICSInputBoxUp = False, askQuestionUp = False,
495 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
496 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
497 Pixel timerForegroundPixel, timerBackgroundPixel;
498 Pixel buttonForegroundPixel, buttonBackgroundPixel;
499 char *chessDir, *programName, *programVersion,
500 *gameCopyFilename, *gamePasteFilename;
501 Boolean alwaysOnTop = False;
502 Boolean saveSettingsOnExit;
503 char *settingsFileName;
504 char *icsTextMenuString;
506 char *firstChessProgramNames;
507 char *secondChessProgramNames;
509 WindowPlacement wpMain;
510 WindowPlacement wpConsole;
511 WindowPlacement wpComment;
512 WindowPlacement wpMoveHistory;
513 WindowPlacement wpEvalGraph;
514 WindowPlacement wpEngineOutput;
515 WindowPlacement wpGameList;
516 WindowPlacement wpTags;
520 Pixmap pieceBitmap[2][(int)BlackPawn];
521 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
522 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
523 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
524 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
525 int useImages, useImageSqs;
526 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
527 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
528 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
529 XImage *ximLightSquare, *ximDarkSquare;
532 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
533 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
535 #define White(piece) ((int)(piece) < (int)BlackPawn)
537 /* Variables for doing smooth animation. This whole thing
538 would be much easier if the board was double-buffered,
539 but that would require a fairly major rewrite. */
544 GC blitGC, pieceGC, outlineGC;
545 XPoint startSquare, prevFrame, mouseDelta;
549 int startBoardX, startBoardY;
552 /* There can be two pieces being animated at once: a player
553 can begin dragging a piece before the remote opponent has moved. */
555 static AnimState game, player;
557 /* Bitmaps for use as masks when drawing XPM pieces.
558 Need one for each black and white piece. */
559 static Pixmap xpmMask[BlackKing + 1];
561 /* This magic number is the number of intermediate frames used
562 in each half of the animation. For short moves it's reduced
563 by 1. The total number of frames will be factor * 2 + 1. */
566 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
568 MenuItem fileMenu[] = {
569 {N_("New Game"), ResetProc},
570 {N_("New Shuffle Game ..."), ShuffleMenuProc},
571 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
572 {"----", NothingProc},
573 {N_("Load Game"), LoadGameProc},
574 {N_("Load Next Game"), LoadNextGameProc},
575 {N_("Load Previous Game"), LoadPrevGameProc},
576 {N_("Reload Same Game"), ReloadGameProc},
577 {N_("Save Game"), SaveGameProc},
578 {"----", NothingProc},
579 {N_("Copy Game"), CopyGameProc},
580 {N_("Paste Game"), PasteGameProc},
581 {"----", NothingProc},
582 {N_("Load Position"), LoadPositionProc},
583 {N_("Load Next Position"), LoadNextPositionProc},
584 {N_("Load Previous Position"), LoadPrevPositionProc},
585 {N_("Reload Same Position"), ReloadPositionProc},
586 {N_("Save Position"), SavePositionProc},
587 {"----", NothingProc},
588 {N_("Copy Position"), CopyPositionProc},
589 {N_("Paste Position"), PastePositionProc},
590 {"----", NothingProc},
591 {N_("Mail Move"), MailMoveProc},
592 {N_("Reload CMail Message"), ReloadCmailMsgProc},
593 {"----", NothingProc},
594 {N_("Exit"), QuitProc},
598 MenuItem modeMenu[] = {
599 {N_("Machine White"), MachineWhiteProc},
600 {N_("Machine Black"), MachineBlackProc},
601 {N_("Two Machines"), TwoMachinesProc},
602 {N_("Analysis Mode"), AnalyzeModeProc},
603 {N_("Analyze File"), AnalyzeFileProc },
604 {N_("ICS Client"), IcsClientProc},
605 {N_("Edit Game"), EditGameProc},
606 {N_("Edit Position"), EditPositionProc},
607 {N_("Training"), TrainingProc},
608 {"----", NothingProc},
609 {N_("Show Engine Output"), EngineOutputProc},
610 {N_("Show Evaluation Graph"), EvalGraphProc},
611 {N_("Show Game List"), ShowGameListProc},
612 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
613 {"----", NothingProc},
614 {N_("Edit Tags"), EditTagsProc},
615 {N_("Edit Comment"), EditCommentProc},
616 {N_("ICS Input Box"), IcsInputBoxProc},
617 {N_("Pause"), PauseProc},
621 MenuItem actionMenu[] = {
622 {N_("Accept"), AcceptProc},
623 {N_("Decline"), DeclineProc},
624 {N_("Rematch"), RematchProc},
625 {"----", NothingProc},
626 {N_("Call Flag"), CallFlagProc},
627 {N_("Draw"), DrawProc},
628 {N_("Adjourn"), AdjournProc},
629 {N_("Abort"), AbortProc},
630 {N_("Resign"), ResignProc},
631 {"----", NothingProc},
632 {N_("Stop Observing"), StopObservingProc},
633 {N_("Stop Examining"), StopExaminingProc},
634 {"----", NothingProc},
635 {N_("Adjudicate to White"), AdjuWhiteProc},
636 {N_("Adjudicate to Black"), AdjuBlackProc},
637 {N_("Adjudicate Draw"), AdjuDrawProc},
641 MenuItem stepMenu[] = {
642 {N_("Backward"), BackwardProc},
643 {N_("Forward"), ForwardProc},
644 {N_("Back to Start"), ToStartProc},
645 {N_("Forward to End"), ToEndProc},
646 {N_("Revert"), RevertProc},
647 {N_("Truncate Game"), TruncateGameProc},
648 {"----", NothingProc},
649 {N_("Move Now"), MoveNowProc},
650 {N_("Retract Move"), RetractMoveProc},
654 MenuItem optionsMenu[] = {
655 {N_("Flip View"), FlipViewProc},
656 {"----", NothingProc},
657 {N_("Adjudications ..."), EngineMenuProc},
658 {N_("General Settings ..."), UciMenuProc},
659 {N_("Engine #1 Settings ..."), FirstSettingsProc},
660 {N_("Engine #2 Settings ..."), SecondSettingsProc},
661 {N_("Time Control ..."), TimeControlProc},
662 {"----", NothingProc},
663 {N_("Always Queen"), AlwaysQueenProc},
664 {N_("Animate Dragging"), AnimateDraggingProc},
665 {N_("Animate Moving"), AnimateMovingProc},
666 {N_("Auto Comment"), AutocommProc},
667 {N_("Auto Flag"), AutoflagProc},
668 {N_("Auto Flip View"), AutoflipProc},
669 {N_("Auto Observe"), AutobsProc},
670 {N_("Auto Raise Board"), AutoraiseProc},
671 {N_("Auto Save"), AutosaveProc},
672 {N_("Blindfold"), BlindfoldProc},
673 {N_("Flash Moves"), FlashMovesProc},
674 {N_("Get Move List"), GetMoveListProc},
676 {N_("Highlight Dragging"), HighlightDraggingProc},
678 {N_("Highlight Last Move"), HighlightLastMoveProc},
679 {N_("Move Sound"), MoveSoundProc},
680 {N_("ICS Alarm"), IcsAlarmProc},
681 {N_("Old Save Style"), OldSaveStyleProc},
682 {N_("Periodic Updates"), PeriodicUpdatesProc},
683 {N_("Ponder Next Move"), PonderNextMoveProc},
684 {N_("Popup Exit Message"), PopupExitMessageProc},
685 {N_("Popup Move Errors"), PopupMoveErrorsProc},
686 {N_("Premove"), PremoveProc},
687 {N_("Quiet Play"), QuietPlayProc},
688 {N_("Show Coords"), ShowCoordsProc},
689 {N_("Hide Thinking"), HideThinkingProc},
690 {N_("Test Legality"), TestLegalityProc},
691 {"----", NothingProc},
692 {N_("Save Settings Now"), SaveSettingsProc},
693 {N_("Save Settings on Exit"), SaveOnExitProc},
697 MenuItem helpMenu[] = {
698 {N_("Info XBoard"), InfoProc},
699 {N_("Man XBoard"), ManProc},
700 {"----", NothingProc},
701 {N_("Hint"), HintProc},
702 {N_("Book"), BookProc},
703 {"----", NothingProc},
704 {N_("About XBoard"), AboutProc},
709 {N_("File"), fileMenu},
710 {N_("Mode"), modeMenu},
711 {N_("Action"), actionMenu},
712 {N_("Step"), stepMenu},
713 {N_("Options"), optionsMenu},
714 {N_("Help"), helpMenu},
718 #define PAUSE_BUTTON N_("P")
719 MenuItem buttonBar[] = {
722 {PAUSE_BUTTON, PauseProc},
728 #define PIECE_MENU_SIZE 18
729 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
730 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
731 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
732 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
733 N_("Empty square"), N_("Clear board") },
734 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
735 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
736 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
737 N_("Empty square"), N_("Clear board") }
739 /* must be in same order as PieceMenuStrings! */
740 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
741 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
742 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
743 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
744 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
745 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
746 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
747 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
748 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
751 #define DROP_MENU_SIZE 6
752 String dropMenuStrings[DROP_MENU_SIZE] = {
753 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
755 /* must be in same order as PieceMenuStrings! */
756 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
757 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
758 WhiteRook, WhiteQueen
766 DropMenuEnables dmEnables[] = {
784 { XtNborderWidth, 0 },
785 { XtNdefaultDistance, 0 },
789 { XtNborderWidth, 0 },
790 { XtNresizable, (XtArgVal) True },
794 { XtNborderWidth, 0 },
800 { XtNjustify, (XtArgVal) XtJustifyRight },
801 { XtNlabel, (XtArgVal) "..." },
802 { XtNresizable, (XtArgVal) True },
803 { XtNresize, (XtArgVal) False }
806 Arg messageArgs[] = {
807 { XtNjustify, (XtArgVal) XtJustifyLeft },
808 { XtNlabel, (XtArgVal) "..." },
809 { XtNresizable, (XtArgVal) True },
810 { XtNresize, (XtArgVal) False }
814 { XtNborderWidth, 0 },
815 { XtNjustify, (XtArgVal) XtJustifyLeft }
818 XtResource clientResources[] = {
819 { "flashCount", "flashCount", XtRInt, sizeof(int),
820 XtOffset(AppDataPtr, flashCount), XtRImmediate,
821 (XtPointer) FLASH_COUNT },
824 XrmOptionDescRec shellOptions[] = {
825 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
826 { "-flash", "flashCount", XrmoptionNoArg, "3" },
827 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
830 XtActionsRec boardActions[] = {
831 { "DrawPosition", DrawPositionProc },
832 { "HandleUserMove", HandleUserMove },
833 { "AnimateUserMove", AnimateUserMove },
834 { "FileNameAction", FileNameAction },
835 { "AskQuestionProc", AskQuestionProc },
836 { "AskQuestionReplyAction", AskQuestionReplyAction },
837 { "PieceMenuPopup", PieceMenuPopup },
838 { "WhiteClock", WhiteClock },
839 { "BlackClock", BlackClock },
840 { "Iconify", Iconify },
841 { "ResetProc", ResetProc },
842 { "LoadGameProc", LoadGameProc },
843 { "LoadNextGameProc", LoadNextGameProc },
844 { "LoadPrevGameProc", LoadPrevGameProc },
845 { "LoadSelectedProc", LoadSelectedProc },
846 { "ReloadGameProc", ReloadGameProc },
847 { "LoadPositionProc", LoadPositionProc },
848 { "LoadNextPositionProc", LoadNextPositionProc },
849 { "LoadPrevPositionProc", LoadPrevPositionProc },
850 { "ReloadPositionProc", ReloadPositionProc },
851 { "CopyPositionProc", CopyPositionProc },
852 { "PastePositionProc", PastePositionProc },
853 { "CopyGameProc", CopyGameProc },
854 { "PasteGameProc", PasteGameProc },
855 { "SaveGameProc", SaveGameProc },
856 { "SavePositionProc", SavePositionProc },
857 { "MailMoveProc", MailMoveProc },
858 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
859 { "QuitProc", QuitProc },
860 { "MachineWhiteProc", MachineWhiteProc },
861 { "MachineBlackProc", MachineBlackProc },
862 { "AnalysisModeProc", AnalyzeModeProc },
863 { "AnalyzeFileProc", AnalyzeFileProc },
864 { "TwoMachinesProc", TwoMachinesProc },
865 { "IcsClientProc", IcsClientProc },
866 { "EditGameProc", EditGameProc },
867 { "EditPositionProc", EditPositionProc },
868 { "TrainingProc", EditPositionProc },
869 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
870 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
871 { "ShowGameListProc", ShowGameListProc },
872 { "ShowMoveListProc", HistoryShowProc},
873 { "EditTagsProc", EditCommentProc },
874 { "EditCommentProc", EditCommentProc },
875 { "IcsAlarmProc", IcsAlarmProc },
876 { "IcsInputBoxProc", IcsInputBoxProc },
877 { "PauseProc", PauseProc },
878 { "AcceptProc", AcceptProc },
879 { "DeclineProc", DeclineProc },
880 { "RematchProc", RematchProc },
881 { "CallFlagProc", CallFlagProc },
882 { "DrawProc", DrawProc },
883 { "AdjournProc", AdjournProc },
884 { "AbortProc", AbortProc },
885 { "ResignProc", ResignProc },
886 { "AdjuWhiteProc", AdjuWhiteProc },
887 { "AdjuBlackProc", AdjuBlackProc },
888 { "AdjuDrawProc", AdjuDrawProc },
889 { "EnterKeyProc", EnterKeyProc },
890 { "StopObservingProc", StopObservingProc },
891 { "StopExaminingProc", StopExaminingProc },
892 { "BackwardProc", BackwardProc },
893 { "ForwardProc", ForwardProc },
894 { "ToStartProc", ToStartProc },
895 { "ToEndProc", ToEndProc },
896 { "RevertProc", RevertProc },
897 { "TruncateGameProc", TruncateGameProc },
898 { "MoveNowProc", MoveNowProc },
899 { "RetractMoveProc", RetractMoveProc },
900 { "AlwaysQueenProc", AlwaysQueenProc },
901 { "AnimateDraggingProc", AnimateDraggingProc },
902 { "AnimateMovingProc", AnimateMovingProc },
903 { "AutoflagProc", AutoflagProc },
904 { "AutoflipProc", AutoflipProc },
905 { "AutobsProc", AutobsProc },
906 { "AutoraiseProc", AutoraiseProc },
907 { "AutosaveProc", AutosaveProc },
908 { "BlindfoldProc", BlindfoldProc },
909 { "FlashMovesProc", FlashMovesProc },
910 { "FlipViewProc", FlipViewProc },
911 { "GetMoveListProc", GetMoveListProc },
913 { "HighlightDraggingProc", HighlightDraggingProc },
915 { "HighlightLastMoveProc", HighlightLastMoveProc },
916 { "IcsAlarmProc", IcsAlarmProc },
917 { "MoveSoundProc", MoveSoundProc },
918 { "OldSaveStyleProc", OldSaveStyleProc },
919 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
920 { "PonderNextMoveProc", PonderNextMoveProc },
921 { "PopupExitMessageProc", PopupExitMessageProc },
922 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
923 { "PremoveProc", PremoveProc },
924 { "QuietPlayProc", QuietPlayProc },
925 { "ShowCoordsProc", ShowCoordsProc },
926 { "ShowThinkingProc", ShowThinkingProc },
927 { "HideThinkingProc", HideThinkingProc },
928 { "TestLegalityProc", TestLegalityProc },
929 { "SaveSettingsProc", SaveSettingsProc },
930 { "SaveOnExitProc", SaveOnExitProc },
931 { "InfoProc", InfoProc },
932 { "ManProc", ManProc },
933 { "HintProc", HintProc },
934 { "BookProc", BookProc },
935 { "AboutGameProc", AboutGameProc },
936 { "AboutProc", AboutProc },
937 { "DebugProc", DebugProc },
938 { "NothingProc", NothingProc },
939 { "CommentPopDown", (XtActionProc) CommentPopDown },
940 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
941 { "TagsPopDown", (XtActionProc) TagsPopDown },
942 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
943 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
944 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
945 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
946 { "GameListPopDown", (XtActionProc) GameListPopDown },
947 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
948 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
949 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
950 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
951 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
952 { "EnginePopDown", (XtActionProc) EnginePopDown },
953 { "UciPopDown", (XtActionProc) UciPopDown },
954 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
955 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
956 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
959 char globalTranslations[] =
960 ":<Key>R: ResignProc() \n \
961 :<Key>r: ResetProc() \n \
962 :<Key>g: LoadGameProc() \n \
963 :<Key>N: LoadNextGameProc() \n \
964 :<Key>P: LoadPrevGameProc() \n \
965 :<Key>Q: QuitProc() \n \
966 :<Key>F: ToEndProc() \n \
967 :<Key>f: ForwardProc() \n \
968 :<Key>B: ToStartProc() \n \
969 :<Key>b: BackwardProc() \n \
970 :<Key>p: PauseProc() \n \
971 :<Key>d: DrawProc() \n \
972 :<Key>t: CallFlagProc() \n \
973 :<Key>i: Iconify() \n \
974 :<Key>c: Iconify() \n \
975 :<Key>v: FlipViewProc() \n \
976 <KeyDown>Control_L: BackwardProc() \n \
977 <KeyUp>Control_L: ForwardProc() \n \
978 <KeyDown>Control_R: BackwardProc() \n \
979 <KeyUp>Control_R: ForwardProc() \n \
980 Shift<Key>1: AskQuestionProc(\"Direct command\",\
981 \"Send to chess program:\",,1) \n \
982 Shift<Key>2: AskQuestionProc(\"Direct command\",\
983 \"Send to second chess program:\",,2) \n";
985 char boardTranslations[] =
986 "<Btn1Down>: HandleUserMove() \n \
987 <Btn1Up>: HandleUserMove() \n \
988 <Btn1Motion>: AnimateUserMove() \n \
989 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuB) \n \
991 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuW) \n \
993 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
994 PieceMenuPopup(menuW) \n \
995 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
996 PieceMenuPopup(menuB) \n";
998 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
999 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1001 char ICSInputTranslations[] =
1002 "<Key>Return: EnterKeyProc() \n";
1004 String xboardResources[] = {
1005 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1006 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1007 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1012 /* Max possible square size */
1013 #define MAXSQSIZE 256
1015 static int xpm_avail[MAXSQSIZE];
1017 #ifdef HAVE_DIR_STRUCT
1019 /* Extract piece size from filename */
1021 xpm_getsize(name, len, ext)
1032 if ((p=strchr(name, '.')) == NULL ||
1033 StrCaseCmp(p+1, ext) != 0)
1039 while (*p && isdigit(*p))
1046 /* Setup xpm_avail */
1048 xpm_getavail(dirname, ext)
1056 for (i=0; i<MAXSQSIZE; ++i)
1059 if (appData.debugMode)
1060 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1062 dir = opendir(dirname);
1065 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1066 programName, dirname);
1070 while ((ent=readdir(dir)) != NULL) {
1071 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1072 if (i > 0 && i < MAXSQSIZE)
1082 xpm_print_avail(fp, ext)
1088 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1089 for (i=1; i<MAXSQSIZE; ++i) {
1095 /* Return XPM piecesize closest to size */
1097 xpm_closest_to(dirname, size, ext)
1103 int sm_diff = MAXSQSIZE;
1107 xpm_getavail(dirname, ext);
1109 if (appData.debugMode)
1110 xpm_print_avail(stderr, ext);
1112 for (i=1; i<MAXSQSIZE; ++i) {
1115 diff = (diff<0) ? -diff : diff;
1116 if (diff < sm_diff) {
1124 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1130 #else /* !HAVE_DIR_STRUCT */
1131 /* If we are on a system without a DIR struct, we can't
1132 read the directory, so we can't collect a list of
1133 filenames, etc., so we can't do any size-fitting. */
1135 xpm_closest_to(dirname, size, ext)
1140 fprintf(stderr, _("\
1141 Warning: No DIR structure found on this system --\n\
1142 Unable to autosize for XPM/XIM pieces.\n\
1143 Please report this error to frankm@hiwaay.net.\n\
1144 Include system type & operating system in message.\n"));
1147 #endif /* HAVE_DIR_STRUCT */
1149 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1150 "magenta", "cyan", "white" };
1154 TextColors textColors[(int)NColorClasses];
1156 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1158 parse_color(str, which)
1162 char *p, buf[100], *d;
1165 if (strlen(str) > 99) /* watch bounds on buf */
1170 for (i=0; i<which; ++i) {
1177 /* Could be looking at something like:
1179 .. in which case we want to stop on a comma also */
1180 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1184 return -1; /* Use default for empty field */
1187 if (which == 2 || isdigit(*p))
1190 while (*p && isalpha(*p))
1195 for (i=0; i<8; ++i) {
1196 if (!StrCaseCmp(buf, cnames[i]))
1197 return which? (i+40) : (i+30);
1199 if (!StrCaseCmp(buf, "default")) return -1;
1201 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1206 parse_cpair(cc, str)
1210 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1211 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1216 /* bg and attr are optional */
1217 textColors[(int)cc].bg = parse_color(str, 1);
1218 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1219 textColors[(int)cc].attr = 0;
1225 /* Arrange to catch delete-window events */
1226 Atom wm_delete_window;
1228 CatchDeleteWindow(Widget w, String procname)
1231 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1232 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1233 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1240 XtSetArg(args[0], XtNiconic, False);
1241 XtSetValues(shellWidget, args, 1);
1243 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1246 //---------------------------------------------------------------------------------------------------------
1247 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1250 #define CW_USEDEFAULT (1<<31)
1251 #define ICS_TEXT_MENU_SIZE 90
1252 #define DEBUG_FILE "xboard.debug"
1253 #define SetCurrentDirectory chdir
1254 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1258 // these two must some day move to frontend.h, when they are implemented
1259 Boolean MoveHistoryIsUp();
1260 Boolean GameListIsUp();
1262 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1265 // front-end part of option handling
1267 // [HGM] This platform-dependent table provides the location for storing the color info
1268 extern char *crWhite, * crBlack;
1272 &appData.whitePieceColor,
1273 &appData.blackPieceColor,
1274 &appData.lightSquareColor,
1275 &appData.darkSquareColor,
1276 &appData.highlightSquareColor,
1277 &appData.premoveHighlightColor,
1290 ParseFont(char *name, int number)
1291 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1293 case 0: // CLOCK_FONT
1294 appData.clockFont = strdup(name);
1296 case 1: // MESSAGE_FONT
1297 appData.font = strdup(name);
1299 case 2: // COORD_FONT
1300 appData.coordFont = strdup(name);
1309 { // only 2 fonts currently
1310 appData.clockFont = CLOCK_FONT_NAME;
1311 appData.coordFont = COORD_FONT_NAME;
1312 appData.font = DEFAULT_FONT_NAME;
1317 { // no-op, until we identify the code for this already in XBoard and move it here
1321 ParseColor(int n, char *name)
1322 { // in XBoard, just copy the color-name string
1323 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1327 ParseTextAttribs(ColorClass cc, char *s)
1329 (&appData.colorShout)[cc] = strdup(s);
1333 ParseBoardSize(void *addr, char *name)
1335 appData.boardSize = strdup(name);
1340 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1344 SetCommPortDefaults()
1345 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1348 // [HGM] args: these three cases taken out to stay in front-end
1350 SaveFontArg(FILE *f, ArgDescriptor *ad)
1353 switch((int)ad->argLoc) {
1354 case 0: // CLOCK_FONT
1355 name = appData.clockFont;
1357 case 1: // MESSAGE_FONT
1358 name = appData.font;
1360 case 2: // COORD_FONT
1361 name = appData.coordFont;
1366 // Do not save fonts for now, as the saved font would be board-size specific
1367 // and not suitable for a re-start at another board size
1368 // fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1373 { // nothing to do, as the sounds are at all times represented by their text-string names already
1377 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1378 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1379 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1383 SaveColor(FILE *f, ArgDescriptor *ad)
1384 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1385 if(colorVariable[(int)ad->argLoc])
1386 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1390 SaveBoardSize(FILE *f, char *name, void *addr)
1391 { // wrapper to shield back-end from BoardSize & sizeInfo
1392 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1396 ParseCommPortSettings(char *s)
1397 { // no such option in XBoard (yet)
1400 extern Widget engineOutputShell;
1401 extern Widget tagsShell, editTagsShell;
1403 GetActualPlacement(Widget wg, WindowPlacement *wp)
1413 XtSetArg(args[i], XtNx, &x); i++;
1414 XtSetArg(args[i], XtNy, &y); i++;
1415 XtSetArg(args[i], XtNwidth, &w); i++;
1416 XtSetArg(args[i], XtNheight, &h); i++;
1417 XtGetValues(wg, args, i);
1426 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1427 // In XBoard this will have to wait until awareness of window parameters is implemented
1428 GetActualPlacement(shellWidget, &wpMain);
1429 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1430 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1431 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1432 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1433 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1434 else GetActualPlacement(editShell, &wpComment);
1435 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1436 else GetActualPlacement(editTagsShell, &wpTags);
1440 PrintCommPortSettings(FILE *f, char *name)
1441 { // This option does not exist in XBoard
1445 MySearchPath(char *installDir, char *name, char *fullname)
1446 { // just append installDir and name. Perhaps ExpandPath should be used here?
1447 name = ExpandPathName(name);
1448 if(name && name[0] == '/') strcpy(fullname, name); else {
1449 sprintf(fullname, "%s%c%s", installDir, '/', name);
1455 MyGetFullPathName(char *name, char *fullname)
1456 { // should use ExpandPath?
1457 name = ExpandPathName(name);
1458 strcpy(fullname, name);
1463 EnsureOnScreen(int *x, int *y, int minX, int minY)
1470 { // [HGM] args: allows testing if main window is realized from back-end
1471 return xBoardWindow != 0;
1475 PopUpStartupDialog()
1476 { // start menu not implemented in XBoard
1479 ConvertToLine(int argc, char **argv)
1481 static char line[128*1024], buf[1024];
1485 for(i=1; i<argc; i++) {
1486 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1487 && argv[i][0] != '{' )
1488 sprintf(buf, "{%s} ", argv[i]);
1489 else sprintf(buf, "%s ", argv[i]);
1492 line[strlen(line)-1] = NULLCHAR;
1496 //--------------------------------------------------------------------------------------------
1499 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1501 #define BoardSize int
1502 void InitDrawingSizes(BoardSize boardSize, int flags)
1503 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1504 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1506 XtGeometryResult gres;
1509 if(!formWidget) return;
1512 * Enable shell resizing.
1514 shellArgs[0].value = (XtArgVal) &w;
1515 shellArgs[1].value = (XtArgVal) &h;
1516 XtGetValues(shellWidget, shellArgs, 2);
1518 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1519 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1520 XtSetValues(shellWidget, &shellArgs[2], 4);
1522 XtSetArg(args[0], XtNdefaultDistance, &sep);
1523 XtGetValues(formWidget, args, 1);
1525 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1526 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1529 XtSetArg(args[0], XtNwidth, boardWidth);
1530 XtSetArg(args[1], XtNheight, boardHeight);
1531 XtSetValues(boardWidget, args, 2);
1533 timerWidth = (boardWidth - sep) / 2;
1534 XtSetArg(args[0], XtNwidth, timerWidth);
1535 XtSetValues(whiteTimerWidget, args, 1);
1536 XtSetValues(blackTimerWidget, args, 1);
1538 XawFormDoLayout(formWidget, False);
1540 if (appData.titleInWindow) {
1542 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1543 XtSetArg(args[i], XtNheight, &h); i++;
1544 XtGetValues(titleWidget, args, i);
1546 w = boardWidth - 2*bor;
1548 XtSetArg(args[0], XtNwidth, &w);
1549 XtGetValues(menuBarWidget, args, 1);
1550 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1553 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1554 if (gres != XtGeometryYes && appData.debugMode) {
1556 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1557 programName, gres, w, h, wr, hr);
1561 XawFormDoLayout(formWidget, True);
1564 * Inhibit shell resizing.
1566 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1567 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1568 shellArgs[4].value = shellArgs[2].value = w;
1569 shellArgs[5].value = shellArgs[3].value = h;
1570 XtSetValues(shellWidget, &shellArgs[0], 6);
1572 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1575 for(i=0; i<4; i++) {
1577 for(p=0; p<=(int)WhiteKing; p++)
1578 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1579 if(gameInfo.variant == VariantShogi) {
1580 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1581 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1582 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1583 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1584 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1587 if(gameInfo.variant == VariantGothic) {
1588 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1592 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1593 for(p=0; p<=(int)WhiteKing; p++)
1594 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1595 if(gameInfo.variant == VariantShogi) {
1596 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1597 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1598 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1599 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1600 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1603 if(gameInfo.variant == VariantGothic) {
1604 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1610 for(i=0; i<2; i++) {
1612 for(p=0; p<=(int)WhiteKing; p++)
1613 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1614 if(gameInfo.variant == VariantShogi) {
1615 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1616 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1617 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1618 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1619 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1622 if(gameInfo.variant == VariantGothic) {
1623 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1634 void EscapeExpand(char *p, char *q)
1635 { // [HGM] initstring: routine to shape up string arguments
1636 while(*p++ = *q++) if(p[-1] == '\\')
1638 case 'n': p[-1] = '\n'; break;
1639 case 'r': p[-1] = '\r'; break;
1640 case 't': p[-1] = '\t'; break;
1641 case '\\': p[-1] = '\\'; break;
1642 case 0: *p = 0; return;
1643 default: p[-1] = q[-1]; break;
1652 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1653 XSetWindowAttributes window_attributes;
1655 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1656 XrmValue vFrom, vTo;
1657 XtGeometryResult gres;
1660 int forceMono = False;
1662 srandom(time(0)); // [HGM] book: make random truly random
1664 setbuf(stdout, NULL);
1665 setbuf(stderr, NULL);
1668 programName = strrchr(argv[0], '/');
1669 if (programName == NULL)
1670 programName = argv[0];
1675 XtSetLanguageProc(NULL, NULL, NULL);
1676 bindtextdomain(PACKAGE, LOCALEDIR);
1677 textdomain(PACKAGE);
1681 XtAppInitialize(&appContext, "XBoard", shellOptions,
1682 XtNumber(shellOptions),
1683 &argc, argv, xboardResources, NULL, 0);
1684 appData.boardSize = "";
1685 InitAppData(ConvertToLine(argc, argv));
1687 if (p == NULL) p = "/tmp";
1688 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1689 gameCopyFilename = (char*) malloc(i);
1690 gamePasteFilename = (char*) malloc(i);
1691 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1692 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1694 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1695 clientResources, XtNumber(clientResources),
1698 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1699 static char buf[MSG_SIZ];
1700 EscapeExpand(buf, appData.initString);
1701 appData.initString = strdup(buf);
1702 EscapeExpand(buf, appData.secondInitString);
1703 appData.secondInitString = strdup(buf);
1704 EscapeExpand(buf, appData.firstComputerString);
1705 appData.firstComputerString = strdup(buf);
1706 EscapeExpand(buf, appData.secondComputerString);
1707 appData.secondComputerString = strdup(buf);
1710 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1713 if (chdir(chessDir) != 0) {
1714 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1720 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1721 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1722 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1723 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1726 setbuf(debugFP, NULL);
1729 /* [HGM,HR] make sure board size is acceptable */
1730 if(appData.NrFiles > BOARD_FILES ||
1731 appData.NrRanks > BOARD_RANKS )
1732 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1735 /* This feature does not work; animation needs a rewrite */
1736 appData.highlightDragging = FALSE;
1740 xDisplay = XtDisplay(shellWidget);
1741 xScreen = DefaultScreen(xDisplay);
1742 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1744 gameInfo.variant = StringToVariant(appData.variant);
1745 InitPosition(FALSE);
1748 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1750 if (isdigit(appData.boardSize[0])) {
1751 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1752 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1753 &fontPxlSize, &smallLayout, &tinyLayout);
1755 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1756 programName, appData.boardSize);
1760 /* Find some defaults; use the nearest known size */
1761 SizeDefaults *szd, *nearest;
1762 int distance = 99999;
1763 nearest = szd = sizeDefaults;
1764 while (szd->name != NULL) {
1765 if (abs(szd->squareSize - squareSize) < distance) {
1767 distance = abs(szd->squareSize - squareSize);
1768 if (distance == 0) break;
1772 if (i < 2) lineGap = nearest->lineGap;
1773 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1774 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1775 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1776 if (i < 6) smallLayout = nearest->smallLayout;
1777 if (i < 7) tinyLayout = nearest->tinyLayout;
1780 SizeDefaults *szd = sizeDefaults;
1781 if (*appData.boardSize == NULLCHAR) {
1782 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1783 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1786 if (szd->name == NULL) szd--;
1787 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1789 while (szd->name != NULL &&
1790 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1791 if (szd->name == NULL) {
1792 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1793 programName, appData.boardSize);
1797 squareSize = szd->squareSize;
1798 lineGap = szd->lineGap;
1799 clockFontPxlSize = szd->clockFontPxlSize;
1800 coordFontPxlSize = szd->coordFontPxlSize;
1801 fontPxlSize = szd->fontPxlSize;
1802 smallLayout = szd->smallLayout;
1803 tinyLayout = szd->tinyLayout;
1806 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1807 if (strlen(appData.pixmapDirectory) > 0) {
1808 p = ExpandPathName(appData.pixmapDirectory);
1810 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1811 appData.pixmapDirectory);
1814 if (appData.debugMode) {
1815 fprintf(stderr, _("\
1816 XBoard square size (hint): %d\n\
1817 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1819 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1820 if (appData.debugMode) {
1821 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1825 /* [HR] height treated separately (hacked) */
1826 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1827 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1828 if (appData.showJail == 1) {
1829 /* Jail on top and bottom */
1830 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1831 XtSetArg(boardArgs[2], XtNheight,
1832 boardHeight + 2*(lineGap + squareSize));
1833 } else if (appData.showJail == 2) {
1835 XtSetArg(boardArgs[1], XtNwidth,
1836 boardWidth + 2*(lineGap + squareSize));
1837 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1840 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1841 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1845 * Determine what fonts to use.
1847 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1848 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1849 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1850 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1851 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1852 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1853 appData.font = FindFont(appData.font, fontPxlSize);
1854 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1855 countFontStruct = XQueryFont(xDisplay, countFontID);
1856 // appData.font = FindFont(appData.font, fontPxlSize);
1858 xdb = XtDatabase(xDisplay);
1859 XrmPutStringResource(&xdb, "*font", appData.font);
1862 * Detect if there are not enough colors available and adapt.
1864 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1865 appData.monoMode = True;
1868 if (!appData.monoMode) {
1869 vFrom.addr = (caddr_t) appData.lightSquareColor;
1870 vFrom.size = strlen(appData.lightSquareColor);
1871 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1872 if (vTo.addr == NULL) {
1873 appData.monoMode = True;
1876 lightSquareColor = *(Pixel *) vTo.addr;
1879 if (!appData.monoMode) {
1880 vFrom.addr = (caddr_t) appData.darkSquareColor;
1881 vFrom.size = strlen(appData.darkSquareColor);
1882 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1883 if (vTo.addr == NULL) {
1884 appData.monoMode = True;
1887 darkSquareColor = *(Pixel *) vTo.addr;
1890 if (!appData.monoMode) {
1891 vFrom.addr = (caddr_t) appData.whitePieceColor;
1892 vFrom.size = strlen(appData.whitePieceColor);
1893 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1894 if (vTo.addr == NULL) {
1895 appData.monoMode = True;
1898 whitePieceColor = *(Pixel *) vTo.addr;
1901 if (!appData.monoMode) {
1902 vFrom.addr = (caddr_t) appData.blackPieceColor;
1903 vFrom.size = strlen(appData.blackPieceColor);
1904 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1905 if (vTo.addr == NULL) {
1906 appData.monoMode = True;
1909 blackPieceColor = *(Pixel *) vTo.addr;
1913 if (!appData.monoMode) {
1914 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1915 vFrom.size = strlen(appData.highlightSquareColor);
1916 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1917 if (vTo.addr == NULL) {
1918 appData.monoMode = True;
1921 highlightSquareColor = *(Pixel *) vTo.addr;
1925 if (!appData.monoMode) {
1926 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1927 vFrom.size = strlen(appData.premoveHighlightColor);
1928 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1929 if (vTo.addr == NULL) {
1930 appData.monoMode = True;
1933 premoveHighlightColor = *(Pixel *) vTo.addr;
1938 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1941 if (appData.bitmapDirectory == NULL ||
1942 appData.bitmapDirectory[0] == NULLCHAR)
1943 appData.bitmapDirectory = DEF_BITMAP_DIR;
1946 if (appData.lowTimeWarning && !appData.monoMode) {
1947 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1948 vFrom.size = strlen(appData.lowTimeWarningColor);
1949 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1950 if (vTo.addr == NULL)
1951 appData.monoMode = True;
1953 lowTimeWarningColor = *(Pixel *) vTo.addr;
1956 if (appData.monoMode && appData.debugMode) {
1957 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1958 (unsigned long) XWhitePixel(xDisplay, xScreen),
1959 (unsigned long) XBlackPixel(xDisplay, xScreen));
1962 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1963 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1964 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1965 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1966 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1967 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1968 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1969 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1970 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1971 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1973 if (appData.colorize) {
1975 _("%s: can't parse color names; disabling colorization\n"),
1978 appData.colorize = FALSE;
1980 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
1981 textColors[ColorNone].attr = 0;
1983 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
1989 layoutName = "tinyLayout";
1990 } else if (smallLayout) {
1991 layoutName = "smallLayout";
1993 layoutName = "normalLayout";
1995 /* Outer layoutWidget is there only to provide a name for use in
1996 resources that depend on the layout style */
1998 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
1999 layoutArgs, XtNumber(layoutArgs));
2001 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2002 formArgs, XtNumber(formArgs));
2003 XtSetArg(args[0], XtNdefaultDistance, &sep);
2004 XtGetValues(formWidget, args, 1);
2007 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2008 XtSetArg(args[0], XtNtop, XtChainTop);
2009 XtSetArg(args[1], XtNbottom, XtChainTop);
2010 XtSetArg(args[2], XtNright, XtChainLeft);
2011 XtSetValues(menuBarWidget, args, 3);
2013 widgetList[j++] = whiteTimerWidget =
2014 XtCreateWidget("whiteTime", labelWidgetClass,
2015 formWidget, timerArgs, XtNumber(timerArgs));
2016 XtSetArg(args[0], XtNfont, clockFontStruct);
2017 XtSetArg(args[1], XtNtop, XtChainTop);
2018 XtSetArg(args[2], XtNbottom, XtChainTop);
2019 XtSetValues(whiteTimerWidget, args, 3);
2021 widgetList[j++] = blackTimerWidget =
2022 XtCreateWidget("blackTime", labelWidgetClass,
2023 formWidget, timerArgs, XtNumber(timerArgs));
2024 XtSetArg(args[0], XtNfont, clockFontStruct);
2025 XtSetArg(args[1], XtNtop, XtChainTop);
2026 XtSetArg(args[2], XtNbottom, XtChainTop);
2027 XtSetValues(blackTimerWidget, args, 3);
2029 if (appData.titleInWindow) {
2030 widgetList[j++] = titleWidget =
2031 XtCreateWidget("title", labelWidgetClass, formWidget,
2032 titleArgs, XtNumber(titleArgs));
2033 XtSetArg(args[0], XtNtop, XtChainTop);
2034 XtSetArg(args[1], XtNbottom, XtChainTop);
2035 XtSetValues(titleWidget, args, 2);
2038 if (appData.showButtonBar) {
2039 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2040 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2041 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2042 XtSetArg(args[2], XtNtop, XtChainTop);
2043 XtSetArg(args[3], XtNbottom, XtChainTop);
2044 XtSetValues(buttonBarWidget, args, 4);
2047 widgetList[j++] = messageWidget =
2048 XtCreateWidget("message", labelWidgetClass, formWidget,
2049 messageArgs, XtNumber(messageArgs));
2050 XtSetArg(args[0], XtNtop, XtChainTop);
2051 XtSetArg(args[1], XtNbottom, XtChainTop);
2052 XtSetValues(messageWidget, args, 2);
2054 widgetList[j++] = boardWidget =
2055 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2056 XtNumber(boardArgs));
2058 XtManageChildren(widgetList, j);
2060 timerWidth = (boardWidth - sep) / 2;
2061 XtSetArg(args[0], XtNwidth, timerWidth);
2062 XtSetValues(whiteTimerWidget, args, 1);
2063 XtSetValues(blackTimerWidget, args, 1);
2065 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2066 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2067 XtGetValues(whiteTimerWidget, args, 2);
2069 if (appData.showButtonBar) {
2070 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2071 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2072 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2076 * formWidget uses these constraints but they are stored
2080 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2081 XtSetValues(menuBarWidget, args, i);
2082 if (appData.titleInWindow) {
2085 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2086 XtSetValues(whiteTimerWidget, args, i);
2088 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2089 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2090 XtSetValues(blackTimerWidget, args, i);
2092 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2093 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2094 XtSetValues(titleWidget, args, i);
2096 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2097 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2098 XtSetValues(messageWidget, args, i);
2099 if (appData.showButtonBar) {
2101 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2102 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2103 XtSetValues(buttonBarWidget, args, i);
2107 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2108 XtSetValues(whiteTimerWidget, args, i);
2110 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2111 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2112 XtSetValues(blackTimerWidget, args, i);
2114 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2115 XtSetValues(titleWidget, args, i);
2117 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2118 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2119 XtSetValues(messageWidget, args, i);
2120 if (appData.showButtonBar) {
2122 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2123 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2124 XtSetValues(buttonBarWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2130 XtSetValues(whiteTimerWidget, args, i);
2132 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2133 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2134 XtSetValues(blackTimerWidget, args, i);
2136 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2137 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2138 XtSetValues(messageWidget, args, i);
2139 if (appData.showButtonBar) {
2141 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2142 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2143 XtSetValues(buttonBarWidget, args, i);
2147 XtSetArg(args[0], XtNfromVert, messageWidget);
2148 XtSetArg(args[1], XtNtop, XtChainTop);
2149 XtSetArg(args[2], XtNbottom, XtChainBottom);
2150 XtSetArg(args[3], XtNleft, XtChainLeft);
2151 XtSetArg(args[4], XtNright, XtChainRight);
2152 XtSetValues(boardWidget, args, 5);
2154 XtRealizeWidget(shellWidget);
2157 XtSetArg(args[0], XtNx, wpMain.x);
2158 XtSetArg(args[1], XtNy, wpMain.y);
2159 XtSetValues(shellWidget, args, 2);
2163 * Correct the width of the message and title widgets.
2164 * It is not known why some systems need the extra fudge term.
2165 * The value "2" is probably larger than needed.
2167 XawFormDoLayout(formWidget, False);
2169 #define WIDTH_FUDGE 2
2171 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2172 XtSetArg(args[i], XtNheight, &h); i++;
2173 XtGetValues(messageWidget, args, i);
2174 if (appData.showButtonBar) {
2176 XtSetArg(args[i], XtNwidth, &w); i++;
2177 XtGetValues(buttonBarWidget, args, i);
2178 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2180 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2183 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2184 if (gres != XtGeometryYes && appData.debugMode) {
2185 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2186 programName, gres, w, h, wr, hr);
2189 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2190 /* The size used for the child widget in layout lags one resize behind
2191 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2193 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2194 if (gres != XtGeometryYes && appData.debugMode) {
2195 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2196 programName, gres, w, h, wr, hr);
2199 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2200 XtSetArg(args[1], XtNright, XtChainRight);
2201 XtSetValues(messageWidget, args, 2);
2203 if (appData.titleInWindow) {
2205 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2206 XtSetArg(args[i], XtNheight, &h); i++;
2207 XtGetValues(titleWidget, args, i);
2209 w = boardWidth - 2*bor;
2211 XtSetArg(args[0], XtNwidth, &w);
2212 XtGetValues(menuBarWidget, args, 1);
2213 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2216 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2217 if (gres != XtGeometryYes && appData.debugMode) {
2219 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2220 programName, gres, w, h, wr, hr);
2223 XawFormDoLayout(formWidget, True);
2225 xBoardWindow = XtWindow(boardWidget);
2227 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2228 // not need to go into InitDrawingSizes().
2232 * Create X checkmark bitmap and initialize option menu checks.
2234 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2235 checkmark_bits, checkmark_width, checkmark_height);
2236 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2237 if (appData.alwaysPromoteToQueen) {
2238 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2241 if (appData.animateDragging) {
2242 XtSetValues(XtNameToWidget(menuBarWidget,
2243 "menuOptions.Animate Dragging"),
2246 if (appData.animate) {
2247 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2250 if (appData.autoComment) {
2251 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2254 if (appData.autoCallFlag) {
2255 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2258 if (appData.autoFlipView) {
2259 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2262 if (appData.autoObserve) {
2263 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2266 if (appData.autoRaiseBoard) {
2267 XtSetValues(XtNameToWidget(menuBarWidget,
2268 "menuOptions.Auto Raise Board"), args, 1);
2270 if (appData.autoSaveGames) {
2271 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2274 if (appData.saveGameFile[0] != NULLCHAR) {
2275 /* Can't turn this off from menu */
2276 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2278 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2282 if (appData.blindfold) {
2283 XtSetValues(XtNameToWidget(menuBarWidget,
2284 "menuOptions.Blindfold"), args, 1);
2286 if (appData.flashCount > 0) {
2287 XtSetValues(XtNameToWidget(menuBarWidget,
2288 "menuOptions.Flash Moves"),
2291 if (appData.getMoveList) {
2292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2296 if (appData.highlightDragging) {
2297 XtSetValues(XtNameToWidget(menuBarWidget,
2298 "menuOptions.Highlight Dragging"),
2302 if (appData.highlightLastMove) {
2303 XtSetValues(XtNameToWidget(menuBarWidget,
2304 "menuOptions.Highlight Last Move"),
2307 if (appData.icsAlarm) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2311 if (appData.ringBellAfterMoves) {
2312 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2315 if (appData.oldSaveStyle) {
2316 XtSetValues(XtNameToWidget(menuBarWidget,
2317 "menuOptions.Old Save Style"), args, 1);
2319 if (appData.periodicUpdates) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Periodic Updates"), args, 1);
2323 if (appData.ponderNextMove) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Ponder Next Move"), args, 1);
2327 if (appData.popupExitMessage) {
2328 XtSetValues(XtNameToWidget(menuBarWidget,
2329 "menuOptions.Popup Exit Message"), args, 1);
2331 if (appData.popupMoveErrors) {
2332 XtSetValues(XtNameToWidget(menuBarWidget,
2333 "menuOptions.Popup Move Errors"), args, 1);
2335 if (appData.premove) {
2336 XtSetValues(XtNameToWidget(menuBarWidget,
2337 "menuOptions.Premove"), args, 1);
2339 if (appData.quietPlay) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Quiet Play"), args, 1);
2343 if (appData.showCoords) {
2344 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2347 if (appData.hideThinkingFromHuman) {
2348 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2351 if (appData.testLegality) {
2352 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2355 if (saveSettingsOnExit) {
2356 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2363 ReadBitmap(&wIconPixmap, "icon_white.bm",
2364 icon_white_bits, icon_white_width, icon_white_height);
2365 ReadBitmap(&bIconPixmap, "icon_black.bm",
2366 icon_black_bits, icon_black_width, icon_black_height);
2367 iconPixmap = wIconPixmap;
2369 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2370 XtSetValues(shellWidget, args, i);
2373 * Create a cursor for the board widget.
2375 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2376 XChangeWindowAttributes(xDisplay, xBoardWindow,
2377 CWCursor, &window_attributes);
2380 * Inhibit shell resizing.
2382 shellArgs[0].value = (XtArgVal) &w;
2383 shellArgs[1].value = (XtArgVal) &h;
2384 XtGetValues(shellWidget, shellArgs, 2);
2385 shellArgs[4].value = shellArgs[2].value = w;
2386 shellArgs[5].value = shellArgs[3].value = h;
2387 XtSetValues(shellWidget, &shellArgs[2], 4);
2388 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2389 marginH = h - boardHeight;
2391 CatchDeleteWindow(shellWidget, "QuitProc");
2396 if (appData.bitmapDirectory[0] != NULLCHAR) {
2403 /* Create regular pieces */
2404 if (!useImages) CreatePieces();
2409 if (appData.animate || appData.animateDragging)
2412 XtAugmentTranslations(formWidget,
2413 XtParseTranslationTable(globalTranslations));
2414 XtAugmentTranslations(boardWidget,
2415 XtParseTranslationTable(boardTranslations));
2416 XtAugmentTranslations(whiteTimerWidget,
2417 XtParseTranslationTable(whiteTranslations));
2418 XtAugmentTranslations(blackTimerWidget,
2419 XtParseTranslationTable(blackTranslations));
2421 /* Why is the following needed on some versions of X instead
2422 * of a translation? */
2423 XtAddEventHandler(boardWidget, ExposureMask, False,
2424 (XtEventHandler) EventProc, NULL);
2427 /* [AS] Restore layout */
2428 if( wpMoveHistory.visible ) {
2432 if( wpEvalGraph.visible )
2437 if( wpEngineOutput.visible ) {
2438 EngineOutputPopUp();
2443 if (errorExitStatus == -1) {
2444 if (appData.icsActive) {
2445 /* We now wait until we see "login:" from the ICS before
2446 sending the logon script (problems with timestamp otherwise) */
2447 /*ICSInitScript();*/
2448 if (appData.icsInputBox) ICSInputBoxPopUp();
2452 signal(SIGWINCH, TermSizeSigHandler);
2454 signal(SIGINT, IntSigHandler);
2455 signal(SIGTERM, IntSigHandler);
2456 if (*appData.cmailGameName != NULLCHAR) {
2457 signal(SIGUSR1, CmailSigHandler);
2460 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2463 XtAppMainLoop(appContext);
2464 if (appData.debugMode) fclose(debugFP); // [DM] debug
2471 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2472 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2474 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2475 unlink(gameCopyFilename);
2476 unlink(gamePasteFilename);
2479 RETSIGTYPE TermSizeSigHandler(int sig)
2492 CmailSigHandler(sig)
2498 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2500 /* Activate call-back function CmailSigHandlerCallBack() */
2501 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2503 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2507 CmailSigHandlerCallBack(isr, closure, message, count, error)
2515 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2517 /**** end signal code ****/
2527 f = fopen(appData.icsLogon, "r");
2533 strcat(buf, appData.icsLogon);
2534 f = fopen(buf, "r");
2538 ProcessICSInitScript(f);
2545 EditCommentPopDown();
2560 if (!menuBarWidget) return;
2561 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2563 DisplayError("menuStep.Revert", 0);
2565 XtSetSensitive(w, !grey);
2570 SetMenuEnables(enab)
2574 if (!menuBarWidget) return;
2575 while (enab->name != NULL) {
2576 w = XtNameToWidget(menuBarWidget, enab->name);
2578 DisplayError(enab->name, 0);
2580 XtSetSensitive(w, enab->value);
2586 Enables icsEnables[] = {
2587 { "menuFile.Mail Move", False },
2588 { "menuFile.Reload CMail Message", False },
2589 { "menuMode.Machine Black", False },
2590 { "menuMode.Machine White", False },
2591 { "menuMode.Analysis Mode", False },
2592 { "menuMode.Analyze File", False },
2593 { "menuMode.Two Machines", False },
2595 { "menuHelp.Hint", False },
2596 { "menuHelp.Book", False },
2597 { "menuStep.Move Now", False },
2598 { "menuOptions.Periodic Updates", False },
2599 { "menuOptions.Hide Thinking", False },
2600 { "menuOptions.Ponder Next Move", False },
2605 Enables ncpEnables[] = {
2606 { "menuFile.Mail Move", False },
2607 { "menuFile.Reload CMail Message", False },
2608 { "menuMode.Machine White", False },
2609 { "menuMode.Machine Black", False },
2610 { "menuMode.Analysis Mode", False },
2611 { "menuMode.Analyze File", False },
2612 { "menuMode.Two Machines", False },
2613 { "menuMode.ICS Client", False },
2614 { "menuMode.ICS Input Box", False },
2615 { "Action", False },
2616 { "menuStep.Revert", False },
2617 { "menuStep.Move Now", False },
2618 { "menuStep.Retract Move", False },
2619 { "menuOptions.Auto Comment", False },
2620 { "menuOptions.Auto Flag", False },
2621 { "menuOptions.Auto Flip View", False },
2622 { "menuOptions.Auto Observe", False },
2623 { "menuOptions.Auto Raise Board", False },
2624 { "menuOptions.Get Move List", False },
2625 { "menuOptions.ICS Alarm", False },
2626 { "menuOptions.Move Sound", False },
2627 { "menuOptions.Quiet Play", False },
2628 { "menuOptions.Hide Thinking", False },
2629 { "menuOptions.Periodic Updates", False },
2630 { "menuOptions.Ponder Next Move", False },
2631 { "menuHelp.Hint", False },
2632 { "menuHelp.Book", False },
2636 Enables gnuEnables[] = {
2637 { "menuMode.ICS Client", False },
2638 { "menuMode.ICS Input Box", False },
2639 { "menuAction.Accept", False },
2640 { "menuAction.Decline", False },
2641 { "menuAction.Rematch", False },
2642 { "menuAction.Adjourn", False },
2643 { "menuAction.Stop Examining", False },
2644 { "menuAction.Stop Observing", False },
2645 { "menuStep.Revert", False },
2646 { "menuOptions.Auto Comment", False },
2647 { "menuOptions.Auto Observe", False },
2648 { "menuOptions.Auto Raise Board", False },
2649 { "menuOptions.Get Move List", False },
2650 { "menuOptions.Premove", False },
2651 { "menuOptions.Quiet Play", False },
2653 /* The next two options rely on SetCmailMode being called *after* */
2654 /* SetGNUMode so that when GNU is being used to give hints these */
2655 /* menu options are still available */
2657 { "menuFile.Mail Move", False },
2658 { "menuFile.Reload CMail Message", False },
2662 Enables cmailEnables[] = {
2664 { "menuAction.Call Flag", False },
2665 { "menuAction.Draw", True },
2666 { "menuAction.Adjourn", False },
2667 { "menuAction.Abort", False },
2668 { "menuAction.Stop Observing", False },
2669 { "menuAction.Stop Examining", False },
2670 { "menuFile.Mail Move", True },
2671 { "menuFile.Reload CMail Message", True },
2675 Enables trainingOnEnables[] = {
2676 { "menuMode.Edit Comment", False },
2677 { "menuMode.Pause", False },
2678 { "menuStep.Forward", False },
2679 { "menuStep.Backward", False },
2680 { "menuStep.Forward to End", False },
2681 { "menuStep.Back to Start", False },
2682 { "menuStep.Move Now", False },
2683 { "menuStep.Truncate Game", False },
2687 Enables trainingOffEnables[] = {
2688 { "menuMode.Edit Comment", True },
2689 { "menuMode.Pause", True },
2690 { "menuStep.Forward", True },
2691 { "menuStep.Backward", True },
2692 { "menuStep.Forward to End", True },
2693 { "menuStep.Back to Start", True },
2694 { "menuStep.Move Now", True },
2695 { "menuStep.Truncate Game", True },
2699 Enables machineThinkingEnables[] = {
2700 { "menuFile.Load Game", False },
2701 { "menuFile.Load Next Game", False },
2702 { "menuFile.Load Previous Game", False },
2703 { "menuFile.Reload Same Game", False },
2704 { "menuFile.Paste Game", False },
2705 { "menuFile.Load Position", False },
2706 { "menuFile.Load Next Position", False },
2707 { "menuFile.Load Previous Position", False },
2708 { "menuFile.Reload Same Position", False },
2709 { "menuFile.Paste Position", False },
2710 { "menuMode.Machine White", False },
2711 { "menuMode.Machine Black", False },
2712 { "menuMode.Two Machines", False },
2713 { "menuStep.Retract Move", False },
2717 Enables userThinkingEnables[] = {
2718 { "menuFile.Load Game", True },
2719 { "menuFile.Load Next Game", True },
2720 { "menuFile.Load Previous Game", True },
2721 { "menuFile.Reload Same Game", True },
2722 { "menuFile.Paste Game", True },
2723 { "menuFile.Load Position", True },
2724 { "menuFile.Load Next Position", True },
2725 { "menuFile.Load Previous Position", True },
2726 { "menuFile.Reload Same Position", True },
2727 { "menuFile.Paste Position", True },
2728 { "menuMode.Machine White", True },
2729 { "menuMode.Machine Black", True },
2730 { "menuMode.Two Machines", True },
2731 { "menuStep.Retract Move", True },
2737 SetMenuEnables(icsEnables);
2740 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2741 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2748 SetMenuEnables(ncpEnables);
2754 SetMenuEnables(gnuEnables);
2760 SetMenuEnables(cmailEnables);
2766 SetMenuEnables(trainingOnEnables);
2767 if (appData.showButtonBar) {
2768 XtSetSensitive(buttonBarWidget, False);
2774 SetTrainingModeOff()
2776 SetMenuEnables(trainingOffEnables);
2777 if (appData.showButtonBar) {
2778 XtSetSensitive(buttonBarWidget, True);
2783 SetUserThinkingEnables()
2785 if (appData.noChessProgram) return;
2786 SetMenuEnables(userThinkingEnables);
2790 SetMachineThinkingEnables()
2792 if (appData.noChessProgram) return;
2793 SetMenuEnables(machineThinkingEnables);
2795 case MachinePlaysBlack:
2796 case MachinePlaysWhite:
2797 case TwoMachinesPlay:
2798 XtSetSensitive(XtNameToWidget(menuBarWidget,
2799 ModeToWidgetName(gameMode)), True);
2806 #define Abs(n) ((n)<0 ? -(n) : (n))
2809 * Find a font that matches "pattern" that is as close as
2810 * possible to the targetPxlSize. Prefer fonts that are k
2811 * pixels smaller to fonts that are k pixels larger. The
2812 * pattern must be in the X Consortium standard format,
2813 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2814 * The return value should be freed with XtFree when no
2817 char *FindFont(pattern, targetPxlSize)
2821 char **fonts, *p, *best, *scalable, *scalableTail;
2822 int i, j, nfonts, minerr, err, pxlSize;
2825 char **missing_list;
2827 char *def_string, *base_fnt_lst, strInt[3];
2829 XFontStruct **fnt_list;
2831 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2832 sprintf(strInt, "%d", targetPxlSize);
2833 p = strstr(pattern, "--");
2834 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2835 strcat(base_fnt_lst, strInt);
2836 strcat(base_fnt_lst, strchr(p + 2, '-'));
2838 if ((fntSet = XCreateFontSet(xDisplay,
2842 &def_string)) == NULL) {
2844 fprintf(stderr, _("Unable to create font set.\n"));
2848 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2850 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2852 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2853 programName, pattern);
2861 for (i=0; i<nfonts; i++) {
2864 if (*p != '-') continue;
2866 if (*p == NULLCHAR) break;
2867 if (*p++ == '-') j++;
2869 if (j < 7) continue;
2872 scalable = fonts[i];
2875 err = pxlSize - targetPxlSize;
2876 if (Abs(err) < Abs(minerr) ||
2877 (minerr > 0 && err < 0 && -err == minerr)) {
2883 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2884 /* If the error is too big and there is a scalable font,
2885 use the scalable font. */
2886 int headlen = scalableTail - scalable;
2887 p = (char *) XtMalloc(strlen(scalable) + 10);
2888 while (isdigit(*scalableTail)) scalableTail++;
2889 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2891 p = (char *) XtMalloc(strlen(best) + 1);
2894 if (appData.debugMode) {
2895 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2896 pattern, targetPxlSize, p);
2899 if (missing_count > 0)
2900 XFreeStringList(missing_list);
2901 XFreeFontSet(xDisplay, fntSet);
2903 XFreeFontNames(fonts);
2910 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2911 | GCBackground | GCFunction | GCPlaneMask;
2912 XGCValues gc_values;
2915 gc_values.plane_mask = AllPlanes;
2916 gc_values.line_width = lineGap;
2917 gc_values.line_style = LineSolid;
2918 gc_values.function = GXcopy;
2920 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2921 gc_values.background = XBlackPixel(xDisplay, xScreen);
2922 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2924 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2925 gc_values.background = XWhitePixel(xDisplay, xScreen);
2926 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2927 XSetFont(xDisplay, coordGC, coordFontID);
2929 // [HGM] make font for holdings counts (white on black0
2930 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2931 gc_values.background = XBlackPixel(xDisplay, xScreen);
2932 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2933 XSetFont(xDisplay, countGC, countFontID);
2935 if (appData.monoMode) {
2936 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2937 gc_values.background = XWhitePixel(xDisplay, xScreen);
2938 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2940 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2941 gc_values.background = XBlackPixel(xDisplay, xScreen);
2942 lightSquareGC = wbPieceGC
2943 = XtGetGC(shellWidget, value_mask, &gc_values);
2945 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2946 gc_values.background = XWhitePixel(xDisplay, xScreen);
2947 darkSquareGC = bwPieceGC
2948 = XtGetGC(shellWidget, value_mask, &gc_values);
2950 if (DefaultDepth(xDisplay, xScreen) == 1) {
2951 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2952 gc_values.function = GXcopyInverted;
2953 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2954 gc_values.function = GXcopy;
2955 if (XBlackPixel(xDisplay, xScreen) == 1) {
2956 bwPieceGC = darkSquareGC;
2957 wbPieceGC = copyInvertedGC;
2959 bwPieceGC = copyInvertedGC;
2960 wbPieceGC = lightSquareGC;
2964 gc_values.foreground = highlightSquareColor;
2965 gc_values.background = highlightSquareColor;
2966 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2968 gc_values.foreground = premoveHighlightColor;
2969 gc_values.background = premoveHighlightColor;
2970 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2972 gc_values.foreground = lightSquareColor;
2973 gc_values.background = darkSquareColor;
2974 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2976 gc_values.foreground = darkSquareColor;
2977 gc_values.background = lightSquareColor;
2978 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2980 gc_values.foreground = jailSquareColor;
2981 gc_values.background = jailSquareColor;
2982 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2984 gc_values.foreground = whitePieceColor;
2985 gc_values.background = darkSquareColor;
2986 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2988 gc_values.foreground = whitePieceColor;
2989 gc_values.background = lightSquareColor;
2990 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2992 gc_values.foreground = whitePieceColor;
2993 gc_values.background = jailSquareColor;
2994 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
2996 gc_values.foreground = blackPieceColor;
2997 gc_values.background = darkSquareColor;
2998 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3000 gc_values.foreground = blackPieceColor;
3001 gc_values.background = lightSquareColor;
3002 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3004 gc_values.foreground = blackPieceColor;
3005 gc_values.background = jailSquareColor;
3006 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3010 void loadXIM(xim, xmask, filename, dest, mask)
3023 fp = fopen(filename, "rb");
3025 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3032 for (y=0; y<h; ++y) {
3033 for (x=0; x<h; ++x) {
3038 XPutPixel(xim, x, y, blackPieceColor);
3040 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3043 XPutPixel(xim, x, y, darkSquareColor);
3045 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3048 XPutPixel(xim, x, y, whitePieceColor);
3050 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3053 XPutPixel(xim, x, y, lightSquareColor);
3055 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3061 /* create Pixmap of piece */
3062 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3064 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3067 /* create Pixmap of clipmask
3068 Note: We assume the white/black pieces have the same
3069 outline, so we make only 6 masks. This is okay
3070 since the XPM clipmask routines do the same. */
3072 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3074 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3077 /* now create the 1-bit version */
3078 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3081 values.foreground = 1;
3082 values.background = 0;
3084 /* Don't use XtGetGC, not read only */
3085 maskGC = XCreateGC(xDisplay, *mask,
3086 GCForeground | GCBackground, &values);
3087 XCopyPlane(xDisplay, temp, *mask, maskGC,
3088 0, 0, squareSize, squareSize, 0, 0, 1);
3089 XFreePixmap(xDisplay, temp);
3094 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3096 void CreateXIMPieces()
3101 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3106 /* The XSynchronize calls were copied from CreatePieces.
3107 Not sure if needed, but can't hurt */
3108 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3111 /* temp needed by loadXIM() */
3112 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3113 0, 0, ss, ss, AllPlanes, XYPixmap);
3115 if (strlen(appData.pixmapDirectory) == 0) {
3119 if (appData.monoMode) {
3120 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3124 fprintf(stderr, _("\nLoading XIMs...\n"));
3126 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3127 fprintf(stderr, "%d", piece+1);
3128 for (kind=0; kind<4; kind++) {
3129 fprintf(stderr, ".");
3130 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3131 ExpandPathName(appData.pixmapDirectory),
3132 piece <= (int) WhiteKing ? "" : "w",
3133 pieceBitmapNames[piece],
3135 ximPieceBitmap[kind][piece] =
3136 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3137 0, 0, ss, ss, AllPlanes, XYPixmap);
3138 if (appData.debugMode)
3139 fprintf(stderr, _("(File:%s:) "), buf);
3140 loadXIM(ximPieceBitmap[kind][piece],
3142 &(xpmPieceBitmap2[kind][piece]),
3143 &(ximMaskPm2[piece]));
3144 if(piece <= (int)WhiteKing)
3145 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3147 fprintf(stderr," ");
3149 /* Load light and dark squares */
3150 /* If the LSQ and DSQ pieces don't exist, we will
3151 draw them with solid squares. */
3152 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3153 if (access(buf, 0) != 0) {
3157 fprintf(stderr, _("light square "));
3159 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3160 0, 0, ss, ss, AllPlanes, XYPixmap);
3161 if (appData.debugMode)
3162 fprintf(stderr, _("(File:%s:) "), buf);
3164 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3165 fprintf(stderr, _("dark square "));
3166 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3167 ExpandPathName(appData.pixmapDirectory), ss);
3168 if (appData.debugMode)
3169 fprintf(stderr, _("(File:%s:) "), buf);
3171 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3172 0, 0, ss, ss, AllPlanes, XYPixmap);
3173 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3174 xpmJailSquare = xpmLightSquare;
3176 fprintf(stderr, _("Done.\n"));
3178 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3182 void CreateXPMPieces()
3186 u_int ss = squareSize;
3188 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3189 XpmColorSymbol symbols[4];
3191 /* The XSynchronize calls were copied from CreatePieces.
3192 Not sure if needed, but can't hurt */
3193 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3195 /* Setup translations so piece colors match square colors */
3196 symbols[0].name = "light_piece";
3197 symbols[0].value = appData.whitePieceColor;
3198 symbols[1].name = "dark_piece";
3199 symbols[1].value = appData.blackPieceColor;
3200 symbols[2].name = "light_square";
3201 symbols[2].value = appData.lightSquareColor;
3202 symbols[3].name = "dark_square";
3203 symbols[3].value = appData.darkSquareColor;
3205 attr.valuemask = XpmColorSymbols;
3206 attr.colorsymbols = symbols;
3207 attr.numsymbols = 4;
3209 if (appData.monoMode) {
3210 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3214 if (strlen(appData.pixmapDirectory) == 0) {
3215 XpmPieces* pieces = builtInXpms;
3218 while (pieces->size != squareSize && pieces->size) pieces++;
3219 if (!pieces->size) {
3220 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3223 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3224 for (kind=0; kind<4; kind++) {
3226 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3227 pieces->xpm[piece][kind],
3228 &(xpmPieceBitmap2[kind][piece]),
3229 NULL, &attr)) != 0) {
3230 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3234 if(piece <= (int) WhiteKing)
3235 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3239 xpmJailSquare = xpmLightSquare;
3243 fprintf(stderr, _("\nLoading XPMs...\n"));
3246 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3247 fprintf(stderr, "%d ", piece+1);
3248 for (kind=0; kind<4; kind++) {
3249 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3250 ExpandPathName(appData.pixmapDirectory),
3251 piece > (int) WhiteKing ? "w" : "",
3252 pieceBitmapNames[piece],
3254 if (appData.debugMode) {
3255 fprintf(stderr, _("(File:%s:) "), buf);
3257 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3258 &(xpmPieceBitmap2[kind][piece]),
3259 NULL, &attr)) != 0) {
3260 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3261 // [HGM] missing: read of unorthodox piece failed; substitute King.
3262 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3263 ExpandPathName(appData.pixmapDirectory),
3265 if (appData.debugMode) {
3266 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3268 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3269 &(xpmPieceBitmap2[kind][piece]),
3273 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3278 if(piece <= (int) WhiteKing)
3279 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3282 /* Load light and dark squares */
3283 /* If the LSQ and DSQ pieces don't exist, we will
3284 draw them with solid squares. */
3285 fprintf(stderr, _("light square "));
3286 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3287 if (access(buf, 0) != 0) {
3291 if (appData.debugMode)
3292 fprintf(stderr, _("(File:%s:) "), buf);
3294 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3295 &xpmLightSquare, NULL, &attr)) != 0) {
3296 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3299 fprintf(stderr, _("dark square "));
3300 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3301 ExpandPathName(appData.pixmapDirectory), ss);
3302 if (appData.debugMode) {
3303 fprintf(stderr, _("(File:%s:) "), buf);
3305 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3306 &xpmDarkSquare, NULL, &attr)) != 0) {
3307 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3311 xpmJailSquare = xpmLightSquare;
3312 fprintf(stderr, _("Done.\n"));
3314 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3317 #endif /* HAVE_LIBXPM */
3320 /* No built-in bitmaps */
3325 u_int ss = squareSize;
3327 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3330 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3331 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3332 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3333 pieceBitmapNames[piece],
3334 ss, kind == SOLID ? 's' : 'o');
3335 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3336 if(piece <= (int)WhiteKing)
3337 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3341 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3345 /* With built-in bitmaps */
3348 BuiltInBits* bib = builtInBits;
3351 u_int ss = squareSize;
3353 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3356 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3358 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3359 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3360 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3361 pieceBitmapNames[piece],
3362 ss, kind == SOLID ? 's' : 'o');
3363 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3364 bib->bits[kind][piece], ss, ss);
3365 if(piece <= (int)WhiteKing)
3366 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3370 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3375 void ReadBitmap(pm, name, bits, wreq, hreq)
3378 unsigned char bits[];
3384 char msg[MSG_SIZ], fullname[MSG_SIZ];
3386 if (*appData.bitmapDirectory != NULLCHAR) {
3387 strcpy(fullname, appData.bitmapDirectory);
3388 strcat(fullname, "/");
3389 strcat(fullname, name);
3390 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3391 &w, &h, pm, &x_hot, &y_hot);
3392 fprintf(stderr, "load %s\n", name);
3393 if (errcode != BitmapSuccess) {
3395 case BitmapOpenFailed:
3396 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3398 case BitmapFileInvalid:
3399 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3401 case BitmapNoMemory:
3402 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3406 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3410 fprintf(stderr, _("%s: %s...using built-in\n"),
3412 } else if (w != wreq || h != hreq) {
3414 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3415 programName, fullname, w, h, wreq, hreq);
3421 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3430 if (lineGap == 0) return;
3432 /* [HR] Split this into 2 loops for non-square boards. */
3434 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3435 gridSegments[i].x1 = 0;
3436 gridSegments[i].x2 =
3437 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3438 gridSegments[i].y1 = gridSegments[i].y2
3439 = lineGap / 2 + (i * (squareSize + lineGap));
3442 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3443 gridSegments[j + i].y1 = 0;
3444 gridSegments[j + i].y2 =
3445 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3446 gridSegments[j + i].x1 = gridSegments[j + i].x2
3447 = lineGap / 2 + (j * (squareSize + lineGap));
3451 static void MenuBarSelect(w, addr, index)
3456 XtActionProc proc = (XtActionProc) addr;
3458 (proc)(NULL, NULL, NULL, NULL);
3461 void CreateMenuBarPopup(parent, name, mb)
3471 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3474 XtSetArg(args[j], XtNleftMargin, 20); j++;
3475 XtSetArg(args[j], XtNrightMargin, 20); j++;
3477 while (mi->string != NULL) {
3478 if (strcmp(mi->string, "----") == 0) {
3479 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3482 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3483 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3485 XtAddCallback(entry, XtNcallback,
3486 (XtCallbackProc) MenuBarSelect,
3487 (caddr_t) mi->proc);
3493 Widget CreateMenuBar(mb)
3497 Widget anchor, menuBar;
3499 char menuName[MSG_SIZ];
3502 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3503 XtSetArg(args[j], XtNvSpace, 0); j++;
3504 XtSetArg(args[j], XtNborderWidth, 0); j++;
3505 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3506 formWidget, args, j);
3508 while (mb->name != NULL) {
3509 strcpy(menuName, "menu");
3510 strcat(menuName, mb->name);
3512 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3515 shortName[0] = _(mb->name)[0];
3516 shortName[1] = NULLCHAR;
3517 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3520 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3523 XtSetArg(args[j], XtNborderWidth, 0); j++;
3524 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3526 CreateMenuBarPopup(menuBar, menuName, mb);
3532 Widget CreateButtonBar(mi)
3536 Widget button, buttonBar;
3540 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3542 XtSetArg(args[j], XtNhSpace, 0); j++;
3544 XtSetArg(args[j], XtNborderWidth, 0); j++;
3545 XtSetArg(args[j], XtNvSpace, 0); j++;
3546 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3547 formWidget, args, j);
3549 while (mi->string != NULL) {
3552 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3553 XtSetArg(args[j], XtNborderWidth, 0); j++;
3555 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3556 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3557 buttonBar, args, j);
3558 XtAddCallback(button, XtNcallback,
3559 (XtCallbackProc) MenuBarSelect,
3560 (caddr_t) mi->proc);
3567 CreatePieceMenu(name, color)
3574 ChessSquare selection;
3576 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3577 boardWidget, args, 0);
3579 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3580 String item = pieceMenuStrings[color][i];
3582 if (strcmp(item, "----") == 0) {
3583 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3586 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3587 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3589 selection = pieceMenuTranslation[color][i];
3590 XtAddCallback(entry, XtNcallback,
3591 (XtCallbackProc) PieceMenuSelect,
3592 (caddr_t) selection);
3593 if (selection == WhitePawn || selection == BlackPawn) {
3594 XtSetArg(args[0], XtNpopupOnEntry, entry);
3595 XtSetValues(menu, args, 1);
3608 ChessSquare selection;
3610 whitePieceMenu = CreatePieceMenu("menuW", 0);
3611 blackPieceMenu = CreatePieceMenu("menuB", 1);
3613 XtRegisterGrabAction(PieceMenuPopup, True,
3614 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3615 GrabModeAsync, GrabModeAsync);
3617 XtSetArg(args[0], XtNlabel, _("Drop"));
3618 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3619 boardWidget, args, 1);
3620 for (i = 0; i < DROP_MENU_SIZE; i++) {
3621 String item = dropMenuStrings[i];
3623 if (strcmp(item, "----") == 0) {
3624 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3627 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3628 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3630 selection = dropMenuTranslation[i];
3631 XtAddCallback(entry, XtNcallback,
3632 (XtCallbackProc) DropMenuSelect,
3633 (caddr_t) selection);
3638 void SetupDropMenu()
3646 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3647 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3648 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3649 dmEnables[i].piece);
3650 XtSetSensitive(entry, p != NULL || !appData.testLegality
3651 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3652 && !appData.icsActive));
3654 while (p && *p++ == dmEnables[i].piece) count++;
3655 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3657 XtSetArg(args[j], XtNlabel, label); j++;
3658 XtSetValues(entry, args, j);
3662 void PieceMenuPopup(w, event, params, num_params)
3666 Cardinal *num_params;
3669 if (event->type != ButtonPress) return;
3670 if (errorUp) ErrorPopDown();
3674 whichMenu = params[0];
3676 case IcsPlayingWhite:
3677 case IcsPlayingBlack:
3679 case MachinePlaysWhite:
3680 case MachinePlaysBlack:
3681 if (appData.testLegality &&
3682 gameInfo.variant != VariantBughouse &&
3683 gameInfo.variant != VariantCrazyhouse) return;
3685 whichMenu = "menuD";
3691 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3692 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3693 pmFromX = pmFromY = -1;
3697 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3699 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3701 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3704 static void PieceMenuSelect(w, piece, junk)
3709 if (pmFromX < 0 || pmFromY < 0) return;
3710 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3713 static void DropMenuSelect(w, piece, junk)
3718 if (pmFromX < 0 || pmFromY < 0) return;
3719 DropMenuEvent(piece, pmFromX, pmFromY);
3722 void WhiteClock(w, event, prms, nprms)
3728 if (gameMode == EditPosition || gameMode == IcsExamining) {
3729 SetWhiteToPlayEvent();
3730 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3735 void BlackClock(w, event, prms, nprms)
3741 if (gameMode == EditPosition || gameMode == IcsExamining) {
3742 SetBlackToPlayEvent();
3743 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3750 * If the user selects on a border boundary, return -1; if off the board,
3751 * return -2. Otherwise map the event coordinate to the square.
3753 int EventToSquare(x, limit)
3761 if ((x % (squareSize + lineGap)) >= squareSize)
3763 x /= (squareSize + lineGap);
3769 static void do_flash_delay(msec)
3775 static void drawHighlight(file, rank, gc)
3781 if (lineGap == 0 || appData.blindfold) return;
3784 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3785 (squareSize + lineGap);
3786 y = lineGap/2 + rank * (squareSize + lineGap);
3788 x = lineGap/2 + file * (squareSize + lineGap);
3789 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3790 (squareSize + lineGap);
3793 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3794 squareSize+lineGap, squareSize+lineGap);
3797 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3798 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3801 SetHighlights(fromX, fromY, toX, toY)
3802 int fromX, fromY, toX, toY;
3804 if (hi1X != fromX || hi1Y != fromY) {
3805 if (hi1X >= 0 && hi1Y >= 0) {
3806 drawHighlight(hi1X, hi1Y, lineGC);
3808 if (fromX >= 0 && fromY >= 0) {
3809 drawHighlight(fromX, fromY, highlineGC);
3812 if (hi2X != toX || hi2Y != toY) {
3813 if (hi2X >= 0 && hi2Y >= 0) {
3814 drawHighlight(hi2X, hi2Y, lineGC);
3816 if (toX >= 0 && toY >= 0) {
3817 drawHighlight(toX, toY, highlineGC);
3829 SetHighlights(-1, -1, -1, -1);
3834 SetPremoveHighlights(fromX, fromY, toX, toY)
3835 int fromX, fromY, toX, toY;
3837 if (pm1X != fromX || pm1Y != fromY) {
3838 if (pm1X >= 0 && pm1Y >= 0) {
3839 drawHighlight(pm1X, pm1Y, lineGC);
3841 if (fromX >= 0 && fromY >= 0) {
3842 drawHighlight(fromX, fromY, prelineGC);
3845 if (pm2X != toX || pm2Y != toY) {
3846 if (pm2X >= 0 && pm2Y >= 0) {
3847 drawHighlight(pm2X, pm2Y, lineGC);
3849 if (toX >= 0 && toY >= 0) {
3850 drawHighlight(toX, toY, prelineGC);
3860 ClearPremoveHighlights()
3862 SetPremoveHighlights(-1, -1, -1, -1);
3865 static void BlankSquare(x, y, color, piece, dest)
3870 if (useImages && useImageSqs) {
3874 pm = xpmLightSquare;
3879 case 2: /* neutral */
3884 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3885 squareSize, squareSize, x, y);
3895 case 2: /* neutral */
3900 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3905 I split out the routines to draw a piece so that I could
3906 make a generic flash routine.
3908 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3910 int square_color, x, y;
3913 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3914 switch (square_color) {
3916 case 2: /* neutral */
3918 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3919 ? *pieceToOutline(piece)
3920 : *pieceToSolid(piece),
3921 dest, bwPieceGC, 0, 0,
3922 squareSize, squareSize, x, y);
3925 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3926 ? *pieceToSolid(piece)
3927 : *pieceToOutline(piece),
3928 dest, wbPieceGC, 0, 0,
3929 squareSize, squareSize, x, y);
3934 static void monoDrawPiece(piece, square_color, x, y, dest)
3936 int square_color, x, y;
3939 switch (square_color) {
3941 case 2: /* neutral */
3943 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3944 ? *pieceToOutline(piece)
3945 : *pieceToSolid(piece),
3946 dest, bwPieceGC, 0, 0,
3947 squareSize, squareSize, x, y, 1);
3950 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3951 ? *pieceToSolid(piece)
3952 : *pieceToOutline(piece),
3953 dest, wbPieceGC, 0, 0,
3954 squareSize, squareSize, x, y, 1);
3959 static void colorDrawPiece(piece, square_color, x, y, dest)
3961 int square_color, x, y;
3964 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3965 switch (square_color) {
3967 XCopyPlane(xDisplay, *pieceToSolid(piece),
3968 dest, (int) piece < (int) BlackPawn
3969 ? wlPieceGC : blPieceGC, 0, 0,
3970 squareSize, squareSize, x, y, 1);
3973 XCopyPlane(xDisplay, *pieceToSolid(piece),
3974 dest, (int) piece < (int) BlackPawn
3975 ? wdPieceGC : bdPieceGC, 0, 0,
3976 squareSize, squareSize, x, y, 1);
3978 case 2: /* neutral */
3980 XCopyPlane(xDisplay, *pieceToSolid(piece),
3981 dest, (int) piece < (int) BlackPawn
3982 ? wjPieceGC : bjPieceGC, 0, 0,
3983 squareSize, squareSize, x, y, 1);
3988 static void colorDrawPieceImage(piece, square_color, x, y, dest)
3990 int square_color, x, y;
3995 switch (square_color) {
3997 case 2: /* neutral */
3999 if ((int)piece < (int) BlackPawn) {
4007 if ((int)piece < (int) BlackPawn) {
4015 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4016 dest, wlPieceGC, 0, 0,
4017 squareSize, squareSize, x, y);
4020 typedef void (*DrawFunc)();
4022 DrawFunc ChooseDrawFunc()
4024 if (appData.monoMode) {
4025 if (DefaultDepth(xDisplay, xScreen) == 1) {
4026 return monoDrawPiece_1bit;
4028 return monoDrawPiece;
4032 return colorDrawPieceImage;
4034 return colorDrawPiece;
4038 /* [HR] determine square color depending on chess variant. */
4039 static int SquareColor(row, column)
4044 if (gameInfo.variant == VariantXiangqi) {
4045 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4047 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4049 } else if (row <= 4) {
4055 square_color = ((column + row) % 2) == 1;
4058 /* [hgm] holdings: next line makes all holdings squares light */
4059 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4061 return square_color;
4064 void DrawSquare(row, column, piece, do_flash)
4065 int row, column, do_flash;
4068 int square_color, x, y, direction, font_ascent, font_descent;
4071 XCharStruct overall;
4075 /* Calculate delay in milliseconds (2-delays per complete flash) */
4076 flash_delay = 500 / appData.flashRate;
4079 x = lineGap + ((BOARD_WIDTH-1)-column) *
4080 (squareSize + lineGap);
4081 y = lineGap + row * (squareSize + lineGap);
4083 x = lineGap + column * (squareSize + lineGap);
4084 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4085 (squareSize + lineGap);
4088 square_color = SquareColor(row, column);
4090 if ( // [HGM] holdings: blank out area between board and holdings
4091 column == BOARD_LEFT-1 || column == BOARD_RGHT
4092 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4093 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4094 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4096 // [HGM] print piece counts next to holdings
4097 string[1] = NULLCHAR;
4098 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4099 string[0] = '0' + piece;
4100 XTextExtents(countFontStruct, string, 1, &direction,
4101 &font_ascent, &font_descent, &overall);
4102 if (appData.monoMode) {
4103 XDrawImageString(xDisplay, xBoardWindow, countGC,
4104 x + squareSize - overall.width - 2,
4105 y + font_ascent + 1, string, 1);
4107 XDrawString(xDisplay, xBoardWindow, countGC,
4108 x + squareSize - overall.width - 2,
4109 y + font_ascent + 1, string, 1);
4112 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4113 string[0] = '0' + piece;
4114 XTextExtents(countFontStruct, string, 1, &direction,
4115 &font_ascent, &font_descent, &overall);
4116 if (appData.monoMode) {
4117 XDrawImageString(xDisplay, xBoardWindow, countGC,
4118 x + 2, y + font_ascent + 1, string, 1);
4120 XDrawString(xDisplay, xBoardWindow, countGC,
4121 x + 2, y + font_ascent + 1, string, 1);
4125 if (piece == EmptySquare || appData.blindfold) {
4126 BlankSquare(x, y, square_color, piece, xBoardWindow);
4128 drawfunc = ChooseDrawFunc();
4129 if (do_flash && appData.flashCount > 0) {
4130 for (i=0; i<appData.flashCount; ++i) {
4132 drawfunc(piece, square_color, x, y, xBoardWindow);
4133 XSync(xDisplay, False);
4134 do_flash_delay(flash_delay);
4136 BlankSquare(x, y, square_color, piece, xBoardWindow);
4137 XSync(xDisplay, False);
4138 do_flash_delay(flash_delay);
4141 drawfunc(piece, square_color, x, y, xBoardWindow);
4145 string[1] = NULLCHAR;
4146 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4147 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4148 string[0] = 'a' + column - BOARD_LEFT;
4149 XTextExtents(coordFontStruct, string, 1, &direction,
4150 &font_ascent, &font_descent, &overall);
4151 if (appData.monoMode) {
4152 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4153 x + squareSize - overall.width - 2,
4154 y + squareSize - font_descent - 1, string, 1);
4156 XDrawString(xDisplay, xBoardWindow, coordGC,
4157 x + squareSize - overall.width - 2,
4158 y + squareSize - font_descent - 1, string, 1);
4161 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4162 string[0] = ONE + row;
4163 XTextExtents(coordFontStruct, string, 1, &direction,
4164 &font_ascent, &font_descent, &overall);
4165 if (appData.monoMode) {
4166 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4167 x + 2, y + font_ascent + 1, string, 1);
4169 XDrawString(xDisplay, xBoardWindow, coordGC,
4170 x + 2, y + font_ascent + 1, string, 1);
4176 /* Why is this needed on some versions of X? */
4177 void EventProc(widget, unused, event)
4182 if (!XtIsRealized(widget))
4185 switch (event->type) {
4187 if (event->xexpose.count > 0) return; /* no clipping is done */
4188 XDrawPosition(widget, True, NULL);
4196 void DrawPosition(fullRedraw, board)
4197 /*Boolean*/int fullRedraw;
4200 XDrawPosition(boardWidget, fullRedraw, board);
4203 /* Returns 1 if there are "too many" differences between b1 and b2
4204 (i.e. more than 1 move was made) */
4205 static int too_many_diffs(b1, b2)
4211 for (i=0; i<BOARD_HEIGHT; ++i) {
4212 for (j=0; j<BOARD_WIDTH; ++j) {
4213 if (b1[i][j] != b2[i][j]) {
4214 if (++c > 4) /* Castling causes 4 diffs */
4223 /* Matrix describing castling maneuvers */
4224 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4225 static int castling_matrix[4][5] = {
4226 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4227 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4228 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4229 { 7, 7, 4, 5, 6 } /* 0-0, black */
4232 /* Checks whether castling occurred. If it did, *rrow and *rcol
4233 are set to the destination (row,col) of the rook that moved.
4235 Returns 1 if castling occurred, 0 if not.
4237 Note: Only handles a max of 1 castling move, so be sure
4238 to call too_many_diffs() first.
4240 static int check_castle_draw(newb, oldb, rrow, rcol)
4247 /* For each type of castling... */
4248 for (i=0; i<4; ++i) {
4249 r = castling_matrix[i];
4251 /* Check the 4 squares involved in the castling move */
4253 for (j=1; j<=4; ++j) {
4254 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4261 /* All 4 changed, so it must be a castling move */
4270 static int damage[BOARD_RANKS][BOARD_FILES];
4273 * event handler for redrawing the board
4275 void XDrawPosition(w, repaint, board)
4277 /*Boolean*/int repaint;
4281 static int lastFlipView = 0;
4282 static int lastBoardValid = 0;
4283 static Board lastBoard;
4287 if (board == NULL) {
4288 if (!lastBoardValid) return;
4291 if (!lastBoardValid || lastFlipView != flipView) {
4292 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4293 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4298 * It would be simpler to clear the window with XClearWindow()
4299 * but this causes a very distracting flicker.
4302 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4304 /* If too much changes (begin observing new game, etc.), don't
4306 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4308 /* Special check for castling so we don't flash both the king
4309 and the rook (just flash the king). */
4311 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4312 /* Draw rook with NO flashing. King will be drawn flashing later */
4313 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4314 lastBoard[rrow][rcol] = board[rrow][rcol];
4318 /* First pass -- Draw (newly) empty squares and repair damage.
4319 This prevents you from having a piece show up twice while it
4320 is flashing on its new square */
4321 for (i = 0; i < BOARD_HEIGHT; i++)
4322 for (j = 0; j < BOARD_WIDTH; j++)
4323 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4325 DrawSquare(i, j, board[i][j], 0);
4326 damage[i][j] = False;
4329 /* Second pass -- Draw piece(s) in new position and flash them */
4330 for (i = 0; i < BOARD_HEIGHT; i++)
4331 for (j = 0; j < BOARD_WIDTH; j++)
4332 if (board[i][j] != lastBoard[i][j]) {
4333 DrawSquare(i, j, board[i][j], do_flash);
4337 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4338 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4340 for (i = 0; i < BOARD_HEIGHT; i++)
4341 for (j = 0; j < BOARD_WIDTH; j++) {
4342 DrawSquare(i, j, board[i][j], 0);
4343 damage[i][j] = False;
4347 CopyBoard(lastBoard, board);
4349 lastFlipView = flipView;
4351 /* Draw highlights */
4352 if (pm1X >= 0 && pm1Y >= 0) {
4353 drawHighlight(pm1X, pm1Y, prelineGC);
4355 if (pm2X >= 0 && pm2Y >= 0) {
4356 drawHighlight(pm2X, pm2Y, prelineGC);
4358 if (hi1X >= 0 && hi1Y >= 0) {
4359 drawHighlight(hi1X, hi1Y, highlineGC);
4361 if (hi2X >= 0 && hi2Y >= 0) {
4362 drawHighlight(hi2X, hi2Y, highlineGC);
4365 /* If piece being dragged around board, must redraw that too */
4368 XSync(xDisplay, False);
4373 * event handler for redrawing the board
4375 void DrawPositionProc(w, event, prms, nprms)
4381 XDrawPosition(w, True, NULL);
4386 * event handler for parsing user moves
4388 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4389 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4390 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4391 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4392 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4393 // and at the end FinishMove() to perform the move after optional promotion popups.
4394 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4395 void HandleUserMove(w, event, prms, nprms)
4401 if (w != boardWidget || errorExitStatus != -1) return;
4404 if (event->type == ButtonPress) {
4405 XtPopdown(promotionShell);
4406 XtDestroyWidget(promotionShell);
4407 promotionUp = False;
4415 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4416 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4417 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4420 void AnimateUserMove (Widget w, XEvent * event,
4421 String * params, Cardinal * nParams)
4423 DragPieceMove(event->xmotion.x, event->xmotion.y);
4426 Widget CommentCreate(name, text, mutable, callback, lines)
4428 int /*Boolean*/ mutable;
4429 XtCallbackProc callback;
4433 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4438 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4439 XtGetValues(boardWidget, args, j);
4442 XtSetArg(args[j], XtNresizable, True); j++;
4445 XtCreatePopupShell(name, topLevelShellWidgetClass,
4446 shellWidget, args, j);
4449 XtCreatePopupShell(name, transientShellWidgetClass,
4450 shellWidget, args, j);
4453 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4454 layoutArgs, XtNumber(layoutArgs));
4456 XtCreateManagedWidget("form", formWidgetClass, layout,
4457 formArgs, XtNumber(formArgs));
4461 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4462 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4464 XtSetArg(args[j], XtNstring, text); j++;
4465 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4466 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4467 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4468 XtSetArg(args[j], XtNright, XtChainRight); j++;
4469 XtSetArg(args[j], XtNresizable, True); j++;
4470 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4471 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4472 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4473 XtSetArg(args[j], XtNautoFill, True); j++;
4474 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4476 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4480 XtSetArg(args[j], XtNfromVert, edit); j++;
4481 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4482 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4483 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4484 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4486 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4487 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4490 XtSetArg(args[j], XtNfromVert, edit); j++;
4491 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4492 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4493 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4494 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4495 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4497 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4498 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4501 XtSetArg(args[j], XtNfromVert, edit); j++;
4502 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4503 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4504 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4505 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4506 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4508 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4509 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4512 XtSetArg(args[j], XtNfromVert, edit); j++;
4513 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4514 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4515 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4516 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4518 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4519 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4522 XtSetArg(args[j], XtNfromVert, edit); j++;
4523 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4524 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4525 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4526 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4527 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4529 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4530 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4533 XtRealizeWidget(shell);
4535 if (commentX == -1) {
4538 Dimension pw_height;
4539 Dimension ew_height;
4542 XtSetArg(args[j], XtNheight, &ew_height); j++;
4543 XtGetValues(edit, args, j);
4546 XtSetArg(args[j], XtNheight, &pw_height); j++;
4547 XtGetValues(shell, args, j);
4548 commentH = pw_height + (lines - 1) * ew_height;
4549 commentW = bw_width - 16;
4551 XSync(xDisplay, False);
4553 /* This code seems to tickle an X bug if it is executed too soon
4554 after xboard starts up. The coordinates get transformed as if
4555 the main window was positioned at (0, 0).
4557 XtTranslateCoords(shellWidget,
4558 (bw_width - commentW) / 2, 0 - commentH / 2,
4559 &commentX, &commentY);
4561 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4562 RootWindowOfScreen(XtScreen(shellWidget)),
4563 (bw_width - commentW) / 2, 0 - commentH / 2,
4568 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4571 if(wpComment.width > 0) {
4572 commentX = wpComment.x;
4573 commentY = wpComment.y;
4574 commentW = wpComment.width;
4575 commentH = wpComment.height;
4579 XtSetArg(args[j], XtNheight, commentH); j++;
4580 XtSetArg(args[j], XtNwidth, commentW); j++;
4581 XtSetArg(args[j], XtNx, commentX); j++;
4582 XtSetArg(args[j], XtNy, commentY); j++;
4583 XtSetValues(shell, args, j);
4584 XtSetKeyboardFocus(shell, edit);
4589 /* Used for analysis window and ICS input window */
4590 Widget MiscCreate(name, text, mutable, callback, lines)
4592 int /*Boolean*/ mutable;
4593 XtCallbackProc callback;
4597 Widget shell, layout, form, edit;
4599 Dimension bw_width, pw_height, ew_height, w, h;
4605 XtSetArg(args[j], XtNresizable, True); j++;
4608 XtCreatePopupShell(name, topLevelShellWidgetClass,
4609 shellWidget, args, j);
4612 XtCreatePopupShell(name, transientShellWidgetClass,
4613 shellWidget, args, j);
4616 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4617 layoutArgs, XtNumber(layoutArgs));
4619 XtCreateManagedWidget("form", formWidgetClass, layout,
4620 formArgs, XtNumber(formArgs));
4624 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4625 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4627 XtSetArg(args[j], XtNstring, text); j++;
4628 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4629 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4630 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4631 XtSetArg(args[j], XtNright, XtChainRight); j++;
4632 XtSetArg(args[j], XtNresizable, True); j++;
4633 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4634 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4635 XtSetArg(args[j], XtNautoFill, True); j++;
4636 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4638 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4640 XtRealizeWidget(shell);
4643 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4644 XtGetValues(boardWidget, args, j);
4647 XtSetArg(args[j], XtNheight, &ew_height); j++;
4648 XtGetValues(edit, args, j);
4651 XtSetArg(args[j], XtNheight, &pw_height); j++;
4652 XtGetValues(shell, args, j);
4653 h = pw_height + (lines - 1) * ew_height;
4656 XSync(xDisplay, False);
4658 /* This code seems to tickle an X bug if it is executed too soon
4659 after xboard starts up. The coordinates get transformed as if
4660 the main window was positioned at (0, 0).
4662 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4664 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4665 RootWindowOfScreen(XtScreen(shellWidget)),
4666 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4670 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4673 XtSetArg(args[j], XtNheight, h); j++;
4674 XtSetArg(args[j], XtNwidth, w); j++;
4675 XtSetArg(args[j], XtNx, x); j++;
4676 XtSetArg(args[j], XtNy, y); j++;
4677 XtSetValues(shell, args, j);
4683 static int savedIndex; /* gross that this is global */
4685 void EditCommentPopUp(index, title, text)
4694 if (text == NULL) text = "";
4696 if (editShell == NULL) {
4698 CommentCreate(title, text, True, EditCommentCallback, 4);
4699 XtRealizeWidget(editShell);
4700 CatchDeleteWindow(editShell, "EditCommentPopDown");
4702 edit = XtNameToWidget(editShell, "*form.text");
4704 XtSetArg(args[j], XtNstring, text); j++;
4705 XtSetValues(edit, args, j);
4707 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4708 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4709 XtSetValues(editShell, args, j);
4712 XtPopup(editShell, XtGrabNone);
4716 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4717 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4721 void EditCommentCallback(w, client_data, call_data)
4723 XtPointer client_data, call_data;
4731 XtSetArg(args[j], XtNlabel, &name); j++;
4732 XtGetValues(w, args, j);
4734 if (strcmp(name, _("ok")) == 0) {
4735 edit = XtNameToWidget(editShell, "*form.text");
4737 XtSetArg(args[j], XtNstring, &val); j++;
4738 XtGetValues(edit, args, j);
4739 ReplaceComment(savedIndex, val);
4740 EditCommentPopDown();
4741 } else if (strcmp(name, _("cancel")) == 0) {
4742 EditCommentPopDown();
4743 } else if (strcmp(name, _("clear")) == 0) {
4744 edit = XtNameToWidget(editShell, "*form.text");
4745 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4746 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4750 void EditCommentPopDown()
4755 if (!editUp) return;
4757 XtSetArg(args[j], XtNx, &commentX); j++;
4758 XtSetArg(args[j], XtNy, &commentY); j++;
4759 XtSetArg(args[j], XtNheight, &commentH); j++;
4760 XtSetArg(args[j], XtNwidth, &commentW); j++;
4761 XtGetValues(editShell, args, j);
4762 XtPopdown(editShell);
4765 XtSetArg(args[j], XtNleftBitmap, None); j++;
4766 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4770 void ICSInputBoxPopUp()
4775 char *title = _("ICS Input");
4778 if (ICSInputShell == NULL) {
4779 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4780 tr = XtParseTranslationTable(ICSInputTranslations);
4781 edit = XtNameToWidget(ICSInputShell, "*form.text");
4782 XtOverrideTranslations(edit, tr);
4783 XtRealizeWidget(ICSInputShell);
4784 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4787 edit = XtNameToWidget(ICSInputShell, "*form.text");
4789 XtSetArg(args[j], XtNstring, ""); j++;
4790 XtSetValues(edit, args, j);
4792 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4793 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4794 XtSetValues(ICSInputShell, args, j);
4797 XtPopup(ICSInputShell, XtGrabNone);
4798 XtSetKeyboardFocus(ICSInputShell, edit);
4800 ICSInputBoxUp = True;
4802 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4803 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4807 void ICSInputSendText()
4814 edit = XtNameToWidget(ICSInputShell, "*form.text");
4816 XtSetArg(args[j], XtNstring, &val); j++;
4817 XtGetValues(edit, args, j);
4818 SendMultiLineToICS(val);
4819 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4820 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4823 void ICSInputBoxPopDown()
4828 if (!ICSInputBoxUp) return;
4830 XtPopdown(ICSInputShell);
4831 ICSInputBoxUp = False;
4833 XtSetArg(args[j], XtNleftBitmap, None); j++;
4834 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4838 void CommentPopUp(title, text)
4845 if (commentShell == NULL) {
4847 CommentCreate(title, text, False, CommentCallback, 4);
4848 XtRealizeWidget(commentShell);
4849 CatchDeleteWindow(commentShell, "CommentPopDown");
4851 edit = XtNameToWidget(commentShell, "*form.text");
4853 XtSetArg(args[j], XtNstring, text); j++;
4854 XtSetValues(edit, args, j);
4856 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4857 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4858 XtSetValues(commentShell, args, j);
4861 XtPopup(commentShell, XtGrabNone);
4862 XSync(xDisplay, False);
4867 void CommentCallback(w, client_data, call_data)
4869 XtPointer client_data, call_data;
4876 XtSetArg(args[j], XtNlabel, &name); j++;
4877 XtGetValues(w, args, j);
4879 if (strcmp(name, _("close")) == 0) {
4881 } else if (strcmp(name, _("edit")) == 0) {
4888 void CommentPopDown()
4893 if (!commentUp) return;
4895 XtSetArg(args[j], XtNx, &commentX); j++;
4896 XtSetArg(args[j], XtNy, &commentY); j++;
4897 XtSetArg(args[j], XtNwidth, &commentW); j++;
4898 XtSetArg(args[j], XtNheight, &commentH); j++;
4899 XtGetValues(commentShell, args, j);
4900 XtPopdown(commentShell);
4901 XSync(xDisplay, False);
4905 void FileNamePopUp(label, def, proc, openMode)
4912 Widget popup, layout, dialog, edit;
4918 fileProc = proc; /* I can't see a way not */
4919 fileOpenMode = openMode; /* to use globals here */
4922 XtSetArg(args[i], XtNresizable, True); i++;
4923 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4924 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4925 fileNameShell = popup =
4926 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4927 shellWidget, args, i);
4930 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4931 layoutArgs, XtNumber(layoutArgs));
4934 XtSetArg(args[i], XtNlabel, label); i++;
4935 XtSetArg(args[i], XtNvalue, def); i++;
4936 XtSetArg(args[i], XtNborderWidth, 0); i++;
4937 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4940 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4941 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4942 (XtPointer) dialog);
4944 XtRealizeWidget(popup);
4945 CatchDeleteWindow(popup, "FileNamePopDown");
4947 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4948 &x, &y, &win_x, &win_y, &mask);
4950 XtSetArg(args[0], XtNx, x - 10);
4951 XtSetArg(args[1], XtNy, y - 30);
4952 XtSetValues(popup, args, 2);
4954 XtPopup(popup, XtGrabExclusive);
4957 edit = XtNameToWidget(dialog, "*value");
4958 XtSetKeyboardFocus(popup, edit);
4961 void FileNamePopDown()
4963 if (!filenameUp) return;
4964 XtPopdown(fileNameShell);
4965 XtDestroyWidget(fileNameShell);
4970 void FileNameCallback(w, client_data, call_data)
4972 XtPointer client_data, call_data;
4977 XtSetArg(args[0], XtNlabel, &name);
4978 XtGetValues(w, args, 1);
4980 if (strcmp(name, _("cancel")) == 0) {
4985 FileNameAction(w, NULL, NULL, NULL);
4988 void FileNameAction(w, event, prms, nprms)
5000 name = XawDialogGetValueString(w = XtParent(w));
5002 if ((name != NULL) && (*name != NULLCHAR)) {
5004 XtPopdown(w = XtParent(XtParent(w)));
5008 p = strrchr(buf, ' ');
5015 fullname = ExpandPathName(buf);
5017 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5020 f = fopen(fullname, fileOpenMode);
5022 DisplayError(_("Failed to open file"), errno);
5024 (void) (*fileProc)(f, index, buf);
5031 XtPopdown(w = XtParent(XtParent(w)));
5037 void PromotionPopUp()
5040 Widget dialog, layout;
5042 Dimension bw_width, pw_width;
5046 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5047 XtGetValues(boardWidget, args, j);
5050 XtSetArg(args[j], XtNresizable, True); j++;
5051 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5053 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5054 shellWidget, args, j);
5056 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5057 layoutArgs, XtNumber(layoutArgs));
5060 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5061 XtSetArg(args[j], XtNborderWidth, 0); j++;
5062 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5065 if(gameInfo.variant != VariantShogi) {
5066 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5067 (XtPointer) dialog);
5068 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5069 (XtPointer) dialog);
5070 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5071 (XtPointer) dialog);
5072 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5073 (XtPointer) dialog);
5074 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5075 gameInfo.variant == VariantGiveaway) {
5076 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5077 (XtPointer) dialog);
5079 if(gameInfo.variant == VariantCapablanca ||
5080 gameInfo.variant == VariantGothic ||
5081 gameInfo.variant == VariantCapaRandom) {
5082 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5083 (XtPointer) dialog);
5084 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5085 (XtPointer) dialog);
5087 } else // [HGM] shogi
5089 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5090 (XtPointer) dialog);
5091 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5092 (XtPointer) dialog);
5094 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5095 (XtPointer) dialog);
5097 XtRealizeWidget(promotionShell);
5098 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5101 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5102 XtGetValues(promotionShell, args, j);
5104 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5105 lineGap + squareSize/3 +
5106 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5107 0 : 6*(squareSize + lineGap)), &x, &y);
5110 XtSetArg(args[j], XtNx, x); j++;
5111 XtSetArg(args[j], XtNy, y); j++;
5112 XtSetValues(promotionShell, args, j);
5114 XtPopup(promotionShell, XtGrabNone);
5119 void PromotionPopDown()
5121 if (!promotionUp) return;
5122 XtPopdown(promotionShell);
5123 XtDestroyWidget(promotionShell);
5124 promotionUp = False;
5127 void PromotionCallback(w, client_data, call_data)
5129 XtPointer client_data, call_data;
5135 XtSetArg(args[0], XtNlabel, &name);
5136 XtGetValues(w, args, 1);
5140 if (fromX == -1) return;
5142 if (strcmp(name, _("cancel")) == 0) {
5146 } else if (strcmp(name, _("Knight")) == 0) {
5148 } else if (strcmp(name, _("Promote")) == 0) {
5150 } else if (strcmp(name, _("Defer")) == 0) {
5153 promoChar = ToLower(name[0]);
5156 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5158 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5159 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5164 void ErrorCallback(w, client_data, call_data)
5166 XtPointer client_data, call_data;
5169 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5171 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5177 if (!errorUp) return;
5179 XtPopdown(errorShell);
5180 XtDestroyWidget(errorShell);
5181 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5184 void ErrorPopUp(title, label, modal)
5185 char *title, *label;
5189 Widget dialog, layout;
5193 Dimension bw_width, pw_width;
5194 Dimension pw_height;
5198 XtSetArg(args[i], XtNresizable, True); i++;
5199 XtSetArg(args[i], XtNtitle, title); i++;
5201 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5202 shellWidget, args, i);
5204 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5205 layoutArgs, XtNumber(layoutArgs));
5208 XtSetArg(args[i], XtNlabel, label); i++;
5209 XtSetArg(args[i], XtNborderWidth, 0); i++;
5210 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5213 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5215 XtRealizeWidget(errorShell);
5216 CatchDeleteWindow(errorShell, "ErrorPopDown");
5219 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5220 XtGetValues(boardWidget, args, i);
5222 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5223 XtSetArg(args[i], XtNheight, &pw_height); i++;
5224 XtGetValues(errorShell, args, i);
5227 /* This code seems to tickle an X bug if it is executed too soon
5228 after xboard starts up. The coordinates get transformed as if
5229 the main window was positioned at (0, 0).
5231 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5232 0 - pw_height + squareSize / 3, &x, &y);
5234 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5235 RootWindowOfScreen(XtScreen(boardWidget)),
5236 (bw_width - pw_width) / 2,
5237 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5241 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5244 XtSetArg(args[i], XtNx, x); i++;
5245 XtSetArg(args[i], XtNy, y); i++;
5246 XtSetValues(errorShell, args, i);
5249 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5252 /* Disable all user input other than deleting the window */
5253 static int frozen = 0;
5257 /* Grab by a widget that doesn't accept input */
5258 XtAddGrab(messageWidget, TRUE, FALSE);
5262 /* Undo a FreezeUI */
5265 if (!frozen) return;
5266 XtRemoveGrab(messageWidget);
5270 char *ModeToWidgetName(mode)
5274 case BeginningOfGame:
5275 if (appData.icsActive)
5276 return "menuMode.ICS Client";
5277 else if (appData.noChessProgram ||
5278 *appData.cmailGameName != NULLCHAR)
5279 return "menuMode.Edit Game";
5281 return "menuMode.Machine Black";
5282 case MachinePlaysBlack:
5283 return "menuMode.Machine Black";
5284 case MachinePlaysWhite:
5285 return "menuMode.Machine White";
5287 return "menuMode.Analysis Mode";
5289 return "menuMode.Analyze File";
5290 case TwoMachinesPlay:
5291 return "menuMode.Two Machines";
5293 return "menuMode.Edit Game";
5294 case PlayFromGameFile:
5295 return "menuFile.Load Game";
5297 return "menuMode.Edit Position";
5299 return "menuMode.Training";
5300 case IcsPlayingWhite:
5301 case IcsPlayingBlack:
5305 return "menuMode.ICS Client";
5312 void ModeHighlight()
5315 static int oldPausing = FALSE;
5316 static GameMode oldmode = (GameMode) -1;
5319 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5321 if (pausing != oldPausing) {
5322 oldPausing = pausing;
5324 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5326 XtSetArg(args[0], XtNleftBitmap, None);
5328 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5331 if (appData.showButtonBar) {
5332 /* Always toggle, don't set. Previous code messes up when
5333 invoked while the button is pressed, as releasing it
5334 toggles the state again. */
5337 XtSetArg(args[0], XtNbackground, &oldbg);
5338 XtSetArg(args[1], XtNforeground, &oldfg);
5339 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5341 XtSetArg(args[0], XtNbackground, oldfg);
5342 XtSetArg(args[1], XtNforeground, oldbg);
5344 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5348 wname = ModeToWidgetName(oldmode);
5349 if (wname != NULL) {
5350 XtSetArg(args[0], XtNleftBitmap, None);
5351 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5353 wname = ModeToWidgetName(gameMode);
5354 if (wname != NULL) {
5355 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5356 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5360 /* Maybe all the enables should be handled here, not just this one */
5361 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5362 gameMode == Training || gameMode == PlayFromGameFile);
5367 * Button/menu procedures
5369 void ResetProc(w, event, prms, nprms)
5378 int LoadGamePopUp(f, gameNumber, title)
5383 cmailMsgLoaded = FALSE;
5384 if (gameNumber == 0) {
5385 int error = GameListBuild(f);
5387 DisplayError(_("Cannot build game list"), error);
5388 } else if (!ListEmpty(&gameList) &&
5389 ((ListGame *) gameList.tailPred)->number > 1) {
5390 GameListPopUp(f, title);
5396 return LoadGame(f, gameNumber, title, FALSE);
5399 void LoadGameProc(w, event, prms, nprms)
5405 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5408 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5411 void LoadNextGameProc(w, event, prms, nprms)
5420 void LoadPrevGameProc(w, event, prms, nprms)
5429 void ReloadGameProc(w, event, prms, nprms)
5438 void LoadNextPositionProc(w, event, prms, nprms)
5447 void LoadPrevPositionProc(w, event, prms, nprms)
5456 void ReloadPositionProc(w, event, prms, nprms)
5465 void LoadPositionProc(w, event, prms, nprms)
5471 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5474 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5477 void SaveGameProc(w, event, prms, nprms)
5483 FileNamePopUp(_("Save game file name?"),
5484 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5488 void SavePositionProc(w, event, prms, nprms)
5494 FileNamePopUp(_("Save position file name?"),
5495 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5499 void ReloadCmailMsgProc(w, event, prms, nprms)
5505 ReloadCmailMsgEvent(FALSE);
5508 void MailMoveProc(w, event, prms, nprms)
5517 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5518 static char *selected_fen_position=NULL;
5521 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5522 Atom *type_return, XtPointer *value_return,
5523 unsigned long *length_return, int *format_return)
5525 char *selection_tmp;
5527 if (!selected_fen_position) return False; /* should never happen */
5528 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5529 /* note: since no XtSelectionDoneProc was registered, Xt will
5530 * automatically call XtFree on the value returned. So have to
5531 * make a copy of it allocated with XtMalloc */
5532 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5533 strcpy(selection_tmp, selected_fen_position);
5535 *value_return=selection_tmp;
5536 *length_return=strlen(selection_tmp);
5537 *type_return=*target;
5538 *format_return = 8; /* bits per byte */
5540 } else if (*target == XA_TARGETS(xDisplay)) {
5541 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5542 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5543 targets_tmp[1] = XA_STRING;
5544 *value_return = targets_tmp;
5545 *type_return = XA_ATOM;
5547 *format_return = 8 * sizeof(Atom);
5548 if (*format_return > 32) {
5549 *length_return *= *format_return / 32;
5550 *format_return = 32;
5558 /* note: when called from menu all parameters are NULL, so no clue what the
5559 * Widget which was clicked on was, or what the click event was
5561 void CopyPositionProc(w, event, prms, nprms)
5568 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5569 * have a notion of a position that is selected but not copied.
5570 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5572 if(gameMode == EditPosition) EditPositionDone(TRUE);
5573 if (selected_fen_position) free(selected_fen_position);
5574 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5575 if (!selected_fen_position) return;
5576 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5578 SendPositionSelection,
5579 NULL/* lose_ownership_proc */ ,
5580 NULL/* transfer_done_proc */);
5581 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5583 SendPositionSelection,
5584 NULL/* lose_ownership_proc */ ,
5585 NULL/* transfer_done_proc */);
5588 /* function called when the data to Paste is ready */
5590 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5591 Atom *type, XtPointer value, unsigned long *len, int *format)
5594 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5595 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5596 EditPositionPasteFEN(fenstr);
5600 /* called when Paste Position button is pressed,
5601 * all parameters will be NULL */
5602 void PastePositionProc(w, event, prms, nprms)
5608 XtGetSelectionValue(menuBarWidget,
5609 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5610 /* (XtSelectionCallbackProc) */ PastePositionCB,
5611 NULL, /* client_data passed to PastePositionCB */
5613 /* better to use the time field from the event that triggered the
5614 * call to this function, but that isn't trivial to get
5622 SendGameSelection(Widget w, Atom *selection, Atom *target,
5623 Atom *type_return, XtPointer *value_return,
5624 unsigned long *length_return, int *format_return)
5626 char *selection_tmp;
5628 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5629 FILE* f = fopen(gameCopyFilename, "r");
5632 if (f == NULL) return False;
5636 selection_tmp = XtMalloc(len + 1);
5637 count = fread(selection_tmp, 1, len, f);
5639 XtFree(selection_tmp);
5642 selection_tmp[len] = NULLCHAR;
5643 *value_return = selection_tmp;
5644 *length_return = len;
5645 *type_return = *target;
5646 *format_return = 8; /* bits per byte */
5648 } else if (*target == XA_TARGETS(xDisplay)) {
5649 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5650 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5651 targets_tmp[1] = XA_STRING;
5652 *value_return = targets_tmp;
5653 *type_return = XA_ATOM;
5655 *format_return = 8 * sizeof(Atom);
5656 if (*format_return > 32) {
5657 *length_return *= *format_return / 32;
5658 *format_return = 32;
5666 /* note: when called from menu all parameters are NULL, so no clue what the
5667 * Widget which was clicked on was, or what the click event was
5669 void CopyGameProc(w, event, prms, nprms)
5677 ret = SaveGameToFile(gameCopyFilename, FALSE);
5681 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5682 * have a notion of a game that is selected but not copied.
5683 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5685 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5688 NULL/* lose_ownership_proc */ ,
5689 NULL/* transfer_done_proc */);
5690 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5693 NULL/* lose_ownership_proc */ ,
5694 NULL/* transfer_done_proc */);
5697 /* function called when the data to Paste is ready */
5699 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5700 Atom *type, XtPointer value, unsigned long *len, int *format)
5703 if (value == NULL || *len == 0) {
5704 return; /* nothing had been selected to copy */
5706 f = fopen(gamePasteFilename, "w");
5708 DisplayError(_("Can't open temp file"), errno);
5711 fwrite(value, 1, *len, f);
5714 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5717 /* called when Paste Game button is pressed,
5718 * all parameters will be NULL */
5719 void PasteGameProc(w, event, prms, nprms)
5725 XtGetSelectionValue(menuBarWidget,
5726 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5727 /* (XtSelectionCallbackProc) */ PasteGameCB,
5728 NULL, /* client_data passed to PasteGameCB */
5730 /* better to use the time field from the event that triggered the
5731 * call to this function, but that isn't trivial to get
5741 SaveGameProc(NULL, NULL, NULL, NULL);
5745 void QuitProc(w, event, prms, nprms)
5754 void PauseProc(w, event, prms, nprms)
5764 void MachineBlackProc(w, event, prms, nprms)
5770 MachineBlackEvent();
5773 void MachineWhiteProc(w, event, prms, nprms)
5779 MachineWhiteEvent();
5782 void AnalyzeModeProc(w, event, prms, nprms)
5790 if (!first.analysisSupport) {
5791 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5792 DisplayError(buf, 0);
5795 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5796 if (appData.icsActive) {
5797 if (gameMode != IcsObserving) {
5798 sprintf(buf,_("You are not observing a game"));
5799 DisplayError(buf, 0);
5801 if (appData.icsEngineAnalyze) {
5802 if (appData.debugMode)
5803 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5809 /* if enable, use want disable icsEngineAnalyze */
5810 if (appData.icsEngineAnalyze) {
5815 appData.icsEngineAnalyze = TRUE;
5816 if (appData.debugMode)
5817 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5819 if (!appData.showThinking)
5820 ShowThinkingProc(w,event,prms,nprms);
5825 void AnalyzeFileProc(w, event, prms, nprms)
5831 if (!first.analysisSupport) {
5833 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5834 DisplayError(buf, 0);
5839 if (!appData.showThinking)
5840 ShowThinkingProc(w,event,prms,nprms);
5843 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5844 AnalysisPeriodicEvent(1);
5847 void TwoMachinesProc(w, event, prms, nprms)
5856 void IcsClientProc(w, event, prms, nprms)
5865 void EditGameProc(w, event, prms, nprms)
5874 void EditPositionProc(w, event, prms, nprms)
5880 EditPositionEvent();
5883 void TrainingProc(w, event, prms, nprms)
5892 void EditCommentProc(w, event, prms, nprms)
5899 EditCommentPopDown();
5905 void IcsInputBoxProc(w, event, prms, nprms)
5911 if (ICSInputBoxUp) {
5912 ICSInputBoxPopDown();
5918 void AcceptProc(w, event, prms, nprms)
5927 void DeclineProc(w, event, prms, nprms)
5936 void RematchProc(w, event, prms, nprms)
5945 void CallFlagProc(w, event, prms, nprms)
5954 void DrawProc(w, event, prms, nprms)
5963 void AbortProc(w, event, prms, nprms)
5972 void AdjournProc(w, event, prms, nprms)
5981 void ResignProc(w, event, prms, nprms)
5990 void AdjuWhiteProc(w, event, prms, nprms)
5996 UserAdjudicationEvent(+1);
5999 void AdjuBlackProc(w, event, prms, nprms)
6005 UserAdjudicationEvent(-1);
6008 void AdjuDrawProc(w, event, prms, nprms)
6014 UserAdjudicationEvent(0);
6017 void EnterKeyProc(w, event, prms, nprms)
6023 if (ICSInputBoxUp == True)
6027 void StopObservingProc(w, event, prms, nprms)
6033 StopObservingEvent();
6036 void StopExaminingProc(w, event, prms, nprms)
6042 StopExaminingEvent();
6046 void ForwardProc(w, event, prms, nprms)
6056 void BackwardProc(w, event, prms, nprms)
6065 void ToStartProc(w, event, prms, nprms)
6074 void ToEndProc(w, event, prms, nprms)
6083 void RevertProc(w, event, prms, nprms)
6092 void TruncateGameProc(w, event, prms, nprms)
6098 TruncateGameEvent();
6100 void RetractMoveProc(w, event, prms, nprms)
6109 void MoveNowProc(w, event, prms, nprms)
6119 void AlwaysQueenProc(w, event, prms, nprms)
6127 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6129 if (appData.alwaysPromoteToQueen) {
6130 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6132 XtSetArg(args[0], XtNleftBitmap, None);
6134 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6138 void AnimateDraggingProc(w, event, prms, nprms)
6146 appData.animateDragging = !appData.animateDragging;
6148 if (appData.animateDragging) {
6149 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6152 XtSetArg(args[0], XtNleftBitmap, None);
6154 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6158 void AnimateMovingProc(w, event, prms, nprms)
6166 appData.animate = !appData.animate;
6168 if (appData.animate) {
6169 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6172 XtSetArg(args[0], XtNleftBitmap, None);
6174 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6178 void AutocommProc(w, event, prms, nprms)
6186 appData.autoComment = !appData.autoComment;
6188 if (appData.autoComment) {
6189 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6191 XtSetArg(args[0], XtNleftBitmap, None);
6193 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6198 void AutoflagProc(w, event, prms, nprms)
6206 appData.autoCallFlag = !appData.autoCallFlag;
6208 if (appData.autoCallFlag) {
6209 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6211 XtSetArg(args[0], XtNleftBitmap, None);
6213 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6217 void AutoflipProc(w, event, prms, nprms)
6225 appData.autoFlipView = !appData.autoFlipView;
6227 if (appData.autoFlipView) {
6228 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6230 XtSetArg(args[0], XtNleftBitmap, None);
6232 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6236 void AutobsProc(w, event, prms, nprms)
6244 appData.autoObserve = !appData.autoObserve;
6246 if (appData.autoObserve) {
6247 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6249 XtSetArg(args[0], XtNleftBitmap, None);
6251 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6255 void AutoraiseProc(w, event, prms, nprms)
6263 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6265 if (appData.autoRaiseBoard) {
6266 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6268 XtSetArg(args[0], XtNleftBitmap, None);
6270 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6274 void AutosaveProc(w, event, prms, nprms)
6282 appData.autoSaveGames = !appData.autoSaveGames;
6284 if (appData.autoSaveGames) {
6285 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6287 XtSetArg(args[0], XtNleftBitmap, None);
6289 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6293 void BlindfoldProc(w, event, prms, nprms)
6301 appData.blindfold = !appData.blindfold;
6303 if (appData.blindfold) {
6304 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6306 XtSetArg(args[0], XtNleftBitmap, None);
6308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6311 DrawPosition(True, NULL);
6314 void TestLegalityProc(w, event, prms, nprms)
6322 appData.testLegality = !appData.testLegality;
6324 if (appData.testLegality) {
6325 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6327 XtSetArg(args[0], XtNleftBitmap, None);
6329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6334 void FlashMovesProc(w, event, prms, nprms)
6342 if (appData.flashCount == 0) {
6343 appData.flashCount = 3;
6345 appData.flashCount = -appData.flashCount;
6348 if (appData.flashCount > 0) {
6349 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6351 XtSetArg(args[0], XtNleftBitmap, None);
6353 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6357 void FlipViewProc(w, event, prms, nprms)
6363 flipView = !flipView;
6364 DrawPosition(True, NULL);
6367 void GetMoveListProc(w, event, prms, nprms)
6375 appData.getMoveList = !appData.getMoveList;
6377 if (appData.getMoveList) {
6378 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6381 XtSetArg(args[0], XtNleftBitmap, None);
6383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6388 void HighlightDraggingProc(w, event, prms, nprms)
6396 appData.highlightDragging = !appData.highlightDragging;
6398 if (appData.highlightDragging) {
6399 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6401 XtSetArg(args[0], XtNleftBitmap, None);
6403 XtSetValues(XtNameToWidget(menuBarWidget,
6404 "menuOptions.Highlight Dragging"), args, 1);
6408 void HighlightLastMoveProc(w, event, prms, nprms)
6416 appData.highlightLastMove = !appData.highlightLastMove;
6418 if (appData.highlightLastMove) {
6419 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6421 XtSetArg(args[0], XtNleftBitmap, None);
6423 XtSetValues(XtNameToWidget(menuBarWidget,
6424 "menuOptions.Highlight Last Move"), args, 1);
6427 void IcsAlarmProc(w, event, prms, nprms)
6435 appData.icsAlarm = !appData.icsAlarm;
6437 if (appData.icsAlarm) {
6438 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6440 XtSetArg(args[0], XtNleftBitmap, None);
6442 XtSetValues(XtNameToWidget(menuBarWidget,
6443 "menuOptions.ICS Alarm"), args, 1);
6446 void MoveSoundProc(w, event, prms, nprms)
6454 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6456 if (appData.ringBellAfterMoves) {
6457 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6459 XtSetArg(args[0], XtNleftBitmap, None);
6461 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6466 void OldSaveStyleProc(w, event, prms, nprms)
6474 appData.oldSaveStyle = !appData.oldSaveStyle;
6476 if (appData.oldSaveStyle) {
6477 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6479 XtSetArg(args[0], XtNleftBitmap, None);
6481 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6485 void PeriodicUpdatesProc(w, event, prms, nprms)
6493 PeriodicUpdatesEvent(!appData.periodicUpdates);
6495 if (appData.periodicUpdates) {
6496 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6498 XtSetArg(args[0], XtNleftBitmap, None);
6500 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6504 void PonderNextMoveProc(w, event, prms, nprms)
6512 PonderNextMoveEvent(!appData.ponderNextMove);
6514 if (appData.ponderNextMove) {
6515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6517 XtSetArg(args[0], XtNleftBitmap, None);
6519 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6523 void PopupExitMessageProc(w, event, prms, nprms)
6531 appData.popupExitMessage = !appData.popupExitMessage;
6533 if (appData.popupExitMessage) {
6534 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6536 XtSetArg(args[0], XtNleftBitmap, None);
6538 XtSetValues(XtNameToWidget(menuBarWidget,
6539 "menuOptions.Popup Exit Message"), args, 1);
6542 void PopupMoveErrorsProc(w, event, prms, nprms)
6550 appData.popupMoveErrors = !appData.popupMoveErrors;
6552 if (appData.popupMoveErrors) {
6553 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6555 XtSetArg(args[0], XtNleftBitmap, None);
6557 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6561 void PremoveProc(w, event, prms, nprms)
6569 appData.premove = !appData.premove;
6571 if (appData.premove) {
6572 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6574 XtSetArg(args[0], XtNleftBitmap, None);
6576 XtSetValues(XtNameToWidget(menuBarWidget,
6577 "menuOptions.Premove"), args, 1);
6580 void QuietPlayProc(w, event, prms, nprms)
6588 appData.quietPlay = !appData.quietPlay;
6590 if (appData.quietPlay) {
6591 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6593 XtSetArg(args[0], XtNleftBitmap, None);
6595 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6599 void ShowCoordsProc(w, event, prms, nprms)
6607 appData.showCoords = !appData.showCoords;
6609 if (appData.showCoords) {
6610 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6612 XtSetArg(args[0], XtNleftBitmap, None);
6614 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6617 DrawPosition(True, NULL);
6620 void ShowThinkingProc(w, event, prms, nprms)
6626 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6627 ShowThinkingEvent();
6630 void HideThinkingProc(w, event, prms, nprms)
6638 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6639 ShowThinkingEvent();
6641 if (appData.hideThinkingFromHuman) {
6642 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6644 XtSetArg(args[0], XtNleftBitmap, None);
6646 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6650 void SaveOnExitProc(w, event, prms, nprms)
6658 saveSettingsOnExit = !saveSettingsOnExit;
6660 if (saveSettingsOnExit) {
6661 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6663 XtSetArg(args[0], XtNleftBitmap, None);
6665 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6669 void SaveSettingsProc(w, event, prms, nprms)
6675 SaveSettings(settingsFileName);
6678 void InfoProc(w, event, prms, nprms)
6685 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6690 void ManProc(w, event, prms, nprms)
6698 if (nprms && *nprms > 0)
6702 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6706 void HintProc(w, event, prms, nprms)
6715 void BookProc(w, event, prms, nprms)
6724 void AboutProc(w, event, prms, nprms)
6732 char *zippy = " (with Zippy code)";
6736 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6737 programVersion, zippy,
6738 "Copyright 1991 Digital Equipment Corporation",
6739 "Enhancements Copyright 1992-2009 Free Software Foundation",
6740 "Enhancements Copyright 2005 Alessandro Scotti",
6741 PACKAGE, " is free software and carries NO WARRANTY;",
6742 "see the file COPYING for more information.");
6743 ErrorPopUp(_("About XBoard"), buf, FALSE);
6746 void DebugProc(w, event, prms, nprms)
6752 appData.debugMode = !appData.debugMode;
6755 void AboutGameProc(w, event, prms, nprms)
6764 void NothingProc(w, event, prms, nprms)
6773 void Iconify(w, event, prms, nprms)
6782 XtSetArg(args[0], XtNiconic, True);
6783 XtSetValues(shellWidget, args, 1);
6786 void DisplayMessage(message, extMessage)
6787 char *message, *extMessage;
6789 /* display a message in the message widget */
6798 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6803 message = extMessage;
6807 /* need to test if messageWidget already exists, since this function
6808 can also be called during the startup, if for example a Xresource
6809 is not set up correctly */
6812 XtSetArg(arg, XtNlabel, message);
6813 XtSetValues(messageWidget, &arg, 1);
6819 void DisplayTitle(text)
6824 char title[MSG_SIZ];
6827 if (text == NULL) text = "";
6829 if (appData.titleInWindow) {
6831 XtSetArg(args[i], XtNlabel, text); i++;
6832 XtSetValues(titleWidget, args, i);
6835 if (*text != NULLCHAR) {
6837 strcpy(title, text);
6838 } else if (appData.icsActive) {
6839 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6840 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6841 } else if (appData.cmailGameName[0] != NULLCHAR) {
6842 snprintf(icon, sizeof(icon), "%s", "CMail");
6843 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6845 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6846 } else if (gameInfo.variant == VariantGothic) {
6847 strcpy(icon, programName);
6848 strcpy(title, GOTHIC);
6851 } else if (gameInfo.variant == VariantFalcon) {
6852 strcpy(icon, programName);
6853 strcpy(title, FALCON);
6855 } else if (appData.noChessProgram) {
6856 strcpy(icon, programName);
6857 strcpy(title, programName);
6859 strcpy(icon, first.tidy);
6860 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6863 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6864 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6865 XtSetValues(shellWidget, args, i);
6869 void DisplayError(message, error)
6876 if (appData.debugMode || appData.matchMode) {
6877 fprintf(stderr, "%s: %s\n", programName, message);
6880 if (appData.debugMode || appData.matchMode) {
6881 fprintf(stderr, "%s: %s: %s\n",
6882 programName, message, strerror(error));
6884 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6887 ErrorPopUp(_("Error"), message, FALSE);
6891 void DisplayMoveError(message)
6896 DrawPosition(FALSE, NULL);
6897 if (appData.debugMode || appData.matchMode) {
6898 fprintf(stderr, "%s: %s\n", programName, message);
6900 if (appData.popupMoveErrors) {
6901 ErrorPopUp(_("Error"), message, FALSE);
6903 DisplayMessage(message, "");
6908 void DisplayFatalError(message, error, status)
6914 errorExitStatus = status;
6916 fprintf(stderr, "%s: %s\n", programName, message);
6918 fprintf(stderr, "%s: %s: %s\n",
6919 programName, message, strerror(error));
6920 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6923 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6924 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6930 void DisplayInformation(message)
6934 ErrorPopUp(_("Information"), message, TRUE);
6937 void DisplayNote(message)
6941 ErrorPopUp(_("Note"), message, FALSE);
6945 NullXErrorCheck(dpy, error_event)
6947 XErrorEvent *error_event;
6952 void DisplayIcsInteractionTitle(message)
6955 if (oldICSInteractionTitle == NULL) {
6956 /* Magic to find the old window title, adapted from vim */
6957 char *wina = getenv("WINDOWID");
6959 Window win = (Window) atoi(wina);
6960 Window root, parent, *children;
6961 unsigned int nchildren;
6962 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6964 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6965 if (!XQueryTree(xDisplay, win, &root, &parent,
6966 &children, &nchildren)) break;
6967 if (children) XFree((void *)children);
6968 if (parent == root || parent == 0) break;
6971 XSetErrorHandler(oldHandler);
6973 if (oldICSInteractionTitle == NULL) {
6974 oldICSInteractionTitle = "xterm";
6977 printf("\033]0;%s\007", message);
6981 char pendingReplyPrefix[MSG_SIZ];
6982 ProcRef pendingReplyPR;
6984 void AskQuestionProc(w, event, prms, nprms)
6991 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6995 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6998 void AskQuestionPopDown()
7000 if (!askQuestionUp) return;
7001 XtPopdown(askQuestionShell);
7002 XtDestroyWidget(askQuestionShell);
7003 askQuestionUp = False;
7006 void AskQuestionReplyAction(w, event, prms, nprms)
7016 reply = XawDialogGetValueString(w = XtParent(w));
7017 strcpy(buf, pendingReplyPrefix);
7018 if (*buf) strcat(buf, " ");
7021 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7022 AskQuestionPopDown();
7024 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7027 void AskQuestionCallback(w, client_data, call_data)
7029 XtPointer client_data, call_data;
7034 XtSetArg(args[0], XtNlabel, &name);
7035 XtGetValues(w, args, 1);
7037 if (strcmp(name, _("cancel")) == 0) {
7038 AskQuestionPopDown();
7040 AskQuestionReplyAction(w, NULL, NULL, NULL);
7044 void AskQuestion(title, question, replyPrefix, pr)
7045 char *title, *question, *replyPrefix;
7049 Widget popup, layout, dialog, edit;
7055 strcpy(pendingReplyPrefix, replyPrefix);
7056 pendingReplyPR = pr;
7059 XtSetArg(args[i], XtNresizable, True); i++;
7060 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7061 askQuestionShell = popup =
7062 XtCreatePopupShell(title, transientShellWidgetClass,
7063 shellWidget, args, i);
7066 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7067 layoutArgs, XtNumber(layoutArgs));
7070 XtSetArg(args[i], XtNlabel, question); i++;
7071 XtSetArg(args[i], XtNvalue, ""); i++;
7072 XtSetArg(args[i], XtNborderWidth, 0); i++;
7073 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7076 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7077 (XtPointer) dialog);
7078 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7079 (XtPointer) dialog);
7081 XtRealizeWidget(popup);
7082 CatchDeleteWindow(popup, "AskQuestionPopDown");
7084 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7085 &x, &y, &win_x, &win_y, &mask);
7087 XtSetArg(args[0], XtNx, x - 10);
7088 XtSetArg(args[1], XtNy, y - 30);
7089 XtSetValues(popup, args, 2);
7091 XtPopup(popup, XtGrabExclusive);
7092 askQuestionUp = True;
7094 edit = XtNameToWidget(dialog, "*value");
7095 XtSetKeyboardFocus(popup, edit);
7103 if (*name == NULLCHAR) {
7105 } else if (strcmp(name, "$") == 0) {
7106 putc(BELLCHAR, stderr);
7109 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7117 PlaySound(appData.soundMove);
7123 PlaySound(appData.soundIcsWin);
7129 PlaySound(appData.soundIcsLoss);
7135 PlaySound(appData.soundIcsDraw);
7139 PlayIcsUnfinishedSound()
7141 PlaySound(appData.soundIcsUnfinished);
7147 PlaySound(appData.soundIcsAlarm);
7153 system("stty echo");
7159 system("stty -echo");
7163 Colorize(cc, continuation)
7168 int count, outCount, error;
7170 if (textColors[(int)cc].bg > 0) {
7171 if (textColors[(int)cc].fg > 0) {
7172 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7173 textColors[(int)cc].fg, textColors[(int)cc].bg);
7175 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7176 textColors[(int)cc].bg);
7179 if (textColors[(int)cc].fg > 0) {
7180 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7181 textColors[(int)cc].fg);
7183 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7186 count = strlen(buf);
7187 outCount = OutputToProcess(NoProc, buf, count, &error);
7188 if (outCount < count) {
7189 DisplayFatalError(_("Error writing to display"), error, 1);
7192 if (continuation) return;
7195 PlaySound(appData.soundShout);
7198 PlaySound(appData.soundSShout);
7201 PlaySound(appData.soundChannel1);
7204 PlaySound(appData.soundChannel);
7207 PlaySound(appData.soundKibitz);
7210 PlaySound(appData.soundTell);
7212 case ColorChallenge:
7213 PlaySound(appData.soundChallenge);
7216 PlaySound(appData.soundRequest);
7219 PlaySound(appData.soundSeek);
7230 return getpwuid(getuid())->pw_name;
7233 static char *ExpandPathName(path)
7236 static char static_buf[2000];
7237 char *d, *s, buf[2000];
7243 while (*s && isspace(*s))
7252 if (*(s+1) == '/') {
7253 strcpy(d, getpwuid(getuid())->pw_dir);
7258 *strchr(buf, '/') = 0;
7259 pwd = getpwnam(buf);
7262 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7266 strcpy(d, pwd->pw_dir);
7267 strcat(d, strchr(s+1, '/'));
7278 static char host_name[MSG_SIZ];
7280 #if HAVE_GETHOSTNAME
7281 gethostname(host_name, MSG_SIZ);
7283 #else /* not HAVE_GETHOSTNAME */
7284 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7285 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7287 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7289 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7290 #endif /* not HAVE_GETHOSTNAME */
7293 XtIntervalId delayedEventTimerXID = 0;
7294 DelayedEventCallback delayedEventCallback = 0;
7299 delayedEventTimerXID = 0;
7300 delayedEventCallback();
7304 ScheduleDelayedEvent(cb, millisec)
7305 DelayedEventCallback cb; long millisec;
7307 if(delayedEventTimerXID && delayedEventCallback == cb)
7308 // [HGM] alive: replace, rather than add or flush identical event
7309 XtRemoveTimeOut(delayedEventTimerXID);
7310 delayedEventCallback = cb;
7311 delayedEventTimerXID =
7312 XtAppAddTimeOut(appContext, millisec,
7313 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7316 DelayedEventCallback
7319 if (delayedEventTimerXID) {
7320 return delayedEventCallback;
7327 CancelDelayedEvent()
7329 if (delayedEventTimerXID) {
7330 XtRemoveTimeOut(delayedEventTimerXID);
7331 delayedEventTimerXID = 0;
7335 XtIntervalId loadGameTimerXID = 0;
7337 int LoadGameTimerRunning()
7339 return loadGameTimerXID != 0;
7342 int StopLoadGameTimer()
7344 if (loadGameTimerXID != 0) {
7345 XtRemoveTimeOut(loadGameTimerXID);
7346 loadGameTimerXID = 0;
7354 LoadGameTimerCallback(arg, id)
7358 loadGameTimerXID = 0;
7363 StartLoadGameTimer(millisec)
7367 XtAppAddTimeOut(appContext, millisec,
7368 (XtTimerCallbackProc) LoadGameTimerCallback,
7372 XtIntervalId analysisClockXID = 0;
7375 AnalysisClockCallback(arg, id)
7379 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7380 || appData.icsEngineAnalyze) { // [DM]
7381 AnalysisPeriodicEvent(0);
7382 StartAnalysisClock();
7387 StartAnalysisClock()
7390 XtAppAddTimeOut(appContext, 2000,
7391 (XtTimerCallbackProc) AnalysisClockCallback,
7395 XtIntervalId clockTimerXID = 0;
7397 int ClockTimerRunning()
7399 return clockTimerXID != 0;
7402 int StopClockTimer()
7404 if (clockTimerXID != 0) {
7405 XtRemoveTimeOut(clockTimerXID);
7414 ClockTimerCallback(arg, id)
7423 StartClockTimer(millisec)
7427 XtAppAddTimeOut(appContext, millisec,
7428 (XtTimerCallbackProc) ClockTimerCallback,
7433 DisplayTimerLabel(w, color, timer, highlight)
7442 /* check for low time warning */
7443 Pixel foregroundOrWarningColor = timerForegroundPixel;
7446 appData.lowTimeWarning &&
7447 (timer / 1000) < appData.icsAlarmTime)
7448 foregroundOrWarningColor = lowTimeWarningColor;
7450 if (appData.clockMode) {
7451 sprintf(buf, "%s: %s", color, TimeString(timer));
7452 XtSetArg(args[0], XtNlabel, buf);
7454 sprintf(buf, "%s ", color);
7455 XtSetArg(args[0], XtNlabel, buf);
7460 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7461 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7463 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7464 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7467 XtSetValues(w, args, 3);
7471 DisplayWhiteClock(timeRemaining, highlight)
7477 if(appData.noGUI) return;
7478 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7479 if (highlight && iconPixmap == bIconPixmap) {
7480 iconPixmap = wIconPixmap;
7481 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7482 XtSetValues(shellWidget, args, 1);
7487 DisplayBlackClock(timeRemaining, highlight)
7493 if(appData.noGUI) return;
7494 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7495 if (highlight && iconPixmap == wIconPixmap) {
7496 iconPixmap = bIconPixmap;
7497 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7498 XtSetValues(shellWidget, args, 1);
7516 int StartChildProcess(cmdLine, dir, pr)
7523 int to_prog[2], from_prog[2];
7527 if (appData.debugMode) {
7528 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7531 /* We do NOT feed the cmdLine to the shell; we just
7532 parse it into blank-separated arguments in the
7533 most simple-minded way possible.
7536 strcpy(buf, cmdLine);
7539 while(*p == ' ') p++;
7541 if(*p == '"' || *p == '\'')
7542 p = strchr(++argv[i-1], *p);
7543 else p = strchr(p, ' ');
7544 if (p == NULL) break;
7549 SetUpChildIO(to_prog, from_prog);
7551 if ((pid = fork()) == 0) {
7553 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7554 close(to_prog[1]); // first close the unused pipe ends
7555 close(from_prog[0]);
7556 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7557 dup2(from_prog[1], 1);
7558 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7559 close(from_prog[1]); // and closing again loses one of the pipes!
7560 if(fileno(stderr) >= 2) // better safe than sorry...
7561 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7563 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7568 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7570 execvp(argv[0], argv);
7572 /* If we get here, exec failed */
7577 /* Parent process */
7579 close(from_prog[1]);
7581 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7584 cp->fdFrom = from_prog[0];
7585 cp->fdTo = to_prog[1];
7590 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7591 static RETSIGTYPE AlarmCallBack(int n)
7597 DestroyChildProcess(pr, signalType)
7601 ChildProc *cp = (ChildProc *) pr;
7603 if (cp->kind != CPReal) return;
7605 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7606 signal(SIGALRM, AlarmCallBack);
7608 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7609 kill(cp->pid, SIGKILL); // kill it forcefully
7610 wait((int *) 0); // and wait again
7614 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7616 /* Process is exiting either because of the kill or because of
7617 a quit command sent by the backend; either way, wait for it to die.
7626 InterruptChildProcess(pr)
7629 ChildProc *cp = (ChildProc *) pr;
7631 if (cp->kind != CPReal) return;
7632 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7635 int OpenTelnet(host, port, pr)
7640 char cmdLine[MSG_SIZ];
7642 if (port[0] == NULLCHAR) {
7643 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7645 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7647 return StartChildProcess(cmdLine, "", pr);
7650 int OpenTCP(host, port, pr)
7656 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7657 #else /* !OMIT_SOCKETS */
7659 struct sockaddr_in sa;
7661 unsigned short uport;
7664 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7668 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7669 sa.sin_family = AF_INET;
7670 sa.sin_addr.s_addr = INADDR_ANY;
7671 uport = (unsigned short) 0;
7672 sa.sin_port = htons(uport);
7673 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7677 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7678 if (!(hp = gethostbyname(host))) {
7680 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7681 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7682 hp->h_addrtype = AF_INET;
7684 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7685 hp->h_addr_list[0] = (char *) malloc(4);
7686 hp->h_addr_list[0][0] = b0;
7687 hp->h_addr_list[0][1] = b1;
7688 hp->h_addr_list[0][2] = b2;
7689 hp->h_addr_list[0][3] = b3;
7694 sa.sin_family = hp->h_addrtype;
7695 uport = (unsigned short) atoi(port);
7696 sa.sin_port = htons(uport);
7697 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7699 if (connect(s, (struct sockaddr *) &sa,
7700 sizeof(struct sockaddr_in)) < 0) {
7704 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7711 #endif /* !OMIT_SOCKETS */
7716 int OpenCommPort(name, pr)
7723 fd = open(name, 2, 0);
7724 if (fd < 0) return errno;
7726 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7736 int OpenLoopback(pr)
7742 SetUpChildIO(to, from);
7744 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7747 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7754 int OpenRcmd(host, user, cmd, pr)
7755 char *host, *user, *cmd;
7758 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7762 #define INPUT_SOURCE_BUF_SIZE 8192
7771 char buf[INPUT_SOURCE_BUF_SIZE];
7776 DoInputCallback(closure, source, xid)
7781 InputSource *is = (InputSource *) closure;
7786 if (is->lineByLine) {
7787 count = read(is->fd, is->unused,
7788 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7790 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7793 is->unused += count;
7795 while (p < is->unused) {
7796 q = memchr(p, '\n', is->unused - p);
7797 if (q == NULL) break;
7799 (is->func)(is, is->closure, p, q - p, 0);
7803 while (p < is->unused) {
7808 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7813 (is->func)(is, is->closure, is->buf, count, error);
7817 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7824 ChildProc *cp = (ChildProc *) pr;
7826 is = (InputSource *) calloc(1, sizeof(InputSource));
7827 is->lineByLine = lineByLine;
7831 is->fd = fileno(stdin);
7833 is->kind = cp->kind;
7834 is->fd = cp->fdFrom;
7837 is->unused = is->buf;
7840 is->xid = XtAppAddInput(appContext, is->fd,
7841 (XtPointer) (XtInputReadMask),
7842 (XtInputCallbackProc) DoInputCallback,
7844 is->closure = closure;
7845 return (InputSourceRef) is;
7849 RemoveInputSource(isr)
7852 InputSource *is = (InputSource *) isr;
7854 if (is->xid == 0) return;
7855 XtRemoveInput(is->xid);
7859 int OutputToProcess(pr, message, count, outError)
7865 static int line = 0;
7866 ChildProc *cp = (ChildProc *) pr;
7871 if (appData.noJoin || !appData.useInternalWrap)
7872 outCount = fwrite(message, 1, count, stdout);
7875 int width = get_term_width();
7876 int len = wrap(NULL, message, count, width, &line);
7877 char *msg = malloc(len);
7881 outCount = fwrite(message, 1, count, stdout);
7884 dbgchk = wrap(msg, message, count, width, &line);
7885 if (dbgchk != len && appData.debugMode)
7886 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7887 outCount = fwrite(msg, 1, dbgchk, stdout);
7893 outCount = write(cp->fdTo, message, count);
7903 /* Output message to process, with "ms" milliseconds of delay
7904 between each character. This is needed when sending the logon
7905 script to ICC, which for some reason doesn't like the
7906 instantaneous send. */
7907 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7914 ChildProc *cp = (ChildProc *) pr;
7919 r = write(cp->fdTo, message++, 1);
7932 /**** Animation code by Hugh Fisher, DCS, ANU.
7934 Known problem: if a window overlapping the board is
7935 moved away while a piece is being animated underneath,
7936 the newly exposed area won't be updated properly.
7937 I can live with this.
7939 Known problem: if you look carefully at the animation
7940 of pieces in mono mode, they are being drawn as solid
7941 shapes without interior detail while moving. Fixing
7942 this would be a major complication for minimal return.
7945 /* Masks for XPM pieces. Black and white pieces can have
7946 different shapes, but in the interest of retaining my
7947 sanity pieces must have the same outline on both light
7948 and dark squares, and all pieces must use the same
7949 background square colors/images. */
7951 static int xpmDone = 0;
7954 CreateAnimMasks (pieceDepth)
7961 unsigned long plane;
7964 /* Need a bitmap just to get a GC with right depth */
7965 buf = XCreatePixmap(xDisplay, xBoardWindow,
7967 values.foreground = 1;
7968 values.background = 0;
7969 /* Don't use XtGetGC, not read only */
7970 maskGC = XCreateGC(xDisplay, buf,
7971 GCForeground | GCBackground, &values);
7972 XFreePixmap(xDisplay, buf);
7974 buf = XCreatePixmap(xDisplay, xBoardWindow,
7975 squareSize, squareSize, pieceDepth);
7976 values.foreground = XBlackPixel(xDisplay, xScreen);
7977 values.background = XWhitePixel(xDisplay, xScreen);
7978 bufGC = XCreateGC(xDisplay, buf,
7979 GCForeground | GCBackground, &values);
7981 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7982 /* Begin with empty mask */
7983 if(!xpmDone) // [HGM] pieces: keep using existing
7984 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7985 squareSize, squareSize, 1);
7986 XSetFunction(xDisplay, maskGC, GXclear);
7987 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7988 0, 0, squareSize, squareSize);
7990 /* Take a copy of the piece */
7995 XSetFunction(xDisplay, bufGC, GXcopy);
7996 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7998 0, 0, squareSize, squareSize, 0, 0);
8000 /* XOR the background (light) over the piece */
8001 XSetFunction(xDisplay, bufGC, GXxor);
8003 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8004 0, 0, squareSize, squareSize, 0, 0);
8006 XSetForeground(xDisplay, bufGC, lightSquareColor);
8007 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8010 /* We now have an inverted piece image with the background
8011 erased. Construct mask by just selecting all the non-zero
8012 pixels - no need to reconstruct the original image. */
8013 XSetFunction(xDisplay, maskGC, GXor);
8015 /* Might be quicker to download an XImage and create bitmap
8016 data from it rather than this N copies per piece, but it
8017 only takes a fraction of a second and there is a much
8018 longer delay for loading the pieces. */
8019 for (n = 0; n < pieceDepth; n ++) {
8020 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8021 0, 0, squareSize, squareSize,
8027 XFreePixmap(xDisplay, buf);
8028 XFreeGC(xDisplay, bufGC);
8029 XFreeGC(xDisplay, maskGC);
8033 InitAnimState (anim, info)
8035 XWindowAttributes * info;
8040 /* Each buffer is square size, same depth as window */
8041 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8042 squareSize, squareSize, info->depth);
8043 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8044 squareSize, squareSize, info->depth);
8046 /* Create a plain GC for blitting */
8047 mask = GCForeground | GCBackground | GCFunction |
8048 GCPlaneMask | GCGraphicsExposures;
8049 values.foreground = XBlackPixel(xDisplay, xScreen);
8050 values.background = XWhitePixel(xDisplay, xScreen);
8051 values.function = GXcopy;
8052 values.plane_mask = AllPlanes;
8053 values.graphics_exposures = False;
8054 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8056 /* Piece will be copied from an existing context at
8057 the start of each new animation/drag. */
8058 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8060 /* Outline will be a read-only copy of an existing */
8061 anim->outlineGC = None;
8067 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8068 XWindowAttributes info;
8070 if (xpmDone && gameInfo.variant == old) return;
8071 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8072 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8074 InitAnimState(&game, &info);
8075 InitAnimState(&player, &info);
8077 /* For XPM pieces, we need bitmaps to use as masks. */
8079 CreateAnimMasks(info.depth);
8085 static Boolean frameWaiting;
8087 static RETSIGTYPE FrameAlarm (sig)
8090 frameWaiting = False;
8091 /* In case System-V style signals. Needed?? */
8092 signal(SIGALRM, FrameAlarm);
8099 struct itimerval delay;
8101 XSync(xDisplay, False);
8104 frameWaiting = True;
8105 signal(SIGALRM, FrameAlarm);
8106 delay.it_interval.tv_sec =
8107 delay.it_value.tv_sec = time / 1000;
8108 delay.it_interval.tv_usec =
8109 delay.it_value.tv_usec = (time % 1000) * 1000;
8110 setitimer(ITIMER_REAL, &delay, NULL);
8111 while (frameWaiting) pause();
8112 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8113 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8114 setitimer(ITIMER_REAL, &delay, NULL);
8124 XSync(xDisplay, False);
8126 usleep(time * 1000);
8131 /* Convert board position to corner of screen rect and color */
8134 ScreenSquare(column, row, pt, color)
8135 int column; int row; XPoint * pt; int * color;
8138 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8139 pt->y = lineGap + row * (squareSize + lineGap);
8141 pt->x = lineGap + column * (squareSize + lineGap);
8142 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8144 *color = SquareColor(row, column);
8147 /* Convert window coords to square */
8150 BoardSquare(x, y, column, row)
8151 int x; int y; int * column; int * row;
8153 *column = EventToSquare(x, BOARD_WIDTH);
8154 if (flipView && *column >= 0)
8155 *column = BOARD_WIDTH - 1 - *column;
8156 *row = EventToSquare(y, BOARD_HEIGHT);
8157 if (!flipView && *row >= 0)
8158 *row = BOARD_HEIGHT - 1 - *row;
8163 #undef Max /* just in case */
8165 #define Max(a, b) ((a) > (b) ? (a) : (b))
8166 #define Min(a, b) ((a) < (b) ? (a) : (b))
8169 SetRect(rect, x, y, width, height)
8170 XRectangle * rect; int x; int y; int width; int height;
8174 rect->width = width;
8175 rect->height = height;
8178 /* Test if two frames overlap. If they do, return
8179 intersection rect within old and location of
8180 that rect within new. */
8183 Intersect(old, new, size, area, pt)
8184 XPoint * old; XPoint * new;
8185 int size; XRectangle * area; XPoint * pt;
8187 if (old->x > new->x + size || new->x > old->x + size ||
8188 old->y > new->y + size || new->y > old->y + size) {
8191 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8192 size - abs(old->x - new->x), size - abs(old->y - new->y));
8193 pt->x = Max(old->x - new->x, 0);
8194 pt->y = Max(old->y - new->y, 0);
8199 /* For two overlapping frames, return the rect(s)
8200 in the old that do not intersect with the new. */
8203 CalcUpdateRects(old, new, size, update, nUpdates)
8204 XPoint * old; XPoint * new; int size;
8205 XRectangle update[]; int * nUpdates;
8209 /* If old = new (shouldn't happen) then nothing to draw */
8210 if (old->x == new->x && old->y == new->y) {
8214 /* Work out what bits overlap. Since we know the rects
8215 are the same size we don't need a full intersect calc. */
8217 /* Top or bottom edge? */
8218 if (new->y > old->y) {
8219 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8221 } else if (old->y > new->y) {
8222 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8223 size, old->y - new->y);
8226 /* Left or right edge - don't overlap any update calculated above. */
8227 if (new->x > old->x) {
8228 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8229 new->x - old->x, size - abs(new->y - old->y));
8231 } else if (old->x > new->x) {
8232 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8233 old->x - new->x, size - abs(new->y - old->y));
8240 /* Generate a series of frame coords from start->mid->finish.
8241 The movement rate doubles until the half way point is
8242 reached, then halves back down to the final destination,
8243 which gives a nice slow in/out effect. The algorithmn
8244 may seem to generate too many intermediates for short
8245 moves, but remember that the purpose is to attract the
8246 viewers attention to the piece about to be moved and
8247 then to where it ends up. Too few frames would be less
8251 Tween(start, mid, finish, factor, frames, nFrames)
8252 XPoint * start; XPoint * mid;
8253 XPoint * finish; int factor;
8254 XPoint frames[]; int * nFrames;
8256 int fraction, n, count;
8260 /* Slow in, stepping 1/16th, then 1/8th, ... */
8262 for (n = 0; n < factor; n++)
8264 for (n = 0; n < factor; n++) {
8265 frames[count].x = start->x + (mid->x - start->x) / fraction;
8266 frames[count].y = start->y + (mid->y - start->y) / fraction;
8268 fraction = fraction / 2;
8272 frames[count] = *mid;
8275 /* Slow out, stepping 1/2, then 1/4, ... */
8277 for (n = 0; n < factor; n++) {
8278 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8279 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8281 fraction = fraction * 2;
8286 /* Draw a piece on the screen without disturbing what's there */
8289 SelectGCMask(piece, clip, outline, mask)
8290 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8294 /* Bitmap for piece being moved. */
8295 if (appData.monoMode) {
8296 *mask = *pieceToSolid(piece);
8297 } else if (useImages) {
8299 *mask = xpmMask[piece];
8301 *mask = ximMaskPm[piece];
8304 *mask = *pieceToSolid(piece);
8307 /* GC for piece being moved. Square color doesn't matter, but
8308 since it gets modified we make a copy of the original. */
8310 if (appData.monoMode)
8315 if (appData.monoMode)
8320 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8322 /* Outline only used in mono mode and is not modified */
8324 *outline = bwPieceGC;
8326 *outline = wbPieceGC;
8330 OverlayPiece(piece, clip, outline, dest)
8331 ChessSquare piece; GC clip; GC outline; Drawable dest;
8336 /* Draw solid rectangle which will be clipped to shape of piece */
8337 XFillRectangle(xDisplay, dest, clip,
8338 0, 0, squareSize, squareSize);
8339 if (appData.monoMode)
8340 /* Also draw outline in contrasting color for black
8341 on black / white on white cases */
8342 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8343 0, 0, squareSize, squareSize, 0, 0, 1);
8345 /* Copy the piece */
8350 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8352 0, 0, squareSize, squareSize,
8357 /* Animate the movement of a single piece */
8360 BeginAnimation(anim, piece, startColor, start)
8368 /* The old buffer is initialised with the start square (empty) */
8369 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8370 anim->prevFrame = *start;
8372 /* The piece will be drawn using its own bitmap as a matte */
8373 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8374 XSetClipMask(xDisplay, anim->pieceGC, mask);
8378 AnimationFrame(anim, frame, piece)
8383 XRectangle updates[4];
8388 /* Save what we are about to draw into the new buffer */
8389 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8390 frame->x, frame->y, squareSize, squareSize,
8393 /* Erase bits of the previous frame */
8394 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8395 /* Where the new frame overlapped the previous,
8396 the contents in newBuf are wrong. */
8397 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8398 overlap.x, overlap.y,
8399 overlap.width, overlap.height,
8401 /* Repaint the areas in the old that don't overlap new */
8402 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8403 for (i = 0; i < count; i++)
8404 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8405 updates[i].x - anim->prevFrame.x,
8406 updates[i].y - anim->prevFrame.y,
8407 updates[i].width, updates[i].height,
8408 updates[i].x, updates[i].y);
8410 /* Easy when no overlap */
8411 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8412 0, 0, squareSize, squareSize,
8413 anim->prevFrame.x, anim->prevFrame.y);
8416 /* Save this frame for next time round */
8417 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8418 0, 0, squareSize, squareSize,
8420 anim->prevFrame = *frame;
8422 /* Draw piece over original screen contents, not current,
8423 and copy entire rect. Wipes out overlapping piece images. */
8424 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8425 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8426 0, 0, squareSize, squareSize,
8427 frame->x, frame->y);
8431 EndAnimation (anim, finish)
8435 XRectangle updates[4];
8440 /* The main code will redraw the final square, so we
8441 only need to erase the bits that don't overlap. */
8442 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8443 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8444 for (i = 0; i < count; i++)
8445 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8446 updates[i].x - anim->prevFrame.x,
8447 updates[i].y - anim->prevFrame.y,
8448 updates[i].width, updates[i].height,
8449 updates[i].x, updates[i].y);
8451 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8452 0, 0, squareSize, squareSize,
8453 anim->prevFrame.x, anim->prevFrame.y);
8458 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8460 ChessSquare piece; int startColor;
8461 XPoint * start; XPoint * finish;
8462 XPoint frames[]; int nFrames;
8466 BeginAnimation(anim, piece, startColor, start);
8467 for (n = 0; n < nFrames; n++) {
8468 AnimationFrame(anim, &(frames[n]), piece);
8469 FrameDelay(appData.animSpeed);
8471 EndAnimation(anim, finish);
8474 /* Main control logic for deciding what to animate and how */
8477 AnimateMove(board, fromX, fromY, toX, toY)
8486 XPoint start, finish, mid;
8487 XPoint frames[kFactor * 2 + 1];
8488 int nFrames, startColor, endColor;
8490 /* Are we animating? */
8491 if (!appData.animate || appData.blindfold)
8494 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8495 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8496 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8498 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8499 piece = board[fromY][fromX];
8500 if (piece >= EmptySquare) return;
8505 hop = (piece == WhiteKnight || piece == BlackKnight);
8508 if (appData.debugMode) {
8509 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8510 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8511 piece, fromX, fromY, toX, toY); }
8513 ScreenSquare(fromX, fromY, &start, &startColor);
8514 ScreenSquare(toX, toY, &finish, &endColor);
8517 /* Knight: make diagonal movement then straight */
8518 if (abs(toY - fromY) < abs(toX - fromX)) {
8519 mid.x = start.x + (finish.x - start.x) / 2;
8523 mid.y = start.y + (finish.y - start.y) / 2;
8526 mid.x = start.x + (finish.x - start.x) / 2;
8527 mid.y = start.y + (finish.y - start.y) / 2;
8530 /* Don't use as many frames for very short moves */
8531 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8532 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8534 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8535 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8537 /* Be sure end square is redrawn */
8538 damage[toY][toX] = True;
8542 DragPieceBegin(x, y)
8545 int boardX, boardY, color;
8548 /* Are we animating? */
8549 if (!appData.animateDragging || appData.blindfold)
8552 /* Figure out which square we start in and the
8553 mouse position relative to top left corner. */
8554 BoardSquare(x, y, &boardX, &boardY);
8555 player.startBoardX = boardX;
8556 player.startBoardY = boardY;
8557 ScreenSquare(boardX, boardY, &corner, &color);
8558 player.startSquare = corner;
8559 player.startColor = color;
8560 /* As soon as we start dragging, the piece will jump slightly to
8561 be centered over the mouse pointer. */
8562 player.mouseDelta.x = squareSize/2;
8563 player.mouseDelta.y = squareSize/2;
8564 /* Initialise animation */
8565 player.dragPiece = PieceForSquare(boardX, boardY);
8567 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8568 player.dragActive = True;
8569 BeginAnimation(&player, player.dragPiece, color, &corner);
8570 /* Mark this square as needing to be redrawn. Note that
8571 we don't remove the piece though, since logically (ie
8572 as seen by opponent) the move hasn't been made yet. */
8573 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8574 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8575 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8576 corner.x, corner.y, squareSize, squareSize,
8577 0, 0); // [HGM] zh: unstack in stead of grab
8578 damage[boardY][boardX] = True;
8580 player.dragActive = False;
8590 /* Are we animating? */
8591 if (!appData.animateDragging || appData.blindfold)
8595 if (! player.dragActive)
8597 /* Move piece, maintaining same relative position
8598 of mouse within square */
8599 corner.x = x - player.mouseDelta.x;
8600 corner.y = y - player.mouseDelta.y;
8601 AnimationFrame(&player, &corner, player.dragPiece);
8603 if (appData.highlightDragging) {
8605 BoardSquare(x, y, &boardX, &boardY);
8606 SetHighlights(fromX, fromY, boardX, boardY);
8615 int boardX, boardY, color;
8618 /* Are we animating? */
8619 if (!appData.animateDragging || appData.blindfold)
8623 if (! player.dragActive)
8625 /* Last frame in sequence is square piece is
8626 placed on, which may not match mouse exactly. */
8627 BoardSquare(x, y, &boardX, &boardY);
8628 ScreenSquare(boardX, boardY, &corner, &color);
8629 EndAnimation(&player, &corner);
8631 /* Be sure end square is redrawn */
8632 damage[boardY][boardX] = True;
8634 /* This prevents weird things happening with fast successive
8635 clicks which on my Sun at least can cause motion events
8636 without corresponding press/release. */
8637 player.dragActive = False;
8640 /* Handle expose event while piece being dragged */
8645 if (!player.dragActive || appData.blindfold)
8648 /* What we're doing: logically, the move hasn't been made yet,
8649 so the piece is still in it's original square. But visually
8650 it's being dragged around the board. So we erase the square
8651 that the piece is on and draw it at the last known drag point. */
8652 BlankSquare(player.startSquare.x, player.startSquare.y,
8653 player.startColor, EmptySquare, xBoardWindow);
8654 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8655 damage[player.startBoardY][player.startBoardX] = TRUE;
8658 #include <sys/ioctl.h>
8659 int get_term_width()
8661 int fd, default_width;
8664 default_width = 79; // this is FICS default anyway...
8666 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8668 if (!ioctl(fd, TIOCGSIZE, &win))
8669 default_width = win.ts_cols;
8670 #elif defined(TIOCGWINSZ)
8672 if (!ioctl(fd, TIOCGWINSZ, &win))
8673 default_width = win.ws_col;
8675 return default_width;
8678 void update_ics_width()
8680 static int old_width = 0;
8681 int new_width = get_term_width();
8683 if (old_width != new_width)
8684 ics_printf("set width %d\n", new_width);
8685 old_width = new_width;
8688 void NotifyFrontendLogin()