Make generic dialog popup reentrant
authorH.G. Muller <h.g.muller@hccnet.nl>
Sun, 6 Mar 2011 09:11:06 +0000 (10:11 +0100)
committerArun Persaud <apersaud@lbl.gov>
Thu, 7 Apr 2011 05:21:40 +0000 (22:21 -0700)
To allow persistent dialogs to be implemented through the generic popup,
it must be possible to have several dialogs open at the same time, and
thus make sure the popdowns under the cacel or close-window button know
which one to pop down. To this end an array shells[] is created that
takes over the function of settingsShell, and GenericPopUp gets an extra
parameter telling it which element to use for storing the dialog shell.
This number is then also passed to the callbacks that trigger popdown.
This was a bit nasty for the CatchDeleteWindow stuff, which passes user
data to the callback as text strings.
Keep a separate up/down indicator, so that shell widgets can be kept
for persistent dialogs. Also keep a currentOption per dialog type.
  The coordinates and size of the window is read out and stored in a
WindowPlacement structure, (if one is specified for that dialog), when
the dialog is popped down. When initialized the structure is also used
to set the window parameters when the dialog is created. (The idea being
that the structure was saved in the settings file.)
  The routine MarkMenu checkmarks a given menu item, and logs it for the
given dialog type, so that a later popdown automatically unchecks is.

xboard.c
xoptions.c

index 7d277f7..ce87c05 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -466,6 +466,7 @@ void GameListOptionsPopDown P(());
 void ShufflePopDown P(());
 void TimeControlPopDown P(());
 void SettingsPopDown P(());
+void GenericPopDown P(());
 void update_ics_width P(());
 int get_term_width P(());
 int CopyMemoProc P(());
@@ -1017,6 +1018,7 @@ XtActionsRec boardActions[] = {
     { "ShufflePopDown", (XtActionProc) ShufflePopDown },
     { "TimeControlPopDown", (XtActionProc) TimeControlPopDown },
     { "SettingsPopDown", (XtActionProc) SettingsPopDown },
+    { "GenericPopDown", (XtActionProc) GenericPopDown },
     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
 };
 
index ffb1da4..bc22faf 100644 (file)
@@ -92,6 +92,7 @@ extern Window xBoardWindow;
 extern Arg layoutArgs[2], formArgs[2];
 Pixel timerForegroundPixel, timerBackgroundPixel;
 extern int searchTime;
+extern Atom wm_delete_window;
 extern int lineGap;
 
 // [HGM] the following code for makng menu popups was cloned from the FileNamePopUp routines
@@ -1027,6 +1028,57 @@ void CreateGCs P((int redo));
 void CreateXPMBoard P((char *s, int kind));
 void CreateXPMPieces P((void));
 void GenericReadout();
+Widget shells[10];
+Widget marked[10];
+Boolean shellUp[10];
+WindowPlacement *wp[10];
+Option *dialogOptions[10];
+
+void MarkMenu(char *item, int dlgNr)
+{
+    Arg args[2];
+    XtSetArg(args[0], XtNleftBitmap, xMarkPixmap);
+    XtSetValues(marked[dlgNr] = XtNameToWidget(menuBarWidget, item), args, 1);
+}
+
+int PopDown(int n)
+{
+    int j;
+    Arg args[10];
+    Dimension windowH, windowW; Position windowX, windowY;
+    if (!shellUp[n]) return 0;
+    if(n && wp[n]) { // remember position
+       j = 0;
+       XtSetArg(args[j], XtNx, &windowX); j++;
+       XtSetArg(args[j], XtNy, &windowY); j++;
+       XtSetArg(args[j], XtNheight, &windowH); j++;
+       XtSetArg(args[j], XtNwidth, &windowW); j++;
+       XtGetValues(shells[n], args, j);
+       wp[n]->x = windowX;
+       wp[n]->x = windowY;
+       wp[n]->width  = windowW;
+       wp[n]->height = windowH;
+    }
+    previous = NULL;
+    XtPopdown(shells[n]);
+    if(n == 0) XtDestroyWidget(shells[n]);
+    shellUp[n] = False;
+    if(marked[n]) {
+       XtSetArg(args[0], XtNleftBitmap, None);
+       XtSetValues(marked[n], args, 1);
+    }
+    return 1;
+}
+
+void GenericPopDown(w, event, prms, nprms)
+     Widget w;
+     XEvent *event;
+     String *prms;
+     Cardinal *nprms;
+{
+    int n;
+    PopDown(prms[0][0] - '0');
+}
 
 Option matchOptions[] = {
 { 0,  2, 1000000000, NULL, (void*) &appData.defaultMatchGames, "", NULL, Spin, _("Default Number of Games in Match:") },
@@ -1101,7 +1153,7 @@ void Pick(int n)
        appData.pieceNickNames = "";
        appData.colorNickNames = "";
        Reset(True, True);
-        SettingsPopDown();
+        PopDown(0);
         return;
 }
 
@@ -1489,24 +1541,26 @@ void GenericCallback(w, client_data, call_data)
     int i, j;
     int data = (intptr_t) client_data;
 
+    currentOption = dialogOptions[data>>16]; data &= 0xFFFF;
+
     XtSetArg(args[0], XtNlabel, &name);
     XtGetValues(w, args, 1);
 
     if (strcmp(name, _("cancel")) == 0) {
-        SettingsPopDown();
+        PopDown(data);
         return;
     }
     if (strcmp(name, _("OK")) == 0) { // save buttons imply OK
         GenericReadout();
-        SettingsPopDown();
+        PopDown(data);
         return;
     }
     if(currentOption[data].textValue);
     ((ButtonCallback*) currentOption[data].target)(data);
 }
 
-void
-GenericPopUp(Option *option, char *title)
+int
+GenericPopUp(Option *option, char *title, int dlgNr)
 {
     Arg args[16];
     Widget popup, layout, dialog, edit=NULL, form,  last, b_ok, b_cancel, leftMargin = NULL, textField = NULL;
@@ -1518,15 +1572,23 @@ GenericPopUp(Option *option, char *title)
     static char pane[6] = "paneX";
     Widget texts[100], forelast = NULL, anchor, widest, lastrow = NULL;
 
-    currentOption = option; // make available to callback
+    if(shellUp[dlgNr]) return 0; // already up
+    if(dlgNr && shells[dlgNr]) {
+       XtPopup(shells[dlgNr], XtGrabNone);
+       shellUp[dlgNr] = True;
+       return 0;
+    }
+
+    dialogOptions[dlgNr] = option; // make available to callback
     // kludge: fake address of a ChessProgramState struct that contains the options, so Spin and Combo callbacks work on it
+    // WARNING: this kludge does not work for persistent dialogs, so that these cannot have spin or combo controls!
     currentCps = (ChessProgramState *) ((char *) option - ((char *)&first.option - (char *)&first));
 
 //    if(cps->nrOptions > 50) width = 4; else if(cps->nrOptions>24) width = 2; else width = 1;
 //    height = cps->nrOptions / width + 1;
      i = 0;
     XtSetArg(args[i], XtNresizable, True); i++;
-    SettingsShell = popup =
+    popup = shells[dlgNr] =
       XtCreatePopupShell(title, transientShellWidgetClass,
                         shellWidget, args, i);
 
@@ -1577,7 +1639,13 @@ GenericPopUp(Option *option, char *title)
            XtSetArg(args[j], XtNfromHoriz, dialog);  j++;
            XtSetArg(args[j], XtNborderWidth, 1); j++;
            XtSetArg(args[j], XtNwidth, w); j++;
-           if(option[i].type == TextBox && option[i].min) XtSetArg(args[j], XtNheight, option[i].min); j++;
+           if(option[i].type == TextBox && option[i].min) {
+               XtSetArg(args[j], XtNheight, option[i].min); j++;
+               if(option[i].value & 1) { XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++; }
+               if(option[i].value & 2) { XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollAlways);  j++; }
+               if(option[i].value & 4) { XtSetArg(args[j], XtNautoFill, True);  j++; }
+               if(option[i].value & 8) { XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++; }
+           }
            XtSetArg(args[j], XtNleft, XtChainLeft); j++;
            XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
            XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
@@ -1660,7 +1728,7 @@ GenericPopUp(Option *option, char *title)
                (dialog = last = XtCreateManagedWidget(option[i].name, commandWidgetClass, form, args, j));
            if(option[i].target == NULL) SetColor( *(char**) option[i-1].target, last); else
            XtAddCallback(last, XtNcallback, GenericCallback,
-                         (XtPointer)(intptr_t) i);
+                         (XtPointer)(intptr_t) i + (dlgNr<<16));
            if(option[i].textValue) SetColor( option[i].textValue, last);
            forelast = lastrow; // next button can go on same row
            break;
@@ -1749,16 +1817,17 @@ GenericPopUp(Option *option, char *title)
     XtSetArg(args[j], XtNleft, XtChainRight);  j++;
     XtSetArg(args[j], XtNright, XtChainRight);  j++;
     b_ok = XtCreateManagedWidget(_("OK"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_ok, XtNcallback, GenericCallback, (XtPointer) 0);
+    XtAddCallback(b_ok, XtNcallback, GenericCallback, (XtPointer) dlgNr);
 
     XtSetArg(args[0], XtNfromHoriz, b_ok);
     b_cancel = XtCreateManagedWidget(_("cancel"), commandWidgetClass, form, args, j);
-    XtAddCallback(b_cancel, XtNcallback, SettingsPopDown, (XtPointer) 0);
+    XtAddCallback(b_cancel, XtNcallback, GenericCallback, (XtPointer) dlgNr);
   }
 
     XtRealizeWidget(popup);
-    CatchDeleteWindow(popup, "SettingsPopDown");
-
+    XSetWMProtocols(xDisplay, XtWindow(popup), &wm_delete_window, 1);
+    snprintf(def, MSG_SIZ, "<Message>WM_PROTOCOLS: GenericPopDown(\"%d\") \n", dlgNr);
+    XtAugmentTranslations(popup, XtParseTranslationTable(def));
     XQueryPointer(xDisplay, xBoardWindow, &root, &child,
                  &x, &y, &win_x, &win_y, &mask);
 
@@ -1766,11 +1835,19 @@ GenericPopUp(Option *option, char *title)
     XtSetArg(args[1], XtNy, y - 30);
     XtSetValues(popup, args, 2);
 
-    XtPopup(popup, XtGrabExclusive);
-    SettingsUp = True;
-
+    XtPopup(popup, dlgNr ? XtGrabNone : XtGrabExclusive);
+    shellUp[dlgNr] = True;
     previous = NULL;
     if(textField)SetFocus(textField, popup, (XEvent*) NULL, False);
+    if(dlgNr && wp[dlgNr] && wp[dlgNr]->width > 0) { // if persistent window-info available, reposition
+       j = 0;
+       XtSetArg(args[j], XtNheight, (Dimension) (wp[dlgNr]->height));  j++;
+       XtSetArg(args[j], XtNwidth,  (Dimension) (wp[dlgNr]->width));  j++;
+       XtSetArg(args[j], XtNx, (Position) (wp[dlgNr]->x));  j++;
+       XtSetArg(args[j], XtNy, (Position) (wp[dlgNr]->y));  j++;
+       XtSetValues(popup, args, j);
+    }
+    return 1;
 }
 
 
@@ -1780,7 +1857,7 @@ void IcsOptionsProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(icsOptions, _("ICS Options"));
+   GenericPopUp(icsOptions, _("ICS Options"), 0);
 }
 
 void LoadOptionsProc(w, event, prms, nprms)
@@ -1789,7 +1866,7 @@ void LoadOptionsProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(loadOptions, _("Load Game Options"));
+   GenericPopUp(loadOptions, _("Load Game Options"), 0);
 }
 
 void SaveOptionsProc(w, event, prms, nprms)
@@ -1798,7 +1875,7 @@ void SaveOptionsProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(saveOptions, _("Save Game Options"));
+   GenericPopUp(saveOptions, _("Save Game Options"), 0);
 }
 
 void SoundOptionsProc(w, event, prms, nprms)
@@ -1808,7 +1885,7 @@ void SoundOptionsProc(w, event, prms, nprms)
      Cardinal *nprms;
 {
    soundFiles[2] = "*";
-   GenericPopUp(soundOptions, _("Sound Options"));
+   GenericPopUp(soundOptions, _("Sound Options"), 0);
 }
 
 void BoardOptionsProc(w, event, prms, nprms)
@@ -1817,7 +1894,7 @@ void BoardOptionsProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(boardOptions, _("Board Options"));
+   GenericPopUp(boardOptions, _("Board Options"), 0);
 }
 
 void EngineMenuProc(w, event, prms, nprms)
@@ -1826,7 +1903,7 @@ void EngineMenuProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(adjudicationOptions, "Adjudicate non-ICS Games");
+   GenericPopUp(adjudicationOptions, "Adjudicate non-ICS Games", 0);
 }
 
 void UciMenuProc(w, event, prms, nprms)
@@ -1837,7 +1914,7 @@ void UciMenuProc(w, event, prms, nprms)
 {
    oldCores = appData.smpCores;
    oldPonder = appData.ponderNextMove;
-   GenericPopUp(commonEngineOptions, _("Common Engine Settings"));
+   GenericPopUp(commonEngineOptions, _("Common Engine Settings"), 0);
 }
 
 void NewVariantProc(w, event, prms, nprms)
@@ -1846,7 +1923,7 @@ void NewVariantProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(variantDescriptors, _("New Variant"));
+   GenericPopUp(variantDescriptors, _("New Variant"), 0);
 }
 
 void OptionsProc(w, event, prms, nprms)
@@ -1856,7 +1933,7 @@ void OptionsProc(w, event, prms, nprms)
      Cardinal *nprms;
 {
    oldPonder = appData.ponderNextMove;
-   GenericPopUp(generalOptions, _("General Options"));
+   GenericPopUp(generalOptions, _("General Options"), 0);
 }
 
 void MatchOptionsProc(w, event, prms, nprms)
@@ -1865,7 +1942,7 @@ void MatchOptionsProc(w, event, prms, nprms)
      String *prms;
      Cardinal *nprms;
 {
-   GenericPopUp(matchOptions, _("Match Options"));
+   GenericPopUp(matchOptions, _("Match Options"), 0);
 }
 
 //---------------------------- Chat Windows ----------------------------------------------