X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xoptions.c;h=6993ab26ada7878a743db9bfcd76c63d68b2bab8;hb=67b3a0d7c465522feb67841c7374bf863df19357;hp=99ca568792f341458fb1375ae8284ba6366256b5;hpb=fa8cdd39eca80f4bdbf6e8e8a290fa1b8979224e;p=xboard.git diff --git a/xoptions.c b/xoptions.c index 99ca568..6993ab2 100644 --- a/xoptions.c +++ b/xoptions.c @@ -68,6 +68,9 @@ extern char *getenv(); #include #include +#include +#include + #include "common.h" #include "backend.h" #include "xboard.h" @@ -127,9 +130,18 @@ BoardFocus () //--------------------------- Engine-specific options menu ---------------------------------- int dialogError; -static Boolean browserUp; Option *dialogOptions[NrOfDialogs]; +static Arg layoutArgs[] = { + { XtNborderWidth, 0 }, + { XtNdefaultDistance, 0 }, +}; + +static Arg formArgs[] = { + { XtNborderWidth, 0 }, + { XtNresizable, (XtArgVal) True }, +}; + void GetWidgetText (Option *opt, char **buf) { @@ -230,12 +242,12 @@ HighlightWithScroll (Option *opt, int sel, int max) float top, bottom, f, g; HighlightListBoxItem(opt, sel); if(!ReadScroll(opt, &top, &bottom)) return; // no scroll bar - bottom = bottom*max - 1.; + bottom = bottom*max - 1.f; f = g = top; top *= max; - if(sel > (top + 3*bottom)/4) f = (sel - 0.75*(bottom-top))/max; else - if(sel < (3*top + bottom)/4) f = (sel - 0.25*(bottom-top))/max; - if(f < 0.) f = 0.; if(f + 1./max > 1.) f = 1. - 1./max; + if(sel > (top + 3*bottom)/4) f = (sel - 0.75f*(bottom-top))/max; else + if(sel < (3*top + bottom)/4) f = (sel - 0.25f*(bottom-top))/max; + if(f < 0.f) f = 0.; if(f + 1.f/max > 1.f) f = 1. - 1./max; if(f != g) SetScroll(opt, f); } @@ -296,16 +308,7 @@ SpinCallback (Widget w, XtPointer client_data, XtPointer call_data) for(r = ""; *q; q++) if(*q == '.') r = q; else if(*q == '/') r = ""; // last dot after last slash if(!strcmp(r, "") && !currentCps && opt->type == FileName && opt->textValue) r = opt->textValue; - browserUp = True; - if(XsraSelFile(shells[TransientDlg], opt->name, NULL, NULL, "", "", r, - opt->type == PathName ? "p" : "f", NULL, &p)) { - int len = strlen(p); - if(len && p[len-1] == '/') p[len-1] = NULLCHAR; - XtSetArg(args[0], XtNstring, p); - XtSetValues(opt->handle, args, 1); - } - browserUp = False; - SetFocus(opt->handle, shells[TransientDlg], (XEvent*) NULL, False); + Browse(data>>8, opt->name, NULL, r, opt->type == PathName, "", &p, (FILE**) opt); return; } else if (strcmp(name, "+") == 0) { @@ -328,7 +331,7 @@ ComboSelect (Widget w, caddr_t addr, caddr_t index) // callback for all combo it values[i] = j; // store selected value in Option struct, for retrieval at OK - if(opt[i].type == Graph || opt[i].min & COMBO_CALLBACK && !currentCps) { + if(opt[i].type == Graph || opt[i].min & COMBO_CALLBACK && (!currentCps || shellUp[BrowserDlg])) { ((ButtonCallback*) opt[i].target)(i); return; } @@ -359,7 +362,7 @@ CreateMenuItem (Widget menu, char *msg, XtCallbackProc CB, int n) static Widget CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def) { // fromList determines if the item texts are taken from a list of strings, or from a menu table - int i, j; + int i; Widget menu, entry; Arg arg; MenuItem *mb = (MenuItem *) opt->choice; @@ -370,7 +373,7 @@ CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def) for (i=0; 1; i++) { - char *msg = fromList ? list[i] : mb[i].string, *msg2; + char *msg = fromList ? list[i] : mb[i].string; if(!msg) break; entry = CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i); if(!fromList) mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking @@ -387,11 +390,12 @@ char moveTypeInTranslations[] = "Escape: TypeInProc(0) \n"; extern char filterTranslations[]; extern char gameListTranslations[]; +extern char memoTranslations[]; -char *translationTable[] = { +char *translationTable[] = { // beware: order is essential! historyTranslations, commentTranslations, moveTypeInTranslations, ICSInputTranslations, - filterTranslations, gameListTranslations, + filterTranslations, gameListTranslations, memoTranslations }; void @@ -407,7 +411,8 @@ AddHandler (Option *opt, int nr) Widget shells[NrOfDialogs]; DialogClass parents[NrOfDialogs]; WindowPlacement *wp[NrOfDialogs] = { // Beware! Order must correspond to DialogClass enum - NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory, &wpGameList, &wpEngineOutput + NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory, &wpGameList, &wpEngineOutput, &wpEvalGraph, + NULL, NULL, NULL, NULL, /*&wpMain*/ NULL }; int @@ -416,6 +421,32 @@ DialogExists (DialogClass n) return shells[n] != NULL; } +void +RaiseWindow (DialogClass dlg) +{ + static XEvent xev; + Window root = RootWindow(xDisplay, DefaultScreen(xDisplay)); + Atom atom = XInternAtom (xDisplay, "_NET_ACTIVE_WINDOW", False); + + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = xDisplay; + xev.xclient.window = XtWindow(shells[dlg]); + xev.xclient.message_type = atom; + xev.xclient.format = 32; + xev.xclient.data.l[0] = 1; + xev.xclient.data.l[1] = CurrentTime; + + XSendEvent (xDisplay, + root, False, + SubstructureRedirectMask | SubstructureNotifyMask, + &xev); + + XFlush(xDisplay); + XSync(xDisplay, False); +} + int PopDown (DialogClass n) { // pops down any dialog created by GenericPopUp (or returns False if it wasn't up), unmarks any associated marked menu @@ -443,9 +474,10 @@ PopDown (DialogClass n) MarkMenuItem(marked[n], False); marked[n] = NULL; } - if(!n) currentCps = NULL; // if an Engine Settings dialog was up, we must be popping it down now + if(!n && n != BrowserDlg) currentCps = NULL; // if an Engine Settings dialog was up, we must be popping it down now currentOption = dialogOptions[TransientDlg]; // just in case a transient dialog was up (to allow its check and combo callbacks to work) - XtSetKeyboardFocus(shells[parents[n]], n == BoardWindow ? formWidget: shells[parents[n]]); + RaiseWindow(parents[n]); + if(parents[n] == BoardWindow) XtSetKeyboardFocus(shellWidget, formWidget); return 1; } @@ -454,7 +486,7 @@ GenericPopDown (Widget w, XEvent *event, String *prms, Cardinal *nprms) { // to cause popdown through a translation (Delete Window button!) int dlg = atoi(prms[0]); Widget sh = shells[dlg]; - if(browserUp || dialogError) return; // prevent closing dialog when it has an open file-browse daughter + if(shellUp[BrowserDlg] && dlg != BrowserDlg || dialogError) return; // prevent closing dialog when it has an open file-browse daughter shells[dlg] = w; PopDown(dlg); shells[dlg] = sh; // restore @@ -506,19 +538,40 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event) { // handle expose and mouse events on Graph widget Dimension w, h; Arg args[16]; - int j, button=10, f=1; - Option *opt; + int j, button=10, f=1, sizing=0; + Option *opt, *graph = (Option *) client_data; + PointerCallback *userHandler = graph->target; + cairo_t *cr; + if (!XtIsRealized(widget)) return; switch(event->type) { - case Expose: - if (((XExposeEvent*)event)->count > 0) return; // don't bother if further exposure is pending - /* Get client area */ + case Expose: // make handling of expose events generic, just copying from memory buffer (->choice) to display (->textValue) + /* Get window size */ j = 0; XtSetArg(args[j], XtNwidth, &w); j++; XtSetArg(args[j], XtNheight, &h); j++; XtGetValues(widget, args, j); - break; + sizing = ((w != graph->max || h != graph->value) && ((XExposeEvent*)event)->count >= 0); + graph->max = w; graph->value = h; + if(sizing && ((XExposeEvent*)event)->count > 0) { graph->max = 0; return; } // don't bother if further exposure is pending during resize + if(!graph->textValue || sizing) { // create surfaces of new size for display widget + if(graph->textValue) cairo_surface_destroy((cairo_surface_t *)graph->textValue); + graph->textValue = (char*) cairo_xlib_surface_create(xDisplay, XtWindow(widget), DefaultVisual(xDisplay, 0), w, h); + } + if(sizing) { // the memory buffer was already created in GenericPopup(), + // to give drawing routines opportunity to use it befor first expose event + // (which are only processed when main gets to the event loop, so after all init!) + // so only change when size is no longer good + if(graph->choice) cairo_surface_destroy((cairo_surface_t *) graph->choice); + graph->choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h); + } + cr = cairo_create((cairo_surface_t *) graph->textValue); + cairo_set_source_surface(cr, (cairo_surface_t *) graph->choice, 0, 0); + cairo_rectangle(cr, ((XExposeEvent*)event)->x, ((XExposeEvent*)event)->y, ((XExposeEvent*)event)->width, ((XExposeEvent*)event)->height); + cairo_fill(cr); + cairo_destroy(cr); + return; case MotionNotify: f = 0; w = ((XButtonEvent*)event)->x; h = ((XButtonEvent*)event)->y; @@ -536,7 +589,7 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event) } } button *= f; - opt = ((PointerCallback*) client_data)(button, w, h); + opt = userHandler(button, w, h); if(opt) { // user callback specifies a context menu; pop it up XUngrabPointer(xDisplay, CurrentTime); XtCallActionProc(widget, "XawPositionSimpleMenu", event, &(opt->name), 1); @@ -545,6 +598,15 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event) XSync(xDisplay, False); } +void +GraphExpose (Option *opt, int x, int y, int w, int h) +{ + XExposeEvent e; + if(!opt->handle) return; + e.x = x; e.y = y; e.width = w; e.height = h; e.count = -1; e.type = Expose; // count = -1: kludge to suppress sizing + GraphEventProc(opt->handle, (caddr_t) opt, (XEvent *) &e); // fake expose event +} + static void GenericCallback (Widget w, XtPointer client_data, XtPointer call_data) { // all Buttons in a dialog (including OK, cancel) invoke this @@ -564,7 +626,7 @@ GenericCallback (Widget w, XtPointer client_data, XtPointer call_data) if(GenericReadout(currentOption, -1)) PopDown(dlg); // calls OK-proc after full readout, but no popdown if it returns false } else - if(currentCps) { + if(currentCps && dlg != BrowserDlg) { XtSetArg(args[0], XtNlabel, &name); XtGetValues(w, args, 1); if(currentOption[data].type == SaveButton) GenericReadout(currentOption, -1); @@ -599,7 +661,7 @@ WheelProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) int j=0, n = atoi(prms[0]); static char *params[3] = { "", "Continuous", "Proportional" }; Arg args[16]; - float f, h, top; + float h, top; Widget v; if(!n) { // transient dialogs also use this for list-selection callback n = prms[1][0]-'0'; @@ -612,7 +674,7 @@ WheelProc (Widget w, XEvent *event, String *prms, Cardinal *nprms) XtSetArg(args[j], XtNshown, &h); j++; XtSetArg(args[j], XtNtopOfThumb, &top); j++; XtGetValues(v, args, j); - top += 0.1*h*n; if(top < 0.) top = 0.; + top += 0.1f*h*n; if(top < 0.f) top = 0.; XtCallActionProc(v, "StartScroll", event, params+1, 1); XawScrollbarSetThumb(v, top, -1.0); XtCallActionProc(v, "NotifyThumb", event, params, 0); @@ -631,7 +693,7 @@ static char scrollTranslations[] = static void SqueezeIntoBox (Option *opt, int nr, int width) { // size buttons in bar to fit, clipping button names where necessary - int i, j, wtot = 0; + int i, wtot = 0; Dimension widths[20], oldWidths[20]; Arg arg; for(i=1; inrOptions; if(!n) { DisplayNote(_("Engine has no options")); currentCps = NULL; return 0; } if(n > 50) width = 4; else if(n>24) width = 2; else width = 1; @@ -719,17 +787,17 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtSetArg(args[i], XtNresizable, True); i++; shells[BoardWindow] = shellWidget; parents[dlgNr] = parent; + if(dlgNr == BoardWindow) popup = shellWidget; else popup = shells[dlgNr] = -#if TOPLEVEL - XtCreatePopupShell(title, modal ? transientShellWidgetClass : topLevelShellWidgetClass, -#else - XtCreatePopupShell(title, transientShellWidgetClass, -#endif + XtCreatePopupShell(title, !top || !appData.topLevel ? transientShellWidgetClass : topLevelShellWidgetClass, shells[parent], args, i); layout = XtCreateManagedWidget(layoutName, formWidgetClass, popup, layoutArgs, XtNumber(layoutArgs)); + if(!appData.monoMode && appData.dialogColor[0]) XtSetArg(args[0], XtNbackground, dialogColor); + XtSetValues(layout, args, 1); + for(c=0; cWM_PROTOCOLS: GenericPopDown(\"%d\") \n", dlgNr); - XtAugmentTranslations(popup, XtParseTranslationTable(def)); - XQueryPointer(xDisplay, xBoardWindow, &root, &child, - &x, &y, &win_x, &win_y, &mask); - - XtSetArg(args[0], XtNx, x - 10); - XtSetArg(args[1], XtNy, y - 30); - XtSetValues(popup, args, 2); - + if(dlgNr != BoardWindow) { // assign close button, and position w.r.t. pointer, if not main window + XSetWMProtocols(xDisplay, XtWindow(popup), &wm_delete_window, 1); + snprintf(def, MSG_SIZ, "WM_PROTOCOLS: GenericPopDown(\"%d\") \n", dlgNr); + XtAugmentTranslations(popup, XtParseTranslationTable(def)); + XQueryPointer(xDisplay, xBoardWindow, &root, &child, + &x, &y, &win_x, &win_y, &mask); + + XtSetArg(args[0], XtNx, x - 10); + XtSetArg(args[1], XtNy, y - 30); + XtSetValues(popup, args, 2); + } XtPopup(popup, modal ? XtGrabExclusive : XtGrabNone); shellUp[dlgNr]++; // count rather than flag previous = NULL; @@ -1070,6 +1146,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y)); j++; XtSetValues(popup, args, j); } + RaiseWindow(dlgNr); return 1; // tells caller he must do initialization (e.g. add specific event handlers) } @@ -1110,7 +1187,7 @@ SetInsertPos (Option *opt, int pos) XtSetArg(args[0], XtNinsertPosition, pos); XtSetValues(opt->handle, args, 1); // SetFocus(opt->handle, shells[InputBoxDlg], NULL, False); // No idea why this does not work, and the following is needed: - XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime); +// XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime); } void