int EventToSquare P((int x, int limit));
void DrawSquare P((int row, int column, ChessSquare piece, int do_flash));
void EventProc P((Widget widget, caddr_t unused, XEvent *event));
+void DelayedDrag P((void));
void MoveTypeInProc P((Widget widget, caddr_t unused, XEvent *event));
void HandleUserMove P((Widget w, XEvent *event,
String *prms, Cardinal *nprms));
ICSInputBoxUp = False, askQuestionUp = False,
filenameUp = False, promotionUp = False, pmFromX = -1, pmFromY = -1,
errorUp = False, errorExitStatus = -1, lineGap, defaultLineGap;
+Dimension textHeight;
Pixel timerForegroundPixel, timerBackgroundPixel;
Pixel buttonForegroundPixel, buttonBackgroundPixel;
char *chessDir, *programName, *programVersion,
{ "EvalGraphProc", EvalGraphProc}, // [HGM] Winboard_x avaluation graph window
{ "ShowGameListProc", ShowGameListProc },
{ "ShowMoveListProc", HistoryShowProc},
- { "EditTagsProc", EditCommentProc },
+ { "EditTagsProc", EditTagsProc },
{ "EditBookProc", EditBookProc },
{ "EditCommentProc", EditCommentProc },
{ "IcsInputBoxProc", IcsInputBoxProc },
:<Key>F1: ManProc() \n \
:<Key>F2: FlipViewProc() \n \
:<KeyDown>Return: TempBackwardProc() \n \
- :<KeyUp>Return: TempForwardProc() \n \
- :Ctrl<Key>1: AskQuestionProc(\"Direct command\",\
- \"Send to chess program:\",,1) \n \
- :Ctrl<Key>2: AskQuestionProc(\"Direct command\",\
- \"Send to second chess program:\",,2) \n";
+ :<KeyUp>Return: TempForwardProc() \n";
char boardTranslations[] =
"<Btn1Down>: HandleUserMove(0) \n \
<Btn1Up>: HandleUserMove(0) \n \
<Btn1Motion>: AnimateUserMove() \n \
<Btn3Motion>: HandlePV() \n \
+ <Btn2Motion>: HandlePV() \n \
<Btn3Up>: PieceMenuPopup(menuB) \n \
+ <Btn2Up>: PieceMenuPopup(menuB) \n \
Shift<Btn2Down>: XawPositionSimpleMenu(menuB) XawPositionSimpleMenu(menuD)\
PieceMenuPopup(menuB) \n \
Any<Btn2Down>: XawPositionSimpleMenu(menuW) XawPositionSimpleMenu(menuD) \
}
extern Widget engineOutputShell;
+int frameX, frameY;
void
GetActualPlacement (Widget wg, WindowPlacement *wp)
Arg args[16];
Dimension w, h;
Position x, y;
- int i;
+ XWindowAttributes winAt;
+ Window win, dummy;
+ int i, rx, ry;
if(!wg) return;
- i = 0;
- XtSetArg(args[i], XtNx, &x); i++;
- XtSetArg(args[i], XtNy, &y); i++;
- XtSetArg(args[i], XtNwidth, &w); i++;
- XtSetArg(args[i], XtNheight, &h); i++;
- XtGetValues(wg, args, i);
- wp->x = x - 4;
- wp->y = y - 23;
- wp->height = h;
- wp->width = w;
+ win = XtWindow(wg);
+ XGetWindowAttributes(xDisplay, win, &winAt); // this works, where XtGetValues on XtNx, XtNy does not!
+ XTranslateCoordinates (xDisplay, win, winAt.root, -winAt.border_width, -winAt.border_width, &rx, &ry, &dummy);
+ wp->x = rx - winAt.x;
+ wp->y = ry - winAt.y;
+ wp->height = winAt.height;
+ wp->width = winAt.width;
+ frameX = winAt.x; frameY = winAt.y; // remember to decide if windows touch
}
void
shellArgs[4].value = shellArgs[2].value = w;
shellArgs[5].value = shellArgs[3].value = h;
XtSetValues(shellWidget, &shellArgs[0], 6);
+
+ XSync(xDisplay, False);
+ DelayedDrag();
}
// [HGM] pieces: tailor piece bitmaps to needs of specific variant
}
}
}
+ oldMono = -10; // kludge to force recreation of animation masks
}
#if HAVE_LIBXPM
- if(appData.monoMode == oldMono)
+ if(appData.monoMode != oldMono)
CreateAnimVars();
#endif
oldMono = appData.monoMode;
/* For the coordFont, use the 0th font of the fontset. */
XFontSet coordFontSet = CreateFontSet(appData.coordFont);
XFontStruct **font_struct_list;
+ XFontSetExtents *fontSize;
char **font_name_list;
XFontsOfFontSet(coordFontSet, &font_struct_list, &font_name_list);
coordFontID = XLoadFont(xDisplay, font_name_list[0]);
coordFontStruct = XQueryFont(xDisplay, coordFontID);
+ fontSize = XExtentsOfFontSet(fontSet); // [HGM] figure out how much vertical space font takes
+ textHeight = fontSize->max_logical_extent.height + 5; // add borderWidth
}
#else
appData.font = FindFont(appData.font, fontPxlSize);
programName, gres, w, h, wr, hr);
}
/* !! end hack */
+ if(!textHeight) textHeight = hr; // [HGM] if !NLS textHeight is still undefined, and we grab it from here
XtSetArg(args[0], XtNleft, XtChainLeft); // [HGM] glue ends for good run-time sizing
XtSetArg(args[1], XtNright, XtChainRight);
XtSetValues(messageWidget, args, 2);
/* end why */
XtAddEventHandler(formWidget, KeyPressMask, False,
(XtEventHandler) MoveTypeInProc, NULL);
+ XtAddEventHandler(shellWidget, StructureNotifyMask, False,
+ (XtEventHandler) EventProc, NULL);
/* [AS] Restore layout */
if( wpMoveHistory.visible ) {
(proc)(NULL, NULL, NULL, NULL);
}
+static void
+MenuEngineSelect (Widget w, caddr_t addr, caddr_t index)
+{
+ RecentEngineEvent((int) addr);
+}
+
+void
+AppendEnginesToMenu (Widget menu, char *list)
+{
+ int i=0, j;
+ Widget entry;
+ MenuItem *mi;
+ Arg args[16];
+ char *p;
+
+ if(appData.recentEngines <= 0) return;
+ recentEngines = strdup(list);
+ j = 0;
+ XtSetArg(args[j], XtNleftMargin, 20); j++;
+ XtSetArg(args[j], XtNrightMargin, 20); j++;
+ while (*list) {
+ p = strchr(list, '\n'); if(p == NULL) break;
+ if(i == 0) XtCreateManagedWidget(_("----"), smeLineObjectClass, menu, args, j); // at least one valid item to add
+ *p = 0;
+ XtSetArg(args[j], XtNlabel, XtNewString(list));
+ entry = XtCreateManagedWidget("engine", smeBSBObjectClass, menu, args, j+1);
+ XtAddCallback(entry, XtNcallback,
+ (XtCallbackProc) MenuEngineSelect,
+ (caddr_t) i);
+ i++; *p = '\n'; list = p + 1;
+ }
+}
+
void
CreateMenuBarPopup (Widget parent, String name, Menu *mb)
{
}
mi++;
}
+ if(!strcmp(mb->name, "Engine")) AppendEnginesToMenu(menu, appData.recentEngineList);
}
Widget
whitePieceMenu = CreatePieceMenu("menuW", 0);
blackPieceMenu = CreatePieceMenu("menuB", 1);
+ if(appData.pieceMenu) // [HGM] sweep: no idea what this was good for, but it stopped reporting button events outside the window
XtRegisterGrabAction(PieceMenuPopup, True,
(unsigned)(ButtonPressMask|ButtonReleaseMask),
GrabModeAsync, GrabModeAsync);
drawHighlight(toX, toY, highlineGC);
}
}
+ if(toX<0) // clearing the highlights must have damaged arrow
+ DrawArrowHighlight(hi1X, hi1Y, hi2X, hi2Y); // for now, redraw it (should really be cleared!)
hi1X = fromX;
hi1Y = fromY;
hi2X = toX;
}
}
+double
+Fraction (int x, int start, int stop)
+{
+ double f = ((double) x - start)/(stop - start);
+ if(f > 1.) f = 1.; else if(f < 0.) f = 0.;
+ return f;
+}
+
+static WindowPlacement wpNew;
+
+void
+CoDrag (Widget sh, WindowPlacement *wp)
+{
+ Arg args[16];
+ int j=0, touch=0, fudge = 2;
+ GetActualPlacement(sh, wp);
+ if(abs(wpMain.x + wpMain.width + 2*frameX - wp->x) < fudge) touch = 1; else // right touch
+ if(abs(wp->x + wp->width + 2*frameX - wpMain.x) < fudge) touch = 2; else // left touch
+ if(abs(wpMain.y + wpMain.height + frameX + frameY - wp->y) < fudge) touch = 3; else // bottom touch
+ if(abs(wp->y + wp->height + frameX + frameY - wpMain.y) < fudge) touch = 4; // top touch
+ if(!touch ) return; // only windows that touch co-move
+ if(touch < 3 && wpNew.height != wpMain.height) { // left or right and height changed
+ int heightInc = wpNew.height - wpMain.height;
+ double fracTop = Fraction(wp->y, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
+ double fracBot = Fraction(wp->y + wp->height + frameX + frameY + 1, wpMain.y, wpMain.y + wpMain.height + frameX + frameY);
+ wp->y += fracTop * heightInc;
+ heightInc = (int) (fracBot * heightInc) - (int) (fracTop * heightInc);
+ if(heightInc) XtSetArg(args[j], XtNheight, wp->height + heightInc), j++;
+ } else if(touch > 2 && wpNew.width != wpMain.width) { // top or bottom and width changed
+ int widthInc = wpNew.width - wpMain.width;
+ double fracLeft = Fraction(wp->x, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
+ double fracRght = Fraction(wp->x + wp->width + 2*frameX + 1, wpMain.x, wpMain.x + wpMain.width + 2*frameX);
+ wp->y += fracLeft * widthInc;
+ widthInc = (int) (fracRght * widthInc) - (int) (fracLeft * widthInc);
+ if(widthInc) XtSetArg(args[j], XtNwidth, wp->width + widthInc), j++;
+ }
+ wp->x += wpNew.x - wpMain.x;
+ wp->y += wpNew.y - wpMain.y;
+ if(touch == 1) wp->x += wpNew.width - wpMain.width; else
+ if(touch == 3) wp->y += wpNew.height - wpMain.height;
+ XtSetArg(args[j], XtNx, wp->x); j++;
+ XtSetArg(args[j], XtNy, wp->y); j++;
+ XtSetValues(sh, args, j);
+}
+
+void
+DragProc ()
+{
+ GetActualPlacement(shellWidget, &wpNew);
+ if(wpNew.x == wpMain.x && wpNew.y == wpMain.y && // not moved
+ wpNew.width == wpMain.width && wpNew.height == wpMain.height) // not sized
+ return; // false alarm
+ if(EngineOutputIsUp()) CoDrag(engineOutputShell, &wpEngineOutput);
+ if(MoveHistoryIsUp()) CoDrag(shells[7], &wpMoveHistory);
+ if(EvalGraphIsUp()) CoDrag(evalGraphShell, &wpEvalGraph);
+ if(GameListIsUp()) CoDrag(gameListShell, &wpGameList);
+ wpMain = wpNew;
+ XDrawPosition(boardWidget, True, NULL);
+}
+
+
+void
+DelayedDrag ()
+{
+ static XtIntervalId delayedDragID = 0;
+ if(delayedDragID) XtRemoveTimeOut(delayedDragID); // cancel pending
+ delayedDragID =
+ XtAppAddTimeOut(appContext, 50, (XtTimerCallbackProc) DragProc, (XtPointer) 0); // and schedule new one 50 msec later
+}
/* Why is this needed on some versions of X? */
void
{
if (!XtIsRealized(widget))
return;
-
switch (event->type) {
+ case ConfigureNotify: // main window is being dragged: drag attached windows with it
+ if(appData.useStickyWindows)
+ DelayedDrag(); // as long as events keep coming in faster than 50 msec, they destroy each other
+ break;
case Expose:
if (event->xexpose.count > 0) return; /* no clipping is done */
XDrawPosition(widget, True, NULL);
void
ErrorCallback (Widget w, XtPointer client_data, XtPointer call_data)
{
- errorUp = False;
+ dialogError = errorUp = False;
XtPopdown(w = XtParent(XtParent(XtParent(w))));
XtDestroyWidget(w);
if (errorExitStatus != -1) ExitEvent(errorExitStatus);
ErrorPopDown ()
{
if (!errorUp) return;
- errorUp = False;
+ dialogError = errorUp = False;
XtPopdown(errorShell);
XtDestroyWidget(errorShell);
if (errorExitStatus != -1) ExitEvent(errorExitStatus);
XtSetArg(args[i], XtNtitle, title); i++;
errorShell =
XtCreatePopupShell("errorpopup", transientShellWidgetClass,
- shellWidget, args, i);
+ shellUp[0] ? (dialogError = modal = TRUE, shells[0]) : shellWidget, args, i);
layout =
XtCreateManagedWidget(layoutName, formWidgetClass, errorShell,
layoutArgs, XtNumber(layoutArgs));
NULL/* transfer_done_proc */);
}
+void
+CopyFENToClipboard ()
+{ // wrapper to make call from back-end possible
+ CopyPositionProc(NULL, NULL, NULL, NULL);
+}
+
/* function called when the data to Paste is ready */
static void
PastePositionCB (Widget w, XtPointer client_data, Atom *selection,
snprintf(buf, sizeof(buf),
_("%s%s\n\n"
"Copyright 1991 Digital Equipment Corporation\n"
-"Enhancements Copyright 1992-2009 Free Software Foundation\n"
+"Enhancements Copyright 1992-2012 Free Software Foundation\n"
"Enhancements Copyright 2005 Alessandro Scotti\n\n"
"%s is free software and carries NO WARRANTY;"
"see the file COPYING for more information."),
char buf[MSG_SIZ];
if (appData.debugMode) {
- fprintf(stderr, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
+ fprintf(debugFP, "StartChildProcess (dir=\"%s\") %s\n",dir, cmdLine);
}
/* We do NOT feed the cmdLine to the shell; we just
hop = abs(fromX-toX) == 1 && abs(fromY-toY) == 2 || abs(fromX-toX) == 2 && abs(fromY-toY) == 1;
#endif
- if (appData.debugMode) {
- fprintf(debugFP, hop ? _("AnimateMove: piece %d hops from %d,%d to %d,%d \n") :
- _("AnimateMove: piece %d slides from %d,%d to %d,%d \n"),
- piece, fromX, fromY, toX, toY); }
-
ScreenSquare(fromX, fromY, &start, &startColor);
ScreenSquare(toX, toY, &finish, &endColor);
// Polygon( hdc, arrow, 7 );
}
+void
+ArrowDamage (int s_col, int s_row, int d_col, int d_row)
+{
+ int hor, vert, i;
+ hor = 64*s_col + 32; vert = 64*s_row + 32;
+ for(i=0; i<= 64; i++) {
+ damage[0][vert+6>>6][hor+6>>6] = True;
+ damage[0][vert-6>>6][hor+6>>6] = True;
+ damage[0][vert+6>>6][hor-6>>6] = True;
+ damage[0][vert-6>>6][hor-6>>6] = True;
+ hor += d_col - s_col; vert += d_row - s_row;
+ }
+}
+
/* [AS] Draw an arrow between two squares */
void
DrawArrowBetweenSquares (int s_col, int s_row, int d_col, int d_row)
{
- int s_x, s_y, d_x, d_y, hor, vert, i;
+ int s_x, s_y, d_x, d_y;
if( s_col == d_col && s_row == d_row ) {
return;
A_WIDTH = squareSize / 14.; //[HGM] make float
DrawArrowBetweenPoints( s_x, s_y, d_x, d_y );
-
- hor = 64*s_col + 32; vert = 64*s_row + 32;
- for(i=0; i<= 64; i++) {
- damage[0][vert+6>>6][hor+6>>6] = True;
- damage[0][vert-6>>6][hor+6>>6] = True;
- damage[0][vert+6>>6][hor-6>>6] = True;
- damage[0][vert-6>>6][hor-6>>6] = True;
- hor += d_col - s_col; vert += d_row - s_row;
- }
+ ArrowDamage(s_col, s_row, d_col, d_row);
}
Boolean