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));
210 #define usleep(t) _sleep2(((t)+500)/1000)
214 # define _(s) gettext (s)
215 # define N_(s) gettext_noop (s)
231 int main P((int argc, char **argv));
232 RETSIGTYPE CmailSigHandler P((int sig));
233 RETSIGTYPE IntSigHandler P((int sig));
234 RETSIGTYPE TermSizeSigHandler P((int sig));
235 void CreateGCs P((void));
236 void CreateXIMPieces P((void));
237 void CreateXPMPieces P((void));
238 void CreatePieces P((void));
239 void CreatePieceMenus P((void));
240 Widget CreateMenuBar P((Menu *mb));
241 Widget CreateButtonBar P ((MenuItem *mi));
242 char *FindFont P((char *pattern, int targetPxlSize));
243 void PieceMenuPopup P((Widget w, XEvent *event,
244 String *params, Cardinal *num_params));
245 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
246 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
247 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
248 u_int wreq, u_int hreq));
249 void CreateGrid P((void));
250 int EventToSquare P((int x, int limit));
251 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
252 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
253 void HandleUserMove P((Widget w, XEvent *event,
254 String *prms, Cardinal *nprms));
255 void AnimateUserMove P((Widget w, XEvent * event,
256 String * params, Cardinal * nParams));
257 void WhiteClock P((Widget w, XEvent *event,
258 String *prms, Cardinal *nprms));
259 void BlackClock P((Widget w, XEvent *event,
260 String *prms, Cardinal *nprms));
261 void DrawPositionProc P((Widget w, XEvent *event,
262 String *prms, Cardinal *nprms));
263 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
265 void CommentPopUp P((char *title, char *label));
266 void CommentPopDown P((void));
267 void CommentCallback P((Widget w, XtPointer client_data,
268 XtPointer call_data));
269 void ICSInputBoxPopUp P((void));
270 void ICSInputBoxPopDown P((void));
271 void FileNamePopUp P((char *label, char *def,
272 FileProc proc, char *openMode));
273 void FileNamePopDown P((void));
274 void FileNameCallback P((Widget w, XtPointer client_data,
275 XtPointer call_data));
276 void FileNameAction P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void AskQuestionReplyAction P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void AskQuestionProc P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void AskQuestionPopDown P((void));
283 void PromotionPopDown P((void));
284 void PromotionCallback P((Widget w, XtPointer client_data,
285 XtPointer call_data));
286 void EditCommentPopDown P((void));
287 void EditCommentCallback P((Widget w, XtPointer client_data,
288 XtPointer call_data));
289 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
290 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
291 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
292 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
294 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
296 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
298 void LoadPositionProc P((Widget w, XEvent *event,
299 String *prms, Cardinal *nprms));
300 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
302 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
304 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
306 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
308 void PastePositionProc P((Widget w, XEvent *event, String *prms,
310 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
311 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void SavePositionProc P((Widget w, XEvent *event,
314 String *prms, Cardinal *nprms));
315 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
318 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
320 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
322 void MachineWhiteProc P((Widget w, XEvent *event,
323 String *prms, Cardinal *nprms));
324 void AnalyzeModeProc P((Widget w, XEvent *event,
325 String *prms, Cardinal *nprms));
326 void AnalyzeFileProc P((Widget w, XEvent *event,
327 String *prms, Cardinal *nprms));
328 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
330 void IcsClientProc P((Widget w, XEvent *event, String *prms,
332 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void EditPositionProc P((Widget w, XEvent *event,
334 String *prms, Cardinal *nprms));
335 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void EditCommentProc P((Widget w, XEvent *event,
337 String *prms, Cardinal *nprms));
338 void IcsInputBoxProc P((Widget w, XEvent *event,
339 String *prms, Cardinal *nprms));
340 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
343 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
349 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
350 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
351 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
352 void StopObservingProc P((Widget w, XEvent *event, String *prms,
354 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
356 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
363 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
365 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
368 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
370 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
372 void AutocommProc P((Widget w, XEvent *event, String *prms,
374 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AutobsProc P((Widget w, XEvent *event, String *prms,
378 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
383 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
386 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
388 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
394 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
396 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
398 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
400 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
402 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
403 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
406 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
408 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
410 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
412 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
415 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
418 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
419 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
420 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void DisplayMove P((int moveNumber));
424 void DisplayTitle P((char *title));
425 void ICSInitScript P((void));
426 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
427 void ErrorPopUp P((char *title, char *text, int modal));
428 void ErrorPopDown P((void));
429 static char *ExpandPathName P((char *path));
430 static void CreateAnimVars P((void));
431 static void DragPieceMove P((int x, int y));
432 static void DrawDragPiece P((void));
433 char *ModeToWidgetName P((GameMode mode));
434 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
435 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
436 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
437 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void ShufflePopDown P(());
442 void EnginePopDown P(());
443 void UciPopDown P(());
444 void TimeControlPopDown P(());
445 void NewVariantPopDown P(());
446 void SettingsPopDown P(());
447 void update_ics_width P(());
448 int get_term_width P(());
450 * XBoard depends on Xt R4 or higher
452 int xtVersion = XtSpecificationRelease;
457 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
458 jailSquareColor, highlightSquareColor, premoveHighlightColor;
459 Pixel lowTimeWarningColor;
460 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
461 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
462 wjPieceGC, bjPieceGC, prelineGC, countGC;
463 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
464 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
465 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
466 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
467 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
468 ICSInputShell, fileNameShell, askQuestionShell;
469 Widget historyShell, evalGraphShell, gameListShell;
470 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
471 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
472 Font clockFontID, coordFontID, countFontID;
473 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
474 XtAppContext appContext;
476 char *oldICSInteractionTitle;
480 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
482 Position commentX = -1, commentY = -1;
483 Dimension commentW, commentH;
484 typedef unsigned int BoardSize;
486 Boolean chessProgram;
488 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
489 int squareSize, smallLayout = 0, tinyLayout = 0,
490 marginW, marginH, // [HGM] for run-time resizing
491 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
492 ICSInputBoxUp = False, askQuestionUp = False,
493 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
494 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
495 Pixel timerForegroundPixel, timerBackgroundPixel;
496 Pixel buttonForegroundPixel, buttonBackgroundPixel;
497 char *chessDir, *programName, *programVersion,
498 *gameCopyFilename, *gamePasteFilename;
499 Boolean alwaysOnTop = False;
500 Boolean saveSettingsOnExit;
501 char *settingsFileName;
502 char *icsTextMenuString;
504 char *firstChessProgramNames;
505 char *secondChessProgramNames;
507 WindowPlacement wpMain;
508 WindowPlacement wpConsole;
509 WindowPlacement wpComment;
510 WindowPlacement wpMoveHistory;
511 WindowPlacement wpEvalGraph;
512 WindowPlacement wpEngineOutput;
513 WindowPlacement wpGameList;
514 WindowPlacement wpTags;
518 Pixmap pieceBitmap[2][(int)BlackPawn];
519 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
520 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
521 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
522 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
523 int useImages, useImageSqs;
524 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
525 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
526 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
527 XImage *ximLightSquare, *ximDarkSquare;
530 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
531 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
533 #define White(piece) ((int)(piece) < (int)BlackPawn)
535 /* Variables for doing smooth animation. This whole thing
536 would be much easier if the board was double-buffered,
537 but that would require a fairly major rewrite. */
542 GC blitGC, pieceGC, outlineGC;
543 XPoint startSquare, prevFrame, mouseDelta;
547 int startBoardX, startBoardY;
550 /* There can be two pieces being animated at once: a player
551 can begin dragging a piece before the remote opponent has moved. */
553 static AnimState game, player;
555 /* Bitmaps for use as masks when drawing XPM pieces.
556 Need one for each black and white piece. */
557 static Pixmap xpmMask[BlackKing + 1];
559 /* This magic number is the number of intermediate frames used
560 in each half of the animation. For short moves it's reduced
561 by 1. The total number of frames will be factor * 2 + 1. */
564 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
566 MenuItem fileMenu[] = {
567 {N_("New Game"), ResetProc},
568 {N_("New Shuffle Game ..."), ShuffleMenuProc},
569 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
570 {"----", NothingProc},
571 {N_("Load Game"), LoadGameProc},
572 {N_("Load Next Game"), LoadNextGameProc},
573 {N_("Load Previous Game"), LoadPrevGameProc},
574 {N_("Reload Same Game"), ReloadGameProc},
575 {N_("Save Game"), SaveGameProc},
576 {"----", NothingProc},
577 {N_("Copy Game"), CopyGameProc},
578 {N_("Paste Game"), PasteGameProc},
579 {"----", NothingProc},
580 {N_("Load Position"), LoadPositionProc},
581 {N_("Load Next Position"), LoadNextPositionProc},
582 {N_("Load Previous Position"), LoadPrevPositionProc},
583 {N_("Reload Same Position"), ReloadPositionProc},
584 {N_("Save Position"), SavePositionProc},
585 {"----", NothingProc},
586 {N_("Copy Position"), CopyPositionProc},
587 {N_("Paste Position"), PastePositionProc},
588 {"----", NothingProc},
589 {N_("Mail Move"), MailMoveProc},
590 {N_("Reload CMail Message"), ReloadCmailMsgProc},
591 {"----", NothingProc},
592 {N_("Exit"), QuitProc},
596 MenuItem modeMenu[] = {
597 {N_("Machine White"), MachineWhiteProc},
598 {N_("Machine Black"), MachineBlackProc},
599 {N_("Two Machines"), TwoMachinesProc},
600 {N_("Analysis Mode"), AnalyzeModeProc},
601 {N_("Analyze File"), AnalyzeFileProc },
602 {N_("ICS Client"), IcsClientProc},
603 {N_("Edit Game"), EditGameProc},
604 {N_("Edit Position"), EditPositionProc},
605 {N_("Training"), TrainingProc},
606 {"----", NothingProc},
607 {N_("Show Engine Output"), EngineOutputProc},
608 {N_("Show Evaluation Graph"), NothingProc}, // [HGM] evalgr: not functional yet
609 {N_("Show Game List"), ShowGameListProc},
610 {"Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
611 {"----", NothingProc},
612 {N_("Edit Tags"), EditTagsProc},
613 {N_("Edit Comment"), EditCommentProc},
614 {N_("ICS Input Box"), IcsInputBoxProc},
615 {N_("Pause"), PauseProc},
619 MenuItem actionMenu[] = {
620 {N_("Accept"), AcceptProc},
621 {N_("Decline"), DeclineProc},
622 {N_("Rematch"), RematchProc},
623 {"----", NothingProc},
624 {N_("Call Flag"), CallFlagProc},
625 {N_("Draw"), DrawProc},
626 {N_("Adjourn"), AdjournProc},
627 {N_("Abort"), AbortProc},
628 {N_("Resign"), ResignProc},
629 {"----", NothingProc},
630 {N_("Stop Observing"), StopObservingProc},
631 {N_("Stop Examining"), StopExaminingProc},
632 {"----", NothingProc},
633 {N_("Adjudicate to White"), AdjuWhiteProc},
634 {N_("Adjudicate to Black"), AdjuBlackProc},
635 {N_("Adjudicate Draw"), AdjuDrawProc},
639 MenuItem stepMenu[] = {
640 {N_("Backward"), BackwardProc},
641 {N_("Forward"), ForwardProc},
642 {N_("Back to Start"), ToStartProc},
643 {N_("Forward to End"), ToEndProc},
644 {N_("Revert"), RevertProc},
645 {N_("Truncate Game"), TruncateGameProc},
646 {"----", NothingProc},
647 {N_("Move Now"), MoveNowProc},
648 {N_("Retract Move"), RetractMoveProc},
652 MenuItem optionsMenu[] = {
653 {N_("Flip View"), FlipViewProc},
654 {"----", NothingProc},
655 {N_("Adjudications ..."), EngineMenuProc},
656 {N_("General Settings ..."), UciMenuProc},
657 {N_("Engine #1 Settings ..."), FirstSettingsProc},
658 {N_("Engine #2 Settings ..."), SecondSettingsProc},
659 {N_("Time Control ..."), TimeControlProc},
660 {"----", NothingProc},
661 {N_("Always Queen"), AlwaysQueenProc},
662 {N_("Animate Dragging"), AnimateDraggingProc},
663 {N_("Animate Moving"), AnimateMovingProc},
664 {N_("Auto Comment"), AutocommProc},
665 {N_("Auto Flag"), AutoflagProc},
666 {N_("Auto Flip View"), AutoflipProc},
667 {N_("Auto Observe"), AutobsProc},
668 {N_("Auto Raise Board"), AutoraiseProc},
669 {N_("Auto Save"), AutosaveProc},
670 {N_("Blindfold"), BlindfoldProc},
671 {N_("Flash Moves"), FlashMovesProc},
672 {N_("Get Move List"), GetMoveListProc},
674 {N_("Highlight Dragging"), HighlightDraggingProc},
676 {N_("Highlight Last Move"), HighlightLastMoveProc},
677 {N_("Move Sound"), MoveSoundProc},
678 {N_("ICS Alarm"), IcsAlarmProc},
679 {N_("Old Save Style"), OldSaveStyleProc},
680 {N_("Periodic Updates"), PeriodicUpdatesProc},
681 {N_("Ponder Next Move"), PonderNextMoveProc},
682 {N_("Popup Exit Message"), PopupExitMessageProc},
683 {N_("Popup Move Errors"), PopupMoveErrorsProc},
684 {N_("Premove"), PremoveProc},
685 {N_("Quiet Play"), QuietPlayProc},
686 {N_("Show Coords"), ShowCoordsProc},
687 {N_("Hide Thinking"), HideThinkingProc},
688 {N_("Test Legality"), TestLegalityProc},
689 {"----", NothingProc},
690 {N_("Save Settings Now"), SaveSettingsProc},
691 {N_("Save Settings on Exit"), SaveOnExitProc},
695 MenuItem helpMenu[] = {
696 {N_("Info XBoard"), InfoProc},
697 {N_("Man XBoard"), ManProc},
698 {"----", NothingProc},
699 {N_("Hint"), HintProc},
700 {N_("Book"), BookProc},
701 {"----", NothingProc},
702 {N_("About XBoard"), AboutProc},
707 {N_("File"), fileMenu},
708 {N_("Mode"), modeMenu},
709 {N_("Action"), actionMenu},
710 {N_("Step"), stepMenu},
711 {N_("Options"), optionsMenu},
712 {N_("Help"), helpMenu},
716 #define PAUSE_BUTTON N_("P")
717 MenuItem buttonBar[] = {
720 {PAUSE_BUTTON, PauseProc},
726 #define PIECE_MENU_SIZE 18
727 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
728 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
729 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
730 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
731 N_("Empty square"), N_("Clear board") },
732 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
733 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
734 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
735 N_("Empty square"), N_("Clear board") }
737 /* must be in same order as PieceMenuStrings! */
738 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
739 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
740 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
741 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
742 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
743 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
744 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
745 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
746 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
749 #define DROP_MENU_SIZE 6
750 String dropMenuStrings[DROP_MENU_SIZE] = {
751 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
753 /* must be in same order as PieceMenuStrings! */
754 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
755 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
756 WhiteRook, WhiteQueen
764 DropMenuEnables dmEnables[] = {
782 { XtNborderWidth, 0 },
783 { XtNdefaultDistance, 0 },
787 { XtNborderWidth, 0 },
788 { XtNresizable, (XtArgVal) True },
792 { XtNborderWidth, 0 },
798 { XtNjustify, (XtArgVal) XtJustifyRight },
799 { XtNlabel, (XtArgVal) "..." },
800 { XtNresizable, (XtArgVal) True },
801 { XtNresize, (XtArgVal) False }
804 Arg messageArgs[] = {
805 { XtNjustify, (XtArgVal) XtJustifyLeft },
806 { XtNlabel, (XtArgVal) "..." },
807 { XtNresizable, (XtArgVal) True },
808 { XtNresize, (XtArgVal) False }
812 { XtNborderWidth, 0 },
813 { XtNjustify, (XtArgVal) XtJustifyLeft }
816 XtResource clientResources[] = {
817 { "flashCount", "flashCount", XtRInt, sizeof(int),
818 XtOffset(AppDataPtr, flashCount), XtRImmediate,
819 (XtPointer) FLASH_COUNT },
822 XrmOptionDescRec shellOptions[] = {
823 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
824 { "-flash", "flashCount", XrmoptionNoArg, "3" },
825 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
828 XtActionsRec boardActions[] = {
829 { "DrawPosition", DrawPositionProc },
830 { "HandleUserMove", HandleUserMove },
831 { "AnimateUserMove", AnimateUserMove },
832 { "FileNameAction", FileNameAction },
833 { "AskQuestionProc", AskQuestionProc },
834 { "AskQuestionReplyAction", AskQuestionReplyAction },
835 { "PieceMenuPopup", PieceMenuPopup },
836 { "WhiteClock", WhiteClock },
837 { "BlackClock", BlackClock },
838 { "Iconify", Iconify },
839 { "ResetProc", ResetProc },
840 { "LoadGameProc", LoadGameProc },
841 { "LoadNextGameProc", LoadNextGameProc },
842 { "LoadPrevGameProc", LoadPrevGameProc },
843 { "LoadSelectedProc", LoadSelectedProc },
844 { "ReloadGameProc", ReloadGameProc },
845 { "LoadPositionProc", LoadPositionProc },
846 { "LoadNextPositionProc", LoadNextPositionProc },
847 { "LoadPrevPositionProc", LoadPrevPositionProc },
848 { "ReloadPositionProc", ReloadPositionProc },
849 { "CopyPositionProc", CopyPositionProc },
850 { "PastePositionProc", PastePositionProc },
851 { "CopyGameProc", CopyGameProc },
852 { "PasteGameProc", PasteGameProc },
853 { "SaveGameProc", SaveGameProc },
854 { "SavePositionProc", SavePositionProc },
855 { "MailMoveProc", MailMoveProc },
856 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
857 { "QuitProc", QuitProc },
858 { "MachineWhiteProc", MachineWhiteProc },
859 { "MachineBlackProc", MachineBlackProc },
860 { "AnalysisModeProc", AnalyzeModeProc },
861 { "AnalyzeFileProc", AnalyzeFileProc },
862 { "TwoMachinesProc", TwoMachinesProc },
863 { "IcsClientProc", IcsClientProc },
864 { "EditGameProc", EditGameProc },
865 { "EditPositionProc", EditPositionProc },
866 { "TrainingProc", EditPositionProc },
867 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
868 { "ShowGameListProc", ShowGameListProc },
869 { "ShowMoveListProc", HistoryShowProc},
870 { "EditTagsProc", EditCommentProc },
871 { "EditCommentProc", EditCommentProc },
872 { "IcsAlarmProc", IcsAlarmProc },
873 { "IcsInputBoxProc", IcsInputBoxProc },
874 { "PauseProc", PauseProc },
875 { "AcceptProc", AcceptProc },
876 { "DeclineProc", DeclineProc },
877 { "RematchProc", RematchProc },
878 { "CallFlagProc", CallFlagProc },
879 { "DrawProc", DrawProc },
880 { "AdjournProc", AdjournProc },
881 { "AbortProc", AbortProc },
882 { "ResignProc", ResignProc },
883 { "AdjuWhiteProc", AdjuWhiteProc },
884 { "AdjuBlackProc", AdjuBlackProc },
885 { "AdjuDrawProc", AdjuDrawProc },
886 { "EnterKeyProc", EnterKeyProc },
887 { "StopObservingProc", StopObservingProc },
888 { "StopExaminingProc", StopExaminingProc },
889 { "BackwardProc", BackwardProc },
890 { "ForwardProc", ForwardProc },
891 { "ToStartProc", ToStartProc },
892 { "ToEndProc", ToEndProc },
893 { "RevertProc", RevertProc },
894 { "TruncateGameProc", TruncateGameProc },
895 { "MoveNowProc", MoveNowProc },
896 { "RetractMoveProc", RetractMoveProc },
897 { "AlwaysQueenProc", AlwaysQueenProc },
898 { "AnimateDraggingProc", AnimateDraggingProc },
899 { "AnimateMovingProc", AnimateMovingProc },
900 { "AutoflagProc", AutoflagProc },
901 { "AutoflipProc", AutoflipProc },
902 { "AutobsProc", AutobsProc },
903 { "AutoraiseProc", AutoraiseProc },
904 { "AutosaveProc", AutosaveProc },
905 { "BlindfoldProc", BlindfoldProc },
906 { "FlashMovesProc", FlashMovesProc },
907 { "FlipViewProc", FlipViewProc },
908 { "GetMoveListProc", GetMoveListProc },
910 { "HighlightDraggingProc", HighlightDraggingProc },
912 { "HighlightLastMoveProc", HighlightLastMoveProc },
913 { "IcsAlarmProc", IcsAlarmProc },
914 { "MoveSoundProc", MoveSoundProc },
915 { "OldSaveStyleProc", OldSaveStyleProc },
916 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
917 { "PonderNextMoveProc", PonderNextMoveProc },
918 { "PopupExitMessageProc", PopupExitMessageProc },
919 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
920 { "PremoveProc", PremoveProc },
921 { "QuietPlayProc", QuietPlayProc },
922 { "ShowCoordsProc", ShowCoordsProc },
923 { "ShowThinkingProc", ShowThinkingProc },
924 { "HideThinkingProc", HideThinkingProc },
925 { "TestLegalityProc", TestLegalityProc },
926 { "SaveSettingsProc", SaveSettingsProc },
927 { "SaveOnExitProc", SaveOnExitProc },
928 { "InfoProc", InfoProc },
929 { "ManProc", ManProc },
930 { "HintProc", HintProc },
931 { "BookProc", BookProc },
932 { "AboutGameProc", AboutGameProc },
933 { "AboutProc", AboutProc },
934 { "DebugProc", DebugProc },
935 { "NothingProc", NothingProc },
936 { "CommentPopDown", (XtActionProc) CommentPopDown },
937 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
938 { "TagsPopDown", (XtActionProc) TagsPopDown },
939 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
940 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
941 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
942 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
943 { "GameListPopDown", (XtActionProc) GameListPopDown },
944 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
945 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
946 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
947 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
948 { "EnginePopDown", (XtActionProc) EnginePopDown },
949 { "UciPopDown", (XtActionProc) UciPopDown },
950 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
951 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
952 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
955 char globalTranslations[] =
956 ":<Key>R: ResignProc() \n \
957 :<Key>r: ResetProc() \n \
958 :<Key>g: LoadGameProc() \n \
959 :<Key>N: LoadNextGameProc() \n \
960 :<Key>P: LoadPrevGameProc() \n \
961 :<Key>Q: QuitProc() \n \
962 :<Key>F: ToEndProc() \n \
963 :<Key>f: ForwardProc() \n \
964 :<Key>B: ToStartProc() \n \
965 :<Key>b: BackwardProc() \n \
966 :<Key>p: PauseProc() \n \
967 :<Key>d: DrawProc() \n \
968 :<Key>t: CallFlagProc() \n \
969 :<Key>i: Iconify() \n \
970 :<Key>c: Iconify() \n \
971 :<Key>v: FlipViewProc() \n \
972 <KeyDown>Control_L: BackwardProc() \n \
973 <KeyUp>Control_L: ForwardProc() \n \
974 <KeyDown>Control_R: BackwardProc() \n \
975 <KeyUp>Control_R: ForwardProc() \n \
976 Shift<Key>1: AskQuestionProc(\"Direct command\",\
977 \"Send to chess program:\",,1) \n \
978 Shift<Key>2: AskQuestionProc(\"Direct command\",\
979 \"Send to second chess program:\",,2) \n";
981 char boardTranslations[] =
982 "<Btn1Down>: HandleUserMove() \n \
983 <Btn1Up>: HandleUserMove() \n \
984 <Btn1Motion>: AnimateUserMove() \n \
985 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
986 PieceMenuPopup(menuB) \n \
987 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
988 PieceMenuPopup(menuW) \n \
989 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
990 PieceMenuPopup(menuW) \n \
991 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
992 PieceMenuPopup(menuB) \n";
994 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
995 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
997 char ICSInputTranslations[] =
998 "<Key>Return: EnterKeyProc() \n";
1000 String xboardResources[] = {
1001 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1002 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1003 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1008 /* Max possible square size */
1009 #define MAXSQSIZE 256
1011 static int xpm_avail[MAXSQSIZE];
1013 #ifdef HAVE_DIR_STRUCT
1015 /* Extract piece size from filename */
1017 xpm_getsize(name, len, ext)
1028 if ((p=strchr(name, '.')) == NULL ||
1029 StrCaseCmp(p+1, ext) != 0)
1035 while (*p && isdigit(*p))
1042 /* Setup xpm_avail */
1044 xpm_getavail(dirname, ext)
1052 for (i=0; i<MAXSQSIZE; ++i)
1055 if (appData.debugMode)
1056 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1058 dir = opendir(dirname);
1061 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1062 programName, dirname);
1066 while ((ent=readdir(dir)) != NULL) {
1067 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1068 if (i > 0 && i < MAXSQSIZE)
1078 xpm_print_avail(fp, ext)
1084 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1085 for (i=1; i<MAXSQSIZE; ++i) {
1091 /* Return XPM piecesize closest to size */
1093 xpm_closest_to(dirname, size, ext)
1099 int sm_diff = MAXSQSIZE;
1103 xpm_getavail(dirname, ext);
1105 if (appData.debugMode)
1106 xpm_print_avail(stderr, ext);
1108 for (i=1; i<MAXSQSIZE; ++i) {
1111 diff = (diff<0) ? -diff : diff;
1112 if (diff < sm_diff) {
1120 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1126 #else /* !HAVE_DIR_STRUCT */
1127 /* If we are on a system without a DIR struct, we can't
1128 read the directory, so we can't collect a list of
1129 filenames, etc., so we can't do any size-fitting. */
1131 xpm_closest_to(dirname, size, ext)
1136 fprintf(stderr, _("\
1137 Warning: No DIR structure found on this system --\n\
1138 Unable to autosize for XPM/XIM pieces.\n\
1139 Please report this error to frankm@hiwaay.net.\n\
1140 Include system type & operating system in message.\n"));
1143 #endif /* HAVE_DIR_STRUCT */
1145 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1146 "magenta", "cyan", "white" };
1150 TextColors textColors[(int)NColorClasses];
1152 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1154 parse_color(str, which)
1158 char *p, buf[100], *d;
1161 if (strlen(str) > 99) /* watch bounds on buf */
1166 for (i=0; i<which; ++i) {
1173 /* Could be looking at something like:
1175 .. in which case we want to stop on a comma also */
1176 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1180 return -1; /* Use default for empty field */
1183 if (which == 2 || isdigit(*p))
1186 while (*p && isalpha(*p))
1191 for (i=0; i<8; ++i) {
1192 if (!StrCaseCmp(buf, cnames[i]))
1193 return which? (i+40) : (i+30);
1195 if (!StrCaseCmp(buf, "default")) return -1;
1197 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1202 parse_cpair(cc, str)
1206 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1207 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1212 /* bg and attr are optional */
1213 textColors[(int)cc].bg = parse_color(str, 1);
1214 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1215 textColors[(int)cc].attr = 0;
1221 /* Arrange to catch delete-window events */
1222 Atom wm_delete_window;
1224 CatchDeleteWindow(Widget w, String procname)
1227 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1228 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1229 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1236 XtSetArg(args[0], XtNiconic, False);
1237 XtSetValues(shellWidget, args, 1);
1239 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1242 //---------------------------------------------------------------------------------------------------------
1243 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1246 #define CW_USEDEFAULT (1<<31)
1247 #define ICS_TEXT_MENU_SIZE 90
1248 #define SetCurrentDirectory chdir
1249 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1253 // these two must some day move to frontend.h, when they are implemented
1254 Boolean EvalGraphIsUp();
1255 Boolean MoveHistoryIsUp();
1256 Boolean GameListIsUp();
1258 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1261 // front-end part of option handling
1263 // [HGM] This platform-dependent table provides the location for storing the color info
1266 &appData.whitePieceColor,
1267 &appData.blackPieceColor,
1268 &appData.lightSquareColor,
1269 &appData.darkSquareColor,
1270 &appData.highlightSquareColor,
1271 &appData.premoveHighlightColor,
1284 ParseFont(char *name, int number)
1285 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1287 case 0: // CLOCK_FONT
1288 appData.clockFont = strdup(name);
1290 case 1: // MESSAGE_FONT
1291 appData.font = strdup(name);
1293 case 2: // COORD_FONT
1294 appData.coordFont = strdup(name);
1303 { // only 2 fonts currently
1304 appData.clockFont = CLOCK_FONT_NAME;
1305 appData.coordFont = COORD_FONT_NAME;
1306 appData.font = DEFAULT_FONT_NAME;
1311 { // no-op, until we identify the code for this already in XBoard and move it here
1315 ParseColor(int n, char *name)
1316 { // in XBoard, just copy the color-name string
1317 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1321 ParseTextAttribs(ColorClass cc, char *s)
1323 (&appData.colorShout)[cc] = strdup(s);
1327 ParseBoardSize(void *addr, char *name)
1329 appData.boardSize = strdup(name);
1334 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1338 SetCommPortDefaults()
1339 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1342 // [HGM] args: these three cases taken out to stay in front-end
1344 SaveFontArg(FILE *f, ArgDescriptor *ad)
1347 switch((int)ad->argLoc) {
1348 case 0: // CLOCK_FONT
1349 name = appData.clockFont;
1351 case 1: // MESSAGE_FONT
1352 name = appData.font;
1354 case 2: // COORD_FONT
1355 name = appData.coordFont;
1360 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, name);
1365 { // nothing to do, as the sounds are at all times represented by their text-string names already
1369 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1370 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1371 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1375 SaveColor(FILE *f, ArgDescriptor *ad)
1376 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1377 if(colorVariable[(int)ad->argLoc])
1378 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1382 SaveBoardSize(FILE *f, char *name, void *addr)
1383 { // wrapper to shield back-end from BoardSize & sizeInfo
1384 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1388 ParseCommPortSettings(char *s)
1389 { // no such option in XBoard (yet)
1392 extern Widget engineOutputShell;
1393 extern Widget tagsShell, editTagsShell;
1395 GetActualPlacement(Widget wg, WindowPlacement *wp)
1405 XtSetArg(args[i], XtNx, &x); i++;
1406 XtSetArg(args[i], XtNy, &y); i++;
1407 XtSetArg(args[i], XtNwidth, &w); i++;
1408 XtSetArg(args[i], XtNheight, &h); i++;
1409 XtGetValues(wg, args, i);
1418 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1419 // In XBoard this will have to wait until awareness of window parameters is implemented
1420 GetActualPlacement(shellWidget, &wpMain);
1421 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1422 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1423 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1424 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1425 else GetActualPlacement(editShell, &wpComment);
1426 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1427 else GetActualPlacement(editTagsShell, &wpTags);
1429 GetActualPlacement(hwndConsole, &wpConsole);
1430 GetActualPlacement(evalGraphDialog, &wpEvalGraph);
1435 PrintCommPortSettings(FILE *f, char *name)
1436 { // This option does not exist in XBoard
1440 MySearchPath(char *installDir, char *name, char *fullname)
1441 { // just append installDir and name. Perhaps ExpandPath should be used here?
1442 name = ExpandPathName(name);
1443 if(name && name[0] == '/') strcpy(fullname, name); else {
1444 sprintf(fullname, "%s%c%s", installDir, '/', name);
1450 MyGetFullPathName(char *name, char *fullname)
1451 { // should use ExpandPath?
1452 name = ExpandPathName(name);
1453 strcpy(fullname, name);
1458 EnsureOnScreen(int *x, int *y, int minX, int minY)
1471 { // [HGM] args: allows testing if main window is realized from back-end
1472 return xBoardWindow != 0;
1476 PopUpStartupDialog()
1477 { // start menu not implemented in XBoard
1480 ConvertToLine(int argc, char **argv)
1482 static char line[128*1024], buf[1024];
1486 for(i=1; i<argc; i++) {
1487 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1488 && argv[i][0] != '{' )
1489 sprintf(buf, "{%s} ", argv[i]);
1490 else sprintf(buf, "%s ", argv[i]);
1493 line[strlen(line)-1] = NULLCHAR;
1497 //--------------------------------------------------------------------------------------------
1500 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1502 #define BoardSize int
1503 void InitDrawingSizes(BoardSize boardSize, int flags)
1504 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1505 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1507 XtGeometryResult gres;
1510 if(!formWidget) return;
1513 * Enable shell resizing.
1515 shellArgs[0].value = (XtArgVal) &w;
1516 shellArgs[1].value = (XtArgVal) &h;
1517 XtGetValues(shellWidget, shellArgs, 2);
1519 shellArgs[4].value = 2*w; shellArgs[2].value = 10;
1520 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1521 XtSetValues(shellWidget, &shellArgs[2], 4);
1523 XtSetArg(args[0], XtNdefaultDistance, &sep);
1524 XtGetValues(formWidget, args, 1);
1526 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1527 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1530 XtSetArg(args[0], XtNwidth, boardWidth);
1531 XtSetArg(args[1], XtNheight, boardHeight);
1532 XtSetValues(boardWidget, args, 2);
1534 timerWidth = (boardWidth - sep) / 2;
1535 XtSetArg(args[0], XtNwidth, timerWidth);
1536 XtSetValues(whiteTimerWidget, args, 1);
1537 XtSetValues(blackTimerWidget, args, 1);
1539 XawFormDoLayout(formWidget, False);
1541 if (appData.titleInWindow) {
1543 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1544 XtSetArg(args[i], XtNheight, &h); i++;
1545 XtGetValues(titleWidget, args, i);
1547 w = boardWidth - 2*bor;
1549 XtSetArg(args[0], XtNwidth, &w);
1550 XtGetValues(menuBarWidget, args, 1);
1551 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1554 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1555 if (gres != XtGeometryYes && appData.debugMode) {
1557 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1558 programName, gres, w, h, wr, hr);
1562 XawFormDoLayout(formWidget, True);
1565 * Inhibit shell resizing.
1567 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW;
1568 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1569 shellArgs[4].value = shellArgs[2].value = w;
1570 shellArgs[5].value = shellArgs[3].value = h;
1571 XtSetValues(shellWidget, &shellArgs[0], 6);
1573 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1576 for(i=0; i<4; i++) {
1578 for(p=0; p<=(int)WhiteKing; p++)
1579 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1580 if(gameInfo.variant == VariantShogi) {
1581 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1582 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1583 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1584 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1585 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1588 if(gameInfo.variant == VariantGothic) {
1589 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1593 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1594 for(p=0; p<=(int)WhiteKing; p++)
1595 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1596 if(gameInfo.variant == VariantShogi) {
1597 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1598 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1599 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1600 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1601 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1604 if(gameInfo.variant == VariantGothic) {
1605 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1611 for(i=0; i<2; i++) {
1613 for(p=0; p<=(int)WhiteKing; p++)
1614 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1615 if(gameInfo.variant == VariantShogi) {
1616 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1617 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1618 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1619 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1620 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1623 if(gameInfo.variant == VariantGothic) {
1624 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1635 void EscapeExpand(char *p, char *q)
1636 { // [HGM] initstring: routine to shape up string arguments
1637 while(*p++ = *q++) if(p[-1] == '\\')
1639 case 'n': p[-1] = '\n'; break;
1640 case 'r': p[-1] = '\r'; break;
1641 case 't': p[-1] = '\t'; break;
1642 case '\\': p[-1] = '\\'; break;
1643 case 0: *p = 0; return;
1644 default: p[-1] = q[-1]; break;
1653 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1654 XSetWindowAttributes window_attributes;
1656 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1657 XrmValue vFrom, vTo;
1658 XtGeometryResult gres;
1661 int forceMono = False;
1662 //define INDIRECTION
1664 // [HGM] before anything else, expand any indirection files amongst options
1665 char *argvCopy[1000]; // 1000 seems enough
1666 char newArgs[10000]; // holds actual characters
1669 srandom(time(0)); // [HGM] book: make random truly random
1672 for(i=0; i<argc; i++) {
1673 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1674 //fprintf(stderr, "arg %s\n", argv[i]);
1675 if(argv[i][0] != '@') argvCopy[j++] = argv[i]; else {
1677 FILE *f = fopen(argv[i]+1, "rb");
1678 if(f == NULL) { fprintf(stderr, _("ignore %s\n"), argv[i]); continue; } // do not expand non-existing
1679 argvCopy[j++] = newArgs + k; // get ready for first argument from file
1680 while((c = fgetc(f)) != EOF) { // each line of file inserts 1 argument in the list
1682 if(j >= 1000-2) { printf(_("too many arguments\n")); exit(-1); }
1683 newArgs[k++] = 0; // terminate current arg
1684 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1685 argvCopy[j++] = newArgs + k; // get ready for next
1687 if(k >= 10000-1) { printf(_("too long arguments\n")); exit(-1); }
1701 setbuf(stdout, NULL);
1702 setbuf(stderr, NULL);
1705 programName = strrchr(argv[0], '/');
1706 if (programName == NULL)
1707 programName = argv[0];
1712 XtSetLanguageProc(NULL, NULL, NULL);
1713 bindtextdomain(PACKAGE, LOCALEDIR);
1714 textdomain(PACKAGE);
1718 XtAppInitialize(&appContext, "XBoard", shellOptions,
1719 XtNumber(shellOptions),
1720 &argc, argv, xboardResources, NULL, 0);
1721 appData.boardSize = "";
1722 InitAppData(ConvertToLine(argc, argv));
1724 if (p == NULL) p = "/tmp";
1725 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1726 gameCopyFilename = (char*) malloc(i);
1727 gamePasteFilename = (char*) malloc(i);
1728 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1729 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1731 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1732 clientResources, XtNumber(clientResources),
1735 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1736 static char buf[MSG_SIZ];
1737 EscapeExpand(buf, appData.initString);
1738 appData.initString = strdup(buf);
1739 EscapeExpand(buf, appData.secondInitString);
1740 appData.secondInitString = strdup(buf);
1741 EscapeExpand(buf, appData.firstComputerString);
1742 appData.firstComputerString = strdup(buf);
1743 EscapeExpand(buf, appData.secondComputerString);
1744 appData.secondComputerString = strdup(buf);
1747 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1750 if (chdir(chessDir) != 0) {
1751 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1757 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1758 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1759 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1760 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1763 setbuf(debugFP, NULL);
1766 /* [HGM,HR] make sure board size is acceptable */
1767 if(appData.NrFiles > BOARD_FILES ||
1768 appData.NrRanks > BOARD_RANKS )
1769 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1772 /* This feature does not work; animation needs a rewrite */
1773 appData.highlightDragging = FALSE;
1777 xDisplay = XtDisplay(shellWidget);
1778 xScreen = DefaultScreen(xDisplay);
1779 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1781 gameInfo.variant = StringToVariant(appData.variant);
1782 InitPosition(FALSE);
1785 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1787 if (isdigit(appData.boardSize[0])) {
1788 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1789 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1790 &fontPxlSize, &smallLayout, &tinyLayout);
1792 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1793 programName, appData.boardSize);
1797 /* Find some defaults; use the nearest known size */
1798 SizeDefaults *szd, *nearest;
1799 int distance = 99999;
1800 nearest = szd = sizeDefaults;
1801 while (szd->name != NULL) {
1802 if (abs(szd->squareSize - squareSize) < distance) {
1804 distance = abs(szd->squareSize - squareSize);
1805 if (distance == 0) break;
1809 if (i < 2) lineGap = nearest->lineGap;
1810 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1811 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1812 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1813 if (i < 6) smallLayout = nearest->smallLayout;
1814 if (i < 7) tinyLayout = nearest->tinyLayout;
1817 SizeDefaults *szd = sizeDefaults;
1818 if (*appData.boardSize == NULLCHAR) {
1819 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1820 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1823 if (szd->name == NULL) szd--;
1824 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1826 while (szd->name != NULL &&
1827 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1828 if (szd->name == NULL) {
1829 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1830 programName, appData.boardSize);
1834 squareSize = szd->squareSize;
1835 lineGap = szd->lineGap;
1836 clockFontPxlSize = szd->clockFontPxlSize;
1837 coordFontPxlSize = szd->coordFontPxlSize;
1838 fontPxlSize = szd->fontPxlSize;
1839 smallLayout = szd->smallLayout;
1840 tinyLayout = szd->tinyLayout;
1843 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1844 if (strlen(appData.pixmapDirectory) > 0) {
1845 p = ExpandPathName(appData.pixmapDirectory);
1847 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1848 appData.pixmapDirectory);
1851 if (appData.debugMode) {
1852 fprintf(stderr, _("\
1853 XBoard square size (hint): %d\n\
1854 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1856 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1857 if (appData.debugMode) {
1858 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1862 /* [HR] height treated separately (hacked) */
1863 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1864 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1865 if (appData.showJail == 1) {
1866 /* Jail on top and bottom */
1867 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1868 XtSetArg(boardArgs[2], XtNheight,
1869 boardHeight + 2*(lineGap + squareSize));
1870 } else if (appData.showJail == 2) {
1872 XtSetArg(boardArgs[1], XtNwidth,
1873 boardWidth + 2*(lineGap + squareSize));
1874 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1877 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1878 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1882 * Determine what fonts to use.
1884 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1885 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1886 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1887 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1888 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1889 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1890 appData.font = FindFont(appData.font, fontPxlSize);
1891 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
1892 countFontStruct = XQueryFont(xDisplay, countFontID);
1893 // appData.font = FindFont(appData.font, fontPxlSize);
1895 xdb = XtDatabase(xDisplay);
1896 XrmPutStringResource(&xdb, "*font", appData.font);
1899 * Detect if there are not enough colors available and adapt.
1901 if (DefaultDepth(xDisplay, xScreen) <= 2) {
1902 appData.monoMode = True;
1905 if (!appData.monoMode) {
1906 vFrom.addr = (caddr_t) appData.lightSquareColor;
1907 vFrom.size = strlen(appData.lightSquareColor);
1908 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1909 if (vTo.addr == NULL) {
1910 appData.monoMode = True;
1913 lightSquareColor = *(Pixel *) vTo.addr;
1916 if (!appData.monoMode) {
1917 vFrom.addr = (caddr_t) appData.darkSquareColor;
1918 vFrom.size = strlen(appData.darkSquareColor);
1919 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1920 if (vTo.addr == NULL) {
1921 appData.monoMode = True;
1924 darkSquareColor = *(Pixel *) vTo.addr;
1927 if (!appData.monoMode) {
1928 vFrom.addr = (caddr_t) appData.whitePieceColor;
1929 vFrom.size = strlen(appData.whitePieceColor);
1930 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1931 if (vTo.addr == NULL) {
1932 appData.monoMode = True;
1935 whitePieceColor = *(Pixel *) vTo.addr;
1938 if (!appData.monoMode) {
1939 vFrom.addr = (caddr_t) appData.blackPieceColor;
1940 vFrom.size = strlen(appData.blackPieceColor);
1941 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1942 if (vTo.addr == NULL) {
1943 appData.monoMode = True;
1946 blackPieceColor = *(Pixel *) vTo.addr;
1950 if (!appData.monoMode) {
1951 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1952 vFrom.size = strlen(appData.highlightSquareColor);
1953 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1954 if (vTo.addr == NULL) {
1955 appData.monoMode = True;
1958 highlightSquareColor = *(Pixel *) vTo.addr;
1962 if (!appData.monoMode) {
1963 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1964 vFrom.size = strlen(appData.premoveHighlightColor);
1965 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1966 if (vTo.addr == NULL) {
1967 appData.monoMode = True;
1970 premoveHighlightColor = *(Pixel *) vTo.addr;
1975 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
1978 if (appData.bitmapDirectory == NULL ||
1979 appData.bitmapDirectory[0] == NULLCHAR)
1980 appData.bitmapDirectory = DEF_BITMAP_DIR;
1983 if (appData.lowTimeWarning && !appData.monoMode) {
1984 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
1985 vFrom.size = strlen(appData.lowTimeWarningColor);
1986 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1987 if (vTo.addr == NULL)
1988 appData.monoMode = True;
1990 lowTimeWarningColor = *(Pixel *) vTo.addr;
1993 if (appData.monoMode && appData.debugMode) {
1994 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
1995 (unsigned long) XWhitePixel(xDisplay, xScreen),
1996 (unsigned long) XBlackPixel(xDisplay, xScreen));
1999 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2000 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2001 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2002 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2003 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2004 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2005 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2006 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2007 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2008 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2010 if (appData.colorize) {
2012 _("%s: can't parse color names; disabling colorization\n"),
2015 appData.colorize = FALSE;
2017 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2018 textColors[ColorNone].attr = 0;
2020 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2026 layoutName = "tinyLayout";
2027 } else if (smallLayout) {
2028 layoutName = "smallLayout";
2030 layoutName = "normalLayout";
2032 /* Outer layoutWidget is there only to provide a name for use in
2033 resources that depend on the layout style */
2035 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2036 layoutArgs, XtNumber(layoutArgs));
2038 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2039 formArgs, XtNumber(formArgs));
2040 XtSetArg(args[0], XtNdefaultDistance, &sep);
2041 XtGetValues(formWidget, args, 1);
2044 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2045 XtSetArg(args[0], XtNtop, XtChainTop);
2046 XtSetArg(args[1], XtNbottom, XtChainTop);
2047 XtSetArg(args[2], XtNright, XtChainLeft);
2048 XtSetValues(menuBarWidget, args, 3);
2050 widgetList[j++] = whiteTimerWidget =
2051 XtCreateWidget("whiteTime", labelWidgetClass,
2052 formWidget, timerArgs, XtNumber(timerArgs));
2053 XtSetArg(args[0], XtNfont, clockFontStruct);
2054 XtSetArg(args[1], XtNtop, XtChainTop);
2055 XtSetArg(args[2], XtNbottom, XtChainTop);
2056 XtSetValues(whiteTimerWidget, args, 3);
2058 widgetList[j++] = blackTimerWidget =
2059 XtCreateWidget("blackTime", labelWidgetClass,
2060 formWidget, timerArgs, XtNumber(timerArgs));
2061 XtSetArg(args[0], XtNfont, clockFontStruct);
2062 XtSetArg(args[1], XtNtop, XtChainTop);
2063 XtSetArg(args[2], XtNbottom, XtChainTop);
2064 XtSetValues(blackTimerWidget, args, 3);
2066 if (appData.titleInWindow) {
2067 widgetList[j++] = titleWidget =
2068 XtCreateWidget("title", labelWidgetClass, formWidget,
2069 titleArgs, XtNumber(titleArgs));
2070 XtSetArg(args[0], XtNtop, XtChainTop);
2071 XtSetArg(args[1], XtNbottom, XtChainTop);
2072 XtSetValues(titleWidget, args, 2);
2075 if (appData.showButtonBar) {
2076 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2077 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2078 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2079 XtSetArg(args[2], XtNtop, XtChainTop);
2080 XtSetArg(args[3], XtNbottom, XtChainTop);
2081 XtSetValues(buttonBarWidget, args, 4);
2084 widgetList[j++] = messageWidget =
2085 XtCreateWidget("message", labelWidgetClass, formWidget,
2086 messageArgs, XtNumber(messageArgs));
2087 XtSetArg(args[0], XtNtop, XtChainTop);
2088 XtSetArg(args[1], XtNbottom, XtChainTop);
2089 XtSetValues(messageWidget, args, 2);
2091 widgetList[j++] = boardWidget =
2092 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2093 XtNumber(boardArgs));
2095 XtManageChildren(widgetList, j);
2097 timerWidth = (boardWidth - sep) / 2;
2098 XtSetArg(args[0], XtNwidth, timerWidth);
2099 XtSetValues(whiteTimerWidget, args, 1);
2100 XtSetValues(blackTimerWidget, args, 1);
2102 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2103 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2104 XtGetValues(whiteTimerWidget, args, 2);
2106 if (appData.showButtonBar) {
2107 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2108 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2109 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2113 * formWidget uses these constraints but they are stored
2117 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2118 XtSetValues(menuBarWidget, args, i);
2119 if (appData.titleInWindow) {
2122 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2123 XtSetValues(whiteTimerWidget, args, i);
2125 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2126 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2127 XtSetValues(blackTimerWidget, args, i);
2129 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2130 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2131 XtSetValues(titleWidget, args, i);
2133 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2134 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2135 XtSetValues(messageWidget, args, i);
2136 if (appData.showButtonBar) {
2138 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2139 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2140 XtSetValues(buttonBarWidget, args, i);
2144 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2145 XtSetValues(whiteTimerWidget, args, i);
2147 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2148 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2149 XtSetValues(blackTimerWidget, args, i);
2151 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2152 XtSetValues(titleWidget, args, i);
2154 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2155 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2156 XtSetValues(messageWidget, args, i);
2157 if (appData.showButtonBar) {
2159 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2160 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2161 XtSetValues(buttonBarWidget, args, i);
2166 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2167 XtSetValues(whiteTimerWidget, args, i);
2169 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2170 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2171 XtSetValues(blackTimerWidget, args, i);
2173 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2174 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2175 XtSetValues(messageWidget, args, i);
2176 if (appData.showButtonBar) {
2178 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2179 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2180 XtSetValues(buttonBarWidget, args, i);
2184 XtSetArg(args[0], XtNfromVert, messageWidget);
2185 XtSetArg(args[1], XtNtop, XtChainTop);
2186 XtSetArg(args[2], XtNbottom, XtChainBottom);
2187 XtSetArg(args[3], XtNleft, XtChainLeft);
2188 XtSetArg(args[4], XtNright, XtChainRight);
2189 XtSetValues(boardWidget, args, 5);
2191 XtRealizeWidget(shellWidget);
2194 XtSetArg(args[0], XtNx, wpMain.x);
2195 XtSetArg(args[1], XtNy, wpMain.y);
2196 XtSetValues(shellWidget, args, 2);
2200 * Correct the width of the message and title widgets.
2201 * It is not known why some systems need the extra fudge term.
2202 * The value "2" is probably larger than needed.
2204 XawFormDoLayout(formWidget, False);
2206 #define WIDTH_FUDGE 2
2208 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2209 XtSetArg(args[i], XtNheight, &h); i++;
2210 XtGetValues(messageWidget, args, i);
2211 if (appData.showButtonBar) {
2213 XtSetArg(args[i], XtNwidth, &w); i++;
2214 XtGetValues(buttonBarWidget, args, i);
2215 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2217 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2220 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2221 if (gres != XtGeometryYes && appData.debugMode) {
2222 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2223 programName, gres, w, h, wr, hr);
2226 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2227 /* The size used for the child widget in layout lags one resize behind
2228 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2230 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2231 if (gres != XtGeometryYes && appData.debugMode) {
2232 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2233 programName, gres, w, h, wr, hr);
2236 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2237 XtSetArg(args[1], XtNright, XtChainRight);
2238 XtSetValues(messageWidget, args, 2);
2240 if (appData.titleInWindow) {
2242 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2243 XtSetArg(args[i], XtNheight, &h); i++;
2244 XtGetValues(titleWidget, args, i);
2246 w = boardWidth - 2*bor;
2248 XtSetArg(args[0], XtNwidth, &w);
2249 XtGetValues(menuBarWidget, args, 1);
2250 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2253 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2254 if (gres != XtGeometryYes && appData.debugMode) {
2256 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2257 programName, gres, w, h, wr, hr);
2260 XawFormDoLayout(formWidget, True);
2262 xBoardWindow = XtWindow(boardWidget);
2264 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2265 // not need to go into InitDrawingSizes().
2269 * Create X checkmark bitmap and initialize option menu checks.
2271 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2272 checkmark_bits, checkmark_width, checkmark_height);
2273 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2274 if (appData.alwaysPromoteToQueen) {
2275 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2278 if (appData.animateDragging) {
2279 XtSetValues(XtNameToWidget(menuBarWidget,
2280 "menuOptions.Animate Dragging"),
2283 if (appData.animate) {
2284 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2287 if (appData.autoComment) {
2288 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2291 if (appData.autoCallFlag) {
2292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2295 if (appData.autoFlipView) {
2296 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2299 if (appData.autoObserve) {
2300 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2303 if (appData.autoRaiseBoard) {
2304 XtSetValues(XtNameToWidget(menuBarWidget,
2305 "menuOptions.Auto Raise Board"), args, 1);
2307 if (appData.autoSaveGames) {
2308 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2311 if (appData.saveGameFile[0] != NULLCHAR) {
2312 /* Can't turn this off from menu */
2313 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2315 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2319 if (appData.blindfold) {
2320 XtSetValues(XtNameToWidget(menuBarWidget,
2321 "menuOptions.Blindfold"), args, 1);
2323 if (appData.flashCount > 0) {
2324 XtSetValues(XtNameToWidget(menuBarWidget,
2325 "menuOptions.Flash Moves"),
2328 if (appData.getMoveList) {
2329 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2333 if (appData.highlightDragging) {
2334 XtSetValues(XtNameToWidget(menuBarWidget,
2335 "menuOptions.Highlight Dragging"),
2339 if (appData.highlightLastMove) {
2340 XtSetValues(XtNameToWidget(menuBarWidget,
2341 "menuOptions.Highlight Last Move"),
2344 if (appData.icsAlarm) {
2345 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2348 if (appData.ringBellAfterMoves) {
2349 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2352 if (appData.oldSaveStyle) {
2353 XtSetValues(XtNameToWidget(menuBarWidget,
2354 "menuOptions.Old Save Style"), args, 1);
2356 if (appData.periodicUpdates) {
2357 XtSetValues(XtNameToWidget(menuBarWidget,
2358 "menuOptions.Periodic Updates"), args, 1);
2360 if (appData.ponderNextMove) {
2361 XtSetValues(XtNameToWidget(menuBarWidget,
2362 "menuOptions.Ponder Next Move"), args, 1);
2364 if (appData.popupExitMessage) {
2365 XtSetValues(XtNameToWidget(menuBarWidget,
2366 "menuOptions.Popup Exit Message"), args, 1);
2368 if (appData.popupMoveErrors) {
2369 XtSetValues(XtNameToWidget(menuBarWidget,
2370 "menuOptions.Popup Move Errors"), args, 1);
2372 if (appData.premove) {
2373 XtSetValues(XtNameToWidget(menuBarWidget,
2374 "menuOptions.Premove"), args, 1);
2376 if (appData.quietPlay) {
2377 XtSetValues(XtNameToWidget(menuBarWidget,
2378 "menuOptions.Quiet Play"), args, 1);
2380 if (appData.showCoords) {
2381 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2384 if (appData.hideThinkingFromHuman) {
2385 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2388 if (appData.testLegality) {
2389 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2392 if (saveSettingsOnExit) {
2393 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2400 ReadBitmap(&wIconPixmap, "icon_white.bm",
2401 icon_white_bits, icon_white_width, icon_white_height);
2402 ReadBitmap(&bIconPixmap, "icon_black.bm",
2403 icon_black_bits, icon_black_width, icon_black_height);
2404 iconPixmap = wIconPixmap;
2406 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2407 XtSetValues(shellWidget, args, i);
2410 * Create a cursor for the board widget.
2412 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2413 XChangeWindowAttributes(xDisplay, xBoardWindow,
2414 CWCursor, &window_attributes);
2417 * Inhibit shell resizing.
2419 shellArgs[0].value = (XtArgVal) &w;
2420 shellArgs[1].value = (XtArgVal) &h;
2421 XtGetValues(shellWidget, shellArgs, 2);
2422 shellArgs[4].value = shellArgs[2].value = w;
2423 shellArgs[5].value = shellArgs[3].value = h;
2424 XtSetValues(shellWidget, &shellArgs[2], 4);
2425 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2426 marginH = h - boardHeight;
2428 CatchDeleteWindow(shellWidget, "QuitProc");
2433 if (appData.bitmapDirectory[0] != NULLCHAR) {
2440 /* Create regular pieces */
2441 if (!useImages) CreatePieces();
2446 if (appData.animate || appData.animateDragging)
2449 XtAugmentTranslations(formWidget,
2450 XtParseTranslationTable(globalTranslations));
2451 XtAugmentTranslations(boardWidget,
2452 XtParseTranslationTable(boardTranslations));
2453 XtAugmentTranslations(whiteTimerWidget,
2454 XtParseTranslationTable(whiteTranslations));
2455 XtAugmentTranslations(blackTimerWidget,
2456 XtParseTranslationTable(blackTranslations));
2458 /* Why is the following needed on some versions of X instead
2459 * of a translation? */
2460 XtAddEventHandler(boardWidget, ExposureMask, False,
2461 (XtEventHandler) EventProc, NULL);
2466 if (errorExitStatus == -1) {
2467 if (appData.icsActive) {
2468 /* We now wait until we see "login:" from the ICS before
2469 sending the logon script (problems with timestamp otherwise) */
2470 /*ICSInitScript();*/
2471 if (appData.icsInputBox) ICSInputBoxPopUp();
2475 signal(SIGWINCH, TermSizeSigHandler);
2477 signal(SIGINT, IntSigHandler);
2478 signal(SIGTERM, IntSigHandler);
2479 if (*appData.cmailGameName != NULLCHAR) {
2480 signal(SIGUSR1, CmailSigHandler);
2483 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2486 XtAppMainLoop(appContext);
2487 if (appData.debugMode) fclose(debugFP); // [DM] debug
2494 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2495 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2497 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2498 unlink(gameCopyFilename);
2499 unlink(gamePasteFilename);
2502 RETSIGTYPE TermSizeSigHandler(int sig)
2515 CmailSigHandler(sig)
2521 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2523 /* Activate call-back function CmailSigHandlerCallBack() */
2524 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2526 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2530 CmailSigHandlerCallBack(isr, closure, message, count, error)
2538 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2540 /**** end signal code ****/
2550 f = fopen(appData.icsLogon, "r");
2556 strcat(buf, appData.icsLogon);
2557 f = fopen(buf, "r");
2561 ProcessICSInitScript(f);
2568 EditCommentPopDown();
2583 if (!menuBarWidget) return;
2584 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2586 DisplayError("menuStep.Revert", 0);
2588 XtSetSensitive(w, !grey);
2593 SetMenuEnables(enab)
2597 if (!menuBarWidget) return;
2598 while (enab->name != NULL) {
2599 w = XtNameToWidget(menuBarWidget, enab->name);
2601 DisplayError(enab->name, 0);
2603 XtSetSensitive(w, enab->value);
2609 Enables icsEnables[] = {
2610 { "menuFile.Mail Move", False },
2611 { "menuFile.Reload CMail Message", False },
2612 { "menuMode.Machine Black", False },
2613 { "menuMode.Machine White", False },
2614 { "menuMode.Analysis Mode", False },
2615 { "menuMode.Analyze File", False },
2616 { "menuMode.Two Machines", False },
2618 { "menuHelp.Hint", False },
2619 { "menuHelp.Book", False },
2620 { "menuStep.Move Now", False },
2621 { "menuOptions.Periodic Updates", False },
2622 { "menuOptions.Hide Thinking", False },
2623 { "menuOptions.Ponder Next Move", False },
2628 Enables ncpEnables[] = {
2629 { "menuFile.Mail Move", False },
2630 { "menuFile.Reload CMail Message", False },
2631 { "menuMode.Machine White", False },
2632 { "menuMode.Machine Black", False },
2633 { "menuMode.Analysis Mode", False },
2634 { "menuMode.Analyze File", False },
2635 { "menuMode.Two Machines", False },
2636 { "menuMode.ICS Client", False },
2637 { "menuMode.ICS Input Box", False },
2638 { "Action", False },
2639 { "menuStep.Revert", False },
2640 { "menuStep.Move Now", False },
2641 { "menuStep.Retract Move", False },
2642 { "menuOptions.Auto Comment", False },
2643 { "menuOptions.Auto Flag", False },
2644 { "menuOptions.Auto Flip View", False },
2645 { "menuOptions.Auto Observe", False },
2646 { "menuOptions.Auto Raise Board", False },
2647 { "menuOptions.Get Move List", False },
2648 { "menuOptions.ICS Alarm", False },
2649 { "menuOptions.Move Sound", False },
2650 { "menuOptions.Quiet Play", False },
2651 { "menuOptions.Hide Thinking", False },
2652 { "menuOptions.Periodic Updates", False },
2653 { "menuOptions.Ponder Next Move", False },
2654 { "menuHelp.Hint", False },
2655 { "menuHelp.Book", False },
2659 Enables gnuEnables[] = {
2660 { "menuMode.ICS Client", False },
2661 { "menuMode.ICS Input Box", False },
2662 { "menuAction.Accept", False },
2663 { "menuAction.Decline", False },
2664 { "menuAction.Rematch", False },
2665 { "menuAction.Adjourn", False },
2666 { "menuAction.Stop Examining", False },
2667 { "menuAction.Stop Observing", False },
2668 { "menuStep.Revert", False },
2669 { "menuOptions.Auto Comment", False },
2670 { "menuOptions.Auto Observe", False },
2671 { "menuOptions.Auto Raise Board", False },
2672 { "menuOptions.Get Move List", False },
2673 { "menuOptions.Premove", False },
2674 { "menuOptions.Quiet Play", False },
2676 /* The next two options rely on SetCmailMode being called *after* */
2677 /* SetGNUMode so that when GNU is being used to give hints these */
2678 /* menu options are still available */
2680 { "menuFile.Mail Move", False },
2681 { "menuFile.Reload CMail Message", False },
2685 Enables cmailEnables[] = {
2687 { "menuAction.Call Flag", False },
2688 { "menuAction.Draw", True },
2689 { "menuAction.Adjourn", False },
2690 { "menuAction.Abort", False },
2691 { "menuAction.Stop Observing", False },
2692 { "menuAction.Stop Examining", False },
2693 { "menuFile.Mail Move", True },
2694 { "menuFile.Reload CMail Message", True },
2698 Enables trainingOnEnables[] = {
2699 { "menuMode.Edit Comment", False },
2700 { "menuMode.Pause", False },
2701 { "menuStep.Forward", False },
2702 { "menuStep.Backward", False },
2703 { "menuStep.Forward to End", False },
2704 { "menuStep.Back to Start", False },
2705 { "menuStep.Move Now", False },
2706 { "menuStep.Truncate Game", False },
2710 Enables trainingOffEnables[] = {
2711 { "menuMode.Edit Comment", True },
2712 { "menuMode.Pause", True },
2713 { "menuStep.Forward", True },
2714 { "menuStep.Backward", True },
2715 { "menuStep.Forward to End", True },
2716 { "menuStep.Back to Start", True },
2717 { "menuStep.Move Now", True },
2718 { "menuStep.Truncate Game", True },
2722 Enables machineThinkingEnables[] = {
2723 { "menuFile.Load Game", False },
2724 { "menuFile.Load Next Game", False },
2725 { "menuFile.Load Previous Game", False },
2726 { "menuFile.Reload Same Game", False },
2727 { "menuFile.Paste Game", False },
2728 { "menuFile.Load Position", False },
2729 { "menuFile.Load Next Position", False },
2730 { "menuFile.Load Previous Position", False },
2731 { "menuFile.Reload Same Position", False },
2732 { "menuFile.Paste Position", False },
2733 { "menuMode.Machine White", False },
2734 { "menuMode.Machine Black", False },
2735 { "menuMode.Two Machines", False },
2736 { "menuStep.Retract Move", False },
2740 Enables userThinkingEnables[] = {
2741 { "menuFile.Load Game", True },
2742 { "menuFile.Load Next Game", True },
2743 { "menuFile.Load Previous Game", True },
2744 { "menuFile.Reload Same Game", True },
2745 { "menuFile.Paste Game", True },
2746 { "menuFile.Load Position", True },
2747 { "menuFile.Load Next Position", True },
2748 { "menuFile.Load Previous Position", True },
2749 { "menuFile.Reload Same Position", True },
2750 { "menuFile.Paste Position", True },
2751 { "menuMode.Machine White", True },
2752 { "menuMode.Machine Black", True },
2753 { "menuMode.Two Machines", True },
2754 { "menuStep.Retract Move", True },
2760 SetMenuEnables(icsEnables);
2763 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2764 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2771 SetMenuEnables(ncpEnables);
2777 SetMenuEnables(gnuEnables);
2783 SetMenuEnables(cmailEnables);
2789 SetMenuEnables(trainingOnEnables);
2790 if (appData.showButtonBar) {
2791 XtSetSensitive(buttonBarWidget, False);
2797 SetTrainingModeOff()
2799 SetMenuEnables(trainingOffEnables);
2800 if (appData.showButtonBar) {
2801 XtSetSensitive(buttonBarWidget, True);
2806 SetUserThinkingEnables()
2808 if (appData.noChessProgram) return;
2809 SetMenuEnables(userThinkingEnables);
2813 SetMachineThinkingEnables()
2815 if (appData.noChessProgram) return;
2816 SetMenuEnables(machineThinkingEnables);
2818 case MachinePlaysBlack:
2819 case MachinePlaysWhite:
2820 case TwoMachinesPlay:
2821 XtSetSensitive(XtNameToWidget(menuBarWidget,
2822 ModeToWidgetName(gameMode)), True);
2829 #define Abs(n) ((n)<0 ? -(n) : (n))
2832 * Find a font that matches "pattern" that is as close as
2833 * possible to the targetPxlSize. Prefer fonts that are k
2834 * pixels smaller to fonts that are k pixels larger. The
2835 * pattern must be in the X Consortium standard format,
2836 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
2837 * The return value should be freed with XtFree when no
2840 char *FindFont(pattern, targetPxlSize)
2844 char **fonts, *p, *best, *scalable, *scalableTail;
2845 int i, j, nfonts, minerr, err, pxlSize;
2848 char **missing_list;
2850 char *def_string, *base_fnt_lst, strInt[3];
2852 XFontStruct **fnt_list;
2854 base_fnt_lst = calloc(1, strlen(pattern) + 3);
2855 sprintf(strInt, "%d", targetPxlSize);
2856 p = strstr(pattern, "--");
2857 strncpy(base_fnt_lst, pattern, p - pattern + 2);
2858 strcat(base_fnt_lst, strInt);
2859 strcat(base_fnt_lst, strchr(p + 2, '-'));
2861 if ((fntSet = XCreateFontSet(xDisplay,
2865 &def_string)) == NULL) {
2867 fprintf(stderr, _("Unable to create font set.\n"));
2871 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
2873 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
2875 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
2876 programName, pattern);
2884 for (i=0; i<nfonts; i++) {
2887 if (*p != '-') continue;
2889 if (*p == NULLCHAR) break;
2890 if (*p++ == '-') j++;
2892 if (j < 7) continue;
2895 scalable = fonts[i];
2898 err = pxlSize - targetPxlSize;
2899 if (Abs(err) < Abs(minerr) ||
2900 (minerr > 0 && err < 0 && -err == minerr)) {
2906 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
2907 /* If the error is too big and there is a scalable font,
2908 use the scalable font. */
2909 int headlen = scalableTail - scalable;
2910 p = (char *) XtMalloc(strlen(scalable) + 10);
2911 while (isdigit(*scalableTail)) scalableTail++;
2912 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
2914 p = (char *) XtMalloc(strlen(best) + 1);
2917 if (appData.debugMode) {
2918 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
2919 pattern, targetPxlSize, p);
2922 if (missing_count > 0)
2923 XFreeStringList(missing_list);
2924 XFreeFontSet(xDisplay, fntSet);
2926 XFreeFontNames(fonts);
2933 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
2934 | GCBackground | GCFunction | GCPlaneMask;
2935 XGCValues gc_values;
2938 gc_values.plane_mask = AllPlanes;
2939 gc_values.line_width = lineGap;
2940 gc_values.line_style = LineSolid;
2941 gc_values.function = GXcopy;
2943 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2944 gc_values.background = XBlackPixel(xDisplay, xScreen);
2945 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2947 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2948 gc_values.background = XWhitePixel(xDisplay, xScreen);
2949 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
2950 XSetFont(xDisplay, coordGC, coordFontID);
2952 // [HGM] make font for holdings counts (white on black0
2953 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2954 gc_values.background = XBlackPixel(xDisplay, xScreen);
2955 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
2956 XSetFont(xDisplay, countGC, countFontID);
2958 if (appData.monoMode) {
2959 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2960 gc_values.background = XWhitePixel(xDisplay, xScreen);
2961 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2963 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
2964 gc_values.background = XBlackPixel(xDisplay, xScreen);
2965 lightSquareGC = wbPieceGC
2966 = XtGetGC(shellWidget, value_mask, &gc_values);
2968 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
2969 gc_values.background = XWhitePixel(xDisplay, xScreen);
2970 darkSquareGC = bwPieceGC
2971 = XtGetGC(shellWidget, value_mask, &gc_values);
2973 if (DefaultDepth(xDisplay, xScreen) == 1) {
2974 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
2975 gc_values.function = GXcopyInverted;
2976 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
2977 gc_values.function = GXcopy;
2978 if (XBlackPixel(xDisplay, xScreen) == 1) {
2979 bwPieceGC = darkSquareGC;
2980 wbPieceGC = copyInvertedGC;
2982 bwPieceGC = copyInvertedGC;
2983 wbPieceGC = lightSquareGC;
2987 gc_values.foreground = highlightSquareColor;
2988 gc_values.background = highlightSquareColor;
2989 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2991 gc_values.foreground = premoveHighlightColor;
2992 gc_values.background = premoveHighlightColor;
2993 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
2995 gc_values.foreground = lightSquareColor;
2996 gc_values.background = darkSquareColor;
2997 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
2999 gc_values.foreground = darkSquareColor;
3000 gc_values.background = lightSquareColor;
3001 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3003 gc_values.foreground = jailSquareColor;
3004 gc_values.background = jailSquareColor;
3005 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3007 gc_values.foreground = whitePieceColor;
3008 gc_values.background = darkSquareColor;
3009 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3011 gc_values.foreground = whitePieceColor;
3012 gc_values.background = lightSquareColor;
3013 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3015 gc_values.foreground = whitePieceColor;
3016 gc_values.background = jailSquareColor;
3017 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3019 gc_values.foreground = blackPieceColor;
3020 gc_values.background = darkSquareColor;
3021 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3023 gc_values.foreground = blackPieceColor;
3024 gc_values.background = lightSquareColor;
3025 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3027 gc_values.foreground = blackPieceColor;
3028 gc_values.background = jailSquareColor;
3029 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3033 void loadXIM(xim, xmask, filename, dest, mask)
3046 fp = fopen(filename, "rb");
3048 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3055 for (y=0; y<h; ++y) {
3056 for (x=0; x<h; ++x) {
3061 XPutPixel(xim, x, y, blackPieceColor);
3063 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3066 XPutPixel(xim, x, y, darkSquareColor);
3068 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3071 XPutPixel(xim, x, y, whitePieceColor);
3073 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3076 XPutPixel(xim, x, y, lightSquareColor);
3078 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3084 /* create Pixmap of piece */
3085 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3087 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3090 /* create Pixmap of clipmask
3091 Note: We assume the white/black pieces have the same
3092 outline, so we make only 6 masks. This is okay
3093 since the XPM clipmask routines do the same. */
3095 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3097 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3100 /* now create the 1-bit version */
3101 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3104 values.foreground = 1;
3105 values.background = 0;
3107 /* Don't use XtGetGC, not read only */
3108 maskGC = XCreateGC(xDisplay, *mask,
3109 GCForeground | GCBackground, &values);
3110 XCopyPlane(xDisplay, temp, *mask, maskGC,
3111 0, 0, squareSize, squareSize, 0, 0, 1);
3112 XFreePixmap(xDisplay, temp);
3117 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3119 void CreateXIMPieces()
3124 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3129 /* The XSynchronize calls were copied from CreatePieces.
3130 Not sure if needed, but can't hurt */
3131 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3134 /* temp needed by loadXIM() */
3135 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3136 0, 0, ss, ss, AllPlanes, XYPixmap);
3138 if (strlen(appData.pixmapDirectory) == 0) {
3142 if (appData.monoMode) {
3143 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3147 fprintf(stderr, _("\nLoading XIMs...\n"));
3149 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3150 fprintf(stderr, "%d", piece+1);
3151 for (kind=0; kind<4; kind++) {
3152 fprintf(stderr, ".");
3153 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3154 ExpandPathName(appData.pixmapDirectory),
3155 piece <= (int) WhiteKing ? "" : "w",
3156 pieceBitmapNames[piece],
3158 ximPieceBitmap[kind][piece] =
3159 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3160 0, 0, ss, ss, AllPlanes, XYPixmap);
3161 if (appData.debugMode)
3162 fprintf(stderr, _("(File:%s:) "), buf);
3163 loadXIM(ximPieceBitmap[kind][piece],
3165 &(xpmPieceBitmap2[kind][piece]),
3166 &(ximMaskPm2[piece]));
3167 if(piece <= (int)WhiteKing)
3168 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3170 fprintf(stderr," ");
3172 /* Load light and dark squares */
3173 /* If the LSQ and DSQ pieces don't exist, we will
3174 draw them with solid squares. */
3175 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3176 if (access(buf, 0) != 0) {
3180 fprintf(stderr, _("light square "));
3182 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3183 0, 0, ss, ss, AllPlanes, XYPixmap);
3184 if (appData.debugMode)
3185 fprintf(stderr, _("(File:%s:) "), buf);
3187 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3188 fprintf(stderr, _("dark square "));
3189 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3190 ExpandPathName(appData.pixmapDirectory), ss);
3191 if (appData.debugMode)
3192 fprintf(stderr, _("(File:%s:) "), buf);
3194 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3195 0, 0, ss, ss, AllPlanes, XYPixmap);
3196 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3197 xpmJailSquare = xpmLightSquare;
3199 fprintf(stderr, _("Done.\n"));
3201 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3205 void CreateXPMPieces()
3209 u_int ss = squareSize;
3211 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3212 XpmColorSymbol symbols[4];
3214 /* The XSynchronize calls were copied from CreatePieces.
3215 Not sure if needed, but can't hurt */
3216 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3218 /* Setup translations so piece colors match square colors */
3219 symbols[0].name = "light_piece";
3220 symbols[0].value = appData.whitePieceColor;
3221 symbols[1].name = "dark_piece";
3222 symbols[1].value = appData.blackPieceColor;
3223 symbols[2].name = "light_square";
3224 symbols[2].value = appData.lightSquareColor;
3225 symbols[3].name = "dark_square";
3226 symbols[3].value = appData.darkSquareColor;
3228 attr.valuemask = XpmColorSymbols;
3229 attr.colorsymbols = symbols;
3230 attr.numsymbols = 4;
3232 if (appData.monoMode) {
3233 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3237 if (strlen(appData.pixmapDirectory) == 0) {
3238 XpmPieces* pieces = builtInXpms;
3241 while (pieces->size != squareSize && pieces->size) pieces++;
3242 if (!pieces->size) {
3243 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3246 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3247 for (kind=0; kind<4; kind++) {
3249 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3250 pieces->xpm[piece][kind],
3251 &(xpmPieceBitmap2[kind][piece]),
3252 NULL, &attr)) != 0) {
3253 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3257 if(piece <= (int) WhiteKing)
3258 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3262 xpmJailSquare = xpmLightSquare;
3266 fprintf(stderr, _("\nLoading XPMs...\n"));
3269 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3270 fprintf(stderr, "%d ", piece+1);
3271 for (kind=0; kind<4; kind++) {
3272 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3273 ExpandPathName(appData.pixmapDirectory),
3274 piece > (int) WhiteKing ? "w" : "",
3275 pieceBitmapNames[piece],
3277 if (appData.debugMode) {
3278 fprintf(stderr, _("(File:%s:) "), buf);
3280 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3281 &(xpmPieceBitmap2[kind][piece]),
3282 NULL, &attr)) != 0) {
3283 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3284 // [HGM] missing: read of unorthodox piece failed; substitute King.
3285 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3286 ExpandPathName(appData.pixmapDirectory),
3288 if (appData.debugMode) {
3289 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3291 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3292 &(xpmPieceBitmap2[kind][piece]),
3296 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3301 if(piece <= (int) WhiteKing)
3302 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3305 /* Load light and dark squares */
3306 /* If the LSQ and DSQ pieces don't exist, we will
3307 draw them with solid squares. */
3308 fprintf(stderr, _("light square "));
3309 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3310 if (access(buf, 0) != 0) {
3314 if (appData.debugMode)
3315 fprintf(stderr, _("(File:%s:) "), buf);
3317 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3318 &xpmLightSquare, NULL, &attr)) != 0) {
3319 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3322 fprintf(stderr, _("dark square "));
3323 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3324 ExpandPathName(appData.pixmapDirectory), ss);
3325 if (appData.debugMode) {
3326 fprintf(stderr, _("(File:%s:) "), buf);
3328 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3329 &xpmDarkSquare, NULL, &attr)) != 0) {
3330 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3334 xpmJailSquare = xpmLightSquare;
3335 fprintf(stderr, _("Done.\n"));
3337 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3340 #endif /* HAVE_LIBXPM */
3343 /* No built-in bitmaps */
3348 u_int ss = squareSize;
3350 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3353 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3354 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3355 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3356 pieceBitmapNames[piece],
3357 ss, kind == SOLID ? 's' : 'o');
3358 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3359 if(piece <= (int)WhiteKing)
3360 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3364 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3368 /* With built-in bitmaps */
3371 BuiltInBits* bib = builtInBits;
3374 u_int ss = squareSize;
3376 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3379 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3381 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3382 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3383 sprintf(buf, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3384 pieceBitmapNames[piece],
3385 ss, kind == SOLID ? 's' : 'o');
3386 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3387 bib->bits[kind][piece], ss, ss);
3388 if(piece <= (int)WhiteKing)
3389 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3393 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3398 void ReadBitmap(pm, name, bits, wreq, hreq)
3401 unsigned char bits[];
3407 char msg[MSG_SIZ], fullname[MSG_SIZ];
3409 if (*appData.bitmapDirectory != NULLCHAR) {
3410 strcpy(fullname, appData.bitmapDirectory);
3411 strcat(fullname, "/");
3412 strcat(fullname, name);
3413 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3414 &w, &h, pm, &x_hot, &y_hot);
3415 fprintf(stderr, "load %s\n", name);
3416 if (errcode != BitmapSuccess) {
3418 case BitmapOpenFailed:
3419 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3421 case BitmapFileInvalid:
3422 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3424 case BitmapNoMemory:
3425 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3429 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3433 fprintf(stderr, _("%s: %s...using built-in\n"),
3435 } else if (w != wreq || h != hreq) {
3437 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3438 programName, fullname, w, h, wreq, hreq);
3444 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3453 if (lineGap == 0) return;
3455 /* [HR] Split this into 2 loops for non-square boards. */
3457 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3458 gridSegments[i].x1 = 0;
3459 gridSegments[i].x2 =
3460 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3461 gridSegments[i].y1 = gridSegments[i].y2
3462 = lineGap / 2 + (i * (squareSize + lineGap));
3465 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3466 gridSegments[j + i].y1 = 0;
3467 gridSegments[j + i].y2 =
3468 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3469 gridSegments[j + i].x1 = gridSegments[j + i].x2
3470 = lineGap / 2 + (j * (squareSize + lineGap));
3474 static void MenuBarSelect(w, addr, index)
3479 XtActionProc proc = (XtActionProc) addr;
3481 (proc)(NULL, NULL, NULL, NULL);
3484 void CreateMenuBarPopup(parent, name, mb)
3494 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3497 XtSetArg(args[j], XtNleftMargin, 20); j++;
3498 XtSetArg(args[j], XtNrightMargin, 20); j++;
3500 while (mi->string != NULL) {
3501 if (strcmp(mi->string, "----") == 0) {
3502 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3505 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3506 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3508 XtAddCallback(entry, XtNcallback,
3509 (XtCallbackProc) MenuBarSelect,
3510 (caddr_t) mi->proc);
3516 Widget CreateMenuBar(mb)
3520 Widget anchor, menuBar;
3522 char menuName[MSG_SIZ];
3525 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3526 XtSetArg(args[j], XtNvSpace, 0); j++;
3527 XtSetArg(args[j], XtNborderWidth, 0); j++;
3528 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3529 formWidget, args, j);
3531 while (mb->name != NULL) {
3532 strcpy(menuName, "menu");
3533 strcat(menuName, mb->name);
3535 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3538 shortName[0] = _(mb->name)[0];
3539 shortName[1] = NULLCHAR;
3540 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3543 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3546 XtSetArg(args[j], XtNborderWidth, 0); j++;
3547 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3549 CreateMenuBarPopup(menuBar, menuName, mb);
3555 Widget CreateButtonBar(mi)
3559 Widget button, buttonBar;
3563 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3565 XtSetArg(args[j], XtNhSpace, 0); j++;
3567 XtSetArg(args[j], XtNborderWidth, 0); j++;
3568 XtSetArg(args[j], XtNvSpace, 0); j++;
3569 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3570 formWidget, args, j);
3572 while (mi->string != NULL) {
3575 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3576 XtSetArg(args[j], XtNborderWidth, 0); j++;
3578 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3579 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3580 buttonBar, args, j);
3581 XtAddCallback(button, XtNcallback,
3582 (XtCallbackProc) MenuBarSelect,
3583 (caddr_t) mi->proc);
3590 CreatePieceMenu(name, color)
3597 ChessSquare selection;
3599 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3600 boardWidget, args, 0);
3602 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3603 String item = pieceMenuStrings[color][i];
3605 if (strcmp(item, "----") == 0) {
3606 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3609 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3610 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3612 selection = pieceMenuTranslation[color][i];
3613 XtAddCallback(entry, XtNcallback,
3614 (XtCallbackProc) PieceMenuSelect,
3615 (caddr_t) selection);
3616 if (selection == WhitePawn || selection == BlackPawn) {
3617 XtSetArg(args[0], XtNpopupOnEntry, entry);
3618 XtSetValues(menu, args, 1);
3631 ChessSquare selection;
3633 whitePieceMenu = CreatePieceMenu("menuW", 0);
3634 blackPieceMenu = CreatePieceMenu("menuB", 1);
3636 XtRegisterGrabAction(PieceMenuPopup, True,
3637 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3638 GrabModeAsync, GrabModeAsync);
3640 XtSetArg(args[0], XtNlabel, _("Drop"));
3641 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3642 boardWidget, args, 1);
3643 for (i = 0; i < DROP_MENU_SIZE; i++) {
3644 String item = dropMenuStrings[i];
3646 if (strcmp(item, "----") == 0) {
3647 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3650 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3651 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3653 selection = dropMenuTranslation[i];
3654 XtAddCallback(entry, XtNcallback,
3655 (XtCallbackProc) DropMenuSelect,
3656 (caddr_t) selection);
3661 void SetupDropMenu()
3669 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3670 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3671 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3672 dmEnables[i].piece);
3673 XtSetSensitive(entry, p != NULL || !appData.testLegality
3674 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3675 && !appData.icsActive));
3677 while (p && *p++ == dmEnables[i].piece) count++;
3678 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3680 XtSetArg(args[j], XtNlabel, label); j++;
3681 XtSetValues(entry, args, j);
3685 void PieceMenuPopup(w, event, params, num_params)
3689 Cardinal *num_params;
3692 if (event->type != ButtonPress) return;
3693 if (errorUp) ErrorPopDown();
3697 whichMenu = params[0];
3699 case IcsPlayingWhite:
3700 case IcsPlayingBlack:
3702 case MachinePlaysWhite:
3703 case MachinePlaysBlack:
3704 if (appData.testLegality &&
3705 gameInfo.variant != VariantBughouse &&
3706 gameInfo.variant != VariantCrazyhouse) return;
3708 whichMenu = "menuD";
3714 if (((pmFromX = EventToSquare(event->xbutton.x, BOARD_WIDTH)) < 0) ||
3715 ((pmFromY = EventToSquare(event->xbutton.y, BOARD_HEIGHT)) < 0)) {
3716 pmFromX = pmFromY = -1;
3720 pmFromX = BOARD_WIDTH - 1 - pmFromX;
3722 pmFromY = BOARD_HEIGHT - 1 - pmFromY;
3724 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3727 static void PieceMenuSelect(w, piece, junk)
3732 if (pmFromX < 0 || pmFromY < 0) return;
3733 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3736 static void DropMenuSelect(w, piece, junk)
3741 if (pmFromX < 0 || pmFromY < 0) return;
3742 DropMenuEvent(piece, pmFromX, pmFromY);
3745 void WhiteClock(w, event, prms, nprms)
3751 if (gameMode == EditPosition || gameMode == IcsExamining) {
3752 SetWhiteToPlayEvent();
3753 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3758 void BlackClock(w, event, prms, nprms)
3764 if (gameMode == EditPosition || gameMode == IcsExamining) {
3765 SetBlackToPlayEvent();
3766 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3773 * If the user selects on a border boundary, return -1; if off the board,
3774 * return -2. Otherwise map the event coordinate to the square.
3776 int EventToSquare(x, limit)
3784 if ((x % (squareSize + lineGap)) >= squareSize)
3786 x /= (squareSize + lineGap);
3792 static void do_flash_delay(msec)
3798 static void drawHighlight(file, rank, gc)
3804 if (lineGap == 0 || appData.blindfold) return;
3807 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3808 (squareSize + lineGap);
3809 y = lineGap/2 + rank * (squareSize + lineGap);
3811 x = lineGap/2 + file * (squareSize + lineGap);
3812 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3813 (squareSize + lineGap);
3816 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3817 squareSize+lineGap, squareSize+lineGap);
3820 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3821 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
3824 SetHighlights(fromX, fromY, toX, toY)
3825 int fromX, fromY, toX, toY;
3827 if (hi1X != fromX || hi1Y != fromY) {
3828 if (hi1X >= 0 && hi1Y >= 0) {
3829 drawHighlight(hi1X, hi1Y, lineGC);
3831 if (fromX >= 0 && fromY >= 0) {
3832 drawHighlight(fromX, fromY, highlineGC);
3835 if (hi2X != toX || hi2Y != toY) {
3836 if (hi2X >= 0 && hi2Y >= 0) {
3837 drawHighlight(hi2X, hi2Y, lineGC);
3839 if (toX >= 0 && toY >= 0) {
3840 drawHighlight(toX, toY, highlineGC);
3852 SetHighlights(-1, -1, -1, -1);
3857 SetPremoveHighlights(fromX, fromY, toX, toY)
3858 int fromX, fromY, toX, toY;
3860 if (pm1X != fromX || pm1Y != fromY) {
3861 if (pm1X >= 0 && pm1Y >= 0) {
3862 drawHighlight(pm1X, pm1Y, lineGC);
3864 if (fromX >= 0 && fromY >= 0) {
3865 drawHighlight(fromX, fromY, prelineGC);
3868 if (pm2X != toX || pm2Y != toY) {
3869 if (pm2X >= 0 && pm2Y >= 0) {
3870 drawHighlight(pm2X, pm2Y, lineGC);
3872 if (toX >= 0 && toY >= 0) {
3873 drawHighlight(toX, toY, prelineGC);
3883 ClearPremoveHighlights()
3885 SetPremoveHighlights(-1, -1, -1, -1);
3888 static void BlankSquare(x, y, color, piece, dest)
3893 if (useImages && useImageSqs) {
3897 pm = xpmLightSquare;
3902 case 2: /* neutral */
3907 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
3908 squareSize, squareSize, x, y);
3918 case 2: /* neutral */
3923 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
3928 I split out the routines to draw a piece so that I could
3929 make a generic flash routine.
3931 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
3933 int square_color, x, y;
3936 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3937 switch (square_color) {
3939 case 2: /* neutral */
3941 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3942 ? *pieceToOutline(piece)
3943 : *pieceToSolid(piece),
3944 dest, bwPieceGC, 0, 0,
3945 squareSize, squareSize, x, y);
3948 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
3949 ? *pieceToSolid(piece)
3950 : *pieceToOutline(piece),
3951 dest, wbPieceGC, 0, 0,
3952 squareSize, squareSize, x, y);
3957 static void monoDrawPiece(piece, square_color, x, y, dest)
3959 int square_color, x, y;
3962 switch (square_color) {
3964 case 2: /* neutral */
3966 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3967 ? *pieceToOutline(piece)
3968 : *pieceToSolid(piece),
3969 dest, bwPieceGC, 0, 0,
3970 squareSize, squareSize, x, y, 1);
3973 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
3974 ? *pieceToSolid(piece)
3975 : *pieceToOutline(piece),
3976 dest, wbPieceGC, 0, 0,
3977 squareSize, squareSize, x, y, 1);
3982 static void colorDrawPiece(piece, square_color, x, y, dest)
3984 int square_color, x, y;
3987 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
3988 switch (square_color) {
3990 XCopyPlane(xDisplay, *pieceToSolid(piece),
3991 dest, (int) piece < (int) BlackPawn
3992 ? wlPieceGC : blPieceGC, 0, 0,
3993 squareSize, squareSize, x, y, 1);
3996 XCopyPlane(xDisplay, *pieceToSolid(piece),
3997 dest, (int) piece < (int) BlackPawn
3998 ? wdPieceGC : bdPieceGC, 0, 0,
3999 squareSize, squareSize, x, y, 1);
4001 case 2: /* neutral */
4003 XCopyPlane(xDisplay, *pieceToSolid(piece),
4004 dest, (int) piece < (int) BlackPawn
4005 ? wjPieceGC : bjPieceGC, 0, 0,
4006 squareSize, squareSize, x, y, 1);
4011 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4013 int square_color, x, y;
4018 switch (square_color) {
4020 case 2: /* neutral */
4022 if ((int)piece < (int) BlackPawn) {
4030 if ((int)piece < (int) BlackPawn) {
4038 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4039 dest, wlPieceGC, 0, 0,
4040 squareSize, squareSize, x, y);
4043 typedef void (*DrawFunc)();
4045 DrawFunc ChooseDrawFunc()
4047 if (appData.monoMode) {
4048 if (DefaultDepth(xDisplay, xScreen) == 1) {
4049 return monoDrawPiece_1bit;
4051 return monoDrawPiece;
4055 return colorDrawPieceImage;
4057 return colorDrawPiece;
4061 /* [HR] determine square color depending on chess variant. */
4062 static int SquareColor(row, column)
4067 if (gameInfo.variant == VariantXiangqi) {
4068 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4070 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4072 } else if (row <= 4) {
4078 square_color = ((column + row) % 2) == 1;
4081 /* [hgm] holdings: next line makes all holdings squares light */
4082 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4084 return square_color;
4087 void DrawSquare(row, column, piece, do_flash)
4088 int row, column, do_flash;
4091 int square_color, x, y, direction, font_ascent, font_descent;
4094 XCharStruct overall;
4098 /* Calculate delay in milliseconds (2-delays per complete flash) */
4099 flash_delay = 500 / appData.flashRate;
4102 x = lineGap + ((BOARD_WIDTH-1)-column) *
4103 (squareSize + lineGap);
4104 y = lineGap + row * (squareSize + lineGap);
4106 x = lineGap + column * (squareSize + lineGap);
4107 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4108 (squareSize + lineGap);
4111 square_color = SquareColor(row, column);
4113 if ( // [HGM] holdings: blank out area between board and holdings
4114 column == BOARD_LEFT-1 || column == BOARD_RGHT
4115 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4116 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4117 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4119 // [HGM] print piece counts next to holdings
4120 string[1] = NULLCHAR;
4121 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4122 string[0] = '0' + piece;
4123 XTextExtents(countFontStruct, string, 1, &direction,
4124 &font_ascent, &font_descent, &overall);
4125 if (appData.monoMode) {
4126 XDrawImageString(xDisplay, xBoardWindow, countGC,
4127 x + squareSize - overall.width - 2,
4128 y + font_ascent + 1, string, 1);
4130 XDrawString(xDisplay, xBoardWindow, countGC,
4131 x + squareSize - overall.width - 2,
4132 y + font_ascent + 1, string, 1);
4135 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4136 string[0] = '0' + piece;
4137 XTextExtents(countFontStruct, string, 1, &direction,
4138 &font_ascent, &font_descent, &overall);
4139 if (appData.monoMode) {
4140 XDrawImageString(xDisplay, xBoardWindow, countGC,
4141 x + 2, y + font_ascent + 1, string, 1);
4143 XDrawString(xDisplay, xBoardWindow, countGC,
4144 x + 2, y + font_ascent + 1, string, 1);
4148 if (piece == EmptySquare || appData.blindfold) {
4149 BlankSquare(x, y, square_color, piece, xBoardWindow);
4151 drawfunc = ChooseDrawFunc();
4152 if (do_flash && appData.flashCount > 0) {
4153 for (i=0; i<appData.flashCount; ++i) {
4155 drawfunc(piece, square_color, x, y, xBoardWindow);
4156 XSync(xDisplay, False);
4157 do_flash_delay(flash_delay);
4159 BlankSquare(x, y, square_color, piece, xBoardWindow);
4160 XSync(xDisplay, False);
4161 do_flash_delay(flash_delay);
4164 drawfunc(piece, square_color, x, y, xBoardWindow);
4168 string[1] = NULLCHAR;
4169 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4170 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4171 string[0] = 'a' + column - BOARD_LEFT;
4172 XTextExtents(coordFontStruct, string, 1, &direction,
4173 &font_ascent, &font_descent, &overall);
4174 if (appData.monoMode) {
4175 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4176 x + squareSize - overall.width - 2,
4177 y + squareSize - font_descent - 1, string, 1);
4179 XDrawString(xDisplay, xBoardWindow, coordGC,
4180 x + squareSize - overall.width - 2,
4181 y + squareSize - font_descent - 1, string, 1);
4184 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4185 string[0] = ONE + row;
4186 XTextExtents(coordFontStruct, string, 1, &direction,
4187 &font_ascent, &font_descent, &overall);
4188 if (appData.monoMode) {
4189 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4190 x + 2, y + font_ascent + 1, string, 1);
4192 XDrawString(xDisplay, xBoardWindow, coordGC,
4193 x + 2, y + font_ascent + 1, string, 1);
4199 /* Why is this needed on some versions of X? */
4200 void EventProc(widget, unused, event)
4205 if (!XtIsRealized(widget))
4208 switch (event->type) {
4210 if (event->xexpose.count > 0) return; /* no clipping is done */
4211 XDrawPosition(widget, True, NULL);
4219 void DrawPosition(fullRedraw, board)
4220 /*Boolean*/int fullRedraw;
4223 XDrawPosition(boardWidget, fullRedraw, board);
4226 /* Returns 1 if there are "too many" differences between b1 and b2
4227 (i.e. more than 1 move was made) */
4228 static int too_many_diffs(b1, b2)
4234 for (i=0; i<BOARD_HEIGHT; ++i) {
4235 for (j=0; j<BOARD_WIDTH; ++j) {
4236 if (b1[i][j] != b2[i][j]) {
4237 if (++c > 4) /* Castling causes 4 diffs */
4246 /* Matrix describing castling maneuvers */
4247 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4248 static int castling_matrix[4][5] = {
4249 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4250 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4251 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4252 { 7, 7, 4, 5, 6 } /* 0-0, black */
4255 /* Checks whether castling occurred. If it did, *rrow and *rcol
4256 are set to the destination (row,col) of the rook that moved.
4258 Returns 1 if castling occurred, 0 if not.
4260 Note: Only handles a max of 1 castling move, so be sure
4261 to call too_many_diffs() first.
4263 static int check_castle_draw(newb, oldb, rrow, rcol)
4270 /* For each type of castling... */
4271 for (i=0; i<4; ++i) {
4272 r = castling_matrix[i];
4274 /* Check the 4 squares involved in the castling move */
4276 for (j=1; j<=4; ++j) {
4277 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4284 /* All 4 changed, so it must be a castling move */
4293 static int damage[BOARD_RANKS][BOARD_FILES];
4296 * event handler for redrawing the board
4298 void XDrawPosition(w, repaint, board)
4300 /*Boolean*/int repaint;
4304 static int lastFlipView = 0;
4305 static int lastBoardValid = 0;
4306 static Board lastBoard;
4310 if (board == NULL) {
4311 if (!lastBoardValid) return;
4314 if (!lastBoardValid || lastFlipView != flipView) {
4315 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4316 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4321 * It would be simpler to clear the window with XClearWindow()
4322 * but this causes a very distracting flicker.
4325 if (!repaint && lastBoardValid && lastFlipView == flipView) {
4327 /* If too much changes (begin observing new game, etc.), don't
4329 do_flash = too_many_diffs(board, lastBoard) ? 0 : 1;
4331 /* Special check for castling so we don't flash both the king
4332 and the rook (just flash the king). */
4334 if (check_castle_draw(board, lastBoard, &rrow, &rcol)) {
4335 /* Draw rook with NO flashing. King will be drawn flashing later */
4336 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4337 lastBoard[rrow][rcol] = board[rrow][rcol];
4341 /* First pass -- Draw (newly) empty squares and repair damage.
4342 This prevents you from having a piece show up twice while it
4343 is flashing on its new square */
4344 for (i = 0; i < BOARD_HEIGHT; i++)
4345 for (j = 0; j < BOARD_WIDTH; j++)
4346 if ((board[i][j] != lastBoard[i][j] && board[i][j] == EmptySquare)
4348 DrawSquare(i, j, board[i][j], 0);
4349 damage[i][j] = False;
4352 /* Second pass -- Draw piece(s) in new position and flash them */
4353 for (i = 0; i < BOARD_HEIGHT; i++)
4354 for (j = 0; j < BOARD_WIDTH; j++)
4355 if (board[i][j] != lastBoard[i][j]) {
4356 DrawSquare(i, j, board[i][j], do_flash);
4360 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4361 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4363 for (i = 0; i < BOARD_HEIGHT; i++)
4364 for (j = 0; j < BOARD_WIDTH; j++) {
4365 DrawSquare(i, j, board[i][j], 0);
4366 damage[i][j] = False;
4370 CopyBoard(lastBoard, board);
4372 lastFlipView = flipView;
4374 /* Draw highlights */
4375 if (pm1X >= 0 && pm1Y >= 0) {
4376 drawHighlight(pm1X, pm1Y, prelineGC);
4378 if (pm2X >= 0 && pm2Y >= 0) {
4379 drawHighlight(pm2X, pm2Y, prelineGC);
4381 if (hi1X >= 0 && hi1Y >= 0) {
4382 drawHighlight(hi1X, hi1Y, highlineGC);
4384 if (hi2X >= 0 && hi2Y >= 0) {
4385 drawHighlight(hi2X, hi2Y, highlineGC);
4388 /* If piece being dragged around board, must redraw that too */
4391 XSync(xDisplay, False);
4396 * event handler for redrawing the board
4398 void DrawPositionProc(w, event, prms, nprms)
4404 XDrawPosition(w, True, NULL);
4409 * event handler for parsing user moves
4411 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4412 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4413 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4414 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4415 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4416 // and at the end FinishMove() to perform the move after optional promotion popups.
4417 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4418 void HandleUserMove(w, event, prms, nprms)
4424 if (w != boardWidget || errorExitStatus != -1) return;
4427 if (event->type == ButtonPress) {
4428 XtPopdown(promotionShell);
4429 XtDestroyWidget(promotionShell);
4430 promotionUp = False;
4438 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4439 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4440 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4443 void AnimateUserMove (Widget w, XEvent * event,
4444 String * params, Cardinal * nParams)
4446 DragPieceMove(event->xmotion.x, event->xmotion.y);
4449 Widget CommentCreate(name, text, mutable, callback, lines)
4451 int /*Boolean*/ mutable;
4452 XtCallbackProc callback;
4456 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4461 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4462 XtGetValues(boardWidget, args, j);
4465 XtSetArg(args[j], XtNresizable, True); j++;
4468 XtCreatePopupShell(name, topLevelShellWidgetClass,
4469 shellWidget, args, j);
4472 XtCreatePopupShell(name, transientShellWidgetClass,
4473 shellWidget, args, j);
4476 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4477 layoutArgs, XtNumber(layoutArgs));
4479 XtCreateManagedWidget("form", formWidgetClass, layout,
4480 formArgs, XtNumber(formArgs));
4484 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4485 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4487 XtSetArg(args[j], XtNstring, text); j++;
4488 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4489 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4490 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4491 XtSetArg(args[j], XtNright, XtChainRight); j++;
4492 XtSetArg(args[j], XtNresizable, True); j++;
4493 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4494 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4495 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4496 XtSetArg(args[j], XtNautoFill, True); j++;
4497 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4499 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4503 XtSetArg(args[j], XtNfromVert, edit); j++;
4504 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4505 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4506 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4507 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4509 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4510 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4513 XtSetArg(args[j], XtNfromVert, edit); j++;
4514 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4515 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4516 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4517 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4518 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4520 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4521 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4524 XtSetArg(args[j], XtNfromVert, edit); j++;
4525 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4526 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4527 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4528 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4529 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4531 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4532 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4535 XtSetArg(args[j], XtNfromVert, edit); j++;
4536 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4537 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4538 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4539 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4541 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4542 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4545 XtSetArg(args[j], XtNfromVert, edit); j++;
4546 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4547 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4548 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4549 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4550 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4552 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4553 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4556 XtRealizeWidget(shell);
4558 if (commentX == -1) {
4561 Dimension pw_height;
4562 Dimension ew_height;
4565 XtSetArg(args[j], XtNheight, &ew_height); j++;
4566 XtGetValues(edit, args, j);
4569 XtSetArg(args[j], XtNheight, &pw_height); j++;
4570 XtGetValues(shell, args, j);
4571 commentH = pw_height + (lines - 1) * ew_height;
4572 commentW = bw_width - 16;
4574 XSync(xDisplay, False);
4576 /* This code seems to tickle an X bug if it is executed too soon
4577 after xboard starts up. The coordinates get transformed as if
4578 the main window was positioned at (0, 0).
4580 XtTranslateCoords(shellWidget,
4581 (bw_width - commentW) / 2, 0 - commentH / 2,
4582 &commentX, &commentY);
4584 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4585 RootWindowOfScreen(XtScreen(shellWidget)),
4586 (bw_width - commentW) / 2, 0 - commentH / 2,
4591 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4594 if(wpComment.width > 0) {
4595 commentX = wpComment.x;
4596 commentY = wpComment.y;
4597 commentW = wpComment.width;
4598 commentH = wpComment.height;
4602 XtSetArg(args[j], XtNheight, commentH); j++;
4603 XtSetArg(args[j], XtNwidth, commentW); j++;
4604 XtSetArg(args[j], XtNx, commentX); j++;
4605 XtSetArg(args[j], XtNy, commentY); j++;
4606 XtSetValues(shell, args, j);
4607 XtSetKeyboardFocus(shell, edit);
4612 /* Used for analysis window and ICS input window */
4613 Widget MiscCreate(name, text, mutable, callback, lines)
4615 int /*Boolean*/ mutable;
4616 XtCallbackProc callback;
4620 Widget shell, layout, form, edit;
4622 Dimension bw_width, pw_height, ew_height, w, h;
4628 XtSetArg(args[j], XtNresizable, True); j++;
4631 XtCreatePopupShell(name, topLevelShellWidgetClass,
4632 shellWidget, args, j);
4635 XtCreatePopupShell(name, transientShellWidgetClass,
4636 shellWidget, args, j);
4639 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4640 layoutArgs, XtNumber(layoutArgs));
4642 XtCreateManagedWidget("form", formWidgetClass, layout,
4643 formArgs, XtNumber(formArgs));
4647 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4648 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4650 XtSetArg(args[j], XtNstring, text); j++;
4651 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4652 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4653 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4654 XtSetArg(args[j], XtNright, XtChainRight); j++;
4655 XtSetArg(args[j], XtNresizable, True); j++;
4656 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4657 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4658 XtSetArg(args[j], XtNautoFill, True); j++;
4659 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4661 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4663 XtRealizeWidget(shell);
4666 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4667 XtGetValues(boardWidget, args, j);
4670 XtSetArg(args[j], XtNheight, &ew_height); j++;
4671 XtGetValues(edit, args, j);
4674 XtSetArg(args[j], XtNheight, &pw_height); j++;
4675 XtGetValues(shell, args, j);
4676 h = pw_height + (lines - 1) * ew_height;
4679 XSync(xDisplay, False);
4681 /* This code seems to tickle an X bug if it is executed too soon
4682 after xboard starts up. The coordinates get transformed as if
4683 the main window was positioned at (0, 0).
4685 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4687 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4688 RootWindowOfScreen(XtScreen(shellWidget)),
4689 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4693 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4696 XtSetArg(args[j], XtNheight, h); j++;
4697 XtSetArg(args[j], XtNwidth, w); j++;
4698 XtSetArg(args[j], XtNx, x); j++;
4699 XtSetArg(args[j], XtNy, y); j++;
4700 XtSetValues(shell, args, j);
4706 static int savedIndex; /* gross that this is global */
4708 void EditCommentPopUp(index, title, text)
4717 if (text == NULL) text = "";
4719 if (editShell == NULL) {
4721 CommentCreate(title, text, True, EditCommentCallback, 4);
4722 XtRealizeWidget(editShell);
4723 CatchDeleteWindow(editShell, "EditCommentPopDown");
4725 edit = XtNameToWidget(editShell, "*form.text");
4727 XtSetArg(args[j], XtNstring, text); j++;
4728 XtSetValues(edit, args, j);
4730 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4731 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4732 XtSetValues(editShell, args, j);
4735 XtPopup(editShell, XtGrabNone);
4739 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4740 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4744 void EditCommentCallback(w, client_data, call_data)
4746 XtPointer client_data, call_data;
4754 XtSetArg(args[j], XtNlabel, &name); j++;
4755 XtGetValues(w, args, j);
4757 if (strcmp(name, _("ok")) == 0) {
4758 edit = XtNameToWidget(editShell, "*form.text");
4760 XtSetArg(args[j], XtNstring, &val); j++;
4761 XtGetValues(edit, args, j);
4762 ReplaceComment(savedIndex, val);
4763 EditCommentPopDown();
4764 } else if (strcmp(name, _("cancel")) == 0) {
4765 EditCommentPopDown();
4766 } else if (strcmp(name, _("clear")) == 0) {
4767 edit = XtNameToWidget(editShell, "*form.text");
4768 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4769 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4773 void EditCommentPopDown()
4778 if (!editUp) return;
4780 XtSetArg(args[j], XtNx, &commentX); j++;
4781 XtSetArg(args[j], XtNy, &commentY); j++;
4782 XtSetArg(args[j], XtNheight, &commentH); j++;
4783 XtSetArg(args[j], XtNwidth, &commentW); j++;
4784 XtGetValues(editShell, args, j);
4785 XtPopdown(editShell);
4788 XtSetArg(args[j], XtNleftBitmap, None); j++;
4789 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4793 void ICSInputBoxPopUp()
4798 char *title = _("ICS Input");
4801 if (ICSInputShell == NULL) {
4802 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
4803 tr = XtParseTranslationTable(ICSInputTranslations);
4804 edit = XtNameToWidget(ICSInputShell, "*form.text");
4805 XtOverrideTranslations(edit, tr);
4806 XtRealizeWidget(ICSInputShell);
4807 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
4810 edit = XtNameToWidget(ICSInputShell, "*form.text");
4812 XtSetArg(args[j], XtNstring, ""); j++;
4813 XtSetValues(edit, args, j);
4815 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4816 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4817 XtSetValues(ICSInputShell, args, j);
4820 XtPopup(ICSInputShell, XtGrabNone);
4821 XtSetKeyboardFocus(ICSInputShell, edit);
4823 ICSInputBoxUp = True;
4825 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4826 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4830 void ICSInputSendText()
4837 edit = XtNameToWidget(ICSInputShell, "*form.text");
4839 XtSetArg(args[j], XtNstring, &val); j++;
4840 XtGetValues(edit, args, j);
4841 SendMultiLineToICS(val);
4842 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4843 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4846 void ICSInputBoxPopDown()
4851 if (!ICSInputBoxUp) return;
4853 XtPopdown(ICSInputShell);
4854 ICSInputBoxUp = False;
4856 XtSetArg(args[j], XtNleftBitmap, None); j++;
4857 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
4861 void CommentPopUp(title, text)
4868 if (commentShell == NULL) {
4870 CommentCreate(title, text, False, CommentCallback, 4);
4871 XtRealizeWidget(commentShell);
4872 CatchDeleteWindow(commentShell, "CommentPopDown");
4874 edit = XtNameToWidget(commentShell, "*form.text");
4876 XtSetArg(args[j], XtNstring, text); j++;
4877 XtSetValues(edit, args, j);
4879 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4880 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4881 XtSetValues(commentShell, args, j);
4884 XtPopup(commentShell, XtGrabNone);
4885 XSync(xDisplay, False);
4890 void CommentCallback(w, client_data, call_data)
4892 XtPointer client_data, call_data;
4899 XtSetArg(args[j], XtNlabel, &name); j++;
4900 XtGetValues(w, args, j);
4902 if (strcmp(name, _("close")) == 0) {
4904 } else if (strcmp(name, _("edit")) == 0) {
4911 void CommentPopDown()
4916 if (!commentUp) return;
4918 XtSetArg(args[j], XtNx, &commentX); j++;
4919 XtSetArg(args[j], XtNy, &commentY); j++;
4920 XtSetArg(args[j], XtNwidth, &commentW); j++;
4921 XtSetArg(args[j], XtNheight, &commentH); j++;
4922 XtGetValues(commentShell, args, j);
4923 XtPopdown(commentShell);
4924 XSync(xDisplay, False);
4928 void FileNamePopUp(label, def, proc, openMode)
4935 Widget popup, layout, dialog, edit;
4941 fileProc = proc; /* I can't see a way not */
4942 fileOpenMode = openMode; /* to use globals here */
4945 XtSetArg(args[i], XtNresizable, True); i++;
4946 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
4947 XtSetArg(args[i], XtNtitle, XtNewString(_("File name prompt"))); i++;
4948 fileNameShell = popup =
4949 XtCreatePopupShell("File name prompt", transientShellWidgetClass,
4950 shellWidget, args, i);
4953 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
4954 layoutArgs, XtNumber(layoutArgs));
4957 XtSetArg(args[i], XtNlabel, label); i++;
4958 XtSetArg(args[i], XtNvalue, def); i++;
4959 XtSetArg(args[i], XtNborderWidth, 0); i++;
4960 dialog = XtCreateManagedWidget("fileName", dialogWidgetClass,
4963 XawDialogAddButton(dialog, _("ok"), FileNameCallback, (XtPointer) dialog);
4964 XawDialogAddButton(dialog, _("cancel"), FileNameCallback,
4965 (XtPointer) dialog);
4967 XtRealizeWidget(popup);
4968 CatchDeleteWindow(popup, "FileNamePopDown");
4970 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
4971 &x, &y, &win_x, &win_y, &mask);
4973 XtSetArg(args[0], XtNx, x - 10);
4974 XtSetArg(args[1], XtNy, y - 30);
4975 XtSetValues(popup, args, 2);
4977 XtPopup(popup, XtGrabExclusive);
4980 edit = XtNameToWidget(dialog, "*value");
4981 XtSetKeyboardFocus(popup, edit);
4984 void FileNamePopDown()
4986 if (!filenameUp) return;
4987 XtPopdown(fileNameShell);
4988 XtDestroyWidget(fileNameShell);
4993 void FileNameCallback(w, client_data, call_data)
4995 XtPointer client_data, call_data;
5000 XtSetArg(args[0], XtNlabel, &name);
5001 XtGetValues(w, args, 1);
5003 if (strcmp(name, _("cancel")) == 0) {
5008 FileNameAction(w, NULL, NULL, NULL);
5011 void FileNameAction(w, event, prms, nprms)
5023 name = XawDialogGetValueString(w = XtParent(w));
5025 if ((name != NULL) && (*name != NULLCHAR)) {
5027 XtPopdown(w = XtParent(XtParent(w)));
5031 p = strrchr(buf, ' ');
5038 fullname = ExpandPathName(buf);
5040 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5043 f = fopen(fullname, fileOpenMode);
5045 DisplayError(_("Failed to open file"), errno);
5047 (void) (*fileProc)(f, index, buf);
5054 XtPopdown(w = XtParent(XtParent(w)));
5060 void PromotionPopUp()
5063 Widget dialog, layout;
5065 Dimension bw_width, pw_width;
5069 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5070 XtGetValues(boardWidget, args, j);
5073 XtSetArg(args[j], XtNresizable, True); j++;
5074 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5076 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5077 shellWidget, args, j);
5079 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5080 layoutArgs, XtNumber(layoutArgs));
5083 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5084 XtSetArg(args[j], XtNborderWidth, 0); j++;
5085 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5088 if(gameInfo.variant != VariantShogi) {
5089 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5090 (XtPointer) dialog);
5091 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5092 (XtPointer) dialog);
5093 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5094 (XtPointer) dialog);
5095 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5096 (XtPointer) dialog);
5097 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5098 gameInfo.variant == VariantGiveaway) {
5099 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5100 (XtPointer) dialog);
5102 if(gameInfo.variant == VariantCapablanca ||
5103 gameInfo.variant == VariantGothic ||
5104 gameInfo.variant == VariantCapaRandom) {
5105 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5106 (XtPointer) dialog);
5107 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5108 (XtPointer) dialog);
5110 } else // [HGM] shogi
5112 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5113 (XtPointer) dialog);
5114 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5115 (XtPointer) dialog);
5117 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5118 (XtPointer) dialog);
5120 XtRealizeWidget(promotionShell);
5121 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5124 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5125 XtGetValues(promotionShell, args, j);
5127 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5128 lineGap + squareSize/3 +
5129 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5130 0 : 6*(squareSize + lineGap)), &x, &y);
5133 XtSetArg(args[j], XtNx, x); j++;
5134 XtSetArg(args[j], XtNy, y); j++;
5135 XtSetValues(promotionShell, args, j);
5137 XtPopup(promotionShell, XtGrabNone);
5142 void PromotionPopDown()
5144 if (!promotionUp) return;
5145 XtPopdown(promotionShell);
5146 XtDestroyWidget(promotionShell);
5147 promotionUp = False;
5150 void PromotionCallback(w, client_data, call_data)
5152 XtPointer client_data, call_data;
5158 XtSetArg(args[0], XtNlabel, &name);
5159 XtGetValues(w, args, 1);
5163 if (fromX == -1) return;
5165 if (strcmp(name, _("cancel")) == 0) {
5169 } else if (strcmp(name, _("Knight")) == 0) {
5171 } else if (strcmp(name, _("Promote")) == 0) {
5173 } else if (strcmp(name, _("Defer")) == 0) {
5176 promoChar = ToLower(name[0]);
5179 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5181 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5182 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5187 void ErrorCallback(w, client_data, call_data)
5189 XtPointer client_data, call_data;
5192 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5194 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5200 if (!errorUp) return;
5202 XtPopdown(errorShell);
5203 XtDestroyWidget(errorShell);
5204 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5207 void ErrorPopUp(title, label, modal)
5208 char *title, *label;
5212 Widget dialog, layout;
5216 Dimension bw_width, pw_width;
5217 Dimension pw_height;
5221 XtSetArg(args[i], XtNresizable, True); i++;
5222 XtSetArg(args[i], XtNtitle, title); i++;
5224 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5225 shellWidget, args, i);
5227 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5228 layoutArgs, XtNumber(layoutArgs));
5231 XtSetArg(args[i], XtNlabel, label); i++;
5232 XtSetArg(args[i], XtNborderWidth, 0); i++;
5233 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5236 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5238 XtRealizeWidget(errorShell);
5239 CatchDeleteWindow(errorShell, "ErrorPopDown");
5242 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5243 XtGetValues(boardWidget, args, i);
5245 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5246 XtSetArg(args[i], XtNheight, &pw_height); i++;
5247 XtGetValues(errorShell, args, i);
5250 /* This code seems to tickle an X bug if it is executed too soon
5251 after xboard starts up. The coordinates get transformed as if
5252 the main window was positioned at (0, 0).
5254 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5255 0 - pw_height + squareSize / 3, &x, &y);
5257 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5258 RootWindowOfScreen(XtScreen(boardWidget)),
5259 (bw_width - pw_width) / 2,
5260 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5264 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5267 XtSetArg(args[i], XtNx, x); i++;
5268 XtSetArg(args[i], XtNy, y); i++;
5269 XtSetValues(errorShell, args, i);
5272 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5275 /* Disable all user input other than deleting the window */
5276 static int frozen = 0;
5280 /* Grab by a widget that doesn't accept input */
5281 XtAddGrab(messageWidget, TRUE, FALSE);
5285 /* Undo a FreezeUI */
5288 if (!frozen) return;
5289 XtRemoveGrab(messageWidget);
5293 char *ModeToWidgetName(mode)
5297 case BeginningOfGame:
5298 if (appData.icsActive)
5299 return "menuMode.ICS Client";
5300 else if (appData.noChessProgram ||
5301 *appData.cmailGameName != NULLCHAR)
5302 return "menuMode.Edit Game";
5304 return "menuMode.Machine Black";
5305 case MachinePlaysBlack:
5306 return "menuMode.Machine Black";
5307 case MachinePlaysWhite:
5308 return "menuMode.Machine White";
5310 return "menuMode.Analysis Mode";
5312 return "menuMode.Analyze File";
5313 case TwoMachinesPlay:
5314 return "menuMode.Two Machines";
5316 return "menuMode.Edit Game";
5317 case PlayFromGameFile:
5318 return "menuFile.Load Game";
5320 return "menuMode.Edit Position";
5322 return "menuMode.Training";
5323 case IcsPlayingWhite:
5324 case IcsPlayingBlack:
5328 return "menuMode.ICS Client";
5335 void ModeHighlight()
5338 static int oldPausing = FALSE;
5339 static GameMode oldmode = (GameMode) -1;
5342 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5344 if (pausing != oldPausing) {
5345 oldPausing = pausing;
5347 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5349 XtSetArg(args[0], XtNleftBitmap, None);
5351 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5354 if (appData.showButtonBar) {
5355 /* Always toggle, don't set. Previous code messes up when
5356 invoked while the button is pressed, as releasing it
5357 toggles the state again. */
5360 XtSetArg(args[0], XtNbackground, &oldbg);
5361 XtSetArg(args[1], XtNforeground, &oldfg);
5362 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5364 XtSetArg(args[0], XtNbackground, oldfg);
5365 XtSetArg(args[1], XtNforeground, oldbg);
5367 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5371 wname = ModeToWidgetName(oldmode);
5372 if (wname != NULL) {
5373 XtSetArg(args[0], XtNleftBitmap, None);
5374 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5376 wname = ModeToWidgetName(gameMode);
5377 if (wname != NULL) {
5378 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5379 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5383 /* Maybe all the enables should be handled here, not just this one */
5384 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5385 gameMode == Training || gameMode == PlayFromGameFile);
5390 * Button/menu procedures
5392 void ResetProc(w, event, prms, nprms)
5401 int LoadGamePopUp(f, gameNumber, title)
5406 cmailMsgLoaded = FALSE;
5407 if (gameNumber == 0) {
5408 int error = GameListBuild(f);
5410 DisplayError(_("Cannot build game list"), error);
5411 } else if (!ListEmpty(&gameList) &&
5412 ((ListGame *) gameList.tailPred)->number > 1) {
5413 GameListPopUp(f, title);
5419 return LoadGame(f, gameNumber, title, FALSE);
5422 void LoadGameProc(w, event, prms, nprms)
5428 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5431 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5434 void LoadNextGameProc(w, event, prms, nprms)
5443 void LoadPrevGameProc(w, event, prms, nprms)
5452 void ReloadGameProc(w, event, prms, nprms)
5461 void LoadNextPositionProc(w, event, prms, nprms)
5470 void LoadPrevPositionProc(w, event, prms, nprms)
5479 void ReloadPositionProc(w, event, prms, nprms)
5488 void LoadPositionProc(w, event, prms, nprms)
5494 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5497 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5500 void SaveGameProc(w, event, prms, nprms)
5506 FileNamePopUp(_("Save game file name?"),
5507 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5511 void SavePositionProc(w, event, prms, nprms)
5517 FileNamePopUp(_("Save position file name?"),
5518 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5522 void ReloadCmailMsgProc(w, event, prms, nprms)
5528 ReloadCmailMsgEvent(FALSE);
5531 void MailMoveProc(w, event, prms, nprms)
5540 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5541 static char *selected_fen_position=NULL;
5544 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5545 Atom *type_return, XtPointer *value_return,
5546 unsigned long *length_return, int *format_return)
5548 char *selection_tmp;
5550 if (!selected_fen_position) return False; /* should never happen */
5551 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5552 /* note: since no XtSelectionDoneProc was registered, Xt will
5553 * automatically call XtFree on the value returned. So have to
5554 * make a copy of it allocated with XtMalloc */
5555 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5556 strcpy(selection_tmp, selected_fen_position);
5558 *value_return=selection_tmp;
5559 *length_return=strlen(selection_tmp);
5560 *type_return=*target;
5561 *format_return = 8; /* bits per byte */
5563 } else if (*target == XA_TARGETS(xDisplay)) {
5564 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5565 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5566 targets_tmp[1] = XA_STRING;
5567 *value_return = targets_tmp;
5568 *type_return = XA_ATOM;
5570 *format_return = 8 * sizeof(Atom);
5571 if (*format_return > 32) {
5572 *length_return *= *format_return / 32;
5573 *format_return = 32;
5581 /* note: when called from menu all parameters are NULL, so no clue what the
5582 * Widget which was clicked on was, or what the click event was
5584 void CopyPositionProc(w, event, prms, nprms)
5591 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5592 * have a notion of a position that is selected but not copied.
5593 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5595 if (selected_fen_position) free(selected_fen_position);
5596 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5597 if (!selected_fen_position) return;
5598 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5600 SendPositionSelection,
5601 NULL/* lose_ownership_proc */ ,
5602 NULL/* transfer_done_proc */);
5603 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5605 SendPositionSelection,
5606 NULL/* lose_ownership_proc */ ,
5607 NULL/* transfer_done_proc */);
5610 /* function called when the data to Paste is ready */
5612 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5613 Atom *type, XtPointer value, unsigned long *len, int *format)
5616 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5617 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5618 EditPositionPasteFEN(fenstr);
5622 /* called when Paste Position button is pressed,
5623 * all parameters will be NULL */
5624 void PastePositionProc(w, event, prms, nprms)
5630 XtGetSelectionValue(menuBarWidget,
5631 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5632 /* (XtSelectionCallbackProc) */ PastePositionCB,
5633 NULL, /* client_data passed to PastePositionCB */
5635 /* better to use the time field from the event that triggered the
5636 * call to this function, but that isn't trivial to get
5644 SendGameSelection(Widget w, Atom *selection, Atom *target,
5645 Atom *type_return, XtPointer *value_return,
5646 unsigned long *length_return, int *format_return)
5648 char *selection_tmp;
5650 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5651 FILE* f = fopen(gameCopyFilename, "r");
5654 if (f == NULL) return False;
5658 selection_tmp = XtMalloc(len + 1);
5659 count = fread(selection_tmp, 1, len, f);
5661 XtFree(selection_tmp);
5664 selection_tmp[len] = NULLCHAR;
5665 *value_return = selection_tmp;
5666 *length_return = len;
5667 *type_return = *target;
5668 *format_return = 8; /* bits per byte */
5670 } else if (*target == XA_TARGETS(xDisplay)) {
5671 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5672 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5673 targets_tmp[1] = XA_STRING;
5674 *value_return = targets_tmp;
5675 *type_return = XA_ATOM;
5677 *format_return = 8 * sizeof(Atom);
5678 if (*format_return > 32) {
5679 *length_return *= *format_return / 32;
5680 *format_return = 32;
5688 /* note: when called from menu all parameters are NULL, so no clue what the
5689 * Widget which was clicked on was, or what the click event was
5691 void CopyGameProc(w, event, prms, nprms)
5699 ret = SaveGameToFile(gameCopyFilename, FALSE);
5703 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5704 * have a notion of a game that is selected but not copied.
5705 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5707 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5710 NULL/* lose_ownership_proc */ ,
5711 NULL/* transfer_done_proc */);
5712 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5715 NULL/* lose_ownership_proc */ ,
5716 NULL/* transfer_done_proc */);
5719 /* function called when the data to Paste is ready */
5721 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5722 Atom *type, XtPointer value, unsigned long *len, int *format)
5725 if (value == NULL || *len == 0) {
5726 return; /* nothing had been selected to copy */
5728 f = fopen(gamePasteFilename, "w");
5730 DisplayError(_("Can't open temp file"), errno);
5733 fwrite(value, 1, *len, f);
5736 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5739 /* called when Paste Game button is pressed,
5740 * all parameters will be NULL */
5741 void PasteGameProc(w, event, prms, nprms)
5747 XtGetSelectionValue(menuBarWidget,
5748 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5749 /* (XtSelectionCallbackProc) */ PasteGameCB,
5750 NULL, /* client_data passed to PasteGameCB */
5752 /* better to use the time field from the event that triggered the
5753 * call to this function, but that isn't trivial to get
5763 SaveGameProc(NULL, NULL, NULL, NULL);
5767 void QuitProc(w, event, prms, nprms)
5776 void PauseProc(w, event, prms, nprms)
5786 void MachineBlackProc(w, event, prms, nprms)
5792 MachineBlackEvent();
5795 void MachineWhiteProc(w, event, prms, nprms)
5801 MachineWhiteEvent();
5804 void AnalyzeModeProc(w, event, prms, nprms)
5812 if (!first.analysisSupport) {
5813 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5814 DisplayError(buf, 0);
5817 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5818 if (appData.icsActive) {
5819 if (gameMode != IcsObserving) {
5820 sprintf(buf,_("You are not observing a game"));
5821 DisplayError(buf, 0);
5823 if (appData.icsEngineAnalyze) {
5824 if (appData.debugMode)
5825 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5831 /* if enable, use want disable icsEngineAnalyze */
5832 if (appData.icsEngineAnalyze) {
5837 appData.icsEngineAnalyze = TRUE;
5838 if (appData.debugMode)
5839 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5841 if (!appData.showThinking)
5842 ShowThinkingProc(w,event,prms,nprms);
5847 void AnalyzeFileProc(w, event, prms, nprms)
5853 if (!first.analysisSupport) {
5855 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5856 DisplayError(buf, 0);
5861 if (!appData.showThinking)
5862 ShowThinkingProc(w,event,prms,nprms);
5865 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
5866 AnalysisPeriodicEvent(1);
5869 void TwoMachinesProc(w, event, prms, nprms)
5878 void IcsClientProc(w, event, prms, nprms)
5887 void EditGameProc(w, event, prms, nprms)
5896 void EditPositionProc(w, event, prms, nprms)
5902 EditPositionEvent();
5905 void TrainingProc(w, event, prms, nprms)
5914 void EditCommentProc(w, event, prms, nprms)
5921 EditCommentPopDown();
5927 void IcsInputBoxProc(w, event, prms, nprms)
5933 if (ICSInputBoxUp) {
5934 ICSInputBoxPopDown();
5940 void AcceptProc(w, event, prms, nprms)
5949 void DeclineProc(w, event, prms, nprms)
5958 void RematchProc(w, event, prms, nprms)
5967 void CallFlagProc(w, event, prms, nprms)
5976 void DrawProc(w, event, prms, nprms)
5985 void AbortProc(w, event, prms, nprms)
5994 void AdjournProc(w, event, prms, nprms)
6003 void ResignProc(w, event, prms, nprms)
6012 void AdjuWhiteProc(w, event, prms, nprms)
6018 UserAdjudicationEvent(+1);
6021 void AdjuBlackProc(w, event, prms, nprms)
6027 UserAdjudicationEvent(-1);
6030 void AdjuDrawProc(w, event, prms, nprms)
6036 UserAdjudicationEvent(0);
6039 void EnterKeyProc(w, event, prms, nprms)
6045 if (ICSInputBoxUp == True)
6049 void StopObservingProc(w, event, prms, nprms)
6055 StopObservingEvent();
6058 void StopExaminingProc(w, event, prms, nprms)
6064 StopExaminingEvent();
6068 void ForwardProc(w, event, prms, nprms)
6078 void BackwardProc(w, event, prms, nprms)
6087 void ToStartProc(w, event, prms, nprms)
6096 void ToEndProc(w, event, prms, nprms)
6105 void RevertProc(w, event, prms, nprms)
6114 void TruncateGameProc(w, event, prms, nprms)
6120 TruncateGameEvent();
6122 void RetractMoveProc(w, event, prms, nprms)
6131 void MoveNowProc(w, event, prms, nprms)
6141 void AlwaysQueenProc(w, event, prms, nprms)
6149 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6151 if (appData.alwaysPromoteToQueen) {
6152 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6154 XtSetArg(args[0], XtNleftBitmap, None);
6156 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6160 void AnimateDraggingProc(w, event, prms, nprms)
6168 appData.animateDragging = !appData.animateDragging;
6170 if (appData.animateDragging) {
6171 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6174 XtSetArg(args[0], XtNleftBitmap, None);
6176 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6180 void AnimateMovingProc(w, event, prms, nprms)
6188 appData.animate = !appData.animate;
6190 if (appData.animate) {
6191 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6194 XtSetArg(args[0], XtNleftBitmap, None);
6196 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6200 void AutocommProc(w, event, prms, nprms)
6208 appData.autoComment = !appData.autoComment;
6210 if (appData.autoComment) {
6211 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6213 XtSetArg(args[0], XtNleftBitmap, None);
6215 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6220 void AutoflagProc(w, event, prms, nprms)
6228 appData.autoCallFlag = !appData.autoCallFlag;
6230 if (appData.autoCallFlag) {
6231 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6233 XtSetArg(args[0], XtNleftBitmap, None);
6235 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6239 void AutoflipProc(w, event, prms, nprms)
6247 appData.autoFlipView = !appData.autoFlipView;
6249 if (appData.autoFlipView) {
6250 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6252 XtSetArg(args[0], XtNleftBitmap, None);
6254 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6258 void AutobsProc(w, event, prms, nprms)
6266 appData.autoObserve = !appData.autoObserve;
6268 if (appData.autoObserve) {
6269 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6271 XtSetArg(args[0], XtNleftBitmap, None);
6273 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6277 void AutoraiseProc(w, event, prms, nprms)
6285 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6287 if (appData.autoRaiseBoard) {
6288 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6290 XtSetArg(args[0], XtNleftBitmap, None);
6292 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6296 void AutosaveProc(w, event, prms, nprms)
6304 appData.autoSaveGames = !appData.autoSaveGames;
6306 if (appData.autoSaveGames) {
6307 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6309 XtSetArg(args[0], XtNleftBitmap, None);
6311 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6315 void BlindfoldProc(w, event, prms, nprms)
6323 appData.blindfold = !appData.blindfold;
6325 if (appData.blindfold) {
6326 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6328 XtSetArg(args[0], XtNleftBitmap, None);
6330 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6333 DrawPosition(True, NULL);
6336 void TestLegalityProc(w, event, prms, nprms)
6344 appData.testLegality = !appData.testLegality;
6346 if (appData.testLegality) {
6347 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6349 XtSetArg(args[0], XtNleftBitmap, None);
6351 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6356 void FlashMovesProc(w, event, prms, nprms)
6364 if (appData.flashCount == 0) {
6365 appData.flashCount = 3;
6367 appData.flashCount = -appData.flashCount;
6370 if (appData.flashCount > 0) {
6371 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6373 XtSetArg(args[0], XtNleftBitmap, None);
6375 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6379 void FlipViewProc(w, event, prms, nprms)
6385 flipView = !flipView;
6386 DrawPosition(True, NULL);
6389 void GetMoveListProc(w, event, prms, nprms)
6397 appData.getMoveList = !appData.getMoveList;
6399 if (appData.getMoveList) {
6400 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6403 XtSetArg(args[0], XtNleftBitmap, None);
6405 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6410 void HighlightDraggingProc(w, event, prms, nprms)
6418 appData.highlightDragging = !appData.highlightDragging;
6420 if (appData.highlightDragging) {
6421 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6423 XtSetArg(args[0], XtNleftBitmap, None);
6425 XtSetValues(XtNameToWidget(menuBarWidget,
6426 "menuOptions.Highlight Dragging"), args, 1);
6430 void HighlightLastMoveProc(w, event, prms, nprms)
6438 appData.highlightLastMove = !appData.highlightLastMove;
6440 if (appData.highlightLastMove) {
6441 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6443 XtSetArg(args[0], XtNleftBitmap, None);
6445 XtSetValues(XtNameToWidget(menuBarWidget,
6446 "menuOptions.Highlight Last Move"), args, 1);
6449 void IcsAlarmProc(w, event, prms, nprms)
6457 appData.icsAlarm = !appData.icsAlarm;
6459 if (appData.icsAlarm) {
6460 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6462 XtSetArg(args[0], XtNleftBitmap, None);
6464 XtSetValues(XtNameToWidget(menuBarWidget,
6465 "menuOptions.ICS Alarm"), args, 1);
6468 void MoveSoundProc(w, event, prms, nprms)
6476 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6478 if (appData.ringBellAfterMoves) {
6479 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6481 XtSetArg(args[0], XtNleftBitmap, None);
6483 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6488 void OldSaveStyleProc(w, event, prms, nprms)
6496 appData.oldSaveStyle = !appData.oldSaveStyle;
6498 if (appData.oldSaveStyle) {
6499 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6501 XtSetArg(args[0], XtNleftBitmap, None);
6503 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6507 void PeriodicUpdatesProc(w, event, prms, nprms)
6515 PeriodicUpdatesEvent(!appData.periodicUpdates);
6517 if (appData.periodicUpdates) {
6518 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6520 XtSetArg(args[0], XtNleftBitmap, None);
6522 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6526 void PonderNextMoveProc(w, event, prms, nprms)
6534 PonderNextMoveEvent(!appData.ponderNextMove);
6536 if (appData.ponderNextMove) {
6537 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6539 XtSetArg(args[0], XtNleftBitmap, None);
6541 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6545 void PopupExitMessageProc(w, event, prms, nprms)
6553 appData.popupExitMessage = !appData.popupExitMessage;
6555 if (appData.popupExitMessage) {
6556 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6558 XtSetArg(args[0], XtNleftBitmap, None);
6560 XtSetValues(XtNameToWidget(menuBarWidget,
6561 "menuOptions.Popup Exit Message"), args, 1);
6564 void PopupMoveErrorsProc(w, event, prms, nprms)
6572 appData.popupMoveErrors = !appData.popupMoveErrors;
6574 if (appData.popupMoveErrors) {
6575 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6577 XtSetArg(args[0], XtNleftBitmap, None);
6579 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6583 void PremoveProc(w, event, prms, nprms)
6591 appData.premove = !appData.premove;
6593 if (appData.premove) {
6594 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6596 XtSetArg(args[0], XtNleftBitmap, None);
6598 XtSetValues(XtNameToWidget(menuBarWidget,
6599 "menuOptions.Premove"), args, 1);
6602 void QuietPlayProc(w, event, prms, nprms)
6610 appData.quietPlay = !appData.quietPlay;
6612 if (appData.quietPlay) {
6613 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6615 XtSetArg(args[0], XtNleftBitmap, None);
6617 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6621 void ShowCoordsProc(w, event, prms, nprms)
6629 appData.showCoords = !appData.showCoords;
6631 if (appData.showCoords) {
6632 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6634 XtSetArg(args[0], XtNleftBitmap, None);
6636 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6639 DrawPosition(True, NULL);
6642 void ShowThinkingProc(w, event, prms, nprms)
6648 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6649 ShowThinkingEvent();
6652 void HideThinkingProc(w, event, prms, nprms)
6660 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6661 ShowThinkingEvent();
6663 if (appData.hideThinkingFromHuman) {
6664 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6666 XtSetArg(args[0], XtNleftBitmap, None);
6668 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6672 void SaveOnExitProc(w, event, prms, nprms)
6680 saveSettingsOnExit = !saveSettingsOnExit;
6682 if (saveSettingsOnExit) {
6683 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6685 XtSetArg(args[0], XtNleftBitmap, None);
6687 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6691 void SaveSettingsProc(w, event, prms, nprms)
6697 SaveSettings(settingsFileName);
6700 void InfoProc(w, event, prms, nprms)
6707 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6712 void ManProc(w, event, prms, nprms)
6720 if (nprms && *nprms > 0)
6724 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6728 void HintProc(w, event, prms, nprms)
6737 void BookProc(w, event, prms, nprms)
6746 void AboutProc(w, event, prms, nprms)
6754 char *zippy = " (with Zippy code)";
6758 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
6759 programVersion, zippy,
6760 "Copyright 1991 Digital Equipment Corporation",
6761 "Enhancements Copyright 1992-2009 Free Software Foundation",
6762 "Enhancements Copyright 2005 Alessandro Scotti",
6763 PACKAGE, " is free software and carries NO WARRANTY;",
6764 "see the file COPYING for more information.");
6765 ErrorPopUp(_("About XBoard"), buf, FALSE);
6768 void DebugProc(w, event, prms, nprms)
6774 appData.debugMode = !appData.debugMode;
6777 void AboutGameProc(w, event, prms, nprms)
6786 void NothingProc(w, event, prms, nprms)
6795 void Iconify(w, event, prms, nprms)
6804 XtSetArg(args[0], XtNiconic, True);
6805 XtSetValues(shellWidget, args, 1);
6808 void DisplayMessage(message, extMessage)
6809 char *message, *extMessage;
6811 /* display a message in the message widget */
6820 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6825 message = extMessage;
6829 /* need to test if messageWidget already exists, since this function
6830 can also be called during the startup, if for example a Xresource
6831 is not set up correctly */
6834 XtSetArg(arg, XtNlabel, message);
6835 XtSetValues(messageWidget, &arg, 1);
6841 void DisplayTitle(text)
6846 char title[MSG_SIZ];
6849 if (text == NULL) text = "";
6851 if (appData.titleInWindow) {
6853 XtSetArg(args[i], XtNlabel, text); i++;
6854 XtSetValues(titleWidget, args, i);
6857 if (*text != NULLCHAR) {
6859 strcpy(title, text);
6860 } else if (appData.icsActive) {
6861 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6862 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6863 } else if (appData.cmailGameName[0] != NULLCHAR) {
6864 snprintf(icon, sizeof(icon), "%s", "CMail");
6865 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6867 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6868 } else if (gameInfo.variant == VariantGothic) {
6869 strcpy(icon, programName);
6870 strcpy(title, GOTHIC);
6873 } else if (gameInfo.variant == VariantFalcon) {
6874 strcpy(icon, programName);
6875 strcpy(title, FALCON);
6877 } else if (appData.noChessProgram) {
6878 strcpy(icon, programName);
6879 strcpy(title, programName);
6881 strcpy(icon, first.tidy);
6882 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6885 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6886 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6887 XtSetValues(shellWidget, args, i);
6891 void DisplayError(message, error)
6898 if (appData.debugMode || appData.matchMode) {
6899 fprintf(stderr, "%s: %s\n", programName, message);
6902 if (appData.debugMode || appData.matchMode) {
6903 fprintf(stderr, "%s: %s: %s\n",
6904 programName, message, strerror(error));
6906 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6909 ErrorPopUp(_("Error"), message, FALSE);
6913 void DisplayMoveError(message)
6918 DrawPosition(FALSE, NULL);
6919 if (appData.debugMode || appData.matchMode) {
6920 fprintf(stderr, "%s: %s\n", programName, message);
6922 if (appData.popupMoveErrors) {
6923 ErrorPopUp(_("Error"), message, FALSE);
6925 DisplayMessage(message, "");
6930 void DisplayFatalError(message, error, status)
6936 errorExitStatus = status;
6938 fprintf(stderr, "%s: %s\n", programName, message);
6940 fprintf(stderr, "%s: %s: %s\n",
6941 programName, message, strerror(error));
6942 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6945 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6946 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6952 void DisplayInformation(message)
6956 ErrorPopUp(_("Information"), message, TRUE);
6959 void DisplayNote(message)
6963 ErrorPopUp(_("Note"), message, FALSE);
6967 NullXErrorCheck(dpy, error_event)
6969 XErrorEvent *error_event;
6974 void DisplayIcsInteractionTitle(message)
6977 if (oldICSInteractionTitle == NULL) {
6978 /* Magic to find the old window title, adapted from vim */
6979 char *wina = getenv("WINDOWID");
6981 Window win = (Window) atoi(wina);
6982 Window root, parent, *children;
6983 unsigned int nchildren;
6984 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6986 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6987 if (!XQueryTree(xDisplay, win, &root, &parent,
6988 &children, &nchildren)) break;
6989 if (children) XFree((void *)children);
6990 if (parent == root || parent == 0) break;
6993 XSetErrorHandler(oldHandler);
6995 if (oldICSInteractionTitle == NULL) {
6996 oldICSInteractionTitle = "xterm";
6999 printf("\033]0;%s\007", message);
7003 char pendingReplyPrefix[MSG_SIZ];
7004 ProcRef pendingReplyPR;
7006 void AskQuestionProc(w, event, prms, nprms)
7013 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7017 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7020 void AskQuestionPopDown()
7022 if (!askQuestionUp) return;
7023 XtPopdown(askQuestionShell);
7024 XtDestroyWidget(askQuestionShell);
7025 askQuestionUp = False;
7028 void AskQuestionReplyAction(w, event, prms, nprms)
7038 reply = XawDialogGetValueString(w = XtParent(w));
7039 strcpy(buf, pendingReplyPrefix);
7040 if (*buf) strcat(buf, " ");
7043 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7044 AskQuestionPopDown();
7046 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7049 void AskQuestionCallback(w, client_data, call_data)
7051 XtPointer client_data, call_data;
7056 XtSetArg(args[0], XtNlabel, &name);
7057 XtGetValues(w, args, 1);
7059 if (strcmp(name, _("cancel")) == 0) {
7060 AskQuestionPopDown();
7062 AskQuestionReplyAction(w, NULL, NULL, NULL);
7066 void AskQuestion(title, question, replyPrefix, pr)
7067 char *title, *question, *replyPrefix;
7071 Widget popup, layout, dialog, edit;
7077 strcpy(pendingReplyPrefix, replyPrefix);
7078 pendingReplyPR = pr;
7081 XtSetArg(args[i], XtNresizable, True); i++;
7082 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7083 askQuestionShell = popup =
7084 XtCreatePopupShell(title, transientShellWidgetClass,
7085 shellWidget, args, i);
7088 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7089 layoutArgs, XtNumber(layoutArgs));
7092 XtSetArg(args[i], XtNlabel, question); i++;
7093 XtSetArg(args[i], XtNvalue, ""); i++;
7094 XtSetArg(args[i], XtNborderWidth, 0); i++;
7095 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7098 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7099 (XtPointer) dialog);
7100 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7101 (XtPointer) dialog);
7103 XtRealizeWidget(popup);
7104 CatchDeleteWindow(popup, "AskQuestionPopDown");
7106 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7107 &x, &y, &win_x, &win_y, &mask);
7109 XtSetArg(args[0], XtNx, x - 10);
7110 XtSetArg(args[1], XtNy, y - 30);
7111 XtSetValues(popup, args, 2);
7113 XtPopup(popup, XtGrabExclusive);
7114 askQuestionUp = True;
7116 edit = XtNameToWidget(dialog, "*value");
7117 XtSetKeyboardFocus(popup, edit);
7125 if (*name == NULLCHAR) {
7127 } else if (strcmp(name, "$") == 0) {
7128 putc(BELLCHAR, stderr);
7131 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7139 PlaySound(appData.soundMove);
7145 PlaySound(appData.soundIcsWin);
7151 PlaySound(appData.soundIcsLoss);
7157 PlaySound(appData.soundIcsDraw);
7161 PlayIcsUnfinishedSound()
7163 PlaySound(appData.soundIcsUnfinished);
7169 PlaySound(appData.soundIcsAlarm);
7175 system("stty echo");
7181 system("stty -echo");
7185 Colorize(cc, continuation)
7190 int count, outCount, error;
7192 if (textColors[(int)cc].bg > 0) {
7193 if (textColors[(int)cc].fg > 0) {
7194 sprintf(buf, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7195 textColors[(int)cc].fg, textColors[(int)cc].bg);
7197 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7198 textColors[(int)cc].bg);
7201 if (textColors[(int)cc].fg > 0) {
7202 sprintf(buf, "\033[0;%d;%dm", textColors[(int)cc].attr,
7203 textColors[(int)cc].fg);
7205 sprintf(buf, "\033[0;%dm", textColors[(int)cc].attr);
7208 count = strlen(buf);
7209 outCount = OutputToProcess(NoProc, buf, count, &error);
7210 if (outCount < count) {
7211 DisplayFatalError(_("Error writing to display"), error, 1);
7214 if (continuation) return;
7217 PlaySound(appData.soundShout);
7220 PlaySound(appData.soundSShout);
7223 PlaySound(appData.soundChannel1);
7226 PlaySound(appData.soundChannel);
7229 PlaySound(appData.soundKibitz);
7232 PlaySound(appData.soundTell);
7234 case ColorChallenge:
7235 PlaySound(appData.soundChallenge);
7238 PlaySound(appData.soundRequest);
7241 PlaySound(appData.soundSeek);
7252 return getpwuid(getuid())->pw_name;
7255 static char *ExpandPathName(path)
7258 static char static_buf[2000];
7259 char *d, *s, buf[2000];
7265 while (*s && isspace(*s))
7274 if (*(s+1) == '/') {
7275 strcpy(d, getpwuid(getuid())->pw_dir);
7280 *strchr(buf, '/') = 0;
7281 pwd = getpwnam(buf);
7284 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7288 strcpy(d, pwd->pw_dir);
7289 strcat(d, strchr(s+1, '/'));
7300 static char host_name[MSG_SIZ];
7302 #if HAVE_GETHOSTNAME
7303 gethostname(host_name, MSG_SIZ);
7305 #else /* not HAVE_GETHOSTNAME */
7306 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7307 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7309 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7311 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7312 #endif /* not HAVE_GETHOSTNAME */
7315 XtIntervalId delayedEventTimerXID = 0;
7316 DelayedEventCallback delayedEventCallback = 0;
7321 delayedEventTimerXID = 0;
7322 delayedEventCallback();
7326 ScheduleDelayedEvent(cb, millisec)
7327 DelayedEventCallback cb; long millisec;
7329 if(delayedEventTimerXID && delayedEventCallback == cb)
7330 // [HGM] alive: replace, rather than add or flush identical event
7331 XtRemoveTimeOut(delayedEventTimerXID);
7332 delayedEventCallback = cb;
7333 delayedEventTimerXID =
7334 XtAppAddTimeOut(appContext, millisec,
7335 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7338 DelayedEventCallback
7341 if (delayedEventTimerXID) {
7342 return delayedEventCallback;
7349 CancelDelayedEvent()
7351 if (delayedEventTimerXID) {
7352 XtRemoveTimeOut(delayedEventTimerXID);
7353 delayedEventTimerXID = 0;
7357 XtIntervalId loadGameTimerXID = 0;
7359 int LoadGameTimerRunning()
7361 return loadGameTimerXID != 0;
7364 int StopLoadGameTimer()
7366 if (loadGameTimerXID != 0) {
7367 XtRemoveTimeOut(loadGameTimerXID);
7368 loadGameTimerXID = 0;
7376 LoadGameTimerCallback(arg, id)
7380 loadGameTimerXID = 0;
7385 StartLoadGameTimer(millisec)
7389 XtAppAddTimeOut(appContext, millisec,
7390 (XtTimerCallbackProc) LoadGameTimerCallback,
7394 XtIntervalId analysisClockXID = 0;
7397 AnalysisClockCallback(arg, id)
7401 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7402 || appData.icsEngineAnalyze) { // [DM]
7403 AnalysisPeriodicEvent(0);
7404 StartAnalysisClock();
7409 StartAnalysisClock()
7412 XtAppAddTimeOut(appContext, 2000,
7413 (XtTimerCallbackProc) AnalysisClockCallback,
7417 XtIntervalId clockTimerXID = 0;
7419 int ClockTimerRunning()
7421 return clockTimerXID != 0;
7424 int StopClockTimer()
7426 if (clockTimerXID != 0) {
7427 XtRemoveTimeOut(clockTimerXID);
7436 ClockTimerCallback(arg, id)
7445 StartClockTimer(millisec)
7449 XtAppAddTimeOut(appContext, millisec,
7450 (XtTimerCallbackProc) ClockTimerCallback,
7455 DisplayTimerLabel(w, color, timer, highlight)
7464 /* check for low time warning */
7465 Pixel foregroundOrWarningColor = timerForegroundPixel;
7468 appData.lowTimeWarning &&
7469 (timer / 1000) < appData.icsAlarmTime)
7470 foregroundOrWarningColor = lowTimeWarningColor;
7472 if (appData.clockMode) {
7473 sprintf(buf, "%s: %s", color, TimeString(timer));
7474 XtSetArg(args[0], XtNlabel, buf);
7476 sprintf(buf, "%s ", color);
7477 XtSetArg(args[0], XtNlabel, buf);
7482 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7483 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7485 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7486 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7489 XtSetValues(w, args, 3);
7493 DisplayWhiteClock(timeRemaining, highlight)
7499 if(appData.noGUI) return;
7500 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7501 if (highlight && iconPixmap == bIconPixmap) {
7502 iconPixmap = wIconPixmap;
7503 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7504 XtSetValues(shellWidget, args, 1);
7509 DisplayBlackClock(timeRemaining, highlight)
7515 if(appData.noGUI) return;
7516 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7517 if (highlight && iconPixmap == wIconPixmap) {
7518 iconPixmap = bIconPixmap;
7519 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7520 XtSetValues(shellWidget, args, 1);
7538 int StartChildProcess(cmdLine, dir, pr)
7545 int to_prog[2], from_prog[2];
7549 if (appData.debugMode) {
7550 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7553 /* We do NOT feed the cmdLine to the shell; we just
7554 parse it into blank-separated arguments in the
7555 most simple-minded way possible.
7558 strcpy(buf, cmdLine);
7563 if (p == NULL) break;
7568 SetUpChildIO(to_prog, from_prog);
7570 if ((pid = fork()) == 0) {
7572 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7573 close(to_prog[1]); // first close the unused pipe ends
7574 close(from_prog[0]);
7575 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7576 dup2(from_prog[1], 1);
7577 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7578 close(from_prog[1]); // and closing again loses one of the pipes!
7579 if(fileno(stderr) >= 2) // better safe than sorry...
7580 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7582 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7587 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7589 execvp(argv[0], argv);
7591 /* If we get here, exec failed */
7596 /* Parent process */
7598 close(from_prog[1]);
7600 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7603 cp->fdFrom = from_prog[0];
7604 cp->fdTo = to_prog[1];
7609 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7610 static RETSIGTYPE AlarmCallBack(int n)
7616 DestroyChildProcess(pr, signalType)
7620 ChildProc *cp = (ChildProc *) pr;
7622 if (cp->kind != CPReal) return;
7624 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7625 signal(SIGALRM, AlarmCallBack);
7627 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7628 kill(cp->pid, SIGKILL); // kill it forcefully
7629 wait((int *) 0); // and wait again
7633 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7635 /* Process is exiting either because of the kill or because of
7636 a quit command sent by the backend; either way, wait for it to die.
7645 InterruptChildProcess(pr)
7648 ChildProc *cp = (ChildProc *) pr;
7650 if (cp->kind != CPReal) return;
7651 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7654 int OpenTelnet(host, port, pr)
7659 char cmdLine[MSG_SIZ];
7661 if (port[0] == NULLCHAR) {
7662 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7664 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7666 return StartChildProcess(cmdLine, "", pr);
7669 int OpenTCP(host, port, pr)
7675 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7676 #else /* !OMIT_SOCKETS */
7678 struct sockaddr_in sa;
7680 unsigned short uport;
7683 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7687 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7688 sa.sin_family = AF_INET;
7689 sa.sin_addr.s_addr = INADDR_ANY;
7690 uport = (unsigned short) 0;
7691 sa.sin_port = htons(uport);
7692 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7696 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7697 if (!(hp = gethostbyname(host))) {
7699 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7700 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7701 hp->h_addrtype = AF_INET;
7703 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7704 hp->h_addr_list[0] = (char *) malloc(4);
7705 hp->h_addr_list[0][0] = b0;
7706 hp->h_addr_list[0][1] = b1;
7707 hp->h_addr_list[0][2] = b2;
7708 hp->h_addr_list[0][3] = b3;
7713 sa.sin_family = hp->h_addrtype;
7714 uport = (unsigned short) atoi(port);
7715 sa.sin_port = htons(uport);
7716 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
7718 if (connect(s, (struct sockaddr *) &sa,
7719 sizeof(struct sockaddr_in)) < 0) {
7723 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7730 #endif /* !OMIT_SOCKETS */
7735 int OpenCommPort(name, pr)
7742 fd = open(name, 2, 0);
7743 if (fd < 0) return errno;
7745 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7755 int OpenLoopback(pr)
7761 SetUpChildIO(to, from);
7763 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7766 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7773 int OpenRcmd(host, user, cmd, pr)
7774 char *host, *user, *cmd;
7777 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7781 #define INPUT_SOURCE_BUF_SIZE 8192
7790 char buf[INPUT_SOURCE_BUF_SIZE];
7795 DoInputCallback(closure, source, xid)
7800 InputSource *is = (InputSource *) closure;
7805 if (is->lineByLine) {
7806 count = read(is->fd, is->unused,
7807 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7809 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7812 is->unused += count;
7814 while (p < is->unused) {
7815 q = memchr(p, '\n', is->unused - p);
7816 if (q == NULL) break;
7818 (is->func)(is, is->closure, p, q - p, 0);
7822 while (p < is->unused) {
7827 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7832 (is->func)(is, is->closure, is->buf, count, error);
7836 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7843 ChildProc *cp = (ChildProc *) pr;
7845 is = (InputSource *) calloc(1, sizeof(InputSource));
7846 is->lineByLine = lineByLine;
7850 is->fd = fileno(stdin);
7852 is->kind = cp->kind;
7853 is->fd = cp->fdFrom;
7856 is->unused = is->buf;
7859 is->xid = XtAppAddInput(appContext, is->fd,
7860 (XtPointer) (XtInputReadMask),
7861 (XtInputCallbackProc) DoInputCallback,
7863 is->closure = closure;
7864 return (InputSourceRef) is;
7868 RemoveInputSource(isr)
7871 InputSource *is = (InputSource *) isr;
7873 if (is->xid == 0) return;
7874 XtRemoveInput(is->xid);
7878 int OutputToProcess(pr, message, count, outError)
7884 static int line = 0;
7885 ChildProc *cp = (ChildProc *) pr;
7890 if (appData.noJoin || !appData.useInternalWrap)
7891 outCount = fwrite(message, 1, count, stdout);
7894 int width = get_term_width();
7895 int len = wrap(NULL, message, count, width, &line);
7896 char *msg = malloc(len);
7900 outCount = fwrite(message, 1, count, stdout);
7903 dbgchk = wrap(msg, message, count, width, &line);
7904 if (dbgchk != len && appData.debugMode)
7905 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7906 outCount = fwrite(msg, 1, dbgchk, stdout);
7912 outCount = write(cp->fdTo, message, count);
7922 /* Output message to process, with "ms" milliseconds of delay
7923 between each character. This is needed when sending the logon
7924 script to ICC, which for some reason doesn't like the
7925 instantaneous send. */
7926 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
7933 ChildProc *cp = (ChildProc *) pr;
7938 r = write(cp->fdTo, message++, 1);
7951 /**** Animation code by Hugh Fisher, DCS, ANU.
7953 Known problem: if a window overlapping the board is
7954 moved away while a piece is being animated underneath,
7955 the newly exposed area won't be updated properly.
7956 I can live with this.
7958 Known problem: if you look carefully at the animation
7959 of pieces in mono mode, they are being drawn as solid
7960 shapes without interior detail while moving. Fixing
7961 this would be a major complication for minimal return.
7964 /* Masks for XPM pieces. Black and white pieces can have
7965 different shapes, but in the interest of retaining my
7966 sanity pieces must have the same outline on both light
7967 and dark squares, and all pieces must use the same
7968 background square colors/images. */
7970 static int xpmDone = 0;
7973 CreateAnimMasks (pieceDepth)
7980 unsigned long plane;
7983 /* Need a bitmap just to get a GC with right depth */
7984 buf = XCreatePixmap(xDisplay, xBoardWindow,
7986 values.foreground = 1;
7987 values.background = 0;
7988 /* Don't use XtGetGC, not read only */
7989 maskGC = XCreateGC(xDisplay, buf,
7990 GCForeground | GCBackground, &values);
7991 XFreePixmap(xDisplay, buf);
7993 buf = XCreatePixmap(xDisplay, xBoardWindow,
7994 squareSize, squareSize, pieceDepth);
7995 values.foreground = XBlackPixel(xDisplay, xScreen);
7996 values.background = XWhitePixel(xDisplay, xScreen);
7997 bufGC = XCreateGC(xDisplay, buf,
7998 GCForeground | GCBackground, &values);
8000 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8001 /* Begin with empty mask */
8002 if(!xpmDone) // [HGM] pieces: keep using existing
8003 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8004 squareSize, squareSize, 1);
8005 XSetFunction(xDisplay, maskGC, GXclear);
8006 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8007 0, 0, squareSize, squareSize);
8009 /* Take a copy of the piece */
8014 XSetFunction(xDisplay, bufGC, GXcopy);
8015 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8017 0, 0, squareSize, squareSize, 0, 0);
8019 /* XOR the background (light) over the piece */
8020 XSetFunction(xDisplay, bufGC, GXxor);
8022 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8023 0, 0, squareSize, squareSize, 0, 0);
8025 XSetForeground(xDisplay, bufGC, lightSquareColor);
8026 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8029 /* We now have an inverted piece image with the background
8030 erased. Construct mask by just selecting all the non-zero
8031 pixels - no need to reconstruct the original image. */
8032 XSetFunction(xDisplay, maskGC, GXor);
8034 /* Might be quicker to download an XImage and create bitmap
8035 data from it rather than this N copies per piece, but it
8036 only takes a fraction of a second and there is a much
8037 longer delay for loading the pieces. */
8038 for (n = 0; n < pieceDepth; n ++) {
8039 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8040 0, 0, squareSize, squareSize,
8046 XFreePixmap(xDisplay, buf);
8047 XFreeGC(xDisplay, bufGC);
8048 XFreeGC(xDisplay, maskGC);
8052 InitAnimState (anim, info)
8054 XWindowAttributes * info;
8059 /* Each buffer is square size, same depth as window */
8060 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8061 squareSize, squareSize, info->depth);
8062 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8063 squareSize, squareSize, info->depth);
8065 /* Create a plain GC for blitting */
8066 mask = GCForeground | GCBackground | GCFunction |
8067 GCPlaneMask | GCGraphicsExposures;
8068 values.foreground = XBlackPixel(xDisplay, xScreen);
8069 values.background = XWhitePixel(xDisplay, xScreen);
8070 values.function = GXcopy;
8071 values.plane_mask = AllPlanes;
8072 values.graphics_exposures = False;
8073 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8075 /* Piece will be copied from an existing context at
8076 the start of each new animation/drag. */
8077 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8079 /* Outline will be a read-only copy of an existing */
8080 anim->outlineGC = None;
8086 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8087 XWindowAttributes info;
8089 if (xpmDone && gameInfo.variant == old) return;
8090 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8091 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8093 InitAnimState(&game, &info);
8094 InitAnimState(&player, &info);
8096 /* For XPM pieces, we need bitmaps to use as masks. */
8098 CreateAnimMasks(info.depth);
8104 static Boolean frameWaiting;
8106 static RETSIGTYPE FrameAlarm (sig)
8109 frameWaiting = False;
8110 /* In case System-V style signals. Needed?? */
8111 signal(SIGALRM, FrameAlarm);
8118 struct itimerval delay;
8120 XSync(xDisplay, False);
8123 frameWaiting = True;
8124 signal(SIGALRM, FrameAlarm);
8125 delay.it_interval.tv_sec =
8126 delay.it_value.tv_sec = time / 1000;
8127 delay.it_interval.tv_usec =
8128 delay.it_value.tv_usec = (time % 1000) * 1000;
8129 setitimer(ITIMER_REAL, &delay, NULL);
8130 while (frameWaiting) pause();
8131 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8132 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8133 setitimer(ITIMER_REAL, &delay, NULL);
8143 XSync(xDisplay, False);
8145 usleep(time * 1000);
8150 /* Convert board position to corner of screen rect and color */
8153 ScreenSquare(column, row, pt, color)
8154 int column; int row; XPoint * pt; int * color;
8157 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8158 pt->y = lineGap + row * (squareSize + lineGap);
8160 pt->x = lineGap + column * (squareSize + lineGap);
8161 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8163 *color = SquareColor(row, column);
8166 /* Convert window coords to square */
8169 BoardSquare(x, y, column, row)
8170 int x; int y; int * column; int * row;
8172 *column = EventToSquare(x, BOARD_WIDTH);
8173 if (flipView && *column >= 0)
8174 *column = BOARD_WIDTH - 1 - *column;
8175 *row = EventToSquare(y, BOARD_HEIGHT);
8176 if (!flipView && *row >= 0)
8177 *row = BOARD_HEIGHT - 1 - *row;
8182 #undef Max /* just in case */
8184 #define Max(a, b) ((a) > (b) ? (a) : (b))
8185 #define Min(a, b) ((a) < (b) ? (a) : (b))
8188 SetRect(rect, x, y, width, height)
8189 XRectangle * rect; int x; int y; int width; int height;
8193 rect->width = width;
8194 rect->height = height;
8197 /* Test if two frames overlap. If they do, return
8198 intersection rect within old and location of
8199 that rect within new. */
8202 Intersect(old, new, size, area, pt)
8203 XPoint * old; XPoint * new;
8204 int size; XRectangle * area; XPoint * pt;
8206 if (old->x > new->x + size || new->x > old->x + size ||
8207 old->y > new->y + size || new->y > old->y + size) {
8210 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8211 size - abs(old->x - new->x), size - abs(old->y - new->y));
8212 pt->x = Max(old->x - new->x, 0);
8213 pt->y = Max(old->y - new->y, 0);
8218 /* For two overlapping frames, return the rect(s)
8219 in the old that do not intersect with the new. */
8222 CalcUpdateRects(old, new, size, update, nUpdates)
8223 XPoint * old; XPoint * new; int size;
8224 XRectangle update[]; int * nUpdates;
8228 /* If old = new (shouldn't happen) then nothing to draw */
8229 if (old->x == new->x && old->y == new->y) {
8233 /* Work out what bits overlap. Since we know the rects
8234 are the same size we don't need a full intersect calc. */
8236 /* Top or bottom edge? */
8237 if (new->y > old->y) {
8238 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8240 } else if (old->y > new->y) {
8241 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8242 size, old->y - new->y);
8245 /* Left or right edge - don't overlap any update calculated above. */
8246 if (new->x > old->x) {
8247 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8248 new->x - old->x, size - abs(new->y - old->y));
8250 } else if (old->x > new->x) {
8251 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8252 old->x - new->x, size - abs(new->y - old->y));
8259 /* Generate a series of frame coords from start->mid->finish.
8260 The movement rate doubles until the half way point is
8261 reached, then halves back down to the final destination,
8262 which gives a nice slow in/out effect. The algorithmn
8263 may seem to generate too many intermediates for short
8264 moves, but remember that the purpose is to attract the
8265 viewers attention to the piece about to be moved and
8266 then to where it ends up. Too few frames would be less
8270 Tween(start, mid, finish, factor, frames, nFrames)
8271 XPoint * start; XPoint * mid;
8272 XPoint * finish; int factor;
8273 XPoint frames[]; int * nFrames;
8275 int fraction, n, count;
8279 /* Slow in, stepping 1/16th, then 1/8th, ... */
8281 for (n = 0; n < factor; n++)
8283 for (n = 0; n < factor; n++) {
8284 frames[count].x = start->x + (mid->x - start->x) / fraction;
8285 frames[count].y = start->y + (mid->y - start->y) / fraction;
8287 fraction = fraction / 2;
8291 frames[count] = *mid;
8294 /* Slow out, stepping 1/2, then 1/4, ... */
8296 for (n = 0; n < factor; n++) {
8297 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8298 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8300 fraction = fraction * 2;
8305 /* Draw a piece on the screen without disturbing what's there */
8308 SelectGCMask(piece, clip, outline, mask)
8309 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8313 /* Bitmap for piece being moved. */
8314 if (appData.monoMode) {
8315 *mask = *pieceToSolid(piece);
8316 } else if (useImages) {
8318 *mask = xpmMask[piece];
8320 *mask = ximMaskPm[piece];
8323 *mask = *pieceToSolid(piece);
8326 /* GC for piece being moved. Square color doesn't matter, but
8327 since it gets modified we make a copy of the original. */
8329 if (appData.monoMode)
8334 if (appData.monoMode)
8339 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8341 /* Outline only used in mono mode and is not modified */
8343 *outline = bwPieceGC;
8345 *outline = wbPieceGC;
8349 OverlayPiece(piece, clip, outline, dest)
8350 ChessSquare piece; GC clip; GC outline; Drawable dest;
8355 /* Draw solid rectangle which will be clipped to shape of piece */
8356 XFillRectangle(xDisplay, dest, clip,
8357 0, 0, squareSize, squareSize);
8358 if (appData.monoMode)
8359 /* Also draw outline in contrasting color for black
8360 on black / white on white cases */
8361 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8362 0, 0, squareSize, squareSize, 0, 0, 1);
8364 /* Copy the piece */
8369 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8371 0, 0, squareSize, squareSize,
8376 /* Animate the movement of a single piece */
8379 BeginAnimation(anim, piece, startColor, start)
8387 /* The old buffer is initialised with the start square (empty) */
8388 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8389 anim->prevFrame = *start;
8391 /* The piece will be drawn using its own bitmap as a matte */
8392 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8393 XSetClipMask(xDisplay, anim->pieceGC, mask);
8397 AnimationFrame(anim, frame, piece)
8402 XRectangle updates[4];
8407 /* Save what we are about to draw into the new buffer */
8408 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8409 frame->x, frame->y, squareSize, squareSize,
8412 /* Erase bits of the previous frame */
8413 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8414 /* Where the new frame overlapped the previous,
8415 the contents in newBuf are wrong. */
8416 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8417 overlap.x, overlap.y,
8418 overlap.width, overlap.height,
8420 /* Repaint the areas in the old that don't overlap new */
8421 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8422 for (i = 0; i < count; i++)
8423 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8424 updates[i].x - anim->prevFrame.x,
8425 updates[i].y - anim->prevFrame.y,
8426 updates[i].width, updates[i].height,
8427 updates[i].x, updates[i].y);
8429 /* Easy when no overlap */
8430 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8431 0, 0, squareSize, squareSize,
8432 anim->prevFrame.x, anim->prevFrame.y);
8435 /* Save this frame for next time round */
8436 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8437 0, 0, squareSize, squareSize,
8439 anim->prevFrame = *frame;
8441 /* Draw piece over original screen contents, not current,
8442 and copy entire rect. Wipes out overlapping piece images. */
8443 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8444 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8445 0, 0, squareSize, squareSize,
8446 frame->x, frame->y);
8450 EndAnimation (anim, finish)
8454 XRectangle updates[4];
8459 /* The main code will redraw the final square, so we
8460 only need to erase the bits that don't overlap. */
8461 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8462 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8463 for (i = 0; i < count; i++)
8464 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8465 updates[i].x - anim->prevFrame.x,
8466 updates[i].y - anim->prevFrame.y,
8467 updates[i].width, updates[i].height,
8468 updates[i].x, updates[i].y);
8470 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8471 0, 0, squareSize, squareSize,
8472 anim->prevFrame.x, anim->prevFrame.y);
8477 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8479 ChessSquare piece; int startColor;
8480 XPoint * start; XPoint * finish;
8481 XPoint frames[]; int nFrames;
8485 BeginAnimation(anim, piece, startColor, start);
8486 for (n = 0; n < nFrames; n++) {
8487 AnimationFrame(anim, &(frames[n]), piece);
8488 FrameDelay(appData.animSpeed);
8490 EndAnimation(anim, finish);
8493 /* Main control logic for deciding what to animate and how */
8496 AnimateMove(board, fromX, fromY, toX, toY)
8505 XPoint start, finish, mid;
8506 XPoint frames[kFactor * 2 + 1];
8507 int nFrames, startColor, endColor;
8509 /* Are we animating? */
8510 if (!appData.animate || appData.blindfold)
8513 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8514 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8515 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8517 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8518 piece = board[fromY][fromX];
8519 if (piece >= EmptySquare) return;
8524 hop = (piece == WhiteKnight || piece == BlackKnight);
8527 if (appData.debugMode) {
8528 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8529 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8530 piece, fromX, fromY, toX, toY); }
8532 ScreenSquare(fromX, fromY, &start, &startColor);
8533 ScreenSquare(toX, toY, &finish, &endColor);
8536 /* Knight: make diagonal movement then straight */
8537 if (abs(toY - fromY) < abs(toX - fromX)) {
8538 mid.x = start.x + (finish.x - start.x) / 2;
8542 mid.y = start.y + (finish.y - start.y) / 2;
8545 mid.x = start.x + (finish.x - start.x) / 2;
8546 mid.y = start.y + (finish.y - start.y) / 2;
8549 /* Don't use as many frames for very short moves */
8550 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8551 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8553 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8554 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8556 /* Be sure end square is redrawn */
8557 damage[toY][toX] = True;
8561 DragPieceBegin(x, y)
8564 int boardX, boardY, color;
8567 /* Are we animating? */
8568 if (!appData.animateDragging || appData.blindfold)
8571 /* Figure out which square we start in and the
8572 mouse position relative to top left corner. */
8573 BoardSquare(x, y, &boardX, &boardY);
8574 player.startBoardX = boardX;
8575 player.startBoardY = boardY;
8576 ScreenSquare(boardX, boardY, &corner, &color);
8577 player.startSquare = corner;
8578 player.startColor = color;
8579 /* As soon as we start dragging, the piece will jump slightly to
8580 be centered over the mouse pointer. */
8581 player.mouseDelta.x = squareSize/2;
8582 player.mouseDelta.y = squareSize/2;
8583 /* Initialise animation */
8584 player.dragPiece = PieceForSquare(boardX, boardY);
8586 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8587 player.dragActive = True;
8588 BeginAnimation(&player, player.dragPiece, color, &corner);
8589 /* Mark this square as needing to be redrawn. Note that
8590 we don't remove the piece though, since logically (ie
8591 as seen by opponent) the move hasn't been made yet. */
8592 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8593 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8594 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8595 corner.x, corner.y, squareSize, squareSize,
8596 0, 0); // [HGM] zh: unstack in stead of grab
8597 damage[boardY][boardX] = True;
8599 player.dragActive = False;
8609 /* Are we animating? */
8610 if (!appData.animateDragging || appData.blindfold)
8614 if (! player.dragActive)
8616 /* Move piece, maintaining same relative position
8617 of mouse within square */
8618 corner.x = x - player.mouseDelta.x;
8619 corner.y = y - player.mouseDelta.y;
8620 AnimationFrame(&player, &corner, player.dragPiece);
8622 if (appData.highlightDragging) {
8624 BoardSquare(x, y, &boardX, &boardY);
8625 SetHighlights(fromX, fromY, boardX, boardY);
8634 int boardX, boardY, color;
8637 /* Are we animating? */
8638 if (!appData.animateDragging || appData.blindfold)
8642 if (! player.dragActive)
8644 /* Last frame in sequence is square piece is
8645 placed on, which may not match mouse exactly. */
8646 BoardSquare(x, y, &boardX, &boardY);
8647 ScreenSquare(boardX, boardY, &corner, &color);
8648 EndAnimation(&player, &corner);
8650 /* Be sure end square is redrawn */
8651 damage[boardY][boardX] = True;
8653 /* This prevents weird things happening with fast successive
8654 clicks which on my Sun at least can cause motion events
8655 without corresponding press/release. */
8656 player.dragActive = False;
8659 /* Handle expose event while piece being dragged */
8664 if (!player.dragActive || appData.blindfold)
8667 /* What we're doing: logically, the move hasn't been made yet,
8668 so the piece is still in it's original square. But visually
8669 it's being dragged around the board. So we erase the square
8670 that the piece is on and draw it at the last known drag point. */
8671 BlankSquare(player.startSquare.x, player.startSquare.y,
8672 player.startColor, EmptySquare, xBoardWindow);
8673 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8674 damage[player.startBoardY][player.startBoardX] = TRUE;
8677 #include <sys/ioctl.h>
8678 int get_term_width()
8680 int fd, default_width;
8683 default_width = 79; // this is FICS default anyway...
8685 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8687 if (!ioctl(fd, TIOCGSIZE, &win))
8688 default_width = win.ts_cols;
8689 #elif defined(TIOCGWINSZ)
8691 if (!ioctl(fd, TIOCGWINSZ, &win))
8692 default_width = win.ws_col;
8694 return default_width;
8697 void update_ics_width()
8699 static int old_width = 0;
8700 int new_width = get_term_width();
8702 if (old_width != new_width)
8703 ics_printf("set width %d\n", new_width);
8704 old_width = new_width;
8707 void NotifyFrontendLogin()