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 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>
65 # if HAVE_SYS_SOCKET_H
66 # include <sys/socket.h>
67 # include <netinet/in.h>
69 # else /* not HAVE_SYS_SOCKET_H */
70 # if HAVE_LAN_SOCKET_H
71 # include <lan/socket.h>
73 # include <lan/netdb.h>
74 # else /* not HAVE_LAN_SOCKET_H */
75 # define OMIT_SOCKETS 1
76 # endif /* not HAVE_LAN_SOCKET_H */
77 # endif /* not HAVE_SYS_SOCKET_H */
78 #endif /* !OMIT_SOCKETS */
83 #else /* not STDC_HEADERS */
84 extern char *getenv();
87 # else /* not HAVE_STRING_H */
89 # endif /* not HAVE_STRING_H */
90 #endif /* not STDC_HEADERS */
93 # include <sys/fcntl.h>
94 #else /* not HAVE_SYS_FCNTL_H */
97 # endif /* HAVE_FCNTL_H */
98 #endif /* not HAVE_SYS_FCNTL_H */
100 #if HAVE_SYS_SYSTEMINFO_H
101 # include <sys/systeminfo.h>
102 #endif /* HAVE_SYS_SYSTEMINFO_H */
104 #if TIME_WITH_SYS_TIME
105 # include <sys/time.h>
109 # include <sys/time.h>
120 # include <sys/wait.h>
125 # define NAMLEN(dirent) strlen((dirent)->d_name)
126 # define HAVE_DIR_STRUCT
128 # define dirent direct
129 # define NAMLEN(dirent) (dirent)->d_namlen
131 # include <sys/ndir.h>
132 # define HAVE_DIR_STRUCT
135 # include <sys/dir.h>
136 # define HAVE_DIR_STRUCT
140 # define HAVE_DIR_STRUCT
145 # if HAVE_LIBREADLINE /* add gnu-readline support */
146 #include <readline/readline.h>
147 #include <readline/history.h>
150 #include <X11/Intrinsic.h>
151 #include <X11/StringDefs.h>
152 #include <X11/Shell.h>
153 #include <X11/cursorfont.h>
154 #include <X11/Xatom.h>
155 #include <X11/Xmu/Atoms.h>
157 #include <X11/Xaw3d/Dialog.h>
158 #include <X11/Xaw3d/Form.h>
159 #include <X11/Xaw3d/List.h>
160 #include <X11/Xaw3d/Label.h>
161 #include <X11/Xaw3d/SimpleMenu.h>
162 #include <X11/Xaw3d/SmeBSB.h>
163 #include <X11/Xaw3d/SmeLine.h>
164 #include <X11/Xaw3d/Box.h>
165 #include <X11/Xaw3d/MenuButton.h>
166 #include <X11/Xaw3d/Text.h>
167 #include <X11/Xaw3d/AsciiText.h>
169 #include <X11/Xaw/Dialog.h>
170 #include <X11/Xaw/Form.h>
171 #include <X11/Xaw/List.h>
172 #include <X11/Xaw/Label.h>
173 #include <X11/Xaw/SimpleMenu.h>
174 #include <X11/Xaw/SmeBSB.h>
175 #include <X11/Xaw/SmeLine.h>
176 #include <X11/Xaw/Box.h>
177 #include <X11/Xaw/MenuButton.h>
178 #include <X11/Xaw/Text.h>
179 #include <X11/Xaw/AsciiText.h>
182 // [HGM] bitmaps: put before incuding the bitmaps / pixmaps, to know how many piece types there are.
187 #include "pixmaps/pixmaps.h"
188 #define IMAGE_EXT "xpm"
190 #define IMAGE_EXT "xim"
191 #include "bitmaps/bitmaps.h"
194 #include "bitmaps/icon_white.bm"
195 #include "bitmaps/icon_black.bm"
196 #include "bitmaps/checkmark.bm"
198 #include "frontend.h"
200 #include "backendz.h"
204 #include "xgamelist.h"
205 #include "xhistory.h"
206 #include "xedittags.h"
209 // must be moved to xengineoutput.h
211 void EngineOutputProc P((Widget w, XEvent *event,
212 String *prms, Cardinal *nprms));
213 void EvalGraphProc P((Widget w, XEvent *event,
214 String *prms, Cardinal *nprms));
221 #define usleep(t) _sleep2(((t)+500)/1000)
225 # define _(s) gettext (s)
226 # define N_(s) gettext_noop (s)
242 int main P((int argc, char **argv));
243 FILE * XsraSelFile P((Widget w, char *prompt, char *ok, char *cancel, char *failed,
244 char *init_path, char *mode, int (*show_entry)(), char **name_return));
245 RETSIGTYPE CmailSigHandler P((int sig));
246 RETSIGTYPE IntSigHandler P((int sig));
247 RETSIGTYPE TermSizeSigHandler P((int sig));
248 void CreateGCs P((void));
249 void CreateXIMPieces P((void));
250 void CreateXPMPieces P((void));
251 void CreatePieces P((void));
252 void CreatePieceMenus P((void));
253 Widget CreateMenuBar P((Menu *mb));
254 Widget CreateButtonBar P ((MenuItem *mi));
255 char *FindFont P((char *pattern, int targetPxlSize));
256 void PieceMenuPopup P((Widget w, XEvent *event,
257 String *params, Cardinal *num_params));
258 static void PieceMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
259 static void DropMenuSelect P((Widget w, ChessSquare piece, caddr_t junk));
260 void ReadBitmap P((Pixmap *pm, String name, unsigned char bits[],
261 u_int wreq, u_int hreq));
262 void CreateGrid P((void));
263 int EventToSquare P((int x, int limit));
264 void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
265 void EventProc P((Widget widget, caddr_t unused, XEvent *event));
266 void HandleUserMove P((Widget w, XEvent *event,
267 String *prms, Cardinal *nprms));
268 void AnimateUserMove P((Widget w, XEvent * event,
269 String * params, Cardinal * nParams));
270 void HandlePV P((Widget w, XEvent * event,
271 String * params, Cardinal * nParams));
272 void SelectPV P((Widget w, XEvent * event,
273 String * params, Cardinal * nParams));
274 void StopPV P((Widget w, XEvent * event,
275 String * params, Cardinal * nParams));
276 void WhiteClock P((Widget w, XEvent *event,
277 String *prms, Cardinal *nprms));
278 void BlackClock P((Widget w, XEvent *event,
279 String *prms, Cardinal *nprms));
280 void DrawPositionProc P((Widget w, XEvent *event,
281 String *prms, Cardinal *nprms));
282 void XDrawPosition P((Widget w, /*Boolean*/int repaint,
284 void CommentClick P((Widget w, XEvent * event,
285 String * params, Cardinal * nParams));
286 void CommentPopUp P((char *title, char *label));
287 void CommentPopDown P((void));
288 void CommentCallback P((Widget w, XtPointer client_data,
289 XtPointer call_data));
290 void ICSInputBoxPopUp P((void));
291 void ICSInputBoxPopDown P((void));
292 void FileNamePopUp P((char *label, char *def,
293 FileProc proc, char *openMode));
294 void FileNamePopDown P((void));
295 void FileNameCallback P((Widget w, XtPointer client_data,
296 XtPointer call_data));
297 void FileNameAction P((Widget w, XEvent *event,
298 String *prms, Cardinal *nprms));
299 void AskQuestionReplyAction P((Widget w, XEvent *event,
300 String *prms, Cardinal *nprms));
301 void AskQuestionProc P((Widget w, XEvent *event,
302 String *prms, Cardinal *nprms));
303 void AskQuestionPopDown P((void));
304 void PromotionPopDown P((void));
305 void PromotionCallback P((Widget w, XtPointer client_data,
306 XtPointer call_data));
307 void EditCommentPopDown P((void));
308 void EditCommentCallback P((Widget w, XtPointer client_data,
309 XtPointer call_data));
310 void SelectCommand P((Widget w, XtPointer client_data, XtPointer call_data));
311 void ResetProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
312 void LoadGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
313 void LoadNextGameProc P((Widget w, XEvent *event, String *prms,
315 void LoadPrevGameProc P((Widget w, XEvent *event, String *prms,
317 void ReloadGameProc P((Widget w, XEvent *event, String *prms,
319 void LoadPositionProc P((Widget w, XEvent *event,
320 String *prms, Cardinal *nprms));
321 void LoadNextPositionProc P((Widget w, XEvent *event, String *prms,
323 void LoadPrevPositionProc P((Widget w, XEvent *event, String *prms,
325 void ReloadPositionProc P((Widget w, XEvent *event, String *prms,
327 void CopyPositionProc P((Widget w, XEvent *event, String *prms,
329 void PastePositionProc P((Widget w, XEvent *event, String *prms,
331 void CopyGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
332 void PasteGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
333 void SaveGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
334 void SavePositionProc P((Widget w, XEvent *event,
335 String *prms, Cardinal *nprms));
336 void MailMoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
337 void ReloadCmailMsgProc P((Widget w, XEvent *event, String *prms,
339 void QuitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
340 void PauseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
341 void MachineBlackProc P((Widget w, XEvent *event, String *prms,
343 void MachineWhiteProc P((Widget w, XEvent *event,
344 String *prms, Cardinal *nprms));
345 void AnalyzeModeProc P((Widget w, XEvent *event,
346 String *prms, Cardinal *nprms));
347 void AnalyzeFileProc P((Widget w, XEvent *event,
348 String *prms, Cardinal *nprms));
349 void TwoMachinesProc P((Widget w, XEvent *event, String *prms,
351 void IcsClientProc P((Widget w, XEvent *event, String *prms,
353 void EditGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
354 void EditPositionProc P((Widget w, XEvent *event,
355 String *prms, Cardinal *nprms));
356 void TrainingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
357 void EditCommentProc P((Widget w, XEvent *event,
358 String *prms, Cardinal *nprms));
359 void IcsInputBoxProc P((Widget w, XEvent *event,
360 String *prms, Cardinal *nprms));
361 void AcceptProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
362 void DeclineProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
363 void RematchProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
364 void CallFlagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
365 void DrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
366 void AbortProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
367 void AdjournProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
368 void ResignProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
369 void AdjuWhiteProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
370 void AdjuBlackProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
371 void AdjuDrawProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
372 void EnterKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
373 void UpKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
374 void DownKeyProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
375 void StopObservingProc P((Widget w, XEvent *event, String *prms,
377 void StopExaminingProc P((Widget w, XEvent *event, String *prms,
379 void UploadProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
380 void BackwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
381 void ForwardProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
382 void ToStartProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
383 void ToEndProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
384 void RevertProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
385 void AnnotateProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
386 void TruncateGameProc P((Widget w, XEvent *event, String *prms,
388 void RetractMoveProc P((Widget w, XEvent *event, String *prms,
390 void MoveNowProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
391 void AlwaysQueenProc P((Widget w, XEvent *event, String *prms,
393 void AnimateDraggingProc P((Widget w, XEvent *event, String *prms,
395 void AnimateMovingProc P((Widget w, XEvent *event, String *prms,
397 void AutocommProc P((Widget w, XEvent *event, String *prms,
399 void AutoflagProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
400 void AutoflipProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
401 void AutobsProc P((Widget w, XEvent *event, String *prms,
403 void AutoraiseProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
404 void AutosaveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
405 void BlindfoldProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
406 void FlashMovesProc P((Widget w, XEvent *event, String *prms,
408 void FlipViewProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
409 void GetMoveListProc P((Widget w, XEvent *event, String *prms,
411 void HighlightDraggingProc P((Widget w, XEvent *event, String *prms,
413 void HighlightLastMoveProc P((Widget w, XEvent *event, String *prms,
415 void MoveSoundProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
416 void IcsAlarmProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
417 void OldSaveStyleProc P((Widget w, XEvent *event, String *prms,
419 void PeriodicUpdatesProc P((Widget w, XEvent *event, String *prms,
421 void PonderNextMoveProc P((Widget w, XEvent *event, String *prms,
423 void PopupMoveErrorsProc P((Widget w, XEvent *event, String *prms,
425 void PopupExitMessageProc P((Widget w, XEvent *event, String *prms,
427 void PremoveProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
428 void QuietPlayProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
429 void ShowCoordsProc P((Widget w, XEvent *event, String *prms,
431 void ShowThinkingProc P((Widget w, XEvent *event, String *prms,
433 void HideThinkingProc P((Widget w, XEvent *event, String *prms,
435 void TestLegalityProc P((Widget w, XEvent *event, String *prms,
437 void SaveSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
438 void SaveOnExitProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
439 void InfoProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
440 void ManProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
441 void HintProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
442 void BookProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
443 void AboutGameProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
444 void AboutProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
445 void DebugProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
446 void NothingProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
447 void Iconify P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
448 void DisplayMove P((int moveNumber));
449 void DisplayTitle P((char *title));
450 void ICSInitScript P((void));
451 int LoadGamePopUp P((FILE *f, int gameNumber, char *title));
452 void ErrorPopUp P((char *title, char *text, int modal));
453 void ErrorPopDown P((void));
454 static char *ExpandPathName P((char *path));
455 static void CreateAnimVars P((void));
456 static void DragPieceMove P((int x, int y));
457 static void DrawDragPiece P((void));
458 char *ModeToWidgetName P((GameMode mode));
459 void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
460 void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
461 void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
462 void TimeControlProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
463 void NewVariantProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
464 void FirstSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
465 void SecondSettingsProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
466 void GameListOptionsPopUp P((Widget w, XEvent *event, String *prms, Cardinal *nprms));
467 void GameListOptionsPopDown P(());
468 void ShufflePopDown P(());
469 void EnginePopDown P(());
470 void UciPopDown P(());
471 void TimeControlPopDown P(());
472 void NewVariantPopDown P(());
473 void SettingsPopDown P(());
474 void update_ics_width P(());
475 int get_term_width P(());
476 int CopyMemoProc P(());
478 # if HAVE_LIBREADLINE /* add gnu-readline support */
479 static void ReadlineCompleteHandler P((char *));
483 * XBoard depends on Xt R4 or higher
485 int xtVersion = XtSpecificationRelease;
490 Pixel lightSquareColor, darkSquareColor, whitePieceColor, blackPieceColor,
491 jailSquareColor, highlightSquareColor, premoveHighlightColor;
492 Pixel lowTimeWarningColor;
493 GC lightSquareGC, darkSquareGC, jailSquareGC, lineGC, wdPieceGC, wlPieceGC,
494 bdPieceGC, blPieceGC, wbPieceGC, bwPieceGC, coordGC, highlineGC,
495 wjPieceGC, bjPieceGC, prelineGC, countGC;
496 Pixmap iconPixmap, wIconPixmap, bIconPixmap, xMarkPixmap;
497 Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
498 whiteTimerWidget, blackTimerWidget, titleWidget, widgetList[16],
499 commentShell, promotionShell, whitePieceMenu, blackPieceMenu, dropMenu,
500 menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
501 ICSInputShell, fileNameShell, askQuestionShell;
502 Widget historyShell, evalGraphShell, gameListShell;
503 int hOffset; // [HGM] dual
504 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
505 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
506 XSegment jailGridSegments[BOARD_RANKS + BOARD_FILES + 6];
507 Font clockFontID, coordFontID, countFontID;
508 XFontStruct *clockFontStruct, *coordFontStruct, *countFontStruct;
509 XtAppContext appContext;
511 char *oldICSInteractionTitle;
515 char installDir[] = "."; // [HGM] UCI: needed for UCI; probably needs run-time initializtion
517 # if HAVE_LIBREADLINE /* gnu readline support */
518 static char* readline_buffer;
519 static int readline_complete=0;
520 extern int sending_ICS_login;
521 extern int sending_ICS_password;
524 Position commentX = -1, commentY = -1;
525 Dimension commentW, commentH;
526 typedef unsigned int BoardSize;
528 Boolean chessProgram;
530 int minX, minY; // [HGM] placement: volatile limits on upper-left corner
531 int squareSize, smallLayout = 0, tinyLayout = 0,
532 marginW, marginH, // [HGM] for run-time resizing
533 fromX = -1, fromY = -1, toX, toY, commentUp = False, analysisUp = False,
534 ICSInputBoxUp = False, askQuestionUp = False,
535 filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
536 editUp = False, errorUp = False, errorExitStatus = -1, lineGap;
537 Pixel timerForegroundPixel, timerBackgroundPixel;
538 Pixel buttonForegroundPixel, buttonBackgroundPixel;
539 char *chessDir, *programName, *programVersion,
540 *gameCopyFilename, *gamePasteFilename;
541 Boolean alwaysOnTop = False;
542 Boolean saveSettingsOnExit;
543 char *settingsFileName;
544 char *icsTextMenuString;
546 char *firstChessProgramNames;
547 char *secondChessProgramNames;
549 WindowPlacement wpMain;
550 WindowPlacement wpConsole;
551 WindowPlacement wpComment;
552 WindowPlacement wpMoveHistory;
553 WindowPlacement wpEvalGraph;
554 WindowPlacement wpEngineOutput;
555 WindowPlacement wpGameList;
556 WindowPlacement wpTags;
560 Pixmap pieceBitmap[2][(int)BlackPawn];
561 Pixmap pieceBitmap2[2][(int)BlackPawn+4]; /* [HGM] pieces */
562 Pixmap xpmPieceBitmap[4][(int)BlackPawn]; /* LL, LD, DL, DD actually used*/
563 Pixmap xpmPieceBitmap2[4][(int)BlackPawn+4]; /* LL, LD, DL, DD set to select from */
564 Pixmap xpmLightSquare, xpmDarkSquare, xpmJailSquare;
565 int useImages, useImageSqs;
566 XImage *ximPieceBitmap[4][(int)BlackPawn+4]; /* LL, LD, DL, DD */
567 Pixmap ximMaskPm[(int)BlackPawn]; /* clipmasks, used for XIM pieces */
568 Pixmap ximMaskPm2[(int)BlackPawn+4]; /* clipmasks, used for XIM pieces */
569 XImage *ximLightSquare, *ximDarkSquare;
572 #define pieceToSolid(piece) &pieceBitmap[SOLID][(piece) % (int)BlackPawn]
573 #define pieceToOutline(piece) &pieceBitmap[OUTLINE][(piece) % (int)BlackPawn]
575 #define White(piece) ((int)(piece) < (int)BlackPawn)
577 /* Variables for doing smooth animation. This whole thing
578 would be much easier if the board was double-buffered,
579 but that would require a fairly major rewrite. */
584 GC blitGC, pieceGC, outlineGC;
585 XPoint startSquare, prevFrame, mouseDelta;
589 int startBoardX, startBoardY;
592 /* There can be two pieces being animated at once: a player
593 can begin dragging a piece before the remote opponent has moved. */
595 static AnimState game, player;
597 /* Bitmaps for use as masks when drawing XPM pieces.
598 Need one for each black and white piece. */
599 static Pixmap xpmMask[BlackKing + 1];
601 /* This magic number is the number of intermediate frames used
602 in each half of the animation. For short moves it's reduced
603 by 1. The total number of frames will be factor * 2 + 1. */
606 SizeDefaults sizeDefaults[] = SIZE_DEFAULTS;
608 MenuItem fileMenu[] = {
609 {N_("New Game"), ResetProc},
610 {N_("New Shuffle Game ..."), ShuffleMenuProc},
611 {N_("New Variant ..."), NewVariantProc}, // [HGM] variant: not functional yet
612 {"----", NothingProc},
613 {N_("Load Game"), LoadGameProc},
614 {N_("Load Next Game"), LoadNextGameProc},
615 {N_("Load Previous Game"), LoadPrevGameProc},
616 {N_("Reload Same Game"), ReloadGameProc},
617 {N_("Save Game"), SaveGameProc},
618 {"----", NothingProc},
619 {N_("Copy Game"), CopyGameProc},
620 {N_("Paste Game"), PasteGameProc},
621 {"----", NothingProc},
622 {N_("Load Position"), LoadPositionProc},
623 {N_("Load Next Position"), LoadNextPositionProc},
624 {N_("Load Previous Position"), LoadPrevPositionProc},
625 {N_("Reload Same Position"), ReloadPositionProc},
626 {N_("Save Position"), SavePositionProc},
627 {"----", NothingProc},
628 {N_("Copy Position"), CopyPositionProc},
629 {N_("Paste Position"), PastePositionProc},
630 {"----", NothingProc},
631 {N_("Mail Move"), MailMoveProc},
632 {N_("Reload CMail Message"), ReloadCmailMsgProc},
633 {"----", NothingProc},
634 {N_("Exit"), QuitProc},
638 MenuItem modeMenu[] = {
639 {N_("Machine White"), MachineWhiteProc},
640 {N_("Machine Black"), MachineBlackProc},
641 {N_("Two Machines"), TwoMachinesProc},
642 {N_("Analysis Mode"), AnalyzeModeProc},
643 {N_("Analyze File"), AnalyzeFileProc },
644 {N_("ICS Client"), IcsClientProc},
645 {N_("Edit Game"), EditGameProc},
646 {N_("Edit Position"), EditPositionProc},
647 {N_("Training"), TrainingProc},
648 {"----", NothingProc},
649 {N_("Show Engine Output"), EngineOutputProc},
650 {N_("Show Evaluation Graph"), EvalGraphProc},
651 {N_("Show Game List"), ShowGameListProc},
652 {N_("Show Move History"), HistoryShowProc}, // [HGM] hist: activate 4.2.7 code
653 {"----", NothingProc},
654 {N_("Edit Tags"), EditTagsProc},
655 {N_("Edit Comment"), EditCommentProc},
656 {N_("ICS Input Box"), IcsInputBoxProc},
657 {N_("Pause"), PauseProc},
661 MenuItem actionMenu[] = {
662 {N_("Accept"), AcceptProc},
663 {N_("Decline"), DeclineProc},
664 {N_("Rematch"), RematchProc},
665 {"----", NothingProc},
666 {N_("Call Flag"), CallFlagProc},
667 {N_("Draw"), DrawProc},
668 {N_("Adjourn"), AdjournProc},
669 {N_("Abort"), AbortProc},
670 {N_("Resign"), ResignProc},
671 {"----", NothingProc},
672 {N_("Stop Observing"), StopObservingProc},
673 {N_("Stop Examining"), StopExaminingProc},
674 {N_("Upload to Examine"), UploadProc},
675 {"----", NothingProc},
676 {N_("Adjudicate to White"), AdjuWhiteProc},
677 {N_("Adjudicate to Black"), AdjuBlackProc},
678 {N_("Adjudicate Draw"), AdjuDrawProc},
682 MenuItem stepMenu[] = {
683 {N_("Backward"), BackwardProc},
684 {N_("Forward"), ForwardProc},
685 {N_("Back to Start"), ToStartProc},
686 {N_("Forward to End"), ToEndProc},
687 {N_("Revert"), RevertProc},
688 {N_("Annotate"), AnnotateProc},
689 {N_("Truncate Game"), TruncateGameProc},
690 {"----", NothingProc},
691 {N_("Move Now"), MoveNowProc},
692 {N_("Retract Move"), RetractMoveProc},
696 MenuItem optionsMenu[] = {
697 {N_("Flip View"), FlipViewProc},
698 {"----", NothingProc},
699 {N_("Adjudications ..."), EngineMenuProc},
700 {N_("General Settings ..."), UciMenuProc},
701 {N_("Engine #1 Settings ..."), FirstSettingsProc},
702 {N_("Engine #2 Settings ..."), SecondSettingsProc},
703 {N_("Time Control ..."), TimeControlProc},
704 {N_("Game List ..."), GameListOptionsPopUp},
705 {"----", NothingProc},
706 {N_("Always Queen"), AlwaysQueenProc},
707 {N_("Animate Dragging"), AnimateDraggingProc},
708 {N_("Animate Moving"), AnimateMovingProc},
709 {N_("Auto Comment"), AutocommProc},
710 {N_("Auto Flag"), AutoflagProc},
711 {N_("Auto Flip View"), AutoflipProc},
712 {N_("Auto Observe"), AutobsProc},
713 {N_("Auto Raise Board"), AutoraiseProc},
714 {N_("Auto Save"), AutosaveProc},
715 {N_("Blindfold"), BlindfoldProc},
716 {N_("Flash Moves"), FlashMovesProc},
717 {N_("Get Move List"), GetMoveListProc},
719 {N_("Highlight Dragging"), HighlightDraggingProc},
721 {N_("Highlight Last Move"), HighlightLastMoveProc},
722 {N_("Move Sound"), MoveSoundProc},
723 {N_("ICS Alarm"), IcsAlarmProc},
724 {N_("Old Save Style"), OldSaveStyleProc},
725 {N_("Periodic Updates"), PeriodicUpdatesProc},
726 {N_("Ponder Next Move"), PonderNextMoveProc},
727 {N_("Popup Exit Message"), PopupExitMessageProc},
728 {N_("Popup Move Errors"), PopupMoveErrorsProc},
729 {N_("Premove"), PremoveProc},
730 {N_("Quiet Play"), QuietPlayProc},
731 {N_("Show Coords"), ShowCoordsProc},
732 {N_("Hide Thinking"), HideThinkingProc},
733 {N_("Test Legality"), TestLegalityProc},
734 {"----", NothingProc},
735 {N_("Save Settings Now"), SaveSettingsProc},
736 {N_("Save Settings on Exit"), SaveOnExitProc},
740 MenuItem helpMenu[] = {
741 {N_("Info XBoard"), InfoProc},
742 {N_("Man XBoard"), ManProc},
743 {"----", NothingProc},
744 {N_("Hint"), HintProc},
745 {N_("Book"), BookProc},
746 {"----", NothingProc},
747 {N_("About XBoard"), AboutProc},
752 {N_("File"), fileMenu},
753 {N_("Mode"), modeMenu},
754 {N_("Action"), actionMenu},
755 {N_("Step"), stepMenu},
756 {N_("Options"), optionsMenu},
757 {N_("Help"), helpMenu},
761 #define PAUSE_BUTTON N_("P")
762 MenuItem buttonBar[] = {
765 {PAUSE_BUTTON, PauseProc},
771 #define PIECE_MENU_SIZE 18
772 String pieceMenuStrings[2][PIECE_MENU_SIZE] = {
773 { N_("White"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
774 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
775 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
776 N_("Empty square"), N_("Clear board") },
777 { N_("Black"), "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"),
778 N_("Queen"), N_("King"), "----", N_("Elephant"), N_("Cannon"),
779 N_("Archbishop"), N_("Chancellor"), "----", N_("Promote"), N_("Demote"),
780 N_("Empty square"), N_("Clear board") }
782 /* must be in same order as PieceMenuStrings! */
783 ChessSquare pieceMenuTranslation[2][PIECE_MENU_SIZE] = {
784 { WhitePlay, (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
785 WhiteRook, WhiteQueen, WhiteKing, (ChessSquare) 0, WhiteAlfil,
786 WhiteCannon, WhiteAngel, WhiteMarshall, (ChessSquare) 0,
787 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
788 { BlackPlay, (ChessSquare) 0, BlackPawn, BlackKnight, BlackBishop,
789 BlackRook, BlackQueen, BlackKing, (ChessSquare) 0, BlackAlfil,
790 BlackCannon, BlackAngel, BlackMarshall, (ChessSquare) 0,
791 PromotePiece, DemotePiece, EmptySquare, ClearBoard },
794 #define DROP_MENU_SIZE 6
795 String dropMenuStrings[DROP_MENU_SIZE] = {
796 "----", N_("Pawn"), N_("Knight"), N_("Bishop"), N_("Rook"), N_("Queen")
798 /* must be in same order as PieceMenuStrings! */
799 ChessSquare dropMenuTranslation[DROP_MENU_SIZE] = {
800 (ChessSquare) 0, WhitePawn, WhiteKnight, WhiteBishop,
801 WhiteRook, WhiteQueen
809 DropMenuEnables dmEnables[] = {
827 { XtNborderWidth, 0 },
828 { XtNdefaultDistance, 0 },
832 { XtNborderWidth, 0 },
833 { XtNresizable, (XtArgVal) True },
837 { XtNborderWidth, 0 },
843 { XtNjustify, (XtArgVal) XtJustifyRight },
844 { XtNlabel, (XtArgVal) "..." },
845 { XtNresizable, (XtArgVal) True },
846 { XtNresize, (XtArgVal) False }
849 Arg messageArgs[] = {
850 { XtNjustify, (XtArgVal) XtJustifyLeft },
851 { XtNlabel, (XtArgVal) "..." },
852 { XtNresizable, (XtArgVal) True },
853 { XtNresize, (XtArgVal) False }
857 { XtNborderWidth, 0 },
858 { XtNjustify, (XtArgVal) XtJustifyLeft }
861 XtResource clientResources[] = {
862 { "flashCount", "flashCount", XtRInt, sizeof(int),
863 XtOffset(AppDataPtr, flashCount), XtRImmediate,
864 (XtPointer) FLASH_COUNT },
867 XrmOptionDescRec shellOptions[] = {
868 { "-flashCount", "flashCount", XrmoptionSepArg, NULL },
869 { "-flash", "flashCount", XrmoptionNoArg, "3" },
870 { "-xflash", "flashCount", XrmoptionNoArg, "0" },
873 XtActionsRec boardActions[] = {
874 { "DrawPosition", DrawPositionProc },
875 { "HandleUserMove", HandleUserMove },
876 { "AnimateUserMove", AnimateUserMove },
877 { "HandlePV", HandlePV },
878 { "SelectPV", SelectPV },
879 { "StopPV", StopPV },
880 { "FileNameAction", FileNameAction },
881 { "AskQuestionProc", AskQuestionProc },
882 { "AskQuestionReplyAction", AskQuestionReplyAction },
883 { "PieceMenuPopup", PieceMenuPopup },
884 { "WhiteClock", WhiteClock },
885 { "BlackClock", BlackClock },
886 { "Iconify", Iconify },
887 { "ResetProc", ResetProc },
888 { "NewVariantProc", NewVariantProc },
889 { "LoadGameProc", LoadGameProc },
890 { "LoadNextGameProc", LoadNextGameProc },
891 { "LoadPrevGameProc", LoadPrevGameProc },
892 { "LoadSelectedProc", LoadSelectedProc },
893 { "SetFilterProc", SetFilterProc },
894 { "ReloadGameProc", ReloadGameProc },
895 { "LoadPositionProc", LoadPositionProc },
896 { "LoadNextPositionProc", LoadNextPositionProc },
897 { "LoadPrevPositionProc", LoadPrevPositionProc },
898 { "ReloadPositionProc", ReloadPositionProc },
899 { "CopyPositionProc", CopyPositionProc },
900 { "PastePositionProc", PastePositionProc },
901 { "CopyGameProc", CopyGameProc },
902 { "PasteGameProc", PasteGameProc },
903 { "SaveGameProc", SaveGameProc },
904 { "SavePositionProc", SavePositionProc },
905 { "MailMoveProc", MailMoveProc },
906 { "ReloadCmailMsgProc", ReloadCmailMsgProc },
907 { "QuitProc", QuitProc },
908 { "MachineWhiteProc", MachineWhiteProc },
909 { "MachineBlackProc", MachineBlackProc },
910 { "AnalysisModeProc", AnalyzeModeProc },
911 { "AnalyzeFileProc", AnalyzeFileProc },
912 { "TwoMachinesProc", TwoMachinesProc },
913 { "IcsClientProc", IcsClientProc },
914 { "EditGameProc", EditGameProc },
915 { "EditPositionProc", EditPositionProc },
916 { "TrainingProc", EditPositionProc },
917 { "EngineOutputProc", EngineOutputProc}, // [HGM] Winboard_x engine-output window
918 { "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
919 { "ShowGameListProc", ShowGameListProc },
920 { "ShowMoveListProc", HistoryShowProc},
921 { "EditTagsProc", EditCommentProc },
922 { "EditCommentProc", EditCommentProc },
923 { "IcsAlarmProc", IcsAlarmProc },
924 { "IcsInputBoxProc", IcsInputBoxProc },
925 { "PauseProc", PauseProc },
926 { "AcceptProc", AcceptProc },
927 { "DeclineProc", DeclineProc },
928 { "RematchProc", RematchProc },
929 { "CallFlagProc", CallFlagProc },
930 { "DrawProc", DrawProc },
931 { "AdjournProc", AdjournProc },
932 { "AbortProc", AbortProc },
933 { "ResignProc", ResignProc },
934 { "AdjuWhiteProc", AdjuWhiteProc },
935 { "AdjuBlackProc", AdjuBlackProc },
936 { "AdjuDrawProc", AdjuDrawProc },
937 { "EnterKeyProc", EnterKeyProc },
938 { "UpKeyProc", UpKeyProc },
939 { "DownKeyProc", DownKeyProc },
940 { "StopObservingProc", StopObservingProc },
941 { "StopExaminingProc", StopExaminingProc },
942 { "UploadProc", UploadProc },
943 { "BackwardProc", BackwardProc },
944 { "ForwardProc", ForwardProc },
945 { "ToStartProc", ToStartProc },
946 { "ToEndProc", ToEndProc },
947 { "RevertProc", RevertProc },
948 { "AnnotateProc", AnnotateProc },
949 { "TruncateGameProc", TruncateGameProc },
950 { "MoveNowProc", MoveNowProc },
951 { "RetractMoveProc", RetractMoveProc },
952 { "EngineMenuProc", (XtActionProc) EngineMenuProc },
953 { "UciMenuProc", (XtActionProc) UciMenuProc },
954 { "TimeControlProc", (XtActionProc) TimeControlProc },
955 { "AlwaysQueenProc", AlwaysQueenProc },
956 { "AnimateDraggingProc", AnimateDraggingProc },
957 { "AnimateMovingProc", AnimateMovingProc },
958 { "AutoflagProc", AutoflagProc },
959 { "AutoflipProc", AutoflipProc },
960 { "AutobsProc", AutobsProc },
961 { "AutoraiseProc", AutoraiseProc },
962 { "AutosaveProc", AutosaveProc },
963 { "BlindfoldProc", BlindfoldProc },
964 { "FlashMovesProc", FlashMovesProc },
965 { "FlipViewProc", FlipViewProc },
966 { "GetMoveListProc", GetMoveListProc },
968 { "HighlightDraggingProc", HighlightDraggingProc },
970 { "HighlightLastMoveProc", HighlightLastMoveProc },
971 { "IcsAlarmProc", IcsAlarmProc },
972 { "MoveSoundProc", MoveSoundProc },
973 { "OldSaveStyleProc", OldSaveStyleProc },
974 { "PeriodicUpdatesProc", PeriodicUpdatesProc },
975 { "PonderNextMoveProc", PonderNextMoveProc },
976 { "PopupExitMessageProc", PopupExitMessageProc },
977 { "PopupMoveErrorsProc", PopupMoveErrorsProc },
978 { "PremoveProc", PremoveProc },
979 { "QuietPlayProc", QuietPlayProc },
980 { "ShowCoordsProc", ShowCoordsProc },
981 { "ShowThinkingProc", ShowThinkingProc },
982 { "HideThinkingProc", HideThinkingProc },
983 { "TestLegalityProc", TestLegalityProc },
984 { "SaveSettingsProc", SaveSettingsProc },
985 { "SaveOnExitProc", SaveOnExitProc },
986 { "InfoProc", InfoProc },
987 { "ManProc", ManProc },
988 { "HintProc", HintProc },
989 { "BookProc", BookProc },
990 { "AboutGameProc", AboutGameProc },
991 { "AboutProc", AboutProc },
992 { "DebugProc", DebugProc },
993 { "NothingProc", NothingProc },
994 { "CommentClick", (XtActionProc) CommentClick },
995 { "CommentPopDown", (XtActionProc) CommentPopDown },
996 { "EditCommentPopDown", (XtActionProc) EditCommentPopDown },
997 { "TagsPopDown", (XtActionProc) TagsPopDown },
998 { "ErrorPopDown", (XtActionProc) ErrorPopDown },
999 { "ICSInputBoxPopDown", (XtActionProc) ICSInputBoxPopDown },
1000 { "FileNamePopDown", (XtActionProc) FileNamePopDown },
1001 { "AskQuestionPopDown", (XtActionProc) AskQuestionPopDown },
1002 { "GameListPopDown", (XtActionProc) GameListPopDown },
1003 { "GameListOptionsPopDown", (XtActionProc) GameListOptionsPopDown },
1004 { "PromotionPopDown", (XtActionProc) PromotionPopDown },
1005 { "HistoryPopDown", (XtActionProc) HistoryPopDown },
1006 { "EngineOutputPopDown", (XtActionProc) EngineOutputPopDown },
1007 { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
1008 { "ShufflePopDown", (XtActionProc) ShufflePopDown },
1009 { "EnginePopDown", (XtActionProc) EnginePopDown },
1010 { "UciPopDown", (XtActionProc) UciPopDown },
1011 { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
1012 { "NewVariantPopDown", (XtActionProc) NewVariantPopDown },
1013 { "SettingsPopDown", (XtActionProc) SettingsPopDown },
1014 { "CopyMemoProc", (XtActionProc) CopyMemoProc },
1017 char globalTranslations[] =
1018 ":<Key>F9: ResignProc() \n \
1019 :Ctrl<Key>n: ResetProc() \n \
1020 :Meta<Key>V: NewVariantProc() \n \
1021 :Ctrl<Key>o: LoadGameProc() \n \
1022 :Meta<Key>Next: LoadNextGameProc() \n \
1023 :Meta<Key>Prior: LoadPrevGameProc() \n \
1024 :Ctrl<Key>s: SaveGameProc() \n \
1025 :Ctrl<Key>c: CopyGameProc() \n \
1026 :Ctrl<Key>v: PasteGameProc() \n \
1027 :Ctrl<Key>O: LoadPositionProc() \n \
1028 :Shift Meta<Key>Next: LoadNextPositionProc() \n \
1029 :Shift Meta<Key>Prior: LoadPrevPositionProc() \n \
1030 :Ctrl<Key>S: SavePositionProc() \n \
1031 :Ctrl<Key>C: CopyPositionProc() \n \
1032 :Ctrl<Key>V: PastePositionProc() \n \
1033 :Ctrl<Key>q: QuitProc() \n \
1034 :Ctrl<Key>w: MachineWhiteProc() \n \
1035 :Ctrl<Key>b: MachineBlackProc() \n \
1036 :Ctrl<Key>t: TwoMachinesProc() \n \
1037 :Ctrl<Key>a: AnalysisModeProc() \n \
1038 :Ctrl<Key>f: AnalyzeFileProc() \n \
1039 :Ctrl<Key>e: EditGameProc() \n \
1040 :Ctrl<Key>E: EditPositionProc() \n \
1041 :Meta<Key>O: EngineOutputProc() \n \
1042 :Meta<Key>E: EvalGraphProc() \n \
1043 :Meta<Key>G: ShowGameListProc() \n \
1044 :Meta<Key>H: ShowMoveListProc() \n \
1045 :<Key>Pause: PauseProc() \n \
1046 :<Key>F3: AcceptProc() \n \
1047 :<Key>F4: DeclineProc() \n \
1048 :<Key>F12: RematchProc() \n \
1049 :<Key>F5: CallFlagProc() \n \
1050 :<Key>F6: DrawProc() \n \
1051 :<Key>F7: AdjournProc() \n \
1052 :<Key>F8: AbortProc() \n \
1053 :<Key>F10: StopObservingProc() \n \
1054 :<Key>F11: StopExaminingProc() \n \
1055 :Meta Ctrl<Key>F12: DebugProc() \n \
1056 :Meta<Key>End: ToEndProc() \n \
1057 :Meta<Key>Right: ForwardProc() \n \
1058 :Meta<Key>Home: ToStartProc() \n \
1059 :Meta<Key>Left: BackwardProc() \n \
1060 :Ctrl<Key>m: MoveNowProc() \n \
1061 :Ctrl<Key>x: RetractMoveProc() \n \
1062 :Meta<Key>J: EngineMenuProc() \n \
1063 :Meta<Key>U: UciMenuProc() \n \
1064 :Meta<Key>T: TimeControlProc() \n \
1065 :Ctrl<Key>Q: AlwaysQueenProc() \n \
1066 :Ctrl<Key>F: AutoflagProc() \n \
1067 :Ctrl<Key>A: AnimateMovingProc() \n \
1068 :Ctrl<Key>P: PonderNextMoveProc() \n \
1069 :Ctrl<Key>L: TestLegalityProc() \n \
1070 :Ctrl<Key>H: HideThinkingProc() \n \
1071 :<Key>-: Iconify() \n \
1072 :<Key>F1: ManProc() \n \
1073 :<Key>F2: FlipViewProc() \n \
1074 <KeyDown>.: BackwardProc() \n \
1075 <KeyUp>.: ForwardProc() \n \
1076 Shift<Key>1: AskQuestionProc(\"Direct command\",\
1077 \"Send to chess program:\",,1) \n \
1078 Shift<Key>2: AskQuestionProc(\"Direct command\",\
1079 \"Send to second chess program:\",,2) \n";
1081 char boardTranslations[] =
1082 "<Btn1Down>: HandleUserMove() \n \
1083 <Btn1Up>: HandleUserMove() \n \
1084 <Btn1Motion>: AnimateUserMove() \n \
1085 <Btn3Motion>: HandlePV() \n \
1086 <Btn3Up>: PieceMenuPopup(menuB) \n \
1087 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1088 PieceMenuPopup(menuB) \n \
1089 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1090 PieceMenuPopup(menuW) \n \
1091 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1092 PieceMenuPopup(menuW) \n \
1093 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1094 PieceMenuPopup(menuB) \n";
1096 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1097 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1099 char ICSInputTranslations[] =
1100 "<Key>Up: UpKeyProc() \n "
1101 "<Key>Down: DownKeyProc() \n "
1102 "<Key>Return: EnterKeyProc() \n";
1104 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1105 // as the widget is destroyed before the up-click can call extend-end
1106 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1108 String xboardResources[] = {
1109 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1110 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1111 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1116 /* Max possible square size */
1117 #define MAXSQSIZE 256
1119 static int xpm_avail[MAXSQSIZE];
1121 #ifdef HAVE_DIR_STRUCT
1123 /* Extract piece size from filename */
1125 xpm_getsize(name, len, ext)
1136 if ((p=strchr(name, '.')) == NULL ||
1137 StrCaseCmp(p+1, ext) != 0)
1143 while (*p && isdigit(*p))
1150 /* Setup xpm_avail */
1152 xpm_getavail(dirname, ext)
1160 for (i=0; i<MAXSQSIZE; ++i)
1163 if (appData.debugMode)
1164 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1166 dir = opendir(dirname);
1169 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1170 programName, dirname);
1174 while ((ent=readdir(dir)) != NULL) {
1175 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1176 if (i > 0 && i < MAXSQSIZE)
1186 xpm_print_avail(fp, ext)
1192 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1193 for (i=1; i<MAXSQSIZE; ++i) {
1199 /* Return XPM piecesize closest to size */
1201 xpm_closest_to(dirname, size, ext)
1207 int sm_diff = MAXSQSIZE;
1211 xpm_getavail(dirname, ext);
1213 if (appData.debugMode)
1214 xpm_print_avail(stderr, ext);
1216 for (i=1; i<MAXSQSIZE; ++i) {
1219 diff = (diff<0) ? -diff : diff;
1220 if (diff < sm_diff) {
1228 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1234 #else /* !HAVE_DIR_STRUCT */
1235 /* If we are on a system without a DIR struct, we can't
1236 read the directory, so we can't collect a list of
1237 filenames, etc., so we can't do any size-fitting. */
1239 xpm_closest_to(dirname, size, ext)
1244 fprintf(stderr, _("\
1245 Warning: No DIR structure found on this system --\n\
1246 Unable to autosize for XPM/XIM pieces.\n\
1247 Please report this error to frankm@hiwaay.net.\n\
1248 Include system type & operating system in message.\n"));
1251 #endif /* HAVE_DIR_STRUCT */
1253 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1254 "magenta", "cyan", "white" };
1258 TextColors textColors[(int)NColorClasses];
1260 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1262 parse_color(str, which)
1266 char *p, buf[100], *d;
1269 if (strlen(str) > 99) /* watch bounds on buf */
1274 for (i=0; i<which; ++i) {
1281 /* Could be looking at something like:
1283 .. in which case we want to stop on a comma also */
1284 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1288 return -1; /* Use default for empty field */
1291 if (which == 2 || isdigit(*p))
1294 while (*p && isalpha(*p))
1299 for (i=0; i<8; ++i) {
1300 if (!StrCaseCmp(buf, cnames[i]))
1301 return which? (i+40) : (i+30);
1303 if (!StrCaseCmp(buf, "default")) return -1;
1305 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1310 parse_cpair(cc, str)
1314 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1315 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1320 /* bg and attr are optional */
1321 textColors[(int)cc].bg = parse_color(str, 1);
1322 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1323 textColors[(int)cc].attr = 0;
1329 /* Arrange to catch delete-window events */
1330 Atom wm_delete_window;
1332 CatchDeleteWindow(Widget w, String procname)
1335 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1336 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1337 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1344 XtSetArg(args[0], XtNiconic, False);
1345 XtSetValues(shellWidget, args, 1);
1347 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1350 //---------------------------------------------------------------------------------------------------------
1351 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1354 #define CW_USEDEFAULT (1<<31)
1355 #define ICS_TEXT_MENU_SIZE 90
1356 #define DEBUG_FILE "xboard.debug"
1357 #define SetCurrentDirectory chdir
1358 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1362 // these two must some day move to frontend.h, when they are implemented
1363 Boolean GameListIsUp();
1365 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1368 // front-end part of option handling
1370 // [HGM] This platform-dependent table provides the location for storing the color info
1371 extern char *crWhite, * crBlack;
1375 &appData.whitePieceColor,
1376 &appData.blackPieceColor,
1377 &appData.lightSquareColor,
1378 &appData.darkSquareColor,
1379 &appData.highlightSquareColor,
1380 &appData.premoveHighlightColor,
1381 &appData.lowTimeWarningColor,
1392 // [HGM] font: keep a font for each square size, even non-stndard ones
1393 #define NUM_SIZES 18
1394 #define MAX_SIZE 130
1395 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1396 char *fontTable[NUM_FONTS][MAX_SIZE];
1399 ParseFont(char *name, int number)
1400 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1402 if(sscanf(name, "size%d:", &size)) {
1403 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1404 // defer processing it until we know if it matches our board size
1405 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1406 fontTable[number][size] = strdup(strchr(name, ':')+1);
1407 fontValid[number][size] = True;
1412 case 0: // CLOCK_FONT
1413 appData.clockFont = strdup(name);
1415 case 1: // MESSAGE_FONT
1416 appData.font = strdup(name);
1418 case 2: // COORD_FONT
1419 appData.coordFont = strdup(name);
1424 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1429 { // only 2 fonts currently
1430 appData.clockFont = CLOCK_FONT_NAME;
1431 appData.coordFont = COORD_FONT_NAME;
1432 appData.font = DEFAULT_FONT_NAME;
1437 { // no-op, until we identify the code for this already in XBoard and move it here
1441 ParseColor(int n, char *name)
1442 { // in XBoard, just copy the color-name string
1443 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1447 ParseTextAttribs(ColorClass cc, char *s)
1449 (&appData.colorShout)[cc] = strdup(s);
1453 ParseBoardSize(void *addr, char *name)
1455 appData.boardSize = strdup(name);
1460 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1464 SetCommPortDefaults()
1465 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1468 // [HGM] args: these three cases taken out to stay in front-end
1470 SaveFontArg(FILE *f, ArgDescriptor *ad)
1473 int i, n = (int)ad->argLoc;
1475 case 0: // CLOCK_FONT
1476 name = appData.clockFont;
1478 case 1: // MESSAGE_FONT
1479 name = appData.font;
1481 case 2: // COORD_FONT
1482 name = appData.coordFont;
1487 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1488 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1489 fontTable[n][squareSize] = strdup(name);
1490 fontValid[n][squareSize] = True;
1493 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1494 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1499 { // nothing to do, as the sounds are at all times represented by their text-string names already
1503 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1504 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1505 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1509 SaveColor(FILE *f, ArgDescriptor *ad)
1510 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1511 if(colorVariable[(int)ad->argLoc])
1512 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1516 SaveBoardSize(FILE *f, char *name, void *addr)
1517 { // wrapper to shield back-end from BoardSize & sizeInfo
1518 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1522 ParseCommPortSettings(char *s)
1523 { // no such option in XBoard (yet)
1526 extern Widget engineOutputShell;
1527 extern Widget tagsShell, editTagsShell;
1529 GetActualPlacement(Widget wg, WindowPlacement *wp)
1539 XtSetArg(args[i], XtNx, &x); i++;
1540 XtSetArg(args[i], XtNy, &y); i++;
1541 XtSetArg(args[i], XtNwidth, &w); i++;
1542 XtSetArg(args[i], XtNheight, &h); i++;
1543 XtGetValues(wg, args, i);
1552 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1553 // In XBoard this will have to wait until awareness of window parameters is implemented
1554 GetActualPlacement(shellWidget, &wpMain);
1555 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1556 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1557 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1558 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1559 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1560 else GetActualPlacement(editShell, &wpComment);
1561 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1562 else GetActualPlacement(editTagsShell, &wpTags);
1566 PrintCommPortSettings(FILE *f, char *name)
1567 { // This option does not exist in XBoard
1571 MySearchPath(char *installDir, char *name, char *fullname)
1572 { // just append installDir and name. Perhaps ExpandPath should be used here?
1573 name = ExpandPathName(name);
1574 if(name && name[0] == '/')
1575 safeStrCpy(fullname, name, MSG_SIZ );
1577 sprintf(fullname, "%s%c%s", installDir, '/', name);
1583 MyGetFullPathName(char *name, char *fullname)
1584 { // should use ExpandPath?
1585 name = ExpandPathName(name);
1586 safeStrCpy(fullname, name, MSG_SIZ );
1591 EnsureOnScreen(int *x, int *y, int minX, int minY)
1598 { // [HGM] args: allows testing if main window is realized from back-end
1599 return xBoardWindow != 0;
1603 PopUpStartupDialog()
1604 { // start menu not implemented in XBoard
1608 ConvertToLine(int argc, char **argv)
1610 static char line[128*1024], buf[1024];
1614 for(i=1; i<argc; i++)
1616 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1617 && argv[i][0] != '{' )
1618 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1620 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1621 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1624 line[strlen(line)-1] = NULLCHAR;
1628 //--------------------------------------------------------------------------------------------
1630 extern Boolean twoBoards, partnerUp;
1633 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1635 #define BoardSize int
1636 void InitDrawingSizes(BoardSize boardSize, int flags)
1637 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1638 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1640 XtGeometryResult gres;
1643 if(!formWidget) return;
1646 * Enable shell resizing.
1648 shellArgs[0].value = (XtArgVal) &w;
1649 shellArgs[1].value = (XtArgVal) &h;
1650 XtGetValues(shellWidget, shellArgs, 2);
1652 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1653 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1654 XtSetValues(shellWidget, &shellArgs[2], 4);
1656 XtSetArg(args[0], XtNdefaultDistance, &sep);
1657 XtGetValues(formWidget, args, 1);
1659 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1660 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1662 hOffset = boardWidth + 10;
1663 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1664 secondSegments[i] = gridSegments[i];
1665 secondSegments[i].x1 += hOffset;
1666 secondSegments[i].x2 += hOffset;
1669 XtSetArg(args[0], XtNwidth, boardWidth);
1670 XtSetArg(args[1], XtNheight, boardHeight);
1671 XtSetValues(boardWidget, args, 2);
1673 timerWidth = (boardWidth - sep) / 2;
1674 XtSetArg(args[0], XtNwidth, timerWidth);
1675 XtSetValues(whiteTimerWidget, args, 1);
1676 XtSetValues(blackTimerWidget, args, 1);
1678 XawFormDoLayout(formWidget, False);
1680 if (appData.titleInWindow) {
1682 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1683 XtSetArg(args[i], XtNheight, &h); i++;
1684 XtGetValues(titleWidget, args, i);
1686 w = boardWidth - 2*bor;
1688 XtSetArg(args[0], XtNwidth, &w);
1689 XtGetValues(menuBarWidget, args, 1);
1690 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1693 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1694 if (gres != XtGeometryYes && appData.debugMode) {
1696 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1697 programName, gres, w, h, wr, hr);
1701 XawFormDoLayout(formWidget, True);
1704 * Inhibit shell resizing.
1706 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1707 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1708 shellArgs[4].value = shellArgs[2].value = w;
1709 shellArgs[5].value = shellArgs[3].value = h;
1710 XtSetValues(shellWidget, &shellArgs[0], 6);
1712 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1715 for(i=0; i<4; i++) {
1717 for(p=0; p<=(int)WhiteKing; p++)
1718 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1719 if(gameInfo.variant == VariantShogi) {
1720 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1721 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1722 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1723 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1724 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1727 if(gameInfo.variant == VariantGothic) {
1728 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1732 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1733 for(p=0; p<=(int)WhiteKing; p++)
1734 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1735 if(gameInfo.variant == VariantShogi) {
1736 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1737 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1738 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1739 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1740 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1743 if(gameInfo.variant == VariantGothic) {
1744 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1750 for(i=0; i<2; i++) {
1752 for(p=0; p<=(int)WhiteKing; p++)
1753 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1754 if(gameInfo.variant == VariantShogi) {
1755 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1756 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1757 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1758 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1759 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1762 if(gameInfo.variant == VariantGothic) {
1763 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1779 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1780 XSetWindowAttributes window_attributes;
1782 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1783 XrmValue vFrom, vTo;
1784 XtGeometryResult gres;
1787 int forceMono = False;
1789 srandom(time(0)); // [HGM] book: make random truly random
1791 setbuf(stdout, NULL);
1792 setbuf(stderr, NULL);
1795 # if HAVE_LIBREADLINE
1796 /* install gnu-readline handler */
1797 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1798 rl_readline_name="XBoard";
1801 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1802 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1806 programName = strrchr(argv[0], '/');
1807 if (programName == NULL)
1808 programName = argv[0];
1813 XtSetLanguageProc(NULL, NULL, NULL);
1814 bindtextdomain(PACKAGE, LOCALEDIR);
1815 textdomain(PACKAGE);
1819 XtAppInitialize(&appContext, "XBoard", shellOptions,
1820 XtNumber(shellOptions),
1821 &argc, argv, xboardResources, NULL, 0);
1822 appData.boardSize = "";
1823 InitAppData(ConvertToLine(argc, argv));
1825 if (p == NULL) p = "/tmp";
1826 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1827 gameCopyFilename = (char*) malloc(i);
1828 gamePasteFilename = (char*) malloc(i);
1829 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1830 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1832 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1833 clientResources, XtNumber(clientResources),
1836 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1837 static char buf[MSG_SIZ];
1838 EscapeExpand(buf, appData.initString);
1839 appData.initString = strdup(buf);
1840 EscapeExpand(buf, appData.secondInitString);
1841 appData.secondInitString = strdup(buf);
1842 EscapeExpand(buf, appData.firstComputerString);
1843 appData.firstComputerString = strdup(buf);
1844 EscapeExpand(buf, appData.secondComputerString);
1845 appData.secondComputerString = strdup(buf);
1848 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1851 if (chdir(chessDir) != 0) {
1852 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1858 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1859 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1860 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1861 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1864 setbuf(debugFP, NULL);
1867 /* [HGM,HR] make sure board size is acceptable */
1868 if(appData.NrFiles > BOARD_FILES ||
1869 appData.NrRanks > BOARD_RANKS )
1870 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1873 /* This feature does not work; animation needs a rewrite */
1874 appData.highlightDragging = FALSE;
1878 xDisplay = XtDisplay(shellWidget);
1879 xScreen = DefaultScreen(xDisplay);
1880 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1882 gameInfo.variant = StringToVariant(appData.variant);
1883 InitPosition(FALSE);
1886 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1888 if (isdigit(appData.boardSize[0])) {
1889 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1890 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1891 &fontPxlSize, &smallLayout, &tinyLayout);
1893 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1894 programName, appData.boardSize);
1898 /* Find some defaults; use the nearest known size */
1899 SizeDefaults *szd, *nearest;
1900 int distance = 99999;
1901 nearest = szd = sizeDefaults;
1902 while (szd->name != NULL) {
1903 if (abs(szd->squareSize - squareSize) < distance) {
1905 distance = abs(szd->squareSize - squareSize);
1906 if (distance == 0) break;
1910 if (i < 2) lineGap = nearest->lineGap;
1911 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1912 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1913 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1914 if (i < 6) smallLayout = nearest->smallLayout;
1915 if (i < 7) tinyLayout = nearest->tinyLayout;
1918 SizeDefaults *szd = sizeDefaults;
1919 if (*appData.boardSize == NULLCHAR) {
1920 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1921 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1924 if (szd->name == NULL) szd--;
1925 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1927 while (szd->name != NULL &&
1928 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1929 if (szd->name == NULL) {
1930 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1931 programName, appData.boardSize);
1935 squareSize = szd->squareSize;
1936 lineGap = szd->lineGap;
1937 clockFontPxlSize = szd->clockFontPxlSize;
1938 coordFontPxlSize = szd->coordFontPxlSize;
1939 fontPxlSize = szd->fontPxlSize;
1940 smallLayout = szd->smallLayout;
1941 tinyLayout = szd->tinyLayout;
1942 // [HGM] font: use defaults from settings file if available and not overruled
1944 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1945 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1946 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1947 appData.font = fontTable[MESSAGE_FONT][squareSize];
1948 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1949 appData.coordFont = fontTable[COORD_FONT][squareSize];
1951 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1952 if (strlen(appData.pixmapDirectory) > 0) {
1953 p = ExpandPathName(appData.pixmapDirectory);
1955 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1956 appData.pixmapDirectory);
1959 if (appData.debugMode) {
1960 fprintf(stderr, _("\
1961 XBoard square size (hint): %d\n\
1962 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1964 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1965 if (appData.debugMode) {
1966 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1970 /* [HR] height treated separately (hacked) */
1971 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1972 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1973 if (appData.showJail == 1) {
1974 /* Jail on top and bottom */
1975 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1976 XtSetArg(boardArgs[2], XtNheight,
1977 boardHeight + 2*(lineGap + squareSize));
1978 } else if (appData.showJail == 2) {
1980 XtSetArg(boardArgs[1], XtNwidth,
1981 boardWidth + 2*(lineGap + squareSize));
1982 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1985 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1986 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1990 * Determine what fonts to use.
1992 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1993 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1994 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1995 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1996 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1997 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1998 appData.font = FindFont(appData.font, fontPxlSize);
1999 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2000 countFontStruct = XQueryFont(xDisplay, countFontID);
2001 // appData.font = FindFont(appData.font, fontPxlSize);
2003 xdb = XtDatabase(xDisplay);
2004 XrmPutStringResource(&xdb, "*font", appData.font);
2007 * Detect if there are not enough colors available and adapt.
2009 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2010 appData.monoMode = True;
2013 if (!appData.monoMode) {
2014 vFrom.addr = (caddr_t) appData.lightSquareColor;
2015 vFrom.size = strlen(appData.lightSquareColor);
2016 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2017 if (vTo.addr == NULL) {
2018 appData.monoMode = True;
2021 lightSquareColor = *(Pixel *) vTo.addr;
2024 if (!appData.monoMode) {
2025 vFrom.addr = (caddr_t) appData.darkSquareColor;
2026 vFrom.size = strlen(appData.darkSquareColor);
2027 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2028 if (vTo.addr == NULL) {
2029 appData.monoMode = True;
2032 darkSquareColor = *(Pixel *) vTo.addr;
2035 if (!appData.monoMode) {
2036 vFrom.addr = (caddr_t) appData.whitePieceColor;
2037 vFrom.size = strlen(appData.whitePieceColor);
2038 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2039 if (vTo.addr == NULL) {
2040 appData.monoMode = True;
2043 whitePieceColor = *(Pixel *) vTo.addr;
2046 if (!appData.monoMode) {
2047 vFrom.addr = (caddr_t) appData.blackPieceColor;
2048 vFrom.size = strlen(appData.blackPieceColor);
2049 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2050 if (vTo.addr == NULL) {
2051 appData.monoMode = True;
2054 blackPieceColor = *(Pixel *) vTo.addr;
2058 if (!appData.monoMode) {
2059 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2060 vFrom.size = strlen(appData.highlightSquareColor);
2061 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2062 if (vTo.addr == NULL) {
2063 appData.monoMode = True;
2066 highlightSquareColor = *(Pixel *) vTo.addr;
2070 if (!appData.monoMode) {
2071 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2072 vFrom.size = strlen(appData.premoveHighlightColor);
2073 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2074 if (vTo.addr == NULL) {
2075 appData.monoMode = True;
2078 premoveHighlightColor = *(Pixel *) vTo.addr;
2083 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2086 if (appData.bitmapDirectory == NULL ||
2087 appData.bitmapDirectory[0] == NULLCHAR)
2088 appData.bitmapDirectory = DEF_BITMAP_DIR;
2091 if (appData.lowTimeWarning && !appData.monoMode) {
2092 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2093 vFrom.size = strlen(appData.lowTimeWarningColor);
2094 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2095 if (vTo.addr == NULL)
2096 appData.monoMode = True;
2098 lowTimeWarningColor = *(Pixel *) vTo.addr;
2101 if (appData.monoMode && appData.debugMode) {
2102 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2103 (unsigned long) XWhitePixel(xDisplay, xScreen),
2104 (unsigned long) XBlackPixel(xDisplay, xScreen));
2107 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2108 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2109 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2110 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2111 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2112 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2113 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2114 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2115 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2116 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2118 if (appData.colorize) {
2120 _("%s: can't parse color names; disabling colorization\n"),
2123 appData.colorize = FALSE;
2125 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2126 textColors[ColorNone].attr = 0;
2128 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2134 layoutName = "tinyLayout";
2135 } else if (smallLayout) {
2136 layoutName = "smallLayout";
2138 layoutName = "normalLayout";
2140 /* Outer layoutWidget is there only to provide a name for use in
2141 resources that depend on the layout style */
2143 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2144 layoutArgs, XtNumber(layoutArgs));
2146 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2147 formArgs, XtNumber(formArgs));
2148 XtSetArg(args[0], XtNdefaultDistance, &sep);
2149 XtGetValues(formWidget, args, 1);
2152 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2153 XtSetArg(args[0], XtNtop, XtChainTop);
2154 XtSetArg(args[1], XtNbottom, XtChainTop);
2155 XtSetArg(args[2], XtNright, XtChainLeft);
2156 XtSetValues(menuBarWidget, args, 3);
2158 widgetList[j++] = whiteTimerWidget =
2159 XtCreateWidget("whiteTime", labelWidgetClass,
2160 formWidget, timerArgs, XtNumber(timerArgs));
2161 XtSetArg(args[0], XtNfont, clockFontStruct);
2162 XtSetArg(args[1], XtNtop, XtChainTop);
2163 XtSetArg(args[2], XtNbottom, XtChainTop);
2164 XtSetValues(whiteTimerWidget, args, 3);
2166 widgetList[j++] = blackTimerWidget =
2167 XtCreateWidget("blackTime", labelWidgetClass,
2168 formWidget, timerArgs, XtNumber(timerArgs));
2169 XtSetArg(args[0], XtNfont, clockFontStruct);
2170 XtSetArg(args[1], XtNtop, XtChainTop);
2171 XtSetArg(args[2], XtNbottom, XtChainTop);
2172 XtSetValues(blackTimerWidget, args, 3);
2174 if (appData.titleInWindow) {
2175 widgetList[j++] = titleWidget =
2176 XtCreateWidget("title", labelWidgetClass, formWidget,
2177 titleArgs, XtNumber(titleArgs));
2178 XtSetArg(args[0], XtNtop, XtChainTop);
2179 XtSetArg(args[1], XtNbottom, XtChainTop);
2180 XtSetValues(titleWidget, args, 2);
2183 if (appData.showButtonBar) {
2184 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2185 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2186 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2187 XtSetArg(args[2], XtNtop, XtChainTop);
2188 XtSetArg(args[3], XtNbottom, XtChainTop);
2189 XtSetValues(buttonBarWidget, args, 4);
2192 widgetList[j++] = messageWidget =
2193 XtCreateWidget("message", labelWidgetClass, formWidget,
2194 messageArgs, XtNumber(messageArgs));
2195 XtSetArg(args[0], XtNtop, XtChainTop);
2196 XtSetArg(args[1], XtNbottom, XtChainTop);
2197 XtSetValues(messageWidget, args, 2);
2199 widgetList[j++] = boardWidget =
2200 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2201 XtNumber(boardArgs));
2203 XtManageChildren(widgetList, j);
2205 timerWidth = (boardWidth - sep) / 2;
2206 XtSetArg(args[0], XtNwidth, timerWidth);
2207 XtSetValues(whiteTimerWidget, args, 1);
2208 XtSetValues(blackTimerWidget, args, 1);
2210 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2211 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2212 XtGetValues(whiteTimerWidget, args, 2);
2214 if (appData.showButtonBar) {
2215 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2216 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2217 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2221 * formWidget uses these constraints but they are stored
2225 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2226 XtSetValues(menuBarWidget, args, i);
2227 if (appData.titleInWindow) {
2230 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2231 XtSetValues(whiteTimerWidget, args, i);
2233 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2234 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2235 XtSetValues(blackTimerWidget, args, i);
2237 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2238 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2239 XtSetValues(titleWidget, args, i);
2241 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2242 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2243 XtSetValues(messageWidget, args, i);
2244 if (appData.showButtonBar) {
2246 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2247 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2248 XtSetValues(buttonBarWidget, args, i);
2252 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2253 XtSetValues(whiteTimerWidget, args, i);
2255 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2256 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2257 XtSetValues(blackTimerWidget, args, i);
2259 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2260 XtSetValues(titleWidget, args, i);
2262 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2263 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2264 XtSetValues(messageWidget, args, i);
2265 if (appData.showButtonBar) {
2267 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2268 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2269 XtSetValues(buttonBarWidget, args, i);
2274 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2275 XtSetValues(whiteTimerWidget, args, i);
2277 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2278 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2279 XtSetValues(blackTimerWidget, args, i);
2281 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2282 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2283 XtSetValues(messageWidget, args, i);
2284 if (appData.showButtonBar) {
2286 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2287 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2288 XtSetValues(buttonBarWidget, args, i);
2292 XtSetArg(args[0], XtNfromVert, messageWidget);
2293 XtSetArg(args[1], XtNtop, XtChainTop);
2294 XtSetArg(args[2], XtNbottom, XtChainBottom);
2295 XtSetArg(args[3], XtNleft, XtChainLeft);
2296 XtSetArg(args[4], XtNright, XtChainRight);
2297 XtSetValues(boardWidget, args, 5);
2299 XtRealizeWidget(shellWidget);
2302 XtSetArg(args[0], XtNx, wpMain.x);
2303 XtSetArg(args[1], XtNy, wpMain.y);
2304 XtSetValues(shellWidget, args, 2);
2308 * Correct the width of the message and title widgets.
2309 * It is not known why some systems need the extra fudge term.
2310 * The value "2" is probably larger than needed.
2312 XawFormDoLayout(formWidget, False);
2314 #define WIDTH_FUDGE 2
2316 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2317 XtSetArg(args[i], XtNheight, &h); i++;
2318 XtGetValues(messageWidget, args, i);
2319 if (appData.showButtonBar) {
2321 XtSetArg(args[i], XtNwidth, &w); i++;
2322 XtGetValues(buttonBarWidget, args, i);
2323 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2325 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2328 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2329 if (gres != XtGeometryYes && appData.debugMode) {
2330 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2331 programName, gres, w, h, wr, hr);
2334 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2335 /* The size used for the child widget in layout lags one resize behind
2336 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2338 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2339 if (gres != XtGeometryYes && appData.debugMode) {
2340 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2341 programName, gres, w, h, wr, hr);
2344 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2345 XtSetArg(args[1], XtNright, XtChainRight);
2346 XtSetValues(messageWidget, args, 2);
2348 if (appData.titleInWindow) {
2350 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2351 XtSetArg(args[i], XtNheight, &h); i++;
2352 XtGetValues(titleWidget, args, i);
2354 w = boardWidth - 2*bor;
2356 XtSetArg(args[0], XtNwidth, &w);
2357 XtGetValues(menuBarWidget, args, 1);
2358 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2361 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2362 if (gres != XtGeometryYes && appData.debugMode) {
2364 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2365 programName, gres, w, h, wr, hr);
2368 XawFormDoLayout(formWidget, True);
2370 xBoardWindow = XtWindow(boardWidget);
2372 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2373 // not need to go into InitDrawingSizes().
2377 * Create X checkmark bitmap and initialize option menu checks.
2379 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2380 checkmark_bits, checkmark_width, checkmark_height);
2381 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2382 if (appData.alwaysPromoteToQueen) {
2383 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2386 if (appData.animateDragging) {
2387 XtSetValues(XtNameToWidget(menuBarWidget,
2388 "menuOptions.Animate Dragging"),
2391 if (appData.animate) {
2392 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2395 if (appData.autoComment) {
2396 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2399 if (appData.autoCallFlag) {
2400 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2403 if (appData.autoFlipView) {
2404 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2407 if (appData.autoObserve) {
2408 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2411 if (appData.autoRaiseBoard) {
2412 XtSetValues(XtNameToWidget(menuBarWidget,
2413 "menuOptions.Auto Raise Board"), args, 1);
2415 if (appData.autoSaveGames) {
2416 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2419 if (appData.saveGameFile[0] != NULLCHAR) {
2420 /* Can't turn this off from menu */
2421 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2423 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2427 if (appData.blindfold) {
2428 XtSetValues(XtNameToWidget(menuBarWidget,
2429 "menuOptions.Blindfold"), args, 1);
2431 if (appData.flashCount > 0) {
2432 XtSetValues(XtNameToWidget(menuBarWidget,
2433 "menuOptions.Flash Moves"),
2436 if (appData.getMoveList) {
2437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2441 if (appData.highlightDragging) {
2442 XtSetValues(XtNameToWidget(menuBarWidget,
2443 "menuOptions.Highlight Dragging"),
2447 if (appData.highlightLastMove) {
2448 XtSetValues(XtNameToWidget(menuBarWidget,
2449 "menuOptions.Highlight Last Move"),
2452 if (appData.icsAlarm) {
2453 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2456 if (appData.ringBellAfterMoves) {
2457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2460 if (appData.oldSaveStyle) {
2461 XtSetValues(XtNameToWidget(menuBarWidget,
2462 "menuOptions.Old Save Style"), args, 1);
2464 if (appData.periodicUpdates) {
2465 XtSetValues(XtNameToWidget(menuBarWidget,
2466 "menuOptions.Periodic Updates"), args, 1);
2468 if (appData.ponderNextMove) {
2469 XtSetValues(XtNameToWidget(menuBarWidget,
2470 "menuOptions.Ponder Next Move"), args, 1);
2472 if (appData.popupExitMessage) {
2473 XtSetValues(XtNameToWidget(menuBarWidget,
2474 "menuOptions.Popup Exit Message"), args, 1);
2476 if (appData.popupMoveErrors) {
2477 XtSetValues(XtNameToWidget(menuBarWidget,
2478 "menuOptions.Popup Move Errors"), args, 1);
2480 if (appData.premove) {
2481 XtSetValues(XtNameToWidget(menuBarWidget,
2482 "menuOptions.Premove"), args, 1);
2484 if (appData.quietPlay) {
2485 XtSetValues(XtNameToWidget(menuBarWidget,
2486 "menuOptions.Quiet Play"), args, 1);
2488 if (appData.showCoords) {
2489 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2492 if (appData.hideThinkingFromHuman) {
2493 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2496 if (appData.testLegality) {
2497 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2500 if (saveSettingsOnExit) {
2501 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2508 ReadBitmap(&wIconPixmap, "icon_white.bm",
2509 icon_white_bits, icon_white_width, icon_white_height);
2510 ReadBitmap(&bIconPixmap, "icon_black.bm",
2511 icon_black_bits, icon_black_width, icon_black_height);
2512 iconPixmap = wIconPixmap;
2514 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2515 XtSetValues(shellWidget, args, i);
2518 * Create a cursor for the board widget.
2520 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2521 XChangeWindowAttributes(xDisplay, xBoardWindow,
2522 CWCursor, &window_attributes);
2525 * Inhibit shell resizing.
2527 shellArgs[0].value = (XtArgVal) &w;
2528 shellArgs[1].value = (XtArgVal) &h;
2529 XtGetValues(shellWidget, shellArgs, 2);
2530 shellArgs[4].value = shellArgs[2].value = w;
2531 shellArgs[5].value = shellArgs[3].value = h;
2532 XtSetValues(shellWidget, &shellArgs[2], 4);
2533 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2534 marginH = h - boardHeight;
2536 CatchDeleteWindow(shellWidget, "QuitProc");
2541 if (appData.bitmapDirectory[0] != NULLCHAR) {
2548 /* Create regular pieces */
2549 if (!useImages) CreatePieces();
2554 if (appData.animate || appData.animateDragging)
2557 XtAugmentTranslations(formWidget,
2558 XtParseTranslationTable(globalTranslations));
2559 XtAugmentTranslations(boardWidget,
2560 XtParseTranslationTable(boardTranslations));
2561 XtAugmentTranslations(whiteTimerWidget,
2562 XtParseTranslationTable(whiteTranslations));
2563 XtAugmentTranslations(blackTimerWidget,
2564 XtParseTranslationTable(blackTranslations));
2566 /* Why is the following needed on some versions of X instead
2567 * of a translation? */
2568 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2569 (XtEventHandler) EventProc, NULL);
2572 /* [AS] Restore layout */
2573 if( wpMoveHistory.visible ) {
2577 if( wpEvalGraph.visible )
2582 if( wpEngineOutput.visible ) {
2583 EngineOutputPopUp();
2588 if (errorExitStatus == -1) {
2589 if (appData.icsActive) {
2590 /* We now wait until we see "login:" from the ICS before
2591 sending the logon script (problems with timestamp otherwise) */
2592 /*ICSInitScript();*/
2593 if (appData.icsInputBox) ICSInputBoxPopUp();
2597 signal(SIGWINCH, TermSizeSigHandler);
2599 signal(SIGINT, IntSigHandler);
2600 signal(SIGTERM, IntSigHandler);
2601 if (*appData.cmailGameName != NULLCHAR) {
2602 signal(SIGUSR1, CmailSigHandler);
2605 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2607 XtSetKeyboardFocus(shellWidget, formWidget);
2609 XtAppMainLoop(appContext);
2610 if (appData.debugMode) fclose(debugFP); // [DM] debug
2617 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2618 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2620 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2621 unlink(gameCopyFilename);
2622 unlink(gamePasteFilename);
2624 # if HAVE_LIBREADLINE
2625 /* remove gnu-readline handler. */
2626 rl_callback_handler_remove();
2632 RETSIGTYPE TermSizeSigHandler(int sig)
2645 CmailSigHandler(sig)
2651 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2653 /* Activate call-back function CmailSigHandlerCallBack() */
2654 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2656 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2660 CmailSigHandlerCallBack(isr, closure, message, count, error)
2668 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2670 /**** end signal code ****/
2676 /* try to open the icsLogon script, either in the location given
2677 * or in the users HOME directory
2684 f = fopen(appData.icsLogon, "r");
2687 homedir = getenv("HOME");
2688 if (homedir != NULL)
2690 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2691 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2692 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2693 f = fopen(buf, "r");
2698 ProcessICSInitScript(f);
2700 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2709 EditCommentPopDown();
2724 if (!menuBarWidget) return;
2725 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2727 DisplayError("menuStep.Revert", 0);
2729 XtSetSensitive(w, !grey);
2731 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2733 DisplayError("menuStep.Annotate", 0);
2735 XtSetSensitive(w, !grey);
2740 SetMenuEnables(enab)
2744 if (!menuBarWidget) return;
2745 while (enab->name != NULL) {
2746 w = XtNameToWidget(menuBarWidget, enab->name);
2748 DisplayError(enab->name, 0);
2750 XtSetSensitive(w, enab->value);
2756 Enables icsEnables[] = {
2757 { "menuFile.Mail Move", False },
2758 { "menuFile.Reload CMail Message", False },
2759 { "menuMode.Machine Black", False },
2760 { "menuMode.Machine White", False },
2761 { "menuMode.Analysis Mode", False },
2762 { "menuMode.Analyze File", False },
2763 { "menuMode.Two Machines", False },
2765 { "menuHelp.Hint", False },
2766 { "menuHelp.Book", False },
2767 { "menuStep.Move Now", False },
2768 { "menuOptions.Periodic Updates", False },
2769 { "menuOptions.Hide Thinking", False },
2770 { "menuOptions.Ponder Next Move", False },
2772 { "menuStep.Annotate", False },
2776 Enables ncpEnables[] = {
2777 { "menuFile.Mail Move", False },
2778 { "menuFile.Reload CMail Message", False },
2779 { "menuMode.Machine White", False },
2780 { "menuMode.Machine Black", False },
2781 { "menuMode.Analysis Mode", False },
2782 { "menuMode.Analyze File", False },
2783 { "menuMode.Two Machines", False },
2784 { "menuMode.ICS Client", False },
2785 { "menuMode.ICS Input Box", False },
2786 { "Action", False },
2787 { "menuStep.Revert", False },
2788 { "menuStep.Annotate", False },
2789 { "menuStep.Move Now", False },
2790 { "menuStep.Retract Move", False },
2791 { "menuOptions.Auto Comment", False },
2792 { "menuOptions.Auto Flag", False },
2793 { "menuOptions.Auto Flip View", False },
2794 { "menuOptions.Auto Observe", False },
2795 { "menuOptions.Auto Raise Board", False },
2796 { "menuOptions.Get Move List", False },
2797 { "menuOptions.ICS Alarm", False },
2798 { "menuOptions.Move Sound", False },
2799 { "menuOptions.Quiet Play", False },
2800 { "menuOptions.Hide Thinking", False },
2801 { "menuOptions.Periodic Updates", False },
2802 { "menuOptions.Ponder Next Move", False },
2803 { "menuHelp.Hint", False },
2804 { "menuHelp.Book", False },
2808 Enables gnuEnables[] = {
2809 { "menuMode.ICS Client", False },
2810 { "menuMode.ICS Input Box", False },
2811 { "menuAction.Accept", False },
2812 { "menuAction.Decline", False },
2813 { "menuAction.Rematch", False },
2814 { "menuAction.Adjourn", False },
2815 { "menuAction.Stop Examining", False },
2816 { "menuAction.Stop Observing", False },
2817 { "menuAction.Upload to Examine", False },
2818 { "menuStep.Revert", False },
2819 { "menuStep.Annotate", False },
2820 { "menuOptions.Auto Comment", False },
2821 { "menuOptions.Auto Observe", False },
2822 { "menuOptions.Auto Raise Board", False },
2823 { "menuOptions.Get Move List", False },
2824 { "menuOptions.Premove", False },
2825 { "menuOptions.Quiet Play", False },
2827 /* The next two options rely on SetCmailMode being called *after* */
2828 /* SetGNUMode so that when GNU is being used to give hints these */
2829 /* menu options are still available */
2831 { "menuFile.Mail Move", False },
2832 { "menuFile.Reload CMail Message", False },
2836 Enables cmailEnables[] = {
2838 { "menuAction.Call Flag", False },
2839 { "menuAction.Draw", True },
2840 { "menuAction.Adjourn", False },
2841 { "menuAction.Abort", False },
2842 { "menuAction.Stop Observing", False },
2843 { "menuAction.Stop Examining", False },
2844 { "menuFile.Mail Move", True },
2845 { "menuFile.Reload CMail Message", True },
2849 Enables trainingOnEnables[] = {
2850 { "menuMode.Edit Comment", False },
2851 { "menuMode.Pause", False },
2852 { "menuStep.Forward", False },
2853 { "menuStep.Backward", False },
2854 { "menuStep.Forward to End", False },
2855 { "menuStep.Back to Start", False },
2856 { "menuStep.Move Now", False },
2857 { "menuStep.Truncate Game", False },
2861 Enables trainingOffEnables[] = {
2862 { "menuMode.Edit Comment", True },
2863 { "menuMode.Pause", True },
2864 { "menuStep.Forward", True },
2865 { "menuStep.Backward", True },
2866 { "menuStep.Forward to End", True },
2867 { "menuStep.Back to Start", True },
2868 { "menuStep.Move Now", True },
2869 { "menuStep.Truncate Game", True },
2873 Enables machineThinkingEnables[] = {
2874 { "menuFile.Load Game", False },
2875 { "menuFile.Load Next Game", False },
2876 { "menuFile.Load Previous Game", False },
2877 { "menuFile.Reload Same Game", False },
2878 { "menuFile.Paste Game", False },
2879 { "menuFile.Load Position", False },
2880 { "menuFile.Load Next Position", False },
2881 { "menuFile.Load Previous Position", False },
2882 { "menuFile.Reload Same Position", False },
2883 { "menuFile.Paste Position", False },
2884 { "menuMode.Machine White", False },
2885 { "menuMode.Machine Black", False },
2886 { "menuMode.Two Machines", False },
2887 { "menuStep.Retract Move", False },
2891 Enables userThinkingEnables[] = {
2892 { "menuFile.Load Game", True },
2893 { "menuFile.Load Next Game", True },
2894 { "menuFile.Load Previous Game", True },
2895 { "menuFile.Reload Same Game", True },
2896 { "menuFile.Paste Game", True },
2897 { "menuFile.Load Position", True },
2898 { "menuFile.Load Next Position", True },
2899 { "menuFile.Load Previous Position", True },
2900 { "menuFile.Reload Same Position", True },
2901 { "menuFile.Paste Position", True },
2902 { "menuMode.Machine White", True },
2903 { "menuMode.Machine Black", True },
2904 { "menuMode.Two Machines", True },
2905 { "menuStep.Retract Move", True },
2911 SetMenuEnables(icsEnables);
2914 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2915 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2922 SetMenuEnables(ncpEnables);
2928 SetMenuEnables(gnuEnables);
2934 SetMenuEnables(cmailEnables);
2940 SetMenuEnables(trainingOnEnables);
2941 if (appData.showButtonBar) {
2942 XtSetSensitive(buttonBarWidget, False);
2948 SetTrainingModeOff()
2950 SetMenuEnables(trainingOffEnables);
2951 if (appData.showButtonBar) {
2952 XtSetSensitive(buttonBarWidget, True);
2957 SetUserThinkingEnables()
2959 if (appData.noChessProgram) return;
2960 SetMenuEnables(userThinkingEnables);
2964 SetMachineThinkingEnables()
2966 if (appData.noChessProgram) return;
2967 SetMenuEnables(machineThinkingEnables);
2969 case MachinePlaysBlack:
2970 case MachinePlaysWhite:
2971 case TwoMachinesPlay:
2972 XtSetSensitive(XtNameToWidget(menuBarWidget,
2973 ModeToWidgetName(gameMode)), True);
2980 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2981 #define HISTORY_SIZE 64
\r
2982 static char *history[HISTORY_SIZE];
\r
2983 int histIn = 0, histP = 0;
\r
2986 SaveInHistory(char *cmd)
\r
2988 if (history[histIn] != NULL) {
\r
2989 free(history[histIn]);
\r
2990 history[histIn] = NULL;
\r
2992 if (*cmd == NULLCHAR) return;
\r
2993 history[histIn] = StrSave(cmd);
\r
2994 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2995 if (history[histIn] != NULL) {
\r
2996 free(history[histIn]);
\r
2997 history[histIn] = NULL;
\r
3003 PrevInHistory(char *cmd)
\r
3006 if (histP == histIn) {
\r
3007 if (history[histIn] != NULL) free(history[histIn]);
\r
3008 history[histIn] = StrSave(cmd);
\r
3010 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3011 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3013 return history[histP];
\r
3019 if (histP == histIn) return NULL;
\r
3020 histP = (histP + 1) % HISTORY_SIZE;
\r
3021 return history[histP];
\r
3023 // end of borrowed code
\r
3025 #define Abs(n) ((n)<0 ? -(n) : (n))
3028 * Find a font that matches "pattern" that is as close as
3029 * possible to the targetPxlSize. Prefer fonts that are k
3030 * pixels smaller to fonts that are k pixels larger. The
3031 * pattern must be in the X Consortium standard format,
3032 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3033 * The return value should be freed with XtFree when no
3037 FindFont(pattern, targetPxlSize)
3041 char **fonts, *p, *best, *scalable, *scalableTail;
3042 int i, j, nfonts, minerr, err, pxlSize;
3045 char **missing_list;
3047 char *def_string, *base_fnt_lst, strInt[3];
3049 XFontStruct **fnt_list;
3051 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3052 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3053 p = strstr(pattern, "--");
3054 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3055 strcat(base_fnt_lst, strInt);
3056 strcat(base_fnt_lst, strchr(p + 2, '-'));
3058 if ((fntSet = XCreateFontSet(xDisplay,
3062 &def_string)) == NULL) {
3064 fprintf(stderr, _("Unable to create font set.\n"));
3068 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3070 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3072 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3073 programName, pattern);
3081 for (i=0; i<nfonts; i++) {
3084 if (*p != '-') continue;
3086 if (*p == NULLCHAR) break;
3087 if (*p++ == '-') j++;
3089 if (j < 7) continue;
3092 scalable = fonts[i];
3095 err = pxlSize - targetPxlSize;
3096 if (Abs(err) < Abs(minerr) ||
3097 (minerr > 0 && err < 0 && -err == minerr)) {
3103 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3104 /* If the error is too big and there is a scalable font,
3105 use the scalable font. */
3106 int headlen = scalableTail - scalable;
3107 p = (char *) XtMalloc(strlen(scalable) + 10);
3108 while (isdigit(*scalableTail)) scalableTail++;
3109 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3111 p = (char *) XtMalloc(strlen(best) + 2);
3112 safeStrCpy(p, best, strlen(best)+1 );
3114 if (appData.debugMode) {
3115 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3116 pattern, targetPxlSize, p);
3119 if (missing_count > 0)
3120 XFreeStringList(missing_list);
3121 XFreeFontSet(xDisplay, fntSet);
3123 XFreeFontNames(fonts);
3130 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3131 | GCBackground | GCFunction | GCPlaneMask;
3132 XGCValues gc_values;
3135 gc_values.plane_mask = AllPlanes;
3136 gc_values.line_width = lineGap;
3137 gc_values.line_style = LineSolid;
3138 gc_values.function = GXcopy;
3140 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3141 gc_values.background = XBlackPixel(xDisplay, xScreen);
3142 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3144 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3145 gc_values.background = XWhitePixel(xDisplay, xScreen);
3146 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3147 XSetFont(xDisplay, coordGC, coordFontID);
3149 // [HGM] make font for holdings counts (white on black0
3150 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3151 gc_values.background = XBlackPixel(xDisplay, xScreen);
3152 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3153 XSetFont(xDisplay, countGC, countFontID);
3155 if (appData.monoMode) {
3156 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3157 gc_values.background = XWhitePixel(xDisplay, xScreen);
3158 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3160 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3161 gc_values.background = XBlackPixel(xDisplay, xScreen);
3162 lightSquareGC = wbPieceGC
3163 = XtGetGC(shellWidget, value_mask, &gc_values);
3165 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3166 gc_values.background = XWhitePixel(xDisplay, xScreen);
3167 darkSquareGC = bwPieceGC
3168 = XtGetGC(shellWidget, value_mask, &gc_values);
3170 if (DefaultDepth(xDisplay, xScreen) == 1) {
3171 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3172 gc_values.function = GXcopyInverted;
3173 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3174 gc_values.function = GXcopy;
3175 if (XBlackPixel(xDisplay, xScreen) == 1) {
3176 bwPieceGC = darkSquareGC;
3177 wbPieceGC = copyInvertedGC;
3179 bwPieceGC = copyInvertedGC;
3180 wbPieceGC = lightSquareGC;
3184 gc_values.foreground = highlightSquareColor;
3185 gc_values.background = highlightSquareColor;
3186 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3188 gc_values.foreground = premoveHighlightColor;
3189 gc_values.background = premoveHighlightColor;
3190 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3192 gc_values.foreground = lightSquareColor;
3193 gc_values.background = darkSquareColor;
3194 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3196 gc_values.foreground = darkSquareColor;
3197 gc_values.background = lightSquareColor;
3198 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3200 gc_values.foreground = jailSquareColor;
3201 gc_values.background = jailSquareColor;
3202 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3204 gc_values.foreground = whitePieceColor;
3205 gc_values.background = darkSquareColor;
3206 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3208 gc_values.foreground = whitePieceColor;
3209 gc_values.background = lightSquareColor;
3210 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3212 gc_values.foreground = whitePieceColor;
3213 gc_values.background = jailSquareColor;
3214 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3216 gc_values.foreground = blackPieceColor;
3217 gc_values.background = darkSquareColor;
3218 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3220 gc_values.foreground = blackPieceColor;
3221 gc_values.background = lightSquareColor;
3222 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3224 gc_values.foreground = blackPieceColor;
3225 gc_values.background = jailSquareColor;
3226 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3230 void loadXIM(xim, xmask, filename, dest, mask)
3243 fp = fopen(filename, "rb");
3245 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3252 for (y=0; y<h; ++y) {
3253 for (x=0; x<h; ++x) {
3258 XPutPixel(xim, x, y, blackPieceColor);
3260 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3263 XPutPixel(xim, x, y, darkSquareColor);
3265 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3268 XPutPixel(xim, x, y, whitePieceColor);
3270 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3273 XPutPixel(xim, x, y, lightSquareColor);
3275 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3281 /* create Pixmap of piece */
3282 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3284 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3287 /* create Pixmap of clipmask
3288 Note: We assume the white/black pieces have the same
3289 outline, so we make only 6 masks. This is okay
3290 since the XPM clipmask routines do the same. */
3292 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3294 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3297 /* now create the 1-bit version */
3298 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3301 values.foreground = 1;
3302 values.background = 0;
3304 /* Don't use XtGetGC, not read only */
3305 maskGC = XCreateGC(xDisplay, *mask,
3306 GCForeground | GCBackground, &values);
3307 XCopyPlane(xDisplay, temp, *mask, maskGC,
3308 0, 0, squareSize, squareSize, 0, 0, 1);
3309 XFreePixmap(xDisplay, temp);
3314 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3316 void CreateXIMPieces()
3321 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3326 /* The XSynchronize calls were copied from CreatePieces.
3327 Not sure if needed, but can't hurt */
3328 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3331 /* temp needed by loadXIM() */
3332 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3333 0, 0, ss, ss, AllPlanes, XYPixmap);
3335 if (strlen(appData.pixmapDirectory) == 0) {
3339 if (appData.monoMode) {
3340 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3344 fprintf(stderr, _("\nLoading XIMs...\n"));
3346 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3347 fprintf(stderr, "%d", piece+1);
3348 for (kind=0; kind<4; kind++) {
3349 fprintf(stderr, ".");
3350 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3351 ExpandPathName(appData.pixmapDirectory),
3352 piece <= (int) WhiteKing ? "" : "w",
3353 pieceBitmapNames[piece],
3355 ximPieceBitmap[kind][piece] =
3356 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3357 0, 0, ss, ss, AllPlanes, XYPixmap);
3358 if (appData.debugMode)
3359 fprintf(stderr, _("(File:%s:) "), buf);
3360 loadXIM(ximPieceBitmap[kind][piece],
3362 &(xpmPieceBitmap2[kind][piece]),
3363 &(ximMaskPm2[piece]));
3364 if(piece <= (int)WhiteKing)
3365 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3367 fprintf(stderr," ");
3369 /* Load light and dark squares */
3370 /* If the LSQ and DSQ pieces don't exist, we will
3371 draw them with solid squares. */
3372 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3373 if (access(buf, 0) != 0) {
3377 fprintf(stderr, _("light square "));
3379 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3380 0, 0, ss, ss, AllPlanes, XYPixmap);
3381 if (appData.debugMode)
3382 fprintf(stderr, _("(File:%s:) "), buf);
3384 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3385 fprintf(stderr, _("dark square "));
3386 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3387 ExpandPathName(appData.pixmapDirectory), ss);
3388 if (appData.debugMode)
3389 fprintf(stderr, _("(File:%s:) "), buf);
3391 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3392 0, 0, ss, ss, AllPlanes, XYPixmap);
3393 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3394 xpmJailSquare = xpmLightSquare;
3396 fprintf(stderr, _("Done.\n"));
3398 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3402 void CreateXPMPieces()
3406 u_int ss = squareSize;
3408 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3409 XpmColorSymbol symbols[4];
3411 /* The XSynchronize calls were copied from CreatePieces.
3412 Not sure if needed, but can't hurt */
3413 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3415 /* Setup translations so piece colors match square colors */
3416 symbols[0].name = "light_piece";
3417 symbols[0].value = appData.whitePieceColor;
3418 symbols[1].name = "dark_piece";
3419 symbols[1].value = appData.blackPieceColor;
3420 symbols[2].name = "light_square";
3421 symbols[2].value = appData.lightSquareColor;
3422 symbols[3].name = "dark_square";
3423 symbols[3].value = appData.darkSquareColor;
3425 attr.valuemask = XpmColorSymbols;
3426 attr.colorsymbols = symbols;
3427 attr.numsymbols = 4;
3429 if (appData.monoMode) {
3430 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3434 if (strlen(appData.pixmapDirectory) == 0) {
3435 XpmPieces* pieces = builtInXpms;
3438 while (pieces->size != squareSize && pieces->size) pieces++;
3439 if (!pieces->size) {
3440 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3443 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3444 for (kind=0; kind<4; kind++) {
3446 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3447 pieces->xpm[piece][kind],
3448 &(xpmPieceBitmap2[kind][piece]),
3449 NULL, &attr)) != 0) {
3450 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3454 if(piece <= (int) WhiteKing)
3455 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3459 xpmJailSquare = xpmLightSquare;
3463 fprintf(stderr, _("\nLoading XPMs...\n"));
3466 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3467 fprintf(stderr, "%d ", piece+1);
3468 for (kind=0; kind<4; kind++) {
3469 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3470 ExpandPathName(appData.pixmapDirectory),
3471 piece > (int) WhiteKing ? "w" : "",
3472 pieceBitmapNames[piece],
3474 if (appData.debugMode) {
3475 fprintf(stderr, _("(File:%s:) "), buf);
3477 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3478 &(xpmPieceBitmap2[kind][piece]),
3479 NULL, &attr)) != 0) {
3480 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3481 // [HGM] missing: read of unorthodox piece failed; substitute King.
3482 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3483 ExpandPathName(appData.pixmapDirectory),
3485 if (appData.debugMode) {
3486 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3488 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3489 &(xpmPieceBitmap2[kind][piece]),
3493 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3498 if(piece <= (int) WhiteKing)
3499 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3502 /* Load light and dark squares */
3503 /* If the LSQ and DSQ pieces don't exist, we will
3504 draw them with solid squares. */
3505 fprintf(stderr, _("light square "));
3506 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3507 if (access(buf, 0) != 0) {
3511 if (appData.debugMode)
3512 fprintf(stderr, _("(File:%s:) "), buf);
3514 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3515 &xpmLightSquare, NULL, &attr)) != 0) {
3516 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3519 fprintf(stderr, _("dark square "));
3520 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3521 ExpandPathName(appData.pixmapDirectory), ss);
3522 if (appData.debugMode) {
3523 fprintf(stderr, _("(File:%s:) "), buf);
3525 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3526 &xpmDarkSquare, NULL, &attr)) != 0) {
3527 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3531 xpmJailSquare = xpmLightSquare;
3532 fprintf(stderr, _("Done.\n"));
3534 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3537 #endif /* HAVE_LIBXPM */
3540 /* No built-in bitmaps */
3545 u_int ss = squareSize;
3547 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3550 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3551 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3552 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3553 pieceBitmapNames[piece],
3554 ss, kind == SOLID ? 's' : 'o');
3555 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3556 if(piece <= (int)WhiteKing)
3557 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3561 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3565 /* With built-in bitmaps */
3568 BuiltInBits* bib = builtInBits;
3571 u_int ss = squareSize;
3573 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3576 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3578 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3579 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3580 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3581 pieceBitmapNames[piece],
3582 ss, kind == SOLID ? 's' : 'o');
3583 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3584 bib->bits[kind][piece], ss, ss);
3585 if(piece <= (int)WhiteKing)
3586 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3590 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3595 void ReadBitmap(pm, name, bits, wreq, hreq)
3598 unsigned char bits[];
3604 char msg[MSG_SIZ], fullname[MSG_SIZ];
3606 if (*appData.bitmapDirectory != NULLCHAR) {
3607 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3608 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3609 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3610 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3611 &w, &h, pm, &x_hot, &y_hot);
3612 fprintf(stderr, "load %s\n", name);
3613 if (errcode != BitmapSuccess) {
3615 case BitmapOpenFailed:
3616 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3618 case BitmapFileInvalid:
3619 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3621 case BitmapNoMemory:
3622 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3626 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3630 fprintf(stderr, _("%s: %s...using built-in\n"),
3632 } else if (w != wreq || h != hreq) {
3634 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3635 programName, fullname, w, h, wreq, hreq);
3641 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3650 if (lineGap == 0) return;
3652 /* [HR] Split this into 2 loops for non-square boards. */
3654 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3655 gridSegments[i].x1 = 0;
3656 gridSegments[i].x2 =
3657 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3658 gridSegments[i].y1 = gridSegments[i].y2
3659 = lineGap / 2 + (i * (squareSize + lineGap));
3662 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3663 gridSegments[j + i].y1 = 0;
3664 gridSegments[j + i].y2 =
3665 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3666 gridSegments[j + i].x1 = gridSegments[j + i].x2
3667 = lineGap / 2 + (j * (squareSize + lineGap));
3671 static void MenuBarSelect(w, addr, index)
3676 XtActionProc proc = (XtActionProc) addr;
3678 (proc)(NULL, NULL, NULL, NULL);
3681 void CreateMenuBarPopup(parent, name, mb)
3691 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3694 XtSetArg(args[j], XtNleftMargin, 20); j++;
3695 XtSetArg(args[j], XtNrightMargin, 20); j++;
3697 while (mi->string != NULL) {
3698 if (strcmp(mi->string, "----") == 0) {
3699 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3702 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3703 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3705 XtAddCallback(entry, XtNcallback,
3706 (XtCallbackProc) MenuBarSelect,
3707 (caddr_t) mi->proc);
3713 Widget CreateMenuBar(mb)
3717 Widget anchor, menuBar;
3719 char menuName[MSG_SIZ];
3722 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3723 XtSetArg(args[j], XtNvSpace, 0); j++;
3724 XtSetArg(args[j], XtNborderWidth, 0); j++;
3725 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3726 formWidget, args, j);
3728 while (mb->name != NULL) {
3729 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3730 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3732 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3735 shortName[0] = _(mb->name)[0];
3736 shortName[1] = NULLCHAR;
3737 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3740 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3743 XtSetArg(args[j], XtNborderWidth, 0); j++;
3744 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3746 CreateMenuBarPopup(menuBar, menuName, mb);
3752 Widget CreateButtonBar(mi)
3756 Widget button, buttonBar;
3760 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3762 XtSetArg(args[j], XtNhSpace, 0); j++;
3764 XtSetArg(args[j], XtNborderWidth, 0); j++;
3765 XtSetArg(args[j], XtNvSpace, 0); j++;
3766 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3767 formWidget, args, j);
3769 while (mi->string != NULL) {
3772 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3773 XtSetArg(args[j], XtNborderWidth, 0); j++;
3775 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3776 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3777 buttonBar, args, j);
3778 XtAddCallback(button, XtNcallback,
3779 (XtCallbackProc) MenuBarSelect,
3780 (caddr_t) mi->proc);
3787 CreatePieceMenu(name, color)
3794 ChessSquare selection;
3796 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3797 boardWidget, args, 0);
3799 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3800 String item = pieceMenuStrings[color][i];
3802 if (strcmp(item, "----") == 0) {
3803 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3806 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3807 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3809 selection = pieceMenuTranslation[color][i];
3810 XtAddCallback(entry, XtNcallback,
3811 (XtCallbackProc) PieceMenuSelect,
3812 (caddr_t) selection);
3813 if (selection == WhitePawn || selection == BlackPawn) {
3814 XtSetArg(args[0], XtNpopupOnEntry, entry);
3815 XtSetValues(menu, args, 1);
3828 ChessSquare selection;
3830 whitePieceMenu = CreatePieceMenu("menuW", 0);
3831 blackPieceMenu = CreatePieceMenu("menuB", 1);
3833 XtRegisterGrabAction(PieceMenuPopup, True,
3834 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3835 GrabModeAsync, GrabModeAsync);
3837 XtSetArg(args[0], XtNlabel, _("Drop"));
3838 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3839 boardWidget, args, 1);
3840 for (i = 0; i < DROP_MENU_SIZE; i++) {
3841 String item = dropMenuStrings[i];
3843 if (strcmp(item, "----") == 0) {
3844 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3847 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3848 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3850 selection = dropMenuTranslation[i];
3851 XtAddCallback(entry, XtNcallback,
3852 (XtCallbackProc) DropMenuSelect,
3853 (caddr_t) selection);
3858 void SetupDropMenu()
3866 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3867 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3868 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3869 dmEnables[i].piece);
3870 XtSetSensitive(entry, p != NULL || !appData.testLegality
3871 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3872 && !appData.icsActive));
3874 while (p && *p++ == dmEnables[i].piece) count++;
3875 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3877 XtSetArg(args[j], XtNlabel, label); j++;
3878 XtSetValues(entry, args, j);
3882 void PieceMenuPopup(w, event, params, num_params)
3886 Cardinal *num_params;
3888 String whichMenu; int menuNr;
3889 if (event->type == ButtonRelease)
3890 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3891 else if (event->type == ButtonPress)
3892 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3894 case 0: whichMenu = params[0]; break;
3895 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3897 case -1: if (errorUp) ErrorPopDown();
3900 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3903 static void PieceMenuSelect(w, piece, junk)
3908 if (pmFromX < 0 || pmFromY < 0) return;
3909 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3912 static void DropMenuSelect(w, piece, junk)
3917 if (pmFromX < 0 || pmFromY < 0) return;
3918 DropMenuEvent(piece, pmFromX, pmFromY);
3921 void WhiteClock(w, event, prms, nprms)
3927 if (gameMode == EditPosition || gameMode == IcsExamining) {
3928 SetWhiteToPlayEvent();
3929 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3934 void BlackClock(w, event, prms, nprms)
3940 if (gameMode == EditPosition || gameMode == IcsExamining) {
3941 SetBlackToPlayEvent();
3942 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3949 * If the user selects on a border boundary, return -1; if off the board,
3950 * return -2. Otherwise map the event coordinate to the square.
3952 int EventToSquare(x, limit)
3960 if ((x % (squareSize + lineGap)) >= squareSize)
3962 x /= (squareSize + lineGap);
3968 static void do_flash_delay(msec)
3974 static void drawHighlight(file, rank, gc)
3980 if (lineGap == 0 || appData.blindfold) return;
3983 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3984 (squareSize + lineGap);
3985 y = lineGap/2 + rank * (squareSize + lineGap);
3987 x = lineGap/2 + file * (squareSize + lineGap);
3988 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3989 (squareSize + lineGap);
3992 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3993 squareSize+lineGap, squareSize+lineGap);
3996 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3997 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4000 SetHighlights(fromX, fromY, toX, toY)
4001 int fromX, fromY, toX, toY;
4003 if (hi1X != fromX || hi1Y != fromY) {
4004 if (hi1X >= 0 && hi1Y >= 0) {
4005 drawHighlight(hi1X, hi1Y, lineGC);
4007 } // [HGM] first erase both, then draw new!
4008 if (hi2X != toX || hi2Y != toY) {
4009 if (hi2X >= 0 && hi2Y >= 0) {
4010 drawHighlight(hi2X, hi2Y, lineGC);
4013 if (hi1X != fromX || hi1Y != fromY) {
4014 if (fromX >= 0 && fromY >= 0) {
4015 drawHighlight(fromX, fromY, highlineGC);
4018 if (hi2X != toX || hi2Y != toY) {
4019 if (toX >= 0 && toY >= 0) {
4020 drawHighlight(toX, toY, highlineGC);
4032 SetHighlights(-1, -1, -1, -1);
4037 SetPremoveHighlights(fromX, fromY, toX, toY)
4038 int fromX, fromY, toX, toY;
4040 if (pm1X != fromX || pm1Y != fromY) {
4041 if (pm1X >= 0 && pm1Y >= 0) {
4042 drawHighlight(pm1X, pm1Y, lineGC);
4044 if (fromX >= 0 && fromY >= 0) {
4045 drawHighlight(fromX, fromY, prelineGC);
4048 if (pm2X != toX || pm2Y != toY) {
4049 if (pm2X >= 0 && pm2Y >= 0) {
4050 drawHighlight(pm2X, pm2Y, lineGC);
4052 if (toX >= 0 && toY >= 0) {
4053 drawHighlight(toX, toY, prelineGC);
4063 ClearPremoveHighlights()
4065 SetPremoveHighlights(-1, -1, -1, -1);
4068 static void BlankSquare(x, y, color, piece, dest)
4073 if (useImages && useImageSqs) {
4077 pm = xpmLightSquare;
4082 case 2: /* neutral */
4087 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4088 squareSize, squareSize, x, y);
4098 case 2: /* neutral */
4103 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4108 I split out the routines to draw a piece so that I could
4109 make a generic flash routine.
4111 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4113 int square_color, x, y;
4116 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4117 switch (square_color) {
4119 case 2: /* neutral */
4121 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4122 ? *pieceToOutline(piece)
4123 : *pieceToSolid(piece),
4124 dest, bwPieceGC, 0, 0,
4125 squareSize, squareSize, x, y);
4128 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4129 ? *pieceToSolid(piece)
4130 : *pieceToOutline(piece),
4131 dest, wbPieceGC, 0, 0,
4132 squareSize, squareSize, x, y);
4137 static void monoDrawPiece(piece, square_color, x, y, dest)
4139 int square_color, x, y;
4142 switch (square_color) {
4144 case 2: /* neutral */
4146 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4147 ? *pieceToOutline(piece)
4148 : *pieceToSolid(piece),
4149 dest, bwPieceGC, 0, 0,
4150 squareSize, squareSize, x, y, 1);
4153 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4154 ? *pieceToSolid(piece)
4155 : *pieceToOutline(piece),
4156 dest, wbPieceGC, 0, 0,
4157 squareSize, squareSize, x, y, 1);
4162 static void colorDrawPiece(piece, square_color, x, y, dest)
4164 int square_color, x, y;
4167 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4168 switch (square_color) {
4170 XCopyPlane(xDisplay, *pieceToSolid(piece),
4171 dest, (int) piece < (int) BlackPawn
4172 ? wlPieceGC : blPieceGC, 0, 0,
4173 squareSize, squareSize, x, y, 1);
4176 XCopyPlane(xDisplay, *pieceToSolid(piece),
4177 dest, (int) piece < (int) BlackPawn
4178 ? wdPieceGC : bdPieceGC, 0, 0,
4179 squareSize, squareSize, x, y, 1);
4181 case 2: /* neutral */
4183 XCopyPlane(xDisplay, *pieceToSolid(piece),
4184 dest, (int) piece < (int) BlackPawn
4185 ? wjPieceGC : bjPieceGC, 0, 0,
4186 squareSize, squareSize, x, y, 1);
4191 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4193 int square_color, x, y;
4198 switch (square_color) {
4200 case 2: /* neutral */
4202 if ((int)piece < (int) BlackPawn) {
4210 if ((int)piece < (int) BlackPawn) {
4218 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4219 dest, wlPieceGC, 0, 0,
4220 squareSize, squareSize, x, y);
4223 typedef void (*DrawFunc)();
4225 DrawFunc ChooseDrawFunc()
4227 if (appData.monoMode) {
4228 if (DefaultDepth(xDisplay, xScreen) == 1) {
4229 return monoDrawPiece_1bit;
4231 return monoDrawPiece;
4235 return colorDrawPieceImage;
4237 return colorDrawPiece;
4241 /* [HR] determine square color depending on chess variant. */
4242 static int SquareColor(row, column)
4247 if (gameInfo.variant == VariantXiangqi) {
4248 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4250 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4252 } else if (row <= 4) {
4258 square_color = ((column + row) % 2) == 1;
4261 /* [hgm] holdings: next line makes all holdings squares light */
4262 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4264 return square_color;
4267 void DrawSquare(row, column, piece, do_flash)
4268 int row, column, do_flash;
4271 int square_color, x, y, direction, font_ascent, font_descent;
4274 XCharStruct overall;
4278 /* Calculate delay in milliseconds (2-delays per complete flash) */
4279 flash_delay = 500 / appData.flashRate;
4282 x = lineGap + ((BOARD_WIDTH-1)-column) *
4283 (squareSize + lineGap);
4284 y = lineGap + row * (squareSize + lineGap);
4286 x = lineGap + column * (squareSize + lineGap);
4287 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4288 (squareSize + lineGap);
4291 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4293 square_color = SquareColor(row, column);
4295 if ( // [HGM] holdings: blank out area between board and holdings
4296 column == BOARD_LEFT-1 || column == BOARD_RGHT
4297 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4298 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4299 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4301 // [HGM] print piece counts next to holdings
4302 string[1] = NULLCHAR;
4303 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4304 string[0] = '0' + piece;
4305 XTextExtents(countFontStruct, string, 1, &direction,
4306 &font_ascent, &font_descent, &overall);
4307 if (appData.monoMode) {
4308 XDrawImageString(xDisplay, xBoardWindow, countGC,
4309 x + squareSize - overall.width - 2,
4310 y + font_ascent + 1, string, 1);
4312 XDrawString(xDisplay, xBoardWindow, countGC,
4313 x + squareSize - overall.width - 2,
4314 y + font_ascent + 1, string, 1);
4317 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4318 string[0] = '0' + piece;
4319 XTextExtents(countFontStruct, string, 1, &direction,
4320 &font_ascent, &font_descent, &overall);
4321 if (appData.monoMode) {
4322 XDrawImageString(xDisplay, xBoardWindow, countGC,
4323 x + 2, y + font_ascent + 1, string, 1);
4325 XDrawString(xDisplay, xBoardWindow, countGC,
4326 x + 2, y + font_ascent + 1, string, 1);
4330 if (piece == EmptySquare || appData.blindfold) {
4331 BlankSquare(x, y, square_color, piece, xBoardWindow);
4333 drawfunc = ChooseDrawFunc();
4334 if (do_flash && appData.flashCount > 0) {
4335 for (i=0; i<appData.flashCount; ++i) {
4337 drawfunc(piece, square_color, x, y, xBoardWindow);
4338 XSync(xDisplay, False);
4339 do_flash_delay(flash_delay);
4341 BlankSquare(x, y, square_color, piece, xBoardWindow);
4342 XSync(xDisplay, False);
4343 do_flash_delay(flash_delay);
4346 drawfunc(piece, square_color, x, y, xBoardWindow);
4350 string[1] = NULLCHAR;
4351 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4352 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4353 string[0] = 'a' + column - BOARD_LEFT;
4354 XTextExtents(coordFontStruct, string, 1, &direction,
4355 &font_ascent, &font_descent, &overall);
4356 if (appData.monoMode) {
4357 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4358 x + squareSize - overall.width - 2,
4359 y + squareSize - font_descent - 1, string, 1);
4361 XDrawString(xDisplay, xBoardWindow, coordGC,
4362 x + squareSize - overall.width - 2,
4363 y + squareSize - font_descent - 1, string, 1);
4366 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4367 string[0] = ONE + row;
4368 XTextExtents(coordFontStruct, string, 1, &direction,
4369 &font_ascent, &font_descent, &overall);
4370 if (appData.monoMode) {
4371 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4372 x + 2, y + font_ascent + 1, string, 1);
4374 XDrawString(xDisplay, xBoardWindow, coordGC,
4375 x + 2, y + font_ascent + 1, string, 1);
4378 if(!partnerUp && marker[row][column]) {
4379 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4380 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4385 /* Why is this needed on some versions of X? */
4386 void EventProc(widget, unused, event)
4391 if (!XtIsRealized(widget))
4394 switch (event->type) {
4396 if (event->xexpose.count > 0) return; /* no clipping is done */
4397 XDrawPosition(widget, True, NULL);
4398 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4399 flipView = !flipView; partnerUp = !partnerUp;
4400 XDrawPosition(widget, True, NULL);
4401 flipView = !flipView; partnerUp = !partnerUp;
4405 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4412 void DrawPosition(fullRedraw, board)
4413 /*Boolean*/int fullRedraw;
4416 XDrawPosition(boardWidget, fullRedraw, board);
4419 /* Returns 1 if there are "too many" differences between b1 and b2
4420 (i.e. more than 1 move was made) */
4421 static int too_many_diffs(b1, b2)
4427 for (i=0; i<BOARD_HEIGHT; ++i) {
4428 for (j=0; j<BOARD_WIDTH; ++j) {
4429 if (b1[i][j] != b2[i][j]) {
4430 if (++c > 4) /* Castling causes 4 diffs */
4439 /* Matrix describing castling maneuvers */
4440 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4441 static int castling_matrix[4][5] = {
4442 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4443 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4444 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4445 { 7, 7, 4, 5, 6 } /* 0-0, black */
4448 /* Checks whether castling occurred. If it did, *rrow and *rcol
4449 are set to the destination (row,col) of the rook that moved.
4451 Returns 1 if castling occurred, 0 if not.
4453 Note: Only handles a max of 1 castling move, so be sure
4454 to call too_many_diffs() first.
4456 static int check_castle_draw(newb, oldb, rrow, rcol)
4463 /* For each type of castling... */
4464 for (i=0; i<4; ++i) {
4465 r = castling_matrix[i];
4467 /* Check the 4 squares involved in the castling move */
4469 for (j=1; j<=4; ++j) {
4470 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4477 /* All 4 changed, so it must be a castling move */
4486 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4487 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4489 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4492 void DrawSeekBackground( int left, int top, int right, int bottom )
4494 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4497 void DrawSeekText(char *buf, int x, int y)
4499 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4502 void DrawSeekDot(int x, int y, int colorNr)
4504 int square = colorNr & 0x80;
4507 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4509 XFillRectangle(xDisplay, xBoardWindow, color,
4510 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4512 XFillArc(xDisplay, xBoardWindow, color,
4513 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4516 static int damage[2][BOARD_RANKS][BOARD_FILES];
4519 * event handler for redrawing the board
4521 void XDrawPosition(w, repaint, board)
4523 /*Boolean*/int repaint;
4527 static int lastFlipView = 0;
4528 static int lastBoardValid[2] = {0, 0};
4529 static Board lastBoard[2];
4532 int nr = twoBoards*partnerUp;
4534 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4536 if (board == NULL) {
4537 if (!lastBoardValid[nr]) return;
4538 board = lastBoard[nr];
4540 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4541 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4542 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4547 * It would be simpler to clear the window with XClearWindow()
4548 * but this causes a very distracting flicker.
4551 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4553 /* If too much changes (begin observing new game, etc.), don't
4555 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4557 /* Special check for castling so we don't flash both the king
4558 and the rook (just flash the king). */
4560 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4561 /* Draw rook with NO flashing. King will be drawn flashing later */
4562 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4563 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4567 /* First pass -- Draw (newly) empty squares and repair damage.
4568 This prevents you from having a piece show up twice while it
4569 is flashing on its new square */
4570 for (i = 0; i < BOARD_HEIGHT; i++)
4571 for (j = 0; j < BOARD_WIDTH; j++)
4572 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4573 || damage[nr][i][j]) {
4574 DrawSquare(i, j, board[i][j], 0);
4575 damage[nr][i][j] = False;
4578 /* Second pass -- Draw piece(s) in new position and flash them */
4579 for (i = 0; i < BOARD_HEIGHT; i++)
4580 for (j = 0; j < BOARD_WIDTH; j++)
4581 if (board[i][j] != lastBoard[nr][i][j]) {
4582 DrawSquare(i, j, board[i][j], do_flash);
4586 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4587 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4588 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4590 for (i = 0; i < BOARD_HEIGHT; i++)
4591 for (j = 0; j < BOARD_WIDTH; j++) {
4592 DrawSquare(i, j, board[i][j], 0);
4593 damage[nr][i][j] = False;
4597 CopyBoard(lastBoard[nr], board);
4598 lastBoardValid[nr] = 1;
4599 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4600 lastFlipView = flipView;
4602 /* Draw highlights */
4603 if (pm1X >= 0 && pm1Y >= 0) {
4604 drawHighlight(pm1X, pm1Y, prelineGC);
4606 if (pm2X >= 0 && pm2Y >= 0) {
4607 drawHighlight(pm2X, pm2Y, prelineGC);
4609 if (hi1X >= 0 && hi1Y >= 0) {
4610 drawHighlight(hi1X, hi1Y, highlineGC);
4612 if (hi2X >= 0 && hi2Y >= 0) {
4613 drawHighlight(hi2X, hi2Y, highlineGC);
4616 /* If piece being dragged around board, must redraw that too */
4619 XSync(xDisplay, False);
4624 * event handler for redrawing the board
4626 void DrawPositionProc(w, event, prms, nprms)
4632 XDrawPosition(w, True, NULL);
4637 * event handler for parsing user moves
4639 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4640 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4641 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4642 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4643 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4644 // and at the end FinishMove() to perform the move after optional promotion popups.
4645 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4646 void HandleUserMove(w, event, prms, nprms)
4652 if (w != boardWidget || errorExitStatus != -1) return;
4655 if (event->type == ButtonPress) {
4656 XtPopdown(promotionShell);
4657 XtDestroyWidget(promotionShell);
4658 promotionUp = False;
4666 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4667 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4668 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4671 void AnimateUserMove (Widget w, XEvent * event,
4672 String * params, Cardinal * nParams)
4674 DragPieceMove(event->xmotion.x, event->xmotion.y);
4677 void HandlePV (Widget w, XEvent * event,
4678 String * params, Cardinal * nParams)
4679 { // [HGM] pv: walk PV
4680 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4683 Widget CommentCreate(name, text, mutable, callback, lines)
4685 int /*Boolean*/ mutable;
4686 XtCallbackProc callback;
4690 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4695 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4696 XtGetValues(boardWidget, args, j);
4699 XtSetArg(args[j], XtNresizable, True); j++;
4702 XtCreatePopupShell(name, topLevelShellWidgetClass,
4703 shellWidget, args, j);
4706 XtCreatePopupShell(name, transientShellWidgetClass,
4707 shellWidget, args, j);
4710 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4711 layoutArgs, XtNumber(layoutArgs));
4713 XtCreateManagedWidget("form", formWidgetClass, layout,
4714 formArgs, XtNumber(formArgs));
4718 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4719 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4721 XtSetArg(args[j], XtNstring, text); j++;
4722 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4723 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4724 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4725 XtSetArg(args[j], XtNright, XtChainRight); j++;
4726 XtSetArg(args[j], XtNresizable, True); j++;
4727 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4728 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4729 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4730 XtSetArg(args[j], XtNautoFill, True); j++;
4731 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4733 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4734 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4738 XtSetArg(args[j], XtNfromVert, edit); j++;
4739 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4740 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4741 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4742 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4744 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4745 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4748 XtSetArg(args[j], XtNfromVert, edit); j++;
4749 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4750 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4751 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4752 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4753 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4755 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4756 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4759 XtSetArg(args[j], XtNfromVert, edit); j++;
4760 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4761 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4762 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4763 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4764 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4766 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4767 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4770 XtSetArg(args[j], XtNfromVert, edit); j++;
4771 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4772 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4773 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4774 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4776 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4777 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4780 XtSetArg(args[j], XtNfromVert, edit); j++;
4781 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4782 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4783 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4784 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4785 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4787 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4788 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4791 XtRealizeWidget(shell);
4793 if (commentX == -1) {
4796 Dimension pw_height;
4797 Dimension ew_height;
4800 XtSetArg(args[j], XtNheight, &ew_height); j++;
4801 XtGetValues(edit, args, j);
4804 XtSetArg(args[j], XtNheight, &pw_height); j++;
4805 XtGetValues(shell, args, j);
4806 commentH = pw_height + (lines - 1) * ew_height;
4807 commentW = bw_width - 16;
4809 XSync(xDisplay, False);
4811 /* This code seems to tickle an X bug if it is executed too soon
4812 after xboard starts up. The coordinates get transformed as if
4813 the main window was positioned at (0, 0).
4815 XtTranslateCoords(shellWidget,
4816 (bw_width - commentW) / 2, 0 - commentH / 2,
4817 &commentX, &commentY);
4819 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4820 RootWindowOfScreen(XtScreen(shellWidget)),
4821 (bw_width - commentW) / 2, 0 - commentH / 2,
4826 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4829 if(wpComment.width > 0) {
4830 commentX = wpComment.x;
4831 commentY = wpComment.y;
4832 commentW = wpComment.width;
4833 commentH = wpComment.height;
4837 XtSetArg(args[j], XtNheight, commentH); j++;
4838 XtSetArg(args[j], XtNwidth, commentW); j++;
4839 XtSetArg(args[j], XtNx, commentX); j++;
4840 XtSetArg(args[j], XtNy, commentY); j++;
4841 XtSetValues(shell, args, j);
4842 XtSetKeyboardFocus(shell, edit);
4847 /* Used for analysis window and ICS input window */
4848 Widget MiscCreate(name, text, mutable, callback, lines)
4850 int /*Boolean*/ mutable;
4851 XtCallbackProc callback;
4855 Widget shell, layout, form, edit;
4857 Dimension bw_width, pw_height, ew_height, w, h;
4863 XtSetArg(args[j], XtNresizable, True); j++;
4866 XtCreatePopupShell(name, topLevelShellWidgetClass,
4867 shellWidget, args, j);
4870 XtCreatePopupShell(name, transientShellWidgetClass,
4871 shellWidget, args, j);
4874 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4875 layoutArgs, XtNumber(layoutArgs));
4877 XtCreateManagedWidget("form", formWidgetClass, layout,
4878 formArgs, XtNumber(formArgs));
4882 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4883 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4885 XtSetArg(args[j], XtNstring, text); j++;
4886 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4887 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4888 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4889 XtSetArg(args[j], XtNright, XtChainRight); j++;
4890 XtSetArg(args[j], XtNresizable, True); j++;
4891 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4892 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4893 XtSetArg(args[j], XtNautoFill, True); j++;
4894 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4896 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4898 XtRealizeWidget(shell);
4901 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4902 XtGetValues(boardWidget, args, j);
4905 XtSetArg(args[j], XtNheight, &ew_height); j++;
4906 XtGetValues(edit, args, j);
4909 XtSetArg(args[j], XtNheight, &pw_height); j++;
4910 XtGetValues(shell, args, j);
4911 h = pw_height + (lines - 1) * ew_height;
4914 XSync(xDisplay, False);
4916 /* This code seems to tickle an X bug if it is executed too soon
4917 after xboard starts up. The coordinates get transformed as if
4918 the main window was positioned at (0, 0).
4920 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4922 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4923 RootWindowOfScreen(XtScreen(shellWidget)),
4924 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4928 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4931 XtSetArg(args[j], XtNheight, h); j++;
4932 XtSetArg(args[j], XtNwidth, w); j++;
4933 XtSetArg(args[j], XtNx, x); j++;
4934 XtSetArg(args[j], XtNy, y); j++;
4935 XtSetValues(shell, args, j);
4941 static int savedIndex; /* gross that this is global */
4943 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4946 XawTextPosition index, dummy;
4949 XawTextGetSelectionPos(w, &index, &dummy);
4950 XtSetArg(arg, XtNstring, &val);
4951 XtGetValues(w, &arg, 1);
4952 ReplaceComment(savedIndex, val);
4953 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4954 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4957 void EditCommentPopUp(index, title, text)
4966 if (text == NULL) text = "";
4968 if (editShell == NULL) {
4970 CommentCreate(title, text, True, EditCommentCallback, 4);
4971 XtRealizeWidget(editShell);
4972 CatchDeleteWindow(editShell, "EditCommentPopDown");
4974 edit = XtNameToWidget(editShell, "*form.text");
4976 XtSetArg(args[j], XtNstring, text); j++;
4977 XtSetValues(edit, args, j);
4979 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4980 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4981 XtSetValues(editShell, args, j);
4984 XtPopup(editShell, XtGrabNone);
4988 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4989 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4993 void EditCommentCallback(w, client_data, call_data)
4995 XtPointer client_data, call_data;
5003 XtSetArg(args[j], XtNlabel, &name); j++;
5004 XtGetValues(w, args, j);
5006 if (strcmp(name, _("ok")) == 0) {
5007 edit = XtNameToWidget(editShell, "*form.text");
5009 XtSetArg(args[j], XtNstring, &val); j++;
5010 XtGetValues(edit, args, j);
5011 ReplaceComment(savedIndex, val);
5012 EditCommentPopDown();
5013 } else if (strcmp(name, _("cancel")) == 0) {
5014 EditCommentPopDown();
5015 } else if (strcmp(name, _("clear")) == 0) {
5016 edit = XtNameToWidget(editShell, "*form.text");
5017 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5018 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5022 void EditCommentPopDown()
5027 if (!editUp) return;
5029 XtSetArg(args[j], XtNx, &commentX); j++;
5030 XtSetArg(args[j], XtNy, &commentY); j++;
5031 XtSetArg(args[j], XtNheight, &commentH); j++;
5032 XtSetArg(args[j], XtNwidth, &commentW); j++;
5033 XtGetValues(editShell, args, j);
5034 XtPopdown(editShell);
5037 XtSetArg(args[j], XtNleftBitmap, None); j++;
5038 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5042 void ICSInputBoxPopUp()
5047 char *title = _("ICS Input");
5050 if (ICSInputShell == NULL) {
5051 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5052 tr = XtParseTranslationTable(ICSInputTranslations);
5053 edit = XtNameToWidget(ICSInputShell, "*form.text");
5054 XtOverrideTranslations(edit, tr);
5055 XtRealizeWidget(ICSInputShell);
5056 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5059 edit = XtNameToWidget(ICSInputShell, "*form.text");
5061 XtSetArg(args[j], XtNstring, ""); j++;
5062 XtSetValues(edit, args, j);
5064 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5065 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5066 XtSetValues(ICSInputShell, args, j);
5069 XtPopup(ICSInputShell, XtGrabNone);
5070 XtSetKeyboardFocus(ICSInputShell, edit);
5072 ICSInputBoxUp = True;
5074 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5075 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5079 void ICSInputSendText()
5086 edit = XtNameToWidget(ICSInputShell, "*form.text");
5088 XtSetArg(args[j], XtNstring, &val); j++;
5089 XtGetValues(edit, args, j);
5091 SendMultiLineToICS(val);
5092 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5093 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5096 void ICSInputBoxPopDown()
5101 if (!ICSInputBoxUp) return;
5103 XtPopdown(ICSInputShell);
5104 ICSInputBoxUp = False;
5106 XtSetArg(args[j], XtNleftBitmap, None); j++;
5107 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5111 void CommentPopUp(title, text)
5118 savedIndex = currentMove; // [HGM] vari
5119 if (commentShell == NULL) {
5121 CommentCreate(title, text, False, CommentCallback, 4);
5122 XtRealizeWidget(commentShell);
5123 CatchDeleteWindow(commentShell, "CommentPopDown");
5125 edit = XtNameToWidget(commentShell, "*form.text");
5127 XtSetArg(args[j], XtNstring, text); j++;
5128 XtSetValues(edit, args, j);
5130 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5131 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5132 XtSetValues(commentShell, args, j);
5135 XtPopup(commentShell, XtGrabNone);
5136 XSync(xDisplay, False);
5141 void CommentCallback(w, client_data, call_data)
5143 XtPointer client_data, call_data;
5150 XtSetArg(args[j], XtNlabel, &name); j++;
5151 XtGetValues(w, args, j);
5153 if (strcmp(name, _("close")) == 0) {
5155 } else if (strcmp(name, _("edit")) == 0) {
5162 void CommentPopDown()
5167 if (!commentUp) return;
5169 XtSetArg(args[j], XtNx, &commentX); j++;
5170 XtSetArg(args[j], XtNy, &commentY); j++;
5171 XtSetArg(args[j], XtNwidth, &commentW); j++;
5172 XtSetArg(args[j], XtNheight, &commentH); j++;
5173 XtGetValues(commentShell, args, j);
5174 XtPopdown(commentShell);
5175 XSync(xDisplay, False);
5179 void FileNamePopUp(label, def, proc, openMode)
5185 fileProc = proc; /* I can't see a way not */
5186 fileOpenMode = openMode; /* to use globals here */
5187 { // [HGM] use file-selector dialog stolen from Ghostview
5189 int index; // this is not supported yet
5191 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5192 def, openMode, NULL, &name))
5193 (void) (*fileProc)(f, index=0, name);
5197 void FileNamePopDown()
5199 if (!filenameUp) return;
5200 XtPopdown(fileNameShell);
5201 XtDestroyWidget(fileNameShell);
5206 void FileNameCallback(w, client_data, call_data)
5208 XtPointer client_data, call_data;
5213 XtSetArg(args[0], XtNlabel, &name);
5214 XtGetValues(w, args, 1);
5216 if (strcmp(name, _("cancel")) == 0) {
5221 FileNameAction(w, NULL, NULL, NULL);
5224 void FileNameAction(w, event, prms, nprms)
5236 name = XawDialogGetValueString(w = XtParent(w));
5238 if ((name != NULL) && (*name != NULLCHAR)) {
5239 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5240 XtPopdown(w = XtParent(XtParent(w)));
5244 p = strrchr(buf, ' ');
5251 fullname = ExpandPathName(buf);
5253 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5256 f = fopen(fullname, fileOpenMode);
5258 DisplayError(_("Failed to open file"), errno);
5260 (void) (*fileProc)(f, index, buf);
5267 XtPopdown(w = XtParent(XtParent(w)));
5273 void PromotionPopUp()
5276 Widget dialog, layout;
5278 Dimension bw_width, pw_width;
5282 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5283 XtGetValues(boardWidget, args, j);
5286 XtSetArg(args[j], XtNresizable, True); j++;
5287 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5289 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5290 shellWidget, args, j);
5292 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5293 layoutArgs, XtNumber(layoutArgs));
5296 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5297 XtSetArg(args[j], XtNborderWidth, 0); j++;
5298 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5301 if(gameInfo.variant != VariantShogi) {
5302 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5303 (XtPointer) dialog);
5304 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5305 (XtPointer) dialog);
5306 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5307 (XtPointer) dialog);
5308 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5309 (XtPointer) dialog);
5310 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5311 gameInfo.variant == VariantGiveaway) {
5312 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5313 (XtPointer) dialog);
5315 if(gameInfo.variant == VariantCapablanca ||
5316 gameInfo.variant == VariantGothic ||
5317 gameInfo.variant == VariantCapaRandom) {
5318 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5319 (XtPointer) dialog);
5320 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5321 (XtPointer) dialog);
5323 } else // [HGM] shogi
5325 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5326 (XtPointer) dialog);
5327 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5328 (XtPointer) dialog);
5330 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5331 (XtPointer) dialog);
5333 XtRealizeWidget(promotionShell);
5334 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5337 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5338 XtGetValues(promotionShell, args, j);
5340 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5341 lineGap + squareSize/3 +
5342 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5343 0 : 6*(squareSize + lineGap)), &x, &y);
5346 XtSetArg(args[j], XtNx, x); j++;
5347 XtSetArg(args[j], XtNy, y); j++;
5348 XtSetValues(promotionShell, args, j);
5350 XtPopup(promotionShell, XtGrabNone);
5355 void PromotionPopDown()
5357 if (!promotionUp) return;
5358 XtPopdown(promotionShell);
5359 XtDestroyWidget(promotionShell);
5360 promotionUp = False;
5363 void PromotionCallback(w, client_data, call_data)
5365 XtPointer client_data, call_data;
5371 XtSetArg(args[0], XtNlabel, &name);
5372 XtGetValues(w, args, 1);
5376 if (fromX == -1) return;
5378 if (strcmp(name, _("cancel")) == 0) {
5382 } else if (strcmp(name, _("Knight")) == 0) {
5384 } else if (strcmp(name, _("Promote")) == 0) {
5386 } else if (strcmp(name, _("Defer")) == 0) {
5389 promoChar = ToLower(name[0]);
5392 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5394 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5395 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5400 void ErrorCallback(w, client_data, call_data)
5402 XtPointer client_data, call_data;
5405 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5407 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5413 if (!errorUp) return;
5415 XtPopdown(errorShell);
5416 XtDestroyWidget(errorShell);
5417 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5420 void ErrorPopUp(title, label, modal)
5421 char *title, *label;
5425 Widget dialog, layout;
5429 Dimension bw_width, pw_width;
5430 Dimension pw_height;
5434 XtSetArg(args[i], XtNresizable, True); i++;
5435 XtSetArg(args[i], XtNtitle, title); i++;
5437 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5438 shellWidget, args, i);
5440 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5441 layoutArgs, XtNumber(layoutArgs));
5444 XtSetArg(args[i], XtNlabel, label); i++;
5445 XtSetArg(args[i], XtNborderWidth, 0); i++;
5446 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5449 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5451 XtRealizeWidget(errorShell);
5452 CatchDeleteWindow(errorShell, "ErrorPopDown");
5455 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5456 XtGetValues(boardWidget, args, i);
5458 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5459 XtSetArg(args[i], XtNheight, &pw_height); i++;
5460 XtGetValues(errorShell, args, i);
5463 /* This code seems to tickle an X bug if it is executed too soon
5464 after xboard starts up. The coordinates get transformed as if
5465 the main window was positioned at (0, 0).
5467 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5468 0 - pw_height + squareSize / 3, &x, &y);
5470 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5471 RootWindowOfScreen(XtScreen(boardWidget)),
5472 (bw_width - pw_width) / 2,
5473 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5477 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5480 XtSetArg(args[i], XtNx, x); i++;
5481 XtSetArg(args[i], XtNy, y); i++;
5482 XtSetValues(errorShell, args, i);
5485 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5488 /* Disable all user input other than deleting the window */
5489 static int frozen = 0;
5493 /* Grab by a widget that doesn't accept input */
5494 XtAddGrab(messageWidget, TRUE, FALSE);
5498 /* Undo a FreezeUI */
5501 if (!frozen) return;
5502 XtRemoveGrab(messageWidget);
5506 char *ModeToWidgetName(mode)
5510 case BeginningOfGame:
5511 if (appData.icsActive)
5512 return "menuMode.ICS Client";
5513 else if (appData.noChessProgram ||
5514 *appData.cmailGameName != NULLCHAR)
5515 return "menuMode.Edit Game";
5517 return "menuMode.Machine Black";
5518 case MachinePlaysBlack:
5519 return "menuMode.Machine Black";
5520 case MachinePlaysWhite:
5521 return "menuMode.Machine White";
5523 return "menuMode.Analysis Mode";
5525 return "menuMode.Analyze File";
5526 case TwoMachinesPlay:
5527 return "menuMode.Two Machines";
5529 return "menuMode.Edit Game";
5530 case PlayFromGameFile:
5531 return "menuFile.Load Game";
5533 return "menuMode.Edit Position";
5535 return "menuMode.Training";
5536 case IcsPlayingWhite:
5537 case IcsPlayingBlack:
5541 return "menuMode.ICS Client";
5548 void ModeHighlight()
5551 static int oldPausing = FALSE;
5552 static GameMode oldmode = (GameMode) -1;
5555 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5557 if (pausing != oldPausing) {
5558 oldPausing = pausing;
5560 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5562 XtSetArg(args[0], XtNleftBitmap, None);
5564 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5567 if (appData.showButtonBar) {
5568 /* Always toggle, don't set. Previous code messes up when
5569 invoked while the button is pressed, as releasing it
5570 toggles the state again. */
5573 XtSetArg(args[0], XtNbackground, &oldbg);
5574 XtSetArg(args[1], XtNforeground, &oldfg);
5575 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5577 XtSetArg(args[0], XtNbackground, oldfg);
5578 XtSetArg(args[1], XtNforeground, oldbg);
5580 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5584 wname = ModeToWidgetName(oldmode);
5585 if (wname != NULL) {
5586 XtSetArg(args[0], XtNleftBitmap, None);
5587 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5589 wname = ModeToWidgetName(gameMode);
5590 if (wname != NULL) {
5591 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5592 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5596 /* Maybe all the enables should be handled here, not just this one */
5597 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5598 gameMode == Training || gameMode == PlayFromGameFile);
5603 * Button/menu procedures
5605 void ResetProc(w, event, prms, nprms)
5614 int LoadGamePopUp(f, gameNumber, title)
5619 cmailMsgLoaded = FALSE;
5620 if (gameNumber == 0) {
5621 int error = GameListBuild(f);
5623 DisplayError(_("Cannot build game list"), error);
5624 } else if (!ListEmpty(&gameList) &&
5625 ((ListGame *) gameList.tailPred)->number > 1) {
5626 GameListPopUp(f, title);
5632 return LoadGame(f, gameNumber, title, FALSE);
5635 void LoadGameProc(w, event, prms, nprms)
5641 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5644 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5647 void LoadNextGameProc(w, event, prms, nprms)
5656 void LoadPrevGameProc(w, event, prms, nprms)
5665 void ReloadGameProc(w, event, prms, nprms)
5674 void LoadNextPositionProc(w, event, prms, nprms)
5683 void LoadPrevPositionProc(w, event, prms, nprms)
5692 void ReloadPositionProc(w, event, prms, nprms)
5701 void LoadPositionProc(w, event, prms, nprms)
5707 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5710 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5713 void SaveGameProc(w, event, prms, nprms)
5719 FileNamePopUp(_("Save game file name?"),
5720 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5724 void SavePositionProc(w, event, prms, nprms)
5730 FileNamePopUp(_("Save position file name?"),
5731 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5735 void ReloadCmailMsgProc(w, event, prms, nprms)
5741 ReloadCmailMsgEvent(FALSE);
5744 void MailMoveProc(w, event, prms, nprms)
5753 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5754 char *selected_fen_position=NULL;
5757 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5758 Atom *type_return, XtPointer *value_return,
5759 unsigned long *length_return, int *format_return)
5761 char *selection_tmp;
5763 if (!selected_fen_position) return False; /* should never happen */
5764 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5765 /* note: since no XtSelectionDoneProc was registered, Xt will
5766 * automatically call XtFree on the value returned. So have to
5767 * make a copy of it allocated with XtMalloc */
5768 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5769 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5771 *value_return=selection_tmp;
5772 *length_return=strlen(selection_tmp);
5773 *type_return=*target;
5774 *format_return = 8; /* bits per byte */
5776 } else if (*target == XA_TARGETS(xDisplay)) {
5777 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5778 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5779 targets_tmp[1] = XA_STRING;
5780 *value_return = targets_tmp;
5781 *type_return = XA_ATOM;
5783 *format_return = 8 * sizeof(Atom);
5784 if (*format_return > 32) {
5785 *length_return *= *format_return / 32;
5786 *format_return = 32;
5794 /* note: when called from menu all parameters are NULL, so no clue what the
5795 * Widget which was clicked on was, or what the click event was
5797 void CopyPositionProc(w, event, prms, nprms)
5804 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5805 * have a notion of a position that is selected but not copied.
5806 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5808 if(gameMode == EditPosition) EditPositionDone(TRUE);
5809 if (selected_fen_position) free(selected_fen_position);
5810 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5811 if (!selected_fen_position) return;
5812 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5814 SendPositionSelection,
5815 NULL/* lose_ownership_proc */ ,
5816 NULL/* transfer_done_proc */);
5817 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5819 SendPositionSelection,
5820 NULL/* lose_ownership_proc */ ,
5821 NULL/* transfer_done_proc */);
5824 /* function called when the data to Paste is ready */
5826 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5827 Atom *type, XtPointer value, unsigned long *len, int *format)
5830 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5831 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5832 EditPositionPasteFEN(fenstr);
5836 /* called when Paste Position button is pressed,
5837 * all parameters will be NULL */
5838 void PastePositionProc(w, event, prms, nprms)
5844 XtGetSelectionValue(menuBarWidget,
5845 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5846 /* (XtSelectionCallbackProc) */ PastePositionCB,
5847 NULL, /* client_data passed to PastePositionCB */
5849 /* better to use the time field from the event that triggered the
5850 * call to this function, but that isn't trivial to get
5858 SendGameSelection(Widget w, Atom *selection, Atom *target,
5859 Atom *type_return, XtPointer *value_return,
5860 unsigned long *length_return, int *format_return)
5862 char *selection_tmp;
5864 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5865 FILE* f = fopen(gameCopyFilename, "r");
5868 if (f == NULL) return False;
5872 selection_tmp = XtMalloc(len + 1);
5873 count = fread(selection_tmp, 1, len, f);
5875 XtFree(selection_tmp);
5878 selection_tmp[len] = NULLCHAR;
5879 *value_return = selection_tmp;
5880 *length_return = len;
5881 *type_return = *target;
5882 *format_return = 8; /* bits per byte */
5884 } else if (*target == XA_TARGETS(xDisplay)) {
5885 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5886 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5887 targets_tmp[1] = XA_STRING;
5888 *value_return = targets_tmp;
5889 *type_return = XA_ATOM;
5891 *format_return = 8 * sizeof(Atom);
5892 if (*format_return > 32) {
5893 *length_return *= *format_return / 32;
5894 *format_return = 32;
5902 /* note: when called from menu all parameters are NULL, so no clue what the
5903 * Widget which was clicked on was, or what the click event was
5905 void CopyGameProc(w, event, prms, nprms)
5913 ret = SaveGameToFile(gameCopyFilename, FALSE);
5917 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5918 * have a notion of a game that is selected but not copied.
5919 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5921 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5924 NULL/* lose_ownership_proc */ ,
5925 NULL/* transfer_done_proc */);
5926 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5929 NULL/* lose_ownership_proc */ ,
5930 NULL/* transfer_done_proc */);
5933 /* function called when the data to Paste is ready */
5935 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5936 Atom *type, XtPointer value, unsigned long *len, int *format)
5939 if (value == NULL || *len == 0) {
5940 return; /* nothing had been selected to copy */
5942 f = fopen(gamePasteFilename, "w");
5944 DisplayError(_("Can't open temp file"), errno);
5947 fwrite(value, 1, *len, f);
5950 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5953 /* called when Paste Game button is pressed,
5954 * all parameters will be NULL */
5955 void PasteGameProc(w, event, prms, nprms)
5961 XtGetSelectionValue(menuBarWidget,
5962 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5963 /* (XtSelectionCallbackProc) */ PasteGameCB,
5964 NULL, /* client_data passed to PasteGameCB */
5966 /* better to use the time field from the event that triggered the
5967 * call to this function, but that isn't trivial to get
5977 SaveGameProc(NULL, NULL, NULL, NULL);
5981 void QuitProc(w, event, prms, nprms)
5990 void PauseProc(w, event, prms, nprms)
6000 void MachineBlackProc(w, event, prms, nprms)
6006 MachineBlackEvent();
6009 void MachineWhiteProc(w, event, prms, nprms)
6015 MachineWhiteEvent();
6018 void AnalyzeModeProc(w, event, prms, nprms)
6026 if (!first.analysisSupport) {
6027 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6028 DisplayError(buf, 0);
6031 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6032 if (appData.icsActive) {
6033 if (gameMode != IcsObserving) {
6034 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6035 DisplayError(buf, 0);
6037 if (appData.icsEngineAnalyze) {
6038 if (appData.debugMode)
6039 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6045 /* if enable, use want disable icsEngineAnalyze */
6046 if (appData.icsEngineAnalyze) {
6051 appData.icsEngineAnalyze = TRUE;
6052 if (appData.debugMode)
6053 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6055 if (!appData.showThinking)
6056 ShowThinkingProc(w,event,prms,nprms);
6061 void AnalyzeFileProc(w, event, prms, nprms)
6067 if (!first.analysisSupport) {
6069 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6070 DisplayError(buf, 0);
6075 if (!appData.showThinking)
6076 ShowThinkingProc(w,event,prms,nprms);
6079 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6080 AnalysisPeriodicEvent(1);
6083 void TwoMachinesProc(w, event, prms, nprms)
6092 void IcsClientProc(w, event, prms, nprms)
6101 void EditGameProc(w, event, prms, nprms)
6110 void EditPositionProc(w, event, prms, nprms)
6116 EditPositionEvent();
6119 void TrainingProc(w, event, prms, nprms)
6128 void EditCommentProc(w, event, prms, nprms)
6135 EditCommentPopDown();
6141 void IcsInputBoxProc(w, event, prms, nprms)
6147 if (ICSInputBoxUp) {
6148 ICSInputBoxPopDown();
6154 void AcceptProc(w, event, prms, nprms)
6163 void DeclineProc(w, event, prms, nprms)
6172 void RematchProc(w, event, prms, nprms)
6181 void CallFlagProc(w, event, prms, nprms)
6190 void DrawProc(w, event, prms, nprms)
6199 void AbortProc(w, event, prms, nprms)
6208 void AdjournProc(w, event, prms, nprms)
6217 void ResignProc(w, event, prms, nprms)
6226 void AdjuWhiteProc(w, event, prms, nprms)
6232 UserAdjudicationEvent(+1);
6235 void AdjuBlackProc(w, event, prms, nprms)
6241 UserAdjudicationEvent(-1);
6244 void AdjuDrawProc(w, event, prms, nprms)
6250 UserAdjudicationEvent(0);
6253 void EnterKeyProc(w, event, prms, nprms)
6259 if (ICSInputBoxUp == True)
6263 void UpKeyProc(w, event, prms, nprms)
6268 { // [HGM] input: let up-arrow recall previous line from history
6275 if (!ICSInputBoxUp) return;
6276 edit = XtNameToWidget(ICSInputShell, "*form.text");
6278 XtSetArg(args[j], XtNstring, &val); j++;
6279 XtGetValues(edit, args, j);
6280 val = PrevInHistory(val);
6281 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6282 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6284 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6285 XawTextReplace(edit, 0, 0, &t);
6286 XawTextSetInsertionPoint(edit, 9999);
6290 void DownKeyProc(w, event, prms, nprms)
6295 { // [HGM] input: let down-arrow recall next line from history
6300 if (!ICSInputBoxUp) return;
6301 edit = XtNameToWidget(ICSInputShell, "*form.text");
6302 val = NextInHistory();
6303 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6304 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6306 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6307 XawTextReplace(edit, 0, 0, &t);
6308 XawTextSetInsertionPoint(edit, 9999);
6312 void StopObservingProc(w, event, prms, nprms)
6318 StopObservingEvent();
6321 void StopExaminingProc(w, event, prms, nprms)
6327 StopExaminingEvent();
6330 void UploadProc(w, event, prms, nprms)
6340 void ForwardProc(w, event, prms, nprms)
6350 void BackwardProc(w, event, prms, nprms)
6359 void ToStartProc(w, event, prms, nprms)
6368 void ToEndProc(w, event, prms, nprms)
6377 void RevertProc(w, event, prms, nprms)
6386 void AnnotateProc(w, event, prms, nprms)
6395 void TruncateGameProc(w, event, prms, nprms)
6401 TruncateGameEvent();
6403 void RetractMoveProc(w, event, prms, nprms)
6412 void MoveNowProc(w, event, prms, nprms)
6422 void AlwaysQueenProc(w, event, prms, nprms)
6430 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6432 if (appData.alwaysPromoteToQueen) {
6433 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6435 XtSetArg(args[0], XtNleftBitmap, None);
6437 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6441 void AnimateDraggingProc(w, event, prms, nprms)
6449 appData.animateDragging = !appData.animateDragging;
6451 if (appData.animateDragging) {
6452 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6455 XtSetArg(args[0], XtNleftBitmap, None);
6457 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6461 void AnimateMovingProc(w, event, prms, nprms)
6469 appData.animate = !appData.animate;
6471 if (appData.animate) {
6472 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6475 XtSetArg(args[0], XtNleftBitmap, None);
6477 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6481 void AutocommProc(w, event, prms, nprms)
6489 appData.autoComment = !appData.autoComment;
6491 if (appData.autoComment) {
6492 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6494 XtSetArg(args[0], XtNleftBitmap, None);
6496 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6501 void AutoflagProc(w, event, prms, nprms)
6509 appData.autoCallFlag = !appData.autoCallFlag;
6511 if (appData.autoCallFlag) {
6512 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6514 XtSetArg(args[0], XtNleftBitmap, None);
6516 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6520 void AutoflipProc(w, event, prms, nprms)
6528 appData.autoFlipView = !appData.autoFlipView;
6530 if (appData.autoFlipView) {
6531 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6533 XtSetArg(args[0], XtNleftBitmap, None);
6535 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6539 void AutobsProc(w, event, prms, nprms)
6547 appData.autoObserve = !appData.autoObserve;
6549 if (appData.autoObserve) {
6550 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6552 XtSetArg(args[0], XtNleftBitmap, None);
6554 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6558 void AutoraiseProc(w, event, prms, nprms)
6566 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6568 if (appData.autoRaiseBoard) {
6569 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6571 XtSetArg(args[0], XtNleftBitmap, None);
6573 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6577 void AutosaveProc(w, event, prms, nprms)
6585 appData.autoSaveGames = !appData.autoSaveGames;
6587 if (appData.autoSaveGames) {
6588 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6590 XtSetArg(args[0], XtNleftBitmap, None);
6592 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6596 void BlindfoldProc(w, event, prms, nprms)
6604 appData.blindfold = !appData.blindfold;
6606 if (appData.blindfold) {
6607 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6609 XtSetArg(args[0], XtNleftBitmap, None);
6611 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6614 DrawPosition(True, NULL);
6617 void TestLegalityProc(w, event, prms, nprms)
6625 appData.testLegality = !appData.testLegality;
6627 if (appData.testLegality) {
6628 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6630 XtSetArg(args[0], XtNleftBitmap, None);
6632 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6637 void FlashMovesProc(w, event, prms, nprms)
6645 if (appData.flashCount == 0) {
6646 appData.flashCount = 3;
6648 appData.flashCount = -appData.flashCount;
6651 if (appData.flashCount > 0) {
6652 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6654 XtSetArg(args[0], XtNleftBitmap, None);
6656 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6660 void FlipViewProc(w, event, prms, nprms)
6666 flipView = !flipView;
6667 DrawPosition(True, NULL);
6670 void GetMoveListProc(w, event, prms, nprms)
6678 appData.getMoveList = !appData.getMoveList;
6680 if (appData.getMoveList) {
6681 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6684 XtSetArg(args[0], XtNleftBitmap, None);
6686 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6691 void HighlightDraggingProc(w, event, prms, nprms)
6699 appData.highlightDragging = !appData.highlightDragging;
6701 if (appData.highlightDragging) {
6702 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6704 XtSetArg(args[0], XtNleftBitmap, None);
6706 XtSetValues(XtNameToWidget(menuBarWidget,
6707 "menuOptions.Highlight Dragging"), args, 1);
6711 void HighlightLastMoveProc(w, event, prms, nprms)
6719 appData.highlightLastMove = !appData.highlightLastMove;
6721 if (appData.highlightLastMove) {
6722 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6724 XtSetArg(args[0], XtNleftBitmap, None);
6726 XtSetValues(XtNameToWidget(menuBarWidget,
6727 "menuOptions.Highlight Last Move"), args, 1);
6730 void IcsAlarmProc(w, event, prms, nprms)
6738 appData.icsAlarm = !appData.icsAlarm;
6740 if (appData.icsAlarm) {
6741 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6743 XtSetArg(args[0], XtNleftBitmap, None);
6745 XtSetValues(XtNameToWidget(menuBarWidget,
6746 "menuOptions.ICS Alarm"), args, 1);
6749 void MoveSoundProc(w, event, prms, nprms)
6757 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6759 if (appData.ringBellAfterMoves) {
6760 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6762 XtSetArg(args[0], XtNleftBitmap, None);
6764 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6769 void OldSaveStyleProc(w, event, prms, nprms)
6777 appData.oldSaveStyle = !appData.oldSaveStyle;
6779 if (appData.oldSaveStyle) {
6780 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6782 XtSetArg(args[0], XtNleftBitmap, None);
6784 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6788 void PeriodicUpdatesProc(w, event, prms, nprms)
6796 PeriodicUpdatesEvent(!appData.periodicUpdates);
6798 if (appData.periodicUpdates) {
6799 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6801 XtSetArg(args[0], XtNleftBitmap, None);
6803 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6807 void PonderNextMoveProc(w, event, prms, nprms)
6815 PonderNextMoveEvent(!appData.ponderNextMove);
6817 if (appData.ponderNextMove) {
6818 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6820 XtSetArg(args[0], XtNleftBitmap, None);
6822 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6826 void PopupExitMessageProc(w, event, prms, nprms)
6834 appData.popupExitMessage = !appData.popupExitMessage;
6836 if (appData.popupExitMessage) {
6837 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6839 XtSetArg(args[0], XtNleftBitmap, None);
6841 XtSetValues(XtNameToWidget(menuBarWidget,
6842 "menuOptions.Popup Exit Message"), args, 1);
6845 void PopupMoveErrorsProc(w, event, prms, nprms)
6853 appData.popupMoveErrors = !appData.popupMoveErrors;
6855 if (appData.popupMoveErrors) {
6856 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6858 XtSetArg(args[0], XtNleftBitmap, None);
6860 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6864 void PremoveProc(w, event, prms, nprms)
6872 appData.premove = !appData.premove;
6874 if (appData.premove) {
6875 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6877 XtSetArg(args[0], XtNleftBitmap, None);
6879 XtSetValues(XtNameToWidget(menuBarWidget,
6880 "menuOptions.Premove"), args, 1);
6883 void QuietPlayProc(w, event, prms, nprms)
6891 appData.quietPlay = !appData.quietPlay;
6893 if (appData.quietPlay) {
6894 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6896 XtSetArg(args[0], XtNleftBitmap, None);
6898 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6902 void ShowCoordsProc(w, event, prms, nprms)
6910 appData.showCoords = !appData.showCoords;
6912 if (appData.showCoords) {
6913 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6915 XtSetArg(args[0], XtNleftBitmap, None);
6917 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6920 DrawPosition(True, NULL);
6923 void ShowThinkingProc(w, event, prms, nprms)
6929 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6930 ShowThinkingEvent();
6933 void HideThinkingProc(w, event, prms, nprms)
6941 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6942 ShowThinkingEvent();
6944 if (appData.hideThinkingFromHuman) {
6945 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6947 XtSetArg(args[0], XtNleftBitmap, None);
6949 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6953 void SaveOnExitProc(w, event, prms, nprms)
6961 saveSettingsOnExit = !saveSettingsOnExit;
6963 if (saveSettingsOnExit) {
6964 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6966 XtSetArg(args[0], XtNleftBitmap, None);
6968 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6972 void SaveSettingsProc(w, event, prms, nprms)
6978 SaveSettings(settingsFileName);
6981 void InfoProc(w, event, prms, nprms)
6988 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6993 void ManProc(w, event, prms, nprms)
7001 if (nprms && *nprms > 0)
7005 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7009 void HintProc(w, event, prms, nprms)
7018 void BookProc(w, event, prms, nprms)
7027 void AboutProc(w, event, prms, nprms)
7035 char *zippy = " (with Zippy code)";
7039 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7040 programVersion, zippy,
7041 "Copyright 1991 Digital Equipment Corporation",
7042 "Enhancements Copyright 1992-2009 Free Software Foundation",
7043 "Enhancements Copyright 2005 Alessandro Scotti",
7044 PACKAGE, " is free software and carries NO WARRANTY;",
7045 "see the file COPYING for more information.");
7046 ErrorPopUp(_("About XBoard"), buf, FALSE);
7049 void DebugProc(w, event, prms, nprms)
7055 appData.debugMode = !appData.debugMode;
7058 void AboutGameProc(w, event, prms, nprms)
7067 void NothingProc(w, event, prms, nprms)
7076 void Iconify(w, event, prms, nprms)
7085 XtSetArg(args[0], XtNiconic, True);
7086 XtSetValues(shellWidget, args, 1);
7089 void DisplayMessage(message, extMessage)
7090 char *message, *extMessage;
7092 /* display a message in the message widget */
7101 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7106 message = extMessage;
7110 /* need to test if messageWidget already exists, since this function
7111 can also be called during the startup, if for example a Xresource
7112 is not set up correctly */
7115 XtSetArg(arg, XtNlabel, message);
7116 XtSetValues(messageWidget, &arg, 1);
7122 void DisplayTitle(text)
7127 char title[MSG_SIZ];
7130 if (text == NULL) text = "";
7132 if (appData.titleInWindow) {
7134 XtSetArg(args[i], XtNlabel, text); i++;
7135 XtSetValues(titleWidget, args, i);
7138 if (*text != NULLCHAR) {
7139 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7140 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7141 } else if (appData.icsActive) {
7142 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7143 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7144 } else if (appData.cmailGameName[0] != NULLCHAR) {
7145 snprintf(icon, sizeof(icon), "%s", "CMail");
7146 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7148 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7149 } else if (gameInfo.variant == VariantGothic) {
7150 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7151 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7154 } else if (gameInfo.variant == VariantFalcon) {
7155 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7156 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7158 } else if (appData.noChessProgram) {
7159 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7160 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7162 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7163 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7166 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7167 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7168 XtSetValues(shellWidget, args, i);
7173 DisplayError(message, error)
7180 if (appData.debugMode || appData.matchMode) {
7181 fprintf(stderr, "%s: %s\n", programName, message);
7184 if (appData.debugMode || appData.matchMode) {
7185 fprintf(stderr, "%s: %s: %s\n",
7186 programName, message, strerror(error));
7188 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7191 ErrorPopUp(_("Error"), message, FALSE);
7195 void DisplayMoveError(message)
7200 DrawPosition(FALSE, NULL);
7201 if (appData.debugMode || appData.matchMode) {
7202 fprintf(stderr, "%s: %s\n", programName, message);
7204 if (appData.popupMoveErrors) {
7205 ErrorPopUp(_("Error"), message, FALSE);
7207 DisplayMessage(message, "");
7212 void DisplayFatalError(message, error, status)
7218 errorExitStatus = status;
7220 fprintf(stderr, "%s: %s\n", programName, message);
7222 fprintf(stderr, "%s: %s: %s\n",
7223 programName, message, strerror(error));
7224 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7227 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7228 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7234 void DisplayInformation(message)
7238 ErrorPopUp(_("Information"), message, TRUE);
7241 void DisplayNote(message)
7245 ErrorPopUp(_("Note"), message, FALSE);
7249 NullXErrorCheck(dpy, error_event)
7251 XErrorEvent *error_event;
7256 void DisplayIcsInteractionTitle(message)
7259 if (oldICSInteractionTitle == NULL) {
7260 /* Magic to find the old window title, adapted from vim */
7261 char *wina = getenv("WINDOWID");
7263 Window win = (Window) atoi(wina);
7264 Window root, parent, *children;
7265 unsigned int nchildren;
7266 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7268 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7269 if (!XQueryTree(xDisplay, win, &root, &parent,
7270 &children, &nchildren)) break;
7271 if (children) XFree((void *)children);
7272 if (parent == root || parent == 0) break;
7275 XSetErrorHandler(oldHandler);
7277 if (oldICSInteractionTitle == NULL) {
7278 oldICSInteractionTitle = "xterm";
7281 printf("\033]0;%s\007", message);
7285 char pendingReplyPrefix[MSG_SIZ];
7286 ProcRef pendingReplyPR;
7288 void AskQuestionProc(w, event, prms, nprms)
7295 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7299 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7302 void AskQuestionPopDown()
7304 if (!askQuestionUp) return;
7305 XtPopdown(askQuestionShell);
7306 XtDestroyWidget(askQuestionShell);
7307 askQuestionUp = False;
7310 void AskQuestionReplyAction(w, event, prms, nprms)
7320 reply = XawDialogGetValueString(w = XtParent(w));
7321 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7322 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7323 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7324 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7325 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7326 AskQuestionPopDown();
7328 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7331 void AskQuestionCallback(w, client_data, call_data)
7333 XtPointer client_data, call_data;
7338 XtSetArg(args[0], XtNlabel, &name);
7339 XtGetValues(w, args, 1);
7341 if (strcmp(name, _("cancel")) == 0) {
7342 AskQuestionPopDown();
7344 AskQuestionReplyAction(w, NULL, NULL, NULL);
7348 void AskQuestion(title, question, replyPrefix, pr)
7349 char *title, *question, *replyPrefix;
7353 Widget popup, layout, dialog, edit;
7359 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7360 pendingReplyPR = pr;
7363 XtSetArg(args[i], XtNresizable, True); i++;
7364 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7365 askQuestionShell = popup =
7366 XtCreatePopupShell(title, transientShellWidgetClass,
7367 shellWidget, args, i);
7370 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7371 layoutArgs, XtNumber(layoutArgs));
7374 XtSetArg(args[i], XtNlabel, question); i++;
7375 XtSetArg(args[i], XtNvalue, ""); i++;
7376 XtSetArg(args[i], XtNborderWidth, 0); i++;
7377 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7380 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7381 (XtPointer) dialog);
7382 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7383 (XtPointer) dialog);
7385 XtRealizeWidget(popup);
7386 CatchDeleteWindow(popup, "AskQuestionPopDown");
7388 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7389 &x, &y, &win_x, &win_y, &mask);
7391 XtSetArg(args[0], XtNx, x - 10);
7392 XtSetArg(args[1], XtNy, y - 30);
7393 XtSetValues(popup, args, 2);
7395 XtPopup(popup, XtGrabExclusive);
7396 askQuestionUp = True;
7398 edit = XtNameToWidget(dialog, "*value");
7399 XtSetKeyboardFocus(popup, edit);
7407 if (*name == NULLCHAR) {
7409 } else if (strcmp(name, "$") == 0) {
7410 putc(BELLCHAR, stderr);
7413 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7421 PlaySound(appData.soundMove);
7427 PlaySound(appData.soundIcsWin);
7433 PlaySound(appData.soundIcsLoss);
7439 PlaySound(appData.soundIcsDraw);
7443 PlayIcsUnfinishedSound()
7445 PlaySound(appData.soundIcsUnfinished);
7451 PlaySound(appData.soundIcsAlarm);
7457 system("stty echo");
7463 system("stty -echo");
7467 Colorize(cc, continuation)
7472 int count, outCount, error;
7474 if (textColors[(int)cc].bg > 0) {
7475 if (textColors[(int)cc].fg > 0) {
7476 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7477 textColors[(int)cc].fg, textColors[(int)cc].bg);
7479 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7480 textColors[(int)cc].bg);
7483 if (textColors[(int)cc].fg > 0) {
7484 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7485 textColors[(int)cc].fg);
7487 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7490 count = strlen(buf);
7491 outCount = OutputToProcess(NoProc, buf, count, &error);
7492 if (outCount < count) {
7493 DisplayFatalError(_("Error writing to display"), error, 1);
7496 if (continuation) return;
7499 PlaySound(appData.soundShout);
7502 PlaySound(appData.soundSShout);
7505 PlaySound(appData.soundChannel1);
7508 PlaySound(appData.soundChannel);
7511 PlaySound(appData.soundKibitz);
7514 PlaySound(appData.soundTell);
7516 case ColorChallenge:
7517 PlaySound(appData.soundChallenge);
7520 PlaySound(appData.soundRequest);
7523 PlaySound(appData.soundSeek);
7534 return getpwuid(getuid())->pw_name;
7538 ExpandPathName(path)
7541 static char static_buf[4*MSG_SIZ];
7542 char *d, *s, buf[4*MSG_SIZ];
7548 while (*s && isspace(*s))
7557 if (*(s+1) == '/') {
7558 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7562 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7563 *strchr(buf, '/') = 0;
7564 pwd = getpwnam(buf);
7567 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7571 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7572 strcat(d, strchr(s+1, '/'));
7576 safeStrCpy(d, s, 4*MSG_SIZ );
7583 static char host_name[MSG_SIZ];
7585 #if HAVE_GETHOSTNAME
7586 gethostname(host_name, MSG_SIZ);
7588 #else /* not HAVE_GETHOSTNAME */
7589 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7590 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7592 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7594 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7595 #endif /* not HAVE_GETHOSTNAME */
7598 XtIntervalId delayedEventTimerXID = 0;
7599 DelayedEventCallback delayedEventCallback = 0;
7604 delayedEventTimerXID = 0;
7605 delayedEventCallback();
7609 ScheduleDelayedEvent(cb, millisec)
7610 DelayedEventCallback cb; long millisec;
7612 if(delayedEventTimerXID && delayedEventCallback == cb)
7613 // [HGM] alive: replace, rather than add or flush identical event
7614 XtRemoveTimeOut(delayedEventTimerXID);
7615 delayedEventCallback = cb;
7616 delayedEventTimerXID =
7617 XtAppAddTimeOut(appContext, millisec,
7618 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7621 DelayedEventCallback
7624 if (delayedEventTimerXID) {
7625 return delayedEventCallback;
7632 CancelDelayedEvent()
7634 if (delayedEventTimerXID) {
7635 XtRemoveTimeOut(delayedEventTimerXID);
7636 delayedEventTimerXID = 0;
7640 XtIntervalId loadGameTimerXID = 0;
7642 int LoadGameTimerRunning()
7644 return loadGameTimerXID != 0;
7647 int StopLoadGameTimer()
7649 if (loadGameTimerXID != 0) {
7650 XtRemoveTimeOut(loadGameTimerXID);
7651 loadGameTimerXID = 0;
7659 LoadGameTimerCallback(arg, id)
7663 loadGameTimerXID = 0;
7668 StartLoadGameTimer(millisec)
7672 XtAppAddTimeOut(appContext, millisec,
7673 (XtTimerCallbackProc) LoadGameTimerCallback,
7677 XtIntervalId analysisClockXID = 0;
7680 AnalysisClockCallback(arg, id)
7684 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7685 || appData.icsEngineAnalyze) { // [DM]
7686 AnalysisPeriodicEvent(0);
7687 StartAnalysisClock();
7692 StartAnalysisClock()
7695 XtAppAddTimeOut(appContext, 2000,
7696 (XtTimerCallbackProc) AnalysisClockCallback,
7700 XtIntervalId clockTimerXID = 0;
7702 int ClockTimerRunning()
7704 return clockTimerXID != 0;
7707 int StopClockTimer()
7709 if (clockTimerXID != 0) {
7710 XtRemoveTimeOut(clockTimerXID);
7719 ClockTimerCallback(arg, id)
7728 StartClockTimer(millisec)
7732 XtAppAddTimeOut(appContext, millisec,
7733 (XtTimerCallbackProc) ClockTimerCallback,
7738 DisplayTimerLabel(w, color, timer, highlight)
7747 /* check for low time warning */
7748 Pixel foregroundOrWarningColor = timerForegroundPixel;
7751 appData.lowTimeWarning &&
7752 (timer / 1000) < appData.icsAlarmTime)
7753 foregroundOrWarningColor = lowTimeWarningColor;
7755 if (appData.clockMode) {
7756 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7757 XtSetArg(args[0], XtNlabel, buf);
7759 snprintf(buf, MSG_SIZ, "%s ", color);
7760 XtSetArg(args[0], XtNlabel, buf);
7765 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7766 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7768 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7769 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7772 XtSetValues(w, args, 3);
7776 DisplayWhiteClock(timeRemaining, highlight)
7782 if(appData.noGUI) return;
7783 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7784 if (highlight && iconPixmap == bIconPixmap) {
7785 iconPixmap = wIconPixmap;
7786 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7787 XtSetValues(shellWidget, args, 1);
7792 DisplayBlackClock(timeRemaining, highlight)
7798 if(appData.noGUI) return;
7799 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7800 if (highlight && iconPixmap == wIconPixmap) {
7801 iconPixmap = bIconPixmap;
7802 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7803 XtSetValues(shellWidget, args, 1);
7821 int StartChildProcess(cmdLine, dir, pr)
7828 int to_prog[2], from_prog[2];
7832 if (appData.debugMode) {
7833 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7836 /* We do NOT feed the cmdLine to the shell; we just
7837 parse it into blank-separated arguments in the
7838 most simple-minded way possible.
7841 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7844 while(*p == ' ') p++;
7846 if(*p == '"' || *p == '\'')
7847 p = strchr(++argv[i-1], *p);
7848 else p = strchr(p, ' ');
7849 if (p == NULL) break;
7854 SetUpChildIO(to_prog, from_prog);
7856 if ((pid = fork()) == 0) {
7858 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7859 close(to_prog[1]); // first close the unused pipe ends
7860 close(from_prog[0]);
7861 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7862 dup2(from_prog[1], 1);
7863 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7864 close(from_prog[1]); // and closing again loses one of the pipes!
7865 if(fileno(stderr) >= 2) // better safe than sorry...
7866 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7868 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7873 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7875 execvp(argv[0], argv);
7877 /* If we get here, exec failed */
7882 /* Parent process */
7884 close(from_prog[1]);
7886 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7889 cp->fdFrom = from_prog[0];
7890 cp->fdTo = to_prog[1];
7895 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7896 static RETSIGTYPE AlarmCallBack(int n)
7902 DestroyChildProcess(pr, signalType)
7906 ChildProc *cp = (ChildProc *) pr;
7908 if (cp->kind != CPReal) return;
7910 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7911 signal(SIGALRM, AlarmCallBack);
7913 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7914 kill(cp->pid, SIGKILL); // kill it forcefully
7915 wait((int *) 0); // and wait again
7919 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7921 /* Process is exiting either because of the kill or because of
7922 a quit command sent by the backend; either way, wait for it to die.
7931 InterruptChildProcess(pr)
7934 ChildProc *cp = (ChildProc *) pr;
7936 if (cp->kind != CPReal) return;
7937 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7940 int OpenTelnet(host, port, pr)
7945 char cmdLine[MSG_SIZ];
7947 if (port[0] == NULLCHAR) {
7948 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7950 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7952 return StartChildProcess(cmdLine, "", pr);
7955 int OpenTCP(host, port, pr)
7961 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7962 #else /* !OMIT_SOCKETS */
7964 struct sockaddr_in sa;
7966 unsigned short uport;
7969 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7973 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7974 sa.sin_family = AF_INET;
7975 sa.sin_addr.s_addr = INADDR_ANY;
7976 uport = (unsigned short) 0;
7977 sa.sin_port = htons(uport);
7978 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7982 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7983 if (!(hp = gethostbyname(host))) {
7985 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7986 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7987 hp->h_addrtype = AF_INET;
7989 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7990 hp->h_addr_list[0] = (char *) malloc(4);
7991 hp->h_addr_list[0][0] = b0;
7992 hp->h_addr_list[0][1] = b1;
7993 hp->h_addr_list[0][2] = b2;
7994 hp->h_addr_list[0][3] = b3;
7999 sa.sin_family = hp->h_addrtype;
8000 uport = (unsigned short) atoi(port);
8001 sa.sin_port = htons(uport);
8002 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8004 if (connect(s, (struct sockaddr *) &sa,
8005 sizeof(struct sockaddr_in)) < 0) {
8009 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8016 #endif /* !OMIT_SOCKETS */
8021 int OpenCommPort(name, pr)
8028 fd = open(name, 2, 0);
8029 if (fd < 0) return errno;
8031 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8041 int OpenLoopback(pr)
8047 SetUpChildIO(to, from);
8049 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8052 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8059 int OpenRcmd(host, user, cmd, pr)
8060 char *host, *user, *cmd;
8063 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8067 #define INPUT_SOURCE_BUF_SIZE 8192
8076 char buf[INPUT_SOURCE_BUF_SIZE];
8081 DoInputCallback(closure, source, xid)
8086 InputSource *is = (InputSource *) closure;
8091 if (is->lineByLine) {
8092 count = read(is->fd, is->unused,
8093 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8095 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8098 is->unused += count;
8100 while (p < is->unused) {
8101 q = memchr(p, '\n', is->unused - p);
8102 if (q == NULL) break;
8104 (is->func)(is, is->closure, p, q - p, 0);
8108 while (p < is->unused) {
8113 # if HAVE_LIBREADLINE
8114 /* check if input is from stdin, if yes, use gnu-readline */
8115 if( is->fd==fileno(stdin) )
8117 /* to clear the line */
8120 /* read from stdin */
8121 rl_callback_read_char();
8123 /* redisplay the current line, check special case for login and password */
8124 if(sending_ICS_password)
8126 int i; char buf[MSG_SIZ];
8130 /* blank the password */
8131 count = strlen(rl_line_buffer);
8134 printf("PROBLEM with readline\n");
8137 for(i=0;i<count;i++)
8141 printf("\rpassword: %s",buf);
8143 else if (sending_ICS_login)
8145 /* show login prompt */
8146 count = strlen(rl_line_buffer);
8147 printf("\rlogin: %s",rl_line_buffer);
8150 rl_reset_line_state();
8152 if(readline_complete)
8154 /* copy into XBoards buffer */
8155 count = strlen(readline_buffer);
8156 if (count>INPUT_SOURCE_BUF_SIZE-1)
8158 printf("PROBLEM with readline\n");
8159 count = INPUT_SOURCE_BUF_SIZE;
8161 strncpy(is->buf,readline_buffer,count);
8162 is->buf[count]='\n';count++;
8164 /* reset gnu-readline state */
8165 free(readline_buffer);
8166 readline_buffer=NULL;
8167 readline_complete=0;
8173 (is->func)(is, is->closure, is->buf, count, error);
8175 /* are we done with the password? */
8176 if(sending_ICS_password)
8177 sending_ICS_password=0;
8178 if(sending_ICS_login)
8179 sending_ICS_login=0;
8184 /* input not from stdin, use default method */
8185 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8190 (is->func)(is, is->closure, is->buf, count, error);
8192 #else /* no readline support */
8193 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8198 (is->func)(is, is->closure, is->buf, count, error);
8204 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8211 ChildProc *cp = (ChildProc *) pr;
8213 is = (InputSource *) calloc(1, sizeof(InputSource));
8214 is->lineByLine = lineByLine;
8218 is->fd = fileno(stdin);
8220 is->kind = cp->kind;
8221 is->fd = cp->fdFrom;
8224 is->unused = is->buf;
8227 is->xid = XtAppAddInput(appContext, is->fd,
8228 (XtPointer) (XtInputReadMask),
8229 (XtInputCallbackProc) DoInputCallback,
8231 is->closure = closure;
8232 return (InputSourceRef) is;
8236 RemoveInputSource(isr)
8239 InputSource *is = (InputSource *) isr;
8241 if (is->xid == 0) return;
8242 XtRemoveInput(is->xid);
8246 int OutputToProcess(pr, message, count, outError)
8252 static int line = 0;
8253 ChildProc *cp = (ChildProc *) pr;
8259 if (appData.noJoin || !appData.useInternalWrap)
8260 outCount = fwrite(message, 1, count, stdout);
8263 int width = get_term_width();
8264 int len = wrap(NULL, message, count, width, &line);
8265 char *msg = malloc(len);
8269 outCount = fwrite(message, 1, count, stdout);
8272 dbgchk = wrap(msg, message, count, width, &line);
8273 if (dbgchk != len && appData.debugMode)
8274 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8275 outCount = fwrite(msg, 1, dbgchk, stdout);
8280 # if HAVE_LIBREADLINE
8281 /* readline support */
8282 if(strlen(rl_line_buffer))
8283 printf("\n> %s",rl_line_buffer);
8288 outCount = write(cp->fdTo, message, count);
8298 /* Output message to process, with "ms" milliseconds of delay
8299 between each character. This is needed when sending the logon
8300 script to ICC, which for some reason doesn't like the
8301 instantaneous send. */
8302 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8309 ChildProc *cp = (ChildProc *) pr;
8314 r = write(cp->fdTo, message++, 1);
8327 /**** Animation code by Hugh Fisher, DCS, ANU.
8329 Known problem: if a window overlapping the board is
8330 moved away while a piece is being animated underneath,
8331 the newly exposed area won't be updated properly.
8332 I can live with this.
8334 Known problem: if you look carefully at the animation
8335 of pieces in mono mode, they are being drawn as solid
8336 shapes without interior detail while moving. Fixing
8337 this would be a major complication for minimal return.
8340 /* Masks for XPM pieces. Black and white pieces can have
8341 different shapes, but in the interest of retaining my
8342 sanity pieces must have the same outline on both light
8343 and dark squares, and all pieces must use the same
8344 background square colors/images. */
8346 static int xpmDone = 0;
8349 CreateAnimMasks (pieceDepth)
8356 unsigned long plane;
8359 /* Need a bitmap just to get a GC with right depth */
8360 buf = XCreatePixmap(xDisplay, xBoardWindow,
8362 values.foreground = 1;
8363 values.background = 0;
8364 /* Don't use XtGetGC, not read only */
8365 maskGC = XCreateGC(xDisplay, buf,
8366 GCForeground | GCBackground, &values);
8367 XFreePixmap(xDisplay, buf);
8369 buf = XCreatePixmap(xDisplay, xBoardWindow,
8370 squareSize, squareSize, pieceDepth);
8371 values.foreground = XBlackPixel(xDisplay, xScreen);
8372 values.background = XWhitePixel(xDisplay, xScreen);
8373 bufGC = XCreateGC(xDisplay, buf,
8374 GCForeground | GCBackground, &values);
8376 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8377 /* Begin with empty mask */
8378 if(!xpmDone) // [HGM] pieces: keep using existing
8379 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8380 squareSize, squareSize, 1);
8381 XSetFunction(xDisplay, maskGC, GXclear);
8382 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8383 0, 0, squareSize, squareSize);
8385 /* Take a copy of the piece */
8390 XSetFunction(xDisplay, bufGC, GXcopy);
8391 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8393 0, 0, squareSize, squareSize, 0, 0);
8395 /* XOR the background (light) over the piece */
8396 XSetFunction(xDisplay, bufGC, GXxor);
8398 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8399 0, 0, squareSize, squareSize, 0, 0);
8401 XSetForeground(xDisplay, bufGC, lightSquareColor);
8402 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8405 /* We now have an inverted piece image with the background
8406 erased. Construct mask by just selecting all the non-zero
8407 pixels - no need to reconstruct the original image. */
8408 XSetFunction(xDisplay, maskGC, GXor);
8410 /* Might be quicker to download an XImage and create bitmap
8411 data from it rather than this N copies per piece, but it
8412 only takes a fraction of a second and there is a much
8413 longer delay for loading the pieces. */
8414 for (n = 0; n < pieceDepth; n ++) {
8415 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8416 0, 0, squareSize, squareSize,
8422 XFreePixmap(xDisplay, buf);
8423 XFreeGC(xDisplay, bufGC);
8424 XFreeGC(xDisplay, maskGC);
8428 InitAnimState (anim, info)
8430 XWindowAttributes * info;
8435 /* Each buffer is square size, same depth as window */
8436 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8437 squareSize, squareSize, info->depth);
8438 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8439 squareSize, squareSize, info->depth);
8441 /* Create a plain GC for blitting */
8442 mask = GCForeground | GCBackground | GCFunction |
8443 GCPlaneMask | GCGraphicsExposures;
8444 values.foreground = XBlackPixel(xDisplay, xScreen);
8445 values.background = XWhitePixel(xDisplay, xScreen);
8446 values.function = GXcopy;
8447 values.plane_mask = AllPlanes;
8448 values.graphics_exposures = False;
8449 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8451 /* Piece will be copied from an existing context at
8452 the start of each new animation/drag. */
8453 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8455 /* Outline will be a read-only copy of an existing */
8456 anim->outlineGC = None;
8462 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8463 XWindowAttributes info;
8465 if (xpmDone && gameInfo.variant == old) return;
8466 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8467 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8469 InitAnimState(&game, &info);
8470 InitAnimState(&player, &info);
8472 /* For XPM pieces, we need bitmaps to use as masks. */
8474 CreateAnimMasks(info.depth);
8480 static Boolean frameWaiting;
8482 static RETSIGTYPE FrameAlarm (sig)
8485 frameWaiting = False;
8486 /* In case System-V style signals. Needed?? */
8487 signal(SIGALRM, FrameAlarm);
8494 struct itimerval delay;
8496 XSync(xDisplay, False);
8499 frameWaiting = True;
8500 signal(SIGALRM, FrameAlarm);
8501 delay.it_interval.tv_sec =
8502 delay.it_value.tv_sec = time / 1000;
8503 delay.it_interval.tv_usec =
8504 delay.it_value.tv_usec = (time % 1000) * 1000;
8505 setitimer(ITIMER_REAL, &delay, NULL);
8506 while (frameWaiting) pause();
8507 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8508 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8509 setitimer(ITIMER_REAL, &delay, NULL);
8519 XSync(xDisplay, False);
8521 usleep(time * 1000);
8526 /* Convert board position to corner of screen rect and color */
8529 ScreenSquare(column, row, pt, color)
8530 int column; int row; XPoint * pt; int * color;
8533 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8534 pt->y = lineGap + row * (squareSize + lineGap);
8536 pt->x = lineGap + column * (squareSize + lineGap);
8537 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8539 *color = SquareColor(row, column);
8542 /* Convert window coords to square */
8545 BoardSquare(x, y, column, row)
8546 int x; int y; int * column; int * row;
8548 *column = EventToSquare(x, BOARD_WIDTH);
8549 if (flipView && *column >= 0)
8550 *column = BOARD_WIDTH - 1 - *column;
8551 *row = EventToSquare(y, BOARD_HEIGHT);
8552 if (!flipView && *row >= 0)
8553 *row = BOARD_HEIGHT - 1 - *row;
8558 #undef Max /* just in case */
8560 #define Max(a, b) ((a) > (b) ? (a) : (b))
8561 #define Min(a, b) ((a) < (b) ? (a) : (b))
8564 SetRect(rect, x, y, width, height)
8565 XRectangle * rect; int x; int y; int width; int height;
8569 rect->width = width;
8570 rect->height = height;
8573 /* Test if two frames overlap. If they do, return
8574 intersection rect within old and location of
8575 that rect within new. */
8578 Intersect(old, new, size, area, pt)
8579 XPoint * old; XPoint * new;
8580 int size; XRectangle * area; XPoint * pt;
8582 if (old->x > new->x + size || new->x > old->x + size ||
8583 old->y > new->y + size || new->y > old->y + size) {
8586 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8587 size - abs(old->x - new->x), size - abs(old->y - new->y));
8588 pt->x = Max(old->x - new->x, 0);
8589 pt->y = Max(old->y - new->y, 0);
8594 /* For two overlapping frames, return the rect(s)
8595 in the old that do not intersect with the new. */
8598 CalcUpdateRects(old, new, size, update, nUpdates)
8599 XPoint * old; XPoint * new; int size;
8600 XRectangle update[]; int * nUpdates;
8604 /* If old = new (shouldn't happen) then nothing to draw */
8605 if (old->x == new->x && old->y == new->y) {
8609 /* Work out what bits overlap. Since we know the rects
8610 are the same size we don't need a full intersect calc. */
8612 /* Top or bottom edge? */
8613 if (new->y > old->y) {
8614 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8616 } else if (old->y > new->y) {
8617 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8618 size, old->y - new->y);
8621 /* Left or right edge - don't overlap any update calculated above. */
8622 if (new->x > old->x) {
8623 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8624 new->x - old->x, size - abs(new->y - old->y));
8626 } else if (old->x > new->x) {
8627 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8628 old->x - new->x, size - abs(new->y - old->y));
8635 /* Generate a series of frame coords from start->mid->finish.
8636 The movement rate doubles until the half way point is
8637 reached, then halves back down to the final destination,
8638 which gives a nice slow in/out effect. The algorithmn
8639 may seem to generate too many intermediates for short
8640 moves, but remember that the purpose is to attract the
8641 viewers attention to the piece about to be moved and
8642 then to where it ends up. Too few frames would be less
8646 Tween(start, mid, finish, factor, frames, nFrames)
8647 XPoint * start; XPoint * mid;
8648 XPoint * finish; int factor;
8649 XPoint frames[]; int * nFrames;
8651 int fraction, n, count;
8655 /* Slow in, stepping 1/16th, then 1/8th, ... */
8657 for (n = 0; n < factor; n++)
8659 for (n = 0; n < factor; n++) {
8660 frames[count].x = start->x + (mid->x - start->x) / fraction;
8661 frames[count].y = start->y + (mid->y - start->y) / fraction;
8663 fraction = fraction / 2;
8667 frames[count] = *mid;
8670 /* Slow out, stepping 1/2, then 1/4, ... */
8672 for (n = 0; n < factor; n++) {
8673 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8674 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8676 fraction = fraction * 2;
8681 /* Draw a piece on the screen without disturbing what's there */
8684 SelectGCMask(piece, clip, outline, mask)
8685 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8689 /* Bitmap for piece being moved. */
8690 if (appData.monoMode) {
8691 *mask = *pieceToSolid(piece);
8692 } else if (useImages) {
8694 *mask = xpmMask[piece];
8696 *mask = ximMaskPm[piece];
8699 *mask = *pieceToSolid(piece);
8702 /* GC for piece being moved. Square color doesn't matter, but
8703 since it gets modified we make a copy of the original. */
8705 if (appData.monoMode)
8710 if (appData.monoMode)
8715 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8717 /* Outline only used in mono mode and is not modified */
8719 *outline = bwPieceGC;
8721 *outline = wbPieceGC;
8725 OverlayPiece(piece, clip, outline, dest)
8726 ChessSquare piece; GC clip; GC outline; Drawable dest;
8731 /* Draw solid rectangle which will be clipped to shape of piece */
8732 XFillRectangle(xDisplay, dest, clip,
8733 0, 0, squareSize, squareSize);
8734 if (appData.monoMode)
8735 /* Also draw outline in contrasting color for black
8736 on black / white on white cases */
8737 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8738 0, 0, squareSize, squareSize, 0, 0, 1);
8740 /* Copy the piece */
8745 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8747 0, 0, squareSize, squareSize,
8752 /* Animate the movement of a single piece */
8755 BeginAnimation(anim, piece, startColor, start)
8763 /* The old buffer is initialised with the start square (empty) */
8764 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8765 anim->prevFrame = *start;
8767 /* The piece will be drawn using its own bitmap as a matte */
8768 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8769 XSetClipMask(xDisplay, anim->pieceGC, mask);
8773 AnimationFrame(anim, frame, piece)
8778 XRectangle updates[4];
8783 /* Save what we are about to draw into the new buffer */
8784 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8785 frame->x, frame->y, squareSize, squareSize,
8788 /* Erase bits of the previous frame */
8789 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8790 /* Where the new frame overlapped the previous,
8791 the contents in newBuf are wrong. */
8792 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8793 overlap.x, overlap.y,
8794 overlap.width, overlap.height,
8796 /* Repaint the areas in the old that don't overlap new */
8797 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8798 for (i = 0; i < count; i++)
8799 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8800 updates[i].x - anim->prevFrame.x,
8801 updates[i].y - anim->prevFrame.y,
8802 updates[i].width, updates[i].height,
8803 updates[i].x, updates[i].y);
8805 /* Easy when no overlap */
8806 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8807 0, 0, squareSize, squareSize,
8808 anim->prevFrame.x, anim->prevFrame.y);
8811 /* Save this frame for next time round */
8812 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8813 0, 0, squareSize, squareSize,
8815 anim->prevFrame = *frame;
8817 /* Draw piece over original screen contents, not current,
8818 and copy entire rect. Wipes out overlapping piece images. */
8819 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8820 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8821 0, 0, squareSize, squareSize,
8822 frame->x, frame->y);
8826 EndAnimation (anim, finish)
8830 XRectangle updates[4];
8835 /* The main code will redraw the final square, so we
8836 only need to erase the bits that don't overlap. */
8837 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8838 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8839 for (i = 0; i < count; i++)
8840 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8841 updates[i].x - anim->prevFrame.x,
8842 updates[i].y - anim->prevFrame.y,
8843 updates[i].width, updates[i].height,
8844 updates[i].x, updates[i].y);
8846 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8847 0, 0, squareSize, squareSize,
8848 anim->prevFrame.x, anim->prevFrame.y);
8853 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8855 ChessSquare piece; int startColor;
8856 XPoint * start; XPoint * finish;
8857 XPoint frames[]; int nFrames;
8861 BeginAnimation(anim, piece, startColor, start);
8862 for (n = 0; n < nFrames; n++) {
8863 AnimationFrame(anim, &(frames[n]), piece);
8864 FrameDelay(appData.animSpeed);
8866 EndAnimation(anim, finish);
8869 /* Main control logic for deciding what to animate and how */
8872 AnimateMove(board, fromX, fromY, toX, toY)
8881 XPoint start, finish, mid;
8882 XPoint frames[kFactor * 2 + 1];
8883 int nFrames, startColor, endColor;
8885 /* Are we animating? */
8886 if (!appData.animate || appData.blindfold)
8889 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8890 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8891 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8893 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8894 piece = board[fromY][fromX];
8895 if (piece >= EmptySquare) return;
8900 hop = (piece == WhiteKnight || piece == BlackKnight);
8903 if (appData.debugMode) {
8904 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8905 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8906 piece, fromX, fromY, toX, toY); }
8908 ScreenSquare(fromX, fromY, &start, &startColor);
8909 ScreenSquare(toX, toY, &finish, &endColor);
8912 /* Knight: make diagonal movement then straight */
8913 if (abs(toY - fromY) < abs(toX - fromX)) {
8914 mid.x = start.x + (finish.x - start.x) / 2;
8918 mid.y = start.y + (finish.y - start.y) / 2;
8921 mid.x = start.x + (finish.x - start.x) / 2;
8922 mid.y = start.y + (finish.y - start.y) / 2;
8925 /* Don't use as many frames for very short moves */
8926 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8927 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8929 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8930 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8932 /* Be sure end square is redrawn */
8933 damage[0][toY][toX] = True;
8937 DragPieceBegin(x, y)
8940 int boardX, boardY, color;
8943 /* Are we animating? */
8944 if (!appData.animateDragging || appData.blindfold)
8947 /* Figure out which square we start in and the
8948 mouse position relative to top left corner. */
8949 BoardSquare(x, y, &boardX, &boardY);
8950 player.startBoardX = boardX;
8951 player.startBoardY = boardY;
8952 ScreenSquare(boardX, boardY, &corner, &color);
8953 player.startSquare = corner;
8954 player.startColor = color;
8955 /* As soon as we start dragging, the piece will jump slightly to
8956 be centered over the mouse pointer. */
8957 player.mouseDelta.x = squareSize/2;
8958 player.mouseDelta.y = squareSize/2;
8959 /* Initialise animation */
8960 player.dragPiece = PieceForSquare(boardX, boardY);
8962 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8963 player.dragActive = True;
8964 BeginAnimation(&player, player.dragPiece, color, &corner);
8965 /* Mark this square as needing to be redrawn. Note that
8966 we don't remove the piece though, since logically (ie
8967 as seen by opponent) the move hasn't been made yet. */
8968 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8969 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8970 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8971 corner.x, corner.y, squareSize, squareSize,
8972 0, 0); // [HGM] zh: unstack in stead of grab
8973 damage[0][boardY][boardX] = True;
8975 player.dragActive = False;
8985 /* Are we animating? */
8986 if (!appData.animateDragging || appData.blindfold)
8990 if (! player.dragActive)
8992 /* Move piece, maintaining same relative position
8993 of mouse within square */
8994 corner.x = x - player.mouseDelta.x;
8995 corner.y = y - player.mouseDelta.y;
8996 AnimationFrame(&player, &corner, player.dragPiece);
8998 if (appData.highlightDragging) {
9000 BoardSquare(x, y, &boardX, &boardY);
9001 SetHighlights(fromX, fromY, boardX, boardY);
9010 int boardX, boardY, color;
9013 /* Are we animating? */
9014 if (!appData.animateDragging || appData.blindfold)
9018 if (! player.dragActive)
9020 /* Last frame in sequence is square piece is
9021 placed on, which may not match mouse exactly. */
9022 BoardSquare(x, y, &boardX, &boardY);
9023 ScreenSquare(boardX, boardY, &corner, &color);
9024 EndAnimation(&player, &corner);
9026 /* Be sure end square is redrawn */
9027 damage[0][boardY][boardX] = True;
9029 /* This prevents weird things happening with fast successive
9030 clicks which on my Sun at least can cause motion events
9031 without corresponding press/release. */
9032 player.dragActive = False;
9035 /* Handle expose event while piece being dragged */
9040 if (!player.dragActive || appData.blindfold)
9043 /* What we're doing: logically, the move hasn't been made yet,
9044 so the piece is still in it's original square. But visually
9045 it's being dragged around the board. So we erase the square
9046 that the piece is on and draw it at the last known drag point. */
9047 BlankSquare(player.startSquare.x, player.startSquare.y,
9048 player.startColor, EmptySquare, xBoardWindow);
9049 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9050 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9053 #include <sys/ioctl.h>
9054 int get_term_width()
9056 int fd, default_width;
9059 default_width = 79; // this is FICS default anyway...
9061 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9063 if (!ioctl(fd, TIOCGSIZE, &win))
9064 default_width = win.ts_cols;
9065 #elif defined(TIOCGWINSZ)
9067 if (!ioctl(fd, TIOCGWINSZ, &win))
9068 default_width = win.ws_col;
9070 return default_width;
9076 static int old_width = 0;
9077 int new_width = get_term_width();
9079 if (old_width != new_width)
9080 ics_printf("set width %d\n", new_width);
9081 old_width = new_width;
9084 void NotifyFrontendLogin()
9089 # if HAVE_LIBREADLINE
9091 ReadlineCompleteHandler(char* ptr)
9093 /* make gnu-readline keep the history */
9094 readline_buffer = ptr;
9095 readline_complete = 1;
9097 if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)