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, 2010, 2011, 2012 Free Software Foundation, Inc.
10 * The following terms apply to Digital Equipment Corporation's copyright
12 * ------------------------------------------------------------------------
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation, and that the name of Digital not be
20 * used in advertising or publicity pertaining to distribution of the
21 * software without specific, written prior permission.
23 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * ------------------------------------------------------------------------
32 * The following terms apply to the enhanced version of XBoard
33 * distributed by the Free Software Foundation:
34 * ------------------------------------------------------------------------
36 * GNU XBoard is free software: you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation, either version 3 of the License, or (at
39 * your option) any later version.
41 * GNU XBoard is distributed in the hope that it will be useful, but
42 * WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 * General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program. If not, see http://www.gnu.org/licenses/. *
49 *------------------------------------------------------------------------
50 ** See the file ChangeLog for a revision history. */
60 #include <sys/types.h>
66 # if HAVE_SYS_SOCKET_H
67 # include <sys/socket.h>
68 # include <netinet/in.h>
70 # else /* not HAVE_SYS_SOCKET_H */
71 # if HAVE_LAN_SOCKET_H
72 # include <lan/socket.h>
74 # include <lan/netdb.h>
75 # else /* not HAVE_LAN_SOCKET_H */
76 # define OMIT_SOCKETS 1
77 # endif /* not HAVE_LAN_SOCKET_H */
78 # endif /* not HAVE_SYS_SOCKET_H */
79 #endif /* !OMIT_SOCKETS */
84 #else /* not STDC_HEADERS */
85 extern char *getenv();
88 # else /* not HAVE_STRING_H */
90 # endif /* not HAVE_STRING_H */
91 #endif /* not STDC_HEADERS */
94 # include <sys/fcntl.h>
95 #else /* not HAVE_SYS_FCNTL_H */
98 # endif /* HAVE_FCNTL_H */
99 #endif /* not HAVE_SYS_FCNTL_H */
101 #if HAVE_SYS_SYSTEMINFO_H
102 # include <sys/systeminfo.h>
103 #endif /* HAVE_SYS_SYSTEMINFO_H */
105 #if TIME_WITH_SYS_TIME
106 # include <sys/time.h>
110 # include <sys/time.h>
121 # include <sys/wait.h>
126 # define NAMLEN(dirent) strlen((dirent)->d_name)
127 # define HAVE_DIR_STRUCT
129 # define dirent direct
130 # define NAMLEN(dirent) (dirent)->d_namlen
132 # include <sys/ndir.h>
133 # define HAVE_DIR_STRUCT
136 # include <sys/dir.h>
137 # define HAVE_DIR_STRUCT
141 # define HAVE_DIR_STRUCT
149 #include <X11/Intrinsic.h>
150 #include <X11/StringDefs.h>
151 #include <X11/Shell.h>
152 #include <X11/cursorfont.h>
153 #include <X11/Xatom.h>
154 #include <X11/Xmu/Atoms.h>
156 #include <X11/Xaw3d/Dialog.h>
157 #include <X11/Xaw3d/Form.h>
158 #include <X11/Xaw3d/List.h>
159 #include <X11/Xaw3d/Label.h>
160 #include <X11/Xaw3d/SimpleMenu.h>
161 #include <X11/Xaw3d/SmeBSB.h>
162 #include <X11/Xaw3d/SmeLine.h>
163 #include <X11/Xaw3d/Box.h>
164 #include <X11/Xaw3d/MenuButton.h>
165 #include <X11/Xaw3d/Text.h>
166 #include <X11/Xaw3d/AsciiText.h>
168 #include <X11/Xaw/Dialog.h>
169 #include <X11/Xaw/Form.h>
170 #include <X11/Xaw/List.h>
171 #include <X11/Xaw/Label.h>
172 #include <X11/Xaw/SimpleMenu.h>
173 #include <X11/Xaw/SmeBSB.h>
174 #include <X11/Xaw/SmeLine.h>
175 #include <X11/Xaw/Box.h>
176 #include <X11/Xaw/MenuButton.h>
177 #include <X11/Xaw/Text.h>
178 #include <X11/Xaw/AsciiText.h>
181 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
186 #include "pixmaps/pixmaps.h"
187 #define IMAGE_EXT "xpm"
189 #define IMAGE_EXT "xim"
190 #include "bitmaps/bitmaps.h"
193 #include "bitmaps/icon_white.bm"
194 #include "bitmaps/icon_black.bm"
195 #include "bitmaps/checkmark.bm"
197 #include "frontend.h"
199 #include "backendz.h"
203 #include "xgamelist.h"
204 #include "xhistory.h"
205 #include "xedittags.h"
208 // must be moved to xengineoutput.h
210 void EngineOutputProc P((Widget w, XEvent *event,
211 String *prms, Cardinal *nprms));
212 void EvalGraphProc P((Widget w, XEvent *event,
213 String *prms, Cardinal *nprms));
220 #define usleep(t) _sleep2(((t)+500)/1000)
224 # define _(s) gettext (s)
225 # define N_(s) gettext_noop (s)
245 int main P((int argc, char **argv));
246 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
247 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
248 RETSIGTYPE CmailSigHandler P((int sig));
249 RETSIGTYPE IntSigHandler P((int sig));
250 RETSIGTYPE TermSizeSigHandler P((int sig));
251 void CreateGCs P((int redo));
252 void CreateAnyPieces P((void));
253 void CreateXIMPieces P((void));
254 void CreateXPMPieces P((void));
255 void CreateXPMBoard P((char *s, int n));
256 void CreatePieces P((void));
257 void CreatePieceMenus P((void));
258 Widget CreateMenuBar P((Menu *mb, int boardWidth));
259 Widget CreateButtonBar P ((MenuItem *mi));
261 char *InsertPxlSize P((char *pattern, int targetPxlSize));
262 XFontSet CreateFontSet P((char *base_fnt_lst));
264 char *FindFont P((char *pattern, int targetPxlSize));
266 void PieceMenuPopup P((Widget w, XEvent *event,
267 String *params, Cardinal *num_params));
268 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
269 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
270 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
271 u_int wreq, u_int hreq));
272 void CreateGrid P((void));
273 int EventToSquare P((int x, int limit));
274 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
275 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
276 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
277 void HandleUserMove P((Widget w, XEvent *event,
278 String *prms, Cardinal *nprms));
279 void AnimateUserMove P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void HandlePV P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void SelectPV P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void StopPV P((Widget w, XEvent * event,
286 String * params, Cardinal * nParams));
287 void WhiteClock P((Widget w, XEvent *event,
288 String *prms, Cardinal *nprms));
289 void BlackClock P((Widget w, XEvent *event,
290 String *prms, Cardinal *nprms));
291 void DrawPositionProc P((Widget w, XEvent *event,
292 String *prms, Cardinal *nprms));
293 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
295 void CommentClick P((Widget w, XEvent * event,
296 String * params, Cardinal * nParams));
297 void CommentPopUp P((char *title, char *label));
298 void CommentPopDown P((void));
299 void ICSInputBoxPopUp P((void));
300 void ICSInputBoxPopDown P((void));
301 void FileNamePopUp P((char *label, char *def, char *filter,
302 FileProc proc, char *openMode));
303 void FileNamePopDown P((void));
304 void FileNameCallback P((Widget w, XtPointer client_data,
305 XtPointer call_data));
306 void FileNameAction P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void AskQuestionReplyAction P((Widget w, XEvent *event,
309 String *prms, Cardinal *nprms));
310 void AskQuestionProc P((Widget w, XEvent *event,
311 String *prms, Cardinal *nprms));
312 void AskQuestionPopDown P((void));
313 void PromotionPopDown P((void));
314 void PromotionCallback P((Widget w, XtPointer client_data,
315 XtPointer call_data));
316 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
317 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
318 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
319 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
321 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
323 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
325 void LoadPositionProc P((Widget w, XEvent *event,
326 String *prms, Cardinal *nprms));
327 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
329 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
331 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
333 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
335 void PastePositionProc P((Widget w, XEvent *event, String *prms,
337 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void SavePositionProc P((Widget w, XEvent *event,
342 String *prms, Cardinal *nprms));
343 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
344 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
346 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
347 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
348 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
350 void MachineWhiteProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AnalyzeModeProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void AnalyzeFileProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
358 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
359 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
360 void IcsClientProc P((Widget w, XEvent *event, String *prms,
362 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void EditPositionProc P((Widget w, XEvent *event,
364 String *prms, Cardinal *nprms));
365 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void EditCommentProc P((Widget w, XEvent *event,
367 String *prms, Cardinal *nprms));
368 void IcsInputBoxProc P((Widget w, XEvent *event,
369 String *prms, Cardinal *nprms));
370 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void StopObservingProc P((Widget w, XEvent *event, String *prms,
387 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
389 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
393 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 Boolean TempBackwardActive = False;
395 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
398 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
399 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
401 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
403 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
406 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
408 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
410 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
412 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
413 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
415 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
418 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
420 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
422 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
424 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
425 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
427 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
429 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
431 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
433 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
434 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
436 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
438 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
440 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
442 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
451 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
452 void DisplayMove P((int moveNumber));
453 void DisplayTitle P((char *title));
454 void ICSInitScript P((void));
455 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
456 void ErrorPopUp P((char *title, char *text, int modal));
457 void ErrorPopDown P((void));
458 static char *ExpandPathName P((char *path));
459 static void CreateAnimVars P((void));
460 static void DragPieceMove P((int x, int y));
461 static void DrawDragPiece P((void));
462 char *ModeToWidgetName P((GameMode mode));
463 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
477 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
478 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
479 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
480 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
481 void GameListOptionsPopDown P(());
482 void GenericPopDown P(());
483 void update_ics_width P(());
484 int get_term_width P(());
485 int CopyMemoProc P(());
486 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
487 Boolean IsDrawArrowEnabled P(());
490 * XBoard depends on Xt R4 or higher
492 int xtVersion = XtSpecificationRelease;
497 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
498 jailSquareColor, highlightSquareColor, premoveHighlightColor;
499 Pixel lowTimeWarningColor;
500 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
501 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
502 wjPieceGC, bjPieceGC, prelineGC, countGC;
503 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
504 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
505 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
506 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
507 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
508 ICSInputShell, fileNameShell, askQuestionShell;
509 Widget historyShell, evalGraphShell, gameListShell;
510 int hOffset; // [HGM] dual
511 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
512 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
513 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
515 XFontSet fontSet, clockFontSet;
518 XFontStruct *clockFontStruct;
520 Font coordFontID, countFontID;
521 XFontStruct *coordFontStruct, *countFontStruct;
522 XtAppContext appContext;
524 char *oldICSInteractionTitle;
528 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
530 Position commentX = -1, commentY = -1;
531 Dimension commentW, commentH;
532 typedef unsigned int BoardSize;
534 Boolean chessProgram;
536 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
537 int squareSize, smallLayout = 0, tinyLayout = 0,
538 marginW, marginH, // [HGM] for run-time resizing
539 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
540 ICSInputBoxUp = False, askQuestionUp = False,
541 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
542 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
543 Dimension textHeight;
544 Pixel timerForegroundPixel, timerBackgroundPixel;
545 Pixel buttonForegroundPixel, buttonBackgroundPixel;
546 char *chessDir, *programName, *programVersion,
547 *gameCopyFilename, *gamePasteFilename;
548 Boolean alwaysOnTop = False;
549 Boolean saveSettingsOnExit;
550 char *settingsFileName;
551 char *icsTextMenuString;
553 char *firstChessProgramNames;
554 char *secondChessProgramNames;
556 WindowPlacement wpMain;
557 WindowPlacement wpConsole;
558 WindowPlacement wpComment;
559 WindowPlacement wpMoveHistory;
560 WindowPlacement wpEvalGraph;
561 WindowPlacement wpEngineOutput;
562 WindowPlacement wpGameList;
563 WindowPlacement wpTags;
565 extern Widget shells[];
566 extern Boolean shellUp[];
570 Pixmap pieceBitmap[2][(int)BlackPawn];
571 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
572 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
573 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
574 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
575 Pixmap xpmBoardBitmap[2];
576 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
577 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
578 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
579 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
580 XImage *ximLightSquare, *ximDarkSquare;
583 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
584 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
586 #define White(piece) ((int)(piece) < (int)BlackPawn)
588 /* Variables for doing smooth animation. This whole thing
589 would be much easier if the board was double-buffered,
590 but that would require a fairly major rewrite. */
595 GC blitGC, pieceGC, outlineGC;
596 XPoint startSquare, prevFrame, mouseDelta;
600 int startBoardX, startBoardY;
603 /* There can be two pieces being animated at once: a player
604 can begin dragging a piece before the remote opponent has moved. */
606 static AnimState game, player;
608 /* Bitmaps for use as masks when drawing XPM pieces.
609 Need one for each black and white piece. */
610 static Pixmap xpmMask[BlackKing + 1];
612 /* This magic number is the number of intermediate frames used
613 in each half of the animation. For short moves it's reduced
614 by 1. The total number of frames will be factor * 2 + 1. */
617 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
619 MenuItem fileMenu[] = {
620 {N_("New Game Ctrl+N"), "New Game", ResetProc},
621 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
622 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
623 {"----", NULL, NothingProc},
624 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
625 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
626 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
627 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
628 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
629 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
630 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
631 {"----", NULL, NothingProc},
632 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
633 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
634 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
635 {"----", NULL, NothingProc},
636 {N_("Mail Move"), "Mail Move", MailMoveProc},
637 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
638 {"----", NULL, NothingProc},
639 {N_("Quit Ctr+Q"), "Exit", QuitProc},
643 MenuItem editMenu[] = {
644 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
645 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
646 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
647 {"----", NULL, NothingProc},
648 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
649 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
650 {"----", NULL, NothingProc},
651 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
652 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
653 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
654 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
655 {N_("Edit Book"), "Edit Book", EditBookProc},
656 {"----", NULL, NothingProc},
657 {N_("Revert Home"), "Revert", RevertProc},
658 {N_("Annotate"), "Annotate", AnnotateProc},
659 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
660 {"----", NULL, NothingProc},
661 {N_("Backward Alt+Left"), "Backward", BackwardProc},
662 {N_("Forward Alt+Right"), "Forward", ForwardProc},
663 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
664 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
668 MenuItem viewMenu[] = {
669 {N_("Flip View F2"), "Flip View", FlipViewProc},
670 {"----", NULL, NothingProc},
671 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
672 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
673 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
674 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
675 {N_("ICS text menu"), "ICStex", IcsTextProc},
676 {"----", NULL, NothingProc},
677 {N_("Tags"), "Show Tags", EditTagsProc},
678 {N_("Comments"), "Show Comments", EditCommentProc},
679 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
680 {"----", NULL, NothingProc},
681 {N_("Board..."), "Board Options", BoardOptionsProc},
682 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
686 MenuItem modeMenu[] = {
687 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
688 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
689 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
690 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
691 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
692 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
693 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
694 {N_("Training"), "Training", TrainingProc},
695 {N_("ICS Client"), "ICS Client", IcsClientProc},
696 {"----", NULL, NothingProc},
697 {N_("Machine Match"), "Machine Match", MatchProc},
698 {N_("Pause Pause"), "Pause", PauseProc},
702 MenuItem actionMenu[] = {
703 {N_("Accept F3"), "Accept", AcceptProc},
704 {N_("Decline F4"), "Decline", DeclineProc},
705 {N_("Rematch F12"), "Rematch", RematchProc},
706 {"----", NULL, NothingProc},
707 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
708 {N_("Draw F6"), "Draw", DrawProc},
709 {N_("Adjourn F7"), "Adjourn", AdjournProc},
710 {N_("Abort F8"),"Abort", AbortProc},
711 {N_("Resign F9"), "Resign", ResignProc},
712 {"----", NULL, NothingProc},
713 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
714 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
715 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
716 {"----", NULL, NothingProc},
717 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
718 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
719 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
723 MenuItem engineMenu[] = {
724 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
725 {"----", NULL, NothingProc},
726 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
727 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
728 {"----", NULL, NothingProc},
729 {N_("Hint"), "Hint", HintProc},
730 {N_("Book"), "Book", BookProc},
731 {"----", NULL, NothingProc},
732 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
733 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
737 MenuItem optionsMenu[] = {
738 #define OPTIONSDIALOG
740 {N_("General ..."), "General", OptionsProc},
742 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
743 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
744 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
745 {N_("ICS ..."), "ICS", IcsOptionsProc},
746 {N_("Match ..."), "Match", MatchOptionsProc},
747 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
748 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
749 // {N_(" ..."), "", OptionsProc},
750 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
751 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
752 {"----", NULL, NothingProc},
753 #ifndef OPTIONSDIALOG
754 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
755 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
756 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
757 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
758 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
759 {N_("Blindfold"), "Blindfold", BlindfoldProc},
760 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
762 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
764 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
765 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
766 {N_("Move Sound"), "Move Sound", MoveSoundProc},
767 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
768 {N_("One-Click Moving"), "OneClick", OneClickProc},
769 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
770 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
771 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
772 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
773 // {N_("Premove"), "Premove", PremoveProc},
774 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
775 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
776 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
777 {"----", NULL, NothingProc},
779 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
780 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
784 MenuItem helpMenu[] = {
785 {N_("Info XBoard"), "Info XBoard", InfoProc},
786 {N_("Man XBoard F1"), "Man XBoard", ManProc},
787 {"----", NULL, NothingProc},
788 {N_("About XBoard"), "About XBoard", AboutProc},
793 {N_("File"), "File", fileMenu},
794 {N_("Edit"), "Edit", editMenu},
795 {N_("View"), "View", viewMenu},
796 {N_("Mode"), "Mode", modeMenu},
797 {N_("Action"), "Action", actionMenu},
798 {N_("Engine"), "Engine", engineMenu},
799 {N_("Options"), "Options", optionsMenu},
800 {N_("Help"), "Help", helpMenu},
804 #define PAUSE_BUTTON "P"
805 MenuItem buttonBar[] = {
806 {"<<", "<<", ToStartProc},
807 {"<", "<", BackwardProc},
808 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
809 {">", ">", ForwardProc},
810 {">>", ">>", ToEndProc},
814 #define PIECE_MENU_SIZE 18
815 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
816 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
817 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
818 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
819 N_("Empty square"), N_("Clear board") },
820 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
821 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
822 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
823 N_("Empty square"), N_("Clear board") }
825 /* must be in same order as pieceMenuStrings! */
826 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
827 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
828 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
829 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
830 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
831 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
832 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
833 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
834 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
837 #define DROP_MENU_SIZE 6
838 String dropMenuStrings[DROP_MENU_SIZE] = {
839 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
841 /* must be in same order as dropMenuStrings! */
842 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
843 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
844 WhiteRook, WhiteQueen
852 DropMenuEnables dmEnables[] = {
870 { XtNborderWidth, 0 },
871 { XtNdefaultDistance, 0 },
875 { XtNborderWidth, 0 },
876 { XtNresizable, (XtArgVal) True },
880 { XtNborderWidth, 0 },
886 { XtNjustify, (XtArgVal) XtJustifyRight },
887 { XtNlabel, (XtArgVal) "..." },
888 { XtNresizable, (XtArgVal) True },
889 { XtNresize, (XtArgVal) False }
892 Arg messageArgs[] = {
893 { XtNjustify, (XtArgVal) XtJustifyLeft },
894 { XtNlabel, (XtArgVal) "..." },
895 { XtNresizable, (XtArgVal) True },
896 { XtNresize, (XtArgVal) False }
900 { XtNborderWidth, 0 },
901 { XtNjustify, (XtArgVal) XtJustifyLeft }
904 XtResource clientResources[] = {
905 { "flashCount", "flashCount", XtRInt, sizeof(int),
906 XtOffset(AppDataPtr, flashCount), XtRImmediate,
907 (XtPointer) FLASH_COUNT },
910 XrmOptionDescRec shellOptions[] = {
911 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
912 { "-flash", "flashCount", XrmoptionNoArg, "3" },
913 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
916 XtActionsRec boardActions[] = {
917 { "DrawPosition", DrawPositionProc },
918 { "HandleUserMove", HandleUserMove },
919 { "AnimateUserMove", AnimateUserMove },
920 { "HandlePV", HandlePV },
921 { "SelectPV", SelectPV },
922 { "StopPV", StopPV },
923 { "FileNameAction", FileNameAction },
924 { "AskQuestionProc", AskQuestionProc },
925 { "AskQuestionReplyAction", AskQuestionReplyAction },
926 { "PieceMenuPopup", PieceMenuPopup },
927 { "WhiteClock", WhiteClock },
928 { "BlackClock", BlackClock },
929 { "ResetProc", ResetProc },
930 { "NewVariantProc", NewVariantProc },
931 { "LoadGameProc", LoadGameProc },
932 { "LoadNextGameProc", LoadNextGameProc },
933 { "LoadPrevGameProc", LoadPrevGameProc },
934 { "LoadSelectedProc", LoadSelectedProc },
935 { "SetFilterProc", SetFilterProc },
936 { "ReloadGameProc", ReloadGameProc },
937 { "LoadPositionProc", LoadPositionProc },
938 { "LoadNextPositionProc", LoadNextPositionProc },
939 { "LoadPrevPositionProc", LoadPrevPositionProc },
940 { "ReloadPositionProc", ReloadPositionProc },
941 { "CopyPositionProc", CopyPositionProc },
942 { "PastePositionProc", PastePositionProc },
943 { "CopyGameProc", CopyGameProc },
944 { "CopyGameListProc", CopyGameListProc },
945 { "PasteGameProc", PasteGameProc },
946 { "SaveGameProc", SaveGameProc },
947 { "SavePositionProc", SavePositionProc },
948 { "MailMoveProc", MailMoveProc },
949 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
950 { "QuitProc", QuitProc },
951 { "MachineWhiteProc", MachineWhiteProc },
952 { "MachineBlackProc", MachineBlackProc },
953 { "AnalysisModeProc", AnalyzeModeProc },
954 { "AnalyzeFileProc", AnalyzeFileProc },
955 { "TwoMachinesProc", TwoMachinesProc },
956 { "IcsClientProc", IcsClientProc },
957 { "EditGameProc", EditGameProc },
958 { "EditPositionProc", EditPositionProc },
959 { "TrainingProc", EditPositionProc },
960 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
961 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
962 { "ShowGameListProc", ShowGameListProc },
963 { "ShowMoveListProc", HistoryShowProc},
964 { "EditTagsProc", EditTagsProc },
965 { "EditBookProc", EditBookProc },
966 { "EditCommentProc", EditCommentProc },
967 { "IcsInputBoxProc", IcsInputBoxProc },
968 { "PauseProc", PauseProc },
969 { "AcceptProc", AcceptProc },
970 { "DeclineProc", DeclineProc },
971 { "RematchProc", RematchProc },
972 { "CallFlagProc", CallFlagProc },
973 { "DrawProc", DrawProc },
974 { "AdjournProc", AdjournProc },
975 { "AbortProc", AbortProc },
976 { "ResignProc", ResignProc },
977 { "AdjuWhiteProc", AdjuWhiteProc },
978 { "AdjuBlackProc", AdjuBlackProc },
979 { "AdjuDrawProc", AdjuDrawProc },
980 { "TypeInProc", TypeInProc },
981 { "EnterKeyProc", EnterKeyProc },
982 { "UpKeyProc", UpKeyProc },
983 { "DownKeyProc", DownKeyProc },
984 { "StopObservingProc", StopObservingProc },
985 { "StopExaminingProc", StopExaminingProc },
986 { "UploadProc", UploadProc },
987 { "BackwardProc", BackwardProc },
988 { "ForwardProc", ForwardProc },
989 { "TempBackwardProc", TempBackwardProc },
990 { "TempForwardProc", TempForwardProc },
991 { "ToStartProc", ToStartProc },
992 { "ToEndProc", ToEndProc },
993 { "RevertProc", RevertProc },
994 { "AnnotateProc", AnnotateProc },
995 { "TruncateGameProc", TruncateGameProc },
996 { "MoveNowProc", MoveNowProc },
997 { "RetractMoveProc", RetractMoveProc },
998 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
999 { "UciMenuProc", (XtActionProc) UciMenuProc },
1000 { "TimeControlProc", (XtActionProc) TimeControlProc },
1001 { "FlipViewProc", FlipViewProc },
1002 { "PonderNextMoveProc", PonderNextMoveProc },
1003 #ifndef OPTIONSDIALOG
1004 { "AlwaysQueenProc", AlwaysQueenProc },
1005 { "AnimateDraggingProc", AnimateDraggingProc },
1006 { "AnimateMovingProc", AnimateMovingProc },
1007 { "AutoflagProc", AutoflagProc },
1008 { "AutoflipProc", AutoflipProc },
1009 { "BlindfoldProc", BlindfoldProc },
1010 { "FlashMovesProc", FlashMovesProc },
1012 { "HighlightDraggingProc", HighlightDraggingProc },
1014 { "HighlightLastMoveProc", HighlightLastMoveProc },
1015 // { "IcsAlarmProc", IcsAlarmProc },
1016 { "MoveSoundProc", MoveSoundProc },
1017 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1018 { "PopupExitMessageProc", PopupExitMessageProc },
1019 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1020 // { "PremoveProc", PremoveProc },
1021 { "ShowCoordsProc", ShowCoordsProc },
1022 { "ShowThinkingProc", ShowThinkingProc },
1023 { "HideThinkingProc", HideThinkingProc },
1024 { "TestLegalityProc", TestLegalityProc },
1026 { "SaveSettingsProc", SaveSettingsProc },
1027 { "SaveOnExitProc", SaveOnExitProc },
1028 { "InfoProc", InfoProc },
1029 { "ManProc", ManProc },
1030 { "HintProc", HintProc },
1031 { "BookProc", BookProc },
1032 { "AboutGameProc", AboutGameProc },
1033 { "AboutProc", AboutProc },
1034 { "DebugProc", DebugProc },
1035 { "NothingProc", NothingProc },
1036 { "CommentClick", (XtActionProc) CommentClick },
1037 { "CommentPopDown", (XtActionProc) CommentPopDown },
1038 { "TagsPopDown", (XtActionProc) TagsPopDown },
1039 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1040 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1041 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1042 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1043 { "GameListPopDown", (XtActionProc) GameListPopDown },
1044 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1045 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1046 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1047 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1048 { "GenericPopDown", (XtActionProc) GenericPopDown },
1049 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1050 { "SelectMove", (XtActionProc) SelectMove },
1053 char globalTranslations[] =
1054 ":<Key>F9: ResignProc() \n \
1055 :Ctrl<Key>n: ResetProc() \n \
1056 :Meta<Key>V: NewVariantProc() \n \
1057 :Ctrl<Key>o: LoadGameProc() \n \
1058 :Meta<Key>Next: LoadNextGameProc() \n \
1059 :Meta<Key>Prior: LoadPrevGameProc() \n \
1060 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1061 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1062 :Ctrl<Key>s: SaveGameProc() \n \
1063 :Ctrl<Key>c: CopyGameProc() \n \
1064 :Ctrl<Key>v: PasteGameProc() \n \
1065 :Ctrl<Key>O: LoadPositionProc() \n \
1066 :Shift<Key>Next: LoadNextPositionProc() \n \
1067 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1068 :Ctrl<Key>S: SavePositionProc() \n \
1069 :Ctrl<Key>C: CopyPositionProc() \n \
1070 :Ctrl<Key>V: PastePositionProc() \n \
1071 :Ctrl<Key>q: QuitProc() \n \
1072 :Ctrl<Key>w: MachineWhiteProc() \n \
1073 :Ctrl<Key>b: MachineBlackProc() \n \
1074 :Ctrl<Key>t: TwoMachinesProc() \n \
1075 :Ctrl<Key>a: AnalysisModeProc() \n \
1076 :Ctrl<Key>g: AnalyzeFileProc() \n \
1077 :Ctrl<Key>e: EditGameProc() \n \
1078 :Ctrl<Key>E: EditPositionProc() \n \
1079 :Meta<Key>O: EngineOutputProc() \n \
1080 :Meta<Key>E: EvalGraphProc() \n \
1081 :Meta<Key>G: ShowGameListProc() \n \
1082 :Meta<Key>H: ShowMoveListProc() \n \
1083 :<Key>Pause: PauseProc() \n \
1084 :<Key>F3: AcceptProc() \n \
1085 :<Key>F4: DeclineProc() \n \
1086 :<Key>F12: RematchProc() \n \
1087 :<Key>F5: CallFlagProc() \n \
1088 :<Key>F6: DrawProc() \n \
1089 :<Key>F7: AdjournProc() \n \
1090 :<Key>F8: AbortProc() \n \
1091 :<Key>F10: StopObservingProc() \n \
1092 :<Key>F11: StopExaminingProc() \n \
1093 :Meta Ctrl<Key>F12: DebugProc() \n \
1094 :Meta<Key>End: ToEndProc() \n \
1095 :Meta<Key>Right: ForwardProc() \n \
1096 :Meta<Key>Home: ToStartProc() \n \
1097 :Meta<Key>Left: BackwardProc() \n \
1098 :<Key>Left: BackwardProc() \n \
1099 :<Key>Right: ForwardProc() \n \
1100 :<Key>Home: RevertProc() \n \
1101 :<Key>End: TruncateGameProc() \n \
1102 :Ctrl<Key>m: MoveNowProc() \n \
1103 :Ctrl<Key>x: RetractMoveProc() \n \
1104 :Meta<Key>J: EngineMenuProc() \n \
1105 :Meta<Key>U: UciMenuProc() \n \
1106 :Meta<Key>T: TimeControlProc() \n \
1107 :Ctrl<Key>P: PonderNextMoveProc() \n "
1108 #ifndef OPTIONSDIALOG
1110 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1111 :Ctrl<Key>F: AutoflagProc() \n \
1112 :Ctrl<Key>A: AnimateMovingProc() \n \
1113 :Ctrl<Key>L: TestLegalityProc() \n \
1114 :Ctrl<Key>H: HideThinkingProc() \n "
1117 :<Key>F1: ManProc() \n \
1118 :<Key>F2: FlipViewProc() \n \
1119 :<KeyDown>Return: TempBackwardProc() \n \
1120 :<KeyUp>Return: TempForwardProc() \n";
1122 char boardTranslations[] =
1123 "<Btn1Down>: HandleUserMove(0) \n \
1124 Shift<Btn1Up>: HandleUserMove(1) \n \
1125 <Btn1Up>: HandleUserMove(0) \n \
1126 <Btn1Motion>: AnimateUserMove() \n \
1127 <Btn3Motion>: HandlePV() \n \
1128 <Btn3Up>: PieceMenuPopup(menuB) \n \
1129 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1130 PieceMenuPopup(menuB) \n \
1131 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1132 PieceMenuPopup(menuW) \n \
1133 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1134 PieceMenuPopup(menuW) \n \
1135 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1136 PieceMenuPopup(menuB) \n";
1138 char whiteTranslations[] =
1139 "Shift<BtnDown>: WhiteClock(1)\n \
1140 <BtnDown>: WhiteClock(0)\n";
1141 char blackTranslations[] =
1142 "Shift<BtnDown>: BlackClock(1)\n \
1143 <BtnDown>: BlackClock(0)\n";
1145 char ICSInputTranslations[] =
1146 "<Key>Up: UpKeyProc() \n "
1147 "<Key>Down: DownKeyProc() \n "
1148 "<Key>Return: EnterKeyProc() \n";
1150 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1151 // as the widget is destroyed before the up-click can call extend-end
1152 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1154 String xboardResources[] = {
1155 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1156 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1157 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1162 /* Max possible square size */
1163 #define MAXSQSIZE 256
1165 static int xpm_avail[MAXSQSIZE];
1167 #ifdef HAVE_DIR_STRUCT
1169 /* Extract piece size from filename */
1171 xpm_getsize (char *name, int len, char *ext)
1179 if ((p=strchr(name, '.')) == NULL ||
1180 StrCaseCmp(p+1, ext) != 0)
1186 while (*p && isdigit(*p))
1193 /* Setup xpm_avail */
1195 xpm_getavail (char *dirname, char *ext)
1201 for (i=0; i<MAXSQSIZE; ++i)
1204 if (appData.debugMode)
1205 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1207 dir = opendir(dirname);
1210 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1211 programName, dirname);
1215 while ((ent=readdir(dir)) != NULL) {
1216 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1217 if (i > 0 && i < MAXSQSIZE)
1227 xpm_print_avail (FILE *fp, char *ext)
1231 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1232 for (i=1; i<MAXSQSIZE; ++i) {
1238 /* Return XPM piecesize closest to size */
1240 xpm_closest_to (char *dirname, int size, char *ext)
1243 int sm_diff = MAXSQSIZE;
1247 xpm_getavail(dirname, ext);
1249 if (appData.debugMode)
1250 xpm_print_avail(stderr, ext);
1252 for (i=1; i<MAXSQSIZE; ++i) {
1255 diff = (diff<0) ? -diff : diff;
1256 if (diff < sm_diff) {
1264 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1270 #else /* !HAVE_DIR_STRUCT */
1271 /* If we are on a system without a DIR struct, we can't
1272 read the directory, so we can't collect a list of
1273 filenames, etc., so we can't do any size-fitting. */
1275 xpm_closest_to (char *dirname, int size, char *ext)
1277 fprintf(stderr, _("\
1278 Warning: No DIR structure found on this system --\n\
1279 Unable to autosize for XPM/XIM pieces.\n\
1280 Please report this error to %s.\n\
1281 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1284 #endif /* HAVE_DIR_STRUCT */
1286 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1287 "magenta", "cyan", "white" };
1291 TextColors textColors[(int)NColorClasses];
1293 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1295 parse_color (char *str, int which)
1297 char *p, buf[100], *d;
1300 if (strlen(str) > 99) /* watch bounds on buf */
1305 for (i=0; i<which; ++i) {
1312 /* Could be looking at something like:
1314 .. in which case we want to stop on a comma also */
1315 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1319 return -1; /* Use default for empty field */
1322 if (which == 2 || isdigit(*p))
1325 while (*p && isalpha(*p))
1330 for (i=0; i<8; ++i) {
1331 if (!StrCaseCmp(buf, cnames[i]))
1332 return which? (i+40) : (i+30);
1334 if (!StrCaseCmp(buf, "default")) return -1;
1336 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1341 parse_cpair (ColorClass cc, char *str)
1343 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1344 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1349 /* bg and attr are optional */
1350 textColors[(int)cc].bg = parse_color(str, 1);
1351 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1352 textColors[(int)cc].attr = 0;
1358 /* Arrange to catch delete-window events */
1359 Atom wm_delete_window;
1361 CatchDeleteWindow (Widget w, String procname)
1364 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1365 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1366 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1373 XtSetArg(args[0], XtNiconic, False);
1374 XtSetValues(shellWidget, args, 1);
1376 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1379 //---------------------------------------------------------------------------------------------------------
1380 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1383 #define CW_USEDEFAULT (1<<31)
1384 #define ICS_TEXT_MENU_SIZE 90
1385 #define DEBUG_FILE "xboard.debug"
1386 #define SetCurrentDirectory chdir
1387 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1391 // these two must some day move to frontend.h, when they are implemented
1392 Boolean GameListIsUp();
1394 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1397 // front-end part of option handling
1399 // [HGM] This platform-dependent table provides the location for storing the color info
1400 extern char *crWhite, * crBlack;
1404 &appData.whitePieceColor,
1405 &appData.blackPieceColor,
1406 &appData.lightSquareColor,
1407 &appData.darkSquareColor,
1408 &appData.highlightSquareColor,
1409 &appData.premoveHighlightColor,
1410 &appData.lowTimeWarningColor,
1421 // [HGM] font: keep a font for each square size, even non-stndard ones
1422 #define NUM_SIZES 18
1423 #define MAX_SIZE 130
1424 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1425 char *fontTable[NUM_FONTS][MAX_SIZE];
1428 ParseFont (char *name, int number)
1429 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1431 if(sscanf(name, "size%d:", &size)) {
1432 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1433 // defer processing it until we know if it matches our board size
1434 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1435 fontTable[number][size] = strdup(strchr(name, ':')+1);
1436 fontValid[number][size] = True;
1441 case 0: // CLOCK_FONT
1442 appData.clockFont = strdup(name);
1444 case 1: // MESSAGE_FONT
1445 appData.font = strdup(name);
1447 case 2: // COORD_FONT
1448 appData.coordFont = strdup(name);
1453 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1458 { // only 2 fonts currently
1459 appData.clockFont = CLOCK_FONT_NAME;
1460 appData.coordFont = COORD_FONT_NAME;
1461 appData.font = DEFAULT_FONT_NAME;
1466 { // no-op, until we identify the code for this already in XBoard and move it here
1470 ParseColor (int n, char *name)
1471 { // in XBoard, just copy the color-name string
1472 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1476 ParseTextAttribs (ColorClass cc, char *s)
1478 (&appData.colorShout)[cc] = strdup(s);
1482 ParseBoardSize (void *addr, char *name)
1484 appData.boardSize = strdup(name);
1489 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1493 SetCommPortDefaults ()
1494 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1497 // [HGM] args: these three cases taken out to stay in front-end
1499 SaveFontArg (FILE *f, ArgDescriptor *ad)
1502 int i, n = (int)(intptr_t)ad->argLoc;
1504 case 0: // CLOCK_FONT
1505 name = appData.clockFont;
1507 case 1: // MESSAGE_FONT
1508 name = appData.font;
1510 case 2: // COORD_FONT
1511 name = appData.coordFont;
1516 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1517 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1518 fontTable[n][squareSize] = strdup(name);
1519 fontValid[n][squareSize] = True;
1522 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1523 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1528 { // nothing to do, as the sounds are at all times represented by their text-string names already
1532 SaveAttribsArg (FILE *f, ArgDescriptor *ad)
1533 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1534 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1538 SaveColor (FILE *f, ArgDescriptor *ad)
1539 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1540 if(colorVariable[(int)(intptr_t)ad->argLoc])
1541 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1545 SaveBoardSize (FILE *f, char *name, void *addr)
1546 { // wrapper to shield back-end from BoardSize & sizeInfo
1547 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1551 ParseCommPortSettings (char *s)
1552 { // no such option in XBoard (yet)
1555 extern Widget engineOutputShell;
1558 GetActualPlacement (Widget wg, WindowPlacement *wp)
1568 XtSetArg(args[i], XtNx, &x); i++;
1569 XtSetArg(args[i], XtNy, &y); i++;
1570 XtSetArg(args[i], XtNwidth, &w); i++;
1571 XtSetArg(args[i], XtNheight, &h); i++;
1572 XtGetValues(wg, args, i);
1581 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1582 // In XBoard this will have to wait until awareness of window parameters is implemented
1583 GetActualPlacement(shellWidget, &wpMain);
1584 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1585 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1586 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1587 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1588 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1589 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1593 PrintCommPortSettings (FILE *f, char *name)
1594 { // This option does not exist in XBoard
1598 MySearchPath (char *installDir, char *name, char *fullname)
1599 { // just append installDir and name. Perhaps ExpandPath should be used here?
1600 name = ExpandPathName(name);
1601 if(name && name[0] == '/')
1602 safeStrCpy(fullname, name, MSG_SIZ );
1604 sprintf(fullname, "%s%c%s", installDir, '/', name);
1610 MyGetFullPathName (char *name, char *fullname)
1611 { // should use ExpandPath?
1612 name = ExpandPathName(name);
1613 safeStrCpy(fullname, name, MSG_SIZ );
1618 EnsureOnScreen (int *x, int *y, int minX, int minY)
1625 { // [HGM] args: allows testing if main window is realized from back-end
1626 return xBoardWindow != 0;
1630 PopUpStartupDialog ()
1631 { // start menu not implemented in XBoard
1635 ConvertToLine (int argc, char **argv)
1637 static char line[128*1024], buf[1024];
1641 for(i=1; i<argc; i++)
1643 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1644 && argv[i][0] != '{' )
1645 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1647 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1648 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1651 line[strlen(line)-1] = NULLCHAR;
1655 //--------------------------------------------------------------------------------------------
1657 extern Boolean twoBoards, partnerUp;
1660 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1662 #define BoardSize int
1664 InitDrawingSizes (BoardSize boardSize, int flags)
1665 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1666 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1668 XtGeometryResult gres;
1670 static Dimension oldWidth, oldHeight;
1671 static VariantClass oldVariant;
1672 static int oldDual = -1, oldMono = -1;
1674 if(!formWidget) return;
1676 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1677 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1678 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1680 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1682 * Enable shell resizing.
1684 shellArgs[0].value = (XtArgVal) &w;
1685 shellArgs[1].value = (XtArgVal) &h;
1686 XtGetValues(shellWidget, shellArgs, 2);
1688 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1689 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1690 XtSetValues(shellWidget, &shellArgs[2], 4);
1692 XtSetArg(args[0], XtNdefaultDistance, &sep);
1693 XtGetValues(formWidget, args, 1);
1695 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1697 hOffset = boardWidth + 10;
1698 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1699 secondSegments[i] = gridSegments[i];
1700 secondSegments[i].x1 += hOffset;
1701 secondSegments[i].x2 += hOffset;
1704 XtSetArg(args[0], XtNwidth, boardWidth);
1705 XtSetArg(args[1], XtNheight, boardHeight);
1706 XtSetValues(boardWidget, args, 2);
1708 timerWidth = (boardWidth - sep) / 2;
1709 XtSetArg(args[0], XtNwidth, timerWidth);
1710 XtSetValues(whiteTimerWidget, args, 1);
1711 XtSetValues(blackTimerWidget, args, 1);
1713 XawFormDoLayout(formWidget, False);
1715 if (appData.titleInWindow) {
1717 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1718 XtSetArg(args[i], XtNheight, &h); i++;
1719 XtGetValues(titleWidget, args, i);
1721 w = boardWidth - 2*bor;
1723 XtSetArg(args[0], XtNwidth, &w);
1724 XtGetValues(menuBarWidget, args, 1);
1725 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1728 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1729 if (gres != XtGeometryYes && appData.debugMode) {
1731 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1732 programName, gres, w, h, wr, hr);
1736 XawFormDoLayout(formWidget, True);
1739 * Inhibit shell resizing.
1741 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1742 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1743 shellArgs[4].value = shellArgs[2].value = w;
1744 shellArgs[5].value = shellArgs[3].value = h;
1745 XtSetValues(shellWidget, &shellArgs[0], 6);
1748 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1751 if(gameInfo.variant != oldVariant) { // and only if variant changed
1754 for(i=0; i<4; i++) {
1756 for(p=0; p<=(int)WhiteKing; p++)
1757 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1758 if(gameInfo.variant == VariantShogi) {
1759 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1760 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1761 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1762 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1763 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1766 if(gameInfo.variant == VariantGothic) {
1767 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1770 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1771 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1772 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1775 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1776 for(p=0; p<=(int)WhiteKing; p++)
1777 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1778 if(gameInfo.variant == VariantShogi) {
1779 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1780 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1781 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1782 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1783 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1786 if(gameInfo.variant == VariantGothic) {
1787 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1790 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1791 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1792 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1797 for(i=0; i<2; i++) {
1799 for(p=0; p<=(int)WhiteKing; p++)
1800 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1801 if(gameInfo.variant == VariantShogi) {
1802 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1803 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1804 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1805 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1806 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1809 if(gameInfo.variant == VariantGothic) {
1810 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1813 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1814 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1815 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1821 if(appData.monoMode != oldMono)
1824 oldMono = appData.monoMode;
1829 ParseIcsTextColors ()
1830 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1831 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1832 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1833 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1834 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1835 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1836 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1837 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1838 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1839 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1840 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1842 if (appData.colorize) {
1844 _("%s: can't parse color names; disabling colorization\n"),
1847 appData.colorize = FALSE;
1853 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1854 XrmValue vFrom, vTo;
1855 int forceMono = False;
1857 if (!appData.monoMode) {
1858 vFrom.addr = (caddr_t) appData.lightSquareColor;
1859 vFrom.size = strlen(appData.lightSquareColor);
1860 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1861 if (vTo.addr == NULL) {
1862 appData.monoMode = True;
1865 lightSquareColor = *(Pixel *) vTo.addr;
1868 if (!appData.monoMode) {
1869 vFrom.addr = (caddr_t) appData.darkSquareColor;
1870 vFrom.size = strlen(appData.darkSquareColor);
1871 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1872 if (vTo.addr == NULL) {
1873 appData.monoMode = True;
1876 darkSquareColor = *(Pixel *) vTo.addr;
1879 if (!appData.monoMode) {
1880 vFrom.addr = (caddr_t) appData.whitePieceColor;
1881 vFrom.size = strlen(appData.whitePieceColor);
1882 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1883 if (vTo.addr == NULL) {
1884 appData.monoMode = True;
1887 whitePieceColor = *(Pixel *) vTo.addr;
1890 if (!appData.monoMode) {
1891 vFrom.addr = (caddr_t) appData.blackPieceColor;
1892 vFrom.size = strlen(appData.blackPieceColor);
1893 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1894 if (vTo.addr == NULL) {
1895 appData.monoMode = True;
1898 blackPieceColor = *(Pixel *) vTo.addr;
1902 if (!appData.monoMode) {
1903 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1904 vFrom.size = strlen(appData.highlightSquareColor);
1905 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1906 if (vTo.addr == NULL) {
1907 appData.monoMode = True;
1910 highlightSquareColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1916 vFrom.size = strlen(appData.premoveHighlightColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 premoveHighlightColor = *(Pixel *) vTo.addr;
1930 { // [HGM] taken out of main
1932 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1933 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1934 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1936 if (appData.bitmapDirectory[0] != NULLCHAR) {
1940 CreateXPMBoard(appData.liteBackTextureFile, 1);
1941 CreateXPMBoard(appData.darkBackTextureFile, 0);
1945 /* Create regular pieces */
1946 if (!useImages) CreatePieces();
1951 main (int argc, char **argv)
1953 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1954 XSetWindowAttributes window_attributes;
1956 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1957 XrmValue vFrom, vTo;
1958 XtGeometryResult gres;
1961 int forceMono = False;
1963 srandom(time(0)); // [HGM] book: make random truly random
1965 setbuf(stdout, NULL);
1966 setbuf(stderr, NULL);
1969 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1970 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1974 programName = strrchr(argv[0], '/');
1975 if (programName == NULL)
1976 programName = argv[0];
1981 XtSetLanguageProc(NULL, NULL, NULL);
1982 bindtextdomain(PACKAGE, LOCALEDIR);
1983 textdomain(PACKAGE);
1987 XtAppInitialize(&appContext, "XBoard", shellOptions,
1988 XtNumber(shellOptions),
1989 &argc, argv, xboardResources, NULL, 0);
1990 appData.boardSize = "";
1991 InitAppData(ConvertToLine(argc, argv));
1993 if (p == NULL) p = "/tmp";
1994 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1995 gameCopyFilename = (char*) malloc(i);
1996 gamePasteFilename = (char*) malloc(i);
1997 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1998 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2000 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2001 clientResources, XtNumber(clientResources),
2004 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2005 static char buf[MSG_SIZ];
2006 EscapeExpand(buf, appData.firstInitString);
2007 appData.firstInitString = strdup(buf);
2008 EscapeExpand(buf, appData.secondInitString);
2009 appData.secondInitString = strdup(buf);
2010 EscapeExpand(buf, appData.firstComputerString);
2011 appData.firstComputerString = strdup(buf);
2012 EscapeExpand(buf, appData.secondComputerString);
2013 appData.secondComputerString = strdup(buf);
2016 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2019 if (chdir(chessDir) != 0) {
2020 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2026 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2027 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2028 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2029 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2032 setbuf(debugFP, NULL);
2036 if (appData.debugMode) {
2037 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2041 /* [HGM,HR] make sure board size is acceptable */
2042 if(appData.NrFiles > BOARD_FILES ||
2043 appData.NrRanks > BOARD_RANKS )
2044 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2047 /* This feature does not work; animation needs a rewrite */
2048 appData.highlightDragging = FALSE;
2052 xDisplay = XtDisplay(shellWidget);
2053 xScreen = DefaultScreen(xDisplay);
2054 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2056 gameInfo.variant = StringToVariant(appData.variant);
2057 InitPosition(FALSE);
2060 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2062 if (isdigit(appData.boardSize[0])) {
2063 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2064 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2065 &fontPxlSize, &smallLayout, &tinyLayout);
2067 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2068 programName, appData.boardSize);
2072 /* Find some defaults; use the nearest known size */
2073 SizeDefaults *szd, *nearest;
2074 int distance = 99999;
2075 nearest = szd = sizeDefaults;
2076 while (szd->name != NULL) {
2077 if (abs(szd->squareSize - squareSize) < distance) {
2079 distance = abs(szd->squareSize - squareSize);
2080 if (distance == 0) break;
2084 if (i < 2) lineGap = nearest->lineGap;
2085 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2086 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2087 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2088 if (i < 6) smallLayout = nearest->smallLayout;
2089 if (i < 7) tinyLayout = nearest->tinyLayout;
2092 SizeDefaults *szd = sizeDefaults;
2093 if (*appData.boardSize == NULLCHAR) {
2094 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2095 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2098 if (szd->name == NULL) szd--;
2099 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2101 while (szd->name != NULL &&
2102 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2103 if (szd->name == NULL) {
2104 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2105 programName, appData.boardSize);
2109 squareSize = szd->squareSize;
2110 lineGap = szd->lineGap;
2111 clockFontPxlSize = szd->clockFontPxlSize;
2112 coordFontPxlSize = szd->coordFontPxlSize;
2113 fontPxlSize = szd->fontPxlSize;
2114 smallLayout = szd->smallLayout;
2115 tinyLayout = szd->tinyLayout;
2116 // [HGM] font: use defaults from settings file if available and not overruled
2118 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2119 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2120 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2121 appData.font = fontTable[MESSAGE_FONT][squareSize];
2122 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2123 appData.coordFont = fontTable[COORD_FONT][squareSize];
2125 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2126 if (strlen(appData.pixmapDirectory) > 0) {
2127 p = ExpandPathName(appData.pixmapDirectory);
2129 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2130 appData.pixmapDirectory);
2133 if (appData.debugMode) {
2134 fprintf(stderr, _("\
2135 XBoard square size (hint): %d\n\
2136 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2138 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2139 if (appData.debugMode) {
2140 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2143 defaultLineGap = lineGap;
2144 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2146 /* [HR] height treated separately (hacked) */
2147 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2148 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2149 if (appData.showJail == 1) {
2150 /* Jail on top and bottom */
2151 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2152 XtSetArg(boardArgs[2], XtNheight,
2153 boardHeight + 2*(lineGap + squareSize));
2154 } else if (appData.showJail == 2) {
2156 XtSetArg(boardArgs[1], XtNwidth,
2157 boardWidth + 2*(lineGap + squareSize));
2158 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2161 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2162 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2166 * Determine what fonts to use.
2169 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2170 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2171 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2172 fontSet = CreateFontSet(appData.font);
2173 clockFontSet = CreateFontSet(appData.clockFont);
2175 /* For the coordFont, use the 0th font of the fontset. */
2176 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2177 XFontStruct **font_struct_list;
2178 char **font_name_list;
2179 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2180 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2181 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2184 appData.font = FindFont(appData.font, fontPxlSize);
2185 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2186 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2187 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2188 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2189 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2190 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2192 countFontID = coordFontID; // [HGM] holdings
2193 countFontStruct = coordFontStruct;
2195 xdb = XtDatabase(xDisplay);
2197 XrmPutLineResource(&xdb, "*international: True");
2198 vTo.size = sizeof(XFontSet);
2199 vTo.addr = (XtPointer) &fontSet;
2200 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2202 XrmPutStringResource(&xdb, "*font", appData.font);
2206 * Detect if there are not enough colors available and adapt.
2208 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2209 appData.monoMode = True;
2212 forceMono = MakeColors();
2215 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2217 appData.monoMode = True;
2220 if (appData.lowTimeWarning && !appData.monoMode) {
2221 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2222 vFrom.size = strlen(appData.lowTimeWarningColor);
2223 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2224 if (vTo.addr == NULL)
2225 appData.monoMode = True;
2227 lowTimeWarningColor = *(Pixel *) vTo.addr;
2230 if (appData.monoMode && appData.debugMode) {
2231 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2232 (unsigned long) XWhitePixel(xDisplay, xScreen),
2233 (unsigned long) XBlackPixel(xDisplay, xScreen));
2236 ParseIcsTextColors();
2237 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2238 textColors[ColorNone].attr = 0;
2240 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2246 layoutName = "tinyLayout";
2247 } else if (smallLayout) {
2248 layoutName = "smallLayout";
2250 layoutName = "normalLayout";
2252 /* Outer layoutWidget is there only to provide a name for use in
2253 resources that depend on the layout style */
2255 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2256 layoutArgs, XtNumber(layoutArgs));
2258 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2259 formArgs, XtNumber(formArgs));
2260 XtSetArg(args[0], XtNdefaultDistance, &sep);
2261 XtGetValues(formWidget, args, 1);
2264 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar, boardWidth);
2265 XtSetArg(args[0], XtNtop, XtChainTop);
2266 XtSetArg(args[1], XtNbottom, XtChainTop);
2267 XtSetArg(args[2], XtNright, XtChainLeft);
2268 XtSetValues(menuBarWidget, args, 3);
2270 widgetList[j++] = whiteTimerWidget =
2271 XtCreateWidget("whiteTime", labelWidgetClass,
2272 formWidget, timerArgs, XtNumber(timerArgs));
2274 XtSetArg(args[0], XtNfontSet, clockFontSet);
2276 XtSetArg(args[0], XtNfont, clockFontStruct);
2278 XtSetArg(args[1], XtNtop, XtChainTop);
2279 XtSetArg(args[2], XtNbottom, XtChainTop);
2280 XtSetValues(whiteTimerWidget, args, 3);
2282 widgetList[j++] = blackTimerWidget =
2283 XtCreateWidget("blackTime", labelWidgetClass,
2284 formWidget, timerArgs, XtNumber(timerArgs));
2286 XtSetArg(args[0], XtNfontSet, clockFontSet);
2288 XtSetArg(args[0], XtNfont, clockFontStruct);
2290 XtSetArg(args[1], XtNtop, XtChainTop);
2291 XtSetArg(args[2], XtNbottom, XtChainTop);
2292 XtSetValues(blackTimerWidget, args, 3);
2294 if (appData.titleInWindow) {
2295 widgetList[j++] = titleWidget =
2296 XtCreateWidget("title", labelWidgetClass, formWidget,
2297 titleArgs, XtNumber(titleArgs));
2298 XtSetArg(args[0], XtNtop, XtChainTop);
2299 XtSetArg(args[1], XtNbottom, XtChainTop);
2300 XtSetValues(titleWidget, args, 2);
2303 if (appData.showButtonBar) {
2304 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2305 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2306 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2307 XtSetArg(args[2], XtNtop, XtChainTop);
2308 XtSetArg(args[3], XtNbottom, XtChainTop);
2309 XtSetValues(buttonBarWidget, args, 4);
2312 widgetList[j++] = messageWidget =
2313 XtCreateWidget("message", labelWidgetClass, formWidget,
2314 messageArgs, XtNumber(messageArgs));
2315 XtSetArg(args[0], XtNtop, XtChainTop);
2316 XtSetArg(args[1], XtNbottom, XtChainTop);
2317 XtSetValues(messageWidget, args, 2);
2318 XtSetArg(args[0], XtNheight, &textHeight); // [HGM] get height for use in generic popup
2319 XtGetValues(messageWidget, args, 1);
2321 widgetList[j++] = boardWidget =
2322 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2323 XtNumber(boardArgs));
2325 XtManageChildren(widgetList, j);
2327 timerWidth = (boardWidth - sep) / 2;
2328 XtSetArg(args[0], XtNwidth, timerWidth);
2329 XtSetValues(whiteTimerWidget, args, 1);
2330 XtSetValues(blackTimerWidget, args, 1);
2332 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2333 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2334 XtGetValues(whiteTimerWidget, args, 2);
2336 if (appData.showButtonBar) {
2337 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2338 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2339 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2343 * formWidget uses these constraints but they are stored
2347 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2348 XtSetValues(menuBarWidget, args, i);
2349 if (appData.titleInWindow) {
2352 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2353 XtSetValues(whiteTimerWidget, args, i);
2355 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2356 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2357 XtSetValues(blackTimerWidget, args, i);
2359 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2360 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2361 XtSetValues(titleWidget, args, i);
2363 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2364 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2365 XtSetValues(messageWidget, args, i);
2366 if (appData.showButtonBar) {
2368 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2369 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2370 XtSetValues(buttonBarWidget, args, i);
2374 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2375 XtSetValues(whiteTimerWidget, args, i);
2377 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2378 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2379 XtSetValues(blackTimerWidget, args, i);
2381 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2382 XtSetValues(titleWidget, args, i);
2384 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2385 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2386 XtSetValues(messageWidget, args, i);
2387 if (appData.showButtonBar) {
2389 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2390 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2391 XtSetValues(buttonBarWidget, args, i);
2396 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2397 XtSetValues(whiteTimerWidget, args, i);
2399 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2400 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2401 XtSetValues(blackTimerWidget, args, i);
2403 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2404 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2405 XtSetValues(messageWidget, args, i);
2406 if (appData.showButtonBar) {
2408 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2409 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2410 XtSetValues(buttonBarWidget, args, i);
2414 XtSetArg(args[0], XtNfromVert, messageWidget);
2415 XtSetArg(args[1], XtNtop, XtChainTop);
2416 XtSetArg(args[2], XtNbottom, XtChainBottom);
2417 XtSetArg(args[3], XtNleft, XtChainLeft);
2418 XtSetArg(args[4], XtNright, XtChainRight);
2419 XtSetValues(boardWidget, args, 5);
2421 XtRealizeWidget(shellWidget);
2424 XtSetArg(args[0], XtNx, wpMain.x);
2425 XtSetArg(args[1], XtNy, wpMain.y);
2426 XtSetValues(shellWidget, args, 2);
2430 * Correct the width of the message and title widgets.
2431 * It is not known why some systems need the extra fudge term.
2432 * The value "2" is probably larger than needed.
2434 XawFormDoLayout(formWidget, False);
2436 #define WIDTH_FUDGE 2
2438 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2439 XtSetArg(args[i], XtNheight, &h); i++;
2440 XtGetValues(messageWidget, args, i);
2441 if (appData.showButtonBar) {
2443 XtSetArg(args[i], XtNwidth, &w); i++;
2444 XtGetValues(buttonBarWidget, args, i);
2445 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2447 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2450 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2451 if (gres != XtGeometryYes && appData.debugMode) {
2452 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2453 programName, gres, w, h, wr, hr);
2456 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2457 /* The size used for the child widget in layout lags one resize behind
2458 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2460 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2461 if (gres != XtGeometryYes && appData.debugMode) {
2462 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2463 programName, gres, w, h, wr, hr);
2466 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2467 XtSetArg(args[1], XtNright, XtChainRight);
2468 XtSetValues(messageWidget, args, 2);
2470 if (appData.titleInWindow) {
2472 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2473 XtSetArg(args[i], XtNheight, &h); i++;
2474 XtGetValues(titleWidget, args, i);
2476 w = boardWidth - 2*bor;
2478 XtSetArg(args[0], XtNwidth, &w);
2479 XtGetValues(menuBarWidget, args, 1);
2480 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2483 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2484 if (gres != XtGeometryYes && appData.debugMode) {
2486 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2487 programName, gres, w, h, wr, hr);
2490 XawFormDoLayout(formWidget, True);
2492 xBoardWindow = XtWindow(boardWidget);
2494 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2495 // not need to go into InitDrawingSizes().
2499 * Create X checkmark bitmap and initialize option menu checks.
2501 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2502 checkmark_bits, checkmark_width, checkmark_height);
2503 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2504 #ifndef OPTIONSDIALOG
2505 if (appData.alwaysPromoteToQueen) {
2506 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2509 if (appData.animateDragging) {
2510 XtSetValues(XtNameToWidget(menuBarWidget,
2511 "menuOptions.Animate Dragging"),
2514 if (appData.animate) {
2515 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2518 if (appData.autoCallFlag) {
2519 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2522 if (appData.autoFlipView) {
2523 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2526 if (appData.blindfold) {
2527 XtSetValues(XtNameToWidget(menuBarWidget,
2528 "menuOptions.Blindfold"), args, 1);
2530 if (appData.flashCount > 0) {
2531 XtSetValues(XtNameToWidget(menuBarWidget,
2532 "menuOptions.Flash Moves"),
2536 if (appData.highlightDragging) {
2537 XtSetValues(XtNameToWidget(menuBarWidget,
2538 "menuOptions.Highlight Dragging"),
2542 if (appData.highlightLastMove) {
2543 XtSetValues(XtNameToWidget(menuBarWidget,
2544 "menuOptions.Highlight Last Move"),
2547 if (appData.highlightMoveWithArrow) {
2548 XtSetValues(XtNameToWidget(menuBarWidget,
2549 "menuOptions.Arrow"),
2552 // if (appData.icsAlarm) {
2553 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2556 if (appData.ringBellAfterMoves) {
2557 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2560 if (appData.oneClick) {
2561 XtSetValues(XtNameToWidget(menuBarWidget,
2562 "menuOptions.OneClick"), args, 1);
2564 if (appData.periodicUpdates) {
2565 XtSetValues(XtNameToWidget(menuBarWidget,
2566 "menuOptions.Periodic Updates"), args, 1);
2568 if (appData.ponderNextMove) {
2569 XtSetValues(XtNameToWidget(menuBarWidget,
2570 "menuOptions.Ponder Next Move"), args, 1);
2572 if (appData.popupExitMessage) {
2573 XtSetValues(XtNameToWidget(menuBarWidget,
2574 "menuOptions.Popup Exit Message"), args, 1);
2576 if (appData.popupMoveErrors) {
2577 XtSetValues(XtNameToWidget(menuBarWidget,
2578 "menuOptions.Popup Move Errors"), args, 1);
2580 // if (appData.premove) {
2581 // XtSetValues(XtNameToWidget(menuBarWidget,
2582 // "menuOptions.Premove"), args, 1);
2584 if (appData.showCoords) {
2585 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2588 if (appData.hideThinkingFromHuman) {
2589 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2592 if (appData.testLegality) {
2593 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2597 if (saveSettingsOnExit) {
2598 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2605 ReadBitmap(&wIconPixmap, "icon_white.bm",
2606 icon_white_bits, icon_white_width, icon_white_height);
2607 ReadBitmap(&bIconPixmap, "icon_black.bm",
2608 icon_black_bits, icon_black_width, icon_black_height);
2609 iconPixmap = wIconPixmap;
2611 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2612 XtSetValues(shellWidget, args, i);
2615 * Create a cursor for the board widget.
2617 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2618 XChangeWindowAttributes(xDisplay, xBoardWindow,
2619 CWCursor, &window_attributes);
2622 * Inhibit shell resizing.
2624 shellArgs[0].value = (XtArgVal) &w;
2625 shellArgs[1].value = (XtArgVal) &h;
2626 XtGetValues(shellWidget, shellArgs, 2);
2627 shellArgs[4].value = shellArgs[2].value = w;
2628 shellArgs[5].value = shellArgs[3].value = h;
2629 XtSetValues(shellWidget, &shellArgs[2], 4);
2630 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2631 marginH = h - boardHeight;
2633 CatchDeleteWindow(shellWidget, "QuitProc");
2641 if (appData.animate || appData.animateDragging)
2644 XtAugmentTranslations(formWidget,
2645 XtParseTranslationTable(globalTranslations));
2646 XtAugmentTranslations(boardWidget,
2647 XtParseTranslationTable(boardTranslations));
2648 XtAugmentTranslations(whiteTimerWidget,
2649 XtParseTranslationTable(whiteTranslations));
2650 XtAugmentTranslations(blackTimerWidget,
2651 XtParseTranslationTable(blackTranslations));
2653 /* Why is the following needed on some versions of X instead
2654 * of a translation? */
2655 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2656 (XtEventHandler) EventProc, NULL);
2658 XtAddEventHandler(formWidget, KeyPressMask, False,
2659 (XtEventHandler) MoveTypeInProc, NULL);
2661 /* [AS] Restore layout */
2662 if( wpMoveHistory.visible ) {
2666 if( wpEvalGraph.visible )
2671 if( wpEngineOutput.visible ) {
2672 EngineOutputPopUp();
2677 if (errorExitStatus == -1) {
2678 if (appData.icsActive) {
2679 /* We now wait until we see "login:" from the ICS before
2680 sending the logon script (problems with timestamp otherwise) */
2681 /*ICSInitScript();*/
2682 if (appData.icsInputBox) ICSInputBoxPopUp();
2686 signal(SIGWINCH, TermSizeSigHandler);
2688 signal(SIGINT, IntSigHandler);
2689 signal(SIGTERM, IntSigHandler);
2690 if (*appData.cmailGameName != NULLCHAR) {
2691 signal(SIGUSR1, CmailSigHandler);
2694 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2696 // XtSetKeyboardFocus(shellWidget, formWidget);
2697 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2699 XtAppMainLoop(appContext);
2700 if (appData.debugMode) fclose(debugFP); // [DM] debug
2704 static Boolean noEcho;
2709 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2710 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2712 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2713 unlink(gameCopyFilename);
2714 unlink(gamePasteFilename);
2715 if(noEcho) EchoOn();
2719 TermSizeSigHandler (int sig)
2725 IntSigHandler (int sig)
2731 CmailSigHandler (int sig)
2736 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2738 /* Activate call-back function CmailSigHandlerCallBack() */
2739 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2741 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2745 CmailSigHandlerCallBack (InputSourceRef isr, VOIDSTAR closure, char *message, int count, int error)
2748 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2750 /**** end signal code ****/
2756 /* try to open the icsLogon script, either in the location given
2757 * or in the users HOME directory
2764 f = fopen(appData.icsLogon, "r");
2767 homedir = getenv("HOME");
2768 if (homedir != NULL)
2770 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2771 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2772 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2773 f = fopen(buf, "r");
2778 ProcessICSInitScript(f);
2780 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2799 GreyRevert (Boolean grey)
2802 if (!menuBarWidget) return;
2803 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2805 DisplayError("menuEdit.Revert", 0);
2807 XtSetSensitive(w, !grey);
2809 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2811 DisplayError("menuEdit.Annotate", 0);
2813 XtSetSensitive(w, !grey);
2818 SetMenuEnables (Enables *enab)
2821 if (!menuBarWidget) return;
2822 while (enab->name != NULL) {
2823 w = XtNameToWidget(menuBarWidget, enab->name);
2825 DisplayError(enab->name, 0);
2827 XtSetSensitive(w, enab->value);
2833 Enables icsEnables[] = {
2834 { "menuFile.Mail Move", False },
2835 { "menuFile.Reload CMail Message", False },
2836 { "menuMode.Machine Black", False },
2837 { "menuMode.Machine White", False },
2838 { "menuMode.Analysis Mode", False },
2839 { "menuMode.Analyze File", False },
2840 { "menuMode.Two Machines", False },
2841 { "menuMode.Machine Match", False },
2843 { "menuEngine.Hint", False },
2844 { "menuEngine.Book", False },
2845 { "menuEngine.Move Now", False },
2846 #ifndef OPTIONSDIALOG
2847 { "menuOptions.Periodic Updates", False },
2848 { "menuOptions.Hide Thinking", False },
2849 { "menuOptions.Ponder Next Move", False },
2852 { "menuEngine.Engine #1 Settings", False },
2853 { "menuEngine.Engine #2 Settings", False },
2854 { "menuEngine.Load Engine", False },
2855 { "menuEdit.Annotate", False },
2856 { "menuOptions.Match", False },
2860 Enables ncpEnables[] = {
2861 { "menuFile.Mail Move", False },
2862 { "menuFile.Reload CMail Message", False },
2863 { "menuMode.Machine White", False },
2864 { "menuMode.Machine Black", False },
2865 { "menuMode.Analysis Mode", False },
2866 { "menuMode.Analyze File", False },
2867 { "menuMode.Two Machines", False },
2868 { "menuMode.Machine Match", False },
2869 { "menuMode.ICS Client", False },
2870 { "menuView.ICStex", False },
2871 { "menuView.ICS Input Box", False },
2872 { "Action", False },
2873 { "menuEdit.Revert", False },
2874 { "menuEdit.Annotate", False },
2875 { "menuEngine.Engine #1 Settings", False },
2876 { "menuEngine.Engine #2 Settings", False },
2877 { "menuEngine.Move Now", False },
2878 { "menuEngine.Retract Move", False },
2879 { "menuOptions.ICS", False },
2880 #ifndef OPTIONSDIALOG
2881 { "menuOptions.Auto Flag", False },
2882 { "menuOptions.Auto Flip View", False },
2883 // { "menuOptions.ICS Alarm", False },
2884 { "menuOptions.Move Sound", False },
2885 { "menuOptions.Hide Thinking", False },
2886 { "menuOptions.Periodic Updates", False },
2887 { "menuOptions.Ponder Next Move", False },
2889 { "menuEngine.Hint", False },
2890 { "menuEngine.Book", False },
2894 Enables gnuEnables[] = {
2895 { "menuMode.ICS Client", False },
2896 { "menuView.ICStex", False },
2897 { "menuView.ICS Input Box", False },
2898 { "menuAction.Accept", False },
2899 { "menuAction.Decline", False },
2900 { "menuAction.Rematch", False },
2901 { "menuAction.Adjourn", False },
2902 { "menuAction.Stop Examining", False },
2903 { "menuAction.Stop Observing", False },
2904 { "menuAction.Upload to Examine", False },
2905 { "menuEdit.Revert", False },
2906 { "menuEdit.Annotate", False },
2907 { "menuOptions.ICS", False },
2909 /* The next two options rely on SetCmailMode being called *after* */
2910 /* SetGNUMode so that when GNU is being used to give hints these */
2911 /* menu options are still available */
2913 { "menuFile.Mail Move", False },
2914 { "menuFile.Reload CMail Message", False },
2915 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2916 { "menuMode.Machine White", True },
2917 { "menuMode.Machine Black", True },
2918 { "menuMode.Analysis Mode", True },
2919 { "menuMode.Analyze File", True },
2920 { "menuMode.Two Machines", True },
2921 { "menuMode.Machine Match", True },
2922 { "menuEngine.Engine #1 Settings", True },
2923 { "menuEngine.Engine #2 Settings", True },
2924 { "menuEngine.Hint", True },
2925 { "menuEngine.Book", True },
2926 { "menuEngine.Move Now", True },
2927 { "menuEngine.Retract Move", True },
2932 Enables cmailEnables[] = {
2934 { "menuAction.Call Flag", False },
2935 { "menuAction.Draw", True },
2936 { "menuAction.Adjourn", False },
2937 { "menuAction.Abort", False },
2938 { "menuAction.Stop Observing", False },
2939 { "menuAction.Stop Examining", False },
2940 { "menuFile.Mail Move", True },
2941 { "menuFile.Reload CMail Message", True },
2945 Enables trainingOnEnables[] = {
2946 { "menuMode.Edit Comment", False },
2947 { "menuMode.Pause", False },
2948 { "menuEdit.Forward", False },
2949 { "menuEdit.Backward", False },
2950 { "menuEdit.Forward to End", False },
2951 { "menuEdit.Back to Start", False },
2952 { "menuEngine.Move Now", False },
2953 { "menuEdit.Truncate Game", False },
2957 Enables trainingOffEnables[] = {
2958 { "menuMode.Edit Comment", True },
2959 { "menuMode.Pause", True },
2960 { "menuEdit.Forward", True },
2961 { "menuEdit.Backward", True },
2962 { "menuEdit.Forward to End", True },
2963 { "menuEdit.Back to Start", True },
2964 { "menuEngine.Move Now", True },
2965 { "menuEdit.Truncate Game", True },
2969 Enables machineThinkingEnables[] = {
2970 { "menuFile.Load Game", False },
2971 // { "menuFile.Load Next Game", False },
2972 // { "menuFile.Load Previous Game", False },
2973 // { "menuFile.Reload Same Game", False },
2974 { "menuEdit.Paste Game", False },
2975 { "menuFile.Load Position", False },
2976 // { "menuFile.Load Next Position", False },
2977 // { "menuFile.Load Previous Position", False },
2978 // { "menuFile.Reload Same Position", False },
2979 { "menuEdit.Paste Position", False },
2980 { "menuMode.Machine White", False },
2981 { "menuMode.Machine Black", False },
2982 { "menuMode.Two Machines", False },
2983 // { "menuMode.Machine Match", False },
2984 { "menuEngine.Retract Move", False },
2988 Enables userThinkingEnables[] = {
2989 { "menuFile.Load Game", True },
2990 // { "menuFile.Load Next Game", True },
2991 // { "menuFile.Load Previous Game", True },
2992 // { "menuFile.Reload Same Game", True },
2993 { "menuEdit.Paste Game", True },
2994 { "menuFile.Load Position", True },
2995 // { "menuFile.Load Next Position", True },
2996 // { "menuFile.Load Previous Position", True },
2997 // { "menuFile.Reload Same Position", True },
2998 { "menuEdit.Paste Position", True },
2999 { "menuMode.Machine White", True },
3000 { "menuMode.Machine Black", True },
3001 { "menuMode.Two Machines", True },
3002 // { "menuMode.Machine Match", True },
3003 { "menuEngine.Retract Move", True },
3010 SetMenuEnables(icsEnables);
3013 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3014 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3015 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3023 SetMenuEnables(ncpEnables);
3029 SetMenuEnables(gnuEnables);
3035 SetMenuEnables(cmailEnables);
3039 SetTrainingModeOn ()
3041 SetMenuEnables(trainingOnEnables);
3042 if (appData.showButtonBar) {
3043 XtSetSensitive(buttonBarWidget, False);
3049 SetTrainingModeOff ()
3051 SetMenuEnables(trainingOffEnables);
3052 if (appData.showButtonBar) {
3053 XtSetSensitive(buttonBarWidget, True);
3058 SetUserThinkingEnables ()
3060 if (appData.noChessProgram) return;
3061 SetMenuEnables(userThinkingEnables);
3065 SetMachineThinkingEnables ()
3067 if (appData.noChessProgram) return;
3068 SetMenuEnables(machineThinkingEnables);
3070 case MachinePlaysBlack:
3071 case MachinePlaysWhite:
3072 case TwoMachinesPlay:
3073 XtSetSensitive(XtNameToWidget(menuBarWidget,
3074 ModeToWidgetName(gameMode)), True);
3081 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3082 #define HISTORY_SIZE 64
3083 static char *history[HISTORY_SIZE];
3084 int histIn = 0, histP = 0;
3087 SaveInHistory (char *cmd)
3089 if (history[histIn] != NULL) {
3090 free(history[histIn]);
3091 history[histIn] = NULL;
3093 if (*cmd == NULLCHAR) return;
3094 history[histIn] = StrSave(cmd);
3095 histIn = (histIn + 1) % HISTORY_SIZE;
3096 if (history[histIn] != NULL) {
3097 free(history[histIn]);
3098 history[histIn] = NULL;
3104 PrevInHistory (char *cmd)
3107 if (histP == histIn) {
3108 if (history[histIn] != NULL) free(history[histIn]);
3109 history[histIn] = StrSave(cmd);
3111 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3112 if (newhp == histIn || history[newhp] == NULL) return NULL;
3114 return history[histP];
3120 if (histP == histIn) return NULL;
3121 histP = (histP + 1) % HISTORY_SIZE;
3122 return history[histP];
3124 // end of borrowed code
3126 #define Abs(n) ((n)<0 ? -(n) : (n))
3130 InsertPxlSize (char *pattern, int targetPxlSize)
3132 char *base_fnt_lst, strInt[12], *p, *q;
3133 int alternatives, i, len, strIntLen;
3136 * Replace the "*" (if present) in the pixel-size slot of each
3137 * alternative with the targetPxlSize.
3141 while ((p = strchr(p, ',')) != NULL) {
3145 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3146 strIntLen = strlen(strInt);
3147 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3151 while (alternatives--) {
3152 char *comma = strchr(p, ',');
3153 for (i=0; i<14; i++) {
3154 char *hyphen = strchr(p, '-');
3156 if (comma && hyphen > comma) break;
3157 len = hyphen + 1 - p;
3158 if (i == 7 && *p == '*' && len == 2) {
3160 memcpy(q, strInt, strIntLen);
3170 len = comma + 1 - p;
3177 return base_fnt_lst;
3181 CreateFontSet (char *base_fnt_lst)
3184 char **missing_list;
3188 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3189 &missing_list, &missing_count, &def_string);
3190 if (appData.debugMode) {
3192 XFontStruct **font_struct_list;
3193 char **font_name_list;
3194 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3196 fprintf(debugFP, " got list %s, locale %s\n",
3197 XBaseFontNameListOfFontSet(fntSet),
3198 XLocaleOfFontSet(fntSet));
3199 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3200 for (i = 0; i < count; i++) {
3201 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3204 for (i = 0; i < missing_count; i++) {
3205 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3208 if (fntSet == NULL) {
3209 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3214 #else // not ENABLE_NLS
3216 * Find a font that matches "pattern" that is as close as
3217 * possible to the targetPxlSize. Prefer fonts that are k
3218 * pixels smaller to fonts that are k pixels larger. The
3219 * pattern must be in the X Consortium standard format,
3220 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3221 * The return value should be freed with XtFree when no
3225 FindFont (char *pattern, int targetPxlSize)
3227 char **fonts, *p, *best, *scalable, *scalableTail;
3228 int i, j, nfonts, minerr, err, pxlSize;
3230 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3232 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3233 programName, pattern);
3240 for (i=0; i<nfonts; i++) {
3243 if (*p != '-') continue;
3245 if (*p == NULLCHAR) break;
3246 if (*p++ == '-') j++;
3248 if (j < 7) continue;
3251 scalable = fonts[i];
3254 err = pxlSize - targetPxlSize;
3255 if (Abs(err) < Abs(minerr) ||
3256 (minerr > 0 && err < 0 && -err == minerr)) {
3262 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3263 /* If the error is too big and there is a scalable font,
3264 use the scalable font. */
3265 int headlen = scalableTail - scalable;
3266 p = (char *) XtMalloc(strlen(scalable) + 10);
3267 while (isdigit(*scalableTail)) scalableTail++;
3268 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3270 p = (char *) XtMalloc(strlen(best) + 2);
3271 safeStrCpy(p, best, strlen(best)+1 );
3273 if (appData.debugMode) {
3274 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3275 pattern, targetPxlSize, p);
3277 XFreeFontNames(fonts);
3284 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3285 // must be called before all non-first callse to CreateGCs()
3286 XtReleaseGC(shellWidget, highlineGC);
3287 XtReleaseGC(shellWidget, lightSquareGC);
3288 XtReleaseGC(shellWidget, darkSquareGC);
3289 XtReleaseGC(shellWidget, lineGC);
3290 if (appData.monoMode) {
3291 if (DefaultDepth(xDisplay, xScreen) == 1) {
3292 XtReleaseGC(shellWidget, wbPieceGC);
3294 XtReleaseGC(shellWidget, bwPieceGC);
3297 XtReleaseGC(shellWidget, prelineGC);
3298 XtReleaseGC(shellWidget, jailSquareGC);
3299 XtReleaseGC(shellWidget, wdPieceGC);
3300 XtReleaseGC(shellWidget, wlPieceGC);
3301 XtReleaseGC(shellWidget, wjPieceGC);
3302 XtReleaseGC(shellWidget, bdPieceGC);
3303 XtReleaseGC(shellWidget, blPieceGC);
3304 XtReleaseGC(shellWidget, bjPieceGC);
3309 CreateGCs (int redo)
3311 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3312 | GCBackground | GCFunction | GCPlaneMask;
3313 XGCValues gc_values;
3316 gc_values.plane_mask = AllPlanes;
3317 gc_values.line_width = lineGap;
3318 gc_values.line_style = LineSolid;
3319 gc_values.function = GXcopy;
3322 DeleteGCs(); // called a second time; clean up old GCs first
3323 } else { // [HGM] grid and font GCs created on first call only
3324 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3325 gc_values.background = XWhitePixel(xDisplay, xScreen);
3326 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3327 XSetFont(xDisplay, coordGC, coordFontID);
3329 // [HGM] make font for holdings counts (white on black)
3330 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3331 gc_values.background = XBlackPixel(xDisplay, xScreen);
3332 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3333 XSetFont(xDisplay, countGC, countFontID);
3335 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3336 gc_values.background = XBlackPixel(xDisplay, xScreen);
3337 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3339 if (appData.monoMode) {
3340 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3341 gc_values.background = XWhitePixel(xDisplay, xScreen);
3342 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3344 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3345 gc_values.background = XBlackPixel(xDisplay, xScreen);
3346 lightSquareGC = wbPieceGC
3347 = XtGetGC(shellWidget, value_mask, &gc_values);
3349 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3350 gc_values.background = XWhitePixel(xDisplay, xScreen);
3351 darkSquareGC = bwPieceGC
3352 = XtGetGC(shellWidget, value_mask, &gc_values);
3354 if (DefaultDepth(xDisplay, xScreen) == 1) {
3355 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3356 gc_values.function = GXcopyInverted;
3357 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3358 gc_values.function = GXcopy;
3359 if (XBlackPixel(xDisplay, xScreen) == 1) {
3360 bwPieceGC = darkSquareGC;
3361 wbPieceGC = copyInvertedGC;
3363 bwPieceGC = copyInvertedGC;
3364 wbPieceGC = lightSquareGC;
3368 gc_values.foreground = highlightSquareColor;
3369 gc_values.background = highlightSquareColor;
3370 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3372 gc_values.foreground = premoveHighlightColor;
3373 gc_values.background = premoveHighlightColor;
3374 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3376 gc_values.foreground = lightSquareColor;
3377 gc_values.background = darkSquareColor;
3378 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380 gc_values.foreground = darkSquareColor;
3381 gc_values.background = lightSquareColor;
3382 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3384 gc_values.foreground = jailSquareColor;
3385 gc_values.background = jailSquareColor;
3386 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3388 gc_values.foreground = whitePieceColor;
3389 gc_values.background = darkSquareColor;
3390 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3392 gc_values.foreground = whitePieceColor;
3393 gc_values.background = lightSquareColor;
3394 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3396 gc_values.foreground = whitePieceColor;
3397 gc_values.background = jailSquareColor;
3398 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3400 gc_values.foreground = blackPieceColor;
3401 gc_values.background = darkSquareColor;
3402 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3404 gc_values.foreground = blackPieceColor;
3405 gc_values.background = lightSquareColor;
3406 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3408 gc_values.foreground = blackPieceColor;
3409 gc_values.background = jailSquareColor;
3410 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3415 loadXIM (XImage *xim, XImage *xmask, char *filename, Pixmap *dest, Pixmap *mask)
3423 fp = fopen(filename, "rb");
3425 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3432 for (y=0; y<h; ++y) {
3433 for (x=0; x<h; ++x) {
3438 XPutPixel(xim, x, y, blackPieceColor);
3440 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3443 XPutPixel(xim, x, y, darkSquareColor);
3445 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3448 XPutPixel(xim, x, y, whitePieceColor);
3450 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3453 XPutPixel(xim, x, y, lightSquareColor);
3455 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3463 /* create Pixmap of piece */
3464 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3466 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3469 /* create Pixmap of clipmask
3470 Note: We assume the white/black pieces have the same
3471 outline, so we make only 6 masks. This is okay
3472 since the XPM clipmask routines do the same. */
3474 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3476 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3479 /* now create the 1-bit version */
3480 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3483 values.foreground = 1;
3484 values.background = 0;
3486 /* Don't use XtGetGC, not read only */
3487 maskGC = XCreateGC(xDisplay, *mask,
3488 GCForeground | GCBackground, &values);
3489 XCopyPlane(xDisplay, temp, *mask, maskGC,
3490 0, 0, squareSize, squareSize, 0, 0, 1);
3491 XFreePixmap(xDisplay, temp);
3496 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3504 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3509 /* The XSynchronize calls were copied from CreatePieces.
3510 Not sure if needed, but can't hurt */
3511 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3514 /* temp needed by loadXIM() */
3515 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3516 0, 0, ss, ss, AllPlanes, XYPixmap);
3518 if (strlen(appData.pixmapDirectory) == 0) {
3522 if (appData.monoMode) {
3523 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3527 fprintf(stderr, _("\nLoading XIMs...\n"));
3529 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3530 fprintf(stderr, "%d", piece+1);
3531 for (kind=0; kind<4; kind++) {
3532 fprintf(stderr, ".");
3533 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3534 ExpandPathName(appData.pixmapDirectory),
3535 piece <= (int) WhiteKing ? "" : "w",
3536 pieceBitmapNames[piece],
3538 ximPieceBitmap[kind][piece] =
3539 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3540 0, 0, ss, ss, AllPlanes, XYPixmap);
3541 if (appData.debugMode)
3542 fprintf(stderr, _("(File:%s:) "), buf);
3543 loadXIM(ximPieceBitmap[kind][piece],
3545 &(xpmPieceBitmap2[kind][piece]),
3546 &(ximMaskPm2[piece]));
3547 if(piece <= (int)WhiteKing)
3548 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3550 fprintf(stderr," ");
3552 /* Load light and dark squares */
3553 /* If the LSQ and DSQ pieces don't exist, we will
3554 draw them with solid squares. */
3555 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3556 if (access(buf, 0) != 0) {
3560 fprintf(stderr, _("light square "));
3562 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3563 0, 0, ss, ss, AllPlanes, XYPixmap);
3564 if (appData.debugMode)
3565 fprintf(stderr, _("(File:%s:) "), buf);
3567 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3568 fprintf(stderr, _("dark square "));
3569 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3570 ExpandPathName(appData.pixmapDirectory), ss);
3571 if (appData.debugMode)
3572 fprintf(stderr, _("(File:%s:) "), buf);
3574 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3575 0, 0, ss, ss, AllPlanes, XYPixmap);
3576 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3577 xpmJailSquare = xpmLightSquare;
3579 fprintf(stderr, _("Done.\n"));
3581 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3584 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3588 CreateXPMBoard (char *s, int kind)
3592 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3593 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3594 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3600 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3601 // thisroutine has to be called t free the old piece pixmaps
3603 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3604 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3606 XFreePixmap(xDisplay, xpmLightSquare);
3607 XFreePixmap(xDisplay, xpmDarkSquare);
3616 u_int ss = squareSize;
3618 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3619 XpmColorSymbol symbols[4];
3620 static int redo = False;
3622 if(redo) FreeXPMPieces(); else redo = 1;
3624 /* The XSynchronize calls were copied from CreatePieces.
3625 Not sure if needed, but can't hurt */
3626 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3628 /* Setup translations so piece colors match square colors */
3629 symbols[0].name = "light_piece";
3630 symbols[0].value = appData.whitePieceColor;
3631 symbols[1].name = "dark_piece";
3632 symbols[1].value = appData.blackPieceColor;
3633 symbols[2].name = "light_square";
3634 symbols[2].value = appData.lightSquareColor;
3635 symbols[3].name = "dark_square";
3636 symbols[3].value = appData.darkSquareColor;
3638 attr.valuemask = XpmColorSymbols;
3639 attr.colorsymbols = symbols;
3640 attr.numsymbols = 4;
3642 if (appData.monoMode) {
3643 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3647 if (strlen(appData.pixmapDirectory) == 0) {
3648 XpmPieces* pieces = builtInXpms;
3651 while (pieces->size != squareSize && pieces->size) pieces++;
3652 if (!pieces->size) {
3653 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3656 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3657 for (kind=0; kind<4; kind++) {
3659 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3660 pieces->xpm[piece][kind],
3661 &(xpmPieceBitmap2[kind][piece]),
3662 NULL, &attr)) != 0) {
3663 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3667 if(piece <= (int) WhiteKing)
3668 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3672 xpmJailSquare = xpmLightSquare;
3676 fprintf(stderr, _("\nLoading XPMs...\n"));
3679 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3680 fprintf(stderr, "%d ", piece+1);
3681 for (kind=0; kind<4; kind++) {
3682 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3683 ExpandPathName(appData.pixmapDirectory),
3684 piece > (int) WhiteKing ? "w" : "",
3685 pieceBitmapNames[piece],
3687 if (appData.debugMode) {
3688 fprintf(stderr, _("(File:%s:) "), buf);
3690 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3691 &(xpmPieceBitmap2[kind][piece]),
3692 NULL, &attr)) != 0) {
3693 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3694 // [HGM] missing: read of unorthodox piece failed; substitute King.
3695 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3696 ExpandPathName(appData.pixmapDirectory),
3698 if (appData.debugMode) {
3699 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3701 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3702 &(xpmPieceBitmap2[kind][piece]),
3706 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3711 if(piece <= (int) WhiteKing)
3712 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3715 /* Load light and dark squares */
3716 /* If the LSQ and DSQ pieces don't exist, we will
3717 draw them with solid squares. */
3718 fprintf(stderr, _("light square "));
3719 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3720 if (access(buf, 0) != 0) {
3724 if (appData.debugMode)
3725 fprintf(stderr, _("(File:%s:) "), buf);
3727 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3728 &xpmLightSquare, NULL, &attr)) != 0) {
3729 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3732 fprintf(stderr, _("dark square "));
3733 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3734 ExpandPathName(appData.pixmapDirectory), ss);
3735 if (appData.debugMode) {
3736 fprintf(stderr, _("(File:%s:) "), buf);
3738 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3739 &xpmDarkSquare, NULL, &attr)) != 0) {
3740 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3744 xpmJailSquare = xpmLightSquare;
3745 fprintf(stderr, _("Done.\n"));
3747 oldVariant = -1; // kludge to force re-makig of animation masks
3748 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3751 #endif /* HAVE_LIBXPM */
3754 /* No built-in bitmaps */
3759 u_int ss = squareSize;
3761 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3764 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3765 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3766 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3767 pieceBitmapNames[piece],
3768 ss, kind == SOLID ? 's' : 'o');
3769 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3770 if(piece <= (int)WhiteKing)
3771 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3775 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3779 /* With built-in bitmaps */
3783 BuiltInBits* bib = builtInBits;
3786 u_int ss = squareSize;
3788 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3791 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3793 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3794 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3795 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3796 pieceBitmapNames[piece],
3797 ss, kind == SOLID ? 's' : 'o');
3798 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3799 bib->bits[kind][piece], ss, ss);
3800 if(piece <= (int)WhiteKing)
3801 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3805 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3811 ReadBitmap (Pixmap *pm, String name, unsigned char bits[], u_int wreq, u_int hreq)
3816 char msg[MSG_SIZ], fullname[MSG_SIZ];
3818 if (*appData.bitmapDirectory != NULLCHAR) {
3819 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3820 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3821 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3822 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3823 &w, &h, pm, &x_hot, &y_hot);
3824 fprintf(stderr, "load %s\n", name);
3825 if (errcode != BitmapSuccess) {
3827 case BitmapOpenFailed:
3828 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3830 case BitmapFileInvalid:
3831 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3833 case BitmapNoMemory:
3834 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3838 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3842 fprintf(stderr, _("%s: %s...using built-in\n"),
3844 } else if (w != wreq || h != hreq) {
3846 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3847 programName, fullname, w, h, wreq, hreq);
3853 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3863 if (lineGap == 0) return;
3865 /* [HR] Split this into 2 loops for non-square boards. */
3867 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3868 gridSegments[i].x1 = 0;
3869 gridSegments[i].x2 =
3870 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3871 gridSegments[i].y1 = gridSegments[i].y2
3872 = lineGap / 2 + (i * (squareSize + lineGap));
3875 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3876 gridSegments[j + i].y1 = 0;
3877 gridSegments[j + i].y2 =
3878 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3879 gridSegments[j + i].x1 = gridSegments[j + i].x2
3880 = lineGap / 2 + (j * (squareSize + lineGap));
3885 MenuBarSelect (Widget w, caddr_t addr, caddr_t index)
3887 XtActionProc proc = (XtActionProc) addr;
3889 (proc)(NULL, NULL, NULL, NULL);
3893 CreateMenuBarPopup (Widget parent, String name, Menu *mb)
3900 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3903 XtSetArg(args[j], XtNleftMargin, 20); j++;
3904 XtSetArg(args[j], XtNrightMargin, 20); j++;
3906 while (mi->string != NULL) {
3907 if (strcmp(mi->string, "----") == 0) {
3908 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3911 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3912 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3914 XtAddCallback(entry, XtNcallback,
3915 (XtCallbackProc) MenuBarSelect,
3916 (caddr_t) mi->proc);
3923 CreateMenuBar (Menu *mb, int boardWidth)
3925 int i, j, nr = 0, wtot = 0, widths[10];
3928 char menuName[MSG_SIZ];
3933 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3934 XtSetArg(args[j], XtNvSpace, 0); j++;
3935 XtSetArg(args[j], XtNborderWidth, 0); j++;
3936 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3937 formWidget, args, j);
3939 while (mb->name != NULL) {
3940 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3941 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3943 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3944 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3945 XtSetArg(args[j], XtNborderWidth, 0); j++;
3946 mb->subMenu = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3948 CreateMenuBarPopup(menuBar, menuName, mb);
3950 XtSetArg(args[j], XtNwidth, &w); j++;
3951 XtGetValues(mb->subMenu, args, j);
3952 wtot += mb->textWidth = widths[nr++] = w;
3955 while(wtot > boardWidth - 40) {
3957 for(i=0; i<nr; i++) if(widths[i] > wmax) wmax = widths[imax=i];
3961 for(i=0; i<nr; i++) if(widths[i] != ma[i].textWidth) {
3963 XtSetArg(args[j], XtNwidth, widths[i]); j++;
3964 XtSetValues(ma[i].subMenu, args, j);
3970 CreateButtonBar (MenuItem *mi)
3973 Widget button, buttonBar;
3977 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3979 XtSetArg(args[j], XtNhSpace, 0); j++;
3981 XtSetArg(args[j], XtNborderWidth, 0); j++;
3982 XtSetArg(args[j], XtNvSpace, 0); j++;
3983 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3984 formWidget, args, j);
3986 while (mi->string != NULL) {
3989 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3990 XtSetArg(args[j], XtNborderWidth, 0); j++;
3992 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3993 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3994 buttonBar, args, j);
3995 XtAddCallback(button, XtNcallback,
3996 (XtCallbackProc) MenuBarSelect,
3997 (caddr_t) mi->proc);
4004 CreatePieceMenu (char *name, int color)
4009 ChessSquare selection;
4011 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4012 boardWidget, args, 0);
4014 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4015 String item = pieceMenuStrings[color][i];
4017 if (strcmp(item, "----") == 0) {
4018 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4021 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4022 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4024 selection = pieceMenuTranslation[color][i];
4025 XtAddCallback(entry, XtNcallback,
4026 (XtCallbackProc) PieceMenuSelect,
4027 (caddr_t) selection);
4028 if (selection == WhitePawn || selection == BlackPawn) {
4029 XtSetArg(args[0], XtNpopupOnEntry, entry);
4030 XtSetValues(menu, args, 1);
4043 ChessSquare selection;
4045 whitePieceMenu = CreatePieceMenu("menuW", 0);
4046 blackPieceMenu = CreatePieceMenu("menuB", 1);
4048 XtRegisterGrabAction(PieceMenuPopup, True,
4049 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4050 GrabModeAsync, GrabModeAsync);
4052 XtSetArg(args[0], XtNlabel, _("Drop"));
4053 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4054 boardWidget, args, 1);
4055 for (i = 0; i < DROP_MENU_SIZE; i++) {
4056 String item = dropMenuStrings[i];
4058 if (strcmp(item, "----") == 0) {
4059 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4062 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4063 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4065 selection = dropMenuTranslation[i];
4066 XtAddCallback(entry, XtNcallback,
4067 (XtCallbackProc) DropMenuSelect,
4068 (caddr_t) selection);
4082 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4083 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4084 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4085 dmEnables[i].piece);
4086 XtSetSensitive(entry, p != NULL || !appData.testLegality
4087 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4088 && !appData.icsActive));
4090 while (p && *p++ == dmEnables[i].piece) count++;
4091 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4093 XtSetArg(args[j], XtNlabel, label); j++;
4094 XtSetValues(entry, args, j);
4099 PieceMenuPopup (Widget w, XEvent *event, String *params, Cardinal *num_params)
4101 String whichMenu; int menuNr = -2;
4102 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4103 if (event->type == ButtonRelease)
4104 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4105 else if (event->type == ButtonPress)
4106 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4108 case 0: whichMenu = params[0]; break;
4109 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4111 case -1: if (errorUp) ErrorPopDown();
4114 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4118 PieceMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4120 if (pmFromX < 0 || pmFromY < 0) return;
4121 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4125 DropMenuSelect (Widget w, ChessSquare piece, caddr_t junk)
4127 if (pmFromX < 0 || pmFromY < 0) return;
4128 DropMenuEvent(piece, pmFromX, pmFromY);
4132 WhiteClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4134 shiftKey = prms[0][0] & 1;
4139 BlackClock (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4141 shiftKey = prms[0][0] & 1;
4147 * If the user selects on a border boundary, return -1; if off the board,
4148 * return -2. Otherwise map the event coordinate to the square.
4151 EventToSquare (int x, int limit)
4158 if ((x % (squareSize + lineGap)) >= squareSize)
4160 x /= (squareSize + lineGap);
4167 do_flash_delay (unsigned long msec)
4173 drawHighlight (int file, int rank, GC gc)
4177 if (lineGap == 0) return;
4180 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4181 (squareSize + lineGap);
4182 y = lineGap/2 + rank * (squareSize + lineGap);
4184 x = lineGap/2 + file * (squareSize + lineGap);
4185 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4186 (squareSize + lineGap);
4189 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4190 squareSize+lineGap, squareSize+lineGap);
4193 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4194 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4197 SetHighlights (int fromX, int fromY, int toX, int toY)
4199 if (hi1X != fromX || hi1Y != fromY) {
4200 if (hi1X >= 0 && hi1Y >= 0) {
4201 drawHighlight(hi1X, hi1Y, lineGC);
4203 } // [HGM] first erase both, then draw new!
4204 if (hi2X != toX || hi2Y != toY) {
4205 if (hi2X >= 0 && hi2Y >= 0) {
4206 drawHighlight(hi2X, hi2Y, lineGC);
4209 if (hi1X != fromX || hi1Y != fromY) {
4210 if (fromX >= 0 && fromY >= 0) {
4211 drawHighlight(fromX, fromY, highlineGC);
4214 if (hi2X != toX || hi2Y != toY) {
4215 if (toX >= 0 && toY >= 0) {
4216 drawHighlight(toX, toY, highlineGC);
4219 if(toX<0) // clearing the highlights must have damaged arrow
4220 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); // for now, redraw it (should really be cleared!)
4230 SetHighlights(-1, -1, -1, -1);
4235 SetPremoveHighlights (int fromX, int fromY, int toX, int toY)
4237 if (pm1X != fromX || pm1Y != fromY) {
4238 if (pm1X >= 0 && pm1Y >= 0) {
4239 drawHighlight(pm1X, pm1Y, lineGC);
4241 if (fromX >= 0 && fromY >= 0) {
4242 drawHighlight(fromX, fromY, prelineGC);
4245 if (pm2X != toX || pm2Y != toY) {
4246 if (pm2X >= 0 && pm2Y >= 0) {
4247 drawHighlight(pm2X, pm2Y, lineGC);
4249 if (toX >= 0 && toY >= 0) {
4250 drawHighlight(toX, toY, prelineGC);
4260 ClearPremoveHighlights ()
4262 SetPremoveHighlights(-1, -1, -1, -1);
4266 CutOutSquare (int x, int y, int *x0, int *y0, int kind)
4268 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4269 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4271 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4272 if(textureW[kind] < W*squareSize)
4273 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4275 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4276 if(textureH[kind] < H*squareSize)
4277 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4279 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4284 BlankSquare (int x, int y, int color, ChessSquare piece, Drawable dest, int fac)
4285 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4287 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4288 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4289 squareSize, squareSize, x*fac, y*fac);
4291 if (useImages && useImageSqs) {
4295 pm = xpmLightSquare;
4300 case 2: /* neutral */
4305 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4306 squareSize, squareSize, x*fac, y*fac);
4316 case 2: /* neutral */
4321 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4326 I split out the routines to draw a piece so that I could
4327 make a generic flash routine.
4330 monoDrawPiece_1bit (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4332 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4333 switch (square_color) {
4335 case 2: /* neutral */
4337 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4338 ? *pieceToOutline(piece)
4339 : *pieceToSolid(piece),
4340 dest, bwPieceGC, 0, 0,
4341 squareSize, squareSize, x, y);
4344 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4345 ? *pieceToSolid(piece)
4346 : *pieceToOutline(piece),
4347 dest, wbPieceGC, 0, 0,
4348 squareSize, squareSize, x, y);
4354 monoDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4356 switch (square_color) {
4358 case 2: /* neutral */
4360 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4361 ? *pieceToOutline(piece)
4362 : *pieceToSolid(piece),
4363 dest, bwPieceGC, 0, 0,
4364 squareSize, squareSize, x, y, 1);
4367 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4368 ? *pieceToSolid(piece)
4369 : *pieceToOutline(piece),
4370 dest, wbPieceGC, 0, 0,
4371 squareSize, squareSize, x, y, 1);
4377 colorDrawPiece (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4379 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4380 switch (square_color) {
4382 XCopyPlane(xDisplay, *pieceToSolid(piece),
4383 dest, (int) piece < (int) BlackPawn
4384 ? wlPieceGC : blPieceGC, 0, 0,
4385 squareSize, squareSize, x, y, 1);
4388 XCopyPlane(xDisplay, *pieceToSolid(piece),
4389 dest, (int) piece < (int) BlackPawn
4390 ? wdPieceGC : bdPieceGC, 0, 0,
4391 squareSize, squareSize, x, y, 1);
4393 case 2: /* neutral */
4395 XCopyPlane(xDisplay, *pieceToSolid(piece),
4396 dest, (int) piece < (int) BlackPawn
4397 ? wjPieceGC : bjPieceGC, 0, 0,
4398 squareSize, squareSize, x, y, 1);
4404 colorDrawPieceImage (ChessSquare piece, int square_color, int x, int y, Drawable dest)
4406 int kind, p = piece;
4408 switch (square_color) {
4410 case 2: /* neutral */
4412 if ((int)piece < (int) BlackPawn) {
4420 if ((int)piece < (int) BlackPawn) {
4428 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4429 if(useTexture & square_color+1) {
4430 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4431 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4432 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4433 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4434 XSetClipMask(xDisplay, wlPieceGC, None);
4435 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4437 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4438 dest, wlPieceGC, 0, 0,
4439 squareSize, squareSize, x, y);
4442 typedef void (*DrawFunc)();
4447 if (appData.monoMode) {
4448 if (DefaultDepth(xDisplay, xScreen) == 1) {
4449 return monoDrawPiece_1bit;
4451 return monoDrawPiece;
4455 return colorDrawPieceImage;
4457 return colorDrawPiece;
4461 /* [HR] determine square color depending on chess variant. */
4463 SquareColor (int row, int column)
4467 if (gameInfo.variant == VariantXiangqi) {
4468 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4470 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4472 } else if (row <= 4) {
4478 square_color = ((column + row) % 2) == 1;
4481 /* [hgm] holdings: next line makes all holdings squares light */
4482 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4484 return square_color;
4488 DrawSquare (int row, int column, ChessSquare piece, int do_flash)
4490 int square_color, x, y, direction, font_ascent, font_descent;
4493 XCharStruct overall;
4497 /* Calculate delay in milliseconds (2-delays per complete flash) */
4498 flash_delay = 500 / appData.flashRate;
4501 x = lineGap + ((BOARD_WIDTH-1)-column) *
4502 (squareSize + lineGap);
4503 y = lineGap + row * (squareSize + lineGap);
4505 x = lineGap + column * (squareSize + lineGap);
4506 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4507 (squareSize + lineGap);
4510 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4512 square_color = SquareColor(row, column);
4514 if ( // [HGM] holdings: blank out area between board and holdings
4515 column == BOARD_LEFT-1 || column == BOARD_RGHT
4516 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4517 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4518 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4520 // [HGM] print piece counts next to holdings
4521 string[1] = NULLCHAR;
4522 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4523 string[0] = '0' + piece;
4524 XTextExtents(countFontStruct, string, 1, &direction,
4525 &font_ascent, &font_descent, &overall);
4526 if (appData.monoMode) {
4527 XDrawImageString(xDisplay, xBoardWindow, countGC,
4528 x + squareSize - overall.width - 2,
4529 y + font_ascent + 1, string, 1);
4531 XDrawString(xDisplay, xBoardWindow, countGC,
4532 x + squareSize - overall.width - 2,
4533 y + font_ascent + 1, string, 1);
4536 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4537 string[0] = '0' + piece;
4538 XTextExtents(countFontStruct, string, 1, &direction,
4539 &font_ascent, &font_descent, &overall);
4540 if (appData.monoMode) {
4541 XDrawImageString(xDisplay, xBoardWindow, countGC,
4542 x + 2, y + font_ascent + 1, string, 1);
4544 XDrawString(xDisplay, xBoardWindow, countGC,
4545 x + 2, y + font_ascent + 1, string, 1);
4549 if (piece == EmptySquare || appData.blindfold) {
4550 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4552 drawfunc = ChooseDrawFunc();
4554 if (do_flash && appData.flashCount > 0) {
4555 for (i=0; i<appData.flashCount; ++i) {
4556 drawfunc(piece, square_color, x, y, xBoardWindow);
4557 XSync(xDisplay, False);
4558 do_flash_delay(flash_delay);
4560 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4561 XSync(xDisplay, False);
4562 do_flash_delay(flash_delay);
4565 drawfunc(piece, square_color, x, y, xBoardWindow);
4569 string[1] = NULLCHAR;
4570 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4571 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4572 string[0] = 'a' + column - BOARD_LEFT;
4573 XTextExtents(coordFontStruct, string, 1, &direction,
4574 &font_ascent, &font_descent, &overall);
4575 if (appData.monoMode) {
4576 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4577 x + squareSize - overall.width - 2,
4578 y + squareSize - font_descent - 1, string, 1);
4580 XDrawString(xDisplay, xBoardWindow, coordGC,
4581 x + squareSize - overall.width - 2,
4582 y + squareSize - font_descent - 1, string, 1);
4585 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4586 string[0] = ONE + row;
4587 XTextExtents(coordFontStruct, string, 1, &direction,
4588 &font_ascent, &font_descent, &overall);
4589 if (appData.monoMode) {
4590 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4591 x + 2, y + font_ascent + 1, string, 1);
4593 XDrawString(xDisplay, xBoardWindow, coordGC,
4594 x + 2, y + font_ascent + 1, string, 1);
4597 if(!partnerUp && marker[row][column]) {
4598 if(appData.monoMode) {
4599 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? darkSquareGC : lightSquareGC,
4600 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4601 XDrawArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? lightSquareGC : darkSquareGC,
4602 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4604 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4605 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4610 /* Why is this needed on some versions of X? */
4612 EventProc (Widget widget, caddr_t unused, XEvent *event)
4614 if (!XtIsRealized(widget))
4617 switch (event->type) {
4619 if (event->xexpose.count > 0) return; /* no clipping is done */
4620 XDrawPosition(widget, True, NULL);
4621 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4622 flipView = !flipView; partnerUp = !partnerUp;
4623 XDrawPosition(widget, True, NULL);
4624 flipView = !flipView; partnerUp = !partnerUp;
4628 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4636 DrawPosition (int fullRedraw, Board board)
4638 XDrawPosition(boardWidget, fullRedraw, board);
4641 /* Returns 1 if there are "too many" differences between b1 and b2
4642 (i.e. more than 1 move was made) */
4644 too_many_diffs (Board b1, Board b2)
4649 for (i=0; i<BOARD_HEIGHT; ++i) {
4650 for (j=0; j<BOARD_WIDTH; ++j) {
4651 if (b1[i][j] != b2[i][j]) {
4652 if (++c > 4) /* Castling causes 4 diffs */
4660 /* Matrix describing castling maneuvers */
4661 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4662 static int castling_matrix[4][5] = {
4663 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4664 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4665 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4666 { 7, 7, 4, 5, 6 } /* 0-0, black */
4669 /* Checks whether castling occurred. If it did, *rrow and *rcol
4670 are set to the destination (row,col) of the rook that moved.
4672 Returns 1 if castling occurred, 0 if not.
4674 Note: Only handles a max of 1 castling move, so be sure
4675 to call too_many_diffs() first.
4678 check_castle_draw (Board newb, Board oldb, int *rrow, int *rcol)
4683 /* For each type of castling... */
4684 for (i=0; i<4; ++i) {
4685 r = castling_matrix[i];
4687 /* Check the 4 squares involved in the castling move */
4689 for (j=1; j<=4; ++j) {
4690 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4697 /* All 4 changed, so it must be a castling move */
4706 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4708 DrawSeekAxis (int x, int y, int xTo, int yTo)
4710 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4714 DrawSeekBackground (int left, int top, int right, int bottom)
4716 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4720 DrawSeekText (char *buf, int x, int y)
4722 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4726 DrawSeekDot (int x, int y, int colorNr)
4728 int square = colorNr & 0x80;
4731 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4733 XFillRectangle(xDisplay, xBoardWindow, color,
4734 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4736 XFillArc(xDisplay, xBoardWindow, color,
4737 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4740 static int damage[2][BOARD_RANKS][BOARD_FILES];
4743 * event handler for redrawing the board
4746 XDrawPosition (Widget w, int repaint, Board board)
4749 static int lastFlipView = 0;
4750 static int lastBoardValid[2] = {0, 0};
4751 static Board lastBoard[2];
4754 int nr = twoBoards*partnerUp;
4756 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4758 if (board == NULL) {
4759 if (!lastBoardValid[nr]) return;
4760 board = lastBoard[nr];
4762 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4763 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4764 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4769 * It would be simpler to clear the window with XClearWindow()
4770 * but this causes a very distracting flicker.
4773 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4775 if ( lineGap && IsDrawArrowEnabled())
4776 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4777 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4779 /* If too much changes (begin observing new game, etc.), don't
4781 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4783 /* Special check for castling so we don't flash both the king
4784 and the rook (just flash the king). */
4786 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4787 /* Draw rook with NO flashing. King will be drawn flashing later */
4788 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4789 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4793 /* First pass -- Draw (newly) empty squares and repair damage.
4794 This prevents you from having a piece show up twice while it
4795 is flashing on its new square */
4796 for (i = 0; i < BOARD_HEIGHT; i++)
4797 for (j = 0; j < BOARD_WIDTH; j++)
4798 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4799 || damage[nr][i][j]) {
4800 DrawSquare(i, j, board[i][j], 0);
4801 damage[nr][i][j] = False;
4804 /* Second pass -- Draw piece(s) in new position and flash them */
4805 for (i = 0; i < BOARD_HEIGHT; i++)
4806 for (j = 0; j < BOARD_WIDTH; j++)
4807 if (board[i][j] != lastBoard[nr][i][j]) {
4808 DrawSquare(i, j, board[i][j], do_flash);
4812 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4813 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4814 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4816 for (i = 0; i < BOARD_HEIGHT; i++)
4817 for (j = 0; j < BOARD_WIDTH; j++) {
4818 DrawSquare(i, j, board[i][j], 0);
4819 damage[nr][i][j] = False;
4823 CopyBoard(lastBoard[nr], board);
4824 lastBoardValid[nr] = 1;
4825 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4826 lastFlipView = flipView;
4828 /* Draw highlights */
4829 if (pm1X >= 0 && pm1Y >= 0) {
4830 drawHighlight(pm1X, pm1Y, prelineGC);
4832 if (pm2X >= 0 && pm2Y >= 0) {
4833 drawHighlight(pm2X, pm2Y, prelineGC);
4835 if (hi1X >= 0 && hi1Y >= 0) {
4836 drawHighlight(hi1X, hi1Y, highlineGC);
4838 if (hi2X >= 0 && hi2Y >= 0) {
4839 drawHighlight(hi2X, hi2Y, highlineGC);
4841 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4843 /* If piece being dragged around board, must redraw that too */
4846 XSync(xDisplay, False);
4851 * event handler for redrawing the board
4854 DrawPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4856 XDrawPosition(w, True, NULL);
4861 * event handler for parsing user moves
4863 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4864 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4865 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4866 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4867 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4868 // and at the end FinishMove() to perform the move after optional promotion popups.
4869 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4871 HandleUserMove (Widget w, XEvent *event, String *prms, Cardinal *nprms)
4873 if (w != boardWidget || errorExitStatus != -1) return;
4874 if(nprms) shiftKey = !strcmp(prms[0], "1");
4877 if (event->type == ButtonPress) {
4878 XtPopdown(promotionShell);
4879 XtDestroyWidget(promotionShell);
4880 promotionUp = False;
4888 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4889 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4890 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4894 AnimateUserMove (Widget w, XEvent *event, String *params, Cardinal *nParams)
4896 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4897 DragPieceMove(event->xmotion.x, event->xmotion.y);
4901 HandlePV (Widget w, XEvent * event, String * params, Cardinal * nParams)
4902 { // [HGM] pv: walk PV
4903 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4906 static int savedIndex; /* gross that this is global */
4909 CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4912 XawTextPosition index, dummy;
4915 XawTextGetSelectionPos(w, &index, &dummy);
4916 XtSetArg(arg, XtNstring, &val);
4917 XtGetValues(w, &arg, 1);
4918 ReplaceComment(savedIndex, val);
4919 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4920 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4924 EditCommentPopUp (int index, char *title, char *text)
4927 if (text == NULL) text = "";
4928 NewCommentPopup(title, text, index);
4937 extern Option boxOptions[];
4947 edit = boxOptions[0].handle;
4949 XtSetArg(args[j], XtNstring, &val); j++;
4950 XtGetValues(edit, args, j);
4952 SendMultiLineToICS(val);
4953 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
4954 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
4958 ICSInputBoxPopDown ()
4964 CommentPopUp (char *title, char *text)
4966 savedIndex = currentMove; // [HGM] vari
4967 NewCommentPopup(title, text, currentMove);
4976 static char *openName;
4982 (void) (*fileProc)(openFP, 0, openName);
4986 FileNamePopUp (char *label, char *def, char *filter, FileProc proc, char *openMode)
4988 fileProc = proc; /* I can't see a way not */
4989 fileOpenMode = openMode; /* to use globals here */
4990 { // [HGM] use file-selector dialog stolen from Ghostview
4991 int index; // this is not supported yet
4992 if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, _("could not open: "),
4993 (def[0] ? def : NULL), filter, openMode, NULL, &openName))
4994 // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
4995 ScheduleDelayedEvent(&DelayedLoad, 50);
5002 if (!filenameUp) return;
5003 XtPopdown(fileNameShell);
5004 XtDestroyWidget(fileNameShell);
5010 FileNameCallback (Widget w, XtPointer client_data, XtPointer call_data)
5015 XtSetArg(args[0], XtNlabel, &name);
5016 XtGetValues(w, args, 1);
5018 if (strcmp(name, _("cancel")) == 0) {
5023 FileNameAction(w, NULL, NULL, NULL);
5027 FileNameAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5035 name = XawDialogGetValueString(w = XtParent(w));
5037 if ((name != NULL) && (*name != NULLCHAR)) {
5038 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5039 XtPopdown(w = XtParent(XtParent(w)));
5043 p = strrchr(buf, ' ');
5050 fullname = ExpandPathName(buf);
5052 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5055 f = fopen(fullname, fileOpenMode);
5057 DisplayError(_("Failed to open file"), errno);
5059 (void) (*fileProc)(f, index, buf);
5066 XtPopdown(w = XtParent(XtParent(w)));
5076 Widget dialog, layout;
5078 Dimension bw_width, pw_width;
5080 char *PromoChars = "wglcqrbnkac+=\0";
5083 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5084 XtGetValues(boardWidget, args, j);
5087 XtSetArg(args[j], XtNresizable, True); j++;
5088 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5090 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5091 shellWidget, args, j);
5093 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5094 layoutArgs, XtNumber(layoutArgs));
5097 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5098 XtSetArg(args[j], XtNborderWidth, 0); j++;
5099 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5102 if(gameInfo.variant != VariantShogi) {
5103 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5104 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback, PromoChars + 0);
5105 XawDialogAddButton(dialog, _("General"), PromotionCallback, PromoChars + 1);
5106 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback, PromoChars + 2);
5107 XawDialogAddButton(dialog, _("Captain"), PromotionCallback, PromoChars + 3);
5109 XawDialogAddButton(dialog, _("Queen"), PromotionCallback, PromoChars + 4);
5110 XawDialogAddButton(dialog, _("Rook"), PromotionCallback, PromoChars + 5);
5111 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, PromoChars + 6);
5112 XawDialogAddButton(dialog, _("Knight"), PromotionCallback, PromoChars + 7);
5114 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5115 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5116 gameInfo.variant == VariantGiveaway) {
5117 XawDialogAddButton(dialog, _("King"), PromotionCallback, PromoChars + 8);
5119 if(gameInfo.variant == VariantCapablanca ||
5120 gameInfo.variant == VariantGothic ||
5121 gameInfo.variant == VariantCapaRandom) {
5122 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, PromoChars + 9);
5123 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, PromoChars + 10);
5125 } else // [HGM] shogi
5127 XawDialogAddButton(dialog, _("Promote"), PromotionCallback, PromoChars + 11);
5128 XawDialogAddButton(dialog, _("Defer"), PromotionCallback, PromoChars + 12);
5130 XawDialogAddButton(dialog, _("cancel"), PromotionCallback, PromoChars + 13);
5132 XtRealizeWidget(promotionShell);
5133 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5136 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5137 XtGetValues(promotionShell, args, j);
5139 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5140 lineGap + squareSize/3 +
5141 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5142 0 : 6*(squareSize + lineGap)), &x, &y);
5145 XtSetArg(args[j], XtNx, x); j++;
5146 XtSetArg(args[j], XtNy, y); j++;
5147 XtSetValues(promotionShell, args, j);
5149 XtPopup(promotionShell, XtGrabNone);
5157 if (!promotionUp) return;
5158 XtPopdown(promotionShell);
5159 XtDestroyWidget(promotionShell);
5160 promotionUp = False;
5164 PromotionCallback (Widget w, XtPointer client_data, XtPointer call_data)
5166 int promoChar = * (const char *) client_data;
5170 if (fromX == -1) return;
5177 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5179 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5180 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5186 ErrorCallback (Widget w, XtPointer client_data, XtPointer call_data)
5189 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5191 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5198 if (!errorUp) return;
5200 XtPopdown(errorShell);
5201 XtDestroyWidget(errorShell);
5202 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5206 ErrorPopUp (char *title, char *label, int modal)
5209 Widget dialog, layout;
5213 Dimension bw_width, pw_width;
5214 Dimension pw_height;
5218 XtSetArg(args[i], XtNresizable, True); i++;
5219 XtSetArg(args[i], XtNtitle, title); i++;
5221 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5222 shellWidget, args, i);
5224 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5225 layoutArgs, XtNumber(layoutArgs));
5228 XtSetArg(args[i], XtNlabel, label); i++;
5229 XtSetArg(args[i], XtNborderWidth, 0); i++;
5230 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5233 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5235 XtRealizeWidget(errorShell);
5236 CatchDeleteWindow(errorShell, "ErrorPopDown");
5239 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5240 XtGetValues(boardWidget, args, i);
5242 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5243 XtSetArg(args[i], XtNheight, &pw_height); i++;
5244 XtGetValues(errorShell, args, i);
5247 /* This code seems to tickle an X bug if it is executed too soon
5248 after xboard starts up. The coordinates get transformed as if
5249 the main window was positioned at (0, 0).
5251 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5252 0 - pw_height + squareSize / 3, &x, &y);
5254 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5255 RootWindowOfScreen(XtScreen(boardWidget)),
5256 (bw_width - pw_width) / 2,
5257 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5261 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5264 XtSetArg(args[i], XtNx, x); i++;
5265 XtSetArg(args[i], XtNy, y); i++;
5266 XtSetValues(errorShell, args, i);
5269 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5272 /* Disable all user input other than deleting the window */
5273 static int frozen = 0;
5279 /* Grab by a widget that doesn't accept input */
5280 XtAddGrab(messageWidget, TRUE, FALSE);
5284 /* Undo a FreezeUI */
5288 if (!frozen) return;
5289 XtRemoveGrab(messageWidget);
5294 ModeToWidgetName (GameMode 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";
5339 static int oldPausing = FALSE;
5340 static GameMode oldmode = (GameMode) -1;
5343 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5345 if (pausing != oldPausing) {
5346 oldPausing = pausing;
5348 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5350 XtSetArg(args[0], XtNleftBitmap, None);
5352 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5355 if (appData.showButtonBar) {
5356 /* Always toggle, don't set. Previous code messes up when
5357 invoked while the button is pressed, as releasing it
5358 toggles the state again. */
5361 XtSetArg(args[0], XtNbackground, &oldbg);
5362 XtSetArg(args[1], XtNforeground, &oldfg);
5363 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5365 XtSetArg(args[0], XtNbackground, oldfg);
5366 XtSetArg(args[1], XtNforeground, oldbg);
5368 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5372 wname = ModeToWidgetName(oldmode);
5373 if (wname != NULL) {
5374 XtSetArg(args[0], XtNleftBitmap, None);
5375 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5377 wname = ModeToWidgetName(gameMode);
5378 if (wname != NULL) {
5379 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5380 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5383 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5384 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5386 /* Maybe all the enables should be handled here, not just this one */
5387 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5388 gameMode == Training || gameMode == PlayFromGameFile);
5393 * Button/menu procedures
5396 ResetProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5402 LoadGamePopUp (FILE *f, int gameNumber, char *title)
5404 cmailMsgLoaded = FALSE;
5405 if (gameNumber == 0) {
5406 int error = GameListBuild(f);
5408 DisplayError(_("Cannot build game list"), error);
5409 } else if (!ListEmpty(&gameList) &&
5410 ((ListGame *) gameList.tailPred)->number > 1) {
5411 GameListPopUp(f, title);
5417 return LoadGame(f, gameNumber, title, FALSE);
5421 LoadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5423 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5426 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5430 LoadNextGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5436 LoadPrevGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5442 ReloadGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5448 LoadNextPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5454 LoadPrevPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5460 ReloadPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5466 LoadPositionProc(Widget w, XEvent *event, String *prms, Cardinal *nprms)
5468 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5471 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5475 SaveGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5477 FileNamePopUp(_("Save game file name?"),
5478 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5479 appData.oldSaveStyle ? ".game" : ".pgn",
5484 SavePositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5486 FileNamePopUp(_("Save position file name?"),
5487 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5488 appData.oldSaveStyle ? ".pos" : ".fen",
5493 ReloadCmailMsgProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5495 ReloadCmailMsgEvent(FALSE);
5499 MailMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5504 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5505 char *selected_fen_position=NULL;
5508 SendPositionSelection (Widget w, Atom *selection, Atom *target,
5509 Atom *type_return, XtPointer *value_return,
5510 unsigned long *length_return, int *format_return)
5512 char *selection_tmp;
5514 if (!selected_fen_position) return False; /* should never happen */
5515 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5516 /* note: since no XtSelectionDoneProc was registered, Xt will
5517 * automatically call XtFree on the value returned. So have to
5518 * make a copy of it allocated with XtMalloc */
5519 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5520 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5522 *value_return=selection_tmp;
5523 *length_return=strlen(selection_tmp);
5524 *type_return=*target;
5525 *format_return = 8; /* bits per byte */
5527 } else if (*target == XA_TARGETS(xDisplay)) {
5528 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5529 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5530 targets_tmp[1] = XA_STRING;
5531 *value_return = targets_tmp;
5532 *type_return = XA_ATOM;
5535 // This code leads to a read of value_return out of bounds on 64-bit systems.
5536 // Other code which I have seen always sets *format_return to 32 independent of
5537 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5538 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5539 *format_return = 8 * sizeof(Atom);
5540 if (*format_return > 32) {
5541 *length_return *= *format_return / 32;
5542 *format_return = 32;
5545 *format_return = 32;
5553 /* note: when called from menu all parameters are NULL, so no clue what the
5554 * Widget which was clicked on was, or what the click event was
5557 CopyPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5560 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5561 * have a notion of a position that is selected but not copied.
5562 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5564 if(gameMode == EditPosition) EditPositionDone(TRUE);
5565 if (selected_fen_position) free(selected_fen_position);
5566 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5567 if (!selected_fen_position) return;
5568 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5570 SendPositionSelection,
5571 NULL/* lose_ownership_proc */ ,
5572 NULL/* transfer_done_proc */);
5573 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5575 SendPositionSelection,
5576 NULL/* lose_ownership_proc */ ,
5577 NULL/* transfer_done_proc */);
5580 /* function called when the data to Paste is ready */
5582 PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
5583 Atom *type, XtPointer value, unsigned long *len, int *format)
5586 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5587 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5588 EditPositionPasteFEN(fenstr);
5592 /* called when Paste Position button is pressed,
5593 * all parameters will be NULL */
5594 void PastePositionProc(w, event, prms, nprms)
5600 XtGetSelectionValue(menuBarWidget,
5601 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5602 /* (XtSelectionCallbackProc) */ PastePositionCB,
5603 NULL, /* client_data passed to PastePositionCB */
5605 /* better to use the time field from the event that triggered the
5606 * call to this function, but that isn't trivial to get
5614 SendGameSelection (Widget w, Atom *selection, Atom *target,
5615 Atom *type_return, XtPointer *value_return,
5616 unsigned long *length_return, int *format_return)
5618 char *selection_tmp;
5620 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5621 FILE* f = fopen(gameCopyFilename, "r");
5624 if (f == NULL) return False;
5628 selection_tmp = XtMalloc(len + 1);
5629 count = fread(selection_tmp, 1, len, f);
5632 XtFree(selection_tmp);
5635 selection_tmp[len] = NULLCHAR;
5636 *value_return = selection_tmp;
5637 *length_return = len;
5638 *type_return = *target;
5639 *format_return = 8; /* bits per byte */
5641 } else if (*target == XA_TARGETS(xDisplay)) {
5642 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5643 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5644 targets_tmp[1] = XA_STRING;
5645 *value_return = targets_tmp;
5646 *type_return = XA_ATOM;
5649 // This code leads to a read of value_return out of bounds on 64-bit systems.
5650 // Other code which I have seen always sets *format_return to 32 independent of
5651 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5652 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5653 *format_return = 8 * sizeof(Atom);
5654 if (*format_return > 32) {
5655 *length_return *= *format_return / 32;
5656 *format_return = 32;
5659 *format_return = 32;
5671 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5672 * have a notion of a game that is selected but not copied.
5673 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5675 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5678 NULL/* lose_ownership_proc */ ,
5679 NULL/* transfer_done_proc */);
5680 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5683 NULL/* lose_ownership_proc */ ,
5684 NULL/* transfer_done_proc */);
5687 /* note: when called from menu all parameters are NULL, so no clue what the
5688 * Widget which was clicked on was, or what the click event was
5691 CopyGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5695 ret = SaveGameToFile(gameCopyFilename, FALSE);
5702 CopyGameListProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5704 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5708 /* function called when the data to Paste is ready */
5710 PasteGameCB (Widget w, XtPointer client_data, Atom *selection,
5711 Atom *type, XtPointer value, unsigned long *len, int *format)
5714 if (value == NULL || *len == 0) {
5715 return; /* nothing had been selected to copy */
5717 f = fopen(gamePasteFilename, "w");
5719 DisplayError(_("Can't open temp file"), errno);
5722 fwrite(value, 1, *len, f);
5725 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5728 /* called when Paste Game button is pressed,
5729 * all parameters will be NULL */
5731 PasteGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5733 XtGetSelectionValue(menuBarWidget,
5734 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5735 /* (XtSelectionCallbackProc) */ PasteGameCB,
5736 NULL, /* client_data passed to PasteGameCB */
5738 /* better to use the time field from the event that triggered the
5739 * call to this function, but that isn't trivial to get
5750 SaveGameProc(NULL, NULL, NULL, NULL);
5755 QuitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5761 PauseProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5767 MachineBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5769 MachineBlackEvent();
5773 MachineWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5775 MachineWhiteEvent();
5779 AnalyzeModeProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5783 if (!first.analysisSupport) {
5784 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5785 DisplayError(buf, 0);
5788 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5789 if (appData.icsActive) {
5790 if (gameMode != IcsObserving) {
5791 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5792 DisplayError(buf, 0);
5794 if (appData.icsEngineAnalyze) {
5795 if (appData.debugMode)
5796 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5802 /* if enable, use want disable icsEngineAnalyze */
5803 if (appData.icsEngineAnalyze) {
5808 appData.icsEngineAnalyze = TRUE;
5809 if (appData.debugMode)
5810 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5812 #ifndef OPTIONSDIALOG
5813 if (!appData.showThinking)
5814 ShowThinkingProc(w,event,prms,nprms);
5821 AnalyzeFileProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5823 if (!first.analysisSupport) {
5825 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5826 DisplayError(buf, 0);
5829 // Reset(FALSE, TRUE);
5830 #ifndef OPTIONSDIALOG
5831 if (!appData.showThinking)
5832 ShowThinkingProc(w,event,prms,nprms);
5835 // FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5836 AnalysisPeriodicEvent(1);
5840 TwoMachinesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5846 MatchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5852 IcsClientProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5858 EditGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5864 EditPositionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5866 EditPositionEvent();
5870 TrainingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5876 EditCommentProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5880 if (PopDown(1)) { // popdown succesful
5882 XtSetArg(args[j], XtNleftBitmap, None); j++;
5883 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
5884 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
5885 } else // was not up
5890 IcsInputBoxProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5892 if (!PopDown(4)) ICSInputBoxPopUp();
5896 AcceptProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5902 DeclineProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5908 RematchProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5914 CallFlagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5920 DrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5926 AbortProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5932 AdjournProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5938 ResignProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5944 AdjuWhiteProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5946 UserAdjudicationEvent(+1);
5950 AdjuBlackProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5952 UserAdjudicationEvent(-1);
5956 AdjuDrawProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5958 UserAdjudicationEvent(0);
5962 EnterKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5964 if (shellUp[4] == True)
5969 UpKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5970 { // [HGM] input: let up-arrow recall previous line from history
5977 if (!shellUp[4]) return;
5978 edit = boxOptions[0].handle;
5980 XtSetArg(args[j], XtNstring, &val); j++;
5981 XtGetValues(edit, args, j);
5982 val = PrevInHistory(val);
5983 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5984 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5986 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
5987 XawTextReplace(edit, 0, 0, &t);
5988 XawTextSetInsertionPoint(edit, 9999);
5993 DownKeyProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
5994 { // [HGM] input: let down-arrow recall next line from history
5999 if (!shellUp[4]) return;
6000 edit = boxOptions[0].handle;
6001 val = NextInHistory();
6002 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6003 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6005 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6006 XawTextReplace(edit, 0, 0, &t);
6007 XawTextSetInsertionPoint(edit, 9999);
6012 StopObservingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6014 StopObservingEvent();
6018 StopExaminingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6020 StopExaminingEvent();
6024 UploadProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6031 ForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6038 BackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6044 TempBackwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6046 if (!TempBackwardActive) {
6047 TempBackwardActive = True;
6053 TempForwardProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6055 /* Check to see if triggered by a key release event for a repeating key.
6056 * If so the next queued event will be a key press of the same key at the same time */
6057 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
6059 XPeekEvent(xDisplay, &next);
6060 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
6061 next.xkey.keycode == event->xkey.keycode)
6065 TempBackwardActive = False;
6069 ToStartProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6075 ToEndProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6081 RevertProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6087 AnnotateProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6093 TruncateGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6095 TruncateGameEvent();
6099 RetractMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6105 MoveNowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6111 FlipViewProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6113 flipView = !flipView;
6114 DrawPosition(True, NULL);
6118 PonderNextMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6122 PonderNextMoveEvent(!appData.ponderNextMove);
6123 #ifndef OPTIONSDIALOG
6124 if (appData.ponderNextMove) {
6125 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6127 XtSetArg(args[0], XtNleftBitmap, None);
6129 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6134 #ifndef OPTIONSDIALOG
6136 AlwaysQueenProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6140 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6142 if (appData.alwaysPromoteToQueen) {
6143 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6145 XtSetArg(args[0], XtNleftBitmap, None);
6147 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6152 AnimateDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6156 appData.animateDragging = !appData.animateDragging;
6158 if (appData.animateDragging) {
6159 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6162 XtSetArg(args[0], XtNleftBitmap, None);
6164 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6169 AnimateMovingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6173 appData.animate = !appData.animate;
6175 if (appData.animate) {
6176 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6179 XtSetArg(args[0], XtNleftBitmap, None);
6181 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6186 AutoflagProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6190 appData.autoCallFlag = !appData.autoCallFlag;
6192 if (appData.autoCallFlag) {
6193 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6195 XtSetArg(args[0], XtNleftBitmap, None);
6197 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6202 AutoflipProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6206 appData.autoFlipView = !appData.autoFlipView;
6208 if (appData.autoFlipView) {
6209 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6211 XtSetArg(args[0], XtNleftBitmap, None);
6213 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6218 BlindfoldProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6222 appData.blindfold = !appData.blindfold;
6224 if (appData.blindfold) {
6225 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6227 XtSetArg(args[0], XtNleftBitmap, None);
6229 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6232 DrawPosition(True, NULL);
6236 TestLegalityProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6240 appData.testLegality = !appData.testLegality;
6242 if (appData.testLegality) {
6243 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6245 XtSetArg(args[0], XtNleftBitmap, None);
6247 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6253 FlashMovesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6257 if (appData.flashCount == 0) {
6258 appData.flashCount = 3;
6260 appData.flashCount = -appData.flashCount;
6263 if (appData.flashCount > 0) {
6264 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6266 XtSetArg(args[0], XtNleftBitmap, None);
6268 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6274 HighlightDraggingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6278 appData.highlightDragging = !appData.highlightDragging;
6280 if (appData.highlightDragging) {
6281 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6283 XtSetArg(args[0], XtNleftBitmap, None);
6285 XtSetValues(XtNameToWidget(menuBarWidget,
6286 "menuOptions.Highlight Dragging"), args, 1);
6291 HighlightLastMoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6295 appData.highlightLastMove = !appData.highlightLastMove;
6297 if (appData.highlightLastMove) {
6298 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6300 XtSetArg(args[0], XtNleftBitmap, None);
6302 XtSetValues(XtNameToWidget(menuBarWidget,
6303 "menuOptions.Highlight Last Move"), args, 1);
6307 HighlightArrowProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6311 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6313 if (appData.highlightMoveWithArrow) {
6314 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6316 XtSetArg(args[0], XtNleftBitmap, None);
6318 XtSetValues(XtNameToWidget(menuBarWidget,
6319 "menuOptions.Arrow"), args, 1);
6324 IcsAlarmProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6328 appData.icsAlarm = !appData.icsAlarm;
6330 if (appData.icsAlarm) {
6331 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6333 XtSetArg(args[0], XtNleftBitmap, None);
6335 XtSetValues(XtNameToWidget(menuBarWidget,
6336 "menuOptions.ICS Alarm"), args, 1);
6341 MoveSoundProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6345 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6347 if (appData.ringBellAfterMoves) {
6348 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6350 XtSetArg(args[0], XtNleftBitmap, None);
6352 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6357 OneClickProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6361 appData.oneClick = !appData.oneClick;
6363 if (appData.oneClick) {
6364 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6366 XtSetArg(args[0], XtNleftBitmap, None);
6368 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6373 PeriodicUpdatesProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6377 PeriodicUpdatesEvent(!appData.periodicUpdates);
6379 if (appData.periodicUpdates) {
6380 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6382 XtSetArg(args[0], XtNleftBitmap, None);
6384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6389 PopupExitMessageProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6393 appData.popupExitMessage = !appData.popupExitMessage;
6395 if (appData.popupExitMessage) {
6396 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6398 XtSetArg(args[0], XtNleftBitmap, None);
6400 XtSetValues(XtNameToWidget(menuBarWidget,
6401 "menuOptions.Popup Exit Message"), args, 1);
6405 PopupMoveErrorsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6409 appData.popupMoveErrors = !appData.popupMoveErrors;
6411 if (appData.popupMoveErrors) {
6412 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6414 XtSetArg(args[0], XtNleftBitmap, None);
6416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6422 PremoveProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6426 appData.premove = !appData.premove;
6428 if (appData.premove) {
6429 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6431 XtSetArg(args[0], XtNleftBitmap, None);
6433 XtSetValues(XtNameToWidget(menuBarWidget,
6434 "menuOptions.Premove"), args, 1);
6439 ShowCoordsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6443 appData.showCoords = !appData.showCoords;
6445 if (appData.showCoords) {
6446 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6448 XtSetArg(args[0], XtNleftBitmap, None);
6450 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6453 DrawPosition(True, NULL);
6457 ShowThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6459 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6460 ShowThinkingEvent();
6464 HideThinkingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6468 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6469 ShowThinkingEvent();
6471 if (appData.hideThinkingFromHuman) {
6472 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6474 XtSetArg(args[0], XtNleftBitmap, None);
6476 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6482 SaveOnExitProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6486 saveSettingsOnExit = !saveSettingsOnExit;
6488 if (saveSettingsOnExit) {
6489 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6491 XtSetArg(args[0], XtNleftBitmap, None);
6493 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6498 SaveSettingsProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6500 SaveSettings(settingsFileName);
6504 InfoProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6507 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6513 ManProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6517 if (nprms && *nprms > 0)
6521 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6526 HintProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6532 BookProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6538 AboutProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6542 char *zippy = _(" (with Zippy code)");
6546 snprintf(buf, sizeof(buf),
6548 "Copyright 1991 Digital Equipment Corporation\n"
6549 "Enhancements Copyright 1992-2009 Free Software Foundation\n"
6550 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
6551 "%s is free software and carries NO WARRANTY;"
6552 "see the file COPYING for more information."),
6553 programVersion, zippy, PACKAGE);
6554 ErrorPopUp(_("About XBoard"), buf, FALSE);
6558 DebugProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6560 appData.debugMode = !appData.debugMode;
6564 AboutGameProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6570 NothingProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6576 DisplayMessage (char *message, char *extMessage)
6578 /* display a message in the message widget */
6587 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6592 message = extMessage;
6596 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6598 /* need to test if messageWidget already exists, since this function
6599 can also be called during the startup, if for example a Xresource
6600 is not set up correctly */
6603 XtSetArg(arg, XtNlabel, message);
6604 XtSetValues(messageWidget, &arg, 1);
6611 DisplayTitle (char *text)
6615 char title[MSG_SIZ];
6618 if (text == NULL) text = "";
6620 if (appData.titleInWindow) {
6622 XtSetArg(args[i], XtNlabel, text); i++;
6623 XtSetValues(titleWidget, args, i);
6626 if (*text != NULLCHAR) {
6627 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6628 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6629 } else if (appData.icsActive) {
6630 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6631 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6632 } else if (appData.cmailGameName[0] != NULLCHAR) {
6633 snprintf(icon, sizeof(icon), "%s", "CMail");
6634 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6636 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6637 } else if (gameInfo.variant == VariantGothic) {
6638 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6639 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6642 } else if (gameInfo.variant == VariantFalcon) {
6643 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6644 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6646 } else if (appData.noChessProgram) {
6647 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6648 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6650 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6651 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6654 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6655 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6656 XtSetValues(shellWidget, args, i);
6657 XSync(xDisplay, False);
6662 DisplayError (String message, int error)
6667 if (appData.debugMode || appData.matchMode) {
6668 fprintf(stderr, "%s: %s\n", programName, message);
6671 if (appData.debugMode || appData.matchMode) {
6672 fprintf(stderr, "%s: %s: %s\n",
6673 programName, message, strerror(error));
6675 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6678 ErrorPopUp(_("Error"), message, FALSE);
6683 DisplayMoveError (String message)
6687 DrawPosition(FALSE, NULL);
6688 if (appData.debugMode || appData.matchMode) {
6689 fprintf(stderr, "%s: %s\n", programName, message);
6691 if (appData.popupMoveErrors) {
6692 ErrorPopUp(_("Error"), message, FALSE);
6694 DisplayMessage(message, "");
6700 DisplayFatalError (String message, int error, int status)
6704 errorExitStatus = status;
6706 fprintf(stderr, "%s: %s\n", programName, message);
6708 fprintf(stderr, "%s: %s: %s\n",
6709 programName, message, strerror(error));
6710 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
6713 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
6714 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
6721 DisplayInformation (String message)
6724 ErrorPopUp(_("Information"), message, TRUE);
6728 DisplayNote (String message)
6731 ErrorPopUp(_("Note"), message, FALSE);
6735 NullXErrorCheck (Display *dpy, XErrorEvent *error_event)
6741 DisplayIcsInteractionTitle (String message)
6743 if (oldICSInteractionTitle == NULL) {
6744 /* Magic to find the old window title, adapted from vim */
6745 char *wina = getenv("WINDOWID");
6747 Window win = (Window) atoi(wina);
6748 Window root, parent, *children;
6749 unsigned int nchildren;
6750 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
6752 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
6753 if (!XQueryTree(xDisplay, win, &root, &parent,
6754 &children, &nchildren)) break;
6755 if (children) XFree((void *)children);
6756 if (parent == root || parent == 0) break;
6759 XSetErrorHandler(oldHandler);
6761 if (oldICSInteractionTitle == NULL) {
6762 oldICSInteractionTitle = "xterm";
6765 printf("\033]0;%s\007", message);
6769 char pendingReplyPrefix[MSG_SIZ];
6770 ProcRef pendingReplyPR;
6773 AskQuestionProc (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6776 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
6780 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
6784 AskQuestionPopDown ()
6786 if (!askQuestionUp) return;
6787 XtPopdown(askQuestionShell);
6788 XtDestroyWidget(askQuestionShell);
6789 askQuestionUp = False;
6793 AskQuestionReplyAction (Widget w, XEvent *event, String *prms, Cardinal *nprms)
6799 reply = XawDialogGetValueString(w = XtParent(w));
6800 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
6801 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
6802 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
6803 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
6804 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
6805 AskQuestionPopDown();
6807 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
6811 AskQuestionCallback (Widget w, XtPointer client_data, XtPointer call_data)
6816 XtSetArg(args[0], XtNlabel, &name);
6817 XtGetValues(w, args, 1);
6819 if (strcmp(name, _("cancel")) == 0) {
6820 AskQuestionPopDown();
6822 AskQuestionReplyAction(w, NULL, NULL, NULL);
6827 AskQuestion (char *title, char *question, char *replyPrefix, ProcRef pr)
6830 Widget popup, layout, dialog, edit;
6836 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
6837 pendingReplyPR = pr;
6840 XtSetArg(args[i], XtNresizable, True); i++;
6841 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
6842 askQuestionShell = popup =
6843 XtCreatePopupShell(title, transientShellWidgetClass,
6844 shellWidget, args, i);
6847 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
6848 layoutArgs, XtNumber(layoutArgs));
6851 XtSetArg(args[i], XtNlabel, question); i++;
6852 XtSetArg(args[i], XtNvalue, ""); i++;
6853 XtSetArg(args[i], XtNborderWidth, 0); i++;
6854 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
6857 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
6858 (XtPointer) dialog);
6859 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
6860 (XtPointer) dialog);
6862 XtRealizeWidget(popup);
6863 CatchDeleteWindow(popup, "AskQuestionPopDown");
6865 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
6866 &x, &y, &win_x, &win_y, &mask);
6868 XtSetArg(args[0], XtNx, x - 10);
6869 XtSetArg(args[1], XtNy, y - 30);
6870 XtSetValues(popup, args, 2);
6872 XtPopup(popup, XtGrabExclusive);
6873 askQuestionUp = True;
6875 edit = XtNameToWidget(dialog, "*value");
6876 XtSetKeyboardFocus(popup, edit);
6881 PlaySound (char *name)
6883 if (*name == NULLCHAR) {
6885 } else if (strcmp(name, "$") == 0) {
6886 putc(BELLCHAR, stderr);
6889 char *prefix = "", *sep = "";
6890 if(appData.soundProgram[0] == NULLCHAR) return;
6891 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
6892 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
6900 PlaySound(appData.soundMove);
6906 PlaySound(appData.soundIcsWin);
6912 PlaySound(appData.soundIcsLoss);
6918 PlaySound(appData.soundIcsDraw);
6922 PlayIcsUnfinishedSound ()
6924 PlaySound(appData.soundIcsUnfinished);
6930 PlaySound(appData.soundIcsAlarm);
6936 PlaySound(appData.soundTell);
6942 system("stty echo");
6949 system("stty -echo");
6954 RunCommand (char *buf)
6960 Colorize (ColorClass cc, int continuation)
6963 int count, outCount, error;
6965 if (textColors[(int)cc].bg > 0) {
6966 if (textColors[(int)cc].fg > 0) {
6967 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
6968 textColors[(int)cc].fg, textColors[(int)cc].bg);
6970 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
6971 textColors[(int)cc].bg);
6974 if (textColors[(int)cc].fg > 0) {
6975 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
6976 textColors[(int)cc].fg);
6978 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
6981 count = strlen(buf);
6982 outCount = OutputToProcess(NoProc, buf, count, &error);
6983 if (outCount < count) {
6984 DisplayFatalError(_("Error writing to display"), error, 1);
6987 if (continuation) return;
6990 PlaySound(appData.soundShout);
6993 PlaySound(appData.soundSShout);
6996 PlaySound(appData.soundChannel1);
6999 PlaySound(appData.soundChannel);
7002 PlaySound(appData.soundKibitz);
7005 PlaySound(appData.soundTell);
7007 case ColorChallenge:
7008 PlaySound(appData.soundChallenge);
7011 PlaySound(appData.soundRequest);
7014 PlaySound(appData.soundSeek);
7026 return getpwuid(getuid())->pw_name;
7030 ExpandPathName (char *path)
7032 static char static_buf[4*MSG_SIZ];
7033 char *d, *s, buf[4*MSG_SIZ];
7039 while (*s && isspace(*s))
7048 if (*(s+1) == '/') {
7049 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7053 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7054 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7055 pwd = getpwnam(buf);
7058 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7062 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7063 strcat(d, strchr(s+1, '/'));
7067 safeStrCpy(d, s, 4*MSG_SIZ );
7075 static char host_name[MSG_SIZ];
7077 #if HAVE_GETHOSTNAME
7078 gethostname(host_name, MSG_SIZ);
7080 #else /* not HAVE_GETHOSTNAME */
7081 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7082 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7084 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7086 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7087 #endif /* not HAVE_GETHOSTNAME */
7090 XtIntervalId delayedEventTimerXID = 0;
7091 DelayedEventCallback delayedEventCallback = 0;
7096 delayedEventTimerXID = 0;
7097 delayedEventCallback();
7101 ScheduleDelayedEvent (DelayedEventCallback cb, long millisec)
7103 if(delayedEventTimerXID && delayedEventCallback == cb)
7104 // [HGM] alive: replace, rather than add or flush identical event
7105 XtRemoveTimeOut(delayedEventTimerXID);
7106 delayedEventCallback = cb;
7107 delayedEventTimerXID =
7108 XtAppAddTimeOut(appContext, millisec,
7109 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7112 DelayedEventCallback
7115 if (delayedEventTimerXID) {
7116 return delayedEventCallback;
7123 CancelDelayedEvent ()
7125 if (delayedEventTimerXID) {
7126 XtRemoveTimeOut(delayedEventTimerXID);
7127 delayedEventTimerXID = 0;
7131 XtIntervalId loadGameTimerXID = 0;
7134 LoadGameTimerRunning ()
7136 return loadGameTimerXID != 0;
7140 StopLoadGameTimer ()
7142 if (loadGameTimerXID != 0) {
7143 XtRemoveTimeOut(loadGameTimerXID);
7144 loadGameTimerXID = 0;
7152 LoadGameTimerCallback (XtPointer arg, XtIntervalId *id)
7154 loadGameTimerXID = 0;
7159 StartLoadGameTimer (long millisec)
7162 XtAppAddTimeOut(appContext, millisec,
7163 (XtTimerCallbackProc) LoadGameTimerCallback,
7167 XtIntervalId analysisClockXID = 0;
7170 AnalysisClockCallback (XtPointer arg, XtIntervalId *id)
7172 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7173 || appData.icsEngineAnalyze) { // [DM]
7174 AnalysisPeriodicEvent(0);
7175 StartAnalysisClock();
7180 StartAnalysisClock ()
7183 XtAppAddTimeOut(appContext, 2000,
7184 (XtTimerCallbackProc) AnalysisClockCallback,
7188 XtIntervalId clockTimerXID = 0;
7191 ClockTimerRunning ()
7193 return clockTimerXID != 0;
7199 if (clockTimerXID != 0) {
7200 XtRemoveTimeOut(clockTimerXID);
7209 ClockTimerCallback (XtPointer arg, XtIntervalId *id)
7216 StartClockTimer (long millisec)
7219 XtAppAddTimeOut(appContext, millisec,
7220 (XtTimerCallbackProc) ClockTimerCallback,
7225 DisplayTimerLabel (Widget w, char *color, long timer, int highlight)
7230 /* check for low time warning */
7231 Pixel foregroundOrWarningColor = timerForegroundPixel;
7234 appData.lowTimeWarning &&
7235 (timer / 1000) < appData.icsAlarmTime)
7236 foregroundOrWarningColor = lowTimeWarningColor;
7238 if (appData.clockMode) {
7239 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7240 XtSetArg(args[0], XtNlabel, buf);
7242 snprintf(buf, MSG_SIZ, "%s ", color);
7243 XtSetArg(args[0], XtNlabel, buf);
7248 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7249 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7251 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7252 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7255 XtSetValues(w, args, 3);
7259 DisplayWhiteClock (long timeRemaining, int highlight)
7263 if(appData.noGUI) return;
7264 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7265 if (highlight && iconPixmap == bIconPixmap) {
7266 iconPixmap = wIconPixmap;
7267 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7268 XtSetValues(shellWidget, args, 1);
7273 DisplayBlackClock (long timeRemaining, int highlight)
7277 if(appData.noGUI) return;
7278 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7279 if (highlight && iconPixmap == wIconPixmap) {
7280 iconPixmap = bIconPixmap;
7281 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7282 XtSetValues(shellWidget, args, 1);
7301 StartChildProcess (char *cmdLine, char *dir, ProcRef *pr)
7305 int to_prog[2], from_prog[2];
7309 if (appData.debugMode) {
7310 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7313 /* We do NOT feed the cmdLine to the shell; we just
7314 parse it into blank-separated arguments in the
7315 most simple-minded way possible.
7318 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7321 while(*p == ' ') p++;
7323 if(*p == '"' || *p == '\'')
7324 p = strchr(++argv[i-1], *p);
7325 else p = strchr(p, ' ');
7326 if (p == NULL) break;
7331 SetUpChildIO(to_prog, from_prog);
7333 if ((pid = fork()) == 0) {
7335 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7336 close(to_prog[1]); // first close the unused pipe ends
7337 close(from_prog[0]);
7338 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7339 dup2(from_prog[1], 1);
7340 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7341 close(from_prog[1]); // and closing again loses one of the pipes!
7342 if(fileno(stderr) >= 2) // better safe than sorry...
7343 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7345 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7350 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7352 execvp(argv[0], argv);
7354 /* If we get here, exec failed */
7359 /* Parent process */
7361 close(from_prog[1]);
7363 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7366 cp->fdFrom = from_prog[0];
7367 cp->fdTo = to_prog[1];
7372 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7374 AlarmCallBack (int n)
7380 DestroyChildProcess (ProcRef pr, int signalType)
7382 ChildProc *cp = (ChildProc *) pr;
7384 if (cp->kind != CPReal) return;
7386 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7387 signal(SIGALRM, AlarmCallBack);
7389 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7390 kill(cp->pid, SIGKILL); // kill it forcefully
7391 wait((int *) 0); // and wait again
7395 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7397 /* Process is exiting either because of the kill or because of
7398 a quit command sent by the backend; either way, wait for it to die.
7407 InterruptChildProcess (ProcRef pr)
7409 ChildProc *cp = (ChildProc *) pr;
7411 if (cp->kind != CPReal) return;
7412 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7416 OpenTelnet (char *host, char *port, ProcRef *pr)
7418 char cmdLine[MSG_SIZ];
7420 if (port[0] == NULLCHAR) {
7421 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7423 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7425 return StartChildProcess(cmdLine, "", pr);
7429 OpenTCP (char *host, char *port, ProcRef *pr)
7432 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7433 #else /* !OMIT_SOCKETS */
7434 struct addrinfo hints;
7435 struct addrinfo *ais, *ai;
7440 memset(&hints, 0, sizeof(hints));
7441 hints.ai_family = AF_UNSPEC;
7442 hints.ai_socktype = SOCK_STREAM;
7444 error = getaddrinfo(host, port, &hints, &ais);
7446 /* a getaddrinfo error is not an errno, so can't return it */
7447 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7448 host, port, gai_strerror(error));
7452 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7453 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7457 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7470 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7476 #endif /* !OMIT_SOCKETS */
7482 OpenCommPort (char *name, ProcRef *pr)
7487 fd = open(name, 2, 0);
7488 if (fd < 0) return errno;
7490 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7501 OpenLoopback (ProcRef *pr)
7506 SetUpChildIO(to, from);
7508 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7511 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7519 OpenRcmd (char *host, char *user, char *cmd, ProcRef *pr)
7521 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7525 #define INPUT_SOURCE_BUF_SIZE 8192
7534 char buf[INPUT_SOURCE_BUF_SIZE];
7539 DoInputCallback (caddr_t closure, int *source, XtInputId *xid)
7541 InputSource *is = (InputSource *) closure;
7546 if (is->lineByLine) {
7547 count = read(is->fd, is->unused,
7548 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7550 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7553 is->unused += count;
7555 while (p < is->unused) {
7556 q = memchr(p, '\n', is->unused - p);
7557 if (q == NULL) break;
7559 (is->func)(is, is->closure, p, q - p, 0);
7563 while (p < is->unused) {
7568 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7573 (is->func)(is, is->closure, is->buf, count, error);
7578 AddInputSource (ProcRef pr, int lineByLine, InputCallback func, VOIDSTAR closure)
7581 ChildProc *cp = (ChildProc *) pr;
7583 is = (InputSource *) calloc(1, sizeof(InputSource));
7584 is->lineByLine = lineByLine;
7588 is->fd = fileno(stdin);
7590 is->kind = cp->kind;
7591 is->fd = cp->fdFrom;
7594 is->unused = is->buf;
7597 is->xid = XtAppAddInput(appContext, is->fd,
7598 (XtPointer) (XtInputReadMask),
7599 (XtInputCallbackProc) DoInputCallback,
7601 is->closure = closure;
7602 return (InputSourceRef) is;
7606 RemoveInputSource (InputSourceRef isr)
7608 InputSource *is = (InputSource *) isr;
7610 if (is->xid == 0) return;
7611 XtRemoveInput(is->xid);
7616 OutputToProcess (ProcRef pr, char *message, int count, int *outError)
7618 static int line = 0;
7619 ChildProc *cp = (ChildProc *) pr;
7624 if (appData.noJoin || !appData.useInternalWrap)
7625 outCount = fwrite(message, 1, count, stdout);
7628 int width = get_term_width();
7629 int len = wrap(NULL, message, count, width, &line);
7630 char *msg = malloc(len);
7634 outCount = fwrite(message, 1, count, stdout);
7637 dbgchk = wrap(msg, message, count, width, &line);
7638 if (dbgchk != len && appData.debugMode)
7639 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
7640 outCount = fwrite(msg, 1, dbgchk, stdout);
7646 outCount = write(cp->fdTo, message, count);
7656 /* Output message to process, with "ms" milliseconds of delay
7657 between each character. This is needed when sending the logon
7658 script to ICC, which for some reason doesn't like the
7659 instantaneous send. */
7661 OutputToProcessDelayed (ProcRef pr, char *message, int count, int *outError, long msdelay)
7663 ChildProc *cp = (ChildProc *) pr;
7668 r = write(cp->fdTo, message++, 1);
7681 /**** Animation code by Hugh Fisher, DCS, ANU.
7683 Known problem: if a window overlapping the board is
7684 moved away while a piece is being animated underneath,
7685 the newly exposed area won't be updated properly.
7686 I can live with this.
7688 Known problem: if you look carefully at the animation
7689 of pieces in mono mode, they are being drawn as solid
7690 shapes without interior detail while moving. Fixing
7691 this would be a major complication for minimal return.
7694 /* Masks for XPM pieces. Black and white pieces can have
7695 different shapes, but in the interest of retaining my
7696 sanity pieces must have the same outline on both light
7697 and dark squares, and all pieces must use the same
7698 background square colors/images. */
7700 static int xpmDone = 0;
7703 CreateAnimMasks (int pieceDepth)
7709 unsigned long plane;
7712 /* Need a bitmap just to get a GC with right depth */
7713 buf = XCreatePixmap(xDisplay, xBoardWindow,
7715 values.foreground = 1;
7716 values.background = 0;
7717 /* Don't use XtGetGC, not read only */
7718 maskGC = XCreateGC(xDisplay, buf,
7719 GCForeground | GCBackground, &values);
7720 XFreePixmap(xDisplay, buf);
7722 buf = XCreatePixmap(xDisplay, xBoardWindow,
7723 squareSize, squareSize, pieceDepth);
7724 values.foreground = XBlackPixel(xDisplay, xScreen);
7725 values.background = XWhitePixel(xDisplay, xScreen);
7726 bufGC = XCreateGC(xDisplay, buf,
7727 GCForeground | GCBackground, &values);
7729 for (piece = WhitePawn; piece <= BlackKing; piece++) {
7730 /* Begin with empty mask */
7731 if(!xpmDone) // [HGM] pieces: keep using existing
7732 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
7733 squareSize, squareSize, 1);
7734 XSetFunction(xDisplay, maskGC, GXclear);
7735 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
7736 0, 0, squareSize, squareSize);
7738 /* Take a copy of the piece */
7743 XSetFunction(xDisplay, bufGC, GXcopy);
7744 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
7746 0, 0, squareSize, squareSize, 0, 0);
7748 /* XOR the background (light) over the piece */
7749 XSetFunction(xDisplay, bufGC, GXxor);
7751 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
7752 0, 0, squareSize, squareSize, 0, 0);
7754 XSetForeground(xDisplay, bufGC, lightSquareColor);
7755 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
7758 /* We now have an inverted piece image with the background
7759 erased. Construct mask by just selecting all the non-zero
7760 pixels - no need to reconstruct the original image. */
7761 XSetFunction(xDisplay, maskGC, GXor);
7763 /* Might be quicker to download an XImage and create bitmap
7764 data from it rather than this N copies per piece, but it
7765 only takes a fraction of a second and there is a much
7766 longer delay for loading the pieces. */
7767 for (n = 0; n < pieceDepth; n ++) {
7768 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
7769 0, 0, squareSize, squareSize,
7775 XFreePixmap(xDisplay, buf);
7776 XFreeGC(xDisplay, bufGC);
7777 XFreeGC(xDisplay, maskGC);
7781 InitAnimState (AnimState *anim, XWindowAttributes *info)
7786 /* Each buffer is square size, same depth as window */
7787 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
7788 squareSize, squareSize, info->depth);
7789 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
7790 squareSize, squareSize, info->depth);
7792 /* Create a plain GC for blitting */
7793 mask = GCForeground | GCBackground | GCFunction |
7794 GCPlaneMask | GCGraphicsExposures;
7795 values.foreground = XBlackPixel(xDisplay, xScreen);
7796 values.background = XWhitePixel(xDisplay, xScreen);
7797 values.function = GXcopy;
7798 values.plane_mask = AllPlanes;
7799 values.graphics_exposures = False;
7800 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
7802 /* Piece will be copied from an existing context at
7803 the start of each new animation/drag. */
7804 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
7806 /* Outline will be a read-only copy of an existing */
7807 anim->outlineGC = None;
7813 XWindowAttributes info;
7815 if (xpmDone && gameInfo.variant == oldVariant) return;
7816 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
7817 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
7819 InitAnimState(&game, &info);
7820 InitAnimState(&player, &info);
7822 /* For XPM pieces, we need bitmaps to use as masks. */
7824 CreateAnimMasks(info.depth), xpmDone = 1;
7829 static Boolean frameWaiting;
7832 FrameAlarm (int sig)
7834 frameWaiting = False;
7835 /* In case System-V style signals. Needed?? */
7836 signal(SIGALRM, FrameAlarm);
7840 FrameDelay (int time)
7842 struct itimerval delay;
7844 XSync(xDisplay, False);
7847 frameWaiting = True;
7848 signal(SIGALRM, FrameAlarm);
7849 delay.it_interval.tv_sec =
7850 delay.it_value.tv_sec = time / 1000;
7851 delay.it_interval.tv_usec =
7852 delay.it_value.tv_usec = (time % 1000) * 1000;
7853 setitimer(ITIMER_REAL, &delay, NULL);
7854 while (frameWaiting) pause();
7855 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
7856 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
7857 setitimer(ITIMER_REAL, &delay, NULL);
7864 FrameDelay (int time)
7866 XSync(xDisplay, False);
7868 usleep(time * 1000);
7879 /* Convert board position to corner of screen rect and color */
7882 ScreenSquare (int column, int row, XPoint *pt, int *color)
7885 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
7886 pt->y = lineGap + row * (squareSize + lineGap);
7888 pt->x = lineGap + column * (squareSize + lineGap);
7889 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
7891 *color = SquareColor(row, column);
7894 /* Convert window coords to square */
7897 BoardSquare (int x, int y, int *column, int *row)
7899 *column = EventToSquare(x, BOARD_WIDTH);
7900 if (flipView && *column >= 0)
7901 *column = BOARD_WIDTH - 1 - *column;
7902 *row = EventToSquare(y, BOARD_HEIGHT);
7903 if (!flipView && *row >= 0)
7904 *row = BOARD_HEIGHT - 1 - *row;
7909 #undef Max /* just in case */
7911 #define Max(a, b) ((a) > (b) ? (a) : (b))
7912 #define Min(a, b) ((a) < (b) ? (a) : (b))
7915 SetRect (XRectangle *rect, int x, int y, int width, int height)
7919 rect->width = width;
7920 rect->height = height;
7923 /* Test if two frames overlap. If they do, return
7924 intersection rect within old and location of
7925 that rect within new. */
7928 Intersect ( XPoint *old, XPoint *new, int size, XRectangle *area, XPoint *pt)
7930 if (old->x > new->x + size || new->x > old->x + size ||
7931 old->y > new->y + size || new->y > old->y + size) {
7934 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
7935 size - abs(old->x - new->x), size - abs(old->y - new->y));
7936 pt->x = Max(old->x - new->x, 0);
7937 pt->y = Max(old->y - new->y, 0);
7942 /* For two overlapping frames, return the rect(s)
7943 in the old that do not intersect with the new. */
7946 CalcUpdateRects (XPoint *old, XPoint *new, int size, XRectangle update[], int *nUpdates)
7950 /* If old = new (shouldn't happen) then nothing to draw */
7951 if (old->x == new->x && old->y == new->y) {
7955 /* Work out what bits overlap. Since we know the rects
7956 are the same size we don't need a full intersect calc. */
7958 /* Top or bottom edge? */
7959 if (new->y > old->y) {
7960 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
7962 } else if (old->y > new->y) {
7963 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
7964 size, old->y - new->y);
7967 /* Left or right edge - don't overlap any update calculated above. */
7968 if (new->x > old->x) {
7969 SetRect(&(update[count]), old->x, Max(new->y, old->y),
7970 new->x - old->x, size - abs(new->y - old->y));
7972 } else if (old->x > new->x) {
7973 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
7974 old->x - new->x, size - abs(new->y - old->y));
7981 /* Generate a series of frame coords from start->mid->finish.
7982 The movement rate doubles until the half way point is
7983 reached, then halves back down to the final destination,
7984 which gives a nice slow in/out effect. The algorithmn
7985 may seem to generate too many intermediates for short
7986 moves, but remember that the purpose is to attract the
7987 viewers attention to the piece about to be moved and
7988 then to where it ends up. Too few frames would be less
7992 Tween (XPoint *start, XPoint *mid, XPoint *finish, int factor, XPoint frames[], int *nFrames)
7994 int fraction, n, count;
7998 /* Slow in, stepping 1/16th, then 1/8th, ... */
8000 for (n = 0; n < factor; n++)
8002 for (n = 0; n < factor; n++) {
8003 frames[count].x = start->x + (mid->x - start->x) / fraction;
8004 frames[count].y = start->y + (mid->y - start->y) / fraction;
8006 fraction = fraction / 2;
8010 frames[count] = *mid;
8013 /* Slow out, stepping 1/2, then 1/4, ... */
8015 for (n = 0; n < factor; n++) {
8016 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8017 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8019 fraction = fraction * 2;
8024 /* Draw a piece on the screen without disturbing what's there */
8027 SelectGCMask (ChessSquare piece, GC *clip, GC *outline, Pixmap *mask)
8031 /* Bitmap for piece being moved. */
8032 if (appData.monoMode) {
8033 *mask = *pieceToSolid(piece);
8034 } else if (useImages) {
8036 *mask = xpmMask[piece];
8038 *mask = ximMaskPm[piece];
8041 *mask = *pieceToSolid(piece);
8044 /* GC for piece being moved. Square color doesn't matter, but
8045 since it gets modified we make a copy of the original. */
8047 if (appData.monoMode)
8052 if (appData.monoMode)
8057 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8059 /* Outline only used in mono mode and is not modified */
8061 *outline = bwPieceGC;
8063 *outline = wbPieceGC;
8067 OverlayPiece (ChessSquare piece, GC clip, GC outline, Drawable dest)
8072 /* Draw solid rectangle which will be clipped to shape of piece */
8073 XFillRectangle(xDisplay, dest, clip,
8074 0, 0, squareSize, squareSize);
8075 if (appData.monoMode)
8076 /* Also draw outline in contrasting color for black
8077 on black / white on white cases */
8078 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8079 0, 0, squareSize, squareSize, 0, 0, 1);
8081 /* Copy the piece */
8086 if(appData.upsideDown && flipView) kind ^= 2;
8087 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8089 0, 0, squareSize, squareSize,
8094 /* Animate the movement of a single piece */
8097 BeginAnimation (AnimState *anim, ChessSquare piece, int startColor, XPoint *start)
8101 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8102 /* The old buffer is initialised with the start square (empty) */
8103 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8104 anim->prevFrame = *start;
8106 /* The piece will be drawn using its own bitmap as a matte */
8107 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8108 XSetClipMask(xDisplay, anim->pieceGC, mask);
8112 AnimationFrame (AnimState *anim, XPoint *frame, ChessSquare piece)
8114 XRectangle updates[4];
8119 /* Save what we are about to draw into the new buffer */
8120 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8121 frame->x, frame->y, squareSize, squareSize,
8124 /* Erase bits of the previous frame */
8125 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8126 /* Where the new frame overlapped the previous,
8127 the contents in newBuf are wrong. */
8128 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8129 overlap.x, overlap.y,
8130 overlap.width, overlap.height,
8132 /* Repaint the areas in the old that don't overlap new */
8133 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8134 for (i = 0; i < count; i++)
8135 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8136 updates[i].x - anim->prevFrame.x,
8137 updates[i].y - anim->prevFrame.y,
8138 updates[i].width, updates[i].height,
8139 updates[i].x, updates[i].y);
8141 /* Easy when no overlap */
8142 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8143 0, 0, squareSize, squareSize,
8144 anim->prevFrame.x, anim->prevFrame.y);
8147 /* Save this frame for next time round */
8148 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8149 0, 0, squareSize, squareSize,
8151 anim->prevFrame = *frame;
8153 /* Draw piece over original screen contents, not current,
8154 and copy entire rect. Wipes out overlapping piece images. */
8155 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8156 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8157 0, 0, squareSize, squareSize,
8158 frame->x, frame->y);
8162 EndAnimation (AnimState *anim, XPoint *finish)
8164 XRectangle updates[4];
8169 /* The main code will redraw the final square, so we
8170 only need to erase the bits that don't overlap. */
8171 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8172 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8173 for (i = 0; i < count; i++)
8174 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8175 updates[i].x - anim->prevFrame.x,
8176 updates[i].y - anim->prevFrame.y,
8177 updates[i].width, updates[i].height,
8178 updates[i].x, updates[i].y);
8180 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8181 0, 0, squareSize, squareSize,
8182 anim->prevFrame.x, anim->prevFrame.y);
8187 FrameSequence (AnimState *anim, ChessSquare piece, int startColor, XPoint *start, XPoint *finish, XPoint frames[], int nFrames)
8191 BeginAnimation(anim, piece, startColor, start);
8192 for (n = 0; n < nFrames; n++) {
8193 AnimationFrame(anim, &(frames[n]), piece);
8194 FrameDelay(appData.animSpeed);
8196 EndAnimation(anim, finish);
8200 AnimateAtomicCapture (Board board, int fromX, int fromY, int toX, int toY)
8203 ChessSquare piece = board[fromY][toY];
8204 board[fromY][toY] = EmptySquare;
8205 DrawPosition(FALSE, board);
8207 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8208 y = lineGap + toY * (squareSize + lineGap);
8210 x = lineGap + toX * (squareSize + lineGap);
8211 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8213 for(i=1; i<4*kFactor; i++) {
8214 int r = squareSize * 9 * i/(20*kFactor - 5);
8215 XFillArc(xDisplay, xBoardWindow, highlineGC,
8216 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8217 FrameDelay(appData.animSpeed);
8219 board[fromY][toY] = piece;
8222 /* Main control logic for deciding what to animate and how */
8225 AnimateMove (Board board, int fromX, int fromY, int toX, int toY)
8229 XPoint start, finish, mid;
8230 XPoint frames[kFactor * 2 + 1];
8231 int nFrames, startColor, endColor;
8233 /* Are we animating? */
8234 if (!appData.animate || appData.blindfold)
8237 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8238 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8239 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8241 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8242 piece = board[fromY][fromX];
8243 if (piece >= EmptySquare) return;
8248 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8251 if (appData.debugMode) {
8252 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8253 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8254 piece, fromX, fromY, toX, toY); }
8256 ScreenSquare(fromX, fromY, &start, &startColor);
8257 ScreenSquare(toX, toY, &finish, &endColor);
8260 /* Knight: make straight movement then diagonal */
8261 if (abs(toY - fromY) < abs(toX - fromX)) {
8262 mid.x = start.x + (finish.x - start.x) / 2;
8266 mid.y = start.y + (finish.y - start.y) / 2;
8269 mid.x = start.x + (finish.x - start.x) / 2;
8270 mid.y = start.y + (finish.y - start.y) / 2;
8273 /* Don't use as many frames for very short moves */
8274 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8275 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8277 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8278 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8279 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8281 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8282 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8285 /* Be sure end square is redrawn */
8286 damage[0][toY][toX] = True;
8290 DragPieceBegin (int x, int y, Boolean instantly)
8292 int boardX, boardY, color;
8295 /* Are we animating? */
8296 if (!appData.animateDragging || appData.blindfold)
8299 /* Figure out which square we start in and the
8300 mouse position relative to top left corner. */
8301 BoardSquare(x, y, &boardX, &boardY);
8302 player.startBoardX = boardX;
8303 player.startBoardY = boardY;
8304 ScreenSquare(boardX, boardY, &corner, &color);
8305 player.startSquare = corner;
8306 player.startColor = color;
8307 /* As soon as we start dragging, the piece will jump slightly to
8308 be centered over the mouse pointer. */
8309 player.mouseDelta.x = squareSize/2;
8310 player.mouseDelta.y = squareSize/2;
8311 /* Initialise animation */
8312 player.dragPiece = PieceForSquare(boardX, boardY);
8314 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8315 player.dragActive = True;
8316 BeginAnimation(&player, player.dragPiece, color, &corner);
8317 /* Mark this square as needing to be redrawn. Note that
8318 we don't remove the piece though, since logically (ie
8319 as seen by opponent) the move hasn't been made yet. */
8320 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8321 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8322 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8323 corner.x, corner.y, squareSize, squareSize,
8324 0, 0); // [HGM] zh: unstack in stead of grab
8325 if(gatingPiece != EmptySquare) {
8326 /* Kludge alert: When gating we want the introduced
8327 piece to appear on the from square. To generate an
8328 image of it, we draw it on the board, copy the image,
8329 and draw the original piece again. */
8330 ChessSquare piece = boards[currentMove][boardY][boardX];
8331 DrawSquare(boardY, boardX, gatingPiece, 0);
8332 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8333 corner.x, corner.y, squareSize, squareSize, 0, 0);
8334 DrawSquare(boardY, boardX, piece, 0);
8336 damage[0][boardY][boardX] = True;
8338 player.dragActive = False;
8343 ChangeDragPiece (ChessSquare piece)
8346 player.dragPiece = piece;
8347 /* The piece will be drawn using its own bitmap as a matte */
8348 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8349 XSetClipMask(xDisplay, player.pieceGC, mask);
8353 DragPieceMove (int x, int y)
8357 /* Are we animating? */
8358 if (!appData.animateDragging || appData.blindfold)
8362 if (! player.dragActive)
8364 /* Move piece, maintaining same relative position
8365 of mouse within square */
8366 corner.x = x - player.mouseDelta.x;
8367 corner.y = y - player.mouseDelta.y;
8368 AnimationFrame(&player, &corner, player.dragPiece);
8370 if (appData.highlightDragging) {
8372 BoardSquare(x, y, &boardX, &boardY);
8373 SetHighlights(fromX, fromY, boardX, boardY);
8379 DragPieceEnd (int x, int y)
8381 int boardX, boardY, color;
8384 /* Are we animating? */
8385 if (!appData.animateDragging || appData.blindfold)
8389 if (! player.dragActive)
8391 /* Last frame in sequence is square piece is
8392 placed on, which may not match mouse exactly. */
8393 BoardSquare(x, y, &boardX, &boardY);
8394 ScreenSquare(boardX, boardY, &corner, &color);
8395 EndAnimation(&player, &corner);
8397 /* Be sure end square is redrawn */
8398 damage[0][boardY][boardX] = True;
8400 /* This prevents weird things happening with fast successive
8401 clicks which on my Sun at least can cause motion events
8402 without corresponding press/release. */
8403 player.dragActive = False;
8406 /* Handle expose event while piece being dragged */
8411 if (!player.dragActive || appData.blindfold)
8414 /* What we're doing: logically, the move hasn't been made yet,
8415 so the piece is still in it's original square. But visually
8416 it's being dragged around the board. So we erase the square
8417 that the piece is on and draw it at the last known drag point. */
8418 BlankSquare(player.startSquare.x, player.startSquare.y,
8419 player.startColor, EmptySquare, xBoardWindow, 1);
8420 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8421 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8424 #include <sys/ioctl.h>
8428 int fd, default_width;
8431 default_width = 79; // this is FICS default anyway...
8433 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8435 if (!ioctl(fd, TIOCGSIZE, &win))
8436 default_width = win.ts_cols;
8437 #elif defined(TIOCGWINSZ)
8439 if (!ioctl(fd, TIOCGWINSZ, &win))
8440 default_width = win.ws_col;
8442 return default_width;
8448 static int old_width = 0;
8449 int new_width = get_term_width();
8451 if (old_width != new_width)
8452 ics_printf("set width %d\n", new_width);
8453 old_width = new_width;
8457 NotifyFrontendLogin ()
8462 /* [AS] Arrow highlighting support */
8464 static double A_WIDTH = 5; /* Width of arrow body */
8466 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8467 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8478 return (int) (x + 0.5);
8482 SquareToPos (int rank, int file, int *x, int *y)
8485 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8486 *y = lineGap + rank * (squareSize + lineGap);
8488 *x = lineGap + file * (squareSize + lineGap);
8489 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8493 /* Draw an arrow between two points using current settings */
8495 DrawArrowBetweenPoints (int s_x, int s_y, int d_x, int d_y)
8498 double dx, dy, j, k, x, y;
8501 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8503 arrow[0].x = s_x + A_WIDTH + 0.5;
8506 arrow[1].x = s_x + A_WIDTH + 0.5;
8507 arrow[1].y = d_y - h;
8509 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8510 arrow[2].y = d_y - h;
8515 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8516 arrow[5].y = d_y - h;
8518 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8519 arrow[4].y = d_y - h;
8521 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8524 else if( d_y == s_y ) {
8525 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8528 arrow[0].y = s_y + A_WIDTH + 0.5;
8530 arrow[1].x = d_x - w;
8531 arrow[1].y = s_y + A_WIDTH + 0.5;
8533 arrow[2].x = d_x - w;
8534 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8539 arrow[5].x = d_x - w;
8540 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8542 arrow[4].x = d_x - w;
8543 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8546 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8549 /* [AS] Needed a lot of paper for this! :-) */
8550 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8551 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8553 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8555 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8560 arrow[0].x = Round(x - j);
8561 arrow[0].y = Round(y + j*dx);
8563 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8564 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8567 x = (double) d_x - k;
8568 y = (double) d_y - k*dy;
8571 x = (double) d_x + k;
8572 y = (double) d_y + k*dy;
8575 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8577 arrow[6].x = Round(x - j);
8578 arrow[6].y = Round(y + j*dx);
8580 arrow[2].x = Round(arrow[6].x + 2*j);
8581 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8583 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8584 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8589 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8590 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
8593 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
8594 if(appData.monoMode) arrow[7] = arrow[0], XDrawLines(xDisplay, xBoardWindow, darkSquareGC, arrow, 8, CoordModeOrigin);
8595 // Polygon( hdc, arrow, 7 );
8599 ArrowDamage (int s_col, int s_row, int d_col, int d_row)
8602 hor = 64*s_col + 32; vert = 64*s_row + 32;
8603 for(i=0; i<= 64; i++) {
8604 damage[0][vert+6>>6][hor+6>>6] = True;
8605 damage[0][vert-6>>6][hor+6>>6] = True;
8606 damage[0][vert+6>>6][hor-6>>6] = True;
8607 damage[0][vert-6>>6][hor-6>>6] = True;
8608 hor += d_col - s_col; vert += d_row - s_row;
8612 /* [AS] Draw an arrow between two squares */
8614 DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
8616 int s_x, s_y, d_x, d_y;
8618 if( s_col == d_col && s_row == d_row ) {
8622 /* Get source and destination points */
8623 SquareToPos( s_row, s_col, &s_x, &s_y);
8624 SquareToPos( d_row, d_col, &d_x, &d_y);
8627 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
8629 else if( d_y < s_y ) {
8630 d_y += squareSize / 2 + squareSize / 4;
8633 d_y += squareSize / 2;
8637 d_x += squareSize / 2 - squareSize / 4;
8639 else if( d_x < s_x ) {
8640 d_x += squareSize / 2 + squareSize / 4;
8643 d_x += squareSize / 2;
8646 s_x += squareSize / 2;
8647 s_y += squareSize / 2;
8650 A_WIDTH = squareSize / 14.; //[HGM] make float
8652 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
8653 ArrowDamage(s_col, s_row, d_col, d_row);
8657 IsDrawArrowEnabled ()
8659 return appData.highlightMoveWithArrow && squareSize >= 32;
8663 DrawArrowHighlight (int fromX, int fromY, int toX,int toY)
8665 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
8666 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
8670 UpdateLogos (int displ)
8672 return; // no logos in XBoard yet