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(0) \n \
1083 Shift<Btn1Up>: HandleUserMove(1) \n \
1084 <Btn1Up>: HandleUserMove(0) \n \
1085 <Btn1Motion>: AnimateUserMove() \n \
1086 <Btn3Motion>: HandlePV() \n \
1087 <Btn3Up>: PieceMenuPopup(menuB) \n \
1088 Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
1089 PieceMenuPopup(menuB) \n \
1090 Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
1091 PieceMenuPopup(menuW) \n \
1092 Shift<Btn3Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD)\
1093 PieceMenuPopup(menuW) \n \
1094 Any<Btn3Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD) \
1095 PieceMenuPopup(menuB) \n";
1097 char whiteTranslations[] = "<BtnDown>: WhiteClock()\n";
1098 char blackTranslations[] = "<BtnDown>: BlackClock()\n";
1100 char ICSInputTranslations[] =
1101 "<Key>Up: UpKeyProc() \n "
1102 "<Key>Down: DownKeyProc() \n "
1103 "<Key>Return: EnterKeyProc() \n";
1105 // [HGM] vari: another hideous kludge: call extend-end first so we can be sure select-start works,
1106 // as the widget is destroyed before the up-click can call extend-end
1107 char commentTranslations[] = "<Btn3Down>: extend-end() select-start() CommentClick() \n";
1109 String xboardResources[] = {
1110 "*fileName*value.translations: #override\\n <Key>Return: FileNameAction()",
1111 "*question*value.translations: #override\\n <Key>Return: AskQuestionReplyAction()",
1112 "*errorpopup*translations: #override\\n <Key>Return: ErrorPopDown()",
1117 /* Max possible square size */
1118 #define MAXSQSIZE 256
1120 static int xpm_avail[MAXSQSIZE];
1122 #ifdef HAVE_DIR_STRUCT
1124 /* Extract piece size from filename */
1126 xpm_getsize(name, len, ext)
1137 if ((p=strchr(name, '.')) == NULL ||
1138 StrCaseCmp(p+1, ext) != 0)
1144 while (*p && isdigit(*p))
1151 /* Setup xpm_avail */
1153 xpm_getavail(dirname, ext)
1161 for (i=0; i<MAXSQSIZE; ++i)
1164 if (appData.debugMode)
1165 fprintf(stderr, "XPM dir:%s:ext:%s:\n", dirname, ext);
1167 dir = opendir(dirname);
1170 fprintf(stderr, _("%s: Can't access XPM directory %s\n"),
1171 programName, dirname);
1175 while ((ent=readdir(dir)) != NULL) {
1176 i = xpm_getsize(ent->d_name, NAMLEN(ent), ext);
1177 if (i > 0 && i < MAXSQSIZE)
1187 xpm_print_avail(fp, ext)
1193 fprintf(fp, _("Available `%s' sizes:\n"), ext);
1194 for (i=1; i<MAXSQSIZE; ++i) {
1200 /* Return XPM piecesize closest to size */
1202 xpm_closest_to(dirname, size, ext)
1208 int sm_diff = MAXSQSIZE;
1212 xpm_getavail(dirname, ext);
1214 if (appData.debugMode)
1215 xpm_print_avail(stderr, ext);
1217 for (i=1; i<MAXSQSIZE; ++i) {
1220 diff = (diff<0) ? -diff : diff;
1221 if (diff < sm_diff) {
1229 fprintf(stderr, _("Error: No `%s' files!\n"), ext);
1235 #else /* !HAVE_DIR_STRUCT */
1236 /* If we are on a system without a DIR struct, we can't
1237 read the directory, so we can't collect a list of
1238 filenames, etc., so we can't do any size-fitting. */
1240 xpm_closest_to(dirname, size, ext)
1245 fprintf(stderr, _("\
1246 Warning: No DIR structure found on this system --\n\
1247 Unable to autosize for XPM/XIM pieces.\n\
1248 Please report this error to frankm@hiwaay.net.\n\
1249 Include system type & operating system in message.\n"));
1252 #endif /* HAVE_DIR_STRUCT */
1254 static char *cnames[9] = { "black", "red", "green", "yellow", "blue",
1255 "magenta", "cyan", "white" };
1259 TextColors textColors[(int)NColorClasses];
1261 /* String is: "fg, bg, attr". Which is 0, 1, 2 */
1263 parse_color(str, which)
1267 char *p, buf[100], *d;
1270 if (strlen(str) > 99) /* watch bounds on buf */
1275 for (i=0; i<which; ++i) {
1282 /* Could be looking at something like:
1284 .. in which case we want to stop on a comma also */
1285 while (*p && *p != ',' && !isalpha(*p) && !isdigit(*p))
1289 return -1; /* Use default for empty field */
1292 if (which == 2 || isdigit(*p))
1295 while (*p && isalpha(*p))
1300 for (i=0; i<8; ++i) {
1301 if (!StrCaseCmp(buf, cnames[i]))
1302 return which? (i+40) : (i+30);
1304 if (!StrCaseCmp(buf, "default")) return -1;
1306 fprintf(stderr, _("%s: unrecognized color %s\n"), programName, buf);
1311 parse_cpair(cc, str)
1315 if ((textColors[(int)cc].fg=parse_color(str, 0)) == -2) {
1316 fprintf(stderr, _("%s: can't parse foreground color in `%s'\n"),
1321 /* bg and attr are optional */
1322 textColors[(int)cc].bg = parse_color(str, 1);
1323 if ((textColors[(int)cc].attr = parse_color(str, 2)) < 0) {
1324 textColors[(int)cc].attr = 0;
1330 /* Arrange to catch delete-window events */
1331 Atom wm_delete_window;
1333 CatchDeleteWindow(Widget w, String procname)
1336 XSetWMProtocols(xDisplay, XtWindow(w), &wm_delete_window, 1);
1337 snprintf(buf, sizeof(buf), "<Message>WM_PROTOCOLS: %s() \n", procname);
1338 XtAugmentTranslations(w, XtParseTranslationTable(buf));
1345 XtSetArg(args[0], XtNiconic, False);
1346 XtSetValues(shellWidget, args, 1);
1348 XtPopup(shellWidget, XtGrabNone); /* Raise if lowered */
1351 //---------------------------------------------------------------------------------------------------------
1352 // some symbol definitions to provide the proper (= XBoard) context for the code in args.h
1355 #define CW_USEDEFAULT (1<<31)
1356 #define ICS_TEXT_MENU_SIZE 90
1357 #define DEBUG_FILE "xboard.debug"
1358 #define SetCurrentDirectory chdir
1359 #define GetCurrentDirectory(SIZE, NAME) getcwd(NAME, SIZE)
1363 // these two must some day move to frontend.h, when they are implemented
1364 Boolean GameListIsUp();
1366 // The option definition and parsing code common to XBoard and WinBoard is collected in this file
1369 // front-end part of option handling
1371 // [HGM] This platform-dependent table provides the location for storing the color info
1372 extern char *crWhite, * crBlack;
1376 &appData.whitePieceColor,
1377 &appData.blackPieceColor,
1378 &appData.lightSquareColor,
1379 &appData.darkSquareColor,
1380 &appData.highlightSquareColor,
1381 &appData.premoveHighlightColor,
1382 &appData.lowTimeWarningColor,
1393 // [HGM] font: keep a font for each square size, even non-stndard ones
1394 #define NUM_SIZES 18
1395 #define MAX_SIZE 130
1396 Boolean fontSet[NUM_FONTS], fontValid[NUM_FONTS][MAX_SIZE];
1397 char *fontTable[NUM_FONTS][MAX_SIZE];
1400 ParseFont(char *name, int number)
1401 { // in XBoard, only 2 of the fonts are currently implemented, and we just copy their name
1403 if(sscanf(name, "size%d:", &size)) {
1404 // [HGM] font: font is meant for specific boardSize (likely from settings file);
1405 // defer processing it until we know if it matches our board size
1406 if(size >= 0 && size<MAX_SIZE) { // for now, fixed limit
1407 fontTable[number][size] = strdup(strchr(name, ':')+1);
1408 fontValid[number][size] = True;
1413 case 0: // CLOCK_FONT
1414 appData.clockFont = strdup(name);
1416 case 1: // MESSAGE_FONT
1417 appData.font = strdup(name);
1419 case 2: // COORD_FONT
1420 appData.coordFont = strdup(name);
1425 fontSet[number] = True; // [HGM] font: indicate a font was specified (not from settings file)
1430 { // only 2 fonts currently
1431 appData.clockFont = CLOCK_FONT_NAME;
1432 appData.coordFont = COORD_FONT_NAME;
1433 appData.font = DEFAULT_FONT_NAME;
1438 { // no-op, until we identify the code for this already in XBoard and move it here
1442 ParseColor(int n, char *name)
1443 { // in XBoard, just copy the color-name string
1444 if(colorVariable[n]) *(char**)colorVariable[n] = strdup(name);
1448 ParseTextAttribs(ColorClass cc, char *s)
1450 (&appData.colorShout)[cc] = strdup(s);
1454 ParseBoardSize(void *addr, char *name)
1456 appData.boardSize = strdup(name);
1461 { // In XBoard the sound-playing program takes care of obtaining the actual sound
1465 SetCommPortDefaults()
1466 { // for now, this is a no-op, as the corresponding option does not exist in XBoard
1469 // [HGM] args: these three cases taken out to stay in front-end
1471 SaveFontArg(FILE *f, ArgDescriptor *ad)
1474 int i, n = (int)ad->argLoc;
1476 case 0: // CLOCK_FONT
1477 name = appData.clockFont;
1479 case 1: // MESSAGE_FONT
1480 name = appData.font;
1482 case 2: // COORD_FONT
1483 name = appData.coordFont;
1488 for(i=0; i<NUM_SIZES; i++) // [HGM] font: current font becomes standard for current size
1489 if(sizeDefaults[i].squareSize == squareSize) { // only for standard sizes!
1490 fontTable[n][squareSize] = strdup(name);
1491 fontValid[n][squareSize] = True;
1494 for(i=0; i<MAX_SIZE; i++) if(fontValid[n][i]) // [HGM] font: store all standard fonts
1495 fprintf(f, OPTCHAR "%s" SEPCHAR "size%d:%s\n", ad->argName, i, fontTable[n][i]);
1500 { // nothing to do, as the sounds are at all times represented by their text-string names already
1504 SaveAttribsArg(FILE *f, ArgDescriptor *ad)
1505 { // here the "argLoc" defines a table index. It could have contained the 'ta' pointer itself, though
1506 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, (&appData.colorShout)[(int)ad->argLoc]);
1510 SaveColor(FILE *f, ArgDescriptor *ad)
1511 { // in WinBoard the color is an int and has to be converted to text. In X it would be a string already?
1512 if(colorVariable[(int)ad->argLoc])
1513 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", ad->argName, *(char**)colorVariable[(int)ad->argLoc]);
1517 SaveBoardSize(FILE *f, char *name, void *addr)
1518 { // wrapper to shield back-end from BoardSize & sizeInfo
1519 fprintf(f, OPTCHAR "%s" SEPCHAR "%s\n", name, appData.boardSize);
1523 ParseCommPortSettings(char *s)
1524 { // no such option in XBoard (yet)
1527 extern Widget engineOutputShell;
1528 extern Widget tagsShell, editTagsShell;
1530 GetActualPlacement(Widget wg, WindowPlacement *wp)
1540 XtSetArg(args[i], XtNx, &x); i++;
1541 XtSetArg(args[i], XtNy, &y); i++;
1542 XtSetArg(args[i], XtNwidth, &w); i++;
1543 XtSetArg(args[i], XtNheight, &h); i++;
1544 XtGetValues(wg, args, i);
1553 { // wrapper to shield use of window handles from back-end (make addressible by number?)
1554 // In XBoard this will have to wait until awareness of window parameters is implemented
1555 GetActualPlacement(shellWidget, &wpMain);
1556 if(EngineOutputIsUp()) GetActualPlacement(engineOutputShell, &wpEngineOutput); else
1557 if(MoveHistoryIsUp()) GetActualPlacement(historyShell, &wpMoveHistory);
1558 if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
1559 if(GameListIsUp()) GetActualPlacement(gameListShell, &wpGameList);
1560 if(commentShell) GetActualPlacement(commentShell, &wpComment);
1561 else GetActualPlacement(editShell, &wpComment);
1562 if(tagsShell) GetActualPlacement(tagsShell, &wpTags);
1563 else GetActualPlacement(editTagsShell, &wpTags);
1567 PrintCommPortSettings(FILE *f, char *name)
1568 { // This option does not exist in XBoard
1572 MySearchPath(char *installDir, char *name, char *fullname)
1573 { // just append installDir and name. Perhaps ExpandPath should be used here?
1574 name = ExpandPathName(name);
1575 if(name && name[0] == '/')
1576 safeStrCpy(fullname, name, MSG_SIZ );
1578 sprintf(fullname, "%s%c%s", installDir, '/', name);
1584 MyGetFullPathName(char *name, char *fullname)
1585 { // should use ExpandPath?
1586 name = ExpandPathName(name);
1587 safeStrCpy(fullname, name, MSG_SIZ );
1592 EnsureOnScreen(int *x, int *y, int minX, int minY)
1599 { // [HGM] args: allows testing if main window is realized from back-end
1600 return xBoardWindow != 0;
1604 PopUpStartupDialog()
1605 { // start menu not implemented in XBoard
1609 ConvertToLine(int argc, char **argv)
1611 static char line[128*1024], buf[1024];
1615 for(i=1; i<argc; i++)
1617 if( (strchr(argv[i], ' ') || strchr(argv[i], '\n') ||strchr(argv[i], '\t') )
1618 && argv[i][0] != '{' )
1619 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "{%s} ", argv[i]);
1621 snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%s ", argv[i]);
1622 strncat(line, buf, 128*1024 - strlen(line) - 1 );
1625 line[strlen(line)-1] = NULLCHAR;
1629 //--------------------------------------------------------------------------------------------
1631 extern Boolean twoBoards, partnerUp;
1634 // eventually, all layout determining code should go into a subroutine, but until then IDSIZE remains undefined
1636 #define BoardSize int
1637 void InitDrawingSizes(BoardSize boardSize, int flags)
1638 { // [HGM] resize is functional now, but for board format changes only (nr of ranks, files)
1639 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1641 XtGeometryResult gres;
1644 if(!formWidget) return;
1647 * Enable shell resizing.
1649 shellArgs[0].value = (XtArgVal) &w;
1650 shellArgs[1].value = (XtArgVal) &h;
1651 XtGetValues(shellWidget, shellArgs, 2);
1653 shellArgs[4].value = 3*w; shellArgs[2].value = 10;
1654 shellArgs[5].value = 2*h; shellArgs[3].value = 10;
1655 XtSetValues(shellWidget, &shellArgs[2], 4);
1657 XtSetArg(args[0], XtNdefaultDistance, &sep);
1658 XtGetValues(formWidget, args, 1);
1660 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1661 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1663 hOffset = boardWidth + 10;
1664 for(i=0; i<BOARD_WIDTH+BOARD_HEIGHT+2; i++) { // [HGM] dual: grid for second board
1665 secondSegments[i] = gridSegments[i];
1666 secondSegments[i].x1 += hOffset;
1667 secondSegments[i].x2 += hOffset;
1670 XtSetArg(args[0], XtNwidth, boardWidth);
1671 XtSetArg(args[1], XtNheight, boardHeight);
1672 XtSetValues(boardWidget, args, 2);
1674 timerWidth = (boardWidth - sep) / 2;
1675 XtSetArg(args[0], XtNwidth, timerWidth);
1676 XtSetValues(whiteTimerWidget, args, 1);
1677 XtSetValues(blackTimerWidget, args, 1);
1679 XawFormDoLayout(formWidget, False);
1681 if (appData.titleInWindow) {
1683 XtSetArg(args[i], XtNborderWidth, &bor); i++;
1684 XtSetArg(args[i], XtNheight, &h); i++;
1685 XtGetValues(titleWidget, args, i);
1687 w = boardWidth - 2*bor;
1689 XtSetArg(args[0], XtNwidth, &w);
1690 XtGetValues(menuBarWidget, args, 1);
1691 w = boardWidth - w - sep - 2*bor - 2; // WIDTH_FUDGE
1694 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
1695 if (gres != XtGeometryYes && appData.debugMode) {
1697 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
1698 programName, gres, w, h, wr, hr);
1702 XawFormDoLayout(formWidget, True);
1705 * Inhibit shell resizing.
1707 shellArgs[0].value = w = (XtArgVal) boardWidth + marginW + twoBoards*hOffset; // [HGM] dual
1708 shellArgs[1].value = h = (XtArgVal) boardHeight + marginH;
1709 shellArgs[4].value = shellArgs[2].value = w;
1710 shellArgs[5].value = shellArgs[3].value = h;
1711 XtSetValues(shellWidget, &shellArgs[0], 6);
1713 // [HGM] pieces: tailor piece bitmaps to needs of specific variant
1716 for(i=0; i<4; i++) {
1718 for(p=0; p<=(int)WhiteKing; p++)
1719 xpmPieceBitmap[i][p] = xpmPieceBitmap2[i][p]; // defaults
1720 if(gameInfo.variant == VariantShogi) {
1721 xpmPieceBitmap[i][(int)WhiteCannon] = xpmPieceBitmap2[i][(int)WhiteKing+1];
1722 xpmPieceBitmap[i][(int)WhiteNightrider] = xpmPieceBitmap2[i][(int)WhiteKing+2];
1723 xpmPieceBitmap[i][(int)WhiteSilver] = xpmPieceBitmap2[i][(int)WhiteKing+3];
1724 xpmPieceBitmap[i][(int)WhiteGrasshopper] = xpmPieceBitmap2[i][(int)WhiteKing+4];
1725 xpmPieceBitmap[i][(int)WhiteQueen] = xpmPieceBitmap2[i][(int)WhiteLance];
1728 if(gameInfo.variant == VariantGothic) {
1729 xpmPieceBitmap[i][(int)WhiteMarshall] = xpmPieceBitmap2[i][(int)WhiteSilver];
1733 // [HGM] why are thee ximMasks used at all? the ximPieceBitmaps seem to be never used!
1734 for(p=0; p<=(int)WhiteKing; p++)
1735 ximMaskPm[p] = ximMaskPm2[p]; // defaults
1736 if(gameInfo.variant == VariantShogi) {
1737 ximMaskPm[(int)WhiteCannon] = ximMaskPm2[(int)WhiteKing+1];
1738 ximMaskPm[(int)WhiteNightrider] = ximMaskPm2[(int)WhiteKing+2];
1739 ximMaskPm[(int)WhiteSilver] = ximMaskPm2[(int)WhiteKing+3];
1740 ximMaskPm[(int)WhiteGrasshopper] = ximMaskPm2[(int)WhiteKing+4];
1741 ximMaskPm[(int)WhiteQueen] = ximMaskPm2[(int)WhiteLance];
1744 if(gameInfo.variant == VariantGothic) {
1745 ximMaskPm[(int)WhiteMarshall] = ximMaskPm2[(int)WhiteSilver];
1751 for(i=0; i<2; i++) {
1753 for(p=0; p<=(int)WhiteKing; p++)
1754 pieceBitmap[i][p] = pieceBitmap2[i][p]; // defaults
1755 if(gameInfo.variant == VariantShogi) {
1756 pieceBitmap[i][(int)WhiteCannon] = pieceBitmap2[i][(int)WhiteKing+1];
1757 pieceBitmap[i][(int)WhiteNightrider] = pieceBitmap2[i][(int)WhiteKing+2];
1758 pieceBitmap[i][(int)WhiteSilver] = pieceBitmap2[i][(int)WhiteKing+3];
1759 pieceBitmap[i][(int)WhiteGrasshopper] = pieceBitmap2[i][(int)WhiteKing+4];
1760 pieceBitmap[i][(int)WhiteQueen] = pieceBitmap2[i][(int)WhiteLance];
1763 if(gameInfo.variant == VariantGothic) {
1764 pieceBitmap[i][(int)WhiteMarshall] = pieceBitmap2[i][(int)WhiteSilver];
1780 int i, j, clockFontPxlSize, coordFontPxlSize, fontPxlSize;
1781 XSetWindowAttributes window_attributes;
1783 Dimension timerWidth, boardWidth, boardHeight, w, h, sep, bor, wr, hr;
1784 XrmValue vFrom, vTo;
1785 XtGeometryResult gres;
1788 int forceMono = False;
1790 srandom(time(0)); // [HGM] book: make random truly random
1792 setbuf(stdout, NULL);
1793 setbuf(stderr, NULL);
1796 # if HAVE_LIBREADLINE
1797 /* install gnu-readline handler */
1798 rl_callback_handler_install("> ", ReadlineCompleteHandler);
1799 rl_readline_name="XBoard";
1802 if(argc > 1 && (!strcmp(argv[1], "-v" ) || !strcmp(argv[1], "--version" ))) {
1803 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
1807 programName = strrchr(argv[0], '/');
1808 if (programName == NULL)
1809 programName = argv[0];
1814 XtSetLanguageProc(NULL, NULL, NULL);
1815 bindtextdomain(PACKAGE, LOCALEDIR);
1816 textdomain(PACKAGE);
1820 XtAppInitialize(&appContext, "XBoard", shellOptions,
1821 XtNumber(shellOptions),
1822 &argc, argv, xboardResources, NULL, 0);
1823 appData.boardSize = "";
1824 InitAppData(ConvertToLine(argc, argv));
1826 if (p == NULL) p = "/tmp";
1827 i = strlen(p) + strlen("/.xboardXXXXXx.pgn") + 1;
1828 gameCopyFilename = (char*) malloc(i);
1829 gamePasteFilename = (char*) malloc(i);
1830 snprintf(gameCopyFilename,i, "%s/.xboard%05uc.pgn", p, getpid());
1831 snprintf(gamePasteFilename,i, "%s/.xboard%05up.pgn", p, getpid());
1833 XtGetApplicationResources(shellWidget, (XtPointer) &appData,
1834 clientResources, XtNumber(clientResources),
1837 { // [HGM] initstring: kludge to fix bad bug. expand '\n' characters in init string and computer string.
1838 static char buf[MSG_SIZ];
1839 EscapeExpand(buf, appData.initString);
1840 appData.initString = strdup(buf);
1841 EscapeExpand(buf, appData.secondInitString);
1842 appData.secondInitString = strdup(buf);
1843 EscapeExpand(buf, appData.firstComputerString);
1844 appData.firstComputerString = strdup(buf);
1845 EscapeExpand(buf, appData.secondComputerString);
1846 appData.secondComputerString = strdup(buf);
1849 if ((chessDir = (char *) getenv("CHESSDIR")) == NULL) {
1852 if (chdir(chessDir) != 0) {
1853 fprintf(stderr, _("%s: can't cd to CHESSDIR: "), programName);
1859 if (appData.debugMode && appData.nameOfDebugFile && strcmp(appData.nameOfDebugFile, "stderr")) {
1860 /* [DM] debug info to file [HGM] make the filename a command-line option, and allow it to remain stderr */
1861 if ((debugFP = fopen(appData.nameOfDebugFile, "w")) == NULL) {
1862 printf(_("Failed to open file '%s'\n"), appData.nameOfDebugFile);
1865 setbuf(debugFP, NULL);
1868 /* [HGM,HR] make sure board size is acceptable */
1869 if(appData.NrFiles > BOARD_FILES ||
1870 appData.NrRanks > BOARD_RANKS )
1871 DisplayFatalError(_("Recompile with larger BOARD_RANKS or BOARD_FILES to support this size"), 0, 2);
1874 /* This feature does not work; animation needs a rewrite */
1875 appData.highlightDragging = FALSE;
1879 xDisplay = XtDisplay(shellWidget);
1880 xScreen = DefaultScreen(xDisplay);
1881 wm_delete_window = XInternAtom(xDisplay, "WM_DELETE_WINDOW", True);
1883 gameInfo.variant = StringToVariant(appData.variant);
1884 InitPosition(FALSE);
1887 InitDrawingSizes(-1, 0); // [HGM] initsize: make this into a subroutine
1889 if (isdigit(appData.boardSize[0])) {
1890 i = sscanf(appData.boardSize, "%d,%d,%d,%d,%d,%d,%d", &squareSize,
1891 &lineGap, &clockFontPxlSize, &coordFontPxlSize,
1892 &fontPxlSize, &smallLayout, &tinyLayout);
1894 fprintf(stderr, _("%s: bad boardSize syntax %s\n"),
1895 programName, appData.boardSize);
1899 /* Find some defaults; use the nearest known size */
1900 SizeDefaults *szd, *nearest;
1901 int distance = 99999;
1902 nearest = szd = sizeDefaults;
1903 while (szd->name != NULL) {
1904 if (abs(szd->squareSize - squareSize) < distance) {
1906 distance = abs(szd->squareSize - squareSize);
1907 if (distance == 0) break;
1911 if (i < 2) lineGap = nearest->lineGap;
1912 if (i < 3) clockFontPxlSize = nearest->clockFontPxlSize;
1913 if (i < 4) coordFontPxlSize = nearest->coordFontPxlSize;
1914 if (i < 5) fontPxlSize = nearest->fontPxlSize;
1915 if (i < 6) smallLayout = nearest->smallLayout;
1916 if (i < 7) tinyLayout = nearest->tinyLayout;
1919 SizeDefaults *szd = sizeDefaults;
1920 if (*appData.boardSize == NULLCHAR) {
1921 while (DisplayWidth(xDisplay, xScreen) < szd->minScreenSize ||
1922 DisplayHeight(xDisplay, xScreen) < szd->minScreenSize) {
1925 if (szd->name == NULL) szd--;
1926 appData.boardSize = strdup(szd->name); // [HGM] settings: remember name for saving settings
1928 while (szd->name != NULL &&
1929 StrCaseCmp(szd->name, appData.boardSize) != 0) szd++;
1930 if (szd->name == NULL) {
1931 fprintf(stderr, _("%s: unrecognized boardSize name %s\n"),
1932 programName, appData.boardSize);
1936 squareSize = szd->squareSize;
1937 lineGap = szd->lineGap;
1938 clockFontPxlSize = szd->clockFontPxlSize;
1939 coordFontPxlSize = szd->coordFontPxlSize;
1940 fontPxlSize = szd->fontPxlSize;
1941 smallLayout = szd->smallLayout;
1942 tinyLayout = szd->tinyLayout;
1943 // [HGM] font: use defaults from settings file if available and not overruled
1945 if(!fontSet[CLOCK_FONT] && fontValid[CLOCK_FONT][squareSize])
1946 appData.clockFont = fontTable[CLOCK_FONT][squareSize];
1947 if(!fontSet[MESSAGE_FONT] && fontValid[MESSAGE_FONT][squareSize])
1948 appData.font = fontTable[MESSAGE_FONT][squareSize];
1949 if(!fontSet[COORD_FONT] && fontValid[COORD_FONT][squareSize])
1950 appData.coordFont = fontTable[COORD_FONT][squareSize];
1952 /* Now, using squareSize as a hint, find a good XPM/XIM set size */
1953 if (strlen(appData.pixmapDirectory) > 0) {
1954 p = ExpandPathName(appData.pixmapDirectory);
1956 fprintf(stderr, _("Error expanding path name \"%s\"\n"),
1957 appData.pixmapDirectory);
1960 if (appData.debugMode) {
1961 fprintf(stderr, _("\
1962 XBoard square size (hint): %d\n\
1963 %s fulldir:%s:\n"), squareSize, IMAGE_EXT, p);
1965 squareSize = xpm_closest_to(p, squareSize, IMAGE_EXT);
1966 if (appData.debugMode) {
1967 fprintf(stderr, _("Closest %s size: %d\n"), IMAGE_EXT, squareSize);
1971 /* [HR] height treated separately (hacked) */
1972 boardWidth = lineGap + BOARD_WIDTH * (squareSize + lineGap);
1973 boardHeight = lineGap + BOARD_HEIGHT * (squareSize + lineGap);
1974 if (appData.showJail == 1) {
1975 /* Jail on top and bottom */
1976 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1977 XtSetArg(boardArgs[2], XtNheight,
1978 boardHeight + 2*(lineGap + squareSize));
1979 } else if (appData.showJail == 2) {
1981 XtSetArg(boardArgs[1], XtNwidth,
1982 boardWidth + 2*(lineGap + squareSize));
1983 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1986 XtSetArg(boardArgs[1], XtNwidth, boardWidth);
1987 XtSetArg(boardArgs[2], XtNheight, boardHeight);
1991 * Determine what fonts to use.
1993 appData.clockFont = FindFont(appData.clockFont, clockFontPxlSize);
1994 clockFontID = XLoadFont(xDisplay, appData.clockFont);
1995 clockFontStruct = XQueryFont(xDisplay, clockFontID);
1996 appData.coordFont = FindFont(appData.coordFont, coordFontPxlSize);
1997 coordFontID = XLoadFont(xDisplay, appData.coordFont);
1998 coordFontStruct = XQueryFont(xDisplay, coordFontID);
1999 appData.font = FindFont(appData.font, fontPxlSize);
2000 countFontID = XLoadFont(xDisplay, appData.coordFont); // [HGM] holdings
2001 countFontStruct = XQueryFont(xDisplay, countFontID);
2002 // appData.font = FindFont(appData.font, fontPxlSize);
2004 xdb = XtDatabase(xDisplay);
2005 XrmPutStringResource(&xdb, "*font", appData.font);
2008 * Detect if there are not enough colors available and adapt.
2010 if (DefaultDepth(xDisplay, xScreen) <= 2) {
2011 appData.monoMode = True;
2014 if (!appData.monoMode) {
2015 vFrom.addr = (caddr_t) appData.lightSquareColor;
2016 vFrom.size = strlen(appData.lightSquareColor);
2017 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2018 if (vTo.addr == NULL) {
2019 appData.monoMode = True;
2022 lightSquareColor = *(Pixel *) vTo.addr;
2025 if (!appData.monoMode) {
2026 vFrom.addr = (caddr_t) appData.darkSquareColor;
2027 vFrom.size = strlen(appData.darkSquareColor);
2028 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2029 if (vTo.addr == NULL) {
2030 appData.monoMode = True;
2033 darkSquareColor = *(Pixel *) vTo.addr;
2036 if (!appData.monoMode) {
2037 vFrom.addr = (caddr_t) appData.whitePieceColor;
2038 vFrom.size = strlen(appData.whitePieceColor);
2039 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2040 if (vTo.addr == NULL) {
2041 appData.monoMode = True;
2044 whitePieceColor = *(Pixel *) vTo.addr;
2047 if (!appData.monoMode) {
2048 vFrom.addr = (caddr_t) appData.blackPieceColor;
2049 vFrom.size = strlen(appData.blackPieceColor);
2050 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2051 if (vTo.addr == NULL) {
2052 appData.monoMode = True;
2055 blackPieceColor = *(Pixel *) vTo.addr;
2059 if (!appData.monoMode) {
2060 vFrom.addr = (caddr_t) appData.highlightSquareColor;
2061 vFrom.size = strlen(appData.highlightSquareColor);
2062 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2063 if (vTo.addr == NULL) {
2064 appData.monoMode = True;
2067 highlightSquareColor = *(Pixel *) vTo.addr;
2071 if (!appData.monoMode) {
2072 vFrom.addr = (caddr_t) appData.premoveHighlightColor;
2073 vFrom.size = strlen(appData.premoveHighlightColor);
2074 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2075 if (vTo.addr == NULL) {
2076 appData.monoMode = True;
2079 premoveHighlightColor = *(Pixel *) vTo.addr;
2084 fprintf(stderr, _("%s: too few colors available; trying monochrome mode\n"),
2087 if (appData.bitmapDirectory == NULL ||
2088 appData.bitmapDirectory[0] == NULLCHAR)
2089 appData.bitmapDirectory = DEF_BITMAP_DIR;
2092 if (appData.lowTimeWarning && !appData.monoMode) {
2093 vFrom.addr = (caddr_t) appData.lowTimeWarningColor;
2094 vFrom.size = strlen(appData.lowTimeWarningColor);
2095 XtConvert(shellWidget, XtRString, &vFrom, XtRPixel, &vTo);
2096 if (vTo.addr == NULL)
2097 appData.monoMode = True;
2099 lowTimeWarningColor = *(Pixel *) vTo.addr;
2102 if (appData.monoMode && appData.debugMode) {
2103 fprintf(stderr, _("white pixel = 0x%lx, black pixel = 0x%lx\n"),
2104 (unsigned long) XWhitePixel(xDisplay, xScreen),
2105 (unsigned long) XBlackPixel(xDisplay, xScreen));
2108 if (parse_cpair(ColorShout, appData.colorShout) < 0 ||
2109 parse_cpair(ColorSShout, appData.colorSShout) < 0 ||
2110 parse_cpair(ColorChannel1, appData.colorChannel1) < 0 ||
2111 parse_cpair(ColorChannel, appData.colorChannel) < 0 ||
2112 parse_cpair(ColorKibitz, appData.colorKibitz) < 0 ||
2113 parse_cpair(ColorTell, appData.colorTell) < 0 ||
2114 parse_cpair(ColorChallenge, appData.colorChallenge) < 0 ||
2115 parse_cpair(ColorRequest, appData.colorRequest) < 0 ||
2116 parse_cpair(ColorSeek, appData.colorSeek) < 0 ||
2117 parse_cpair(ColorNormal, appData.colorNormal) < 0)
2119 if (appData.colorize) {
2121 _("%s: can't parse color names; disabling colorization\n"),
2124 appData.colorize = FALSE;
2126 textColors[ColorNone].fg = textColors[ColorNone].bg = -1;
2127 textColors[ColorNone].attr = 0;
2129 XtAppAddActions(appContext, boardActions, XtNumber(boardActions));
2135 layoutName = "tinyLayout";
2136 } else if (smallLayout) {
2137 layoutName = "smallLayout";
2139 layoutName = "normalLayout";
2141 /* Outer layoutWidget is there only to provide a name for use in
2142 resources that depend on the layout style */
2144 XtCreateManagedWidget(layoutName, formWidgetClass, shellWidget,
2145 layoutArgs, XtNumber(layoutArgs));
2147 XtCreateManagedWidget("form", formWidgetClass, layoutWidget,
2148 formArgs, XtNumber(formArgs));
2149 XtSetArg(args[0], XtNdefaultDistance, &sep);
2150 XtGetValues(formWidget, args, 1);
2153 widgetList[j++] = menuBarWidget = CreateMenuBar(menuBar);
2154 XtSetArg(args[0], XtNtop, XtChainTop);
2155 XtSetArg(args[1], XtNbottom, XtChainTop);
2156 XtSetArg(args[2], XtNright, XtChainLeft);
2157 XtSetValues(menuBarWidget, args, 3);
2159 widgetList[j++] = whiteTimerWidget =
2160 XtCreateWidget("whiteTime", labelWidgetClass,
2161 formWidget, timerArgs, XtNumber(timerArgs));
2162 XtSetArg(args[0], XtNfont, clockFontStruct);
2163 XtSetArg(args[1], XtNtop, XtChainTop);
2164 XtSetArg(args[2], XtNbottom, XtChainTop);
2165 XtSetValues(whiteTimerWidget, args, 3);
2167 widgetList[j++] = blackTimerWidget =
2168 XtCreateWidget("blackTime", labelWidgetClass,
2169 formWidget, timerArgs, XtNumber(timerArgs));
2170 XtSetArg(args[0], XtNfont, clockFontStruct);
2171 XtSetArg(args[1], XtNtop, XtChainTop);
2172 XtSetArg(args[2], XtNbottom, XtChainTop);
2173 XtSetValues(blackTimerWidget, args, 3);
2175 if (appData.titleInWindow) {
2176 widgetList[j++] = titleWidget =
2177 XtCreateWidget("title", labelWidgetClass, formWidget,
2178 titleArgs, XtNumber(titleArgs));
2179 XtSetArg(args[0], XtNtop, XtChainTop);
2180 XtSetArg(args[1], XtNbottom, XtChainTop);
2181 XtSetValues(titleWidget, args, 2);
2184 if (appData.showButtonBar) {
2185 widgetList[j++] = buttonBarWidget = CreateButtonBar(buttonBar);
2186 XtSetArg(args[0], XtNleft, XtChainRight); // [HGM] glue to right window edge
2187 XtSetArg(args[1], XtNright, XtChainRight); // for good run-time sizing
2188 XtSetArg(args[2], XtNtop, XtChainTop);
2189 XtSetArg(args[3], XtNbottom, XtChainTop);
2190 XtSetValues(buttonBarWidget, args, 4);
2193 widgetList[j++] = messageWidget =
2194 XtCreateWidget("message", labelWidgetClass, formWidget,
2195 messageArgs, XtNumber(messageArgs));
2196 XtSetArg(args[0], XtNtop, XtChainTop);
2197 XtSetArg(args[1], XtNbottom, XtChainTop);
2198 XtSetValues(messageWidget, args, 2);
2200 widgetList[j++] = boardWidget =
2201 XtCreateWidget("board", widgetClass, formWidget, boardArgs,
2202 XtNumber(boardArgs));
2204 XtManageChildren(widgetList, j);
2206 timerWidth = (boardWidth - sep) / 2;
2207 XtSetArg(args[0], XtNwidth, timerWidth);
2208 XtSetValues(whiteTimerWidget, args, 1);
2209 XtSetValues(blackTimerWidget, args, 1);
2211 XtSetArg(args[0], XtNbackground, &timerBackgroundPixel);
2212 XtSetArg(args[1], XtNforeground, &timerForegroundPixel);
2213 XtGetValues(whiteTimerWidget, args, 2);
2215 if (appData.showButtonBar) {
2216 XtSetArg(args[0], XtNbackground, &buttonBackgroundPixel);
2217 XtSetArg(args[1], XtNforeground, &buttonForegroundPixel);
2218 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
2222 * formWidget uses these constraints but they are stored
2226 XtSetArg(args[i], XtNfromHoriz, 0); i++;
2227 XtSetValues(menuBarWidget, args, i);
2228 if (appData.titleInWindow) {
2231 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2232 XtSetValues(whiteTimerWidget, args, i);
2234 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2235 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2236 XtSetValues(blackTimerWidget, args, i);
2238 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2239 XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
2240 XtSetValues(titleWidget, args, i);
2242 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2243 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2244 XtSetValues(messageWidget, args, i);
2245 if (appData.showButtonBar) {
2247 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2248 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2249 XtSetValues(buttonBarWidget, args, i);
2253 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2254 XtSetValues(whiteTimerWidget, args, i);
2256 XtSetArg(args[i], XtNfromVert, titleWidget); i++;
2257 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2258 XtSetValues(blackTimerWidget, args, i);
2260 XtSetArg(args[i], XtNfromHoriz, menuBarWidget); i++;
2261 XtSetValues(titleWidget, args, i);
2263 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2264 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2265 XtSetValues(messageWidget, args, i);
2266 if (appData.showButtonBar) {
2268 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2269 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2270 XtSetValues(buttonBarWidget, args, i);
2275 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2276 XtSetValues(whiteTimerWidget, args, i);
2278 XtSetArg(args[i], XtNfromVert, menuBarWidget); i++;
2279 XtSetArg(args[i], XtNfromHoriz, whiteTimerWidget); i++;
2280 XtSetValues(blackTimerWidget, args, i);
2282 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2283 XtSetArg(args[i], XtNresizable, (XtArgVal) True); i++;
2284 XtSetValues(messageWidget, args, i);
2285 if (appData.showButtonBar) {
2287 XtSetArg(args[i], XtNfromVert, whiteTimerWidget); i++;
2288 XtSetArg(args[i], XtNfromHoriz, messageWidget); i++;
2289 XtSetValues(buttonBarWidget, args, i);
2293 XtSetArg(args[0], XtNfromVert, messageWidget);
2294 XtSetArg(args[1], XtNtop, XtChainTop);
2295 XtSetArg(args[2], XtNbottom, XtChainBottom);
2296 XtSetArg(args[3], XtNleft, XtChainLeft);
2297 XtSetArg(args[4], XtNright, XtChainRight);
2298 XtSetValues(boardWidget, args, 5);
2300 XtRealizeWidget(shellWidget);
2303 XtSetArg(args[0], XtNx, wpMain.x);
2304 XtSetArg(args[1], XtNy, wpMain.y);
2305 XtSetValues(shellWidget, args, 2);
2309 * Correct the width of the message and title widgets.
2310 * It is not known why some systems need the extra fudge term.
2311 * The value "2" is probably larger than needed.
2313 XawFormDoLayout(formWidget, False);
2315 #define WIDTH_FUDGE 2
2317 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2318 XtSetArg(args[i], XtNheight, &h); i++;
2319 XtGetValues(messageWidget, args, i);
2320 if (appData.showButtonBar) {
2322 XtSetArg(args[i], XtNwidth, &w); i++;
2323 XtGetValues(buttonBarWidget, args, i);
2324 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2326 w = boardWidth - 2*bor + 1; /*!! +1 compensates for kludge below */
2329 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2330 if (gres != XtGeometryYes && appData.debugMode) {
2331 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2332 programName, gres, w, h, wr, hr);
2335 /* !! Horrible hack to work around bug in XFree86 4.0.1 (X11R6.4.3) */
2336 /* The size used for the child widget in layout lags one resize behind
2337 its true size, so we resize a second time, 1 pixel smaller. Yeech! */
2339 gres = XtMakeResizeRequest(messageWidget, w, h, &wr, &hr);
2340 if (gres != XtGeometryYes && appData.debugMode) {
2341 fprintf(stderr, _("%s: messageWidget geometry error %d %d %d %d %d\n"),
2342 programName, gres, w, h, wr, hr);
2345 XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
2346 XtSetArg(args[1], XtNright, XtChainRight);
2347 XtSetValues(messageWidget, args, 2);
2349 if (appData.titleInWindow) {
2351 XtSetArg(args[i], XtNborderWidth, &bor); i++;
2352 XtSetArg(args[i], XtNheight, &h); i++;
2353 XtGetValues(titleWidget, args, i);
2355 w = boardWidth - 2*bor;
2357 XtSetArg(args[0], XtNwidth, &w);
2358 XtGetValues(menuBarWidget, args, 1);
2359 w = boardWidth - w - sep - 2*bor - WIDTH_FUDGE;
2362 gres = XtMakeResizeRequest(titleWidget, w, h, &wr, &hr);
2363 if (gres != XtGeometryYes && appData.debugMode) {
2365 _("%s: titleWidget geometry error %d %d %d %d %d\n"),
2366 programName, gres, w, h, wr, hr);
2369 XawFormDoLayout(formWidget, True);
2371 xBoardWindow = XtWindow(boardWidget);
2373 // [HGM] it seems the layout code ends here, but perhaps the color stuff is size independent and would
2374 // not need to go into InitDrawingSizes().
2378 * Create X checkmark bitmap and initialize option menu checks.
2380 ReadBitmap(&xMarkPixmap, "checkmark.bm",
2381 checkmark_bits, checkmark_width, checkmark_height);
2382 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
2383 if (appData.alwaysPromoteToQueen) {
2384 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
2387 if (appData.animateDragging) {
2388 XtSetValues(XtNameToWidget(menuBarWidget,
2389 "menuOptions.Animate Dragging"),
2392 if (appData.animate) {
2393 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
2396 if (appData.autoComment) {
2397 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
2400 if (appData.autoCallFlag) {
2401 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
2404 if (appData.autoFlipView) {
2405 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Auto Flip View"),
2408 if (appData.autoObserve) {
2409 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
2412 if (appData.autoRaiseBoard) {
2413 XtSetValues(XtNameToWidget(menuBarWidget,
2414 "menuOptions.Auto Raise Board"), args, 1);
2416 if (appData.autoSaveGames) {
2417 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2420 if (appData.saveGameFile[0] != NULLCHAR) {
2421 /* Can't turn this off from menu */
2422 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2424 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
2428 if (appData.blindfold) {
2429 XtSetValues(XtNameToWidget(menuBarWidget,
2430 "menuOptions.Blindfold"), args, 1);
2432 if (appData.flashCount > 0) {
2433 XtSetValues(XtNameToWidget(menuBarWidget,
2434 "menuOptions.Flash Moves"),
2437 if (appData.getMoveList) {
2438 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
2442 if (appData.highlightDragging) {
2443 XtSetValues(XtNameToWidget(menuBarWidget,
2444 "menuOptions.Highlight Dragging"),
2448 if (appData.highlightLastMove) {
2449 XtSetValues(XtNameToWidget(menuBarWidget,
2450 "menuOptions.Highlight Last Move"),
2453 if (appData.icsAlarm) {
2454 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.ICS Alarm"),
2457 if (appData.ringBellAfterMoves) {
2458 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
2461 if (appData.oldSaveStyle) {
2462 XtSetValues(XtNameToWidget(menuBarWidget,
2463 "menuOptions.Old Save Style"), args, 1);
2465 if (appData.periodicUpdates) {
2466 XtSetValues(XtNameToWidget(menuBarWidget,
2467 "menuOptions.Periodic Updates"), args, 1);
2469 if (appData.ponderNextMove) {
2470 XtSetValues(XtNameToWidget(menuBarWidget,
2471 "menuOptions.Ponder Next Move"), args, 1);
2473 if (appData.popupExitMessage) {
2474 XtSetValues(XtNameToWidget(menuBarWidget,
2475 "menuOptions.Popup Exit Message"), args, 1);
2477 if (appData.popupMoveErrors) {
2478 XtSetValues(XtNameToWidget(menuBarWidget,
2479 "menuOptions.Popup Move Errors"), args, 1);
2481 if (appData.premove) {
2482 XtSetValues(XtNameToWidget(menuBarWidget,
2483 "menuOptions.Premove"), args, 1);
2485 if (appData.quietPlay) {
2486 XtSetValues(XtNameToWidget(menuBarWidget,
2487 "menuOptions.Quiet Play"), args, 1);
2489 if (appData.showCoords) {
2490 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
2493 if (appData.hideThinkingFromHuman) {
2494 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
2497 if (appData.testLegality) {
2498 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Test Legality"),
2501 if (saveSettingsOnExit) {
2502 XtSetValues(XtNameToWidget(menuBarWidget,"menuOptions.Save Settings on Exit"),
2509 ReadBitmap(&wIconPixmap, "icon_white.bm",
2510 icon_white_bits, icon_white_width, icon_white_height);
2511 ReadBitmap(&bIconPixmap, "icon_black.bm",
2512 icon_black_bits, icon_black_width, icon_black_height);
2513 iconPixmap = wIconPixmap;
2515 XtSetArg(args[i], XtNiconPixmap, iconPixmap); i++;
2516 XtSetValues(shellWidget, args, i);
2519 * Create a cursor for the board widget.
2521 window_attributes.cursor = XCreateFontCursor(xDisplay, XC_hand2);
2522 XChangeWindowAttributes(xDisplay, xBoardWindow,
2523 CWCursor, &window_attributes);
2526 * Inhibit shell resizing.
2528 shellArgs[0].value = (XtArgVal) &w;
2529 shellArgs[1].value = (XtArgVal) &h;
2530 XtGetValues(shellWidget, shellArgs, 2);
2531 shellArgs[4].value = shellArgs[2].value = w;
2532 shellArgs[5].value = shellArgs[3].value = h;
2533 XtSetValues(shellWidget, &shellArgs[2], 4);
2534 marginW = w - boardWidth; // [HGM] needed to set new shellWidget size when we resize board
2535 marginH = h - boardHeight;
2537 CatchDeleteWindow(shellWidget, "QuitProc");
2542 if (appData.bitmapDirectory[0] != NULLCHAR) {
2549 /* Create regular pieces */
2550 if (!useImages) CreatePieces();
2555 if (appData.animate || appData.animateDragging)
2558 XtAugmentTranslations(formWidget,
2559 XtParseTranslationTable(globalTranslations));
2560 XtAugmentTranslations(boardWidget,
2561 XtParseTranslationTable(boardTranslations));
2562 XtAugmentTranslations(whiteTimerWidget,
2563 XtParseTranslationTable(whiteTranslations));
2564 XtAugmentTranslations(blackTimerWidget,
2565 XtParseTranslationTable(blackTranslations));
2567 /* Why is the following needed on some versions of X instead
2568 * of a translation? */
2569 XtAddEventHandler(boardWidget, ExposureMask|PointerMotionMask, False,
2570 (XtEventHandler) EventProc, NULL);
2573 /* [AS] Restore layout */
2574 if( wpMoveHistory.visible ) {
2578 if( wpEvalGraph.visible )
2583 if( wpEngineOutput.visible ) {
2584 EngineOutputPopUp();
2589 if (errorExitStatus == -1) {
2590 if (appData.icsActive) {
2591 /* We now wait until we see "login:" from the ICS before
2592 sending the logon script (problems with timestamp otherwise) */
2593 /*ICSInitScript();*/
2594 if (appData.icsInputBox) ICSInputBoxPopUp();
2598 signal(SIGWINCH, TermSizeSigHandler);
2600 signal(SIGINT, IntSigHandler);
2601 signal(SIGTERM, IntSigHandler);
2602 if (*appData.cmailGameName != NULLCHAR) {
2603 signal(SIGUSR1, CmailSigHandler);
2606 gameInfo.boardWidth = 0; // [HGM] pieces: kludge to ensure InitPosition() calls InitDrawingSizes()
2608 XtSetKeyboardFocus(shellWidget, formWidget);
2610 XtAppMainLoop(appContext);
2611 if (appData.debugMode) fclose(debugFP); // [DM] debug
2618 if (appData.icsActive && oldICSInteractionTitle != NULL) {
2619 DisplayIcsInteractionTitle(oldICSInteractionTitle);
2621 if (saveSettingsOnExit) SaveSettings(settingsFileName);
2622 unlink(gameCopyFilename);
2623 unlink(gamePasteFilename);
2625 # if HAVE_LIBREADLINE
2626 /* remove gnu-readline handler. */
2627 rl_callback_handler_remove();
2633 RETSIGTYPE TermSizeSigHandler(int sig)
2646 CmailSigHandler(sig)
2652 signal(SIGUSR1, SIG_IGN); /* suspend handler */
2654 /* Activate call-back function CmailSigHandlerCallBack() */
2655 OutputToProcess(cmailPR, (char *)(&dummy), sizeof(int), &error);
2657 signal(SIGUSR1, CmailSigHandler); /* re-activate handler */
2661 CmailSigHandlerCallBack(isr, closure, message, count, error)
2669 ReloadCmailMsgEvent(TRUE); /* Reload cmail msg */
2671 /**** end signal code ****/
2677 /* try to open the icsLogon script, either in the location given
2678 * or in the users HOME directory
2685 f = fopen(appData.icsLogon, "r");
2688 homedir = getenv("HOME");
2689 if (homedir != NULL)
2691 safeStrCpy(buf, homedir, sizeof(buf)/sizeof(buf[0]) );
2692 strncat(buf, "/", MSG_SIZ - strlen(buf) - 1);
2693 strncat(buf, appData.icsLogon, MSG_SIZ - strlen(buf) - 1);
2694 f = fopen(buf, "r");
2699 ProcessICSInitScript(f);
2701 printf("Warning: Couldn't open icsLogon file (checked %s and %s).\n", appData.icsLogon, buf);
2710 EditCommentPopDown();
2725 if (!menuBarWidget) return;
2726 w = XtNameToWidget(menuBarWidget, "menuStep.Revert");
2728 DisplayError("menuStep.Revert", 0);
2730 XtSetSensitive(w, !grey);
2732 w = XtNameToWidget(menuBarWidget, "menuStep.Annotate");
2734 DisplayError("menuStep.Annotate", 0);
2736 XtSetSensitive(w, !grey);
2741 SetMenuEnables(enab)
2745 if (!menuBarWidget) return;
2746 while (enab->name != NULL) {
2747 w = XtNameToWidget(menuBarWidget, enab->name);
2749 DisplayError(enab->name, 0);
2751 XtSetSensitive(w, enab->value);
2757 Enables icsEnables[] = {
2758 { "menuFile.Mail Move", False },
2759 { "menuFile.Reload CMail Message", False },
2760 { "menuMode.Machine Black", False },
2761 { "menuMode.Machine White", False },
2762 { "menuMode.Analysis Mode", False },
2763 { "menuMode.Analyze File", False },
2764 { "menuMode.Two Machines", False },
2766 { "menuHelp.Hint", False },
2767 { "menuHelp.Book", False },
2768 { "menuStep.Move Now", False },
2769 { "menuOptions.Periodic Updates", False },
2770 { "menuOptions.Hide Thinking", False },
2771 { "menuOptions.Ponder Next Move", False },
2773 { "menuStep.Annotate", False },
2777 Enables ncpEnables[] = {
2778 { "menuFile.Mail Move", False },
2779 { "menuFile.Reload CMail Message", False },
2780 { "menuMode.Machine White", False },
2781 { "menuMode.Machine Black", False },
2782 { "menuMode.Analysis Mode", False },
2783 { "menuMode.Analyze File", False },
2784 { "menuMode.Two Machines", False },
2785 { "menuMode.ICS Client", False },
2786 { "menuMode.ICS Input Box", False },
2787 { "Action", False },
2788 { "menuStep.Revert", False },
2789 { "menuStep.Annotate", False },
2790 { "menuStep.Move Now", False },
2791 { "menuStep.Retract Move", False },
2792 { "menuOptions.Auto Comment", False },
2793 { "menuOptions.Auto Flag", False },
2794 { "menuOptions.Auto Flip View", False },
2795 { "menuOptions.Auto Observe", False },
2796 { "menuOptions.Auto Raise Board", False },
2797 { "menuOptions.Get Move List", False },
2798 { "menuOptions.ICS Alarm", False },
2799 { "menuOptions.Move Sound", False },
2800 { "menuOptions.Quiet Play", False },
2801 { "menuOptions.Hide Thinking", False },
2802 { "menuOptions.Periodic Updates", False },
2803 { "menuOptions.Ponder Next Move", False },
2804 { "menuHelp.Hint", False },
2805 { "menuHelp.Book", False },
2809 Enables gnuEnables[] = {
2810 { "menuMode.ICS Client", False },
2811 { "menuMode.ICS Input Box", False },
2812 { "menuAction.Accept", False },
2813 { "menuAction.Decline", False },
2814 { "menuAction.Rematch", False },
2815 { "menuAction.Adjourn", False },
2816 { "menuAction.Stop Examining", False },
2817 { "menuAction.Stop Observing", False },
2818 { "menuAction.Upload to Examine", False },
2819 { "menuStep.Revert", False },
2820 { "menuStep.Annotate", False },
2821 { "menuOptions.Auto Comment", False },
2822 { "menuOptions.Auto Observe", False },
2823 { "menuOptions.Auto Raise Board", False },
2824 { "menuOptions.Get Move List", False },
2825 { "menuOptions.Premove", False },
2826 { "menuOptions.Quiet Play", False },
2828 /* The next two options rely on SetCmailMode being called *after* */
2829 /* SetGNUMode so that when GNU is being used to give hints these */
2830 /* menu options are still available */
2832 { "menuFile.Mail Move", False },
2833 { "menuFile.Reload CMail Message", False },
2837 Enables cmailEnables[] = {
2839 { "menuAction.Call Flag", False },
2840 { "menuAction.Draw", True },
2841 { "menuAction.Adjourn", False },
2842 { "menuAction.Abort", False },
2843 { "menuAction.Stop Observing", False },
2844 { "menuAction.Stop Examining", False },
2845 { "menuFile.Mail Move", True },
2846 { "menuFile.Reload CMail Message", True },
2850 Enables trainingOnEnables[] = {
2851 { "menuMode.Edit Comment", False },
2852 { "menuMode.Pause", False },
2853 { "menuStep.Forward", False },
2854 { "menuStep.Backward", False },
2855 { "menuStep.Forward to End", False },
2856 { "menuStep.Back to Start", False },
2857 { "menuStep.Move Now", False },
2858 { "menuStep.Truncate Game", False },
2862 Enables trainingOffEnables[] = {
2863 { "menuMode.Edit Comment", True },
2864 { "menuMode.Pause", True },
2865 { "menuStep.Forward", True },
2866 { "menuStep.Backward", True },
2867 { "menuStep.Forward to End", True },
2868 { "menuStep.Back to Start", True },
2869 { "menuStep.Move Now", True },
2870 { "menuStep.Truncate Game", True },
2874 Enables machineThinkingEnables[] = {
2875 { "menuFile.Load Game", False },
2876 { "menuFile.Load Next Game", False },
2877 { "menuFile.Load Previous Game", False },
2878 { "menuFile.Reload Same Game", False },
2879 { "menuFile.Paste Game", False },
2880 { "menuFile.Load Position", False },
2881 { "menuFile.Load Next Position", False },
2882 { "menuFile.Load Previous Position", False },
2883 { "menuFile.Reload Same Position", False },
2884 { "menuFile.Paste Position", False },
2885 { "menuMode.Machine White", False },
2886 { "menuMode.Machine Black", False },
2887 { "menuMode.Two Machines", False },
2888 { "menuStep.Retract Move", False },
2892 Enables userThinkingEnables[] = {
2893 { "menuFile.Load Game", True },
2894 { "menuFile.Load Next Game", True },
2895 { "menuFile.Load Previous Game", True },
2896 { "menuFile.Reload Same Game", True },
2897 { "menuFile.Paste Game", True },
2898 { "menuFile.Load Position", True },
2899 { "menuFile.Load Next Position", True },
2900 { "menuFile.Load Previous Position", True },
2901 { "menuFile.Reload Same Position", True },
2902 { "menuFile.Paste Position", True },
2903 { "menuMode.Machine White", True },
2904 { "menuMode.Machine Black", True },
2905 { "menuMode.Two Machines", True },
2906 { "menuStep.Retract Move", True },
2912 SetMenuEnables(icsEnables);
2915 if (appData.zippyPlay && !appData.noChessProgram) /* [DM] icsEngineAnalyze */
2916 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Analysis Mode"), True);
2923 SetMenuEnables(ncpEnables);
2929 SetMenuEnables(gnuEnables);
2935 SetMenuEnables(cmailEnables);
2941 SetMenuEnables(trainingOnEnables);
2942 if (appData.showButtonBar) {
2943 XtSetSensitive(buttonBarWidget, False);
2949 SetTrainingModeOff()
2951 SetMenuEnables(trainingOffEnables);
2952 if (appData.showButtonBar) {
2953 XtSetSensitive(buttonBarWidget, True);
2958 SetUserThinkingEnables()
2960 if (appData.noChessProgram) return;
2961 SetMenuEnables(userThinkingEnables);
2965 SetMachineThinkingEnables()
2967 if (appData.noChessProgram) return;
2968 SetMenuEnables(machineThinkingEnables);
2970 case MachinePlaysBlack:
2971 case MachinePlaysWhite:
2972 case TwoMachinesPlay:
2973 XtSetSensitive(XtNameToWidget(menuBarWidget,
2974 ModeToWidgetName(gameMode)), True);
2981 // [HGM] code borrowed from winboard.c (which should thus go to backend.c!)
2982 #define HISTORY_SIZE 64
\r
2983 static char *history[HISTORY_SIZE];
\r
2984 int histIn = 0, histP = 0;
\r
2987 SaveInHistory(char *cmd)
\r
2989 if (history[histIn] != NULL) {
\r
2990 free(history[histIn]);
\r
2991 history[histIn] = NULL;
\r
2993 if (*cmd == NULLCHAR) return;
\r
2994 history[histIn] = StrSave(cmd);
\r
2995 histIn = (histIn + 1) % HISTORY_SIZE;
\r
2996 if (history[histIn] != NULL) {
\r
2997 free(history[histIn]);
\r
2998 history[histIn] = NULL;
\r
3004 PrevInHistory(char *cmd)
\r
3007 if (histP == histIn) {
\r
3008 if (history[histIn] != NULL) free(history[histIn]);
\r
3009 history[histIn] = StrSave(cmd);
\r
3011 newhp = (histP - 1 + HISTORY_SIZE) % HISTORY_SIZE;
\r
3012 if (newhp == histIn || history[newhp] == NULL) return NULL;
\r
3014 return history[histP];
\r
3020 if (histP == histIn) return NULL;
\r
3021 histP = (histP + 1) % HISTORY_SIZE;
\r
3022 return history[histP];
\r
3024 // end of borrowed code
\r
3026 #define Abs(n) ((n)<0 ? -(n) : (n))
3029 * Find a font that matches "pattern" that is as close as
3030 * possible to the targetPxlSize. Prefer fonts that are k
3031 * pixels smaller to fonts that are k pixels larger. The
3032 * pattern must be in the X Consortium standard format,
3033 * e.g. "-*-helvetica-bold-r-normal--*-*-*-*-*-*-*-*".
3034 * The return value should be freed with XtFree when no
3038 FindFont(pattern, targetPxlSize)
3042 char **fonts, *p, *best, *scalable, *scalableTail;
3043 int i, j, nfonts, minerr, err, pxlSize;
3046 char **missing_list;
3048 char *def_string, *base_fnt_lst, strInt[3];
3050 XFontStruct **fnt_list;
3052 base_fnt_lst = calloc(1, strlen(pattern) + 3);
3053 snprintf(strInt, sizeof(strInt)/sizeof(strInt[0]), "%d", targetPxlSize);
3054 p = strstr(pattern, "--");
3055 strncpy(base_fnt_lst, pattern, p - pattern + 2);
3056 strcat(base_fnt_lst, strInt);
3057 strcat(base_fnt_lst, strchr(p + 2, '-'));
3059 if ((fntSet = XCreateFontSet(xDisplay,
3063 &def_string)) == NULL) {
3065 fprintf(stderr, _("Unable to create font set.\n"));
3069 nfonts = XFontsOfFontSet(fntSet, &fnt_list, &fonts);
3071 fonts = XListFonts(xDisplay, pattern, 999999, &nfonts);
3073 fprintf(stderr, _("%s: no fonts match pattern %s\n"),
3074 programName, pattern);
3082 for (i=0; i<nfonts; i++) {
3085 if (*p != '-') continue;
3087 if (*p == NULLCHAR) break;
3088 if (*p++ == '-') j++;
3090 if (j < 7) continue;
3093 scalable = fonts[i];
3096 err = pxlSize - targetPxlSize;
3097 if (Abs(err) < Abs(minerr) ||
3098 (minerr > 0 && err < 0 && -err == minerr)) {
3104 if (scalable && Abs(minerr) > appData.fontSizeTolerance) {
3105 /* If the error is too big and there is a scalable font,
3106 use the scalable font. */
3107 int headlen = scalableTail - scalable;
3108 p = (char *) XtMalloc(strlen(scalable) + 10);
3109 while (isdigit(*scalableTail)) scalableTail++;
3110 sprintf(p, "%.*s%d%s", headlen, scalable, targetPxlSize, scalableTail);
3112 p = (char *) XtMalloc(strlen(best) + 2);
3113 safeStrCpy(p, best, strlen(best)+1 );
3115 if (appData.debugMode) {
3116 fprintf(debugFP, _("resolved %s at pixel size %d\n to %s\n"),
3117 pattern, targetPxlSize, p);
3120 if (missing_count > 0)
3121 XFreeStringList(missing_list);
3122 XFreeFontSet(xDisplay, fntSet);
3124 XFreeFontNames(fonts);
3131 XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground
3132 | GCBackground | GCFunction | GCPlaneMask;
3133 XGCValues gc_values;
3136 gc_values.plane_mask = AllPlanes;
3137 gc_values.line_width = lineGap;
3138 gc_values.line_style = LineSolid;
3139 gc_values.function = GXcopy;
3141 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3142 gc_values.background = XBlackPixel(xDisplay, xScreen);
3143 lineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3145 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3146 gc_values.background = XWhitePixel(xDisplay, xScreen);
3147 coordGC = XtGetGC(shellWidget, value_mask, &gc_values);
3148 XSetFont(xDisplay, coordGC, coordFontID);
3150 // [HGM] make font for holdings counts (white on black0
3151 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3152 gc_values.background = XBlackPixel(xDisplay, xScreen);
3153 countGC = XtGetGC(shellWidget, value_mask, &gc_values);
3154 XSetFont(xDisplay, countGC, countFontID);
3156 if (appData.monoMode) {
3157 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3158 gc_values.background = XWhitePixel(xDisplay, xScreen);
3159 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3161 gc_values.foreground = XWhitePixel(xDisplay, xScreen);
3162 gc_values.background = XBlackPixel(xDisplay, xScreen);
3163 lightSquareGC = wbPieceGC
3164 = XtGetGC(shellWidget, value_mask, &gc_values);
3166 gc_values.foreground = XBlackPixel(xDisplay, xScreen);
3167 gc_values.background = XWhitePixel(xDisplay, xScreen);
3168 darkSquareGC = bwPieceGC
3169 = XtGetGC(shellWidget, value_mask, &gc_values);
3171 if (DefaultDepth(xDisplay, xScreen) == 1) {
3172 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
3173 gc_values.function = GXcopyInverted;
3174 copyInvertedGC = XtGetGC(shellWidget, value_mask, &gc_values);
3175 gc_values.function = GXcopy;
3176 if (XBlackPixel(xDisplay, xScreen) == 1) {
3177 bwPieceGC = darkSquareGC;
3178 wbPieceGC = copyInvertedGC;
3180 bwPieceGC = copyInvertedGC;
3181 wbPieceGC = lightSquareGC;
3185 gc_values.foreground = highlightSquareColor;
3186 gc_values.background = highlightSquareColor;
3187 highlineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3189 gc_values.foreground = premoveHighlightColor;
3190 gc_values.background = premoveHighlightColor;
3191 prelineGC = XtGetGC(shellWidget, value_mask, &gc_values);
3193 gc_values.foreground = lightSquareColor;
3194 gc_values.background = darkSquareColor;
3195 lightSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3197 gc_values.foreground = darkSquareColor;
3198 gc_values.background = lightSquareColor;
3199 darkSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3201 gc_values.foreground = jailSquareColor;
3202 gc_values.background = jailSquareColor;
3203 jailSquareGC = XtGetGC(shellWidget, value_mask, &gc_values);
3205 gc_values.foreground = whitePieceColor;
3206 gc_values.background = darkSquareColor;
3207 wdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3209 gc_values.foreground = whitePieceColor;
3210 gc_values.background = lightSquareColor;
3211 wlPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3213 gc_values.foreground = whitePieceColor;
3214 gc_values.background = jailSquareColor;
3215 wjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3217 gc_values.foreground = blackPieceColor;
3218 gc_values.background = darkSquareColor;
3219 bdPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3221 gc_values.foreground = blackPieceColor;
3222 gc_values.background = lightSquareColor;
3223 blPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3225 gc_values.foreground = blackPieceColor;
3226 gc_values.background = jailSquareColor;
3227 bjPieceGC = XtGetGC(shellWidget, value_mask, &gc_values);
3231 void loadXIM(xim, xmask, filename, dest, mask)
3244 fp = fopen(filename, "rb");
3246 fprintf(stderr, _("%s: error loading XIM!\n"), programName);
3253 for (y=0; y<h; ++y) {
3254 for (x=0; x<h; ++x) {
3259 XPutPixel(xim, x, y, blackPieceColor);
3261 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3264 XPutPixel(xim, x, y, darkSquareColor);
3266 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3269 XPutPixel(xim, x, y, whitePieceColor);
3271 XPutPixel(xmask, x, y, WhitePixel(xDisplay,xScreen));
3274 XPutPixel(xim, x, y, lightSquareColor);
3276 XPutPixel(xmask, x, y, BlackPixel(xDisplay,xScreen));
3282 /* create Pixmap of piece */
3283 *dest = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3285 XPutImage(xDisplay, *dest, lightSquareGC, xim,
3288 /* create Pixmap of clipmask
3289 Note: We assume the white/black pieces have the same
3290 outline, so we make only 6 masks. This is okay
3291 since the XPM clipmask routines do the same. */
3293 temp = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3295 XPutImage(xDisplay, temp, lightSquareGC, xmask,
3298 /* now create the 1-bit version */
3299 *mask = XCreatePixmap(xDisplay, DefaultRootWindow(xDisplay),
3302 values.foreground = 1;
3303 values.background = 0;
3305 /* Don't use XtGetGC, not read only */
3306 maskGC = XCreateGC(xDisplay, *mask,
3307 GCForeground | GCBackground, &values);
3308 XCopyPlane(xDisplay, temp, *mask, maskGC,
3309 0, 0, squareSize, squareSize, 0, 0, 1);
3310 XFreePixmap(xDisplay, temp);
3315 char pieceBitmapNames[] = "pnbrqfeacwmohijgdvlsukpnsl";
3317 void CreateXIMPieces()
3322 static char *ximkind[] = { "ll", "ld", "dl", "dd" };
3327 /* The XSynchronize calls were copied from CreatePieces.
3328 Not sure if needed, but can't hurt */
3329 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3332 /* temp needed by loadXIM() */
3333 ximtemp = XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3334 0, 0, ss, ss, AllPlanes, XYPixmap);
3336 if (strlen(appData.pixmapDirectory) == 0) {
3340 if (appData.monoMode) {
3341 DisplayFatalError(_("XIM pieces cannot be used in monochrome mode"),
3345 fprintf(stderr, _("\nLoading XIMs...\n"));
3347 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3348 fprintf(stderr, "%d", piece+1);
3349 for (kind=0; kind<4; kind++) {
3350 fprintf(stderr, ".");
3351 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xim",
3352 ExpandPathName(appData.pixmapDirectory),
3353 piece <= (int) WhiteKing ? "" : "w",
3354 pieceBitmapNames[piece],
3356 ximPieceBitmap[kind][piece] =
3357 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3358 0, 0, ss, ss, AllPlanes, XYPixmap);
3359 if (appData.debugMode)
3360 fprintf(stderr, _("(File:%s:) "), buf);
3361 loadXIM(ximPieceBitmap[kind][piece],
3363 &(xpmPieceBitmap2[kind][piece]),
3364 &(ximMaskPm2[piece]));
3365 if(piece <= (int)WhiteKing)
3366 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3368 fprintf(stderr," ");
3370 /* Load light and dark squares */
3371 /* If the LSQ and DSQ pieces don't exist, we will
3372 draw them with solid squares. */
3373 snprintf(buf,sizeof(buf), "%s/lsq%u.xim", ExpandPathName(appData.pixmapDirectory), ss);
3374 if (access(buf, 0) != 0) {
3378 fprintf(stderr, _("light square "));
3380 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3381 0, 0, ss, ss, AllPlanes, XYPixmap);
3382 if (appData.debugMode)
3383 fprintf(stderr, _("(File:%s:) "), buf);
3385 loadXIM(ximLightSquare, NULL, buf, &xpmLightSquare, NULL);
3386 fprintf(stderr, _("dark square "));
3387 snprintf(buf,sizeof(buf), "%s/dsq%u.xim",
3388 ExpandPathName(appData.pixmapDirectory), ss);
3389 if (appData.debugMode)
3390 fprintf(stderr, _("(File:%s:) "), buf);
3392 XGetImage(xDisplay, DefaultRootWindow(xDisplay),
3393 0, 0, ss, ss, AllPlanes, XYPixmap);
3394 loadXIM(ximDarkSquare, NULL, buf, &xpmDarkSquare, NULL);
3395 xpmJailSquare = xpmLightSquare;
3397 fprintf(stderr, _("Done.\n"));
3399 XSynchronize(xDisplay, False); /* Work-around for xlib/xt buffering bug */
3403 void CreateXPMPieces()
3407 u_int ss = squareSize;
3409 static char *xpmkind[] = { "ll", "ld", "dl", "dd" };
3410 XpmColorSymbol symbols[4];
3412 /* The XSynchronize calls were copied from CreatePieces.
3413 Not sure if needed, but can't hurt */
3414 XSynchronize(xDisplay, True); /* Work-around for xlib/xt buffering bug */
3416 /* Setup translations so piece colors match square colors */
3417 symbols[0].name = "light_piece";
3418 symbols[0].value = appData.whitePieceColor;
3419 symbols[1].name = "dark_piece";
3420 symbols[1].value = appData.blackPieceColor;
3421 symbols[2].name = "light_square";
3422 symbols[2].value = appData.lightSquareColor;
3423 symbols[3].name = "dark_square";
3424 symbols[3].value = appData.darkSquareColor;
3426 attr.valuemask = XpmColorSymbols;
3427 attr.colorsymbols = symbols;
3428 attr.numsymbols = 4;
3430 if (appData.monoMode) {
3431 DisplayFatalError(_("XPM pieces cannot be used in monochrome mode"),
3435 if (strlen(appData.pixmapDirectory) == 0) {
3436 XpmPieces* pieces = builtInXpms;
3439 while (pieces->size != squareSize && pieces->size) pieces++;
3440 if (!pieces->size) {
3441 fprintf(stderr, _("No builtin XPM pieces of size %d\n"), squareSize);
3444 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3445 for (kind=0; kind<4; kind++) {
3447 if ((r=XpmCreatePixmapFromData(xDisplay, xBoardWindow,
3448 pieces->xpm[piece][kind],
3449 &(xpmPieceBitmap2[kind][piece]),
3450 NULL, &attr)) != 0) {
3451 fprintf(stderr, _("Error %d loading XPM image \"%s\"\n"),
3455 if(piece <= (int) WhiteKing)
3456 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3460 xpmJailSquare = xpmLightSquare;
3464 fprintf(stderr, _("\nLoading XPMs...\n"));
3467 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3468 fprintf(stderr, "%d ", piece+1);
3469 for (kind=0; kind<4; kind++) {
3470 snprintf(buf, sizeof(buf), "%s/%s%c%s%u.xpm",
3471 ExpandPathName(appData.pixmapDirectory),
3472 piece > (int) WhiteKing ? "w" : "",
3473 pieceBitmapNames[piece],
3475 if (appData.debugMode) {
3476 fprintf(stderr, _("(File:%s:) "), buf);
3478 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3479 &(xpmPieceBitmap2[kind][piece]),
3480 NULL, &attr)) != 0) {
3481 if(piece != (int)WhiteKing && piece > (int)WhiteQueen) {
3482 // [HGM] missing: read of unorthodox piece failed; substitute King.
3483 snprintf(buf, sizeof(buf), "%s/k%s%u.xpm",
3484 ExpandPathName(appData.pixmapDirectory),
3486 if (appData.debugMode) {
3487 fprintf(stderr, _("(Replace by File:%s:) "), buf);
3489 r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3490 &(xpmPieceBitmap2[kind][piece]),
3494 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"),
3499 if(piece <= (int) WhiteKing)
3500 xpmPieceBitmap[kind][piece] = xpmPieceBitmap2[kind][piece];
3503 /* Load light and dark squares */
3504 /* If the LSQ and DSQ pieces don't exist, we will
3505 draw them with solid squares. */
3506 fprintf(stderr, _("light square "));
3507 snprintf(buf, sizeof(buf), "%s/lsq%u.xpm", ExpandPathName(appData.pixmapDirectory), ss);
3508 if (access(buf, 0) != 0) {
3512 if (appData.debugMode)
3513 fprintf(stderr, _("(File:%s:) "), buf);
3515 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3516 &xpmLightSquare, NULL, &attr)) != 0) {
3517 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3520 fprintf(stderr, _("dark square "));
3521 snprintf(buf, sizeof(buf), "%s/dsq%u.xpm",
3522 ExpandPathName(appData.pixmapDirectory), ss);
3523 if (appData.debugMode) {
3524 fprintf(stderr, _("(File:%s:) "), buf);
3526 if ((r=XpmReadFileToPixmap(xDisplay, xBoardWindow, buf,
3527 &xpmDarkSquare, NULL, &attr)) != 0) {
3528 fprintf(stderr, _("Error %d loading XPM file \"%s\"\n"), r, buf);
3532 xpmJailSquare = xpmLightSquare;
3533 fprintf(stderr, _("Done.\n"));
3535 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3538 #endif /* HAVE_LIBXPM */
3541 /* No built-in bitmaps */
3546 u_int ss = squareSize;
3548 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3551 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3552 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3553 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3554 pieceBitmapNames[piece],
3555 ss, kind == SOLID ? 's' : 'o');
3556 ReadBitmap(&pieceBitmap2[kind][piece], buf, NULL, ss, ss);
3557 if(piece <= (int)WhiteKing)
3558 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3562 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3566 /* With built-in bitmaps */
3569 BuiltInBits* bib = builtInBits;
3572 u_int ss = squareSize;
3574 XSynchronize(xDisplay, True); /* Work-around for xlib/xt
3577 while (bib->squareSize != ss && bib->squareSize != 0) bib++;
3579 for (kind = SOLID; kind <= (appData.monoMode ? OUTLINE : SOLID); kind++) {
3580 for (piece = (int) WhitePawn; piece <= (int) WhiteKing + 4; piece++) {
3581 snprintf(buf, MSG_SIZ, "%s%c%u%c.bm", piece > (int)WhiteKing ? "w" : "",
3582 pieceBitmapNames[piece],
3583 ss, kind == SOLID ? 's' : 'o');
3584 ReadBitmap(&pieceBitmap2[kind][piece], buf,
3585 bib->bits[kind][piece], ss, ss);
3586 if(piece <= (int)WhiteKing)
3587 pieceBitmap[kind][piece] = pieceBitmap2[kind][piece];
3591 XSynchronize(xDisplay, False); /* Work-around for xlib/xt
3596 void ReadBitmap(pm, name, bits, wreq, hreq)
3599 unsigned char bits[];
3605 char msg[MSG_SIZ], fullname[MSG_SIZ];
3607 if (*appData.bitmapDirectory != NULLCHAR) {
3608 safeStrCpy(fullname, appData.bitmapDirectory, sizeof(fullname)/sizeof(fullname[0]) );
3609 strncat(fullname, "/", MSG_SIZ - strlen(fullname) - 1);
3610 strncat(fullname, name, MSG_SIZ - strlen(fullname) - 1);
3611 errcode = XReadBitmapFile(xDisplay, xBoardWindow, fullname,
3612 &w, &h, pm, &x_hot, &y_hot);
3613 fprintf(stderr, "load %s\n", name);
3614 if (errcode != BitmapSuccess) {
3616 case BitmapOpenFailed:
3617 snprintf(msg, sizeof(msg), _("Can't open bitmap file %s"), fullname);
3619 case BitmapFileInvalid:
3620 snprintf(msg, sizeof(msg), _("Invalid bitmap in file %s"), fullname);
3622 case BitmapNoMemory:
3623 snprintf(msg, sizeof(msg), _("Ran out of memory reading bitmap file %s"),
3627 snprintf(msg, sizeof(msg), _("Unknown XReadBitmapFile error %d on file %s"),
3631 fprintf(stderr, _("%s: %s...using built-in\n"),
3633 } else if (w != wreq || h != hreq) {
3635 _("%s: Bitmap %s is %dx%d, not %dx%d...using built-in\n"),
3636 programName, fullname, w, h, wreq, hreq);
3642 *pm = XCreateBitmapFromData(xDisplay, xBoardWindow, (char *) bits,
3651 if (lineGap == 0) return;
3653 /* [HR] Split this into 2 loops for non-square boards. */
3655 for (i = 0; i < BOARD_HEIGHT + 1; i++) {
3656 gridSegments[i].x1 = 0;
3657 gridSegments[i].x2 =
3658 lineGap + BOARD_WIDTH * (squareSize + lineGap);
3659 gridSegments[i].y1 = gridSegments[i].y2
3660 = lineGap / 2 + (i * (squareSize + lineGap));
3663 for (j = 0; j < BOARD_WIDTH + 1; j++) {
3664 gridSegments[j + i].y1 = 0;
3665 gridSegments[j + i].y2 =
3666 lineGap + BOARD_HEIGHT * (squareSize + lineGap);
3667 gridSegments[j + i].x1 = gridSegments[j + i].x2
3668 = lineGap / 2 + (j * (squareSize + lineGap));
3672 static void MenuBarSelect(w, addr, index)
3677 XtActionProc proc = (XtActionProc) addr;
3679 (proc)(NULL, NULL, NULL, NULL);
3682 void CreateMenuBarPopup(parent, name, mb)
3692 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3695 XtSetArg(args[j], XtNleftMargin, 20); j++;
3696 XtSetArg(args[j], XtNrightMargin, 20); j++;
3698 while (mi->string != NULL) {
3699 if (strcmp(mi->string, "----") == 0) {
3700 entry = XtCreateManagedWidget(mi->string, smeLineObjectClass,
3703 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string)));
3704 entry = XtCreateManagedWidget(mi->string, smeBSBObjectClass,
3706 XtAddCallback(entry, XtNcallback,
3707 (XtCallbackProc) MenuBarSelect,
3708 (caddr_t) mi->proc);
3714 Widget CreateMenuBar(mb)
3718 Widget anchor, menuBar;
3720 char menuName[MSG_SIZ];
3723 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3724 XtSetArg(args[j], XtNvSpace, 0); j++;
3725 XtSetArg(args[j], XtNborderWidth, 0); j++;
3726 menuBar = XtCreateWidget("menuBar", boxWidgetClass,
3727 formWidget, args, j);
3729 while (mb->name != NULL) {
3730 safeStrCpy(menuName, "menu", sizeof(menuName)/sizeof(menuName[0]) );
3731 strncat(menuName, mb->name, MSG_SIZ - strlen(menuName) - 1);
3733 XtSetArg(args[j], XtNmenuName, XtNewString(menuName)); j++;
3736 shortName[0] = _(mb->name)[0];
3737 shortName[1] = NULLCHAR;
3738 XtSetArg(args[j], XtNlabel, XtNewString(shortName)); j++;
3741 XtSetArg(args[j], XtNlabel, XtNewString(_(mb->name))); j++;
3744 XtSetArg(args[j], XtNborderWidth, 0); j++;
3745 anchor = XtCreateManagedWidget(mb->name, menuButtonWidgetClass,
3747 CreateMenuBarPopup(menuBar, menuName, mb);
3753 Widget CreateButtonBar(mi)
3757 Widget button, buttonBar;
3761 XtSetArg(args[j], XtNorientation, XtorientHorizontal); j++;
3763 XtSetArg(args[j], XtNhSpace, 0); j++;
3765 XtSetArg(args[j], XtNborderWidth, 0); j++;
3766 XtSetArg(args[j], XtNvSpace, 0); j++;
3767 buttonBar = XtCreateWidget("buttonBar", boxWidgetClass,
3768 formWidget, args, j);
3770 while (mi->string != NULL) {
3773 XtSetArg(args[j], XtNinternalWidth, 2); j++;
3774 XtSetArg(args[j], XtNborderWidth, 0); j++;
3776 XtSetArg(args[j], XtNlabel, XtNewString(_(mi->string))); j++;
3777 button = XtCreateManagedWidget(mi->string, commandWidgetClass,
3778 buttonBar, args, j);
3779 XtAddCallback(button, XtNcallback,
3780 (XtCallbackProc) MenuBarSelect,
3781 (caddr_t) mi->proc);
3788 CreatePieceMenu(name, color)
3795 ChessSquare selection;
3797 menu = XtCreatePopupShell(name, simpleMenuWidgetClass,
3798 boardWidget, args, 0);
3800 for (i = 0; i < PIECE_MENU_SIZE; i++) {
3801 String item = pieceMenuStrings[color][i];
3803 if (strcmp(item, "----") == 0) {
3804 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3807 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3808 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3810 selection = pieceMenuTranslation[color][i];
3811 XtAddCallback(entry, XtNcallback,
3812 (XtCallbackProc) PieceMenuSelect,
3813 (caddr_t) selection);
3814 if (selection == WhitePawn || selection == BlackPawn) {
3815 XtSetArg(args[0], XtNpopupOnEntry, entry);
3816 XtSetValues(menu, args, 1);
3829 ChessSquare selection;
3831 whitePieceMenu = CreatePieceMenu("menuW", 0);
3832 blackPieceMenu = CreatePieceMenu("menuB", 1);
3834 XtRegisterGrabAction(PieceMenuPopup, True,
3835 (unsigned)(ButtonPressMask|ButtonReleaseMask),
3836 GrabModeAsync, GrabModeAsync);
3838 XtSetArg(args[0], XtNlabel, _("Drop"));
3839 dropMenu = XtCreatePopupShell("menuD", simpleMenuWidgetClass,
3840 boardWidget, args, 1);
3841 for (i = 0; i < DROP_MENU_SIZE; i++) {
3842 String item = dropMenuStrings[i];
3844 if (strcmp(item, "----") == 0) {
3845 entry = XtCreateManagedWidget(item, smeLineObjectClass,
3848 XtSetArg(args[0], XtNlabel, XtNewString(_(item)));
3849 entry = XtCreateManagedWidget(item, smeBSBObjectClass,
3851 selection = dropMenuTranslation[i];
3852 XtAddCallback(entry, XtNcallback,
3853 (XtCallbackProc) DropMenuSelect,
3854 (caddr_t) selection);
3859 void SetupDropMenu()
3867 for (i=0; i<sizeof(dmEnables)/sizeof(DropMenuEnables); i++) {
3868 entry = XtNameToWidget(dropMenu, dmEnables[i].widget);
3869 p = strchr(gameMode == IcsPlayingWhite ? white_holding : black_holding,
3870 dmEnables[i].piece);
3871 XtSetSensitive(entry, p != NULL || !appData.testLegality
3872 /*!!temp:*/ || (gameInfo.variant == VariantCrazyhouse
3873 && !appData.icsActive));
3875 while (p && *p++ == dmEnables[i].piece) count++;
3876 snprintf(label, sizeof(label), "%s %d", dmEnables[i].widget, count);
3878 XtSetArg(args[j], XtNlabel, label); j++;
3879 XtSetValues(entry, args, j);
3883 void PieceMenuPopup(w, event, params, num_params)
3887 Cardinal *num_params;
3889 String whichMenu; int menuNr;
3890 if (event->type == ButtonRelease)
3891 menuNr = RightClick(Release, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3892 else if (event->type == ButtonPress)
3893 menuNr = RightClick(Press, event->xbutton.x, event->xbutton.y, &pmFromX, &pmFromY);
3895 case 0: whichMenu = params[0]; break;
3896 case 1: SetupDropMenu(); whichMenu = "menuD"; break;
3898 case -1: if (errorUp) ErrorPopDown();
3901 XtPopupSpringLoaded(XtNameToWidget(boardWidget, whichMenu));
3904 static void PieceMenuSelect(w, piece, junk)
3909 if (pmFromX < 0 || pmFromY < 0) return;
3910 EditPositionMenuEvent(piece, pmFromX, pmFromY);
3913 static void DropMenuSelect(w, piece, junk)
3918 if (pmFromX < 0 || pmFromY < 0) return;
3919 DropMenuEvent(piece, pmFromX, pmFromY);
3922 void WhiteClock(w, event, prms, nprms)
3928 if (gameMode == EditPosition || gameMode == IcsExamining) {
3929 SetWhiteToPlayEvent();
3930 } else if (gameMode == IcsPlayingBlack || gameMode == MachinePlaysWhite) {
3935 void BlackClock(w, event, prms, nprms)
3941 if (gameMode == EditPosition || gameMode == IcsExamining) {
3942 SetBlackToPlayEvent();
3943 } else if (gameMode == IcsPlayingWhite || gameMode == MachinePlaysBlack) {
3950 * If the user selects on a border boundary, return -1; if off the board,
3951 * return -2. Otherwise map the event coordinate to the square.
3953 int EventToSquare(x, limit)
3961 if ((x % (squareSize + lineGap)) >= squareSize)
3963 x /= (squareSize + lineGap);
3969 static void do_flash_delay(msec)
3975 static void drawHighlight(file, rank, gc)
3981 if (lineGap == 0 || appData.blindfold) return;
3984 x = lineGap/2 + ((BOARD_WIDTH-1)-file) *
3985 (squareSize + lineGap);
3986 y = lineGap/2 + rank * (squareSize + lineGap);
3988 x = lineGap/2 + file * (squareSize + lineGap);
3989 y = lineGap/2 + ((BOARD_HEIGHT-1)-rank) *
3990 (squareSize + lineGap);
3993 XDrawRectangle(xDisplay, xBoardWindow, gc, x, y,
3994 squareSize+lineGap, squareSize+lineGap);
3997 int hi1X = -1, hi1Y = -1, hi2X = -1, hi2Y = -1;
3998 int pm1X = -1, pm1Y = -1, pm2X = -1, pm2Y = -1;
4001 SetHighlights(fromX, fromY, toX, toY)
4002 int fromX, fromY, toX, toY;
4004 if (hi1X != fromX || hi1Y != fromY) {
4005 if (hi1X >= 0 && hi1Y >= 0) {
4006 drawHighlight(hi1X, hi1Y, lineGC);
4008 } // [HGM] first erase both, then draw new!
4009 if (hi2X != toX || hi2Y != toY) {
4010 if (hi2X >= 0 && hi2Y >= 0) {
4011 drawHighlight(hi2X, hi2Y, lineGC);
4014 if (hi1X != fromX || hi1Y != fromY) {
4015 if (fromX >= 0 && fromY >= 0) {
4016 drawHighlight(fromX, fromY, highlineGC);
4019 if (hi2X != toX || hi2Y != toY) {
4020 if (toX >= 0 && toY >= 0) {
4021 drawHighlight(toX, toY, highlineGC);
4033 SetHighlights(-1, -1, -1, -1);
4038 SetPremoveHighlights(fromX, fromY, toX, toY)
4039 int fromX, fromY, toX, toY;
4041 if (pm1X != fromX || pm1Y != fromY) {
4042 if (pm1X >= 0 && pm1Y >= 0) {
4043 drawHighlight(pm1X, pm1Y, lineGC);
4045 if (fromX >= 0 && fromY >= 0) {
4046 drawHighlight(fromX, fromY, prelineGC);
4049 if (pm2X != toX || pm2Y != toY) {
4050 if (pm2X >= 0 && pm2Y >= 0) {
4051 drawHighlight(pm2X, pm2Y, lineGC);
4053 if (toX >= 0 && toY >= 0) {
4054 drawHighlight(toX, toY, prelineGC);
4064 ClearPremoveHighlights()
4066 SetPremoveHighlights(-1, -1, -1, -1);
4069 static void BlankSquare(x, y, color, piece, dest)
4074 if (useImages && useImageSqs) {
4078 pm = xpmLightSquare;
4083 case 2: /* neutral */
4088 XCopyArea(xDisplay, pm, dest, wlPieceGC, 0, 0,
4089 squareSize, squareSize, x, y);
4099 case 2: /* neutral */
4104 XFillRectangle(xDisplay, dest, gc, x, y, squareSize, squareSize);
4109 I split out the routines to draw a piece so that I could
4110 make a generic flash routine.
4112 static void monoDrawPiece_1bit(piece, square_color, x, y, dest)
4114 int square_color, x, y;
4117 /* Avoid XCopyPlane on 1-bit screens to work around Sun bug */
4118 switch (square_color) {
4120 case 2: /* neutral */
4122 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4123 ? *pieceToOutline(piece)
4124 : *pieceToSolid(piece),
4125 dest, bwPieceGC, 0, 0,
4126 squareSize, squareSize, x, y);
4129 XCopyArea(xDisplay, (int) piece < (int) BlackPawn
4130 ? *pieceToSolid(piece)
4131 : *pieceToOutline(piece),
4132 dest, wbPieceGC, 0, 0,
4133 squareSize, squareSize, x, y);
4138 static void monoDrawPiece(piece, square_color, x, y, dest)
4140 int square_color, x, y;
4143 switch (square_color) {
4145 case 2: /* neutral */
4147 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4148 ? *pieceToOutline(piece)
4149 : *pieceToSolid(piece),
4150 dest, bwPieceGC, 0, 0,
4151 squareSize, squareSize, x, y, 1);
4154 XCopyPlane(xDisplay, (int) piece < (int) BlackPawn
4155 ? *pieceToSolid(piece)
4156 : *pieceToOutline(piece),
4157 dest, wbPieceGC, 0, 0,
4158 squareSize, squareSize, x, y, 1);
4163 static void colorDrawPiece(piece, square_color, x, y, dest)
4165 int square_color, x, y;
4168 if(pieceToSolid(piece) == NULL) return; // [HGM] bitmaps: make it non-fatal if we have no bitmap;
4169 switch (square_color) {
4171 XCopyPlane(xDisplay, *pieceToSolid(piece),
4172 dest, (int) piece < (int) BlackPawn
4173 ? wlPieceGC : blPieceGC, 0, 0,
4174 squareSize, squareSize, x, y, 1);
4177 XCopyPlane(xDisplay, *pieceToSolid(piece),
4178 dest, (int) piece < (int) BlackPawn
4179 ? wdPieceGC : bdPieceGC, 0, 0,
4180 squareSize, squareSize, x, y, 1);
4182 case 2: /* neutral */
4184 XCopyPlane(xDisplay, *pieceToSolid(piece),
4185 dest, (int) piece < (int) BlackPawn
4186 ? wjPieceGC : bjPieceGC, 0, 0,
4187 squareSize, squareSize, x, y, 1);
4192 static void colorDrawPieceImage(piece, square_color, x, y, dest)
4194 int square_color, x, y;
4199 switch (square_color) {
4201 case 2: /* neutral */
4203 if ((int)piece < (int) BlackPawn) {
4211 if ((int)piece < (int) BlackPawn) {
4219 if(appData.upsideDown && flipView) kind ^= 2; // swap white and black pieces
4220 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
4221 dest, wlPieceGC, 0, 0,
4222 squareSize, squareSize, x, y);
4225 typedef void (*DrawFunc)();
4227 DrawFunc ChooseDrawFunc()
4229 if (appData.monoMode) {
4230 if (DefaultDepth(xDisplay, xScreen) == 1) {
4231 return monoDrawPiece_1bit;
4233 return monoDrawPiece;
4237 return colorDrawPieceImage;
4239 return colorDrawPiece;
4243 /* [HR] determine square color depending on chess variant. */
4244 static int SquareColor(row, column)
4249 if (gameInfo.variant == VariantXiangqi) {
4250 if (column >= 3 && column <= 5 && row >= 0 && row <= 2) {
4252 } else if (column >= 3 && column <= 5 && row >= 7 && row <= 9) {
4254 } else if (row <= 4) {
4260 square_color = ((column + row) % 2) == 1;
4263 /* [hgm] holdings: next line makes all holdings squares light */
4264 if(column < BOARD_LEFT || column >= BOARD_RGHT) square_color = 1;
4266 return square_color;
4269 void DrawSquare(row, column, piece, do_flash)
4270 int row, column, do_flash;
4273 int square_color, x, y, direction, font_ascent, font_descent;
4276 XCharStruct overall;
4280 /* Calculate delay in milliseconds (2-delays per complete flash) */
4281 flash_delay = 500 / appData.flashRate;
4284 x = lineGap + ((BOARD_WIDTH-1)-column) *
4285 (squareSize + lineGap);
4286 y = lineGap + row * (squareSize + lineGap);
4288 x = lineGap + column * (squareSize + lineGap);
4289 y = lineGap + ((BOARD_HEIGHT-1)-row) *
4290 (squareSize + lineGap);
4293 if(twoBoards && partnerUp) x += hOffset; // [HGM] dual: draw second board
4295 square_color = SquareColor(row, column);
4297 if ( // [HGM] holdings: blank out area between board and holdings
4298 column == BOARD_LEFT-1 || column == BOARD_RGHT
4299 || (column == BOARD_LEFT-2 && row < BOARD_HEIGHT-gameInfo.holdingsSize)
4300 || (column == BOARD_RGHT+1 && row >= gameInfo.holdingsSize) ) {
4301 BlankSquare(x, y, 2, EmptySquare, xBoardWindow);
4303 // [HGM] print piece counts next to holdings
4304 string[1] = NULLCHAR;
4305 if (column == (flipView ? BOARD_LEFT-1 : BOARD_RGHT) && piece > 1 ) {
4306 string[0] = '0' + piece;
4307 XTextExtents(countFontStruct, string, 1, &direction,
4308 &font_ascent, &font_descent, &overall);
4309 if (appData.monoMode) {
4310 XDrawImageString(xDisplay, xBoardWindow, countGC,
4311 x + squareSize - overall.width - 2,
4312 y + font_ascent + 1, string, 1);
4314 XDrawString(xDisplay, xBoardWindow, countGC,
4315 x + squareSize - overall.width - 2,
4316 y + font_ascent + 1, string, 1);
4319 if (column == (flipView ? BOARD_RGHT : BOARD_LEFT-1) && piece > 1) {
4320 string[0] = '0' + piece;
4321 XTextExtents(countFontStruct, string, 1, &direction,
4322 &font_ascent, &font_descent, &overall);
4323 if (appData.monoMode) {
4324 XDrawImageString(xDisplay, xBoardWindow, countGC,
4325 x + 2, y + font_ascent + 1, string, 1);
4327 XDrawString(xDisplay, xBoardWindow, countGC,
4328 x + 2, y + font_ascent + 1, string, 1);
4332 if (piece == EmptySquare || appData.blindfold) {
4333 BlankSquare(x, y, square_color, piece, xBoardWindow);
4335 drawfunc = ChooseDrawFunc();
4336 if (do_flash && appData.flashCount > 0) {
4337 for (i=0; i<appData.flashCount; ++i) {
4339 drawfunc(piece, square_color, x, y, xBoardWindow);
4340 XSync(xDisplay, False);
4341 do_flash_delay(flash_delay);
4343 BlankSquare(x, y, square_color, piece, xBoardWindow);
4344 XSync(xDisplay, False);
4345 do_flash_delay(flash_delay);
4348 drawfunc(piece, square_color, x, y, xBoardWindow);
4352 string[1] = NULLCHAR;
4353 if (appData.showCoords && row == (flipView ? BOARD_HEIGHT-1 : 0)
4354 && column >= BOARD_LEFT && column < BOARD_RGHT) {
4355 string[0] = 'a' + column - BOARD_LEFT;
4356 XTextExtents(coordFontStruct, string, 1, &direction,
4357 &font_ascent, &font_descent, &overall);
4358 if (appData.monoMode) {
4359 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4360 x + squareSize - overall.width - 2,
4361 y + squareSize - font_descent - 1, string, 1);
4363 XDrawString(xDisplay, xBoardWindow, coordGC,
4364 x + squareSize - overall.width - 2,
4365 y + squareSize - font_descent - 1, string, 1);
4368 if (appData.showCoords && column == (flipView ? BOARD_RGHT-1 : BOARD_LEFT)) {
4369 string[0] = ONE + row;
4370 XTextExtents(coordFontStruct, string, 1, &direction,
4371 &font_ascent, &font_descent, &overall);
4372 if (appData.monoMode) {
4373 XDrawImageString(xDisplay, xBoardWindow, coordGC,
4374 x + 2, y + font_ascent + 1, string, 1);
4376 XDrawString(xDisplay, xBoardWindow, coordGC,
4377 x + 2, y + font_ascent + 1, string, 1);
4380 if(!partnerUp && marker[row][column]) {
4381 XFillArc(xDisplay, xBoardWindow, marker[row][column] == 2 ? prelineGC : highlineGC,
4382 x + squareSize/4, y+squareSize/4, squareSize/2, squareSize/2, 0, 64*360);
4387 /* Why is this needed on some versions of X? */
4388 void EventProc(widget, unused, event)
4393 if (!XtIsRealized(widget))
4396 switch (event->type) {
4398 if (event->xexpose.count > 0) return; /* no clipping is done */
4399 XDrawPosition(widget, True, NULL);
4400 if(twoBoards) { // [HGM] dual: draw other board in other orientation
4401 flipView = !flipView; partnerUp = !partnerUp;
4402 XDrawPosition(widget, True, NULL);
4403 flipView = !flipView; partnerUp = !partnerUp;
4407 if(SeekGraphClick(Press, event->xbutton.x, event->xbutton.y, 1)) break;
\r
4414 void DrawPosition(fullRedraw, board)
4415 /*Boolean*/int fullRedraw;
4418 XDrawPosition(boardWidget, fullRedraw, board);
4421 /* Returns 1 if there are "too many" differences between b1 and b2
4422 (i.e. more than 1 move was made) */
4423 static int too_many_diffs(b1, b2)
4429 for (i=0; i<BOARD_HEIGHT; ++i) {
4430 for (j=0; j<BOARD_WIDTH; ++j) {
4431 if (b1[i][j] != b2[i][j]) {
4432 if (++c > 4) /* Castling causes 4 diffs */
4441 /* Matrix describing castling maneuvers */
4442 /* Row, ColRookFrom, ColKingFrom, ColRookTo, ColKingTo */
4443 static int castling_matrix[4][5] = {
4444 { 0, 0, 4, 3, 2 }, /* 0-0-0, white */
4445 { 0, 7, 4, 5, 6 }, /* 0-0, white */
4446 { 7, 0, 4, 3, 2 }, /* 0-0-0, black */
4447 { 7, 7, 4, 5, 6 } /* 0-0, black */
4450 /* Checks whether castling occurred. If it did, *rrow and *rcol
4451 are set to the destination (row,col) of the rook that moved.
4453 Returns 1 if castling occurred, 0 if not.
4455 Note: Only handles a max of 1 castling move, so be sure
4456 to call too_many_diffs() first.
4458 static int check_castle_draw(newb, oldb, rrow, rcol)
4465 /* For each type of castling... */
4466 for (i=0; i<4; ++i) {
4467 r = castling_matrix[i];
4469 /* Check the 4 squares involved in the castling move */
4471 for (j=1; j<=4; ++j) {
4472 if (newb[r[0]][r[j]] == oldb[r[0]][r[j]]) {
4479 /* All 4 changed, so it must be a castling move */
4488 // [HGM] seekgraph: some low-level drawing routines cloned from xevalgraph
4489 void DrawSeekAxis( int x, int y, int xTo, int yTo )
4491 XDrawLine(xDisplay, xBoardWindow, lineGC, x, y, xTo, yTo);
4494 void DrawSeekBackground( int left, int top, int right, int bottom )
4496 XFillRectangle(xDisplay, xBoardWindow, lightSquareGC, left, top, right-left, bottom-top);
4499 void DrawSeekText(char *buf, int x, int y)
4501 XDrawString(xDisplay, xBoardWindow, coordGC, x, y+4, buf, strlen(buf));
4504 void DrawSeekDot(int x, int y, int colorNr)
4506 int square = colorNr & 0x80;
4509 color = colorNr == 0 ? prelineGC : colorNr == 1 ? darkSquareGC : highlineGC;
4511 XFillRectangle(xDisplay, xBoardWindow, color,
4512 x-squareSize/9, y-squareSize/9, 2*squareSize/9, 2*squareSize/9);
4514 XFillArc(xDisplay, xBoardWindow, color,
4515 x-squareSize/8, y-squareSize/8, squareSize/4, squareSize/4, 0, 64*360);
4518 static int damage[2][BOARD_RANKS][BOARD_FILES];
4521 * event handler for redrawing the board
4523 void XDrawPosition(w, repaint, board)
4525 /*Boolean*/int repaint;
4529 static int lastFlipView = 0;
4530 static int lastBoardValid[2] = {0, 0};
4531 static Board lastBoard[2];
4534 int nr = twoBoards*partnerUp;
4536 if(DrawSeekGraph()) return; // [HGM] seekgraph: suppress any drawing if seek graph up
4538 if (board == NULL) {
4539 if (!lastBoardValid[nr]) return;
4540 board = lastBoard[nr];
4542 if (!lastBoardValid[nr] || (nr == 0 && lastFlipView != flipView)) {
4543 XtSetArg(args[0], XtNleftBitmap, (flipView ? xMarkPixmap : None));
4544 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flip View"),
4549 * It would be simpler to clear the window with XClearWindow()
4550 * but this causes a very distracting flicker.
4553 if (!repaint && lastBoardValid[nr] && (nr == 1 || lastFlipView == flipView)) {
4555 /* If too much changes (begin observing new game, etc.), don't
4557 do_flash = too_many_diffs(board, lastBoard[nr]) ? 0 : 1;
4559 /* Special check for castling so we don't flash both the king
4560 and the rook (just flash the king). */
4562 if (check_castle_draw(board, lastBoard[nr], &rrow, &rcol)) {
4563 /* Draw rook with NO flashing. King will be drawn flashing later */
4564 DrawSquare(rrow, rcol, board[rrow][rcol], 0);
4565 lastBoard[nr][rrow][rcol] = board[rrow][rcol];
4569 /* First pass -- Draw (newly) empty squares and repair damage.
4570 This prevents you from having a piece show up twice while it
4571 is flashing on its new square */
4572 for (i = 0; i < BOARD_HEIGHT; i++)
4573 for (j = 0; j < BOARD_WIDTH; j++)
4574 if ((board[i][j] != lastBoard[nr][i][j] && board[i][j] == EmptySquare)
4575 || damage[nr][i][j]) {
4576 DrawSquare(i, j, board[i][j], 0);
4577 damage[nr][i][j] = False;
4580 /* Second pass -- Draw piece(s) in new position and flash them */
4581 for (i = 0; i < BOARD_HEIGHT; i++)
4582 for (j = 0; j < BOARD_WIDTH; j++)
4583 if (board[i][j] != lastBoard[nr][i][j]) {
4584 DrawSquare(i, j, board[i][j], do_flash);
4588 XDrawSegments(xDisplay, xBoardWindow, lineGC,
4589 twoBoards & partnerUp ? secondSegments : // [HGM] dual
4590 gridSegments, BOARD_HEIGHT + BOARD_WIDTH + 2);
4592 for (i = 0; i < BOARD_HEIGHT; i++)
4593 for (j = 0; j < BOARD_WIDTH; j++) {
4594 DrawSquare(i, j, board[i][j], 0);
4595 damage[nr][i][j] = False;
4599 CopyBoard(lastBoard[nr], board);
4600 lastBoardValid[nr] = 1;
4601 if(nr == 0) { // [HGM] dual: no highlights on second board yet
4602 lastFlipView = flipView;
4604 /* Draw highlights */
4605 if (pm1X >= 0 && pm1Y >= 0) {
4606 drawHighlight(pm1X, pm1Y, prelineGC);
4608 if (pm2X >= 0 && pm2Y >= 0) {
4609 drawHighlight(pm2X, pm2Y, prelineGC);
4611 if (hi1X >= 0 && hi1Y >= 0) {
4612 drawHighlight(hi1X, hi1Y, highlineGC);
4614 if (hi2X >= 0 && hi2Y >= 0) {
4615 drawHighlight(hi2X, hi2Y, highlineGC);
4618 /* If piece being dragged around board, must redraw that too */
4621 XSync(xDisplay, False);
4626 * event handler for redrawing the board
4628 void DrawPositionProc(w, event, prms, nprms)
4634 XDrawPosition(w, True, NULL);
4639 * event handler for parsing user moves
4641 // [HGM] This routine will need quite some reworking. Although the backend still supports the old
4642 // way of doing things, by calling UserMoveEvent() to test the legality of the move and then perform
4643 // it at the end, and doing all kind of preliminary tests here (e.g. to weed out self-captures), it
4644 // should be made to use the new way, of calling UserMoveTest early to determine the legality of the
4645 // move, (which will weed out the illegal selfcaptures and moves into the holdings, and flag promotions),
4646 // and at the end FinishMove() to perform the move after optional promotion popups.
4647 // For now I patched it to allow self-capture with King, and suppress clicks between board and holdings.
4648 void HandleUserMove(w, event, prms, nprms)
4654 if (w != boardWidget || errorExitStatus != -1) return;
4655 if(nprms) shiftKey = !strcmp(prms[0], "1");
4658 if (event->type == ButtonPress) {
4659 XtPopdown(promotionShell);
4660 XtDestroyWidget(promotionShell);
4661 promotionUp = False;
4669 // [HGM] mouse: the rest of the mouse handler is moved to the backend, and called here
4670 if(event->type == ButtonPress) LeftClick(Press, event->xbutton.x, event->xbutton.y);
4671 if(event->type == ButtonRelease) LeftClick(Release, event->xbutton.x, event->xbutton.y);
4674 void AnimateUserMove (Widget w, XEvent * event,
4675 String * params, Cardinal * nParams)
4677 DragPieceMove(event->xmotion.x, event->xmotion.y);
4680 void HandlePV (Widget w, XEvent * event,
4681 String * params, Cardinal * nParams)
4682 { // [HGM] pv: walk PV
4683 MovePV(event->xmotion.x, event->xmotion.y, lineGap + BOARD_HEIGHT * (squareSize + lineGap));
4686 Widget CommentCreate(name, text, mutable, callback, lines)
4688 int /*Boolean*/ mutable;
4689 XtCallbackProc callback;
4693 Widget shell, layout, form, edit, b_ok, b_cancel, b_clear, b_close, b_edit;
4698 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4699 XtGetValues(boardWidget, args, j);
4702 XtSetArg(args[j], XtNresizable, True); j++;
4705 XtCreatePopupShell(name, topLevelShellWidgetClass,
4706 shellWidget, args, j);
4709 XtCreatePopupShell(name, transientShellWidgetClass,
4710 shellWidget, args, j);
4713 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4714 layoutArgs, XtNumber(layoutArgs));
4716 XtCreateManagedWidget("form", formWidgetClass, layout,
4717 formArgs, XtNumber(formArgs));
4721 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4722 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4724 XtSetArg(args[j], XtNstring, text); j++;
4725 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4726 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4727 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4728 XtSetArg(args[j], XtNright, XtChainRight); j++;
4729 XtSetArg(args[j], XtNresizable, True); j++;
4730 XtSetArg(args[j], XtNwidth, bw_width); j++; /*force wider than buttons*/
4731 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4732 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4733 XtSetArg(args[j], XtNautoFill, True); j++;
4734 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4736 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4737 XtOverrideTranslations(edit, XtParseTranslationTable(commentTranslations));
4741 XtSetArg(args[j], XtNfromVert, edit); j++;
4742 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4743 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4744 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4745 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4747 XtCreateManagedWidget(_("ok"), commandWidgetClass, form, args, j);
4748 XtAddCallback(b_ok, XtNcallback, callback, (XtPointer) 0);
4751 XtSetArg(args[j], XtNfromVert, edit); j++;
4752 XtSetArg(args[j], XtNfromHoriz, b_ok); j++;
4753 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4754 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4755 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4756 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4758 XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
4759 XtAddCallback(b_cancel, XtNcallback, callback, (XtPointer) 0);
4762 XtSetArg(args[j], XtNfromVert, edit); j++;
4763 XtSetArg(args[j], XtNfromHoriz, b_cancel); j++;
4764 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4765 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4766 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4767 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4769 XtCreateManagedWidget(_("clear"), commandWidgetClass, form, args, j);
4770 XtAddCallback(b_clear, XtNcallback, callback, (XtPointer) 0);
4773 XtSetArg(args[j], XtNfromVert, edit); j++;
4774 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4775 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4776 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4777 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4779 XtCreateManagedWidget(_("close"), commandWidgetClass, form, args, j);
4780 XtAddCallback(b_close, XtNcallback, callback, (XtPointer) 0);
4783 XtSetArg(args[j], XtNfromVert, edit); j++;
4784 XtSetArg(args[j], XtNfromHoriz, b_close); j++;
4785 XtSetArg(args[j], XtNtop, XtChainBottom); j++;
4786 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4787 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4788 XtSetArg(args[j], XtNright, XtChainLeft); j++;
4790 XtCreateManagedWidget(_("edit"), commandWidgetClass, form, args, j);
4791 XtAddCallback(b_edit, XtNcallback, callback, (XtPointer) 0);
4794 XtRealizeWidget(shell);
4796 if (commentX == -1) {
4799 Dimension pw_height;
4800 Dimension ew_height;
4803 XtSetArg(args[j], XtNheight, &ew_height); j++;
4804 XtGetValues(edit, args, j);
4807 XtSetArg(args[j], XtNheight, &pw_height); j++;
4808 XtGetValues(shell, args, j);
4809 commentH = pw_height + (lines - 1) * ew_height;
4810 commentW = bw_width - 16;
4812 XSync(xDisplay, False);
4814 /* This code seems to tickle an X bug if it is executed too soon
4815 after xboard starts up. The coordinates get transformed as if
4816 the main window was positioned at (0, 0).
4818 XtTranslateCoords(shellWidget,
4819 (bw_width - commentW) / 2, 0 - commentH / 2,
4820 &commentX, &commentY);
4822 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4823 RootWindowOfScreen(XtScreen(shellWidget)),
4824 (bw_width - commentW) / 2, 0 - commentH / 2,
4829 if (commentY < 0) commentY = 0; /*avoid positioning top offscreen*/
4832 if(wpComment.width > 0) {
4833 commentX = wpComment.x;
4834 commentY = wpComment.y;
4835 commentW = wpComment.width;
4836 commentH = wpComment.height;
4840 XtSetArg(args[j], XtNheight, commentH); j++;
4841 XtSetArg(args[j], XtNwidth, commentW); j++;
4842 XtSetArg(args[j], XtNx, commentX); j++;
4843 XtSetArg(args[j], XtNy, commentY); j++;
4844 XtSetValues(shell, args, j);
4845 XtSetKeyboardFocus(shell, edit);
4850 /* Used for analysis window and ICS input window */
4851 Widget MiscCreate(name, text, mutable, callback, lines)
4853 int /*Boolean*/ mutable;
4854 XtCallbackProc callback;
4858 Widget shell, layout, form, edit;
4860 Dimension bw_width, pw_height, ew_height, w, h;
4866 XtSetArg(args[j], XtNresizable, True); j++;
4869 XtCreatePopupShell(name, topLevelShellWidgetClass,
4870 shellWidget, args, j);
4873 XtCreatePopupShell(name, transientShellWidgetClass,
4874 shellWidget, args, j);
4877 XtCreateManagedWidget(layoutName, formWidgetClass, shell,
4878 layoutArgs, XtNumber(layoutArgs));
4880 XtCreateManagedWidget("form", formWidgetClass, layout,
4881 formArgs, XtNumber(formArgs));
4885 XtSetArg(args[j], XtNeditType, XawtextEdit); j++;
4886 XtSetArg(args[j], XtNuseStringInPlace, False); j++;
4888 XtSetArg(args[j], XtNstring, text); j++;
4889 XtSetArg(args[j], XtNtop, XtChainTop); j++;
4890 XtSetArg(args[j], XtNbottom, XtChainBottom); j++;
4891 XtSetArg(args[j], XtNleft, XtChainLeft); j++;
4892 XtSetArg(args[j], XtNright, XtChainRight); j++;
4893 XtSetArg(args[j], XtNresizable, True); j++;
4894 /* !!Work around an apparent bug in XFree86 4.0.1 (X11R6.4.3) */
4895 XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways); j++;
4896 XtSetArg(args[j], XtNautoFill, True); j++;
4897 XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++;
4899 XtCreateManagedWidget("text", asciiTextWidgetClass, form, args, j);
4901 XtRealizeWidget(shell);
4904 XtSetArg(args[j], XtNwidth, &bw_width); j++;
4905 XtGetValues(boardWidget, args, j);
4908 XtSetArg(args[j], XtNheight, &ew_height); j++;
4909 XtGetValues(edit, args, j);
4912 XtSetArg(args[j], XtNheight, &pw_height); j++;
4913 XtGetValues(shell, args, j);
4914 h = pw_height + (lines - 1) * ew_height;
4917 XSync(xDisplay, False);
4919 /* This code seems to tickle an X bug if it is executed too soon
4920 after xboard starts up. The coordinates get transformed as if
4921 the main window was positioned at (0, 0).
4923 XtTranslateCoords(shellWidget, (bw_width - w) / 2, 0 - h / 2, &x, &y);
4925 XTranslateCoordinates(xDisplay, XtWindow(shellWidget),
4926 RootWindowOfScreen(XtScreen(shellWidget)),
4927 (bw_width - w) / 2, 0 - h / 2, &xx, &yy, &junk);
4931 if (y < 0) y = 0; /*avoid positioning top offscreen*/
4934 XtSetArg(args[j], XtNheight, h); j++;
4935 XtSetArg(args[j], XtNwidth, w); j++;
4936 XtSetArg(args[j], XtNx, x); j++;
4937 XtSetArg(args[j], XtNy, y); j++;
4938 XtSetValues(shell, args, j);
4944 static int savedIndex; /* gross that this is global */
4946 void CommentClick (Widget w, XEvent * event, String * params, Cardinal * nParams)
4949 XawTextPosition index, dummy;
4952 XawTextGetSelectionPos(w, &index, &dummy);
4953 XtSetArg(arg, XtNstring, &val);
4954 XtGetValues(w, &arg, 1);
4955 ReplaceComment(savedIndex, val);
4956 if(savedIndex != currentMove) ToNrEvent(savedIndex);
4957 LoadVariation( index, val ); // [HGM] also does the actual moving to it, now
4960 void EditCommentPopUp(index, title, text)
4969 if (text == NULL) text = "";
4971 if (editShell == NULL) {
4973 CommentCreate(title, text, True, EditCommentCallback, 4);
4974 XtRealizeWidget(editShell);
4975 CatchDeleteWindow(editShell, "EditCommentPopDown");
4977 edit = XtNameToWidget(editShell, "*form.text");
4979 XtSetArg(args[j], XtNstring, text); j++;
4980 XtSetValues(edit, args, j);
4982 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
4983 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
4984 XtSetValues(editShell, args, j);
4987 XtPopup(editShell, XtGrabNone);
4991 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
4992 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
4996 void EditCommentCallback(w, client_data, call_data)
4998 XtPointer client_data, call_data;
5006 XtSetArg(args[j], XtNlabel, &name); j++;
5007 XtGetValues(w, args, j);
5009 if (strcmp(name, _("ok")) == 0) {
5010 edit = XtNameToWidget(editShell, "*form.text");
5012 XtSetArg(args[j], XtNstring, &val); j++;
5013 XtGetValues(edit, args, j);
5014 ReplaceComment(savedIndex, val);
5015 EditCommentPopDown();
5016 } else if (strcmp(name, _("cancel")) == 0) {
5017 EditCommentPopDown();
5018 } else if (strcmp(name, _("clear")) == 0) {
5019 edit = XtNameToWidget(editShell, "*form.text");
5020 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5021 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5025 void EditCommentPopDown()
5030 if (!editUp) return;
5032 XtSetArg(args[j], XtNx, &commentX); j++;
5033 XtSetArg(args[j], XtNy, &commentY); j++;
5034 XtSetArg(args[j], XtNheight, &commentH); j++;
5035 XtSetArg(args[j], XtNwidth, &commentW); j++;
5036 XtGetValues(editShell, args, j);
5037 XtPopdown(editShell);
5040 XtSetArg(args[j], XtNleftBitmap, None); j++;
5041 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Edit Comment"),
5045 void ICSInputBoxPopUp()
5050 char *title = _("ICS Input");
5053 if (ICSInputShell == NULL) {
5054 ICSInputShell = MiscCreate(title, "", True, NULL, 1);
5055 tr = XtParseTranslationTable(ICSInputTranslations);
5056 edit = XtNameToWidget(ICSInputShell, "*form.text");
5057 XtOverrideTranslations(edit, tr);
5058 XtRealizeWidget(ICSInputShell);
5059 CatchDeleteWindow(ICSInputShell, "ICSInputBoxPopDown");
5062 edit = XtNameToWidget(ICSInputShell, "*form.text");
5064 XtSetArg(args[j], XtNstring, ""); j++;
5065 XtSetValues(edit, args, j);
5067 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5068 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5069 XtSetValues(ICSInputShell, args, j);
5072 XtPopup(ICSInputShell, XtGrabNone);
5073 XtSetKeyboardFocus(ICSInputShell, edit);
5075 ICSInputBoxUp = True;
5077 XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++;
5078 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5082 void ICSInputSendText()
5089 edit = XtNameToWidget(ICSInputShell, "*form.text");
5091 XtSetArg(args[j], XtNstring, &val); j++;
5092 XtGetValues(edit, args, j);
5094 SendMultiLineToICS(val);
5095 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
5096 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
5099 void ICSInputBoxPopDown()
5104 if (!ICSInputBoxUp) return;
5106 XtPopdown(ICSInputShell);
5107 ICSInputBoxUp = False;
5109 XtSetArg(args[j], XtNleftBitmap, None); j++;
5110 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.ICS Input Box"),
5114 void CommentPopUp(title, text)
5121 savedIndex = currentMove; // [HGM] vari
5122 if (commentShell == NULL) {
5124 CommentCreate(title, text, False, CommentCallback, 4);
5125 XtRealizeWidget(commentShell);
5126 CatchDeleteWindow(commentShell, "CommentPopDown");
5128 edit = XtNameToWidget(commentShell, "*form.text");
5130 XtSetArg(args[j], XtNstring, text); j++;
5131 XtSetValues(edit, args, j);
5133 XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++;
5134 XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++;
5135 XtSetValues(commentShell, args, j);
5138 XtPopup(commentShell, XtGrabNone);
5139 XSync(xDisplay, False);
5144 void CommentCallback(w, client_data, call_data)
5146 XtPointer client_data, call_data;
5153 XtSetArg(args[j], XtNlabel, &name); j++;
5154 XtGetValues(w, args, j);
5156 if (strcmp(name, _("close")) == 0) {
5158 } else if (strcmp(name, _("edit")) == 0) {
5165 void CommentPopDown()
5170 if (!commentUp) return;
5172 XtSetArg(args[j], XtNx, &commentX); j++;
5173 XtSetArg(args[j], XtNy, &commentY); j++;
5174 XtSetArg(args[j], XtNwidth, &commentW); j++;
5175 XtSetArg(args[j], XtNheight, &commentH); j++;
5176 XtGetValues(commentShell, args, j);
5177 XtPopdown(commentShell);
5178 XSync(xDisplay, False);
5182 void FileNamePopUp(label, def, proc, openMode)
5188 fileProc = proc; /* I can't see a way not */
5189 fileOpenMode = openMode; /* to use globals here */
5190 { // [HGM] use file-selector dialog stolen from Ghostview
5192 int index; // this is not supported yet
5194 if(f = XsraSelFile(shellWidget, label, NULL, NULL, "could not open: ",
5195 def, openMode, NULL, &name))
5196 (void) (*fileProc)(f, index=0, name);
5200 void FileNamePopDown()
5202 if (!filenameUp) return;
5203 XtPopdown(fileNameShell);
5204 XtDestroyWidget(fileNameShell);
5209 void FileNameCallback(w, client_data, call_data)
5211 XtPointer client_data, call_data;
5216 XtSetArg(args[0], XtNlabel, &name);
5217 XtGetValues(w, args, 1);
5219 if (strcmp(name, _("cancel")) == 0) {
5224 FileNameAction(w, NULL, NULL, NULL);
5227 void FileNameAction(w, event, prms, nprms)
5239 name = XawDialogGetValueString(w = XtParent(w));
5241 if ((name != NULL) && (*name != NULLCHAR)) {
5242 safeStrCpy(buf, name, sizeof(buf)/sizeof(buf[0]) );
5243 XtPopdown(w = XtParent(XtParent(w)));
5247 p = strrchr(buf, ' ');
5254 fullname = ExpandPathName(buf);
5256 ErrorPopUp(_("Error"), _("Can't open file"), FALSE);
5259 f = fopen(fullname, fileOpenMode);
5261 DisplayError(_("Failed to open file"), errno);
5263 (void) (*fileProc)(f, index, buf);
5270 XtPopdown(w = XtParent(XtParent(w)));
5276 void PromotionPopUp()
5279 Widget dialog, layout;
5281 Dimension bw_width, pw_width;
5285 XtSetArg(args[j], XtNwidth, &bw_width); j++;
5286 XtGetValues(boardWidget, args, j);
5289 XtSetArg(args[j], XtNresizable, True); j++;
5290 XtSetArg(args[j], XtNtitle, XtNewString(_("Promotion"))); j++;
5292 XtCreatePopupShell("Promotion", transientShellWidgetClass,
5293 shellWidget, args, j);
5295 XtCreateManagedWidget(layoutName, formWidgetClass, promotionShell,
5296 layoutArgs, XtNumber(layoutArgs));
5299 XtSetArg(args[j], XtNlabel, _("Promote to what?")); j++;
5300 XtSetArg(args[j], XtNborderWidth, 0); j++;
5301 dialog = XtCreateManagedWidget("promotion", dialogWidgetClass,
5304 if(gameInfo.variant != VariantShogi) {
5305 XawDialogAddButton(dialog, _("Queen"), PromotionCallback,
5306 (XtPointer) dialog);
5307 XawDialogAddButton(dialog, _("Rook"), PromotionCallback,
5308 (XtPointer) dialog);
5309 XawDialogAddButton(dialog, _("Bishop"), PromotionCallback,
5310 (XtPointer) dialog);
5311 XawDialogAddButton(dialog, _("Knight"), PromotionCallback,
5312 (XtPointer) dialog);
5313 if (!appData.testLegality || gameInfo.variant == VariantSuicide ||
5314 gameInfo.variant == VariantGiveaway) {
5315 XawDialogAddButton(dialog, _("King"), PromotionCallback,
5316 (XtPointer) dialog);
5318 if(gameInfo.variant == VariantCapablanca ||
5319 gameInfo.variant == VariantGothic ||
5320 gameInfo.variant == VariantCapaRandom) {
5321 XawDialogAddButton(dialog, _("Archbishop"), PromotionCallback,
5322 (XtPointer) dialog);
5323 XawDialogAddButton(dialog, _("Chancellor"), PromotionCallback,
5324 (XtPointer) dialog);
5326 } else // [HGM] shogi
5328 XawDialogAddButton(dialog, _("Promote"), PromotionCallback,
5329 (XtPointer) dialog);
5330 XawDialogAddButton(dialog, _("Defer"), PromotionCallback,
5331 (XtPointer) dialog);
5333 XawDialogAddButton(dialog, _("cancel"), PromotionCallback,
5334 (XtPointer) dialog);
5336 XtRealizeWidget(promotionShell);
5337 CatchDeleteWindow(promotionShell, "PromotionPopDown");
5340 XtSetArg(args[j], XtNwidth, &pw_width); j++;
5341 XtGetValues(promotionShell, args, j);
5343 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5344 lineGap + squareSize/3 +
5345 ((toY == BOARD_HEIGHT-1) ^ (flipView) ?
5346 0 : 6*(squareSize + lineGap)), &x, &y);
5349 XtSetArg(args[j], XtNx, x); j++;
5350 XtSetArg(args[j], XtNy, y); j++;
5351 XtSetValues(promotionShell, args, j);
5353 XtPopup(promotionShell, XtGrabNone);
5358 void PromotionPopDown()
5360 if (!promotionUp) return;
5361 XtPopdown(promotionShell);
5362 XtDestroyWidget(promotionShell);
5363 promotionUp = False;
5366 void PromotionCallback(w, client_data, call_data)
5368 XtPointer client_data, call_data;
5374 XtSetArg(args[0], XtNlabel, &name);
5375 XtGetValues(w, args, 1);
5379 if (fromX == -1) return;
5381 if (strcmp(name, _("cancel")) == 0) {
5385 } else if (strcmp(name, _("Knight")) == 0) {
5387 } else if (strcmp(name, _("Promote")) == 0) {
5389 } else if (strcmp(name, _("Defer")) == 0) {
5392 promoChar = ToLower(name[0]);
5395 UserMoveEvent(fromX, fromY, toX, toY, promoChar);
5397 if (!appData.highlightLastMove || gotPremove) ClearHighlights();
5398 if (gotPremove) SetPremoveHighlights(fromX, fromY, toX, toY);
5403 void ErrorCallback(w, client_data, call_data)
5405 XtPointer client_data, call_data;
5408 XtPopdown(w = XtParent(XtParent(XtParent(w))));
5410 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5416 if (!errorUp) return;
5418 XtPopdown(errorShell);
5419 XtDestroyWidget(errorShell);
5420 if (errorExitStatus != -1) ExitEvent(errorExitStatus);
5423 void ErrorPopUp(title, label, modal)
5424 char *title, *label;
5428 Widget dialog, layout;
5432 Dimension bw_width, pw_width;
5433 Dimension pw_height;
5437 XtSetArg(args[i], XtNresizable, True); i++;
5438 XtSetArg(args[i], XtNtitle, title); i++;
5440 XtCreatePopupShell("errorpopup", transientShellWidgetClass,
5441 shellWidget, args, i);
5443 XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
5444 layoutArgs, XtNumber(layoutArgs));
5447 XtSetArg(args[i], XtNlabel, label); i++;
5448 XtSetArg(args[i], XtNborderWidth, 0); i++;
5449 dialog = XtCreateManagedWidget("dialog", dialogWidgetClass,
5452 XawDialogAddButton(dialog, _("ok"), ErrorCallback, (XtPointer) dialog);
5454 XtRealizeWidget(errorShell);
5455 CatchDeleteWindow(errorShell, "ErrorPopDown");
5458 XtSetArg(args[i], XtNwidth, &bw_width); i++;
5459 XtGetValues(boardWidget, args, i);
5461 XtSetArg(args[i], XtNwidth, &pw_width); i++;
5462 XtSetArg(args[i], XtNheight, &pw_height); i++;
5463 XtGetValues(errorShell, args, i);
5466 /* This code seems to tickle an X bug if it is executed too soon
5467 after xboard starts up. The coordinates get transformed as if
5468 the main window was positioned at (0, 0).
5470 XtTranslateCoords(boardWidget, (bw_width - pw_width) / 2,
5471 0 - pw_height + squareSize / 3, &x, &y);
5473 XTranslateCoordinates(xDisplay, XtWindow(boardWidget),
5474 RootWindowOfScreen(XtScreen(boardWidget)),
5475 (bw_width - pw_width) / 2,
5476 0 - pw_height + squareSize / 3, &xx, &yy, &junk);
5480 if (y < 0) y = 0; /*avoid positioning top offscreen*/
5483 XtSetArg(args[i], XtNx, x); i++;
5484 XtSetArg(args[i], XtNy, y); i++;
5485 XtSetValues(errorShell, args, i);
5488 XtPopup(errorShell, modal ? XtGrabExclusive : XtGrabNone);
5491 /* Disable all user input other than deleting the window */
5492 static int frozen = 0;
5496 /* Grab by a widget that doesn't accept input */
5497 XtAddGrab(messageWidget, TRUE, FALSE);
5501 /* Undo a FreezeUI */
5504 if (!frozen) return;
5505 XtRemoveGrab(messageWidget);
5509 char *ModeToWidgetName(mode)
5513 case BeginningOfGame:
5514 if (appData.icsActive)
5515 return "menuMode.ICS Client";
5516 else if (appData.noChessProgram ||
5517 *appData.cmailGameName != NULLCHAR)
5518 return "menuMode.Edit Game";
5520 return "menuMode.Machine Black";
5521 case MachinePlaysBlack:
5522 return "menuMode.Machine Black";
5523 case MachinePlaysWhite:
5524 return "menuMode.Machine White";
5526 return "menuMode.Analysis Mode";
5528 return "menuMode.Analyze File";
5529 case TwoMachinesPlay:
5530 return "menuMode.Two Machines";
5532 return "menuMode.Edit Game";
5533 case PlayFromGameFile:
5534 return "menuFile.Load Game";
5536 return "menuMode.Edit Position";
5538 return "menuMode.Training";
5539 case IcsPlayingWhite:
5540 case IcsPlayingBlack:
5544 return "menuMode.ICS Client";
5551 void ModeHighlight()
5554 static int oldPausing = FALSE;
5555 static GameMode oldmode = (GameMode) -1;
5558 if (!boardWidget || !XtIsRealized(boardWidget)) return;
5560 if (pausing != oldPausing) {
5561 oldPausing = pausing;
5563 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5565 XtSetArg(args[0], XtNleftBitmap, None);
5567 XtSetValues(XtNameToWidget(menuBarWidget, "menuMode.Pause"),
5570 if (appData.showButtonBar) {
5571 /* Always toggle, don't set. Previous code messes up when
5572 invoked while the button is pressed, as releasing it
5573 toggles the state again. */
5576 XtSetArg(args[0], XtNbackground, &oldbg);
5577 XtSetArg(args[1], XtNforeground, &oldfg);
5578 XtGetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON),
5580 XtSetArg(args[0], XtNbackground, oldfg);
5581 XtSetArg(args[1], XtNforeground, oldbg);
5583 XtSetValues(XtNameToWidget(buttonBarWidget, PAUSE_BUTTON), args, 2);
5587 wname = ModeToWidgetName(oldmode);
5588 if (wname != NULL) {
5589 XtSetArg(args[0], XtNleftBitmap, None);
5590 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5592 wname = ModeToWidgetName(gameMode);
5593 if (wname != NULL) {
5594 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
5595 XtSetValues(XtNameToWidget(menuBarWidget, wname), args, 1);
5599 /* Maybe all the enables should be handled here, not just this one */
5600 XtSetSensitive(XtNameToWidget(menuBarWidget, "menuMode.Training"),
5601 gameMode == Training || gameMode == PlayFromGameFile);
5606 * Button/menu procedures
5608 void ResetProc(w, event, prms, nprms)
5617 int LoadGamePopUp(f, gameNumber, title)
5622 cmailMsgLoaded = FALSE;
5623 if (gameNumber == 0) {
5624 int error = GameListBuild(f);
5626 DisplayError(_("Cannot build game list"), error);
5627 } else if (!ListEmpty(&gameList) &&
5628 ((ListGame *) gameList.tailPred)->number > 1) {
5629 GameListPopUp(f, title);
5635 return LoadGame(f, gameNumber, title, FALSE);
5638 void LoadGameProc(w, event, prms, nprms)
5644 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5647 FileNamePopUp(_("Load game file name?"), "", LoadGamePopUp, "rb");
5650 void LoadNextGameProc(w, event, prms, nprms)
5659 void LoadPrevGameProc(w, event, prms, nprms)
5668 void ReloadGameProc(w, event, prms, nprms)
5677 void LoadNextPositionProc(w, event, prms, nprms)
5686 void LoadPrevPositionProc(w, event, prms, nprms)
5695 void ReloadPositionProc(w, event, prms, nprms)
5704 void LoadPositionProc(w, event, prms, nprms)
5710 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile) {
5713 FileNamePopUp(_("Load position file name?"), "", LoadPosition, "rb");
5716 void SaveGameProc(w, event, prms, nprms)
5722 FileNamePopUp(_("Save game file name?"),
5723 DefaultFileName(appData.oldSaveStyle ? "game" : "pgn"),
5727 void SavePositionProc(w, event, prms, nprms)
5733 FileNamePopUp(_("Save position file name?"),
5734 DefaultFileName(appData.oldSaveStyle ? "pos" : "fen"),
5738 void ReloadCmailMsgProc(w, event, prms, nprms)
5744 ReloadCmailMsgEvent(FALSE);
5747 void MailMoveProc(w, event, prms, nprms)
5756 /* this variable is shared between CopyPositionProc and SendPositionSelection */
5757 char *selected_fen_position=NULL;
5760 SendPositionSelection(Widget w, Atom *selection, Atom *target,
5761 Atom *type_return, XtPointer *value_return,
5762 unsigned long *length_return, int *format_return)
5764 char *selection_tmp;
5766 if (!selected_fen_position) return False; /* should never happen */
5767 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5768 /* note: since no XtSelectionDoneProc was registered, Xt will
5769 * automatically call XtFree on the value returned. So have to
5770 * make a copy of it allocated with XtMalloc */
5771 selection_tmp= XtMalloc(strlen(selected_fen_position)+16);
5772 safeStrCpy(selection_tmp, selected_fen_position, sizeof(selection_tmp)/sizeof(selection_tmp[0]) );
5774 *value_return=selection_tmp;
5775 *length_return=strlen(selection_tmp);
5776 *type_return=*target;
5777 *format_return = 8; /* bits per byte */
5779 } else if (*target == XA_TARGETS(xDisplay)) {
5780 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5781 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5782 targets_tmp[1] = XA_STRING;
5783 *value_return = targets_tmp;
5784 *type_return = XA_ATOM;
5786 *format_return = 8 * sizeof(Atom);
5787 if (*format_return > 32) {
5788 *length_return *= *format_return / 32;
5789 *format_return = 32;
5797 /* note: when called from menu all parameters are NULL, so no clue what the
5798 * Widget which was clicked on was, or what the click event was
5800 void CopyPositionProc(w, event, prms, nprms)
5807 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5808 * have a notion of a position that is selected but not copied.
5809 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5811 if(gameMode == EditPosition) EditPositionDone(TRUE);
5812 if (selected_fen_position) free(selected_fen_position);
5813 selected_fen_position = (char *)PositionToFEN(currentMove, NULL);
5814 if (!selected_fen_position) return;
5815 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5817 SendPositionSelection,
5818 NULL/* lose_ownership_proc */ ,
5819 NULL/* transfer_done_proc */);
5820 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5822 SendPositionSelection,
5823 NULL/* lose_ownership_proc */ ,
5824 NULL/* transfer_done_proc */);
5827 /* function called when the data to Paste is ready */
5829 PastePositionCB(Widget w, XtPointer client_data, Atom *selection,
5830 Atom *type, XtPointer value, unsigned long *len, int *format)
5833 if (value==NULL || *len==0) return; /* nothing had been selected to copy */
5834 fenstr[*len]='\0'; /* normally this string is terminated, but be safe */
5835 EditPositionPasteFEN(fenstr);
5839 /* called when Paste Position button is pressed,
5840 * all parameters will be NULL */
5841 void PastePositionProc(w, event, prms, nprms)
5847 XtGetSelectionValue(menuBarWidget,
5848 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5849 /* (XtSelectionCallbackProc) */ PastePositionCB,
5850 NULL, /* client_data passed to PastePositionCB */
5852 /* better to use the time field from the event that triggered the
5853 * call to this function, but that isn't trivial to get
5861 SendGameSelection(Widget w, Atom *selection, Atom *target,
5862 Atom *type_return, XtPointer *value_return,
5863 unsigned long *length_return, int *format_return)
5865 char *selection_tmp;
5867 if (*target == XA_STRING || *target == XA_UTF8_STRING(xDisplay)){
5868 FILE* f = fopen(gameCopyFilename, "r");
5871 if (f == NULL) return False;
5875 selection_tmp = XtMalloc(len + 1);
5876 count = fread(selection_tmp, 1, len, f);
5878 XtFree(selection_tmp);
5881 selection_tmp[len] = NULLCHAR;
5882 *value_return = selection_tmp;
5883 *length_return = len;
5884 *type_return = *target;
5885 *format_return = 8; /* bits per byte */
5887 } else if (*target == XA_TARGETS(xDisplay)) {
5888 Atom *targets_tmp = (Atom *) XtMalloc(2 * sizeof(Atom));
5889 targets_tmp[0] = XA_UTF8_STRING(xDisplay);
5890 targets_tmp[1] = XA_STRING;
5891 *value_return = targets_tmp;
5892 *type_return = XA_ATOM;
5894 *format_return = 8 * sizeof(Atom);
5895 if (*format_return > 32) {
5896 *length_return *= *format_return / 32;
5897 *format_return = 32;
5905 /* note: when called from menu all parameters are NULL, so no clue what the
5906 * Widget which was clicked on was, or what the click event was
5908 void CopyGameProc(w, event, prms, nprms)
5916 ret = SaveGameToFile(gameCopyFilename, FALSE);
5920 * Set both PRIMARY (the selection) and CLIPBOARD, since we don't
5921 * have a notion of a game that is selected but not copied.
5922 * See http://www.freedesktop.org/wiki/Specifications/ClipboardsWiki
5924 XtOwnSelection(menuBarWidget, XA_PRIMARY,
5927 NULL/* lose_ownership_proc */ ,
5928 NULL/* transfer_done_proc */);
5929 XtOwnSelection(menuBarWidget, XA_CLIPBOARD(xDisplay),
5932 NULL/* lose_ownership_proc */ ,
5933 NULL/* transfer_done_proc */);
5936 /* function called when the data to Paste is ready */
5938 PasteGameCB(Widget w, XtPointer client_data, Atom *selection,
5939 Atom *type, XtPointer value, unsigned long *len, int *format)
5942 if (value == NULL || *len == 0) {
5943 return; /* nothing had been selected to copy */
5945 f = fopen(gamePasteFilename, "w");
5947 DisplayError(_("Can't open temp file"), errno);
5950 fwrite(value, 1, *len, f);
5953 LoadGameFromFile(gamePasteFilename, 0, gamePasteFilename, TRUE);
5956 /* called when Paste Game button is pressed,
5957 * all parameters will be NULL */
5958 void PasteGameProc(w, event, prms, nprms)
5964 XtGetSelectionValue(menuBarWidget,
5965 appData.pasteSelection ? XA_PRIMARY: XA_CLIPBOARD(xDisplay), XA_STRING,
5966 /* (XtSelectionCallbackProc) */ PasteGameCB,
5967 NULL, /* client_data passed to PasteGameCB */
5969 /* better to use the time field from the event that triggered the
5970 * call to this function, but that isn't trivial to get
5980 SaveGameProc(NULL, NULL, NULL, NULL);
5984 void QuitProc(w, event, prms, nprms)
5993 void PauseProc(w, event, prms, nprms)
6003 void MachineBlackProc(w, event, prms, nprms)
6009 MachineBlackEvent();
6012 void MachineWhiteProc(w, event, prms, nprms)
6018 MachineWhiteEvent();
6021 void AnalyzeModeProc(w, event, prms, nprms)
6029 if (!first.analysisSupport) {
6030 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6031 DisplayError(buf, 0);
6034 /* [DM] icsEngineAnalyze [HGM] This is horrible code; reverse the gameMode and isEngineAnalyze tests! */
6035 if (appData.icsActive) {
6036 if (gameMode != IcsObserving) {
6037 snprintf(buf, MSG_SIZ, _("You are not observing a game"));
6038 DisplayError(buf, 0);
6040 if (appData.icsEngineAnalyze) {
6041 if (appData.debugMode)
6042 fprintf(debugFP, _("Found unexpected active ICS engine analyze \n"));
6048 /* if enable, use want disable icsEngineAnalyze */
6049 if (appData.icsEngineAnalyze) {
6054 appData.icsEngineAnalyze = TRUE;
6055 if (appData.debugMode)
6056 fprintf(debugFP, _("ICS engine analyze starting... \n"));
6058 if (!appData.showThinking)
6059 ShowThinkingProc(w,event,prms,nprms);
6064 void AnalyzeFileProc(w, event, prms, nprms)
6070 if (!first.analysisSupport) {
6072 snprintf(buf, sizeof(buf), _("%s does not support analysis"), first.tidy);
6073 DisplayError(buf, 0);
6078 if (!appData.showThinking)
6079 ShowThinkingProc(w,event,prms,nprms);
6082 FileNamePopUp(_("File to analyze"), "", LoadGamePopUp, "rb");
6083 AnalysisPeriodicEvent(1);
6086 void TwoMachinesProc(w, event, prms, nprms)
6095 void IcsClientProc(w, event, prms, nprms)
6104 void EditGameProc(w, event, prms, nprms)
6113 void EditPositionProc(w, event, prms, nprms)
6119 EditPositionEvent();
6122 void TrainingProc(w, event, prms, nprms)
6131 void EditCommentProc(w, event, prms, nprms)
6138 EditCommentPopDown();
6144 void IcsInputBoxProc(w, event, prms, nprms)
6150 if (ICSInputBoxUp) {
6151 ICSInputBoxPopDown();
6157 void AcceptProc(w, event, prms, nprms)
6166 void DeclineProc(w, event, prms, nprms)
6175 void RematchProc(w, event, prms, nprms)
6184 void CallFlagProc(w, event, prms, nprms)
6193 void DrawProc(w, event, prms, nprms)
6202 void AbortProc(w, event, prms, nprms)
6211 void AdjournProc(w, event, prms, nprms)
6220 void ResignProc(w, event, prms, nprms)
6229 void AdjuWhiteProc(w, event, prms, nprms)
6235 UserAdjudicationEvent(+1);
6238 void AdjuBlackProc(w, event, prms, nprms)
6244 UserAdjudicationEvent(-1);
6247 void AdjuDrawProc(w, event, prms, nprms)
6253 UserAdjudicationEvent(0);
6256 void EnterKeyProc(w, event, prms, nprms)
6262 if (ICSInputBoxUp == True)
6266 void UpKeyProc(w, event, prms, nprms)
6271 { // [HGM] input: let up-arrow recall previous line from history
6278 if (!ICSInputBoxUp) return;
6279 edit = XtNameToWidget(ICSInputShell, "*form.text");
6281 XtSetArg(args[j], XtNstring, &val); j++;
6282 XtGetValues(edit, args, j);
6283 val = PrevInHistory(val);
6284 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6285 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6287 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6288 XawTextReplace(edit, 0, 0, &t);
6289 XawTextSetInsertionPoint(edit, 9999);
6293 void DownKeyProc(w, event, prms, nprms)
6298 { // [HGM] input: let down-arrow recall next line from history
6303 if (!ICSInputBoxUp) return;
6304 edit = XtNameToWidget(ICSInputShell, "*form.text");
6305 val = NextInHistory();
6306 XtCallActionProc(edit, "select-all", NULL, NULL, 0);
6307 XtCallActionProc(edit, "kill-selection", NULL, NULL, 0);
6309 t.ptr = val; t.firstPos = 0; t.length = strlen(val); t.format = XawFmt8Bit;
6310 XawTextReplace(edit, 0, 0, &t);
6311 XawTextSetInsertionPoint(edit, 9999);
6315 void StopObservingProc(w, event, prms, nprms)
6321 StopObservingEvent();
6324 void StopExaminingProc(w, event, prms, nprms)
6330 StopExaminingEvent();
6333 void UploadProc(w, event, prms, nprms)
6343 void ForwardProc(w, event, prms, nprms)
6353 void BackwardProc(w, event, prms, nprms)
6362 void ToStartProc(w, event, prms, nprms)
6371 void ToEndProc(w, event, prms, nprms)
6380 void RevertProc(w, event, prms, nprms)
6389 void AnnotateProc(w, event, prms, nprms)
6398 void TruncateGameProc(w, event, prms, nprms)
6404 TruncateGameEvent();
6406 void RetractMoveProc(w, event, prms, nprms)
6415 void MoveNowProc(w, event, prms, nprms)
6425 void AlwaysQueenProc(w, event, prms, nprms)
6433 appData.alwaysPromoteToQueen = !appData.alwaysPromoteToQueen;
6435 if (appData.alwaysPromoteToQueen) {
6436 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6438 XtSetArg(args[0], XtNleftBitmap, None);
6440 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Always Queen"),
6444 void AnimateDraggingProc(w, event, prms, nprms)
6452 appData.animateDragging = !appData.animateDragging;
6454 if (appData.animateDragging) {
6455 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6458 XtSetArg(args[0], XtNleftBitmap, None);
6460 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Dragging"),
6464 void AnimateMovingProc(w, event, prms, nprms)
6472 appData.animate = !appData.animate;
6474 if (appData.animate) {
6475 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6478 XtSetArg(args[0], XtNleftBitmap, None);
6480 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Animate Moving"),
6484 void AutocommProc(w, event, prms, nprms)
6492 appData.autoComment = !appData.autoComment;
6494 if (appData.autoComment) {
6495 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6497 XtSetArg(args[0], XtNleftBitmap, None);
6499 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Comment"),
6504 void AutoflagProc(w, event, prms, nprms)
6512 appData.autoCallFlag = !appData.autoCallFlag;
6514 if (appData.autoCallFlag) {
6515 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6517 XtSetArg(args[0], XtNleftBitmap, None);
6519 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flag"),
6523 void AutoflipProc(w, event, prms, nprms)
6531 appData.autoFlipView = !appData.autoFlipView;
6533 if (appData.autoFlipView) {
6534 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6536 XtSetArg(args[0], XtNleftBitmap, None);
6538 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Flip View"),
6542 void AutobsProc(w, event, prms, nprms)
6550 appData.autoObserve = !appData.autoObserve;
6552 if (appData.autoObserve) {
6553 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6555 XtSetArg(args[0], XtNleftBitmap, None);
6557 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Observe"),
6561 void AutoraiseProc(w, event, prms, nprms)
6569 appData.autoRaiseBoard = !appData.autoRaiseBoard;
6571 if (appData.autoRaiseBoard) {
6572 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6574 XtSetArg(args[0], XtNleftBitmap, None);
6576 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Raise Board"),
6580 void AutosaveProc(w, event, prms, nprms)
6588 appData.autoSaveGames = !appData.autoSaveGames;
6590 if (appData.autoSaveGames) {
6591 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6593 XtSetArg(args[0], XtNleftBitmap, None);
6595 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Auto Save"),
6599 void BlindfoldProc(w, event, prms, nprms)
6607 appData.blindfold = !appData.blindfold;
6609 if (appData.blindfold) {
6610 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6612 XtSetArg(args[0], XtNleftBitmap, None);
6614 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Blindfold"),
6617 DrawPosition(True, NULL);
6620 void TestLegalityProc(w, event, prms, nprms)
6628 appData.testLegality = !appData.testLegality;
6630 if (appData.testLegality) {
6631 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6633 XtSetArg(args[0], XtNleftBitmap, None);
6635 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Test Legality"),
6640 void FlashMovesProc(w, event, prms, nprms)
6648 if (appData.flashCount == 0) {
6649 appData.flashCount = 3;
6651 appData.flashCount = -appData.flashCount;
6654 if (appData.flashCount > 0) {
6655 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6657 XtSetArg(args[0], XtNleftBitmap, None);
6659 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Flash Moves"),
6663 void FlipViewProc(w, event, prms, nprms)
6669 flipView = !flipView;
6670 DrawPosition(True, NULL);
6673 void GetMoveListProc(w, event, prms, nprms)
6681 appData.getMoveList = !appData.getMoveList;
6683 if (appData.getMoveList) {
6684 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6687 XtSetArg(args[0], XtNleftBitmap, None);
6689 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Get Move List"),
6694 void HighlightDraggingProc(w, event, prms, nprms)
6702 appData.highlightDragging = !appData.highlightDragging;
6704 if (appData.highlightDragging) {
6705 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6707 XtSetArg(args[0], XtNleftBitmap, None);
6709 XtSetValues(XtNameToWidget(menuBarWidget,
6710 "menuOptions.Highlight Dragging"), args, 1);
6714 void HighlightLastMoveProc(w, event, prms, nprms)
6722 appData.highlightLastMove = !appData.highlightLastMove;
6724 if (appData.highlightLastMove) {
6725 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6727 XtSetArg(args[0], XtNleftBitmap, None);
6729 XtSetValues(XtNameToWidget(menuBarWidget,
6730 "menuOptions.Highlight Last Move"), args, 1);
6733 void IcsAlarmProc(w, event, prms, nprms)
6741 appData.icsAlarm = !appData.icsAlarm;
6743 if (appData.icsAlarm) {
6744 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6746 XtSetArg(args[0], XtNleftBitmap, None);
6748 XtSetValues(XtNameToWidget(menuBarWidget,
6749 "menuOptions.ICS Alarm"), args, 1);
6752 void MoveSoundProc(w, event, prms, nprms)
6760 appData.ringBellAfterMoves = !appData.ringBellAfterMoves;
6762 if (appData.ringBellAfterMoves) {
6763 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6765 XtSetArg(args[0], XtNleftBitmap, None);
6767 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Move Sound"),
6772 void OldSaveStyleProc(w, event, prms, nprms)
6780 appData.oldSaveStyle = !appData.oldSaveStyle;
6782 if (appData.oldSaveStyle) {
6783 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6785 XtSetArg(args[0], XtNleftBitmap, None);
6787 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Old Save Style"),
6791 void PeriodicUpdatesProc(w, event, prms, nprms)
6799 PeriodicUpdatesEvent(!appData.periodicUpdates);
6801 if (appData.periodicUpdates) {
6802 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6804 XtSetArg(args[0], XtNleftBitmap, None);
6806 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Periodic Updates"),
6810 void PonderNextMoveProc(w, event, prms, nprms)
6818 PonderNextMoveEvent(!appData.ponderNextMove);
6820 if (appData.ponderNextMove) {
6821 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6823 XtSetArg(args[0], XtNleftBitmap, None);
6825 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Ponder Next Move"),
6829 void PopupExitMessageProc(w, event, prms, nprms)
6837 appData.popupExitMessage = !appData.popupExitMessage;
6839 if (appData.popupExitMessage) {
6840 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6842 XtSetArg(args[0], XtNleftBitmap, None);
6844 XtSetValues(XtNameToWidget(menuBarWidget,
6845 "menuOptions.Popup Exit Message"), args, 1);
6848 void PopupMoveErrorsProc(w, event, prms, nprms)
6856 appData.popupMoveErrors = !appData.popupMoveErrors;
6858 if (appData.popupMoveErrors) {
6859 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6861 XtSetArg(args[0], XtNleftBitmap, None);
6863 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Popup Move Errors"),
6867 void PremoveProc(w, event, prms, nprms)
6875 appData.premove = !appData.premove;
6877 if (appData.premove) {
6878 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6880 XtSetArg(args[0], XtNleftBitmap, None);
6882 XtSetValues(XtNameToWidget(menuBarWidget,
6883 "menuOptions.Premove"), args, 1);
6886 void QuietPlayProc(w, event, prms, nprms)
6894 appData.quietPlay = !appData.quietPlay;
6896 if (appData.quietPlay) {
6897 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6899 XtSetArg(args[0], XtNleftBitmap, None);
6901 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Quiet Play"),
6905 void ShowCoordsProc(w, event, prms, nprms)
6913 appData.showCoords = !appData.showCoords;
6915 if (appData.showCoords) {
6916 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6918 XtSetArg(args[0], XtNleftBitmap, None);
6920 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Show Coords"),
6923 DrawPosition(True, NULL);
6926 void ShowThinkingProc(w, event, prms, nprms)
6932 appData.showThinking = !appData.showThinking; // [HGM] thinking: tken out of ShowThinkingEvent
6933 ShowThinkingEvent();
6936 void HideThinkingProc(w, event, prms, nprms)
6944 appData.hideThinkingFromHuman = !appData.hideThinkingFromHuman; // [HGM] thinking: tken out of ShowThinkingEvent
6945 ShowThinkingEvent();
6947 if (appData.hideThinkingFromHuman) {
6948 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6950 XtSetArg(args[0], XtNleftBitmap, None);
6952 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Hide Thinking"),
6956 void SaveOnExitProc(w, event, prms, nprms)
6964 saveSettingsOnExit = !saveSettingsOnExit;
6966 if (saveSettingsOnExit) {
6967 XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
6969 XtSetArg(args[0], XtNleftBitmap, None);
6971 XtSetValues(XtNameToWidget(menuBarWidget, "menuOptions.Save Settings on Exit"),
6975 void SaveSettingsProc(w, event, prms, nprms)
6981 SaveSettings(settingsFileName);
6984 void InfoProc(w, event, prms, nprms)
6991 snprintf(buf, sizeof(buf), "xterm -e info --directory %s --directory . -f %s &",
6996 void ManProc(w, event, prms, nprms)
7004 if (nprms && *nprms > 0)
7008 snprintf(buf, sizeof(buf), "xterm -e man %s &", name);
7012 void HintProc(w, event, prms, nprms)
7021 void BookProc(w, event, prms, nprms)
7030 void AboutProc(w, event, prms, nprms)
7038 char *zippy = " (with Zippy code)";
7042 snprintf(buf, sizeof(buf), "%s%s\n\n%s\n%s\n%s\n\n%s%s\n%s",
7043 programVersion, zippy,
7044 "Copyright 1991 Digital Equipment Corporation",
7045 "Enhancements Copyright 1992-2009 Free Software Foundation",
7046 "Enhancements Copyright 2005 Alessandro Scotti",
7047 PACKAGE, " is free software and carries NO WARRANTY;",
7048 "see the file COPYING for more information.");
7049 ErrorPopUp(_("About XBoard"), buf, FALSE);
7052 void DebugProc(w, event, prms, nprms)
7058 appData.debugMode = !appData.debugMode;
7061 void AboutGameProc(w, event, prms, nprms)
7070 void NothingProc(w, event, prms, nprms)
7079 void Iconify(w, event, prms, nprms)
7088 XtSetArg(args[0], XtNiconic, True);
7089 XtSetValues(shellWidget, args, 1);
7092 void DisplayMessage(message, extMessage)
7093 char *message, *extMessage;
7095 /* display a message in the message widget */
7104 snprintf(buf, sizeof(buf), "%s %s", message, extMessage);
7109 message = extMessage;
7113 /* need to test if messageWidget already exists, since this function
7114 can also be called during the startup, if for example a Xresource
7115 is not set up correctly */
7118 XtSetArg(arg, XtNlabel, message);
7119 XtSetValues(messageWidget, &arg, 1);
7125 void DisplayTitle(text)
7130 char title[MSG_SIZ];
7133 if (text == NULL) text = "";
7135 if (appData.titleInWindow) {
7137 XtSetArg(args[i], XtNlabel, text); i++;
7138 XtSetValues(titleWidget, args, i);
7141 if (*text != NULLCHAR) {
7142 safeStrCpy(icon, text, sizeof(icon)/sizeof(icon[0]) );
7143 safeStrCpy(title, text, sizeof(title)/sizeof(title[0]) );
7144 } else if (appData.icsActive) {
7145 snprintf(icon, sizeof(icon), "%s", appData.icsHost);
7146 snprintf(title, sizeof(title), "%s: %s", programName, appData.icsHost);
7147 } else if (appData.cmailGameName[0] != NULLCHAR) {
7148 snprintf(icon, sizeof(icon), "%s", "CMail");
7149 snprintf(title,sizeof(title), "%s: %s", programName, "CMail");
7151 // [HGM] license: This stuff should really be done in back-end, but WinBoard already had a pop-up for it
7152 } else if (gameInfo.variant == VariantGothic) {
7153 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7154 safeStrCpy(title, GOTHIC, sizeof(title)/sizeof(title[0]) );
7157 } else if (gameInfo.variant == VariantFalcon) {
7158 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7159 safeStrCpy(title, FALCON, sizeof(title)/sizeof(title[0]) );
7161 } else if (appData.noChessProgram) {
7162 safeStrCpy(icon, programName, sizeof(icon)/sizeof(icon[0]) );
7163 safeStrCpy(title, programName, sizeof(title)/sizeof(title[0]) );
7165 safeStrCpy(icon, first.tidy, sizeof(icon)/sizeof(icon[0]) );
7166 snprintf(title,sizeof(title), "%s: %s", programName, first.tidy);
7169 XtSetArg(args[i], XtNiconName, (XtArgVal) icon); i++;
7170 XtSetArg(args[i], XtNtitle, (XtArgVal) title); i++;
7171 XtSetValues(shellWidget, args, i);
7176 DisplayError(message, error)
7183 if (appData.debugMode || appData.matchMode) {
7184 fprintf(stderr, "%s: %s\n", programName, message);
7187 if (appData.debugMode || appData.matchMode) {
7188 fprintf(stderr, "%s: %s: %s\n",
7189 programName, message, strerror(error));
7191 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7194 ErrorPopUp(_("Error"), message, FALSE);
7198 void DisplayMoveError(message)
7203 DrawPosition(FALSE, NULL);
7204 if (appData.debugMode || appData.matchMode) {
7205 fprintf(stderr, "%s: %s\n", programName, message);
7207 if (appData.popupMoveErrors) {
7208 ErrorPopUp(_("Error"), message, FALSE);
7210 DisplayMessage(message, "");
7215 void DisplayFatalError(message, error, status)
7221 errorExitStatus = status;
7223 fprintf(stderr, "%s: %s\n", programName, message);
7225 fprintf(stderr, "%s: %s: %s\n",
7226 programName, message, strerror(error));
7227 snprintf(buf, sizeof(buf), "%s: %s", message, strerror(error));
7230 if (appData.popupExitMessage && boardWidget && XtIsRealized(boardWidget)) {
7231 ErrorPopUp(status ? _("Fatal Error") : _("Exiting"), message, TRUE);
7237 void DisplayInformation(message)
7241 ErrorPopUp(_("Information"), message, TRUE);
7244 void DisplayNote(message)
7248 ErrorPopUp(_("Note"), message, FALSE);
7252 NullXErrorCheck(dpy, error_event)
7254 XErrorEvent *error_event;
7259 void DisplayIcsInteractionTitle(message)
7262 if (oldICSInteractionTitle == NULL) {
7263 /* Magic to find the old window title, adapted from vim */
7264 char *wina = getenv("WINDOWID");
7266 Window win = (Window) atoi(wina);
7267 Window root, parent, *children;
7268 unsigned int nchildren;
7269 int (*oldHandler)() = XSetErrorHandler(NullXErrorCheck);
7271 if (XFetchName(xDisplay, win, &oldICSInteractionTitle)) break;
7272 if (!XQueryTree(xDisplay, win, &root, &parent,
7273 &children, &nchildren)) break;
7274 if (children) XFree((void *)children);
7275 if (parent == root || parent == 0) break;
7278 XSetErrorHandler(oldHandler);
7280 if (oldICSInteractionTitle == NULL) {
7281 oldICSInteractionTitle = "xterm";
7284 printf("\033]0;%s\007", message);
7288 char pendingReplyPrefix[MSG_SIZ];
7289 ProcRef pendingReplyPR;
7291 void AskQuestionProc(w, event, prms, nprms)
7298 fprintf(stderr, _("AskQuestionProc needed 4 parameters, got %d\n"),
7302 AskQuestionEvent(prms[0], prms[1], prms[2], prms[3]);
7305 void AskQuestionPopDown()
7307 if (!askQuestionUp) return;
7308 XtPopdown(askQuestionShell);
7309 XtDestroyWidget(askQuestionShell);
7310 askQuestionUp = False;
7313 void AskQuestionReplyAction(w, event, prms, nprms)
7323 reply = XawDialogGetValueString(w = XtParent(w));
7324 safeStrCpy(buf, pendingReplyPrefix, sizeof(buf)/sizeof(buf[0]) );
7325 if (*buf) strncat(buf, " ", MSG_SIZ - strlen(buf) - 1);
7326 strncat(buf, reply, MSG_SIZ - strlen(buf) - 1);
7327 strncat(buf, "\n", MSG_SIZ - strlen(buf) - 1);
7328 OutputToProcess(pendingReplyPR, buf, strlen(buf), &err);
7329 AskQuestionPopDown();
7331 if (err) DisplayFatalError(_("Error writing to chess program"), err, 0);
7334 void AskQuestionCallback(w, client_data, call_data)
7336 XtPointer client_data, call_data;
7341 XtSetArg(args[0], XtNlabel, &name);
7342 XtGetValues(w, args, 1);
7344 if (strcmp(name, _("cancel")) == 0) {
7345 AskQuestionPopDown();
7347 AskQuestionReplyAction(w, NULL, NULL, NULL);
7351 void AskQuestion(title, question, replyPrefix, pr)
7352 char *title, *question, *replyPrefix;
7356 Widget popup, layout, dialog, edit;
7362 safeStrCpy(pendingReplyPrefix, replyPrefix, sizeof(pendingReplyPrefix)/sizeof(pendingReplyPrefix[0]) );
7363 pendingReplyPR = pr;
7366 XtSetArg(args[i], XtNresizable, True); i++;
7367 XtSetArg(args[i], XtNwidth, DIALOG_SIZE); i++;
7368 askQuestionShell = popup =
7369 XtCreatePopupShell(title, transientShellWidgetClass,
7370 shellWidget, args, i);
7373 XtCreateManagedWidget(layoutName, formWidgetClass, popup,
7374 layoutArgs, XtNumber(layoutArgs));
7377 XtSetArg(args[i], XtNlabel, question); i++;
7378 XtSetArg(args[i], XtNvalue, ""); i++;
7379 XtSetArg(args[i], XtNborderWidth, 0); i++;
7380 dialog = XtCreateManagedWidget("question", dialogWidgetClass,
7383 XawDialogAddButton(dialog, _("enter"), AskQuestionCallback,
7384 (XtPointer) dialog);
7385 XawDialogAddButton(dialog, _("cancel"), AskQuestionCallback,
7386 (XtPointer) dialog);
7388 XtRealizeWidget(popup);
7389 CatchDeleteWindow(popup, "AskQuestionPopDown");
7391 XQueryPointer(xDisplay, xBoardWindow, &root, &child,
7392 &x, &y, &win_x, &win_y, &mask);
7394 XtSetArg(args[0], XtNx, x - 10);
7395 XtSetArg(args[1], XtNy, y - 30);
7396 XtSetValues(popup, args, 2);
7398 XtPopup(popup, XtGrabExclusive);
7399 askQuestionUp = True;
7401 edit = XtNameToWidget(dialog, "*value");
7402 XtSetKeyboardFocus(popup, edit);
7410 if (*name == NULLCHAR) {
7412 } else if (strcmp(name, "$") == 0) {
7413 putc(BELLCHAR, stderr);
7416 snprintf(buf, sizeof(buf), "%s '%s' &", appData.soundProgram, name);
7424 PlaySound(appData.soundMove);
7430 PlaySound(appData.soundIcsWin);
7436 PlaySound(appData.soundIcsLoss);
7442 PlaySound(appData.soundIcsDraw);
7446 PlayIcsUnfinishedSound()
7448 PlaySound(appData.soundIcsUnfinished);
7454 PlaySound(appData.soundIcsAlarm);
7460 system("stty echo");
7466 system("stty -echo");
7470 Colorize(cc, continuation)
7475 int count, outCount, error;
7477 if (textColors[(int)cc].bg > 0) {
7478 if (textColors[(int)cc].fg > 0) {
7479 snprintf(buf, MSG_SIZ, "\033[0;%d;%d;%dm", textColors[(int)cc].attr,
7480 textColors[(int)cc].fg, textColors[(int)cc].bg);
7482 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7483 textColors[(int)cc].bg);
7486 if (textColors[(int)cc].fg > 0) {
7487 snprintf(buf, MSG_SIZ, "\033[0;%d;%dm", textColors[(int)cc].attr,
7488 textColors[(int)cc].fg);
7490 snprintf(buf, MSG_SIZ, "\033[0;%dm", textColors[(int)cc].attr);
7493 count = strlen(buf);
7494 outCount = OutputToProcess(NoProc, buf, count, &error);
7495 if (outCount < count) {
7496 DisplayFatalError(_("Error writing to display"), error, 1);
7499 if (continuation) return;
7502 PlaySound(appData.soundShout);
7505 PlaySound(appData.soundSShout);
7508 PlaySound(appData.soundChannel1);
7511 PlaySound(appData.soundChannel);
7514 PlaySound(appData.soundKibitz);
7517 PlaySound(appData.soundTell);
7519 case ColorChallenge:
7520 PlaySound(appData.soundChallenge);
7523 PlaySound(appData.soundRequest);
7526 PlaySound(appData.soundSeek);
7537 return getpwuid(getuid())->pw_name;
7541 ExpandPathName(path)
7544 static char static_buf[4*MSG_SIZ];
7545 char *d, *s, buf[4*MSG_SIZ];
7551 while (*s && isspace(*s))
7560 if (*(s+1) == '/') {
7561 safeStrCpy(d, getpwuid(getuid())->pw_dir, 4*MSG_SIZ );
7565 safeStrCpy(buf, s+1, sizeof(buf)/sizeof(buf[0]) );
7566 *strchr(buf, '/') = 0;
7567 pwd = getpwnam(buf);
7570 fprintf(stderr, _("ERROR: Unknown user %s (in path %s)\n"),
7574 safeStrCpy(d, pwd->pw_dir, 4*MSG_SIZ );
7575 strcat(d, strchr(s+1, '/'));
7579 safeStrCpy(d, s, 4*MSG_SIZ );
7586 static char host_name[MSG_SIZ];
7588 #if HAVE_GETHOSTNAME
7589 gethostname(host_name, MSG_SIZ);
7591 #else /* not HAVE_GETHOSTNAME */
7592 # if HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H
7593 sysinfo(SI_HOSTNAME, host_name, MSG_SIZ);
7595 # else /* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7597 # endif/* not (HAVE_SYSINFO && HAVE_SYS_SYSTEMINFO_H) */
7598 #endif /* not HAVE_GETHOSTNAME */
7601 XtIntervalId delayedEventTimerXID = 0;
7602 DelayedEventCallback delayedEventCallback = 0;
7607 delayedEventTimerXID = 0;
7608 delayedEventCallback();
7612 ScheduleDelayedEvent(cb, millisec)
7613 DelayedEventCallback cb; long millisec;
7615 if(delayedEventTimerXID && delayedEventCallback == cb)
7616 // [HGM] alive: replace, rather than add or flush identical event
7617 XtRemoveTimeOut(delayedEventTimerXID);
7618 delayedEventCallback = cb;
7619 delayedEventTimerXID =
7620 XtAppAddTimeOut(appContext, millisec,
7621 (XtTimerCallbackProc) FireDelayedEvent, (XtPointer) 0);
7624 DelayedEventCallback
7627 if (delayedEventTimerXID) {
7628 return delayedEventCallback;
7635 CancelDelayedEvent()
7637 if (delayedEventTimerXID) {
7638 XtRemoveTimeOut(delayedEventTimerXID);
7639 delayedEventTimerXID = 0;
7643 XtIntervalId loadGameTimerXID = 0;
7645 int LoadGameTimerRunning()
7647 return loadGameTimerXID != 0;
7650 int StopLoadGameTimer()
7652 if (loadGameTimerXID != 0) {
7653 XtRemoveTimeOut(loadGameTimerXID);
7654 loadGameTimerXID = 0;
7662 LoadGameTimerCallback(arg, id)
7666 loadGameTimerXID = 0;
7671 StartLoadGameTimer(millisec)
7675 XtAppAddTimeOut(appContext, millisec,
7676 (XtTimerCallbackProc) LoadGameTimerCallback,
7680 XtIntervalId analysisClockXID = 0;
7683 AnalysisClockCallback(arg, id)
7687 if (gameMode == AnalyzeMode || gameMode == AnalyzeFile
7688 || appData.icsEngineAnalyze) { // [DM]
7689 AnalysisPeriodicEvent(0);
7690 StartAnalysisClock();
7695 StartAnalysisClock()
7698 XtAppAddTimeOut(appContext, 2000,
7699 (XtTimerCallbackProc) AnalysisClockCallback,
7703 XtIntervalId clockTimerXID = 0;
7705 int ClockTimerRunning()
7707 return clockTimerXID != 0;
7710 int StopClockTimer()
7712 if (clockTimerXID != 0) {
7713 XtRemoveTimeOut(clockTimerXID);
7722 ClockTimerCallback(arg, id)
7731 StartClockTimer(millisec)
7735 XtAppAddTimeOut(appContext, millisec,
7736 (XtTimerCallbackProc) ClockTimerCallback,
7741 DisplayTimerLabel(w, color, timer, highlight)
7750 /* check for low time warning */
7751 Pixel foregroundOrWarningColor = timerForegroundPixel;
7754 appData.lowTimeWarning &&
7755 (timer / 1000) < appData.icsAlarmTime)
7756 foregroundOrWarningColor = lowTimeWarningColor;
7758 if (appData.clockMode) {
7759 snprintf(buf, MSG_SIZ, "%s: %s", color, TimeString(timer));
7760 XtSetArg(args[0], XtNlabel, buf);
7762 snprintf(buf, MSG_SIZ, "%s ", color);
7763 XtSetArg(args[0], XtNlabel, buf);
7768 XtSetArg(args[1], XtNbackground, foregroundOrWarningColor);
7769 XtSetArg(args[2], XtNforeground, timerBackgroundPixel);
7771 XtSetArg(args[1], XtNbackground, timerBackgroundPixel);
7772 XtSetArg(args[2], XtNforeground, foregroundOrWarningColor);
7775 XtSetValues(w, args, 3);
7779 DisplayWhiteClock(timeRemaining, highlight)
7785 if(appData.noGUI) return;
7786 DisplayTimerLabel(whiteTimerWidget, _("White"), timeRemaining, highlight);
7787 if (highlight && iconPixmap == bIconPixmap) {
7788 iconPixmap = wIconPixmap;
7789 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7790 XtSetValues(shellWidget, args, 1);
7795 DisplayBlackClock(timeRemaining, highlight)
7801 if(appData.noGUI) return;
7802 DisplayTimerLabel(blackTimerWidget, _("Black"), timeRemaining, highlight);
7803 if (highlight && iconPixmap == wIconPixmap) {
7804 iconPixmap = bIconPixmap;
7805 XtSetArg(args[0], XtNiconPixmap, iconPixmap);
7806 XtSetValues(shellWidget, args, 1);
7824 int StartChildProcess(cmdLine, dir, pr)
7831 int to_prog[2], from_prog[2];
7835 if (appData.debugMode) {
7836 fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
7839 /* We do NOT feed the cmdLine to the shell; we just
7840 parse it into blank-separated arguments in the
7841 most simple-minded way possible.
7844 safeStrCpy(buf, cmdLine, sizeof(buf)/sizeof(buf[0]) );
7847 while(*p == ' ') p++;
7849 if(*p == '"' || *p == '\'')
7850 p = strchr(++argv[i-1], *p);
7851 else p = strchr(p, ' ');
7852 if (p == NULL) break;
7857 SetUpChildIO(to_prog, from_prog);
7859 if ((pid = fork()) == 0) {
7861 // [HGM] PSWBTM: made order resistant against case where fd of created pipe was 0 or 1
7862 close(to_prog[1]); // first close the unused pipe ends
7863 close(from_prog[0]);
7864 dup2(to_prog[0], 0); // to_prog was created first, nd is the only one to use 0 or 1
7865 dup2(from_prog[1], 1);
7866 if(to_prog[0] >= 2) close(to_prog[0]); // if 0 or 1, the dup2 already cosed the original
7867 close(from_prog[1]); // and closing again loses one of the pipes!
7868 if(fileno(stderr) >= 2) // better safe than sorry...
7869 dup2(1, fileno(stderr)); /* force stderr to the pipe */
7871 if (dir[0] != NULLCHAR && chdir(dir) != 0) {
7876 nice(appData.niceEngines); // [HGM] nice: adjust priority of engine proc
7878 execvp(argv[0], argv);
7880 /* If we get here, exec failed */
7885 /* Parent process */
7887 close(from_prog[1]);
7889 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
7892 cp->fdFrom = from_prog[0];
7893 cp->fdTo = to_prog[1];
7898 // [HGM] kill: implement the 'hard killing' of AS's Winboard_x
7899 static RETSIGTYPE AlarmCallBack(int n)
7905 DestroyChildProcess(pr, signalType)
7909 ChildProc *cp = (ChildProc *) pr;
7911 if (cp->kind != CPReal) return;
7913 if (signalType == 10) { // [HGM] kill: if it does not terminate in 3 sec, kill
7914 signal(SIGALRM, AlarmCallBack);
7916 if(wait((int *) 0) == -1) { // process does not terminate on its own accord
7917 kill(cp->pid, SIGKILL); // kill it forcefully
7918 wait((int *) 0); // and wait again
7922 kill(cp->pid, signalType == 9 ? SIGKILL : SIGTERM); // [HGM] kill: use hard kill if so requested
7924 /* Process is exiting either because of the kill or because of
7925 a quit command sent by the backend; either way, wait for it to die.
7934 InterruptChildProcess(pr)
7937 ChildProc *cp = (ChildProc *) pr;
7939 if (cp->kind != CPReal) return;
7940 (void) kill(cp->pid, SIGINT); /* stop it thinking */
7943 int OpenTelnet(host, port, pr)
7948 char cmdLine[MSG_SIZ];
7950 if (port[0] == NULLCHAR) {
7951 snprintf(cmdLine, sizeof(cmdLine), "%s %s", appData.telnetProgram, host);
7953 snprintf(cmdLine, sizeof(cmdLine), "%s %s %s", appData.telnetProgram, host, port);
7955 return StartChildProcess(cmdLine, "", pr);
7958 int OpenTCP(host, port, pr)
7964 DisplayFatalError(_("Socket support is not configured in"), 0, 2);
7965 #else /* !OMIT_SOCKETS */
7967 struct sockaddr_in sa;
7969 unsigned short uport;
7972 if ((s = socket(AF_INET, SOCK_STREAM, 6)) < 0) {
7976 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7977 sa.sin_family = AF_INET;
7978 sa.sin_addr.s_addr = INADDR_ANY;
7979 uport = (unsigned short) 0;
7980 sa.sin_port = htons(uport);
7981 if (bind(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) < 0) {
7985 memset((char *) &sa, (int)0, sizeof(struct sockaddr_in));
7986 if (!(hp = gethostbyname(host))) {
7988 if (sscanf(host, "%d.%d.%d.%d", &b0, &b1, &b2, &b3) == 4) {
7989 hp = (struct hostent *) calloc(1, sizeof(struct hostent));
7990 hp->h_addrtype = AF_INET;
7992 hp->h_addr_list = (char **) calloc(2, sizeof(char *));
7993 hp->h_addr_list[0] = (char *) malloc(4);
7994 hp->h_addr_list[0][0] = b0;
7995 hp->h_addr_list[0][1] = b1;
7996 hp->h_addr_list[0][2] = b2;
7997 hp->h_addr_list[0][3] = b3;
8002 sa.sin_family = hp->h_addrtype;
8003 uport = (unsigned short) atoi(port);
8004 sa.sin_port = htons(uport);
8005 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
8007 if (connect(s, (struct sockaddr *) &sa,
8008 sizeof(struct sockaddr_in)) < 0) {
8012 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8019 #endif /* !OMIT_SOCKETS */
8024 int OpenCommPort(name, pr)
8031 fd = open(name, 2, 0);
8032 if (fd < 0) return errno;
8034 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8044 int OpenLoopback(pr)
8050 SetUpChildIO(to, from);
8052 cp = (ChildProc *) calloc(1, sizeof(ChildProc));
8055 cp->fdFrom = to[0]; /* note not from[0]; we are doing a loopback */
8062 int OpenRcmd(host, user, cmd, pr)
8063 char *host, *user, *cmd;
8066 DisplayFatalError(_("internal rcmd not implemented for Unix"), 0, 1);
8070 #define INPUT_SOURCE_BUF_SIZE 8192
8079 char buf[INPUT_SOURCE_BUF_SIZE];
8084 DoInputCallback(closure, source, xid)
8089 InputSource *is = (InputSource *) closure;
8094 if (is->lineByLine) {
8095 count = read(is->fd, is->unused,
8096 INPUT_SOURCE_BUF_SIZE - (is->unused - is->buf));
8098 (is->func)(is, is->closure, is->buf, count, count ? errno : 0);
8101 is->unused += count;
8103 while (p < is->unused) {
8104 q = memchr(p, '\n', is->unused - p);
8105 if (q == NULL) break;
8107 (is->func)(is, is->closure, p, q - p, 0);
8111 while (p < is->unused) {
8116 # if HAVE_LIBREADLINE
8117 /* check if input is from stdin, if yes, use gnu-readline */
8118 if( is->fd==fileno(stdin) )
8120 /* to clear the line */
8123 /* read from stdin */
8124 rl_callback_read_char();
8126 /* redisplay the current line, check special case for login and password */
8127 if(sending_ICS_password)
8129 int i; char buf[MSG_SIZ];
8133 /* blank the password */
8134 count = strlen(rl_line_buffer);
8137 printf("PROBLEM with readline\n");
8140 for(i=0;i<count;i++)
8144 printf("\rpassword: %s",buf);
8146 else if (sending_ICS_login)
8148 /* show login prompt */
8149 count = strlen(rl_line_buffer);
8150 printf("\rlogin: %s",rl_line_buffer);
8153 rl_reset_line_state();
8155 if(readline_complete)
8157 /* copy into XBoards buffer */
8158 count = strlen(readline_buffer);
8159 if (count>INPUT_SOURCE_BUF_SIZE-1)
8161 printf("PROBLEM with readline\n");
8162 count = INPUT_SOURCE_BUF_SIZE;
8164 strncpy(is->buf,readline_buffer,count);
8165 is->buf[count]='\n';count++;
8167 /* reset gnu-readline state */
8168 free(readline_buffer);
8169 readline_buffer=NULL;
8170 readline_complete=0;
8176 (is->func)(is, is->closure, is->buf, count, error);
8178 /* are we done with the password? */
8179 if(sending_ICS_password)
8180 sending_ICS_password=0;
8181 if(sending_ICS_login)
8182 sending_ICS_login=0;
8187 /* input not from stdin, use default method */
8188 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8193 (is->func)(is, is->closure, is->buf, count, error);
8195 #else /* no readline support */
8196 count = read(is->fd, is->buf, INPUT_SOURCE_BUF_SIZE);
8201 (is->func)(is, is->closure, is->buf, count, error);
8207 InputSourceRef AddInputSource(pr, lineByLine, func, closure)
8214 ChildProc *cp = (ChildProc *) pr;
8216 is = (InputSource *) calloc(1, sizeof(InputSource));
8217 is->lineByLine = lineByLine;
8221 is->fd = fileno(stdin);
8223 is->kind = cp->kind;
8224 is->fd = cp->fdFrom;
8227 is->unused = is->buf;
8230 is->xid = XtAppAddInput(appContext, is->fd,
8231 (XtPointer) (XtInputReadMask),
8232 (XtInputCallbackProc) DoInputCallback,
8234 is->closure = closure;
8235 return (InputSourceRef) is;
8239 RemoveInputSource(isr)
8242 InputSource *is = (InputSource *) isr;
8244 if (is->xid == 0) return;
8245 XtRemoveInput(is->xid);
8249 int OutputToProcess(pr, message, count, outError)
8255 static int line = 0;
8256 ChildProc *cp = (ChildProc *) pr;
8262 if (appData.noJoin || !appData.useInternalWrap)
8263 outCount = fwrite(message, 1, count, stdout);
8266 int width = get_term_width();
8267 int len = wrap(NULL, message, count, width, &line);
8268 char *msg = malloc(len);
8272 outCount = fwrite(message, 1, count, stdout);
8275 dbgchk = wrap(msg, message, count, width, &line);
8276 if (dbgchk != len && appData.debugMode)
8277 fprintf(debugFP, "wrap(): dbgchk(%d) != len(%d)\n", dbgchk, len);
8278 outCount = fwrite(msg, 1, dbgchk, stdout);
8283 # if HAVE_LIBREADLINE
8284 /* readline support */
8285 if(strlen(rl_line_buffer))
8286 printf("\n> %s",rl_line_buffer);
8291 outCount = write(cp->fdTo, message, count);
8301 /* Output message to process, with "ms" milliseconds of delay
8302 between each character. This is needed when sending the logon
8303 script to ICC, which for some reason doesn't like the
8304 instantaneous send. */
8305 int OutputToProcessDelayed(pr, message, count, outError, msdelay)
8312 ChildProc *cp = (ChildProc *) pr;
8317 r = write(cp->fdTo, message++, 1);
8330 /**** Animation code by Hugh Fisher, DCS, ANU.
8332 Known problem: if a window overlapping the board is
8333 moved away while a piece is being animated underneath,
8334 the newly exposed area won't be updated properly.
8335 I can live with this.
8337 Known problem: if you look carefully at the animation
8338 of pieces in mono mode, they are being drawn as solid
8339 shapes without interior detail while moving. Fixing
8340 this would be a major complication for minimal return.
8343 /* Masks for XPM pieces. Black and white pieces can have
8344 different shapes, but in the interest of retaining my
8345 sanity pieces must have the same outline on both light
8346 and dark squares, and all pieces must use the same
8347 background square colors/images. */
8349 static int xpmDone = 0;
8352 CreateAnimMasks (pieceDepth)
8359 unsigned long plane;
8362 /* Need a bitmap just to get a GC with right depth */
8363 buf = XCreatePixmap(xDisplay, xBoardWindow,
8365 values.foreground = 1;
8366 values.background = 0;
8367 /* Don't use XtGetGC, not read only */
8368 maskGC = XCreateGC(xDisplay, buf,
8369 GCForeground | GCBackground, &values);
8370 XFreePixmap(xDisplay, buf);
8372 buf = XCreatePixmap(xDisplay, xBoardWindow,
8373 squareSize, squareSize, pieceDepth);
8374 values.foreground = XBlackPixel(xDisplay, xScreen);
8375 values.background = XWhitePixel(xDisplay, xScreen);
8376 bufGC = XCreateGC(xDisplay, buf,
8377 GCForeground | GCBackground, &values);
8379 for (piece = WhitePawn; piece <= BlackKing; piece++) {
8380 /* Begin with empty mask */
8381 if(!xpmDone) // [HGM] pieces: keep using existing
8382 xpmMask[piece] = XCreatePixmap(xDisplay, xBoardWindow,
8383 squareSize, squareSize, 1);
8384 XSetFunction(xDisplay, maskGC, GXclear);
8385 XFillRectangle(xDisplay, xpmMask[piece], maskGC,
8386 0, 0, squareSize, squareSize);
8388 /* Take a copy of the piece */
8393 XSetFunction(xDisplay, bufGC, GXcopy);
8394 XCopyArea(xDisplay, xpmPieceBitmap[kind][((int)piece) % (int)BlackPawn],
8396 0, 0, squareSize, squareSize, 0, 0);
8398 /* XOR the background (light) over the piece */
8399 XSetFunction(xDisplay, bufGC, GXxor);
8401 XCopyArea(xDisplay, xpmLightSquare, buf, bufGC,
8402 0, 0, squareSize, squareSize, 0, 0);
8404 XSetForeground(xDisplay, bufGC, lightSquareColor);
8405 XFillRectangle(xDisplay, buf, bufGC, 0, 0, squareSize, squareSize);
8408 /* We now have an inverted piece image with the background
8409 erased. Construct mask by just selecting all the non-zero
8410 pixels - no need to reconstruct the original image. */
8411 XSetFunction(xDisplay, maskGC, GXor);
8413 /* Might be quicker to download an XImage and create bitmap
8414 data from it rather than this N copies per piece, but it
8415 only takes a fraction of a second and there is a much
8416 longer delay for loading the pieces. */
8417 for (n = 0; n < pieceDepth; n ++) {
8418 XCopyPlane(xDisplay, buf, xpmMask[piece], maskGC,
8419 0, 0, squareSize, squareSize,
8425 XFreePixmap(xDisplay, buf);
8426 XFreeGC(xDisplay, bufGC);
8427 XFreeGC(xDisplay, maskGC);
8431 InitAnimState (anim, info)
8433 XWindowAttributes * info;
8438 /* Each buffer is square size, same depth as window */
8439 anim->saveBuf = XCreatePixmap(xDisplay, xBoardWindow,
8440 squareSize, squareSize, info->depth);
8441 anim->newBuf = XCreatePixmap(xDisplay, xBoardWindow,
8442 squareSize, squareSize, info->depth);
8444 /* Create a plain GC for blitting */
8445 mask = GCForeground | GCBackground | GCFunction |
8446 GCPlaneMask | GCGraphicsExposures;
8447 values.foreground = XBlackPixel(xDisplay, xScreen);
8448 values.background = XWhitePixel(xDisplay, xScreen);
8449 values.function = GXcopy;
8450 values.plane_mask = AllPlanes;
8451 values.graphics_exposures = False;
8452 anim->blitGC = XCreateGC(xDisplay, xBoardWindow, mask, &values);
8454 /* Piece will be copied from an existing context at
8455 the start of each new animation/drag. */
8456 anim->pieceGC = XCreateGC(xDisplay, xBoardWindow, 0, &values);
8458 /* Outline will be a read-only copy of an existing */
8459 anim->outlineGC = None;
8465 static VariantClass old = (VariantClass) -1; // [HGM] pieces: redo every time variant changes
8466 XWindowAttributes info;
8468 if (xpmDone && gameInfo.variant == old) return;
8469 if(xpmDone) old = gameInfo.variant; // first time pieces might not be created yet
8470 XGetWindowAttributes(xDisplay, xBoardWindow, &info);
8472 InitAnimState(&game, &info);
8473 InitAnimState(&player, &info);
8475 /* For XPM pieces, we need bitmaps to use as masks. */
8477 CreateAnimMasks(info.depth);
8483 static Boolean frameWaiting;
8485 static RETSIGTYPE FrameAlarm (sig)
8488 frameWaiting = False;
8489 /* In case System-V style signals. Needed?? */
8490 signal(SIGALRM, FrameAlarm);
8497 struct itimerval delay;
8499 XSync(xDisplay, False);
8502 frameWaiting = True;
8503 signal(SIGALRM, FrameAlarm);
8504 delay.it_interval.tv_sec =
8505 delay.it_value.tv_sec = time / 1000;
8506 delay.it_interval.tv_usec =
8507 delay.it_value.tv_usec = (time % 1000) * 1000;
8508 setitimer(ITIMER_REAL, &delay, NULL);
8509 while (frameWaiting) pause();
8510 delay.it_interval.tv_sec = delay.it_value.tv_sec = 0;
8511 delay.it_interval.tv_usec = delay.it_value.tv_usec = 0;
8512 setitimer(ITIMER_REAL, &delay, NULL);
8522 XSync(xDisplay, False);
8524 usleep(time * 1000);
8529 /* Convert board position to corner of screen rect and color */
8532 ScreenSquare(column, row, pt, color)
8533 int column; int row; XPoint * pt; int * color;
8536 pt->x = lineGap + ((BOARD_WIDTH-1)-column) * (squareSize + lineGap);
8537 pt->y = lineGap + row * (squareSize + lineGap);
8539 pt->x = lineGap + column * (squareSize + lineGap);
8540 pt->y = lineGap + ((BOARD_HEIGHT-1)-row) * (squareSize + lineGap);
8542 *color = SquareColor(row, column);
8545 /* Convert window coords to square */
8548 BoardSquare(x, y, column, row)
8549 int x; int y; int * column; int * row;
8551 *column = EventToSquare(x, BOARD_WIDTH);
8552 if (flipView && *column >= 0)
8553 *column = BOARD_WIDTH - 1 - *column;
8554 *row = EventToSquare(y, BOARD_HEIGHT);
8555 if (!flipView && *row >= 0)
8556 *row = BOARD_HEIGHT - 1 - *row;
8561 #undef Max /* just in case */
8563 #define Max(a, b) ((a) > (b) ? (a) : (b))
8564 #define Min(a, b) ((a) < (b) ? (a) : (b))
8567 SetRect(rect, x, y, width, height)
8568 XRectangle * rect; int x; int y; int width; int height;
8572 rect->width = width;
8573 rect->height = height;
8576 /* Test if two frames overlap. If they do, return
8577 intersection rect within old and location of
8578 that rect within new. */
8581 Intersect(old, new, size, area, pt)
8582 XPoint * old; XPoint * new;
8583 int size; XRectangle * area; XPoint * pt;
8585 if (old->x > new->x + size || new->x > old->x + size ||
8586 old->y > new->y + size || new->y > old->y + size) {
8589 SetRect(area, Max(new->x - old->x, 0), Max(new->y - old->y, 0),
8590 size - abs(old->x - new->x), size - abs(old->y - new->y));
8591 pt->x = Max(old->x - new->x, 0);
8592 pt->y = Max(old->y - new->y, 0);
8597 /* For two overlapping frames, return the rect(s)
8598 in the old that do not intersect with the new. */
8601 CalcUpdateRects(old, new, size, update, nUpdates)
8602 XPoint * old; XPoint * new; int size;
8603 XRectangle update[]; int * nUpdates;
8607 /* If old = new (shouldn't happen) then nothing to draw */
8608 if (old->x == new->x && old->y == new->y) {
8612 /* Work out what bits overlap. Since we know the rects
8613 are the same size we don't need a full intersect calc. */
8615 /* Top or bottom edge? */
8616 if (new->y > old->y) {
8617 SetRect(&(update[count]), old->x, old->y, size, new->y - old->y);
8619 } else if (old->y > new->y) {
8620 SetRect(&(update[count]), old->x, old->y + size - (old->y - new->y),
8621 size, old->y - new->y);
8624 /* Left or right edge - don't overlap any update calculated above. */
8625 if (new->x > old->x) {
8626 SetRect(&(update[count]), old->x, Max(new->y, old->y),
8627 new->x - old->x, size - abs(new->y - old->y));
8629 } else if (old->x > new->x) {
8630 SetRect(&(update[count]), new->x + size, Max(new->y, old->y),
8631 old->x - new->x, size - abs(new->y - old->y));
8638 /* Generate a series of frame coords from start->mid->finish.
8639 The movement rate doubles until the half way point is
8640 reached, then halves back down to the final destination,
8641 which gives a nice slow in/out effect. The algorithmn
8642 may seem to generate too many intermediates for short
8643 moves, but remember that the purpose is to attract the
8644 viewers attention to the piece about to be moved and
8645 then to where it ends up. Too few frames would be less
8649 Tween(start, mid, finish, factor, frames, nFrames)
8650 XPoint * start; XPoint * mid;
8651 XPoint * finish; int factor;
8652 XPoint frames[]; int * nFrames;
8654 int fraction, n, count;
8658 /* Slow in, stepping 1/16th, then 1/8th, ... */
8660 for (n = 0; n < factor; n++)
8662 for (n = 0; n < factor; n++) {
8663 frames[count].x = start->x + (mid->x - start->x) / fraction;
8664 frames[count].y = start->y + (mid->y - start->y) / fraction;
8666 fraction = fraction / 2;
8670 frames[count] = *mid;
8673 /* Slow out, stepping 1/2, then 1/4, ... */
8675 for (n = 0; n < factor; n++) {
8676 frames[count].x = finish->x - (finish->x - mid->x) / fraction;
8677 frames[count].y = finish->y - (finish->y - mid->y) / fraction;
8679 fraction = fraction * 2;
8684 /* Draw a piece on the screen without disturbing what's there */
8687 SelectGCMask(piece, clip, outline, mask)
8688 ChessSquare piece; GC * clip; GC * outline; Pixmap * mask;
8692 /* Bitmap for piece being moved. */
8693 if (appData.monoMode) {
8694 *mask = *pieceToSolid(piece);
8695 } else if (useImages) {
8697 *mask = xpmMask[piece];
8699 *mask = ximMaskPm[piece];
8702 *mask = *pieceToSolid(piece);
8705 /* GC for piece being moved. Square color doesn't matter, but
8706 since it gets modified we make a copy of the original. */
8708 if (appData.monoMode)
8713 if (appData.monoMode)
8718 XCopyGC(xDisplay, source, 0xFFFFFFFF, *clip);
8720 /* Outline only used in mono mode and is not modified */
8722 *outline = bwPieceGC;
8724 *outline = wbPieceGC;
8728 OverlayPiece(piece, clip, outline, dest)
8729 ChessSquare piece; GC clip; GC outline; Drawable dest;
8734 /* Draw solid rectangle which will be clipped to shape of piece */
8735 XFillRectangle(xDisplay, dest, clip,
8736 0, 0, squareSize, squareSize);
8737 if (appData.monoMode)
8738 /* Also draw outline in contrasting color for black
8739 on black / white on white cases */
8740 XCopyPlane(xDisplay, *pieceToOutline(piece), dest, outline,
8741 0, 0, squareSize, squareSize, 0, 0, 1);
8743 /* Copy the piece */
8748 if(appData.upsideDown && flipView) kind ^= 2;
8749 XCopyArea(xDisplay, xpmPieceBitmap[kind][piece],
8751 0, 0, squareSize, squareSize,
8756 /* Animate the movement of a single piece */
8759 BeginAnimation(anim, piece, startColor, start)
8767 /* The old buffer is initialised with the start square (empty) */
8768 BlankSquare(0, 0, startColor, EmptySquare, anim->saveBuf);
8769 anim->prevFrame = *start;
8771 /* The piece will be drawn using its own bitmap as a matte */
8772 SelectGCMask(piece, &anim->pieceGC, &anim->outlineGC, &mask);
8773 XSetClipMask(xDisplay, anim->pieceGC, mask);
8777 AnimationFrame(anim, frame, piece)
8782 XRectangle updates[4];
8787 /* Save what we are about to draw into the new buffer */
8788 XCopyArea(xDisplay, xBoardWindow, anim->newBuf, anim->blitGC,
8789 frame->x, frame->y, squareSize, squareSize,
8792 /* Erase bits of the previous frame */
8793 if (Intersect(&anim->prevFrame, frame, squareSize, &overlap, &pt)) {
8794 /* Where the new frame overlapped the previous,
8795 the contents in newBuf are wrong. */
8796 XCopyArea(xDisplay, anim->saveBuf, anim->newBuf, anim->blitGC,
8797 overlap.x, overlap.y,
8798 overlap.width, overlap.height,
8800 /* Repaint the areas in the old that don't overlap new */
8801 CalcUpdateRects(&anim->prevFrame, frame, squareSize, updates, &count);
8802 for (i = 0; i < count; i++)
8803 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8804 updates[i].x - anim->prevFrame.x,
8805 updates[i].y - anim->prevFrame.y,
8806 updates[i].width, updates[i].height,
8807 updates[i].x, updates[i].y);
8809 /* Easy when no overlap */
8810 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8811 0, 0, squareSize, squareSize,
8812 anim->prevFrame.x, anim->prevFrame.y);
8815 /* Save this frame for next time round */
8816 XCopyArea(xDisplay, anim->newBuf, anim->saveBuf, anim->blitGC,
8817 0, 0, squareSize, squareSize,
8819 anim->prevFrame = *frame;
8821 /* Draw piece over original screen contents, not current,
8822 and copy entire rect. Wipes out overlapping piece images. */
8823 OverlayPiece(piece, anim->pieceGC, anim->outlineGC, anim->newBuf);
8824 XCopyArea(xDisplay, anim->newBuf, xBoardWindow, anim->blitGC,
8825 0, 0, squareSize, squareSize,
8826 frame->x, frame->y);
8830 EndAnimation (anim, finish)
8834 XRectangle updates[4];
8839 /* The main code will redraw the final square, so we
8840 only need to erase the bits that don't overlap. */
8841 if (Intersect(&anim->prevFrame, finish, squareSize, &overlap, &pt)) {
8842 CalcUpdateRects(&anim->prevFrame, finish, squareSize, updates, &count);
8843 for (i = 0; i < count; i++)
8844 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8845 updates[i].x - anim->prevFrame.x,
8846 updates[i].y - anim->prevFrame.y,
8847 updates[i].width, updates[i].height,
8848 updates[i].x, updates[i].y);
8850 XCopyArea(xDisplay, anim->saveBuf, xBoardWindow, anim->blitGC,
8851 0, 0, squareSize, squareSize,
8852 anim->prevFrame.x, anim->prevFrame.y);
8857 FrameSequence(anim, piece, startColor, start, finish, frames, nFrames)
8859 ChessSquare piece; int startColor;
8860 XPoint * start; XPoint * finish;
8861 XPoint frames[]; int nFrames;
8865 BeginAnimation(anim, piece, startColor, start);
8866 for (n = 0; n < nFrames; n++) {
8867 AnimationFrame(anim, &(frames[n]), piece);
8868 FrameDelay(appData.animSpeed);
8870 EndAnimation(anim, finish);
8873 /* Main control logic for deciding what to animate and how */
8876 AnimateMove(board, fromX, fromY, toX, toY)
8885 XPoint start, finish, mid;
8886 XPoint frames[kFactor * 2 + 1];
8887 int nFrames, startColor, endColor;
8889 /* Are we animating? */
8890 if (!appData.animate || appData.blindfold)
8893 if(board[toY][toX] == WhiteRook && board[fromY][fromX] == WhiteKing ||
8894 board[toY][toX] == BlackRook && board[fromY][fromX] == BlackKing)
8895 return; // [HGM] FRC: no animtion of FRC castlings, as to-square is not true to-square
8897 if (fromY < 0 || fromX < 0 || toX < 0 || toY < 0) return;
8898 piece = board[fromY][fromX];
8899 if (piece >= EmptySquare) return;
8904 hop = (piece == WhiteKnight || piece == BlackKnight);
8907 if (appData.debugMode) {
8908 fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
8909 _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
8910 piece, fromX, fromY, toX, toY); }
8912 ScreenSquare(fromX, fromY, &start, &startColor);
8913 ScreenSquare(toX, toY, &finish, &endColor);
8916 /* Knight: make diagonal movement then straight */
8917 if (abs(toY - fromY) < abs(toX - fromX)) {
8918 mid.x = start.x + (finish.x - start.x) / 2;
8922 mid.y = start.y + (finish.y - start.y) / 2;
8925 mid.x = start.x + (finish.x - start.x) / 2;
8926 mid.y = start.y + (finish.y - start.y) / 2;
8929 /* Don't use as many frames for very short moves */
8930 if (abs(toY - fromY) + abs(toX - fromX) <= 2)
8931 Tween(&start, &mid, &finish, kFactor - 1, frames, &nFrames);
8933 Tween(&start, &mid, &finish, kFactor, frames, &nFrames);
8934 FrameSequence(&game, piece, startColor, &start, &finish, frames, nFrames);
8936 /* Be sure end square is redrawn */
8937 damage[0][toY][toX] = True;
8941 DragPieceBegin(x, y)
8944 int boardX, boardY, color;
8947 /* Are we animating? */
8948 if (!appData.animateDragging || appData.blindfold)
8951 /* Figure out which square we start in and the
8952 mouse position relative to top left corner. */
8953 BoardSquare(x, y, &boardX, &boardY);
8954 player.startBoardX = boardX;
8955 player.startBoardY = boardY;
8956 ScreenSquare(boardX, boardY, &corner, &color);
8957 player.startSquare = corner;
8958 player.startColor = color;
8959 /* As soon as we start dragging, the piece will jump slightly to
8960 be centered over the mouse pointer. */
8961 player.mouseDelta.x = squareSize/2;
8962 player.mouseDelta.y = squareSize/2;
8963 /* Initialise animation */
8964 player.dragPiece = PieceForSquare(boardX, boardY);
8966 if (player.dragPiece >= 0 && player.dragPiece < EmptySquare) {
8967 player.dragActive = True;
8968 BeginAnimation(&player, player.dragPiece, color, &corner);
8969 /* Mark this square as needing to be redrawn. Note that
8970 we don't remove the piece though, since logically (ie
8971 as seen by opponent) the move hasn't been made yet. */
8972 if(boardX == BOARD_RGHT+1 && PieceForSquare(boardX-1, boardY) > 1 ||
8973 boardX == BOARD_LEFT-2 && PieceForSquare(boardX+1, boardY) > 1)
8974 XCopyArea(xDisplay, xBoardWindow, player.saveBuf, player.blitGC,
8975 corner.x, corner.y, squareSize, squareSize,
8976 0, 0); // [HGM] zh: unstack in stead of grab
8977 damage[0][boardY][boardX] = True;
8979 player.dragActive = False;
8989 /* Are we animating? */
8990 if (!appData.animateDragging || appData.blindfold)
8994 if (! player.dragActive)
8996 /* Move piece, maintaining same relative position
8997 of mouse within square */
8998 corner.x = x - player.mouseDelta.x;
8999 corner.y = y - player.mouseDelta.y;
9000 AnimationFrame(&player, &corner, player.dragPiece);
9002 if (appData.highlightDragging) {
9004 BoardSquare(x, y, &boardX, &boardY);
9005 SetHighlights(fromX, fromY, boardX, boardY);
9014 int boardX, boardY, color;
9017 /* Are we animating? */
9018 if (!appData.animateDragging || appData.blindfold)
9022 if (! player.dragActive)
9024 /* Last frame in sequence is square piece is
9025 placed on, which may not match mouse exactly. */
9026 BoardSquare(x, y, &boardX, &boardY);
9027 ScreenSquare(boardX, boardY, &corner, &color);
9028 EndAnimation(&player, &corner);
9030 /* Be sure end square is redrawn */
9031 damage[0][boardY][boardX] = True;
9033 /* This prevents weird things happening with fast successive
9034 clicks which on my Sun at least can cause motion events
9035 without corresponding press/release. */
9036 player.dragActive = False;
9039 /* Handle expose event while piece being dragged */
9044 if (!player.dragActive || appData.blindfold)
9047 /* What we're doing: logically, the move hasn't been made yet,
9048 so the piece is still in it's original square. But visually
9049 it's being dragged around the board. So we erase the square
9050 that the piece is on and draw it at the last known drag point. */
9051 BlankSquare(player.startSquare.x, player.startSquare.y,
9052 player.startColor, EmptySquare, xBoardWindow);
9053 AnimationFrame(&player, &player.prevFrame, player.dragPiece);
9054 damage[0][player.startBoardY][player.startBoardX] = TRUE;
9057 #include <sys/ioctl.h>
9058 int get_term_width()
9060 int fd, default_width;
9063 default_width = 79; // this is FICS default anyway...
9065 #if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
9067 if (!ioctl(fd, TIOCGSIZE, &win))
9068 default_width = win.ts_cols;
9069 #elif defined(TIOCGWINSZ)
9071 if (!ioctl(fd, TIOCGWINSZ, &win))
9072 default_width = win.ws_col;
9074 return default_width;
9080 static int old_width = 0;
9081 int new_width = get_term_width();
9083 if (old_width != new_width)
9084 ics_printf("set width %d\n", new_width);
9085 old_width = new_width;
9088 void NotifyFrontendLogin()
9093 # if HAVE_LIBREADLINE
9095 ReadlineCompleteHandler(char* ptr)
9097 /* make gnu-readline keep the history */
9098 readline_buffer = ptr;
9099 readline_complete = 1;
9101 if (ptr && *ptr && !sending_ICS_password && !sending_ICS_login)