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 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)
243 int main P((int argc, char **argv));
244 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
245 char *init_path, char *filter, char *mode, int (*show_entry)(), char **name_return));
246 RETSIGTYPE CmailSigHandler P((int sig));
247 RETSIGTYPE IntSigHandler P((int sig));
248 RETSIGTYPE TermSizeSigHandler P((int sig));
249 void CreateGCs P((int redo));
250 void CreateAnyPieces P((void));
251 void CreateXIMPieces P((void));
252 void CreateXPMPieces P((void));
253 void CreateXPMBoard P((char *s, int n));
254 void CreatePieces P((void));
255 void CreatePieceMenus P((void));
256 Widget CreateMenuBar P((Menu *mb));
257 Widget CreateButtonBar P ((MenuItem *mi));
259 char *InsertPxlSize P((char *pattern, int targetPxlSize));
260 XFontSet CreateFontSet P((char *base_fnt_lst));
262 char *FindFont P((char *pattern, int targetPxlSize));
264 void PieceMenuPopup P((Widget w, XEvent *event,
265 String *params, Cardinal *num_params));
266 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
267 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
268 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
269 u_int wreq, u_int hreq));
270 void CreateGrid P((void));
271 int EventToSquare P((int x, int limit));
272 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
273 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
274 void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
275 void HandleUserMove P((Widget w, XEvent *event,
276 String *prms, Cardinal *nprms));
277 void AnimateUserMove P((Widget w, XEvent * event,
278 String * params, Cardinal * nParams));
279 void HandlePV P((Widget w, XEvent * event,
280 String * params, Cardinal * nParams));
281 void SelectPV P((Widget w, XEvent * event,
282 String * params, Cardinal * nParams));
283 void StopPV P((Widget w, XEvent * event,
284 String * params, Cardinal * nParams));
285 void WhiteClock P((Widget w, XEvent *event,
286 String *prms, Cardinal *nprms));
287 void BlackClock P((Widget w, XEvent *event,
288 String *prms, Cardinal *nprms));
289 void DrawPositionProc P((Widget w, XEvent *event,
290 String *prms, Cardinal *nprms));
291 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
293 void CommentClick P((Widget w, XEvent * event,
294 String * params, Cardinal * nParams));
295 void CommentPopUp P((char *title, char *label));
296 void CommentPopDown P((void));
297 void ICSInputBoxPopUp P((void));
298 void ICSInputBoxPopDown P((void));
299 void FileNamePopUp P((char *label, char *def, char *filter,
300 FileProc proc, char *openMode));
301 void FileNamePopDown P((void));
302 void FileNameCallback P((Widget w, XtPointer client_data,
303 XtPointer call_data));
304 void FileNameAction P((Widget w, XEvent *event,
305 String *prms, Cardinal *nprms));
306 void AskQuestionReplyAction P((Widget w, XEvent *event,
307 String *prms, Cardinal *nprms));
308 void AskQuestionProc P((Widget w, XEvent *event,
309 String *prms, Cardinal *nprms));
310 void AskQuestionPopDown P((void));
311 void PromotionPopDown P((void));
312 void PromotionCallback P((Widget w, XtPointer client_data,
313 XtPointer call_data));
314 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
315 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
316 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
317 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
321 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
323 void LoadPositionProc P((Widget w, XEvent *event,
324 String *prms, Cardinal *nprms));
325 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
327 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
329 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
333 void PastePositionProc P((Widget w, XEvent *event, String *prms,
335 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
336 void CopyGameListProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
338 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
339 void SavePositionProc P((Widget w, XEvent *event,
340 String *prms, Cardinal *nprms));
341 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
342 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
344 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
345 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
346 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
348 void MachineWhiteProc P((Widget w, XEvent *event,
349 String *prms, Cardinal *nprms));
350 void AnalyzeModeProc P((Widget w, XEvent *event,
351 String *prms, Cardinal *nprms));
352 void AnalyzeFileProc P((Widget w, XEvent *event,
353 String *prms, Cardinal *nprms));
354 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
356 void MatchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void MatchOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
358 void IcsClientProc P((Widget w, XEvent *event, String *prms,
360 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
361 void EditPositionProc P((Widget w, XEvent *event,
362 String *prms, Cardinal *nprms));
363 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void EditCommentProc P((Widget w, XEvent *event,
365 String *prms, Cardinal *nprms));
366 void IcsInputBoxProc P((Widget w, XEvent *event,
367 String *prms, Cardinal *nprms));
368 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
376 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
377 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
378 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
379 void TypeInProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void StopObservingProc P((Widget w, XEvent *event, String *prms,
385 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
387 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
388 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
389 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
390 void TempBackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void TempForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
392 Boolean TempBackwardActive = False;
393 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
394 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
395 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
396 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
397 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
399 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
401 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
402 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
404 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
406 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
408 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
410 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
411 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
413 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
414 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
416 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
418 void HighlightArrowProc P((Widget w, XEvent *event, String *prms,
420 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
421 //void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
422 void OneClickProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
423 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
425 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
427 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
429 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
431 //void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
432 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
434 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
436 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
438 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
440 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
449 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
450 void DisplayMove P((int moveNumber));
451 void DisplayTitle P((char *title));
452 void ICSInitScript P((void));
453 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
454 void ErrorPopUp P((char *title, char *text, int modal));
455 void ErrorPopDown P((void));
456 static char *ExpandPathName P((char *path));
457 static void CreateAnimVars P((void));
458 static void DragPieceMove P((int x, int y));
459 static void DrawDragPiece P((void));
460 char *ModeToWidgetName P((GameMode mode));
461 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void OptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void IcsTextProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
468 void LoadEngineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
469 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
470 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
471 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
472 void IcsOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
473 void SoundOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
474 void BoardOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
475 void LoadOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
476 void SaveOptionsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
477 void EditBookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
478 void SelectMove P((Widget w, XEvent * event, String * params, Cardinal * nParams));
479 void GameListOptionsPopDown P(());
480 void GenericPopDown P(());
481 void update_ics_width P(());
482 int get_term_width P(());
483 int CopyMemoProc P(());
484 void DrawArrowHighlight P((int fromX, int fromY, int toX,int toY));
485 Boolean IsDrawArrowEnabled P(());
488 * XBoard depends on Xt R4 or higher
490 int xtVersion = XtSpecificationRelease;
495 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
496 jailSquareColor, highlightSquareColor, premoveHighlightColor;
497 Pixel lowTimeWarningColor;
498 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
499 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
500 wjPieceGC, bjPieceGC, prelineGC, countGC;
501 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
502 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
503 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
504 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
505 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
506 ICSInputShell, fileNameShell, askQuestionShell;
507 Widget historyShell, evalGraphShell, gameListShell;
508 int hOffset; // [HGM] dual
509 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
510 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
511 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
513 XFontSet fontSet, clockFontSet;
516 XFontStruct *clockFontStruct;
518 Font coordFontID, countFontID;
519 XFontStruct *coordFontStruct, *countFontStruct;
520 XtAppContext appContext;
522 char *oldICSInteractionTitle;
526 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
528 Position commentX = -1, commentY = -1;
529 Dimension commentW, commentH;
530 typedef unsigned int BoardSize;
532 Boolean chessProgram;
534 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
535 int squareSize, smallLayout = 0, tinyLayout = 0,
536 marginW, marginH, // [HGM] for run-time resizing
537 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
538 ICSInputBoxUp = False, askQuestionUp = False,
539 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
540 errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
541 Pixel timerForegroundPixel, timerBackgroundPixel;
542 Pixel buttonForegroundPixel, buttonBackgroundPixel;
543 char *chessDir, *programName, *programVersion,
544 *gameCopyFilename, *gamePasteFilename;
545 Boolean alwaysOnTop = False;
546 Boolean saveSettingsOnExit;
547 char *settingsFileName;
548 char *icsTextMenuString;
550 char *firstChessProgramNames;
551 char *secondChessProgramNames;
553 WindowPlacement wpMain;
554 WindowPlacement wpConsole;
555 WindowPlacement wpComment;
556 WindowPlacement wpMoveHistory;
557 WindowPlacement wpEvalGraph;
558 WindowPlacement wpEngineOutput;
559 WindowPlacement wpGameList;
560 WindowPlacement wpTags;
562 extern Widget shells[];
563 extern Boolean shellUp[];
567 Pixmap pieceBitmap[2][(int)BlackPawn];
568 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
569 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
570 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
571 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
572 Pixmap xpmBoardBitmap[2];
573 int useImages, useImageSqs, useTexture, textureW[2], textureH[2];
574 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
575 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
576 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
577 XImage *ximLightSquare, *ximDarkSquare;
580 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
581 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
583 #define White(piece) ((int)(piece) < (int)BlackPawn)
585 /* Variables for doing smooth animation. This whole thing
586 would be much easier if the board was double-buffered,
587 but that would require a fairly major rewrite. */
592 GC blitGC, pieceGC, outlineGC;
593 XPoint startSquare, prevFrame, mouseDelta;
597 int startBoardX, startBoardY;
600 /* There can be two pieces being animated at once: a player
601 can begin dragging a piece before the remote opponent has moved. */
603 static AnimState game, player;
605 /* Bitmaps for use as masks when drawing XPM pieces.
606 Need one for each black and white piece. */
607 static Pixmap xpmMask[BlackKing + 1];
609 /* This magic number is the number of intermediate frames used
610 in each half of the animation. For short moves it's reduced
611 by 1. The total number of frames will be factor * 2 + 1. */
614 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
616 MenuItem fileMenu[] = {
617 {N_("New Game Ctrl+N"), "New Game", ResetProc},
618 {N_("New Shuffle Game ..."), "New Shuffle Game", ShuffleMenuProc},
619 {N_("New Variant ... Alt+Shift+V"), "New Variant", NewVariantProc}, // [HGM] variant: not functional yet
620 {"----", NULL, NothingProc},
621 {N_("Load Game Ctrl+O"), "Load Game", LoadGameProc},
622 {N_("Load Position Ctrl+Shift+O"), "Load Position", LoadPositionProc},
623 // {N_("Load Next Game"), "Load Next Game", LoadNextGameProc},
624 // {N_("Load Previous Game"), "Load Previous Game", LoadPrevGameProc},
625 // {N_("Reload Same Game"), "Reload Same Game", ReloadGameProc},
626 {N_("Next Position Shift+PgDn"), "Load Next Position", LoadNextPositionProc},
627 {N_("Prev Position Shift+PgUp"), "Load Previous Position", LoadPrevPositionProc},
628 {"----", NULL, NothingProc},
629 // {N_("Reload Same Position"), "Reload Same Position", ReloadPositionProc},
630 {N_("Save Game Ctrl+S"), "Save Game", SaveGameProc},
631 {N_("Save Position Ctrl+Shift+S"), "Save Position", SavePositionProc},
632 {"----", NULL, NothingProc},
633 {N_("Mail Move"), "Mail Move", MailMoveProc},
634 {N_("Reload CMail Message"), "Reload CMail Message", ReloadCmailMsgProc},
635 {"----", NULL, NothingProc},
636 {N_("Quit Ctr+Q"), "Exit", QuitProc},
640 MenuItem editMenu[] = {
641 {N_("Copy Game Ctrl+C"), "Copy Game", CopyGameProc},
642 {N_("Copy Position Ctrl+Shift+C"), "Copy Position", CopyPositionProc},
643 {N_("Copy Game List"), "Copy Game List", CopyGameListProc},
644 {"----", NULL, NothingProc},
645 {N_("Paste Game Ctrl+V"), "Paste Game", PasteGameProc},
646 {N_("Paste Position Ctrl+Shift+V"), "Paste Position", PastePositionProc},
647 {"----", NULL, NothingProc},
648 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
649 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
650 {N_("Edit Tags"), "Edit Tags", EditTagsProc},
651 {N_("Edit Comment"), "Edit Comment", EditCommentProc},
652 {N_("Edit Book"), "Edit Book", EditBookProc},
653 {"----", NULL, NothingProc},
654 {N_("Revert Home"), "Revert", RevertProc},
655 {N_("Annotate"), "Annotate", AnnotateProc},
656 {N_("Truncate Game End"), "Truncate Game", TruncateGameProc},
657 {"----", NULL, NothingProc},
658 {N_("Backward Alt+Left"), "Backward", BackwardProc},
659 {N_("Forward Alt+Right"), "Forward", ForwardProc},
660 {N_("Back to Start Alt+Home"), "Back to Start", ToStartProc},
661 {N_("Forward to End Alt+End"), "Forward to End", ToEndProc},
665 MenuItem viewMenu[] = {
666 {N_("Flip View F2"), "Flip View", FlipViewProc},
667 {"----", NULL, NothingProc},
668 {N_("Engine Output Alt+Shift+O"), "Show Engine Output", EngineOutputProc},
669 {N_("Move History Alt+Shift+H"), "Show Move History", HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
670 {N_("Evaluation Graph Alt+Shift+E"), "Show Evaluation Graph", EvalGraphProc},
671 {N_("Game List Alt+Shift+G"), "Show Game List", ShowGameListProc},
672 {N_("ICS text menu"), "ICStex", IcsTextProc},
673 {"----", NULL, NothingProc},
674 {N_("Tags"), "Show Tags", EditTagsProc},
675 {N_("Comments"), "Show Comments", EditCommentProc},
676 {N_("ICS Input Box"), "ICS Input Box", IcsInputBoxProc},
677 {"----", NULL, NothingProc},
678 {N_("Board..."), "Board Options", BoardOptionsProc},
679 {N_("Game List Tags..."), "Game List", GameListOptionsPopUp},
683 MenuItem modeMenu[] = {
684 {N_("Machine White Ctrl+W"), "Machine White", MachineWhiteProc},
685 {N_("Machine Black Ctrl+B"), "Machine Black", MachineBlackProc},
686 {N_("Two Machines Ctrl+T"), "Two Machines", TwoMachinesProc},
687 {N_("Analysis Mode Ctrl+A"), "Analysis Mode", AnalyzeModeProc},
688 {N_("Analyze Game Ctrl+G"), "Analyze File", AnalyzeFileProc },
689 {N_("Edit Game Ctrl+E"), "Edit Game", EditGameProc},
690 {N_("Edit Position Ctrl+Shift+E"), "Edit Position", EditPositionProc},
691 {N_("Training"), "Training", TrainingProc},
692 {N_("ICS Client"), "ICS Client", IcsClientProc},
693 {"----", NULL, NothingProc},
694 {N_("Machine Match"), "Machine Match", MatchProc},
695 {N_("Pause Pause"), "Pause", PauseProc},
699 MenuItem actionMenu[] = {
700 {N_("Accept F3"), "Accept", AcceptProc},
701 {N_("Decline F4"), "Decline", DeclineProc},
702 {N_("Rematch F12"), "Rematch", RematchProc},
703 {"----", NULL, NothingProc},
704 {N_("Call Flag F5"), "Call Flag", CallFlagProc},
705 {N_("Draw F6"), "Draw", DrawProc},
706 {N_("Adjourn F7"), "Adjourn", AdjournProc},
707 {N_("Abort F8"),"Abort", AbortProc},
708 {N_("Resign F9"), "Resign", ResignProc},
709 {"----", NULL, NothingProc},
710 {N_("Stop Observing F10"), "Stop Observing", StopObservingProc},
711 {N_("Stop Examining F11"), "Stop Examining", StopExaminingProc},
712 {N_("Upload to Examine"), "Upload to Examine", UploadProc},
713 {"----", NULL, NothingProc},
714 {N_("Adjudicate to White"), "Adjudicate to White", AdjuWhiteProc},
715 {N_("Adjudicate to Black"), "Adjudicate to Black", AdjuBlackProc},
716 {N_("Adjudicate Draw"), "Adjudicate Draw", AdjuDrawProc},
720 MenuItem engineMenu[] = {
721 {N_("Load New Engine ..."), "Load Engine", LoadEngineProc},
722 {"----", NULL, NothingProc},
723 {N_("Engine #1 Settings ..."), "Engine #1 Settings", FirstSettingsProc},
724 {N_("Engine #2 Settings ..."), "Engine #2 Settings", SecondSettingsProc},
725 {"----", NULL, NothingProc},
726 {N_("Hint"), "Hint", HintProc},
727 {N_("Book"), "Book", BookProc},
728 {"----", NULL, NothingProc},
729 {N_("Move Now Ctrl+M"), "Move Now", MoveNowProc},
730 {N_("Retract Move Ctrl+X"), "Retract Move", RetractMoveProc},
734 MenuItem optionsMenu[] = {
735 #define OPTIONSDIALOG
737 {N_("General ..."), "General", OptionsProc},
739 {N_("Time Control ... Alt+Shift+T"), "Time Control", TimeControlProc},
740 {N_("Common Engine ... Alt+Shift+U"), "Common Engine", UciMenuProc},
741 {N_("Adjudications ... Alt+Shift+J"), "Adjudications", EngineMenuProc},
742 {N_("ICS ..."), "ICS", IcsOptionsProc},
743 {N_("Match ..."), "Match", MatchOptionsProc},
744 {N_("Load Game ..."), "Load Game", LoadOptionsProc},
745 {N_("Save Game ..."), "Save Game", SaveOptionsProc},
746 // {N_(" ..."), "", OptionsProc},
747 {N_("Game List ..."), "Game List", GameListOptionsPopUp},
748 {N_("Sounds ..."), "Sounds", SoundOptionsProc},
749 {"----", NULL, NothingProc},
750 #ifndef OPTIONSDIALOG
751 {N_("Always Queen Ctrl+Shift+Q"), "Always Queen", AlwaysQueenProc},
752 {N_("Animate Dragging"), "Animate Dragging", AnimateDraggingProc},
753 {N_("Animate Moving Ctrl+Shift+A"), "Animate Moving", AnimateMovingProc},
754 {N_("Auto Flag Ctrl+Shift+F"), "Auto Flag", AutoflagProc},
755 {N_("Auto Flip View"), "Auto Flip View", AutoflipProc},
756 {N_("Blindfold"), "Blindfold", BlindfoldProc},
757 {N_("Flash Moves"), "Flash Moves", FlashMovesProc},
759 {N_("Highlight Dragging"), "Highlight Dragging", HighlightDraggingProc},
761 {N_("Highlight Last Move"), "Highlight Last Move", HighlightLastMoveProc},
762 {N_("Highlight With Arrow"), "Arrow", HighlightArrowProc},
763 {N_("Move Sound"), "Move Sound", MoveSoundProc},
764 // {N_("ICS Alarm"), "ICS Alarm", IcsAlarmProc},
765 {N_("One-Click Moving"), "OneClick", OneClickProc},
766 {N_("Periodic Updates"), "Periodic Updates", PeriodicUpdatesProc},
767 {N_("Ponder Next Move Ctrl+Shift+P"), "Ponder Next Move", PonderNextMoveProc},
768 {N_("Popup Exit Message"), "Popup Exit Message", PopupExitMessageProc},
769 {N_("Popup Move Errors"), "Popup Move Errors", PopupMoveErrorsProc},
770 // {N_("Premove"), "Premove", PremoveProc},
771 {N_("Show Coords"), "Show Coords", ShowCoordsProc},
772 {N_("Hide Thinking Ctrl+Shift+H"), "Hide Thinking", HideThinkingProc},
773 {N_("Test Legality Ctrl+Shift+L"), "Test Legality", TestLegalityProc},
774 {"----", NULL, NothingProc},
776 {N_("Save Settings Now"), "Save Settings Now", SaveSettingsProc},
777 {N_("Save Settings on Exit"), "Save Settings on Exit", SaveOnExitProc},
781 MenuItem helpMenu[] = {
782 {N_("Info XBoard"), "Info XBoard", InfoProc},
783 {N_("Man XBoard F1"), "Man XBoard", ManProc},
784 {"----", NULL, NothingProc},
785 {N_("About XBoard"), "About XBoard", AboutProc},
790 {N_("File"), "File", fileMenu},
791 {N_("Edit"), "Edit", editMenu},
792 {N_("View"), "View", viewMenu},
793 {N_("Mode"), "Mode", modeMenu},
794 {N_("Action"), "Action", actionMenu},
795 {N_("Engine"), "Engine", engineMenu},
796 {N_("Options"), "Options", optionsMenu},
797 {N_("Help"), "Help", helpMenu},
801 #define PAUSE_BUTTON "P"
802 MenuItem buttonBar[] = {
803 {"<<", "<<", ToStartProc},
804 {"<", "<", BackwardProc},
805 {N_(PAUSE_BUTTON), PAUSE_BUTTON, PauseProc},
806 {">", ">", ForwardProc},
807 {">>", ">>", ToEndProc},
811 #define PIECE_MENU_SIZE 18
812 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
813 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
814 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
815 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
816 N_("Empty square"), N_("Clear board") },
817 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
818 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
819 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
820 N_("Empty square"), N_("Clear board") }
822 /* must be in same order as pieceMenuStrings! */
823 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
824 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
825 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
826 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
827 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
828 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
829 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
830 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
831 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
834 #define DROP_MENU_SIZE 6
835 String dropMenuStrings[DROP_MENU_SIZE] = {
836 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
838 /* must be in same order as dropMenuStrings! */
839 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
840 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
841 WhiteRook, WhiteQueen
849 DropMenuEnables dmEnables[] = {
867 { XtNborderWidth, 0 },
868 { XtNdefaultDistance, 0 },
872 { XtNborderWidth, 0 },
873 { XtNresizable, (XtArgVal) True },
877 { XtNborderWidth, 0 },
883 { XtNjustify, (XtArgVal) XtJustifyRight },
884 { XtNlabel, (XtArgVal) "..." },
885 { XtNresizable, (XtArgVal) True },
886 { XtNresize, (XtArgVal) False }
889 Arg messageArgs[] = {
890 { XtNjustify, (XtArgVal) XtJustifyLeft },
891 { XtNlabel, (XtArgVal) "..." },
892 { XtNresizable, (XtArgVal) True },
893 { XtNresize, (XtArgVal) False }
897 { XtNborderWidth, 0 },
898 { XtNjustify, (XtArgVal) XtJustifyLeft }
901 XtResource clientResources[] = {
902 { "flashCount", "flashCount", XtRInt, sizeof(int),
903 XtOffset(AppDataPtr, flashCount), XtRImmediate,
904 (XtPointer) FLASH_COUNT },
907 XrmOptionDescRec shellOptions[] = {
908 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
909 { "-flash", "flashCount", XrmoptionNoArg, "3" },
910 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
913 XtActionsRec boardActions[] = {
914 { "DrawPosition", DrawPositionProc },
915 { "HandleUserMove", HandleUserMove },
916 { "AnimateUserMove", AnimateUserMove },
917 { "HandlePV", HandlePV },
918 { "SelectPV", SelectPV },
919 { "StopPV", StopPV },
920 { "FileNameAction", FileNameAction },
921 { "AskQuestionProc", AskQuestionProc },
922 { "AskQuestionReplyAction", AskQuestionReplyAction },
923 { "PieceMenuPopup", PieceMenuPopup },
924 { "WhiteClock", WhiteClock },
925 { "BlackClock", BlackClock },
926 { "ResetProc", ResetProc },
927 { "NewVariantProc", NewVariantProc },
928 { "LoadGameProc", LoadGameProc },
929 { "LoadNextGameProc", LoadNextGameProc },
930 { "LoadPrevGameProc", LoadPrevGameProc },
931 { "LoadSelectedProc", LoadSelectedProc },
932 { "SetFilterProc", SetFilterProc },
933 { "ReloadGameProc", ReloadGameProc },
934 { "LoadPositionProc", LoadPositionProc },
935 { "LoadNextPositionProc", LoadNextPositionProc },
936 { "LoadPrevPositionProc", LoadPrevPositionProc },
937 { "ReloadPositionProc", ReloadPositionProc },
938 { "CopyPositionProc", CopyPositionProc },
939 { "PastePositionProc", PastePositionProc },
940 { "CopyGameProc", CopyGameProc },
941 { "CopyGameListProc", CopyGameListProc },
942 { "PasteGameProc", PasteGameProc },
943 { "SaveGameProc", SaveGameProc },
944 { "SavePositionProc", SavePositionProc },
945 { "MailMoveProc", MailMoveProc },
946 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
947 { "QuitProc", QuitProc },
948 { "MachineWhiteProc", MachineWhiteProc },
949 { "MachineBlackProc", MachineBlackProc },
950 { "AnalysisModeProc", AnalyzeModeProc },
951 { "AnalyzeFileProc", AnalyzeFileProc },
952 { "TwoMachinesProc", TwoMachinesProc },
953 { "IcsClientProc", IcsClientProc },
954 { "EditGameProc", EditGameProc },
955 { "EditPositionProc", EditPositionProc },
956 { "TrainingProc", EditPositionProc },
957 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
958 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
959 { "ShowGameListProc", ShowGameListProc },
960 { "ShowMoveListProc", HistoryShowProc},
961 { "EditTagsProc", EditCommentProc },
962 { "EditBookProc", EditBookProc },
963 { "EditCommentProc", EditCommentProc },
964 { "IcsInputBoxProc", IcsInputBoxProc },
965 { "PauseProc", PauseProc },
966 { "AcceptProc", AcceptProc },
967 { "DeclineProc", DeclineProc },
968 { "RematchProc", RematchProc },
969 { "CallFlagProc", CallFlagProc },
970 { "DrawProc", DrawProc },
971 { "AdjournProc", AdjournProc },
972 { "AbortProc", AbortProc },
973 { "ResignProc", ResignProc },
974 { "AdjuWhiteProc", AdjuWhiteProc },
975 { "AdjuBlackProc", AdjuBlackProc },
976 { "AdjuDrawProc", AdjuDrawProc },
977 { "TypeInProc", TypeInProc },
978 { "EnterKeyProc", EnterKeyProc },
979 { "UpKeyProc", UpKeyProc },
980 { "DownKeyProc", DownKeyProc },
981 { "StopObservingProc", StopObservingProc },
982 { "StopExaminingProc", StopExaminingProc },
983 { "UploadProc", UploadProc },
984 { "BackwardProc", BackwardProc },
985 { "ForwardProc", ForwardProc },
986 { "TempBackwardProc", TempBackwardProc },
987 { "TempForwardProc", TempForwardProc },
988 { "ToStartProc", ToStartProc },
989 { "ToEndProc", ToEndProc },
990 { "RevertProc", RevertProc },
991 { "AnnotateProc", AnnotateProc },
992 { "TruncateGameProc", TruncateGameProc },
993 { "MoveNowProc", MoveNowProc },
994 { "RetractMoveProc", RetractMoveProc },
995 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
996 { "UciMenuProc", (XtActionProc) UciMenuProc },
997 { "TimeControlProc", (XtActionProc) TimeControlProc },
998 { "FlipViewProc", FlipViewProc },
999 { "PonderNextMoveProc", PonderNextMoveProc },
1000 #ifndef OPTIONSDIALOG
1001 { "AlwaysQueenProc", AlwaysQueenProc },
1002 { "AnimateDraggingProc", AnimateDraggingProc },
1003 { "AnimateMovingProc", AnimateMovingProc },
1004 { "AutoflagProc", AutoflagProc },
1005 { "AutoflipProc", AutoflipProc },
1006 { "BlindfoldProc", BlindfoldProc },
1007 { "FlashMovesProc", FlashMovesProc },
1009 { "HighlightDraggingProc", HighlightDraggingProc },
1011 { "HighlightLastMoveProc", HighlightLastMoveProc },
1012 // { "IcsAlarmProc", IcsAlarmProc },
1013 { "MoveSoundProc", MoveSoundProc },
1014 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
1015 { "PopupExitMessageProc", PopupExitMessageProc },
1016 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
1017 // { "PremoveProc", PremoveProc },
1018 { "ShowCoordsProc", ShowCoordsProc },
1019 { "ShowThinkingProc", ShowThinkingProc },
1020 { "HideThinkingProc", HideThinkingProc },
1021 { "TestLegalityProc", TestLegalityProc },
1023 { "SaveSettingsProc", SaveSettingsProc },
1024 { "SaveOnExitProc", SaveOnExitProc },
1025 { "InfoProc", InfoProc },
1026 { "ManProc", ManProc },
1027 { "HintProc", HintProc },
1028 { "BookProc", BookProc },
1029 { "AboutGameProc", AboutGameProc },
1030 { "AboutProc", AboutProc },
1031 { "DebugProc", DebugProc },
1032 { "NothingProc", NothingProc },
1033 { "CommentClick", (XtActionProc) CommentClick },
1034 { "CommentPopDown", (XtActionProc) CommentPopDown },
1035 { "TagsPopDown", (XtActionProc) TagsPopDown },
1036 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
1037 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1038 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1039 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1040 { "GameListPopDown", (XtActionProc) GameListPopDown },
1041 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1042 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1043 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1044 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1045 { "GenericPopDown", (XtActionProc) GenericPopDown },
1046 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1047 { "SelectMove", (XtActionProc) SelectMove },
1050 char globalTranslations[] =
1051 ":<Key>F9: ResignProc() \n \
1052 :Ctrl<Key>n: ResetProc() \n \
1053 :Meta<Key>V: NewVariantProc() \n \
1054 :Ctrl<Key>o: LoadGameProc() \n \
1055 :Meta<Key>Next: LoadNextGameProc() \n \
1056 :Meta<Key>Prior: LoadPrevGameProc() \n \
1057 :Ctrl<Key>Down: LoadSelectedProc(3) \n \
1058 :Ctrl<Key>Up: LoadSelectedProc(-3) \n \
1059 :Ctrl<Key>s: SaveGameProc() \n \
1060 :Ctrl<Key>c: CopyGameProc() \n \
1061 :Ctrl<Key>v: PasteGameProc() \n \
1062 :Ctrl<Key>O: LoadPositionProc() \n \
1063 :Shift<Key>Next: LoadNextPositionProc() \n \
1064 :Shift<Key>Prior: LoadPrevPositionProc() \n \
1065 :Ctrl<Key>S: SavePositionProc() \n \
1066 :Ctrl<Key>C: CopyPositionProc() \n \
1067 :Ctrl<Key>V: PastePositionProc() \n \
1068 :Ctrl<Key>q: QuitProc() \n \
1069 :Ctrl<Key>w: MachineWhiteProc() \n \
1070 :Ctrl<Key>b: MachineBlackProc() \n \
1071 :Ctrl<Key>t: TwoMachinesProc() \n \
1072 :Ctrl<Key>a: AnalysisModeProc() \n \
1073 :Ctrl<Key>g: AnalyzeFileProc() \n \
1074 :Ctrl<Key>e: EditGameProc() \n \
1075 :Ctrl<Key>E: EditPositionProc() \n \
1076 :Meta<Key>O: EngineOutputProc() \n \
1077 :Meta<Key>E: EvalGraphProc() \n \
1078 :Meta<Key>G: ShowGameListProc() \n \
1079 :Meta<Key>H: ShowMoveListProc() \n \
1080 :<Key>Pause: PauseProc() \n \
1081 :<Key>F3: AcceptProc() \n \
1082 :<Key>F4: DeclineProc() \n \
1083 :<Key>F12: RematchProc() \n \
1084 :<Key>F5: CallFlagProc() \n \
1085 :<Key>F6: DrawProc() \n \
1086 :<Key>F7: AdjournProc() \n \
1087 :<Key>F8: AbortProc() \n \
1088 :<Key>F10: StopObservingProc() \n \
1089 :<Key>F11: StopExaminingProc() \n \
1090 :Meta Ctrl<Key>F12: DebugProc() \n \
1091 :Meta<Key>End: ToEndProc() \n \
1092 :Meta<Key>Right: ForwardProc() \n \
1093 :Meta<Key>Home: ToStartProc() \n \
1094 :Meta<Key>Left: BackwardProc() \n \
1095 :<Key>Left: BackwardProc() \n \
1096 :<Key>Right: ForwardProc() \n \
1097 :<Key>Home: RevertProc() \n \
1098 :<Key>End: TruncateGameProc() \n \
1099 :Ctrl<Key>m: MoveNowProc() \n \
1100 :Ctrl<Key>x: RetractMoveProc() \n \
1101 :Meta<Key>J: EngineMenuProc() \n \
1102 :Meta<Key>U: UciMenuProc() \n \
1103 :Meta<Key>T: TimeControlProc() \n \
1104 :Ctrl<Key>P: PonderNextMoveProc() \n "
1105 #ifndef OPTIONSDIALOG
1107 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1108 :Ctrl<Key>F: AutoflagProc() \n \
1109 :Ctrl<Key>A: AnimateMovingProc() \n \
1110 :Ctrl<Key>L: TestLegalityProc() \n \
1111 :Ctrl<Key>H: HideThinkingProc() \n "
1114 :<Key>F1: ManProc() \n \
1115 :<Key>F2: FlipViewProc() \n \
1116 :Ctrl<KeyDown>.: TempBackwardProc() \n \
1117 :Ctrl<KeyUp>.: TempForwardProc() \n \
1118 :Ctrl<Key>1: AskQuestionProc(\"Direct command\",\
1119 \"Send to chess program:\",,1) \n \
1120 :Ctrl<Key>2: AskQuestionProc(\"Direct command\",\
1121 \"Send to second chess program:\",,2) \n";
1123 char boardTranslations[] =
1124 "<Btn1Down>: HandleUserMove(0) \n \
1125 Shift<Btn1Up>: HandleUserMove(1) \n \
1126 <Btn1Up>: HandleUserMove(0) \n \
1127 <Btn1Motion>: AnimateUserMove() \n \
1128 <Btn3Motion>: HandlePV() \n \
1129 <Btn3Up>: PieceMenuPopup(menuB) \n \
1130 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1131 PieceMenuPopup(menuB) \n \
1132 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1133 PieceMenuPopup(menuW) \n \
1134 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1135 PieceMenuPopup(menuW) \n \
1136 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1137 PieceMenuPopup(menuB) \n";
1139 char whiteTranslations[] =
1140 "Shift<BtnDown>: WhiteClock(1)\n \
1141 <BtnDown>: WhiteClock(0)\n";
1142 char blackTranslations[] =
1143 "Shift<BtnDown>: BlackClock(1)\n \
1144 <BtnDown>: BlackClock(0)\n";
1146 char ICSInputTranslations[] =
1147 "<Key>Up: UpKeyProc() \n "
1148 "<Key>Down: DownKeyProc() \n "
1149 "<Key>Return: EnterKeyProc() \n";
1151 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1152 // as the widget is destroyed before the up-click can call extend-end
1153 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1155 String xboardResources[] = {
1156 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1157 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1158 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1163 /* Max possible square size */
1164 #define MAXSQSIZE 256
1166 static int xpm_avail[MAXSQSIZE];
1168 #ifdef HAVE_DIR_STRUCT
1170 /* Extract piece size from filename */
1172 xpm_getsize(name, len, ext)
1183 if ((p=strchr(name, '.')) == NULL ||
1184 StrCaseCmp(p+1, ext) != 0)
1190 while (*p && isdigit(*p))
1197 /* Setup xpm_avail */
1199 xpm_getavail(dirname, ext)
1207 for (i=0; i<MAXSQSIZE; ++i)
1210 if (appData.debugMode)
1211 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1213 dir = opendir(dirname);
1216 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1217 programName, dirname);
1221 while ((ent=readdir(dir)) != NULL) {
1222 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1223 if (i > 0 && i < MAXSQSIZE)
1233 xpm_print_avail(fp, ext)
1239 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1240 for (i=1; i<MAXSQSIZE; ++i) {
1246 /* Return XPM piecesize closest to size */
1248 xpm_closest_to(dirname, size, ext)
1254 int sm_diff = MAXSQSIZE;
1258 xpm_getavail(dirname, ext);
1260 if (appData.debugMode)
1261 xpm_print_avail(stderr, ext);
1263 for (i=1; i<MAXSQSIZE; ++i) {
1266 diff = (diff<0) ? -diff : diff;
1267 if (diff < sm_diff) {
1275 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1281 #else /* !HAVE_DIR_STRUCT */
1282 /* If we are on a system without a DIR struct, we can't
1283 read the directory, so we can't collect a list of
1284 filenames, etc., so we can't do any size-fitting. */
1286 xpm_closest_to(dirname, size, ext)
1291 fprintf(stderr, _("\
1292 Warning: No DIR structure found on this system --\n\
1293 Unable to autosize for XPM/XIM pieces.\n\
1294 Please report this error to %s.\n\
1295 Include system type & operating system in message.\n"), PACKAGE_BUGREPORT););
1298 #endif /* HAVE_DIR_STRUCT */
1300 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1301 "magenta", "cyan", "white" };
1305 TextColors textColors[(int)NColorClasses];
1307 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1309 parse_color(str, which)
1313 char *p, buf[100], *d;
1316 if (strlen(str) > 99) /* watch bounds on buf */
1321 for (i=0; i<which; ++i) {
1328 /* Could be looking at something like:
1330 .. in which case we want to stop on a comma also */
1331 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1335 return -1; /* Use default for empty field */
1338 if (which == 2 || isdigit(*p))
1341 while (*p && isalpha(*p))
1346 for (i=0; i<8; ++i) {
1347 if (!StrCaseCmp(buf, cnames[i]))
1348 return which? (i+40) : (i+30);
1350 if (!StrCaseCmp(buf, "default")) return -1;
1352 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1357 parse_cpair(cc, str)
1361 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1362 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1367 /* bg and attr are optional */
1368 textColors[(int)cc].bg = parse_color(str, 1);
1369 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1370 textColors[(int)cc].attr = 0;
1376 /* Arrange to catch delete-window events */
1377 Atom wm_delete_window;
1379 CatchDeleteWindow(Widget w, String procname)
1382 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1383 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1384 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1391 XtSetArg(args[0], XtNiconic, False);
1392 XtSetValues(shellWidget, args, 1);
1394 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1397 //---------------------------------------------------------------------------------------------------------
1398 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1401 #define CW_USEDEFAULT (1<<31)
1402 #define ICS_TEXT_MENU_SIZE 90
1403 #define DEBUG_FILE "xboard.debug"
1404 #define SetCurrentDirectory chdir
1405 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1409 // these two must some day move to frontend.h, when they are implemented
1410 Boolean GameListIsUp();
1412 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1415 // front-end part of option handling
1417 // [HGM] This platform-dependent table provides the location for storing the color info
1418 extern char *crWhite, * crBlack;
1422 &appData.whitePieceColor,
1423 &appData.blackPieceColor,
1424 &appData.lightSquareColor,
1425 &appData.darkSquareColor,
1426 &appData.highlightSquareColor,
1427 &appData.premoveHighlightColor,
1428 &appData.lowTimeWarningColor,
1439 // [HGM] font: keep a font for each square size, even non-stndard ones
1440 #define NUM_SIZES 18
1441 #define MAX_SIZE 130
1442 Boolean fontIsSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1443 char *fontTable[NUM_FONTS][MAX_SIZE];
1446 ParseFont(char *name, int number)
1447 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1449 if(sscanf(name, "size%d:", &size)) {
1450 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1451 // defer processing it until we know if it matches our board size
1452 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1453 fontTable[number][size] = strdup(strchr(name, ':')+1);
1454 fontValid[number][size] = True;
1459 case 0: // CLOCK_FONT
1460 appData.clockFont = strdup(name);
1462 case 1: // MESSAGE_FONT
1463 appData.font = strdup(name);
1465 case 2: // COORD_FONT
1466 appData.coordFont = strdup(name);
1471 fontIsSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1476 { // only 2 fonts currently
1477 appData.clockFont = CLOCK_FONT_NAME;
1478 appData.coordFont = COORD_FONT_NAME;
1479 appData.font = DEFAULT_FONT_NAME;
1484 { // no-op, until we identify the code for this already in XBoard and move it here
1488 ParseColor(int n, char *name)
1489 { // in XBoard, just copy the color-name string
1490 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1494 ParseTextAttribs(ColorClass cc, char *s)
1496 (&appData.colorShout)[cc] = strdup(s);
1500 ParseBoardSize(void *addr, char *name)
1502 appData.boardSize = strdup(name);
1507 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1511 SetCommPortDefaults()
1512 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1515 // [HGM] args: these three cases taken out to stay in front-end
1517 SaveFontArg(FILE *f, ArgDescriptor *ad)
1520 int i, n = (int)(intptr_t)ad->argLoc;
1522 case 0: // CLOCK_FONT
1523 name = appData.clockFont;
1525 case 1: // MESSAGE_FONT
1526 name = appData.font;
1528 case 2: // COORD_FONT
1529 name = appData.coordFont;
1534 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1535 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1536 fontTable[n][squareSize] = strdup(name);
1537 fontValid[n][squareSize] = True;
1540 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1541 fprintf(f, OPTCHAR "%s" SEPCHAR "\"size%d:%s\"\n", ad->argName, i, fontTable[n][i]);
1546 { // nothing to do, as the sounds are at all times represented by their text-string names already
1550 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1551 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1552 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)(intptr_t)ad->argLoc]);
1556 SaveColor(FILE *f, ArgDescriptor *ad)
1557 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1558 if(colorVariable[(int)(intptr_t)ad->argLoc])
1559 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)(intptr_t)ad->argLoc]);
1563 SaveBoardSize(FILE *f, char *name, void *addr)
1564 { // wrapper to shield back-end from BoardSize & sizeInfo
1565 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1569 ParseCommPortSettings(char *s)
1570 { // no such option in XBoard (yet)
1573 extern Widget engineOutputShell;
1576 GetActualPlacement(Widget wg, WindowPlacement *wp)
1586 XtSetArg(args[i], XtNx, &x); i++;
1587 XtSetArg(args[i], XtNy, &y); i++;
1588 XtSetArg(args[i], XtNwidth, &w); i++;
1589 XtSetArg(args[i], XtNheight, &h); i++;
1590 XtGetValues(wg, args, i);
1599 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1600 // In XBoard this will have to wait until awareness of window parameters is implemented
1601 GetActualPlacement(shellWidget, &wpMain);
1602 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput);
1603 if(MoveHistoryIsUp()) GetActualPlacement(shells[7], &wpMoveHistory);
1604 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1605 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1606 if(shellUp[1]) GetActualPlacement(shells[1], &wpComment);
1607 if(shellUp[2]) GetActualPlacement(shells[2], &wpTags);
1611 PrintCommPortSettings(FILE *f, char *name)
1612 { // This option does not exist in XBoard
1616 MySearchPath(char *installDir, char *name, char *fullname)
1617 { // just append installDir and name. Perhaps ExpandPath should be used here?
1618 name = ExpandPathName(name);
1619 if(name && name[0] == '/')
1620 safeStrCpy(fullname, name, MSG_SIZ );
1622 sprintf(fullname, "%s%c%s", installDir, '/', name);
1628 MyGetFullPathName(char *name, char *fullname)
1629 { // should use ExpandPath?
1630 name = ExpandPathName(name);
1631 safeStrCpy(fullname, name, MSG_SIZ );
1636 EnsureOnScreen(int *x, int *y, int minX, int minY)
1643 { // [HGM] args: allows testing if main window is realized from back-end
1644 return xBoardWindow != 0;
1648 PopUpStartupDialog()
1649 { // start menu not implemented in XBoard
1653 ConvertToLine(int argc, char **argv)
1655 static char line[128*1024], buf[1024];
1659 for(i=1; i<argc; i++)
1661 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') || argv[i][0] == NULLCHAR)
1662 && argv[i][0] != '{' )
1663 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1665 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1666 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1669 line[strlen(line)-1] = NULLCHAR;
1673 //--------------------------------------------------------------------------------------------
1675 extern Boolean twoBoards, partnerUp;
1678 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1680 #define BoardSize int
1681 void InitDrawingSizes(BoardSize boardSize, int flags)
1682 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1683 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1685 XtGeometryResult gres;
1687 static Dimension oldWidth, oldHeight;
1688 static VariantClass oldVariant;
1689 static int oldDual = -1;
1691 if(!formWidget) return;
1693 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
1694 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1695 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1697 if(boardWidth != oldWidth || boardHeight != oldHeight || oldDual != twoBoards) { // do resizing stuff only if size actually changed
1699 * Enable shell resizing.
1701 shellArgs[0].value = (XtArgVal) &w;
1702 shellArgs[1].value = (XtArgVal) &h;
1703 XtGetValues(shellWidget, shellArgs, 2);
1705 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1706 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1707 XtSetValues(shellWidget, &shellArgs[2], 4);
1709 XtSetArg(args[0], XtNdefaultDistance, &sep);
1710 XtGetValues(formWidget, args, 1);
1712 oldWidth = boardWidth; oldHeight = boardHeight; oldDual = twoBoards;
1714 hOffset = boardWidth + 10;
1715 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1716 secondSegments[i] = gridSegments[i];
1717 secondSegments[i].x1 += hOffset;
1718 secondSegments[i].x2 += hOffset;
1721 XtSetArg(args[0], XtNwidth, boardWidth);
1722 XtSetArg(args[1], XtNheight, boardHeight);
1723 XtSetValues(boardWidget, args, 2);
1725 timerWidth = (boardWidth - sep) / 2;
1726 XtSetArg(args[0], XtNwidth, timerWidth);
1727 XtSetValues(whiteTimerWidget, args, 1);
1728 XtSetValues(blackTimerWidget, args, 1);
1730 XawFormDoLayout(formWidget, False);
1732 if (appData.titleInWindow) {
1734 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1735 XtSetArg(args[i], XtNheight, &h); i++;
1736 XtGetValues(titleWidget, args, i);
1738 w = boardWidth - 2*bor;
1740 XtSetArg(args[0], XtNwidth, &w);
1741 XtGetValues(menuBarWidget, args, 1);
1742 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1745 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1746 if (gres != XtGeometryYes && appData.debugMode) {
1748 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1749 programName, gres, w, h, wr, hr);
1753 XawFormDoLayout(formWidget, True);
1756 * Inhibit shell resizing.
1758 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1759 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1760 shellArgs[4].value = shellArgs[2].value = w;
1761 shellArgs[5].value = shellArgs[3].value = h;
1762 XtSetValues(shellWidget, &shellArgs[0], 6);
1765 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1768 if(gameInfo.variant == oldVariant) return; // and only if variant changed
1771 for(i=0; i<4; i++) {
1773 for(p=0; p<=(int)WhiteKing; p++)
1774 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1775 if(gameInfo.variant == VariantShogi) {
1776 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1777 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1778 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1779 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1780 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1783 if(gameInfo.variant == VariantGothic) {
1784 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1787 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1788 xpmPieceBitmap[i][(int)WhiteAngel] = xpmPieceBitmap2[i][(int)WhiteFalcon];
1789 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteAlfil];
1792 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1793 for(p=0; p<=(int)WhiteKing; p++)
1794 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1795 if(gameInfo.variant == VariantShogi) {
1796 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1797 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1798 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1799 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1800 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1803 if(gameInfo.variant == VariantGothic) {
1804 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1807 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1808 ximMaskPm[(int)WhiteAngel] = ximMaskPm2[(int)WhiteFalcon];
1809 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteAlfil];
1814 for(i=0; i<2; i++) {
1816 for(p=0; p<=(int)WhiteKing; p++)
1817 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1818 if(gameInfo.variant == VariantShogi) {
1819 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1820 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1821 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1822 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1823 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1826 if(gameInfo.variant == VariantGothic) {
1827 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1830 if(gameInfo.variant == VariantSChess && (squareSize == 49 || squareSize == 72)) {
1831 pieceBitmap[i][(int)WhiteAngel] = pieceBitmap2[i][(int)WhiteFalcon];
1832 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteAlfil];
1842 void ParseIcsTextColors()
1843 { // [HGM] tken out of main(), so it can be called from ICS-Options dialog
1844 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
1845 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
1846 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
1847 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
1848 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
1849 parse_cpair(ColorTell, appData.colorTell) < 0 ||
1850 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
1851 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
1852 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
1853 parse_cpair(ColorNormal, appData.colorNormal) < 0)
1855 if (appData.colorize) {
1857 _("%s: can't parse color names; disabling colorization\n"),
1860 appData.colorize = FALSE;
1865 { // [HGM] taken out of main(), so it can be called from BoardOptions dialog
1866 XrmValue vFrom, vTo;
1867 int forceMono = False;
1869 if (!appData.monoMode) {
1870 vFrom.addr = (caddr_t) appData.lightSquareColor;
1871 vFrom.size = strlen(appData.lightSquareColor);
1872 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1873 if (vTo.addr == NULL) {
1874 appData.monoMode = True;
1877 lightSquareColor = *(Pixel *) vTo.addr;
1880 if (!appData.monoMode) {
1881 vFrom.addr = (caddr_t) appData.darkSquareColor;
1882 vFrom.size = strlen(appData.darkSquareColor);
1883 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1884 if (vTo.addr == NULL) {
1885 appData.monoMode = True;
1888 darkSquareColor = *(Pixel *) vTo.addr;
1891 if (!appData.monoMode) {
1892 vFrom.addr = (caddr_t) appData.whitePieceColor;
1893 vFrom.size = strlen(appData.whitePieceColor);
1894 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1895 if (vTo.addr == NULL) {
1896 appData.monoMode = True;
1899 whitePieceColor = *(Pixel *) vTo.addr;
1902 if (!appData.monoMode) {
1903 vFrom.addr = (caddr_t) appData.blackPieceColor;
1904 vFrom.size = strlen(appData.blackPieceColor);
1905 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1906 if (vTo.addr == NULL) {
1907 appData.monoMode = True;
1910 blackPieceColor = *(Pixel *) vTo.addr;
1914 if (!appData.monoMode) {
1915 vFrom.addr = (caddr_t) appData.highlightSquareColor;
1916 vFrom.size = strlen(appData.highlightSquareColor);
1917 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1918 if (vTo.addr == NULL) {
1919 appData.monoMode = True;
1922 highlightSquareColor = *(Pixel *) vTo.addr;
1926 if (!appData.monoMode) {
1927 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
1928 vFrom.size = strlen(appData.premoveHighlightColor);
1929 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
1930 if (vTo.addr == NULL) {
1931 appData.monoMode = True;
1934 premoveHighlightColor = *(Pixel *) vTo.addr;
1942 { // [HGM] taken out of main
1944 if (appData.monoMode && // [HGM] no sense to go on to certain doom
1945 (appData.bitmapDirectory == NULL || appData.bitmapDirectory[0] == NULLCHAR))
1946 appData.bitmapDirectory = strdup(DEF_BITMAP_DIR);
1948 if (appData.bitmapDirectory[0] != NULLCHAR) {
1952 CreateXPMBoard(appData.liteBackTextureFile, 1);
1953 CreateXPMBoard(appData.darkBackTextureFile, 0);
1957 /* Create regular pieces */
1958 if (!useImages) CreatePieces();
1967 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1968 XSetWindowAttributes window_attributes;
1970 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1971 XrmValue vFrom, vTo;
1972 XtGeometryResult gres;
1975 int forceMono = False;
1977 srandom(time(0)); // [HGM] book: make random truly random
1979 setbuf(stdout, NULL);
1980 setbuf(stderr, NULL);
1983 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1984 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1988 programName = strrchr(argv[0], '/');
1989 if (programName == NULL)
1990 programName = argv[0];
1995 XtSetLanguageProc(NULL, NULL, NULL);
1996 bindtextdomain(PACKAGE, LOCALEDIR);
1997 textdomain(PACKAGE);
2001 XtAppInitialize(&appContext, "XBoard", shellOptions,
2002 XtNumber(shellOptions),
2003 &argc, argv, xboardResources, NULL, 0);
2004 appData.boardSize = "";
2005 InitAppData(ConvertToLine(argc, argv));
2007 if (p == NULL) p = "/tmp";
2008 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
2009 gameCopyFilename = (char*) malloc(i);
2010 gamePasteFilename = (char*) malloc(i);
2011 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
2012 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
2014 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
2015 clientResources, XtNumber(clientResources),
2018 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
2019 static char buf[MSG_SIZ];
2020 EscapeExpand(buf, appData.firstInitString);
2021 appData.firstInitString = strdup(buf);
2022 EscapeExpand(buf, appData.secondInitString);
2023 appData.secondInitString = strdup(buf);
2024 EscapeExpand(buf, appData.firstComputerString);
2025 appData.firstComputerString = strdup(buf);
2026 EscapeExpand(buf, appData.secondComputerString);
2027 appData.secondComputerString = strdup(buf);
2030 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
2033 if (chdir(chessDir) != 0) {
2034 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
2040 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
2041 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
2042 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
2043 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
2046 setbuf(debugFP, NULL);
2050 if (appData.debugMode) {
2051 fprintf(debugFP, "locale = %s\n", setlocale(LC_ALL, NULL));
2055 /* [HGM,HR] make sure board size is acceptable */
2056 if(appData.NrFiles > BOARD_FILES ||
2057 appData.NrRanks > BOARD_RANKS )
2058 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
2061 /* This feature does not work; animation needs a rewrite */
2062 appData.highlightDragging = FALSE;
2066 xDisplay = XtDisplay(shellWidget);
2067 xScreen = DefaultScreen(xDisplay);
2068 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
2070 gameInfo.variant = StringToVariant(appData.variant);
2071 InitPosition(FALSE);
2074 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
2076 if (isdigit(appData.boardSize[0])) {
2077 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
2078 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
2079 &fontPxlSize, &smallLayout, &tinyLayout);
2081 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
2082 programName, appData.boardSize);
2086 /* Find some defaults; use the nearest known size */
2087 SizeDefaults *szd, *nearest;
2088 int distance = 99999;
2089 nearest = szd = sizeDefaults;
2090 while (szd->name != NULL) {
2091 if (abs(szd->squareSize - squareSize) < distance) {
2093 distance = abs(szd->squareSize - squareSize);
2094 if (distance == 0) break;
2098 if (i < 2) lineGap = nearest->lineGap;
2099 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
2100 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
2101 if (i < 5) fontPxlSize = nearest->fontPxlSize;
2102 if (i < 6) smallLayout = nearest->smallLayout;
2103 if (i < 7) tinyLayout = nearest->tinyLayout;
2106 SizeDefaults *szd = sizeDefaults;
2107 if (*appData.boardSize == NULLCHAR) {
2108 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
2109 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
2112 if (szd->name == NULL) szd--;
2113 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
2115 while (szd->name != NULL &&
2116 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
2117 if (szd->name == NULL) {
2118 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
2119 programName, appData.boardSize);
2123 squareSize = szd->squareSize;
2124 lineGap = szd->lineGap;
2125 clockFontPxlSize = szd->clockFontPxlSize;
2126 coordFontPxlSize = szd->coordFontPxlSize;
2127 fontPxlSize = szd->fontPxlSize;
2128 smallLayout = szd->smallLayout;
2129 tinyLayout = szd->tinyLayout;
2130 // [HGM] font: use defaults from settings file if available and not overruled
2132 if(!fontIsSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
2133 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
2134 if(!fontIsSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
2135 appData.font = fontTable[MESSAGE_FONT][squareSize];
2136 if(!fontIsSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
2137 appData.coordFont = fontTable[COORD_FONT][squareSize];
2139 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
2140 if (strlen(appData.pixmapDirectory) > 0) {
2141 p = ExpandPathName(appData.pixmapDirectory);
2143 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
2144 appData.pixmapDirectory);
2147 if (appData.debugMode) {
2148 fprintf(stderr, _("\
2149 XBoard square size (hint): %d\n\
2150 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
2152 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
2153 if (appData.debugMode) {
2154 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
2157 defaultLineGap = lineGap;
2158 if(appData.overrideLineGap >= 0) lineGap = appData.overrideLineGap;
2160 /* [HR] height treated separately (hacked) */
2161 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
2162 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
2163 if (appData.showJail == 1) {
2164 /* Jail on top and bottom */
2165 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2166 XtSetArg(boardArgs[2], XtNheight,
2167 boardHeight + 2*(lineGap + squareSize));
2168 } else if (appData.showJail == 2) {
2170 XtSetArg(boardArgs[1], XtNwidth,
2171 boardWidth + 2*(lineGap + squareSize));
2172 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2175 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
2176 XtSetArg(boardArgs[2], XtNheight, boardHeight);
2180 * Determine what fonts to use.
2183 appData.font = InsertPxlSize(appData.font, fontPxlSize);
2184 appData.clockFont = InsertPxlSize(appData.clockFont, clockFontPxlSize);
2185 appData.coordFont = InsertPxlSize(appData.coordFont, coordFontPxlSize);
2186 fontSet = CreateFontSet(appData.font);
2187 clockFontSet = CreateFontSet(appData.clockFont);
2189 /* For the coordFont, use the 0th font of the fontset. */
2190 XFontSet coordFontSet = CreateFontSet(appData.coordFont);
2191 XFontStruct **font_struct_list;
2192 char **font_name_list;
2193 XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
2194 coordFontID = XLoadFont(xDisplay, font_name_list[0]);
2195 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2198 appData.font = FindFont(appData.font, fontPxlSize);
2199 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
2200 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
2201 clockFontID = XLoadFont(xDisplay, appData.clockFont);
2202 clockFontStruct = XQueryFont(xDisplay, clockFontID);
2203 coordFontID = XLoadFont(xDisplay, appData.coordFont);
2204 coordFontStruct = XQueryFont(xDisplay, coordFontID);
2206 countFontID = coordFontID; // [HGM] holdings
2207 countFontStruct = coordFontStruct;
2209 xdb = XtDatabase(xDisplay);
2211 XrmPutLineResource(&xdb, "*international: True");
2212 vTo.size = sizeof(XFontSet);
2213 vTo.addr = (XtPointer) &fontSet;
2214 XrmPutResource(&xdb, "*fontSet", XtRFontSet, &vTo);
2216 XrmPutStringResource(&xdb, "*font", appData.font);
2220 * Detect if there are not enough colors available and adapt.
2222 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2223 appData.monoMode = True;
2226 forceMono = MakeColors();
2229 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2231 appData.monoMode = True;
2234 if (appData.lowTimeWarning && !appData.monoMode) {
2235 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2236 vFrom.size = strlen(appData.lowTimeWarningColor);
2237 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2238 if (vTo.addr == NULL)
2239 appData.monoMode = True;
2241 lowTimeWarningColor = *(Pixel *) vTo.addr;
2244 if (appData.monoMode && appData.debugMode) {
2245 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2246 (unsigned long) XWhitePixel(xDisplay, xScreen),
2247 (unsigned long) XBlackPixel(xDisplay, xScreen));
2250 ParseIcsTextColors();
2251 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2252 textColors[ColorNone].attr = 0;
2254 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2260 layoutName = "tinyLayout";
2261 } else if (smallLayout) {
2262 layoutName = "smallLayout";
2264 layoutName = "normalLayout";
2266 /* Outer layoutWidget is there only to provide a name for use in
2267 resources that depend on the layout style */
2269 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2270 layoutArgs, XtNumber(layoutArgs));
2272 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2273 formArgs, XtNumber(formArgs));
2274 XtSetArg(args[0], XtNdefaultDistance, &sep);
2275 XtGetValues(formWidget, args, 1);
2278 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2279 XtSetArg(args[0], XtNtop, XtChainTop);
2280 XtSetArg(args[1], XtNbottom, XtChainTop);
2281 XtSetArg(args[2], XtNright, XtChainLeft);
2282 XtSetValues(menuBarWidget, args, 3);
2284 widgetList[j++] = whiteTimerWidget =
2285 XtCreateWidget("whiteTime", labelWidgetClass,
2286 formWidget, timerArgs, XtNumber(timerArgs));
2288 XtSetArg(args[0], XtNfontSet, clockFontSet);
2290 XtSetArg(args[0], XtNfont, clockFontStruct);
2292 XtSetArg(args[1], XtNtop, XtChainTop);
2293 XtSetArg(args[2], XtNbottom, XtChainTop);
2294 XtSetValues(whiteTimerWidget, args, 3);
2296 widgetList[j++] = blackTimerWidget =
2297 XtCreateWidget("blackTime", labelWidgetClass,
2298 formWidget, timerArgs, XtNumber(timerArgs));
2300 XtSetArg(args[0], XtNfontSet, clockFontSet);
2302 XtSetArg(args[0], XtNfont, clockFontStruct);
2304 XtSetArg(args[1], XtNtop, XtChainTop);
2305 XtSetArg(args[2], XtNbottom, XtChainTop);
2306 XtSetValues(blackTimerWidget, args, 3);
2308 if (appData.titleInWindow) {
2309 widgetList[j++] = titleWidget =
2310 XtCreateWidget("title", labelWidgetClass, formWidget,
2311 titleArgs, XtNumber(titleArgs));
2312 XtSetArg(args[0], XtNtop, XtChainTop);
2313 XtSetArg(args[1], XtNbottom, XtChainTop);
2314 XtSetValues(titleWidget, args, 2);
2317 if (appData.showButtonBar) {
2318 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2319 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2320 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2321 XtSetArg(args[2], XtNtop, XtChainTop);
2322 XtSetArg(args[3], XtNbottom, XtChainTop);
2323 XtSetValues(buttonBarWidget, args, 4);
2326 widgetList[j++] = messageWidget =
2327 XtCreateWidget("message", labelWidgetClass, formWidget,
2328 messageArgs, XtNumber(messageArgs));
2329 XtSetArg(args[0], XtNtop, XtChainTop);
2330 XtSetArg(args[1], XtNbottom, XtChainTop);
2331 XtSetValues(messageWidget, args, 2);
2333 widgetList[j++] = boardWidget =
2334 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2335 XtNumber(boardArgs));
2337 XtManageChildren(widgetList, j);
2339 timerWidth = (boardWidth - sep) / 2;
2340 XtSetArg(args[0], XtNwidth, timerWidth);
2341 XtSetValues(whiteTimerWidget, args, 1);
2342 XtSetValues(blackTimerWidget, args, 1);
2344 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2345 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2346 XtGetValues(whiteTimerWidget, args, 2);
2348 if (appData.showButtonBar) {
2349 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2350 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2351 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2355 * formWidget uses these constraints but they are stored
2359 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2360 XtSetValues(menuBarWidget, args, i);
2361 if (appData.titleInWindow) {
2364 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2365 XtSetValues(whiteTimerWidget, args, i);
2367 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2368 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2369 XtSetValues(blackTimerWidget, args, i);
2371 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2372 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2373 XtSetValues(titleWidget, args, i);
2375 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2376 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2377 XtSetValues(messageWidget, args, i);
2378 if (appData.showButtonBar) {
2380 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2381 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2382 XtSetValues(buttonBarWidget, args, i);
2386 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2387 XtSetValues(whiteTimerWidget, args, i);
2389 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2390 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2391 XtSetValues(blackTimerWidget, args, i);
2393 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2394 XtSetValues(titleWidget, args, i);
2396 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2397 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2398 XtSetValues(messageWidget, args, i);
2399 if (appData.showButtonBar) {
2401 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2402 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2403 XtSetValues(buttonBarWidget, args, i);
2408 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2409 XtSetValues(whiteTimerWidget, args, i);
2411 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2412 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2413 XtSetValues(blackTimerWidget, args, i);
2415 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2416 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2417 XtSetValues(messageWidget, args, i);
2418 if (appData.showButtonBar) {
2420 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2421 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2422 XtSetValues(buttonBarWidget, args, i);
2426 XtSetArg(args[0], XtNfromVert, messageWidget);
2427 XtSetArg(args[1], XtNtop, XtChainTop);
2428 XtSetArg(args[2], XtNbottom, XtChainBottom);
2429 XtSetArg(args[3], XtNleft, XtChainLeft);
2430 XtSetArg(args[4], XtNright, XtChainRight);
2431 XtSetValues(boardWidget, args, 5);
2433 XtRealizeWidget(shellWidget);
2436 XtSetArg(args[0], XtNx, wpMain.x);
2437 XtSetArg(args[1], XtNy, wpMain.y);
2438 XtSetValues(shellWidget, args, 2);
2442 * Correct the width of the message and title widgets.
2443 * It is not known why some systems need the extra fudge term.
2444 * The value "2" is probably larger than needed.
2446 XawFormDoLayout(formWidget, False);
2448 #define WIDTH_FUDGE 2
2450 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2451 XtSetArg(args[i], XtNheight, &h); i++;
2452 XtGetValues(messageWidget, args, i);
2453 if (appData.showButtonBar) {
2455 XtSetArg(args[i], XtNwidth, &w); i++;
2456 XtGetValues(buttonBarWidget, args, i);
2457 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2459 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2462 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2463 if (gres != XtGeometryYes && appData.debugMode) {
2464 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2465 programName, gres, w, h, wr, hr);
2468 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2469 /* The size used for the child widget in layout lags one resize behind
2470 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2472 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2473 if (gres != XtGeometryYes && appData.debugMode) {
2474 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2475 programName, gres, w, h, wr, hr);
2478 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2479 XtSetArg(args[1], XtNright, XtChainRight);
2480 XtSetValues(messageWidget, args, 2);
2482 if (appData.titleInWindow) {
2484 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2485 XtSetArg(args[i], XtNheight, &h); i++;
2486 XtGetValues(titleWidget, args, i);
2488 w = boardWidth - 2*bor;
2490 XtSetArg(args[0], XtNwidth, &w);
2491 XtGetValues(menuBarWidget, args, 1);
2492 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2495 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2496 if (gres != XtGeometryYes && appData.debugMode) {
2498 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2499 programName, gres, w, h, wr, hr);
2502 XawFormDoLayout(formWidget, True);
2504 xBoardWindow = XtWindow(boardWidget);
2506 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2507 // not need to go into InitDrawingSizes().
2511 * Create X checkmark bitmap and initialize option menu checks.
2513 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2514 checkmark_bits, checkmark_width, checkmark_height);
2515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2516 #ifndef OPTIONSDIALOG
2517 if (appData.alwaysPromoteToQueen) {
2518 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2521 if (appData.animateDragging) {
2522 XtSetValues(XtNameToWidget(menuBarWidget,
2523 "menuOptions.Animate Dragging"),
2526 if (appData.animate) {
2527 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2530 if (appData.autoCallFlag) {
2531 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2534 if (appData.autoFlipView) {
2535 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2538 if (appData.blindfold) {
2539 XtSetValues(XtNameToWidget(menuBarWidget,
2540 "menuOptions.Blindfold"), args, 1);
2542 if (appData.flashCount > 0) {
2543 XtSetValues(XtNameToWidget(menuBarWidget,
2544 "menuOptions.Flash Moves"),
2548 if (appData.highlightDragging) {
2549 XtSetValues(XtNameToWidget(menuBarWidget,
2550 "menuOptions.Highlight Dragging"),
2554 if (appData.highlightLastMove) {
2555 XtSetValues(XtNameToWidget(menuBarWidget,
2556 "menuOptions.Highlight Last Move"),
2559 if (appData.highlightMoveWithArrow) {
2560 XtSetValues(XtNameToWidget(menuBarWidget,
2561 "menuOptions.Arrow"),
2564 // if (appData.icsAlarm) {
2565 // XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2568 if (appData.ringBellAfterMoves) {
2569 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2572 if (appData.oneClick) {
2573 XtSetValues(XtNameToWidget(menuBarWidget,
2574 "menuOptions.OneClick"), args, 1);
2576 if (appData.periodicUpdates) {
2577 XtSetValues(XtNameToWidget(menuBarWidget,
2578 "menuOptions.Periodic Updates"), args, 1);
2580 if (appData.ponderNextMove) {
2581 XtSetValues(XtNameToWidget(menuBarWidget,
2582 "menuOptions.Ponder Next Move"), args, 1);
2584 if (appData.popupExitMessage) {
2585 XtSetValues(XtNameToWidget(menuBarWidget,
2586 "menuOptions.Popup Exit Message"), args, 1);
2588 if (appData.popupMoveErrors) {
2589 XtSetValues(XtNameToWidget(menuBarWidget,
2590 "menuOptions.Popup Move Errors"), args, 1);
2592 // if (appData.premove) {
2593 // XtSetValues(XtNameToWidget(menuBarWidget,
2594 // "menuOptions.Premove"), args, 1);
2596 if (appData.showCoords) {
2597 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2600 if (appData.hideThinkingFromHuman) {
2601 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2604 if (appData.testLegality) {
2605 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2609 if (saveSettingsOnExit) {
2610 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2617 ReadBitmap(&wIconPixmap, "icon_white.bm",
2618 icon_white_bits, icon_white_width, icon_white_height);
2619 ReadBitmap(&bIconPixmap, "icon_black.bm",
2620 icon_black_bits, icon_black_width, icon_black_height);
2621 iconPixmap = wIconPixmap;
2623 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2624 XtSetValues(shellWidget, args, i);
2627 * Create a cursor for the board widget.
2629 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2630 XChangeWindowAttributes(xDisplay, xBoardWindow,
2631 CWCursor, &window_attributes);
2634 * Inhibit shell resizing.
2636 shellArgs[0].value = (XtArgVal) &w;
2637 shellArgs[1].value = (XtArgVal) &h;
2638 XtGetValues(shellWidget, shellArgs, 2);
2639 shellArgs[4].value = shellArgs[2].value = w;
2640 shellArgs[5].value = shellArgs[3].value = h;
2641 XtSetValues(shellWidget, &shellArgs[2], 4);
2642 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2643 marginH = h - boardHeight;
2645 CatchDeleteWindow(shellWidget, "QuitProc");
2653 if (appData.animate || appData.animateDragging)
2656 XtAugmentTranslations(formWidget,
2657 XtParseTranslationTable(globalTranslations));
2658 XtAugmentTranslations(boardWidget,
2659 XtParseTranslationTable(boardTranslations));
2660 XtAugmentTranslations(whiteTimerWidget,
2661 XtParseTranslationTable(whiteTranslations));
2662 XtAugmentTranslations(blackTimerWidget,
2663 XtParseTranslationTable(blackTranslations));
2665 /* Why is the following needed on some versions of X instead
2666 * of a translation? */
2667 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2668 (XtEventHandler) EventProc, NULL);
2670 XtAddEventHandler(formWidget, KeyPressMask, False,
2671 (XtEventHandler) MoveTypeInProc, NULL);
2673 /* [AS] Restore layout */
2674 if( wpMoveHistory.visible ) {
2678 if( wpEvalGraph.visible )
2683 if( wpEngineOutput.visible ) {
2684 EngineOutputPopUp();
2689 if (errorExitStatus == -1) {
2690 if (appData.icsActive) {
2691 /* We now wait until we see "login:" from the ICS before
2692 sending the logon script (problems with timestamp otherwise) */
2693 /*ICSInitScript();*/
2694 if (appData.icsInputBox) ICSInputBoxPopUp();
2698 signal(SIGWINCH, TermSizeSigHandler);
2700 signal(SIGINT, IntSigHandler);
2701 signal(SIGTERM, IntSigHandler);
2702 if (*appData.cmailGameName != NULLCHAR) {
2703 signal(SIGUSR1, CmailSigHandler);
2706 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2708 // XtSetKeyboardFocus(shellWidget, formWidget);
2709 XSetInputFocus(xDisplay, XtWindow(formWidget), RevertToPointerRoot, CurrentTime);
2711 XtAppMainLoop(appContext);
2712 if (appData.debugMode) fclose(debugFP); // [DM] debug
2716 static Boolean noEcho;
2721 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2722 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2724 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2725 unlink(gameCopyFilename);
2726 unlink(gamePasteFilename);
2727 if(noEcho) EchoOn();
2730 RETSIGTYPE TermSizeSigHandler(int sig)
2743 CmailSigHandler(sig)
2749 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2751 /* Activate call-back function CmailSigHandlerCallBack() */
2752 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2754 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2758 CmailSigHandlerCallBack(isr, closure, message, count, error)
2766 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2768 /**** end signal code ****/
2774 /* try to open the icsLogon script, either in the location given
2775 * or in the users HOME directory
2782 f = fopen(appData.icsLogon, "r");
2785 homedir = getenv("HOME");
2786 if (homedir != NULL)
2788 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2789 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2790 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2791 f = fopen(buf, "r");
2796 ProcessICSInitScript(f);
2798 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2821 if (!menuBarWidget) return;
2822 w = XtNameToWidget(menuBarWidget, "menuEdit.Revert");
2824 DisplayError("menuEdit.Revert", 0);
2826 XtSetSensitive(w, !grey);
2828 w = XtNameToWidget(menuBarWidget, "menuEdit.Annotate");
2830 DisplayError("menuEdit.Annotate", 0);
2832 XtSetSensitive(w, !grey);
2837 SetMenuEnables(enab)
2841 if (!menuBarWidget) return;
2842 while (enab->name != NULL) {
2843 w = XtNameToWidget(menuBarWidget, enab->name);
2845 DisplayError(enab->name, 0);
2847 XtSetSensitive(w, enab->value);
2853 Enables icsEnables[] = {
2854 { "menuFile.Mail Move", False },
2855 { "menuFile.Reload CMail Message", False },
2856 { "menuMode.Machine Black", False },
2857 { "menuMode.Machine White", False },
2858 { "menuMode.Analysis Mode", False },
2859 { "menuMode.Analyze File", False },
2860 { "menuMode.Two Machines", False },
2861 { "menuMode.Machine Match", False },
2863 { "menuEngine.Hint", False },
2864 { "menuEngine.Book", False },
2865 { "menuEngine.Move Now", False },
2866 #ifndef OPTIONSDIALOG
2867 { "menuOptions.Periodic Updates", False },
2868 { "menuOptions.Hide Thinking", False },
2869 { "menuOptions.Ponder Next Move", False },
2872 { "menuEngine.Engine #1 Settings", False },
2873 { "menuEngine.Engine #2 Settings", False },
2874 { "menuEngine.Load Engine", False },
2875 { "menuEdit.Annotate", False },
2876 { "menuOptions.Match", False },
2880 Enables ncpEnables[] = {
2881 { "menuFile.Mail Move", False },
2882 { "menuFile.Reload CMail Message", False },
2883 { "menuMode.Machine White", False },
2884 { "menuMode.Machine Black", False },
2885 { "menuMode.Analysis Mode", False },
2886 { "menuMode.Analyze File", False },
2887 { "menuMode.Two Machines", False },
2888 { "menuMode.Machine Match", False },
2889 { "menuMode.ICS Client", False },
2890 { "menuView.ICStex", False },
2891 { "menuView.ICS Input Box", False },
2892 { "Action", False },
2893 { "menuEdit.Revert", False },
2894 { "menuEdit.Annotate", False },
2895 { "menuEngine.Engine #1 Settings", False },
2896 { "menuEngine.Engine #2 Settings", False },
2897 { "menuEngine.Move Now", False },
2898 { "menuEngine.Retract Move", False },
2899 { "menuOptions.ICS", False },
2900 #ifndef OPTIONSDIALOG
2901 { "menuOptions.Auto Flag", False },
2902 { "menuOptions.Auto Flip View", False },
2903 // { "menuOptions.ICS Alarm", False },
2904 { "menuOptions.Move Sound", False },
2905 { "menuOptions.Hide Thinking", False },
2906 { "menuOptions.Periodic Updates", False },
2907 { "menuOptions.Ponder Next Move", False },
2909 { "menuEngine.Hint", False },
2910 { "menuEngine.Book", False },
2914 Enables gnuEnables[] = {
2915 { "menuMode.ICS Client", False },
2916 { "menuView.ICStex", False },
2917 { "menuView.ICS Input Box", False },
2918 { "menuAction.Accept", False },
2919 { "menuAction.Decline", False },
2920 { "menuAction.Rematch", False },
2921 { "menuAction.Adjourn", False },
2922 { "menuAction.Stop Examining", False },
2923 { "menuAction.Stop Observing", False },
2924 { "menuAction.Upload to Examine", False },
2925 { "menuEdit.Revert", False },
2926 { "menuEdit.Annotate", False },
2927 { "menuOptions.ICS", False },
2929 /* The next two options rely on SetCmailMode being called *after* */
2930 /* SetGNUMode so that when GNU is being used to give hints these */
2931 /* menu options are still available */
2933 { "menuFile.Mail Move", False },
2934 { "menuFile.Reload CMail Message", False },
2935 // [HGM] The following have been added to make a switch from ncp to GNU mode possible
2936 { "menuMode.Machine White", True },
2937 { "menuMode.Machine Black", True },
2938 { "menuMode.Analysis Mode", True },
2939 { "menuMode.Analyze File", True },
2940 { "menuMode.Two Machines", True },
2941 { "menuMode.Machine Match", True },
2942 { "menuEngine.Engine #1 Settings", True },
2943 { "menuEngine.Engine #2 Settings", True },
2944 { "menuEngine.Hint", True },
2945 { "menuEngine.Book", True },
2946 { "menuEngine.Move Now", True },
2947 { "menuEngine.Retract Move", True },
2952 Enables cmailEnables[] = {
2954 { "menuAction.Call Flag", False },
2955 { "menuAction.Draw", True },
2956 { "menuAction.Adjourn", False },
2957 { "menuAction.Abort", False },
2958 { "menuAction.Stop Observing", False },
2959 { "menuAction.Stop Examining", False },
2960 { "menuFile.Mail Move", True },
2961 { "menuFile.Reload CMail Message", True },
2965 Enables trainingOnEnables[] = {
2966 { "menuMode.Edit Comment", False },
2967 { "menuMode.Pause", False },
2968 { "menuEdit.Forward", False },
2969 { "menuEdit.Backward", False },
2970 { "menuEdit.Forward to End", False },
2971 { "menuEdit.Back to Start", False },
2972 { "menuEngine.Move Now", False },
2973 { "menuEdit.Truncate Game", False },
2977 Enables trainingOffEnables[] = {
2978 { "menuMode.Edit Comment", True },
2979 { "menuMode.Pause", True },
2980 { "menuEdit.Forward", True },
2981 { "menuEdit.Backward", True },
2982 { "menuEdit.Forward to End", True },
2983 { "menuEdit.Back to Start", True },
2984 { "menuEngine.Move Now", True },
2985 { "menuEdit.Truncate Game", True },
2989 Enables machineThinkingEnables[] = {
2990 { "menuFile.Load Game", False },
2991 // { "menuFile.Load Next Game", False },
2992 // { "menuFile.Load Previous Game", False },
2993 // { "menuFile.Reload Same Game", False },
2994 { "menuEdit.Paste Game", False },
2995 { "menuFile.Load Position", False },
2996 // { "menuFile.Load Next Position", False },
2997 // { "menuFile.Load Previous Position", False },
2998 // { "menuFile.Reload Same Position", False },
2999 { "menuEdit.Paste Position", False },
3000 { "menuMode.Machine White", False },
3001 { "menuMode.Machine Black", False },
3002 { "menuMode.Two Machines", False },
3003 // { "menuMode.Machine Match", False },
3004 { "menuEngine.Retract Move", False },
3008 Enables userThinkingEnables[] = {
3009 { "menuFile.Load Game", True },
3010 // { "menuFile.Load Next Game", True },
3011 // { "menuFile.Load Previous Game", True },
3012 // { "menuFile.Reload Same Game", True },
3013 { "menuEdit.Paste Game", True },
3014 { "menuFile.Load Position", True },
3015 // { "menuFile.Load Next Position", True },
3016 // { "menuFile.Load Previous Position", True },
3017 // { "menuFile.Reload Same Position", True },
3018 { "menuEdit.Paste Position", True },
3019 { "menuMode.Machine White", True },
3020 { "menuMode.Machine Black", True },
3021 { "menuMode.Two Machines", True },
3022 // { "menuMode.Machine Match", True },
3023 { "menuEngine.Retract Move", True },
3029 SetMenuEnables(icsEnables);
3032 if (appData.zippyPlay && !appData.noChessProgram) { /* [DM] icsEngineAnalyze */
3033 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
3034 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuEngine.Engine #1 Settings"), True);
3042 SetMenuEnables(ncpEnables);
3048 SetMenuEnables(gnuEnables);
3054 SetMenuEnables(cmailEnables);
3060 SetMenuEnables(trainingOnEnables);
3061 if (appData.showButtonBar) {
3062 XtSetSensitive(buttonBarWidget, False);
3068 SetTrainingModeOff()
3070 SetMenuEnables(trainingOffEnables);
3071 if (appData.showButtonBar) {
3072 XtSetSensitive(buttonBarWidget, True);
3077 SetUserThinkingEnables()
3079 if (appData.noChessProgram) return;
3080 SetMenuEnables(userThinkingEnables);
3084 SetMachineThinkingEnables()
3086 if (appData.noChessProgram) return;
3087 SetMenuEnables(machineThinkingEnables);
3089 case MachinePlaysBlack:
3090 case MachinePlaysWhite:
3091 case TwoMachinesPlay:
3092 XtSetSensitive(XtNameToWidget(menuBarWidget,
3093 ModeToWidgetName(gameMode)), True);
3100 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
3101 #define HISTORY_SIZE 64
3102 static char *history[HISTORY_SIZE];
3103 int histIn = 0, histP = 0;
3106 SaveInHistory(char *cmd)
3108 if (history[histIn] != NULL) {
3109 free(history[histIn]);
3110 history[histIn] = NULL;
3112 if (*cmd == NULLCHAR) return;
3113 history[histIn] = StrSave(cmd);
3114 histIn = (histIn + 1) % HISTORY_SIZE;
3115 if (history[histIn] != NULL) {
3116 free(history[histIn]);
3117 history[histIn] = NULL;
3123 PrevInHistory(char *cmd)
3126 if (histP == histIn) {
3127 if (history[histIn] != NULL) free(history[histIn]);
3128 history[histIn] = StrSave(cmd);
3130 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
3131 if (newhp == histIn || history[newhp] == NULL) return NULL;
3133 return history[histP];
3139 if (histP == histIn) return NULL;
3140 histP = (histP + 1) % HISTORY_SIZE;
3141 return history[histP];
3143 // end of borrowed code
3145 #define Abs(n) ((n)<0 ? -(n) : (n))
3149 InsertPxlSize(pattern, targetPxlSize)
3153 char *base_fnt_lst, strInt[12], *p, *q;
3154 int alternatives, i, len, strIntLen;
3157 * Replace the "*" (if present) in the pixel-size slot of each
3158 * alternative with the targetPxlSize.
3162 while ((p = strchr(p, ',')) != NULL) {
3166 snprintf(strInt, sizeof(strInt), "%d", targetPxlSize);
3167 strIntLen = strlen(strInt);
3168 base_fnt_lst = calloc(1, strlen(pattern) + strIntLen * alternatives + 1);
3172 while (alternatives--) {
3173 char *comma = strchr(p, ',');
3174 for (i=0; i<14; i++) {
3175 char *hyphen = strchr(p, '-');
3177 if (comma && hyphen > comma) break;
3178 len = hyphen + 1 - p;
3179 if (i == 7 && *p == '*' && len == 2) {
3181 memcpy(q, strInt, strIntLen);
3191 len = comma + 1 - p;
3198 return base_fnt_lst;
3202 CreateFontSet(base_fnt_lst)
3206 char **missing_list;
3210 fntSet = XCreateFontSet(xDisplay, base_fnt_lst,
3211 &missing_list, &missing_count, &def_string);
3212 if (appData.debugMode) {
3214 XFontStruct **font_struct_list;
3215 char **font_name_list;
3216 fprintf(debugFP, "Requested font set for list %s\n", base_fnt_lst);
3218 fprintf(debugFP, " got list %s, locale %s\n",
3219 XBaseFontNameListOfFontSet(fntSet),
3220 XLocaleOfFontSet(fntSet));
3221 count = XFontsOfFontSet(fntSet, &font_struct_list, &font_name_list);
3222 for (i = 0; i < count; i++) {
3223 fprintf(debugFP, " got charset %s\n", font_name_list[i]);
3226 for (i = 0; i < missing_count; i++) {
3227 fprintf(debugFP, " missing charset %s\n", missing_list[i]);
3230 if (fntSet == NULL) {
3231 fprintf(stderr, _("Unable to create font set for %s.\n"), base_fnt_lst);
3236 #else // not ENABLE_NLS
3238 * Find a font that matches "pattern" that is as close as
3239 * possible to the targetPxlSize. Prefer fonts that are k
3240 * pixels smaller to fonts that are k pixels larger. The
3241 * pattern must be in the X Consortium standard format,
3242 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3243 * The return value should be freed with XtFree when no
3247 FindFont(pattern, targetPxlSize)
3251 char **fonts, *p, *best, *scalable, *scalableTail;
3252 int i, j, nfonts, minerr, err, pxlSize;
3254 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3256 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3257 programName, pattern);
3264 for (i=0; i<nfonts; i++) {
3267 if (*p != '-') continue;
3269 if (*p == NULLCHAR) break;
3270 if (*p++ == '-') j++;
3272 if (j < 7) continue;
3275 scalable = fonts[i];
3278 err = pxlSize - targetPxlSize;
3279 if (Abs(err) < Abs(minerr) ||
3280 (minerr > 0 && err < 0 && -err == minerr)) {
3286 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3287 /* If the error is too big and there is a scalable font,
3288 use the scalable font. */
3289 int headlen = scalableTail - scalable;
3290 p = (char *) XtMalloc(strlen(scalable) + 10);
3291 while (isdigit(*scalableTail)) scalableTail++;
3292 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3294 p = (char *) XtMalloc(strlen(best) + 2);
3295 safeStrCpy(p, best, strlen(best)+1 );
3297 if (appData.debugMode) {
3298 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3299 pattern, targetPxlSize, p);
3301 XFreeFontNames(fonts);
3307 { // [HGM] deletes GCs that are to be remade, to prevent resource leak;
3308 // must be called before all non-first callse to CreateGCs()
3309 XtReleaseGC(shellWidget, highlineGC);
3310 XtReleaseGC(shellWidget, lightSquareGC);
3311 XtReleaseGC(shellWidget, darkSquareGC);
3312 XtReleaseGC(shellWidget, lineGC);
3313 if (appData.monoMode) {
3314 if (DefaultDepth(xDisplay, xScreen) == 1) {
3315 XtReleaseGC(shellWidget, wbPieceGC);
3317 XtReleaseGC(shellWidget, bwPieceGC);
3320 XtReleaseGC(shellWidget, prelineGC);
3321 XtReleaseGC(shellWidget, jailSquareGC);
3322 XtReleaseGC(shellWidget, wdPieceGC);
3323 XtReleaseGC(shellWidget, wlPieceGC);
3324 XtReleaseGC(shellWidget, wjPieceGC);
3325 XtReleaseGC(shellWidget, bdPieceGC);
3326 XtReleaseGC(shellWidget, blPieceGC);
3327 XtReleaseGC(shellWidget, bjPieceGC);
3331 void CreateGCs(int redo)
3333 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3334 | GCBackground | GCFunction | GCPlaneMask;
3335 XGCValues gc_values;
3338 gc_values.plane_mask = AllPlanes;
3339 gc_values.line_width = lineGap;
3340 gc_values.line_style = LineSolid;
3341 gc_values.function = GXcopy;
3344 DeleteGCs(); // called a second time; clean up old GCs first
3345 } else { // [HGM] grid and font GCs created on first call only
3346 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3347 gc_values.background = XWhitePixel(xDisplay, xScreen);
3348 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3349 XSetFont(xDisplay, coordGC, coordFontID);
3351 // [HGM] make font for holdings counts (white on black)
3352 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3353 gc_values.background = XBlackPixel(xDisplay, xScreen);
3354 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3355 XSetFont(xDisplay, countGC, countFontID);
3357 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3358 gc_values.background = XBlackPixel(xDisplay, xScreen);
3359 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3361 if (appData.monoMode) {
3362 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3363 gc_values.background = XWhitePixel(xDisplay, xScreen);
3364 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3366 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3367 gc_values.background = XBlackPixel(xDisplay, xScreen);
3368 lightSquareGC = wbPieceGC
3369 = XtGetGC(shellWidget, value_mask, &gc_values);
3371 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3372 gc_values.background = XWhitePixel(xDisplay, xScreen);
3373 darkSquareGC = bwPieceGC
3374 = XtGetGC(shellWidget, value_mask, &gc_values);
3376 if (DefaultDepth(xDisplay, xScreen) == 1) {
3377 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3378 gc_values.function = GXcopyInverted;
3379 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3380 gc_values.function = GXcopy;
3381 if (XBlackPixel(xDisplay, xScreen) == 1) {
3382 bwPieceGC = darkSquareGC;
3383 wbPieceGC = copyInvertedGC;
3385 bwPieceGC = copyInvertedGC;
3386 wbPieceGC = lightSquareGC;
3390 gc_values.foreground = highlightSquareColor;
3391 gc_values.background = highlightSquareColor;
3392 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3394 gc_values.foreground = premoveHighlightColor;
3395 gc_values.background = premoveHighlightColor;
3396 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3398 gc_values.foreground = lightSquareColor;
3399 gc_values.background = darkSquareColor;
3400 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3402 gc_values.foreground = darkSquareColor;
3403 gc_values.background = lightSquareColor;
3404 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3406 gc_values.foreground = jailSquareColor;
3407 gc_values.background = jailSquareColor;
3408 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3410 gc_values.foreground = whitePieceColor;
3411 gc_values.background = darkSquareColor;
3412 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3414 gc_values.foreground = whitePieceColor;
3415 gc_values.background = lightSquareColor;
3416 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3418 gc_values.foreground = whitePieceColor;
3419 gc_values.background = jailSquareColor;
3420 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3422 gc_values.foreground = blackPieceColor;
3423 gc_values.background = darkSquareColor;
3424 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3426 gc_values.foreground = blackPieceColor;
3427 gc_values.background = lightSquareColor;
3428 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3430 gc_values.foreground = blackPieceColor;
3431 gc_values.background = jailSquareColor;
3432 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3436 void loadXIM(xim, xmask, filename, dest, mask)
3449 fp = fopen(filename, "rb");
3451 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3458 for (y=0; y<h; ++y) {
3459 for (x=0; x<h; ++x) {
3464 XPutPixel(xim, x, y, blackPieceColor);
3466 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3469 XPutPixel(xim, x, y, darkSquareColor);
3471 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3474 XPutPixel(xim, x, y, whitePieceColor);
3476 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3479 XPutPixel(xim, x, y, lightSquareColor);
3481 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3489 /* create Pixmap of piece */
3490 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3492 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3495 /* create Pixmap of clipmask
3496 Note: We assume the white/black pieces have the same
3497 outline, so we make only 6 masks. This is okay
3498 since the XPM clipmask routines do the same. */
3500 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3502 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3505 /* now create the 1-bit version */
3506 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3509 values.foreground = 1;
3510 values.background = 0;
3512 /* Don't use XtGetGC, not read only */
3513 maskGC = XCreateGC(xDisplay, *mask,
3514 GCForeground | GCBackground, &values);
3515 XCopyPlane(xDisplay, temp, *mask, maskGC,
3516 0, 0, squareSize, squareSize, 0, 0, 1);
3517 XFreePixmap(xDisplay, temp);
3522 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3524 void CreateXIMPieces()
3529 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3534 /* The XSynchronize calls were copied from CreatePieces.
3535 Not sure if needed, but can't hurt */
3536 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3539 /* temp needed by loadXIM() */
3540 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3541 0, 0, ss, ss, AllPlanes, XYPixmap);
3543 if (strlen(appData.pixmapDirectory) == 0) {
3547 if (appData.monoMode) {
3548 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3552 fprintf(stderr, _("\nLoading XIMs...\n"));
3554 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3555 fprintf(stderr, "%d", piece+1);
3556 for (kind=0; kind<4; kind++) {
3557 fprintf(stderr, ".");
3558 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3559 ExpandPathName(appData.pixmapDirectory),
3560 piece <= (int) WhiteKing ? "" : "w",
3561 pieceBitmapNames[piece],
3563 ximPieceBitmap[kind][piece] =
3564 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3565 0, 0, ss, ss, AllPlanes, XYPixmap);
3566 if (appData.debugMode)
3567 fprintf(stderr, _("(File:%s:) "), buf);
3568 loadXIM(ximPieceBitmap[kind][piece],
3570 &(xpmPieceBitmap2[kind][piece]),
3571 &(ximMaskPm2[piece]));
3572 if(piece <= (int)WhiteKing)
3573 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3575 fprintf(stderr," ");
3577 /* Load light and dark squares */
3578 /* If the LSQ and DSQ pieces don't exist, we will
3579 draw them with solid squares. */
3580 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3581 if (access(buf, 0) != 0) {
3585 fprintf(stderr, _("light square "));
3587 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3588 0, 0, ss, ss, AllPlanes, XYPixmap);
3589 if (appData.debugMode)
3590 fprintf(stderr, _("(File:%s:) "), buf);
3592 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3593 fprintf(stderr, _("dark square "));
3594 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3595 ExpandPathName(appData.pixmapDirectory), ss);
3596 if (appData.debugMode)
3597 fprintf(stderr, _("(File:%s:) "), buf);
3599 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3600 0, 0, ss, ss, AllPlanes, XYPixmap);
3601 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3602 xpmJailSquare = xpmLightSquare;
3604 fprintf(stderr, _("Done.\n"));
3606 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3609 static VariantClass oldVariant = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
3612 void CreateXPMBoard(char *s, int kind)
3616 if(!appData.useBitmaps || s == NULL || *s == 0 || *s == '*') { useTexture &= ~(kind+1); return; }
3617 if (XpmReadFileToPixmap(xDisplay, xBoardWindow, s, &(xpmBoardBitmap[kind]), NULL, &attr) == 0) {
3618 useTexture |= kind + 1; textureW[kind] = attr.width; textureH[kind] = attr.height;
3622 void FreeXPMPieces()
3623 { // [HGM] to prevent resoucre leak on calling CreaeXPMPieces() a second time,
3624 // thisroutine has to be called t free the old piece pixmaps
3626 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++)
3627 for (kind=0; kind<4; kind++) XFreePixmap(xDisplay, xpmPieceBitmap2[kind][piece]);
3629 XFreePixmap(xDisplay, xpmLightSquare);
3630 XFreePixmap(xDisplay, xpmDarkSquare);
3634 void CreateXPMPieces()
3638 u_int ss = squareSize;
3640 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3641 XpmColorSymbol symbols[4];
3642 static int redo = False;
3644 if(redo) FreeXPMPieces(); else redo = 1;
3646 /* The XSynchronize calls were copied from CreatePieces.
3647 Not sure if needed, but can't hurt */
3648 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3650 /* Setup translations so piece colors match square colors */
3651 symbols[0].name = "light_piece";
3652 symbols[0].value = appData.whitePieceColor;
3653 symbols[1].name = "dark_piece";
3654 symbols[1].value = appData.blackPieceColor;
3655 symbols[2].name = "light_square";
3656 symbols[2].value = appData.lightSquareColor;
3657 symbols[3].name = "dark_square";
3658 symbols[3].value = appData.darkSquareColor;
3660 attr.valuemask = XpmColorSymbols;
3661 attr.colorsymbols = symbols;
3662 attr.numsymbols = 4;
3664 if (appData.monoMode) {
3665 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3669 if (strlen(appData.pixmapDirectory) == 0) {
3670 XpmPieces* pieces = builtInXpms;
3673 while (pieces->size != squareSize && pieces->size) pieces++;
3674 if (!pieces->size) {
3675 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3678 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3679 for (kind=0; kind<4; kind++) {
3681 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3682 pieces->xpm[piece][kind],
3683 &(xpmPieceBitmap2[kind][piece]),
3684 NULL, &attr)) != 0) {
3685 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3689 if(piece <= (int) WhiteKing)
3690 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3694 xpmJailSquare = xpmLightSquare;
3698 fprintf(stderr, _("\nLoading XPMs...\n"));
3701 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3702 fprintf(stderr, "%d ", piece+1);
3703 for (kind=0; kind<4; kind++) {
3704 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3705 ExpandPathName(appData.pixmapDirectory),
3706 piece > (int) WhiteKing ? "w" : "",
3707 pieceBitmapNames[piece],
3709 if (appData.debugMode) {
3710 fprintf(stderr, _("(File:%s:) "), buf);
3712 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3713 &(xpmPieceBitmap2[kind][piece]),
3714 NULL, &attr)) != 0) {
3715 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3716 // [HGM] missing: read of unorthodox piece failed; substitute King.
3717 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3718 ExpandPathName(appData.pixmapDirectory),
3720 if (appData.debugMode) {
3721 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3723 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3724 &(xpmPieceBitmap2[kind][piece]),
3728 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3733 if(piece <= (int) WhiteKing)
3734 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3737 /* Load light and dark squares */
3738 /* If the LSQ and DSQ pieces don't exist, we will
3739 draw them with solid squares. */
3740 fprintf(stderr, _("light square "));
3741 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3742 if (access(buf, 0) != 0) {
3746 if (appData.debugMode)
3747 fprintf(stderr, _("(File:%s:) "), buf);
3749 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3750 &xpmLightSquare, NULL, &attr)) != 0) {
3751 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3754 fprintf(stderr, _("dark square "));
3755 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3756 ExpandPathName(appData.pixmapDirectory), ss);
3757 if (appData.debugMode) {
3758 fprintf(stderr, _("(File:%s:) "), buf);
3760 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3761 &xpmDarkSquare, NULL, &attr)) != 0) {
3762 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3766 xpmJailSquare = xpmLightSquare;
3767 fprintf(stderr, _("Done.\n"));
3769 oldVariant = -1; // kludge to force re-makig of animation masks
3770 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3773 #endif /* HAVE_LIBXPM */
3776 /* No built-in bitmaps */
3781 u_int ss = squareSize;
3783 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3786 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3787 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3788 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3789 pieceBitmapNames[piece],
3790 ss, kind == SOLID ? 's' : 'o');
3791 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3792 if(piece <= (int)WhiteKing)
3793 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3797 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3801 /* With built-in bitmaps */
3804 BuiltInBits* bib = builtInBits;
3807 u_int ss = squareSize;
3809 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3812 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3814 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3815 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3816 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3817 pieceBitmapNames[piece],
3818 ss, kind == SOLID ? 's' : 'o');
3819 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3820 bib->bits[kind][piece], ss, ss);
3821 if(piece <= (int)WhiteKing)
3822 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3826 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3831 void ReadBitmap(pm, name, bits, wreq, hreq)
3834 unsigned char bits[];
3840 char msg[MSG_SIZ], fullname[MSG_SIZ];
3842 if (*appData.bitmapDirectory != NULLCHAR) {
3843 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3844 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3845 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3846 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3847 &w, &h, pm, &x_hot, &y_hot);
3848 fprintf(stderr, "load %s\n", name);
3849 if (errcode != BitmapSuccess) {
3851 case BitmapOpenFailed:
3852 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3854 case BitmapFileInvalid:
3855 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3857 case BitmapNoMemory:
3858 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3862 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3866 fprintf(stderr, _("%s: %s...using built-in\n"),
3868 } else if (w != wreq || h != hreq) {
3870 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3871 programName, fullname, w, h, wreq, hreq);
3877 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3886 if (lineGap == 0) return;
3888 /* [HR] Split this into 2 loops for non-square boards. */
3890 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3891 gridSegments[i].x1 = 0;
3892 gridSegments[i].x2 =
3893 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3894 gridSegments[i].y1 = gridSegments[i].y2
3895 = lineGap / 2 + (i * (squareSize + lineGap));
3898 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3899 gridSegments[j + i].y1 = 0;
3900 gridSegments[j + i].y2 =
3901 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3902 gridSegments[j + i].x1 = gridSegments[j + i].x2
3903 = lineGap / 2 + (j * (squareSize + lineGap));
3907 static void MenuBarSelect(w, addr, index)
3912 XtActionProc proc = (XtActionProc) addr;
3914 (proc)(NULL, NULL, NULL, NULL);
3917 void CreateMenuBarPopup(parent, name, mb)
3927 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3930 XtSetArg(args[j], XtNleftMargin, 20); j++;
3931 XtSetArg(args[j], XtNrightMargin, 20); j++;
3933 while (mi->string != NULL) {
3934 if (strcmp(mi->string, "----") == 0) {
3935 entry = XtCreateManagedWidget(_(mi->string), smeLineObjectClass,
3938 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3939 entry = XtCreateManagedWidget(mi->ref, smeBSBObjectClass,
3941 XtAddCallback(entry, XtNcallback,
3942 (XtCallbackProc) MenuBarSelect,
3943 (caddr_t) mi->proc);
3949 Widget CreateMenuBar(mb)
3953 Widget anchor, menuBar;
3955 char menuName[MSG_SIZ];
3958 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3959 XtSetArg(args[j], XtNvSpace, 0); j++;
3960 XtSetArg(args[j], XtNborderWidth, 0); j++;
3961 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3962 formWidget, args, j);
3964 while (mb->name != NULL) {
3965 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3966 strncat(menuName, mb->ref, MSG_SIZ - strlen(menuName) - 1);
3968 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3971 shortName[0] = mb->name[0];
3972 shortName[1] = NULLCHAR;
3973 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3976 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3979 XtSetArg(args[j], XtNborderWidth, 0); j++;
3980 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3982 CreateMenuBarPopup(menuBar, menuName, mb);
3988 Widget CreateButtonBar(mi)
3992 Widget button, buttonBar;
3996 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3998 XtSetArg(args[j], XtNhSpace, 0); j++;
4000 XtSetArg(args[j], XtNborderWidth, 0); j++;
4001 XtSetArg(args[j], XtNvSpace, 0); j++;
4002 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
4003 formWidget, args, j);
4005 while (mi->string != NULL) {
4008 XtSetArg(args[j], XtNinternalWidth, 2); j++;
4009 XtSetArg(args[j], XtNborderWidth, 0); j++;
4011 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
4012 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
4013 buttonBar, args, j);
4014 XtAddCallback(button, XtNcallback,
4015 (XtCallbackProc) MenuBarSelect,
4016 (caddr_t) mi->proc);
4023 CreatePieceMenu(name, color)
4030 ChessSquare selection;
4032 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
4033 boardWidget, args, 0);
4035 for (i = 0; i < PIECE_MENU_SIZE; i++) {
4036 String item = pieceMenuStrings[color][i];
4038 if (strcmp(item, "----") == 0) {
4039 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4042 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4043 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4045 selection = pieceMenuTranslation[color][i];
4046 XtAddCallback(entry, XtNcallback,
4047 (XtCallbackProc) PieceMenuSelect,
4048 (caddr_t) selection);
4049 if (selection == WhitePawn || selection == BlackPawn) {
4050 XtSetArg(args[0], XtNpopupOnEntry, entry);
4051 XtSetValues(menu, args, 1);
4064 ChessSquare selection;
4066 whitePieceMenu = CreatePieceMenu("menuW", 0);
4067 blackPieceMenu = CreatePieceMenu("menuB", 1);
4069 XtRegisterGrabAction(PieceMenuPopup, True,
4070 (unsigned)(ButtonPressMask|ButtonReleaseMask),
4071 GrabModeAsync, GrabModeAsync);
4073 XtSetArg(args[0], XtNlabel, _("Drop"));
4074 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
4075 boardWidget, args, 1);
4076 for (i = 0; i < DROP_MENU_SIZE; i++) {
4077 String item = dropMenuStrings[i];
4079 if (strcmp(item, "----") == 0) {
4080 entry = XtCreateManagedWidget(item, smeLineObjectClass,
4083 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
4084 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
4086 selection = dropMenuTranslation[i];
4087 XtAddCallback(entry, XtNcallback,
4088 (XtCallbackProc) DropMenuSelect,
4089 (caddr_t) selection);
4094 void SetupDropMenu()
4102 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
4103 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
4104 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
4105 dmEnables[i].piece);
4106 XtSetSensitive(entry, p != NULL || !appData.testLegality
4107 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
4108 && !appData.icsActive));
4110 while (p && *p++ == dmEnables[i].piece) count++;
4111 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
4113 XtSetArg(args[j], XtNlabel, label); j++;
4114 XtSetValues(entry, args, j);
4118 void PieceMenuPopup(w, event, params, num_params)
4122 Cardinal *num_params;
4124 String whichMenu; int menuNr = -2;
4125 shiftKey = strcmp(params[0], "menuW"); // used to indicate black
4126 if (event->type == ButtonRelease)
4127 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4128 else if (event->type == ButtonPress)
4129 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
4131 case 0: whichMenu = params[0]; break;
4132 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
4134 case -1: if (errorUp) ErrorPopDown();
4137 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
4140 static void PieceMenuSelect(w, piece, junk)
4145 if (pmFromX < 0 || pmFromY < 0) return;
4146 EditPositionMenuEvent(piece, pmFromX, pmFromY);
4149 static void DropMenuSelect(w, piece, junk)
4154 if (pmFromX < 0 || pmFromY < 0) return;
4155 DropMenuEvent(piece, pmFromX, pmFromY);
4158 void WhiteClock(w, event, prms, nprms)
4164 shiftKey = prms[0][0] & 1;
4168 void BlackClock(w, event, prms, nprms)
4174 shiftKey = prms[0][0] & 1;
4180 * If the user selects on a border boundary, return -1; if off the board,
4181 * return -2. Otherwise map the event coordinate to the square.
4183 int EventToSquare(x, limit)
4191 if ((x % (squareSize + lineGap)) >= squareSize)
4193 x /= (squareSize + lineGap);
4199 static void do_flash_delay(msec)
4205 static void drawHighlight(file, rank, gc)
4211 if (lineGap == 0) return;
4214 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
4215 (squareSize + lineGap);
4216 y = lineGap/2 + rank * (squareSize + lineGap);
4218 x = lineGap/2 + file * (squareSize + lineGap);
4219 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
4220 (squareSize + lineGap);
4223 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
4224 squareSize+lineGap, squareSize+lineGap);
4227 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
4228 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4231 SetHighlights(fromX, fromY, toX, toY)
4232 int fromX, fromY, toX, toY;
4234 if (hi1X != fromX || hi1Y != fromY) {
4235 if (hi1X >= 0 && hi1Y >= 0) {
4236 drawHighlight(hi1X, hi1Y, lineGC);
4238 } // [HGM] first erase both, then draw new!
4239 if (hi2X != toX || hi2Y != toY) {
4240 if (hi2X >= 0 && hi2Y >= 0) {
4241 drawHighlight(hi2X, hi2Y, lineGC);
4244 if (hi1X != fromX || hi1Y != fromY) {
4245 if (fromX >= 0 && fromY >= 0) {
4246 drawHighlight(fromX, fromY, highlineGC);
4249 if (hi2X != toX || hi2Y != toY) {
4250 if (toX >= 0 && toY >= 0) {
4251 drawHighlight(toX, toY, highlineGC);
4263 SetHighlights(-1, -1, -1, -1);
4268 SetPremoveHighlights(fromX, fromY, toX, toY)
4269 int fromX, fromY, toX, toY;
4271 if (pm1X != fromX || pm1Y != fromY) {
4272 if (pm1X >= 0 && pm1Y >= 0) {
4273 drawHighlight(pm1X, pm1Y, lineGC);
4275 if (fromX >= 0 && fromY >= 0) {
4276 drawHighlight(fromX, fromY, prelineGC);
4279 if (pm2X != toX || pm2Y != toY) {
4280 if (pm2X >= 0 && pm2Y >= 0) {
4281 drawHighlight(pm2X, pm2Y, lineGC);
4283 if (toX >= 0 && toY >= 0) {
4284 drawHighlight(toX, toY, prelineGC);
4294 ClearPremoveHighlights()
4296 SetPremoveHighlights(-1, -1, -1, -1);
4299 static int CutOutSquare(x, y, x0, y0, kind)
4300 int x, y, *x0, *y0, kind;
4302 int W = BOARD_WIDTH, H = BOARD_HEIGHT;
4303 int nx = x/(squareSize + lineGap), ny = y/(squareSize + lineGap);
4305 if(textureW[kind] < squareSize || textureH[kind] < squareSize) return 0;
4306 if(textureW[kind] < W*squareSize)
4307 *x0 = (textureW[kind] - squareSize) * nx/(W-1);
4309 *x0 = textureW[kind]*nx / W + (textureW[kind] - W*squareSize) / (2*W);
4310 if(textureH[kind] < H*squareSize)
4311 *y0 = (textureH[kind] - squareSize) * ny/(H-1);
4313 *y0 = textureH[kind]*ny / H + (textureH[kind] - H*squareSize) / (2*H);
4317 static void BlankSquare(x, y, color, piece, dest, fac)
4318 int x, y, color, fac;
4321 { // [HGM] extra param 'fac' for forcing destination to (0,0) for copying to animation buffer
4323 if (useImages && color != 2 && (useTexture & color+1) && CutOutSquare(x, y, &x0, &y0, color)) {
4324 XCopyArea(xDisplay, xpmBoardBitmap[color], dest, wlPieceGC, x0, y0,
4325 squareSize, squareSize, x*fac, y*fac);
4327 if (useImages && useImageSqs) {
4331 pm = xpmLightSquare;
4336 case 2: /* neutral */
4341 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4342 squareSize, squareSize, x*fac, y*fac);
4352 case 2: /* neutral */
4357 XFillRectangle(xDisplay, dest, gc, x*fac, y*fac, squareSize, squareSize);
4362 I split out the routines to draw a piece so that I could
4363 make a generic flash routine.
4365 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4367 int square_color, x, y;
4370 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4371 switch (square_color) {
4373 case 2: /* neutral */
4375 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4376 ? *pieceToOutline(piece)
4377 : *pieceToSolid(piece),
4378 dest, bwPieceGC, 0, 0,
4379 squareSize, squareSize, x, y);
4382 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4383 ? *pieceToSolid(piece)
4384 : *pieceToOutline(piece),
4385 dest, wbPieceGC, 0, 0,
4386 squareSize, squareSize, x, y);
4391 static void monoDrawPiece(piece, square_color, x, y, dest)
4393 int square_color, x, y;
4396 switch (square_color) {
4398 case 2: /* neutral */
4400 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4401 ? *pieceToOutline(piece)
4402 : *pieceToSolid(piece),
4403 dest, bwPieceGC, 0, 0,
4404 squareSize, squareSize, x, y, 1);
4407 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4408 ? *pieceToSolid(piece)
4409 : *pieceToOutline(piece),
4410 dest, wbPieceGC, 0, 0,
4411 squareSize, squareSize, x, y, 1);
4416 static void colorDrawPiece(piece, square_color, x, y, dest)
4418 int square_color, x, y;
4421 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4422 switch (square_color) {
4424 XCopyPlane(xDisplay, *pieceToSolid(piece),
4425 dest, (int) piece < (int) BlackPawn
4426 ? wlPieceGC : blPieceGC, 0, 0,
4427 squareSize, squareSize, x, y, 1);
4430 XCopyPlane(xDisplay, *pieceToSolid(piece),
4431 dest, (int) piece < (int) BlackPawn
4432 ? wdPieceGC : bdPieceGC, 0, 0,
4433 squareSize, squareSize, x, y, 1);
4435 case 2: /* neutral */
4437 XCopyPlane(xDisplay, *pieceToSolid(piece),
4438 dest, (int) piece < (int) BlackPawn
4439 ? wjPieceGC : bjPieceGC, 0, 0,
4440 squareSize, squareSize, x, y, 1);
4445 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4447 int square_color, x, y;
4450 int kind, p = piece;
4452 switch (square_color) {
4454 case 2: /* neutral */
4456 if ((int)piece < (int) BlackPawn) {
4464 if ((int)piece < (int) BlackPawn) {
4472 if(appData.upsideDown && flipView) { kind ^= 2; p += p < BlackPawn ? BlackPawn : -BlackPawn; }// swap white and black pieces
4473 if(useTexture & square_color+1) {
4474 BlankSquare(x, y, square_color, piece, dest, 1); // erase previous contents with background
4475 XSetClipMask(xDisplay, wlPieceGC, xpmMask[p]);
4476 XSetClipOrigin(xDisplay, wlPieceGC, x, y);
4477 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece], dest, wlPieceGC, 0, 0, squareSize, squareSize, x, y);
4478 XSetClipMask(xDisplay, wlPieceGC, None);
4479 XSetClipOrigin(xDisplay, wlPieceGC, 0, 0);
4481 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4482 dest, wlPieceGC, 0, 0,
4483 squareSize, squareSize, x, y);
4486 typedef void (*DrawFunc)();
4488 DrawFunc ChooseDrawFunc()
4490 if (appData.monoMode) {
4491 if (DefaultDepth(xDisplay, xScreen) == 1) {
4492 return monoDrawPiece_1bit;
4494 return monoDrawPiece;
4498 return colorDrawPieceImage;
4500 return colorDrawPiece;
4504 /* [HR] determine square color depending on chess variant. */
4505 static int SquareColor(row, column)
4510 if (gameInfo.variant == VariantXiangqi) {
4511 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4513 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4515 } else if (row <= 4) {
4521 square_color = ((column + row) % 2) == 1;
4524 /* [hgm] holdings: next line makes all holdings squares light */
4525 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4527 return square_color;
4530 void DrawSquare(row, column, piece, do_flash)
4531 int row, column, do_flash;
4534 int square_color, x, y, direction, font_ascent, font_descent;
4537 XCharStruct overall;
4541 /* Calculate delay in milliseconds (2-delays per complete flash) */
4542 flash_delay = 500 / appData.flashRate;
4545 x = lineGap + ((BOARD_WIDTH-1)-column) *
4546 (squareSize + lineGap);
4547 y = lineGap + row * (squareSize + lineGap);
4549 x = lineGap + column * (squareSize + lineGap);
4550 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4551 (squareSize + lineGap);
4554 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4556 square_color = SquareColor(row, column);
4558 if ( // [HGM] holdings: blank out area between board and holdings
4559 column == BOARD_LEFT-1 || column == BOARD_RGHT
4560 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4561 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4562 BlankSquare(x, y, 2, EmptySquare, xBoardWindow, 1);
4564 // [HGM] print piece counts next to holdings
4565 string[1] = NULLCHAR;
4566 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4567 string[0] = '0' + piece;
4568 XTextExtents(countFontStruct, string, 1, &direction,
4569 &font_ascent, &font_descent, &overall);
4570 if (appData.monoMode) {
4571 XDrawImageString(xDisplay, xBoardWindow, countGC,
4572 x + squareSize - overall.width - 2,
4573 y + font_ascent + 1, string, 1);
4575 XDrawString(xDisplay, xBoardWindow, countGC,
4576 x + squareSize - overall.width - 2,
4577 y + font_ascent + 1, string, 1);
4580 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4581 string[0] = '0' + piece;
4582 XTextExtents(countFontStruct, string, 1, &direction,
4583 &font_ascent, &font_descent, &overall);
4584 if (appData.monoMode) {
4585 XDrawImageString(xDisplay, xBoardWindow, countGC,
4586 x + 2, y + font_ascent + 1, string, 1);
4588 XDrawString(xDisplay, xBoardWindow, countGC,
4589 x + 2, y + font_ascent + 1, string, 1);
4593 if (piece == EmptySquare || appData.blindfold) {
4594 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4596 drawfunc = ChooseDrawFunc();
4598 if (do_flash && appData.flashCount > 0) {
4599 for (i=0; i<appData.flashCount; ++i) {
4600 drawfunc(piece, square_color, x, y, xBoardWindow);
4601 XSync(xDisplay, False);
4602 do_flash_delay(flash_delay);
4604 BlankSquare(x, y, square_color, piece, xBoardWindow, 1);
4605 XSync(xDisplay, False);
4606 do_flash_delay(flash_delay);
4609 drawfunc(piece, square_color, x, y, xBoardWindow);
4613 string[1] = NULLCHAR;
4614 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4615 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4616 string[0] = 'a' + column - BOARD_LEFT;
4617 XTextExtents(coordFontStruct, string, 1, &direction,
4618 &font_ascent, &font_descent, &overall);
4619 if (appData.monoMode) {
4620 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4621 x + squareSize - overall.width - 2,
4622 y + squareSize - font_descent - 1, string, 1);
4624 XDrawString(xDisplay, xBoardWindow, coordGC,
4625 x + squareSize - overall.width - 2,
4626 y + squareSize - font_descent - 1, string, 1);
4629 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4630 string[0] = ONE + row;
4631 XTextExtents(coordFontStruct, string, 1, &direction,
4632 &font_ascent, &font_descent, &overall);
4633 if (appData.monoMode) {
4634 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4635 x + 2, y + font_ascent + 1, string, 1);
4637 XDrawString(xDisplay, xBoardWindow, coordGC,
4638 x + 2, y + font_ascent + 1, string, 1);
4641 if(!partnerUp && marker[row][column]) {
4642 if(appData.monoMode) {
4643 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? darkSquareGC : lightSquareGC,
4644 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4645 XDrawArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? lightSquareGC : darkSquareGC,
4646 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4648 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4649 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4654 /* Why is this needed on some versions of X? */
4655 void EventProc(widget, unused, event)
4660 if (!XtIsRealized(widget))
4663 switch (event->type) {
4665 if (event->xexpose.count > 0) return; /* no clipping is done */
4666 XDrawPosition(widget, True, NULL);
4667 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4668 flipView = !flipView; partnerUp = !partnerUp;
4669 XDrawPosition(widget, True, NULL);
4670 flipView = !flipView; partnerUp = !partnerUp;
4674 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
4681 void DrawPosition(fullRedraw, board)
4682 /*Boolean*/int fullRedraw;
4685 XDrawPosition(boardWidget, fullRedraw, board);
4688 /* Returns 1 if there are "too many" differences between b1 and b2
4689 (i.e. more than 1 move was made) */
4690 static int too_many_diffs(b1, b2)
4696 for (i=0; i<BOARD_HEIGHT; ++i) {
4697 for (j=0; j<BOARD_WIDTH; ++j) {
4698 if (b1[i][j] != b2[i][j]) {
4699 if (++c > 4) /* Castling causes 4 diffs */
4707 /* Matrix describing castling maneuvers */
4708 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4709 static int castling_matrix[4][5] = {
4710 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4711 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4712 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4713 { 7, 7, 4, 5, 6 } /* 0-0, black */
4716 /* Checks whether castling occurred. If it did, *rrow and *rcol
4717 are set to the destination (row,col) of the rook that moved.
4719 Returns 1 if castling occurred, 0 if not.
4721 Note: Only handles a max of 1 castling move, so be sure
4722 to call too_many_diffs() first.
4724 static int check_castle_draw(newb, oldb, rrow, rcol)
4731 /* For each type of castling... */
4732 for (i=0; i<4; ++i) {
4733 r = castling_matrix[i];
4735 /* Check the 4 squares involved in the castling move */
4737 for (j=1; j<=4; ++j) {
4738 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4745 /* All 4 changed, so it must be a castling move */
4754 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4755 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4757 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4760 void DrawSeekBackground( int left, int top, int right, int bottom )
4762 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4765 void DrawSeekText(char *buf, int x, int y)
4767 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4770 void DrawSeekDot(int x, int y, int colorNr)
4772 int square = colorNr & 0x80;
4775 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4777 XFillRectangle(xDisplay, xBoardWindow, color,
4778 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4780 XFillArc(xDisplay, xBoardWindow, color,
4781 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4784 static int damage[2][BOARD_RANKS][BOARD_FILES];
4787 * event handler for redrawing the board
4789 void XDrawPosition(w, repaint, board)
4791 /*Boolean*/int repaint;
4795 static int lastFlipView = 0;
4796 static int lastBoardValid[2] = {0, 0};
4797 static Board lastBoard[2];
4800 int nr = twoBoards*partnerUp;
4802 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4804 if (board == NULL) {
4805 if (!lastBoardValid[nr]) return;
4806 board = lastBoard[nr];
4808 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4809 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4810 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Flip View"),
4815 * It would be simpler to clear the window with XClearWindow()
4816 * but this causes a very distracting flicker.
4819 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4821 if ( lineGap && IsDrawArrowEnabled())
4822 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4823 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4825 /* If too much changes (begin observing new game, etc.), don't
4827 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4829 /* Special check for castling so we don't flash both the king
4830 and the rook (just flash the king). */
4832 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4833 /* Draw rook with NO flashing. King will be drawn flashing later */
4834 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4835 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4839 /* First pass -- Draw (newly) empty squares and repair damage.
4840 This prevents you from having a piece show up twice while it
4841 is flashing on its new square */
4842 for (i = 0; i < BOARD_HEIGHT; i++)
4843 for (j = 0; j < BOARD_WIDTH; j++)
4844 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4845 || damage[nr][i][j]) {
4846 DrawSquare(i, j, board[i][j], 0);
4847 damage[nr][i][j] = False;
4850 /* Second pass -- Draw piece(s) in new position and flash them */
4851 for (i = 0; i < BOARD_HEIGHT; i++)
4852 for (j = 0; j < BOARD_WIDTH; j++)
4853 if (board[i][j] != lastBoard[nr][i][j]) {
4854 DrawSquare(i, j, board[i][j], do_flash);
4858 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4859 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4860 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4862 for (i = 0; i < BOARD_HEIGHT; i++)
4863 for (j = 0; j < BOARD_WIDTH; j++) {
4864 DrawSquare(i, j, board[i][j], 0);
4865 damage[nr][i][j] = False;
4869 CopyBoard(lastBoard[nr], board);
4870 lastBoardValid[nr] = 1;
4871 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4872 lastFlipView = flipView;
4874 /* Draw highlights */
4875 if (pm1X >= 0 && pm1Y >= 0) {
4876 drawHighlight(pm1X, pm1Y, prelineGC);
4878 if (pm2X >= 0 && pm2Y >= 0) {
4879 drawHighlight(pm2X, pm2Y, prelineGC);
4881 if (hi1X >= 0 && hi1Y >= 0) {
4882 drawHighlight(hi1X, hi1Y, highlineGC);
4884 if (hi2X >= 0 && hi2Y >= 0) {
4885 drawHighlight(hi2X, hi2Y, highlineGC);
4887 DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y);
4889 /* If piece being dragged around board, must redraw that too */
4892 XSync(xDisplay, False);
4897 * event handler for redrawing the board
4899 void DrawPositionProc(w, event, prms, nprms)
4905 XDrawPosition(w, True, NULL);
4910 * event handler for parsing user moves
4912 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4913 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4914 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4915 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4916 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4917 // and at the end FinishMove() to perform the move after optional promotion popups.
4918 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4919 void HandleUserMove(w, event, prms, nprms)
4925 if (w != boardWidget || errorExitStatus != -1) return;
4926 if(nprms) shiftKey = !strcmp(prms[0], "1");
4929 if (event->type == ButtonPress) {
4930 XtPopdown(promotionShell);
4931 XtDestroyWidget(promotionShell);
4932 promotionUp = False;
4940 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4941 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4942 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4945 void AnimateUserMove (Widget w, XEvent * event,
4946 String * params, Cardinal * nParams)
4948 if(!PromoScroll(event->xmotion.x, event->xmotion.y))
4949 DragPieceMove(event->xmotion.x, event->xmotion.y);
4952 void HandlePV (Widget w, XEvent * event,
4953 String * params, Cardinal * nParams)
4954 { // [HGM] pv: walk PV
4955 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4958 static int savedIndex; /* gross that this is global */
4960 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4963 XawTextPosition index, dummy;
4966 XawTextGetSelectionPos(w, &index, &dummy);
4967 XtSetArg(arg, XtNstring, &val);
4968 XtGetValues(w, &arg, 1);
4969 ReplaceComment(savedIndex, val);
4970 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4971 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4974 void EditCommentPopUp(index, title, text)
4979 if (text == NULL) text = "";
4980 NewCommentPopup(title, text, index);
4983 void ICSInputBoxPopUp()
4988 extern Option boxOptions[];
4990 void ICSInputSendText()
4997 edit = boxOptions[0].handle;
4999 XtSetArg(args[j], XtNstring, &val); j++;
5000 XtGetValues(edit, args, j);
5002 SendMultiLineToICS(val);
5003 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5004 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5007 void ICSInputBoxPopDown()
5012 void CommentPopUp(title, text)
5015 savedIndex = currentMove; // [HGM] vari
5016 NewCommentPopup(title, text, currentMove);
5019 void CommentPopDown()
5024 static char *openName;
5029 (void) (*fileProc)(openFP, 0, openName);
5032 void FileNamePopUp(label, def, filter, proc, openMode)
5039 fileProc = proc; /* I can't see a way not */
5040 fileOpenMode = openMode; /* to use globals here */
5041 { // [HGM] use file-selector dialog stolen from Ghostview
5042 int index; // this is not supported yet
5043 if(openFP = XsraSelFile(shellWidget, label, NULL, NULL, _("could not open: "),
5044 (def[0] ? def : NULL), filter, openMode, NULL, &openName))
5045 // [HGM] delay to give expose event opportunity to redraw board after browser-dialog popdown before lengthy load starts
5046 ScheduleDelayedEvent(&DelayedLoad, 50);
5050 void FileNamePopDown()
5052 if (!filenameUp) return;
5053 XtPopdown(fileNameShell);
5054 XtDestroyWidget(fileNameShell);
5059 void FileNameCallback(w, client_data, call_data)
5061 XtPointer client_data, call_data;
5066 XtSetArg(args[0], XtNlabel, &name);
5067 XtGetValues(w, args, 1);
5069 if (strcmp(name, _("cancel")) == 0) {
5074 FileNameAction(w, NULL, NULL, NULL);
5077 void FileNameAction(w, event, prms, nprms)
5089 name = XawDialogGetValueString(w = XtParent(w));
5091 if ((name != NULL) && (*name != NULLCHAR)) {
5092 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5093 XtPopdown(w = XtParent(XtParent(w)));
5097 p = strrchr(buf, ' ');
5104 fullname = ExpandPathName(buf);
5106 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5109 f = fopen(fullname, fileOpenMode);
5111 DisplayError(_("Failed to open file"), errno);
5113 (void) (*fileProc)(f, index, buf);
5120 XtPopdown(w = XtParent(XtParent(w)));
5126 void PromotionPopUp()
5129 Widget dialog, layout;
5131 Dimension bw_width, pw_width;
5133 char *PromoChars = "wglcqrbnkac+=\0";
5136 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5137 XtGetValues(boardWidget, args, j);
5140 XtSetArg(args[j], XtNresizable, True); j++;
5141 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5143 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5144 shellWidget, args, j);
5146 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5147 layoutArgs, XtNumber(layoutArgs));
5150 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5151 XtSetArg(args[j], XtNborderWidth, 0); j++;
5152 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5155 if(gameInfo.variant != VariantShogi) {
5156 if(gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove)) {
5157 XawDialogAddButton(dialog, _("Warlord"), PromotionCallback, PromoChars + 0);
5158 XawDialogAddButton(dialog, _("General"), PromotionCallback, PromoChars + 1);
5159 XawDialogAddButton(dialog, _("Lieutenant"), PromotionCallback, PromoChars + 2);
5160 XawDialogAddButton(dialog, _("Captain"), PromotionCallback, PromoChars + 3);
5162 XawDialogAddButton(dialog, _("Queen"), PromotionCallback, PromoChars + 4);
5163 XawDialogAddButton(dialog, _("Rook"), PromotionCallback, PromoChars + 5);
5164 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback, PromoChars + 6);
5165 XawDialogAddButton(dialog, _("Knight"), PromotionCallback, PromoChars + 7);
5167 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5168 gameInfo.variant == VariantSpartan && !WhiteOnMove(currentMove) ||
5169 gameInfo.variant == VariantGiveaway) {
5170 XawDialogAddButton(dialog, _("King"), PromotionCallback, PromoChars + 8);
5172 if(gameInfo.variant == VariantCapablanca ||
5173 gameInfo.variant == VariantGothic ||
5174 gameInfo.variant == VariantCapaRandom) {
5175 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback, PromoChars + 9);
5176 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback, PromoChars + 10);
5178 } else // [HGM] shogi
5180 XawDialogAddButton(dialog, _("Promote"), PromotionCallback, PromoChars + 11);
5181 XawDialogAddButton(dialog, _("Defer"), PromotionCallback, PromoChars + 12);
5183 XawDialogAddButton(dialog, _("cancel"), PromotionCallback, PromoChars + 13);
5185 XtRealizeWidget(promotionShell);
5186 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5189 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5190 XtGetValues(promotionShell, args, j);
5192 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5193 lineGap + squareSize/3 +
5194 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5195 0 : 6*(squareSize + lineGap)), &x, &y);
5198 XtSetArg(args[j], XtNx, x); j++;
5199 XtSetArg(args[j], XtNy, y); j++;
5200 XtSetValues(promotionShell, args, j);
5202 XtPopup(promotionShell, XtGrabNone);
5207 void PromotionPopDown()
5209 if (!promotionUp) return;
5210 XtPopdown(promotionShell);
5211 XtDestroyWidget(promotionShell);
5212 promotionUp = False;
5215 void PromotionCallback(w, client_data, call_data)
5217 XtPointer client_data, call_data;
5219 int promoChar = * (const char *) client_data;
5223 if (fromX == -1) return;
5230 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5232 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5233 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5238 void ErrorCallback(w, client_data, call_data)
5240 XtPointer client_data, call_data;
5243 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5245 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5251 if (!errorUp) return;
5253 XtPopdown(errorShell);
5254 XtDestroyWidget(errorShell);
5255 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5258 void ErrorPopUp(title, label, modal)
5259 char *title, *label;
5263 Widget dialog, layout;
5267 Dimension bw_width, pw_width;
5268 Dimension pw_height;
5272 XtSetArg(args[i], XtNresizable, True); i++;
5273 XtSetArg(args[i], XtNtitle, title); i++;
5275 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5276 shellWidget, args, i);
5278 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5279 layoutArgs, XtNumber(layoutArgs));
5282 XtSetArg(args[i], XtNlabel, label); i++;
5283 XtSetArg(args[i], XtNborderWidth, 0); i++;
5284 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5287 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5289 XtRealizeWidget(errorShell);
5290 CatchDeleteWindow(errorShell, "ErrorPopDown");
5293 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5294 XtGetValues(boardWidget, args, i);
5296 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5297 XtSetArg(args[i], XtNheight, &pw_height); i++;
5298 XtGetValues(errorShell, args, i);
5301 /* This code seems to tickle an X bug if it is executed too soon
5302 after xboard starts up. The coordinates get transformed as if
5303 the main window was positioned at (0, 0).
5305 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5306 0 - pw_height + squareSize / 3, &x, &y);
5308 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5309 RootWindowOfScreen(XtScreen(boardWidget)),
5310 (bw_width - pw_width) / 2,
5311 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5315 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5318 XtSetArg(args[i], XtNx, x); i++;
5319 XtSetArg(args[i], XtNy, y); i++;
5320 XtSetValues(errorShell, args, i);
5323 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5326 /* Disable all user input other than deleting the window */
5327 static int frozen = 0;
5331 /* Grab by a widget that doesn't accept input */
5332 XtAddGrab(messageWidget, TRUE, FALSE);
5336 /* Undo a FreezeUI */
5339 if (!frozen) return;
5340 XtRemoveGrab(messageWidget);
5344 char *ModeToWidgetName(mode)
5348 case BeginningOfGame:
5349 if (appData.icsActive)
5350 return "menuMode.ICS Client";
5351 else if (appData.noChessProgram ||
5352 *appData.cmailGameName != NULLCHAR)
5353 return "menuMode.Edit Game";
5355 return "menuMode.Machine Black";
5356 case MachinePlaysBlack:
5357 return "menuMode.Machine Black";
5358 case MachinePlaysWhite:
5359 return "menuMode.Machine White";
5361 return "menuMode.Analysis Mode";
5363 return "menuMode.Analyze File";
5364 case TwoMachinesPlay:
5365 return "menuMode.Two Machines";
5367 return "menuMode.Edit Game";
5368 case PlayFromGameFile:
5369 return "menuFile.Load Game";
5371 return "menuMode.Edit Position";
5373 return "menuMode.Training";
5374 case IcsPlayingWhite:
5375 case IcsPlayingBlack:
5379 return "menuMode.ICS Client";
5386 void ModeHighlight()
5389 static int oldPausing = FALSE;
5390 static GameMode oldmode = (GameMode) -1;
5393 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5395 if (pausing != oldPausing) {
5396 oldPausing = pausing;
5398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5400 XtSetArg(args[0], XtNleftBitmap, None);
5402 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5405 if (appData.showButtonBar) {
5406 /* Always toggle, don't set. Previous code messes up when
5407 invoked while the button is pressed, as releasing it
5408 toggles the state again. */
5411 XtSetArg(args[0], XtNbackground, &oldbg);
5412 XtSetArg(args[1], XtNforeground, &oldfg);
5413 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5415 XtSetArg(args[0], XtNbackground, oldfg);
5416 XtSetArg(args[1], XtNforeground, oldbg);
5418 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5422 wname = ModeToWidgetName(oldmode);
5423 if (wname != NULL) {
5424 XtSetArg(args[0], XtNleftBitmap, None);
5425 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5427 wname = ModeToWidgetName(gameMode);
5428 if (wname != NULL) {
5429 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5430 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5433 XtSetArg(args[0], XtNleftBitmap, matchMode && matchGame < appData.matchGames ? xMarkPixmap : None);
5434 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Machine Match"), args, 1);
5436 /* Maybe all the enables should be handled here, not just this one */
5437 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5438 gameMode == Training || gameMode == PlayFromGameFile);
5443 * Button/menu procedures
5445 void ResetProc(w, event, prms, nprms)
5454 int LoadGamePopUp(f, gameNumber, title)
5459 cmailMsgLoaded = FALSE;
5460 if (gameNumber == 0) {
5461 int error = GameListBuild(f);
5463 DisplayError(_("Cannot build game list"), error);
5464 } else if (!ListEmpty(&gameList) &&
5465 ((ListGame *) gameList.tailPred)->number > 1) {
5466 GameListPopUp(f, title);
5472 return LoadGame(f, gameNumber, title, FALSE);
5475 void LoadGameProc(w, event, prms, nprms)
5481 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5484 FileNamePopUp(_("Load game file name?"), "", ".pgn .game", LoadGamePopUp, "rb");
5487 void LoadNextGameProc(w, event, prms, nprms)
5496 void LoadPrevGameProc(w, event, prms, nprms)
5505 void ReloadGameProc(w, event, prms, nprms)
5514 void LoadNextPositionProc(w, event, prms, nprms)
5523 void LoadPrevPositionProc(w, event, prms, nprms)
5532 void ReloadPositionProc(w, event, prms, nprms)
5541 void LoadPositionProc(w, event, prms, nprms)
5547 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5550 FileNamePopUp(_("Load position file name?"), "", ".fen .epd .pos", LoadPosition, "rb");
5553 void SaveGameProc(w, event, prms, nprms)
5559 FileNamePopUp(_("Save game file name?"),
5560 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5561 appData.oldSaveStyle ? ".game" : ".pgn",
5565 void SavePositionProc(w, event, prms, nprms)
5571 FileNamePopUp(_("Save position file name?"),
5572 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5573 appData.oldSaveStyle ? ".pos" : ".fen",
5577 void ReloadCmailMsgProc(w, event, prms, nprms)
5583 ReloadCmailMsgEvent(FALSE);
5586 void MailMoveProc(w, event, prms, nprms)
5595 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5596 char *selected_fen_position=NULL;
5599 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5600 Atom *type_return, XtPointer *value_return,
5601 unsigned long *length_return, int *format_return)
5603 char *selection_tmp;
5605 if (!selected_fen_position) return False; /* should never happen */
5606 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5607 /* note: since no XtSelectionDoneProc was registered, Xt will
5608 * automatically call XtFree on the value returned. So have to
5609 * make a copy of it allocated with XtMalloc */
5610 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5611 safeStrCpy(selection_tmp, selected_fen_position, strlen(selected_fen_position)+16 );
5613 *value_return=selection_tmp;
5614 *length_return=strlen(selection_tmp);
5615 *type_return=*target;
5616 *format_return = 8; /* bits per byte */
5618 } else if (*target == XA_TARGETS(xDisplay)) {
5619 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5620 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5621 targets_tmp[1] = XA_STRING;
5622 *value_return = targets_tmp;
5623 *type_return = XA_ATOM;
5626 // This code leads to a read of value_return out of bounds on 64-bit systems.
5627 // Other code which I have seen always sets *format_return to 32 independent of
5628 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5629 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5630 *format_return = 8 * sizeof(Atom);
5631 if (*format_return > 32) {
5632 *length_return *= *format_return / 32;
5633 *format_return = 32;
5636 *format_return = 32;
5644 /* note: when called from menu all parameters are NULL, so no clue what the
5645 * Widget which was clicked on was, or what the click event was
5647 void CopyPositionProc(w, event, prms, nprms)
5654 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5655 * have a notion of a position that is selected but not copied.
5656 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5658 if(gameMode == EditPosition) EditPositionDone(TRUE);
5659 if (selected_fen_position) free(selected_fen_position);
5660 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5661 if (!selected_fen_position) return;
5662 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5664 SendPositionSelection,
5665 NULL/* lose_ownership_proc */ ,
5666 NULL/* transfer_done_proc */);
5667 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5669 SendPositionSelection,
5670 NULL/* lose_ownership_proc */ ,
5671 NULL/* transfer_done_proc */);
5674 /* function called when the data to Paste is ready */
5676 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5677 Atom *type, XtPointer value, unsigned long *len, int *format)
5680 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5681 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5682 EditPositionPasteFEN(fenstr);
5686 /* called when Paste Position button is pressed,
5687 * all parameters will be NULL */
5688 void PastePositionProc(w, event, prms, nprms)
5694 XtGetSelectionValue(menuBarWidget,
5695 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5696 /* (XtSelectionCallbackProc) */ PastePositionCB,
5697 NULL, /* client_data passed to PastePositionCB */
5699 /* better to use the time field from the event that triggered the
5700 * call to this function, but that isn't trivial to get
5708 SendGameSelection(Widget w, Atom *selection, Atom *target,
5709 Atom *type_return, XtPointer *value_return,
5710 unsigned long *length_return, int *format_return)
5712 char *selection_tmp;
5714 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5715 FILE* f = fopen(gameCopyFilename, "r");
5718 if (f == NULL) return False;
5722 selection_tmp = XtMalloc(len + 1);
5723 count = fread(selection_tmp, 1, len, f);
5726 XtFree(selection_tmp);
5729 selection_tmp[len] = NULLCHAR;
5730 *value_return = selection_tmp;
5731 *length_return = len;
5732 *type_return = *target;
5733 *format_return = 8; /* bits per byte */
5735 } else if (*target == XA_TARGETS(xDisplay)) {
5736 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5737 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5738 targets_tmp[1] = XA_STRING;
5739 *value_return = targets_tmp;
5740 *type_return = XA_ATOM;
5743 // This code leads to a read of value_return out of bounds on 64-bit systems.
5744 // Other code which I have seen always sets *format_return to 32 independent of
5745 // sizeof(Atom) without adjusting *length_return. For instance see TextConvertSelection()
5746 // at http://cgit.freedesktop.org/xorg/lib/libXaw/tree/src/Text.c -- BJ
5747 *format_return = 8 * sizeof(Atom);
5748 if (*format_return > 32) {
5749 *length_return *= *format_return / 32;
5750 *format_return = 32;
5753 *format_return = 32;
5761 void CopySomething()
5764 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5765 * have a notion of a game that is selected but not copied.
5766 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5768 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5771 NULL/* lose_ownership_proc */ ,
5772 NULL/* transfer_done_proc */);
5773 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5776 NULL/* lose_ownership_proc */ ,
5777 NULL/* transfer_done_proc */);
5780 /* note: when called from menu all parameters are NULL, so no clue what the
5781 * Widget which was clicked on was, or what the click event was
5783 void CopyGameProc(w, event, prms, nprms)
5791 ret = SaveGameToFile(gameCopyFilename, FALSE);
5797 void CopyGameListProc(w, event, prms, nprms)
5803 if(!SaveGameListAsText(fopen(gameCopyFilename, "w"))) return;
5807 /* function called when the data to Paste is ready */
5809 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5810 Atom *type, XtPointer value, unsigned long *len, int *format)
5813 if (value == NULL || *len == 0) {
5814 return; /* nothing had been selected to copy */
5816 f = fopen(gamePasteFilename, "w");
5818 DisplayError(_("Can't open temp file"), errno);
5821 fwrite(value, 1, *len, f);
5824 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5827 /* called when Paste Game button is pressed,
5828 * all parameters will be NULL */
5829 void PasteGameProc(w, event, prms, nprms)
5835 XtGetSelectionValue(menuBarWidget,
5836 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5837 /* (XtSelectionCallbackProc) */ PasteGameCB,
5838 NULL, /* client_data passed to PasteGameCB */
5840 /* better to use the time field from the event that triggered the
5841 * call to this function, but that isn't trivial to get
5851 SaveGameProc(NULL, NULL, NULL, NULL);
5855 void QuitProc(w, event, prms, nprms)
5864 void PauseProc(w, event, prms, nprms)
5874 void MachineBlackProc(w, event, prms, nprms)
5880 MachineBlackEvent();
5883 void MachineWhiteProc(w, event, prms, nprms)
5889 MachineWhiteEvent();
5892 void AnalyzeModeProc(w, event, prms, nprms)
5900 if (!first.analysisSupport) {
5901 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5902 DisplayError(buf, 0);
5905 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
5906 if (appData.icsActive) {
5907 if (gameMode != IcsObserving) {
5908 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
5909 DisplayError(buf, 0);
5911 if (appData.icsEngineAnalyze) {
5912 if (appData.debugMode)
5913 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
5919 /* if enable, use want disable icsEngineAnalyze */
5920 if (appData.icsEngineAnalyze) {
5925 appData.icsEngineAnalyze = TRUE;
5926 if (appData.debugMode)
5927 fprintf(debugFP, _("ICS engine analyze starting... \n"));
5929 #ifndef OPTIONSDIALOG
5930 if (!appData.showThinking)
5931 ShowThinkingProc(w,event,prms,nprms);
5937 void AnalyzeFileProc(w, event, prms, nprms)
5943 if (!first.analysisSupport) {
5945 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
5946 DisplayError(buf, 0);
5949 // Reset(FALSE, TRUE);
5950 #ifndef OPTIONSDIALOG
5951 if (!appData.showThinking)
5952 ShowThinkingProc(w,event,prms,nprms);
5955 // FileNamePopUp(_("File to analyze"), "", ".pgn .game", LoadGamePopUp, "rb");
5956 AnalysisPeriodicEvent(1);
5959 void TwoMachinesProc(w, event, prms, nprms)
5968 void MatchProc(w, event, prms, nprms)
5977 void IcsClientProc(w, event, prms, nprms)
5986 void EditGameProc(w, event, prms, nprms)
5995 void EditPositionProc(w, event, prms, nprms)
6001 EditPositionEvent();
6004 void TrainingProc(w, event, prms, nprms)
6013 void EditCommentProc(w, event, prms, nprms)
6021 if (PopDown(1)) { // popdown succesful
6023 XtSetArg(args[j], XtNleftBitmap, None); j++;
6024 XtSetValues(XtNameToWidget(menuBarWidget, "menuEdit.Edit Comment"), args, j);
6025 XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Comments"), args, j);
6026 } else // was not up
6030 void IcsInputBoxProc(w, event, prms, nprms)
6036 if (!PopDown(4)) ICSInputBoxPopUp();
6039 void AcceptProc(w, event, prms, nprms)
6048 void DeclineProc(w, event, prms, nprms)
6057 void RematchProc(w, event, prms, nprms)
6066 void CallFlagProc(w, event, prms, nprms)
6075 void DrawProc(w, event, prms, nprms)
6084 void AbortProc(w, event, prms, nprms)
6093 void AdjournProc(w, event, prms, nprms)
6102 void ResignProc(w, event, prms, nprms)
6111 void AdjuWhiteProc(w, event, prms, nprms)
6117 UserAdjudicationEvent(+1);
6120 void AdjuBlackProc(w, event, prms, nprms)
6126 UserAdjudicationEvent(-1);
6129 void AdjuDrawProc(w, event, prms, nprms)
6135 UserAdjudicationEvent(0);
6138 void EnterKeyProc(w, event, prms, nprms)
6144 if (shellUp[4] == True)
6148 void UpKeyProc(w, event, prms, nprms)
6153 { // [HGM] input: let up-arrow recall previous line from history
6160 if (!shellUp[4]) return;
6161 edit = boxOptions[0].handle;
6163 XtSetArg(args[j], XtNstring, &val); j++;
6164 XtGetValues(edit, args, j);
6165 val = PrevInHistory(val);
6166 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6167 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6169 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6170 XawTextReplace(edit, 0, 0, &t);
6171 XawTextSetInsertionPoint(edit, 9999);
6175 void DownKeyProc(w, event, prms, nprms)
6180 { // [HGM] input: let down-arrow recall next line from history
6185 if (!shellUp[4]) return;
6186 edit = boxOptions[0].handle;
6187 val = NextInHistory();
6188 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6189 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6191 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6192 XawTextReplace(edit, 0, 0, &t);
6193 XawTextSetInsertionPoint(edit, 9999);
6197 void StopObservingProc(w, event, prms, nprms)
6203 StopObservingEvent();
6206 void StopExaminingProc(w, event, prms, nprms)
6212 StopExaminingEvent();
6215 void UploadProc(w, event, prms, nprms)
6225 void ForwardProc(w, event, prms, nprms)
6235 void BackwardProc(w, event, prms, nprms)
6244 void TempBackwardProc(w, event, prms, nprms)
6250 if (!TempBackwardActive) {
6251 TempBackwardActive = True;
6256 void TempForwardProc(w, event, prms, nprms)
6262 /* Check to see if triggered by a key release event for a repeating key.
6263 * If so the next queued event will be a key press of the same key at the same time */
6264 if (XEventsQueued(xDisplay, QueuedAfterReading)) {
6266 XPeekEvent(xDisplay, &next);
6267 if (next.type == KeyPress && next.xkey.time == event->xkey.time &&
6268 next.xkey.keycode == event->xkey.keycode)
6272 TempBackwardActive = False;
6275 void ToStartProc(w, event, prms, nprms)
6284 void ToEndProc(w, event, prms, nprms)
6293 void RevertProc(w, event, prms, nprms)
6302 void AnnotateProc(w, event, prms, nprms)
6311 void TruncateGameProc(w, event, prms, nprms)
6317 TruncateGameEvent();
6319 void RetractMoveProc(w, event, prms, nprms)
6328 void MoveNowProc(w, event, prms, nprms)
6337 void FlipViewProc(w, event, prms, nprms)
6343 flipView = !flipView;
6344 DrawPosition(True, NULL);
6347 void PonderNextMoveProc(w, event, prms, nprms)
6355 PonderNextMoveEvent(!appData.ponderNextMove);
6356 #ifndef OPTIONSDIALOG
6357 if (appData.ponderNextMove) {
6358 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6360 XtSetArg(args[0], XtNleftBitmap, None);
6362 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6367 #ifndef OPTIONSDIALOG
6368 void AlwaysQueenProc(w, event, prms, nprms)
6376 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6378 if (appData.alwaysPromoteToQueen) {
6379 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6381 XtSetArg(args[0], XtNleftBitmap, None);
6383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6387 void AnimateDraggingProc(w, event, prms, nprms)
6395 appData.animateDragging = !appData.animateDragging;
6397 if (appData.animateDragging) {
6398 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6401 XtSetArg(args[0], XtNleftBitmap, None);
6403 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6407 void AnimateMovingProc(w, event, prms, nprms)
6415 appData.animate = !appData.animate;
6417 if (appData.animate) {
6418 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6421 XtSetArg(args[0], XtNleftBitmap, None);
6423 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6427 void AutoflagProc(w, event, prms, nprms)
6435 appData.autoCallFlag = !appData.autoCallFlag;
6437 if (appData.autoCallFlag) {
6438 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6440 XtSetArg(args[0], XtNleftBitmap, None);
6442 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6446 void AutoflipProc(w, event, prms, nprms)
6454 appData.autoFlipView = !appData.autoFlipView;
6456 if (appData.autoFlipView) {
6457 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6459 XtSetArg(args[0], XtNleftBitmap, None);
6461 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6465 void BlindfoldProc(w, event, prms, nprms)
6473 appData.blindfold = !appData.blindfold;
6475 if (appData.blindfold) {
6476 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6478 XtSetArg(args[0], XtNleftBitmap, None);
6480 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6483 DrawPosition(True, NULL);
6486 void TestLegalityProc(w, event, prms, nprms)
6494 appData.testLegality = !appData.testLegality;
6496 if (appData.testLegality) {
6497 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6499 XtSetArg(args[0], XtNleftBitmap, None);
6501 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6506 void FlashMovesProc(w, event, prms, nprms)
6514 if (appData.flashCount == 0) {
6515 appData.flashCount = 3;
6517 appData.flashCount = -appData.flashCount;
6520 if (appData.flashCount > 0) {
6521 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6523 XtSetArg(args[0], XtNleftBitmap, None);
6525 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6530 void HighlightDraggingProc(w, event, prms, nprms)
6538 appData.highlightDragging = !appData.highlightDragging;
6540 if (appData.highlightDragging) {
6541 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6543 XtSetArg(args[0], XtNleftBitmap, None);
6545 XtSetValues(XtNameToWidget(menuBarWidget,
6546 "menuOptions.Highlight Dragging"), args, 1);
6550 void HighlightLastMoveProc(w, event, prms, nprms)
6558 appData.highlightLastMove = !appData.highlightLastMove;
6560 if (appData.highlightLastMove) {
6561 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6563 XtSetArg(args[0], XtNleftBitmap, None);
6565 XtSetValues(XtNameToWidget(menuBarWidget,
6566 "menuOptions.Highlight Last Move"), args, 1);
6569 void HighlightArrowProc(w, event, prms, nprms)
6577 appData.highlightMoveWithArrow = !appData.highlightMoveWithArrow;
6579 if (appData.highlightMoveWithArrow) {
6580 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6582 XtSetArg(args[0], XtNleftBitmap, None);
6584 XtSetValues(XtNameToWidget(menuBarWidget,
6585 "menuOptions.Arrow"), args, 1);
6589 void IcsAlarmProc(w, event, prms, nprms)
6597 appData.icsAlarm = !appData.icsAlarm;
6599 if (appData.icsAlarm) {
6600 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6602 XtSetArg(args[0], XtNleftBitmap, None);
6604 XtSetValues(XtNameToWidget(menuBarWidget,
6605 "menuOptions.ICS Alarm"), args, 1);
6609 void MoveSoundProc(w, event, prms, nprms)
6617 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6619 if (appData.ringBellAfterMoves) {
6620 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6622 XtSetArg(args[0], XtNleftBitmap, None);
6624 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6628 void OneClickProc(w, event, prms, nprms)
6636 appData.oneClick = !appData.oneClick;
6638 if (appData.oneClick) {
6639 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6641 XtSetArg(args[0], XtNleftBitmap, None);
6643 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.OneClick"),
6647 void PeriodicUpdatesProc(w, event, prms, nprms)
6655 PeriodicUpdatesEvent(!appData.periodicUpdates);
6657 if (appData.periodicUpdates) {
6658 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6660 XtSetArg(args[0], XtNleftBitmap, None);
6662 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6666 void PopupExitMessageProc(w, event, prms, nprms)
6674 appData.popupExitMessage = !appData.popupExitMessage;
6676 if (appData.popupExitMessage) {
6677 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6679 XtSetArg(args[0], XtNleftBitmap, None);
6681 XtSetValues(XtNameToWidget(menuBarWidget,
6682 "menuOptions.Popup Exit Message"), args, 1);
6685 void PopupMoveErrorsProc(w, event, prms, nprms)
6693 appData.popupMoveErrors = !appData.popupMoveErrors;
6695 if (appData.popupMoveErrors) {
6696 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6698 XtSetArg(args[0], XtNleftBitmap, None);
6700 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6705 void PremoveProc(w, event, prms, nprms)
6713 appData.premove = !appData.premove;
6715 if (appData.premove) {
6716 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6718 XtSetArg(args[0], XtNleftBitmap, None);
6720 XtSetValues(XtNameToWidget(menuBarWidget,
6721 "menuOptions.Premove"), args, 1);
6725 void ShowCoordsProc(w, event, prms, nprms)
6733 appData.showCoords = !appData.showCoords;
6735 if (appData.showCoords) {
6736 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6738 XtSetArg(args[0], XtNleftBitmap, None);
6740 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6743 DrawPosition(True, NULL);
6746 void ShowThinkingProc(w, event, prms, nprms)
6752 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6753 ShowThinkingEvent();
6756 void HideThinkingProc(w, event, prms, nprms)
6764 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6765 ShowThinkingEvent();
6767 if (appData.hideThinkingFromHuman) {
6768 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6770 XtSetArg(args[0], XtNleftBitmap, None);
6772 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6777 void SaveOnExitProc(w, event, prms, nprms)
6785 saveSettingsOnExit = !saveSettingsOnExit;
6787 if (saveSettingsOnExit) {
6788 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6790 XtSetArg(args[0], XtNleftBitmap, None);
6792 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6796 void SaveSettingsProc(w, event, prms, nprms)
6802 SaveSettings(settingsFileName);
6805 void InfoProc(w, event, prms, nprms)
6812 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6817 void ManProc(w, event, prms, nprms)
6825 if (nprms && *nprms > 0)
6829 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
6833 void HintProc(w, event, prms, nprms)
6842 void BookProc(w, event, prms, nprms)
6851 void AboutProc(w, event, prms, nprms)
6859 char *zippy = _(" (with Zippy code)");
6863 snprintf(buf, sizeof(buf),
6865 "Copyright 1991 Digital Equipment Corporation\n"
6866 "Enhancements Copyright 1992-2009 Free Software Foundation\n"
6867 "Enhancements Copyright 2005 Alessandro Scotti\n\n"
6868 "%s is free software and carries NO WARRANTY;"
6869 "see the file COPYING for more information."),
6870 programVersion, zippy, PACKAGE);
6871 ErrorPopUp(_("About XBoard"), buf, FALSE);
6874 void DebugProc(w, event, prms, nprms)
6880 appData.debugMode = !appData.debugMode;
6883 void AboutGameProc(w, event, prms, nprms)
6892 void NothingProc(w, event, prms, nprms)
6901 void DisplayMessage(message, extMessage)
6902 char *message, *extMessage;
6904 /* display a message in the message widget */
6913 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
6918 message = extMessage;
6922 safeStrCpy(lastMsg, message, MSG_SIZ); // [HGM] make available
6924 /* need to test if messageWidget already exists, since this function
6925 can also be called during the startup, if for example a Xresource
6926 is not set up correctly */
6929 XtSetArg(arg, XtNlabel, message);
6930 XtSetValues(messageWidget, &arg, 1);
6936 void DisplayTitle(text)
6941 char title[MSG_SIZ];
6944 if (text == NULL) text = "";
6946 if (appData.titleInWindow) {
6948 XtSetArg(args[i], XtNlabel, text); i++;
6949 XtSetValues(titleWidget, args, i);
6952 if (*text != NULLCHAR) {
6953 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
6954 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
6955 } else if (appData.icsActive) {
6956 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
6957 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
6958 } else if (appData.cmailGameName[0] != NULLCHAR) {
6959 snprintf(icon, sizeof(icon), "%s", "CMail");
6960 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
6962 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
6963 } else if (gameInfo.variant == VariantGothic) {
6964 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6965 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
6968 } else if (gameInfo.variant == VariantFalcon) {
6969 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6970 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
6972 } else if (appData.noChessProgram) {
6973 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
6974 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
6976 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
6977 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
6980 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
6981 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
6982 XtSetValues(shellWidget, args, i);
6983 XSync(xDisplay, False);
6988 DisplayError(message, error)
6995 if (appData.debugMode || appData.matchMode) {
6996 fprintf(stderr, "%s: %s\n", programName, message);
6999 if (appData.debugMode || appData.matchMode) {
7000 fprintf(stderr, "%s: %s: %s\n",
7001 programName, message, strerror(error));
7003 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7006 ErrorPopUp(_("Error"), message, FALSE);
7010 void DisplayMoveError(message)
7015 DrawPosition(FALSE, NULL);
7016 if (appData.debugMode || appData.matchMode) {
7017 fprintf(stderr, "%s: %s\n", programName, message);
7019 if (appData.popupMoveErrors) {
7020 ErrorPopUp(_("Error"), message, FALSE);
7022 DisplayMessage(message, "");
7027 void DisplayFatalError(message, error, status)
7033 errorExitStatus = status;
7035 fprintf(stderr, "%s: %s\n", programName, message);
7037 fprintf(stderr, "%s: %s: %s\n",
7038 programName, message, strerror(error));
7039 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7042 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7043 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7049 void DisplayInformation(message)
7053 ErrorPopUp(_("Information"), message, TRUE);
7056 void DisplayNote(message)
7060 ErrorPopUp(_("Note"), message, FALSE);
7064 NullXErrorCheck(dpy, error_event)
7066 XErrorEvent *error_event;
7071 void DisplayIcsInteractionTitle(message)
7074 if (oldICSInteractionTitle == NULL) {
7075 /* Magic to find the old window title, adapted from vim */
7076 char *wina = getenv("WINDOWID");
7078 Window win = (Window) atoi(wina);
7079 Window root, parent, *children;
7080 unsigned int nchildren;
7081 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7083 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7084 if (!XQueryTree(xDisplay, win, &root, &parent,
7085 &children, &nchildren)) break;
7086 if (children) XFree((void *)children);
7087 if (parent == root || parent == 0) break;
7090 XSetErrorHandler(oldHandler);
7092 if (oldICSInteractionTitle == NULL) {
7093 oldICSInteractionTitle = "xterm";
7096 printf("\033]0;%s\007", message);
7100 char pendingReplyPrefix[MSG_SIZ];
7101 ProcRef pendingReplyPR;
7103 void AskQuestionProc(w, event, prms, nprms)
7110 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7114 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7117 void AskQuestionPopDown()
7119 if (!askQuestionUp) return;
7120 XtPopdown(askQuestionShell);
7121 XtDestroyWidget(askQuestionShell);
7122 askQuestionUp = False;
7125 void AskQuestionReplyAction(w, event, prms, nprms)
7135 reply = XawDialogGetValueString(w = XtParent(w));
7136 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7137 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7138 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7139 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7140 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7141 AskQuestionPopDown();
7143 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7146 void AskQuestionCallback(w, client_data, call_data)
7148 XtPointer client_data, call_data;
7153 XtSetArg(args[0], XtNlabel, &name);
7154 XtGetValues(w, args, 1);
7156 if (strcmp(name, _("cancel")) == 0) {
7157 AskQuestionPopDown();
7159 AskQuestionReplyAction(w, NULL, NULL, NULL);
7163 void AskQuestion(title, question, replyPrefix, pr)
7164 char *title, *question, *replyPrefix;
7168 Widget popup, layout, dialog, edit;
7174 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7175 pendingReplyPR = pr;
7178 XtSetArg(args[i], XtNresizable, True); i++;
7179 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7180 askQuestionShell = popup =
7181 XtCreatePopupShell(title, transientShellWidgetClass,
7182 shellWidget, args, i);
7185 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7186 layoutArgs, XtNumber(layoutArgs));
7189 XtSetArg(args[i], XtNlabel, question); i++;
7190 XtSetArg(args[i], XtNvalue, ""); i++;
7191 XtSetArg(args[i], XtNborderWidth, 0); i++;
7192 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7195 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7196 (XtPointer) dialog);
7197 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7198 (XtPointer) dialog);
7200 XtRealizeWidget(popup);
7201 CatchDeleteWindow(popup, "AskQuestionPopDown");
7203 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7204 &x, &y, &win_x, &win_y, &mask);
7206 XtSetArg(args[0], XtNx, x - 10);
7207 XtSetArg(args[1], XtNy, y - 30);
7208 XtSetValues(popup, args, 2);
7210 XtPopup(popup, XtGrabExclusive);
7211 askQuestionUp = True;
7213 edit = XtNameToWidget(dialog, "*value");
7214 XtSetKeyboardFocus(popup, edit);
7222 if (*name == NULLCHAR) {
7224 } else if (strcmp(name, "$") == 0) {
7225 putc(BELLCHAR, stderr);
7228 char *prefix = "", *sep = "";
7229 if(appData.soundProgram[0] == NULLCHAR) return;
7230 if(!strchr(name, '/')) { prefix = appData.soundDirectory; sep = "/"; }
7231 snprintf(buf, sizeof(buf), "%s '%s%s%s' &", appData.soundProgram, prefix, sep, name);
7239 PlaySound(appData.soundMove);
7245 PlaySound(appData.soundIcsWin);
7251 PlaySound(appData.soundIcsLoss);
7257 PlaySound(appData.soundIcsDraw);
7261 PlayIcsUnfinishedSound()
7263 PlaySound(appData.soundIcsUnfinished);
7269 PlaySound(appData.soundIcsAlarm);
7275 PlaySound(appData.soundTell);
7281 system("stty echo");
7288 system("stty -echo");
7293 RunCommand(char *buf)
7299 Colorize(cc, continuation)
7304 int count, outCount, error;
7306 if (textColors[(int)cc].bg > 0) {
7307 if (textColors[(int)cc].fg > 0) {
7308 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7309 textColors[(int)cc].fg, textColors[(int)cc].bg);
7311 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7312 textColors[(int)cc].bg);
7315 if (textColors[(int)cc].fg > 0) {
7316 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7317 textColors[(int)cc].fg);
7319 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7322 count = strlen(buf);
7323 outCount = OutputToProcess(NoProc, buf, count, &error);
7324 if (outCount < count) {
7325 DisplayFatalError(_("Error writing to display"), error, 1);
7328 if (continuation) return;
7331 PlaySound(appData.soundShout);
7334 PlaySound(appData.soundSShout);
7337 PlaySound(appData.soundChannel1);
7340 PlaySound(appData.soundChannel);
7343 PlaySound(appData.soundKibitz);
7346 PlaySound(appData.soundTell);
7348 case ColorChallenge:
7349 PlaySound(appData.soundChallenge);
7352 PlaySound(appData.soundRequest);
7355 PlaySound(appData.soundSeek);
7366 return getpwuid(getuid())->pw_name;
7370 ExpandPathName(path)
7373 static char static_buf[4*MSG_SIZ];
7374 char *d, *s, buf[4*MSG_SIZ];
7380 while (*s && isspace(*s))
7389 if (*(s+1) == '/') {
7390 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7394 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7395 { char *p; if(p = strchr(buf, '/')) *p = 0; }
7396 pwd = getpwnam(buf);
7399 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7403 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7404 strcat(d, strchr(s+1, '/'));
7408 safeStrCpy(d, s, 4*MSG_SIZ );
7415 static char host_name[MSG_SIZ];
7417 #if HAVE_GETHOSTNAME
7418 gethostname(host_name, MSG_SIZ);
7420 #else /* not HAVE_GETHOSTNAME */
7421 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7422 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7424 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7426 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7427 #endif /* not HAVE_GETHOSTNAME */
7430 XtIntervalId delayedEventTimerXID = 0;
7431 DelayedEventCallback delayedEventCallback = 0;
7436 delayedEventTimerXID = 0;
7437 delayedEventCallback();
7441 ScheduleDelayedEvent(cb, millisec)
7442 DelayedEventCallback cb; long millisec;
7444 if(delayedEventTimerXID && delayedEventCallback == cb)
7445 // [HGM] alive: replace, rather than add or flush identical event
7446 XtRemoveTimeOut(delayedEventTimerXID);
7447 delayedEventCallback = cb;
7448 delayedEventTimerXID =
7449 XtAppAddTimeOut(appContext, millisec,
7450 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7453 DelayedEventCallback
7456 if (delayedEventTimerXID) {
7457 return delayedEventCallback;
7464 CancelDelayedEvent()
7466 if (delayedEventTimerXID) {
7467 XtRemoveTimeOut(delayedEventTimerXID);
7468 delayedEventTimerXID = 0;
7472 XtIntervalId loadGameTimerXID = 0;
7474 int LoadGameTimerRunning()
7476 return loadGameTimerXID != 0;
7479 int StopLoadGameTimer()
7481 if (loadGameTimerXID != 0) {
7482 XtRemoveTimeOut(loadGameTimerXID);
7483 loadGameTimerXID = 0;
7491 LoadGameTimerCallback(arg, id)
7495 loadGameTimerXID = 0;
7500 StartLoadGameTimer(millisec)
7504 XtAppAddTimeOut(appContext, millisec,
7505 (XtTimerCallbackProc) LoadGameTimerCallback,
7509 XtIntervalId analysisClockXID = 0;
7512 AnalysisClockCallback(arg, id)
7516 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7517 || appData.icsEngineAnalyze) { // [DM]
7518 AnalysisPeriodicEvent(0);
7519 StartAnalysisClock();
7524 StartAnalysisClock()
7527 XtAppAddTimeOut(appContext, 2000,
7528 (XtTimerCallbackProc) AnalysisClockCallback,
7532 XtIntervalId clockTimerXID = 0;
7534 int ClockTimerRunning()
7536 return clockTimerXID != 0;
7539 int StopClockTimer()
7541 if (clockTimerXID != 0) {
7542 XtRemoveTimeOut(clockTimerXID);
7551 ClockTimerCallback(arg, id)
7560 StartClockTimer(millisec)
7564 XtAppAddTimeOut(appContext, millisec,
7565 (XtTimerCallbackProc) ClockTimerCallback,
7570 DisplayTimerLabel(w, color, timer, highlight)
7579 /* check for low time warning */
7580 Pixel foregroundOrWarningColor = timerForegroundPixel;
7583 appData.lowTimeWarning &&
7584 (timer / 1000) < appData.icsAlarmTime)
7585 foregroundOrWarningColor = lowTimeWarningColor;
7587 if (appData.clockMode) {
7588 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7589 XtSetArg(args[0], XtNlabel, buf);
7591 snprintf(buf, MSG_SIZ, "%s ", color);
7592 XtSetArg(args[0], XtNlabel, buf);
7597 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7598 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7600 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7601 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7604 XtSetValues(w, args, 3);
7608 DisplayWhiteClock(timeRemaining, highlight)
7614 if(appData.noGUI) return;
7615 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7616 if (highlight && iconPixmap == bIconPixmap) {
7617 iconPixmap = wIconPixmap;
7618 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7619 XtSetValues(shellWidget, args, 1);
7624 DisplayBlackClock(timeRemaining, highlight)
7630 if(appData.noGUI) return;
7631 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7632 if (highlight && iconPixmap == wIconPixmap) {
7633 iconPixmap = bIconPixmap;
7634 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7635 XtSetValues(shellWidget, args, 1);
7653 int StartChildProcess(cmdLine, dir, pr)
7660 int to_prog[2], from_prog[2];
7664 if (appData.debugMode) {
7665 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7668 /* We do NOT feed the cmdLine to the shell; we just
7669 parse it into blank-separated arguments in the
7670 most simple-minded way possible.
7673 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7676 while(*p == ' ') p++;
7678 if(*p == '"' || *p == '\'')
7679 p = strchr(++argv[i-1], *p);
7680 else p = strchr(p, ' ');
7681 if (p == NULL) break;
7686 SetUpChildIO(to_prog, from_prog);
7688 if ((pid = fork()) == 0) {
7690 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7691 close(to_prog[1]); // first close the unused pipe ends
7692 close(from_prog[0]);
7693 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7694 dup2(from_prog[1], 1);
7695 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7696 close(from_prog[1]); // and closing again loses one of the pipes!
7697 if(fileno(stderr) >= 2) // better safe than sorry...
7698 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7700 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7705 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7707 execvp(argv[0], argv);
7709 /* If we get here, exec failed */
7714 /* Parent process */
7716 close(from_prog[1]);
7718 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7721 cp->fdFrom = from_prog[0];
7722 cp->fdTo = to_prog[1];
7727 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7728 static RETSIGTYPE AlarmCallBack(int n)
7734 DestroyChildProcess(pr, signalType)
7738 ChildProc *cp = (ChildProc *) pr;
7740 if (cp->kind != CPReal) return;
7742 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7743 signal(SIGALRM, AlarmCallBack);
7745 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7746 kill(cp->pid, SIGKILL); // kill it forcefully
7747 wait((int *) 0); // and wait again
7751 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7753 /* Process is exiting either because of the kill or because of
7754 a quit command sent by the backend; either way, wait for it to die.
7763 InterruptChildProcess(pr)
7766 ChildProc *cp = (ChildProc *) pr;
7768 if (cp->kind != CPReal) return;
7769 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7772 int OpenTelnet(host, port, pr)
7777 char cmdLine[MSG_SIZ];
7779 if (port[0] == NULLCHAR) {
7780 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7782 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7784 return StartChildProcess(cmdLine, "", pr);
7787 int OpenTCP(host, port, pr)
7793 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7794 #else /* !OMIT_SOCKETS */
7795 struct addrinfo hints;
7796 struct addrinfo *ais, *ai;
7801 memset(&hints, 0, sizeof(hints));
7802 hints.ai_family = AF_UNSPEC;
7803 hints.ai_socktype = SOCK_STREAM;
7805 error = getaddrinfo(host, port, &hints, &ais);
7807 /* a getaddrinfo error is not an errno, so can't return it */
7808 fprintf(debugFP, "getaddrinfo(%s, %s): %s\n",
7809 host, port, gai_strerror(error));
7813 for (ai = ais; ai != NULL; ai = ai->ai_next) {
7814 if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0) {
7818 if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
7831 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7837 #endif /* !OMIT_SOCKETS */
7842 int OpenCommPort(name, pr)
7849 fd = open(name, 2, 0);
7850 if (fd < 0) return errno;
7852 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7862 int OpenLoopback(pr)
7868 SetUpChildIO(to, from);
7870 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7873 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
7880 int OpenRcmd(host, user, cmd, pr)
7881 char *host, *user, *cmd;
7884 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
7888 #define INPUT_SOURCE_BUF_SIZE 8192
7897 char buf[INPUT_SOURCE_BUF_SIZE];
7902 DoInputCallback(closure, source, xid)
7907 InputSource *is = (InputSource *) closure;
7912 if (is->lineByLine) {
7913 count = read(is->fd, is->unused,
7914 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
7916 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
7919 is->unused += count;
7921 while (p < is->unused) {
7922 q = memchr(p, '\n', is->unused - p);
7923 if (q == NULL) break;
7925 (is->func)(is, is->closure, p, q - p, 0);
7929 while (p < is->unused) {
7934 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
7939 (is->func)(is, is->closure, is->buf, count, error);
7943 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
7950 ChildProc *cp = (ChildProc *) pr;
7952 is = (InputSource *) calloc(1, sizeof(InputSource));
7953 is->lineByLine = lineByLine;
7957 is->fd = fileno(stdin);
7959 is->kind = cp->kind;
7960 is->fd = cp->fdFrom;
7963 is->unused = is->buf;
7966 is->xid = XtAppAddInput(appContext, is->fd,
7967 (XtPointer) (XtInputReadMask),
7968 (XtInputCallbackProc) DoInputCallback,
7970 is->closure = closure;
7971 return (InputSourceRef) is;
7975 RemoveInputSource(isr)
7978 InputSource *is = (InputSource *) isr;
7980 if (is->xid == 0) return;
7981 XtRemoveInput(is->xid);
7985 int OutputToProcess(pr, message, count, outError)
7991 static int line = 0;
7992 ChildProc *cp = (ChildProc *) pr;
7997 if (appData.noJoin || !appData.useInternalWrap)
7998 outCount = fwrite(message, 1, count, stdout);
8001 int width = get_term_width();
8002 int len = wrap(NULL, message, count, width, &line);
8003 char *msg = malloc(len);
8007 outCount = fwrite(message, 1, count, stdout);
8010 dbgchk = wrap(msg, message, count, width, &line);
8011 if (dbgchk != len && appData.debugMode)
8012 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8013 outCount = fwrite(msg, 1, dbgchk, stdout);
8019 outCount = write(cp->fdTo, message, count);
8029 /* Output message to process, with "ms" milliseconds of delay
8030 between each character. This is needed when sending the logon
8031 script to ICC, which for some reason doesn't like the
8032 instantaneous send. */
8033 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8040 ChildProc *cp = (ChildProc *) pr;
8045 r = write(cp->fdTo, message++, 1);
8058 /**** Animation code by Hugh Fisher, DCS, ANU.
8060 Known problem: if a window overlapping the board is
8061 moved away while a piece is being animated underneath,
8062 the newly exposed area won't be updated properly.
8063 I can live with this.
8065 Known problem: if you look carefully at the animation
8066 of pieces in mono mode, they are being drawn as solid
8067 shapes without interior detail while moving. Fixing
8068 this would be a major complication for minimal return.
8071 /* Masks for XPM pieces. Black and white pieces can have
8072 different shapes, but in the interest of retaining my
8073 sanity pieces must have the same outline on both light
8074 and dark squares, and all pieces must use the same
8075 background square colors/images. */
8077 static int xpmDone = 0;
8080 CreateAnimMasks (pieceDepth)
8087 unsigned long plane;
8090 /* Need a bitmap just to get a GC with right depth */
8091 buf = XCreatePixmap(xDisplay, xBoardWindow,
8093 values.foreground = 1;
8094 values.background = 0;
8095 /* Don't use XtGetGC, not read only */
8096 maskGC = XCreateGC(xDisplay, buf,
8097 GCForeground | GCBackground, &values);
8098 XFreePixmap(xDisplay, buf);
8100 buf = XCreatePixmap(xDisplay, xBoardWindow,
8101 squareSize, squareSize, pieceDepth);
8102 values.foreground = XBlackPixel(xDisplay, xScreen);
8103 values.background = XWhitePixel(xDisplay, xScreen);
8104 bufGC = XCreateGC(xDisplay, buf,
8105 GCForeground | GCBackground, &values);
8107 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8108 /* Begin with empty mask */
8109 if(!xpmDone) // [HGM] pieces: keep using existing
8110 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8111 squareSize, squareSize, 1);
8112 XSetFunction(xDisplay, maskGC, GXclear);
8113 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8114 0, 0, squareSize, squareSize);
8116 /* Take a copy of the piece */
8121 XSetFunction(xDisplay, bufGC, GXcopy);
8122 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8124 0, 0, squareSize, squareSize, 0, 0);
8126 /* XOR the background (light) over the piece */
8127 XSetFunction(xDisplay, bufGC, GXxor);
8129 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8130 0, 0, squareSize, squareSize, 0, 0);
8132 XSetForeground(xDisplay, bufGC, lightSquareColor);
8133 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8136 /* We now have an inverted piece image with the background
8137 erased. Construct mask by just selecting all the non-zero
8138 pixels - no need to reconstruct the original image. */
8139 XSetFunction(xDisplay, maskGC, GXor);
8141 /* Might be quicker to download an XImage and create bitmap
8142 data from it rather than this N copies per piece, but it
8143 only takes a fraction of a second and there is a much
8144 longer delay for loading the pieces. */
8145 for (n = 0; n < pieceDepth; n ++) {
8146 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8147 0, 0, squareSize, squareSize,
8153 XFreePixmap(xDisplay, buf);
8154 XFreeGC(xDisplay, bufGC);
8155 XFreeGC(xDisplay, maskGC);
8159 InitAnimState (anim, info)
8161 XWindowAttributes * info;
8166 /* Each buffer is square size, same depth as window */
8167 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8168 squareSize, squareSize, info->depth);
8169 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8170 squareSize, squareSize, info->depth);
8172 /* Create a plain GC for blitting */
8173 mask = GCForeground | GCBackground | GCFunction |
8174 GCPlaneMask | GCGraphicsExposures;
8175 values.foreground = XBlackPixel(xDisplay, xScreen);
8176 values.background = XWhitePixel(xDisplay, xScreen);
8177 values.function = GXcopy;
8178 values.plane_mask = AllPlanes;
8179 values.graphics_exposures = False;
8180 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8182 /* Piece will be copied from an existing context at
8183 the start of each new animation/drag. */
8184 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8186 /* Outline will be a read-only copy of an existing */
8187 anim->outlineGC = None;
8193 XWindowAttributes info;
8195 if (xpmDone && gameInfo.variant == oldVariant) return;
8196 if(xpmDone) oldVariant = gameInfo.variant; // first time pieces might not be created yet
8197 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8199 InitAnimState(&game, &info);
8200 InitAnimState(&player, &info);
8202 /* For XPM pieces, we need bitmaps to use as masks. */
8204 CreateAnimMasks(info.depth), xpmDone = 1;
8209 static Boolean frameWaiting;
8211 static RETSIGTYPE FrameAlarm (sig)
8214 frameWaiting = False;
8215 /* In case System-V style signals. Needed?? */
8216 signal(SIGALRM, FrameAlarm);
8223 struct itimerval delay;
8225 XSync(xDisplay, False);
8228 frameWaiting = True;
8229 signal(SIGALRM, FrameAlarm);
8230 delay.it_interval.tv_sec =
8231 delay.it_value.tv_sec = time / 1000;
8232 delay.it_interval.tv_usec =
8233 delay.it_value.tv_usec = (time % 1000) * 1000;
8234 setitimer(ITIMER_REAL, &delay, NULL);
8235 while (frameWaiting) pause();
8236 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8237 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8238 setitimer(ITIMER_REAL, &delay, NULL);
8248 XSync(xDisplay, False);
8250 usleep(time * 1000);
8261 /* Convert board position to corner of screen rect and color */
8264 ScreenSquare(column, row, pt, color)
8265 int column; int row; XPoint * pt; int * color;
8268 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8269 pt->y = lineGap + row * (squareSize + lineGap);
8271 pt->x = lineGap + column * (squareSize + lineGap);
8272 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8274 *color = SquareColor(row, column);
8277 /* Convert window coords to square */
8280 BoardSquare(x, y, column, row)
8281 int x; int y; int * column; int * row;
8283 *column = EventToSquare(x, BOARD_WIDTH);
8284 if (flipView && *column >= 0)
8285 *column = BOARD_WIDTH - 1 - *column;
8286 *row = EventToSquare(y, BOARD_HEIGHT);
8287 if (!flipView && *row >= 0)
8288 *row = BOARD_HEIGHT - 1 - *row;
8293 #undef Max /* just in case */
8295 #define Max(a, b) ((a) > (b) ? (a) : (b))
8296 #define Min(a, b) ((a) < (b) ? (a) : (b))
8299 SetRect(rect, x, y, width, height)
8300 XRectangle * rect; int x; int y; int width; int height;
8304 rect->width = width;
8305 rect->height = height;
8308 /* Test if two frames overlap. If they do, return
8309 intersection rect within old and location of
8310 that rect within new. */
8313 Intersect(old, new, size, area, pt)
8314 XPoint * old; XPoint * new;
8315 int size; XRectangle * area; XPoint * pt;
8317 if (old->x > new->x + size || new->x > old->x + size ||
8318 old->y > new->y + size || new->y > old->y + size) {
8321 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8322 size - abs(old->x - new->x), size - abs(old->y - new->y));
8323 pt->x = Max(old->x - new->x, 0);
8324 pt->y = Max(old->y - new->y, 0);
8329 /* For two overlapping frames, return the rect(s)
8330 in the old that do not intersect with the new. */
8333 CalcUpdateRects(old, new, size, update, nUpdates)
8334 XPoint * old; XPoint * new; int size;
8335 XRectangle update[]; int * nUpdates;
8339 /* If old = new (shouldn't happen) then nothing to draw */
8340 if (old->x == new->x && old->y == new->y) {
8344 /* Work out what bits overlap. Since we know the rects
8345 are the same size we don't need a full intersect calc. */
8347 /* Top or bottom edge? */
8348 if (new->y > old->y) {
8349 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8351 } else if (old->y > new->y) {
8352 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8353 size, old->y - new->y);
8356 /* Left or right edge - don't overlap any update calculated above. */
8357 if (new->x > old->x) {
8358 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8359 new->x - old->x, size - abs(new->y - old->y));
8361 } else if (old->x > new->x) {
8362 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8363 old->x - new->x, size - abs(new->y - old->y));
8370 /* Generate a series of frame coords from start->mid->finish.
8371 The movement rate doubles until the half way point is
8372 reached, then halves back down to the final destination,
8373 which gives a nice slow in/out effect. The algorithmn
8374 may seem to generate too many intermediates for short
8375 moves, but remember that the purpose is to attract the
8376 viewers attention to the piece about to be moved and
8377 then to where it ends up. Too few frames would be less
8381 Tween(start, mid, finish, factor, frames, nFrames)
8382 XPoint * start; XPoint * mid;
8383 XPoint * finish; int factor;
8384 XPoint frames[]; int * nFrames;
8386 int fraction, n, count;
8390 /* Slow in, stepping 1/16th, then 1/8th, ... */
8392 for (n = 0; n < factor; n++)
8394 for (n = 0; n < factor; n++) {
8395 frames[count].x = start->x + (mid->x - start->x) / fraction;
8396 frames[count].y = start->y + (mid->y - start->y) / fraction;
8398 fraction = fraction / 2;
8402 frames[count] = *mid;
8405 /* Slow out, stepping 1/2, then 1/4, ... */
8407 for (n = 0; n < factor; n++) {
8408 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8409 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8411 fraction = fraction * 2;
8416 /* Draw a piece on the screen without disturbing what's there */
8419 SelectGCMask(piece, clip, outline, mask)
8420 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8424 /* Bitmap for piece being moved. */
8425 if (appData.monoMode) {
8426 *mask = *pieceToSolid(piece);
8427 } else if (useImages) {
8429 *mask = xpmMask[piece];
8431 *mask = ximMaskPm[piece];
8434 *mask = *pieceToSolid(piece);
8437 /* GC for piece being moved. Square color doesn't matter, but
8438 since it gets modified we make a copy of the original. */
8440 if (appData.monoMode)
8445 if (appData.monoMode)
8450 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8452 /* Outline only used in mono mode and is not modified */
8454 *outline = bwPieceGC;
8456 *outline = wbPieceGC;
8460 OverlayPiece(piece, clip, outline, dest)
8461 ChessSquare piece; GC clip; GC outline; Drawable dest;
8466 /* Draw solid rectangle which will be clipped to shape of piece */
8467 XFillRectangle(xDisplay, dest, clip,
8468 0, 0, squareSize, squareSize);
8469 if (appData.monoMode)
8470 /* Also draw outline in contrasting color for black
8471 on black / white on white cases */
8472 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8473 0, 0, squareSize, squareSize, 0, 0, 1);
8475 /* Copy the piece */
8480 if(appData.upsideDown && flipView) kind ^= 2;
8481 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8483 0, 0, squareSize, squareSize,
8488 /* Animate the movement of a single piece */
8491 BeginAnimation(anim, piece, startColor, start)
8499 if(appData.upsideDown && flipView) piece += piece < BlackPawn ? BlackPawn : -BlackPawn;
8500 /* The old buffer is initialised with the start square (empty) */
8501 BlankSquare(start->x, start->y, startColor, EmptySquare, anim->saveBuf, 0);
8502 anim->prevFrame = *start;
8504 /* The piece will be drawn using its own bitmap as a matte */
8505 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8506 XSetClipMask(xDisplay, anim->pieceGC, mask);
8510 AnimationFrame(anim, frame, piece)
8515 XRectangle updates[4];
8520 /* Save what we are about to draw into the new buffer */
8521 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8522 frame->x, frame->y, squareSize, squareSize,
8525 /* Erase bits of the previous frame */
8526 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8527 /* Where the new frame overlapped the previous,
8528 the contents in newBuf are wrong. */
8529 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8530 overlap.x, overlap.y,
8531 overlap.width, overlap.height,
8533 /* Repaint the areas in the old that don't overlap new */
8534 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8535 for (i = 0; i < count; i++)
8536 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8537 updates[i].x - anim->prevFrame.x,
8538 updates[i].y - anim->prevFrame.y,
8539 updates[i].width, updates[i].height,
8540 updates[i].x, updates[i].y);
8542 /* Easy when no overlap */
8543 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8544 0, 0, squareSize, squareSize,
8545 anim->prevFrame.x, anim->prevFrame.y);
8548 /* Save this frame for next time round */
8549 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8550 0, 0, squareSize, squareSize,
8552 anim->prevFrame = *frame;
8554 /* Draw piece over original screen contents, not current,
8555 and copy entire rect. Wipes out overlapping piece images. */
8556 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8557 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8558 0, 0, squareSize, squareSize,
8559 frame->x, frame->y);
8563 EndAnimation (anim, finish)
8567 XRectangle updates[4];
8572 /* The main code will redraw the final square, so we
8573 only need to erase the bits that don't overlap. */
8574 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8575 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8576 for (i = 0; i < count; i++)
8577 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8578 updates[i].x - anim->prevFrame.x,
8579 updates[i].y - anim->prevFrame.y,
8580 updates[i].width, updates[i].height,
8581 updates[i].x, updates[i].y);
8583 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8584 0, 0, squareSize, squareSize,
8585 anim->prevFrame.x, anim->prevFrame.y);
8590 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8592 ChessSquare piece; int startColor;
8593 XPoint * start; XPoint * finish;
8594 XPoint frames[]; int nFrames;
8598 BeginAnimation(anim, piece, startColor, start);
8599 for (n = 0; n < nFrames; n++) {
8600 AnimationFrame(anim, &(frames[n]), piece);
8601 FrameDelay(appData.animSpeed);
8603 EndAnimation(anim, finish);
8607 AnimateAtomicCapture(Board board, int fromX, int fromY, int toX, int toY)
8610 ChessSquare piece = board[fromY][toY];
8611 board[fromY][toY] = EmptySquare;
8612 DrawPosition(FALSE, board);
8614 x = lineGap + ((BOARD_WIDTH-1)-toX) * (squareSize + lineGap);
8615 y = lineGap + toY * (squareSize + lineGap);
8617 x = lineGap + toX * (squareSize + lineGap);
8618 y = lineGap + ((BOARD_HEIGHT-1)-toY) * (squareSize + lineGap);
8620 for(i=1; i<4*kFactor; i++) {
8621 int r = squareSize * 9 * i/(20*kFactor - 5);
8622 XFillArc(xDisplay, xBoardWindow, highlineGC,
8623 x + squareSize/2 - r, y+squareSize/2 - r, 2*r, 2*r, 0, 64*360);
8624 FrameDelay(appData.animSpeed);
8626 board[fromY][toY] = piece;
8629 /* Main control logic for deciding what to animate and how */
8632 AnimateMove(board, fromX, fromY, toX, toY)
8641 XPoint start, finish, mid;
8642 XPoint frames[kFactor * 2 + 1];
8643 int nFrames, startColor, endColor;
8645 /* Are we animating? */
8646 if (!appData.animate || appData.blindfold)
8649 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8650 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8651 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8653 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8654 piece = board[fromY][fromX];
8655 if (piece >= EmptySquare) return;
8660 hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
8663 if (appData.debugMode) {
8664 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8665 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8666 piece, fromX, fromY, toX, toY); }
8668 ScreenSquare(fromX, fromY, &start, &startColor);
8669 ScreenSquare(toX, toY, &finish, &endColor);
8672 /* Knight: make straight movement then diagonal */
8673 if (abs(toY - fromY) < abs(toX - fromX)) {
8674 mid.x = start.x + (finish.x - start.x) / 2;
8678 mid.y = start.y + (finish.y - start.y) / 2;
8681 mid.x = start.x + (finish.x - start.x) / 2;
8682 mid.y = start.y + (finish.y - start.y) / 2;
8685 /* Don't use as many frames for very short moves */
8686 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8687 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8689 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8690 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8691 if(Explode(board, fromX, fromY, toX, toY)) { // mark as damaged
8693 for(i=0; i<BOARD_WIDTH; i++) for(j=0; j<BOARD_HEIGHT; j++)
8694 if((i-toX)*(i-toX) + (j-toY)*(j-toY) < 6) damage[0][j][i] = True;
8697 /* Be sure end square is redrawn */
8698 damage[0][toY][toX] = True;
8702 DragPieceBegin(x, y, instantly)
8703 int x; int y; Boolean instantly;
8705 int boardX, boardY, color;
8708 /* Are we animating? */
8709 if (!appData.animateDragging || appData.blindfold)
8712 /* Figure out which square we start in and the
8713 mouse position relative to top left corner. */
8714 BoardSquare(x, y, &boardX, &boardY);
8715 player.startBoardX = boardX;
8716 player.startBoardY = boardY;
8717 ScreenSquare(boardX, boardY, &corner, &color);
8718 player.startSquare = corner;
8719 player.startColor = color;
8720 /* As soon as we start dragging, the piece will jump slightly to
8721 be centered over the mouse pointer. */
8722 player.mouseDelta.x = squareSize/2;
8723 player.mouseDelta.y = squareSize/2;
8724 /* Initialise animation */
8725 player.dragPiece = PieceForSquare(boardX, boardY);
8727 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8728 player.dragActive = True;
8729 BeginAnimation(&player, player.dragPiece, color, &corner);
8730 /* Mark this square as needing to be redrawn. Note that
8731 we don't remove the piece though, since logically (ie
8732 as seen by opponent) the move hasn't been made yet. */
8733 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8734 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8735 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8736 corner.x, corner.y, squareSize, squareSize,
8737 0, 0); // [HGM] zh: unstack in stead of grab
8738 if(gatingPiece != EmptySquare) {
8739 /* Kludge alert: When gating we want the introduced
8740 piece to appear on the from square. To generate an
8741 image of it, we draw it on the board, copy the image,
8742 and draw the original piece again. */
8743 ChessSquare piece = boards[currentMove][boardY][boardX];
8744 DrawSquare(boardY, boardX, gatingPiece, 0);
8745 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8746 corner.x, corner.y, squareSize, squareSize, 0, 0);
8747 DrawSquare(boardY, boardX, piece, 0);
8749 damage[0][boardY][boardX] = True;
8751 player.dragActive = False;
8756 ChangeDragPiece(ChessSquare piece)
8759 player.dragPiece = piece;
8760 /* The piece will be drawn using its own bitmap as a matte */
8761 SelectGCMask(piece, &player.pieceGC, &player.outlineGC, &mask);
8762 XSetClipMask(xDisplay, player.pieceGC, mask);
8771 /* Are we animating? */
8772 if (!appData.animateDragging || appData.blindfold)
8776 if (! player.dragActive)
8778 /* Move piece, maintaining same relative position
8779 of mouse within square */
8780 corner.x = x - player.mouseDelta.x;
8781 corner.y = y - player.mouseDelta.y;
8782 AnimationFrame(&player, &corner, player.dragPiece);
8784 if (appData.highlightDragging) {
8786 BoardSquare(x, y, &boardX, &boardY);
8787 SetHighlights(fromX, fromY, boardX, boardY);
8796 int boardX, boardY, color;
8799 /* Are we animating? */
8800 if (!appData.animateDragging || appData.blindfold)
8804 if (! player.dragActive)
8806 /* Last frame in sequence is square piece is
8807 placed on, which may not match mouse exactly. */
8808 BoardSquare(x, y, &boardX, &boardY);
8809 ScreenSquare(boardX, boardY, &corner, &color);
8810 EndAnimation(&player, &corner);
8812 /* Be sure end square is redrawn */
8813 damage[0][boardY][boardX] = True;
8815 /* This prevents weird things happening with fast successive
8816 clicks which on my Sun at least can cause motion events
8817 without corresponding press/release. */
8818 player.dragActive = False;
8821 /* Handle expose event while piece being dragged */
8826 if (!player.dragActive || appData.blindfold)
8829 /* What we're doing: logically, the move hasn't been made yet,
8830 so the piece is still in it's original square. But visually
8831 it's being dragged around the board. So we erase the square
8832 that the piece is on and draw it at the last known drag point. */
8833 BlankSquare(player.startSquare.x, player.startSquare.y,
8834 player.startColor, EmptySquare, xBoardWindow, 1);
8835 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
8836 damage[0][player.startBoardY][player.startBoardX] = TRUE;
8839 #include <sys/ioctl.h>
8840 int get_term_width()
8842 int fd, default_width;
8845 default_width = 79; // this is FICS default anyway...
8847 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
8849 if (!ioctl(fd, TIOCGSIZE, &win))
8850 default_width = win.ts_cols;
8851 #elif defined(TIOCGWINSZ)
8853 if (!ioctl(fd, TIOCGWINSZ, &win))
8854 default_width = win.ws_col;
8856 return default_width;
8862 static int old_width = 0;
8863 int new_width = get_term_width();
8865 if (old_width != new_width)
8866 ics_printf("set width %d\n", new_width);
8867 old_width = new_width;
8870 void NotifyFrontendLogin()
8875 /* [AS] Arrow highlighting support */
8877 static double A_WIDTH = 5; /* Width of arrow body */
8879 #define A_HEIGHT_FACTOR 6 /* Length of arrow "point", relative to body width */
8880 #define A_WIDTH_FACTOR 3 /* Width of arrow "point", relative to body width */
8882 static double Sqr( double x )
8887 static int Round( double x )
8889 return (int) (x + 0.5);
8892 void SquareToPos(int rank, int file, int *x, int *y)
8895 *x = lineGap + ((BOARD_WIDTH-1)-file) * (squareSize + lineGap);
8896 *y = lineGap + rank * (squareSize + lineGap);
8898 *x = lineGap + file * (squareSize + lineGap);
8899 *y = lineGap + ((BOARD_HEIGHT-1)-rank) * (squareSize + lineGap);
8903 /* Draw an arrow between two points using current settings */
8904 void DrawArrowBetweenPoints( int s_x, int s_y, int d_x, int d_y )
8907 double dx, dy, j, k, x, y;
8910 int h = (d_y > s_y) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8912 arrow[0].x = s_x + A_WIDTH + 0.5;
8915 arrow[1].x = s_x + A_WIDTH + 0.5;
8916 arrow[1].y = d_y - h;
8918 arrow[2].x = arrow[1].x + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8919 arrow[2].y = d_y - h;
8924 arrow[5].x = arrow[1].x - 2*A_WIDTH + 0.5;
8925 arrow[5].y = d_y - h;
8927 arrow[4].x = arrow[5].x - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8928 arrow[4].y = d_y - h;
8930 arrow[6].x = arrow[1].x - 2*A_WIDTH + 0.5;
8933 else if( d_y == s_y ) {
8934 int w = (d_x > s_x) ? +A_WIDTH*A_HEIGHT_FACTOR : -A_WIDTH*A_HEIGHT_FACTOR;
8937 arrow[0].y = s_y + A_WIDTH + 0.5;
8939 arrow[1].x = d_x - w;
8940 arrow[1].y = s_y + A_WIDTH + 0.5;
8942 arrow[2].x = d_x - w;
8943 arrow[2].y = arrow[1].y + A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8948 arrow[5].x = d_x - w;
8949 arrow[5].y = arrow[1].y - 2*A_WIDTH + 0.5;
8951 arrow[4].x = d_x - w;
8952 arrow[4].y = arrow[5].y - A_WIDTH*(A_WIDTH_FACTOR-1) + 0.5;
8955 arrow[6].y = arrow[1].y - 2*A_WIDTH + 0.5;
8958 /* [AS] Needed a lot of paper for this! :-) */
8959 dy = (double) (d_y - s_y) / (double) (d_x - s_x);
8960 dx = (double) (s_x - d_x) / (double) (s_y - d_y);
8962 j = sqrt( Sqr(A_WIDTH) / (1.0 + Sqr(dx)) );
8964 k = sqrt( Sqr(A_WIDTH*A_HEIGHT_FACTOR) / (1.0 + Sqr(dy)) );
8969 arrow[0].x = Round(x - j);
8970 arrow[0].y = Round(y + j*dx);
8972 arrow[1].x = Round(arrow[0].x + 2*j); // [HGM] prevent width to be affected by rounding twice
8973 arrow[1].y = Round(arrow[0].y - 2*j*dx);
8976 x = (double) d_x - k;
8977 y = (double) d_y - k*dy;
8980 x = (double) d_x + k;
8981 y = (double) d_y + k*dy;
8984 x = Round(x); y = Round(y); // [HGM] make sure width of shaft is rounded the same way on both ends
8986 arrow[6].x = Round(x - j);
8987 arrow[6].y = Round(y + j*dx);
8989 arrow[2].x = Round(arrow[6].x + 2*j);
8990 arrow[2].y = Round(arrow[6].y - 2*j*dx);
8992 arrow[3].x = Round(arrow[2].x + j*(A_WIDTH_FACTOR-1));
8993 arrow[3].y = Round(arrow[2].y - j*(A_WIDTH_FACTOR-1)*dx);
8998 arrow[5].x = Round(arrow[6].x - j*(A_WIDTH_FACTOR-1));
8999 arrow[5].y = Round(arrow[6].y + j*(A_WIDTH_FACTOR-1)*dx);
9002 XFillPolygon(xDisplay, xBoardWindow, highlineGC, arrow, 7, Nonconvex, CoordModeOrigin);
9003 if(appData.monoMode) arrow[7] = arrow[0], XDrawLines(xDisplay, xBoardWindow, darkSquareGC, arrow, 8, CoordModeOrigin);
9004 // Polygon( hdc, arrow, 7 );
9007 /* [AS] Draw an arrow between two squares */
9008 void DrawArrowBetweenSquares( int s_col, int s_row, int d_col, int d_row )
9010 int s_x, s_y, d_x, d_y, hor, vert, i;
9012 if( s_col == d_col && s_row == d_row ) {
9016 /* Get source and destination points */
9017 SquareToPos( s_row, s_col, &s_x, &s_y);
9018 SquareToPos( d_row, d_col, &d_x, &d_y);
9021 d_y += squareSize / 2 - squareSize / 4; // [HGM] round towards same centers on all sides!
9023 else if( d_y < s_y ) {
9024 d_y += squareSize / 2 + squareSize / 4;
9027 d_y += squareSize / 2;
9031 d_x += squareSize / 2 - squareSize / 4;
9033 else if( d_x < s_x ) {
9034 d_x += squareSize / 2 + squareSize / 4;
9037 d_x += squareSize / 2;
9040 s_x += squareSize / 2;
9041 s_y += squareSize / 2;
9044 A_WIDTH = squareSize / 14.; //[HGM] make float
9046 DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
9048 hor = 64*s_col + 32; vert = 64*s_row + 32;
9049 for(i=0; i<= 64; i++) {
9050 damage[0][vert+6>>6][hor+6>>6] = True;
9051 damage[0][vert-6>>6][hor+6>>6] = True;
9052 damage[0][vert+6>>6][hor-6>>6] = True;
9053 damage[0][vert-6>>6][hor-6>>6] = True;
9054 hor += d_col - s_col; vert += d_row - s_row;
9058 Boolean IsDrawArrowEnabled()
9060 return appData.highlightMoveWithArrow && squareSize >= 32;
9063 void DrawArrowHighlight(int fromX, int fromY, int toX,int toY)
9065 if( IsDrawArrowEnabled() && fromX >= 0 && fromY >= 0 && toX >= 0 && toY >= 0)
9066 DrawArrowBetweenSquares(fromX, fromY, toX, toY);
9069 void UpdateLogos(int displ)
9071 return; // no logos in XBoard yet