Back to index

tetex-bin  3.0
xm_prefs_helpers.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 Stefan Ulrich
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to
00006  * deal in the Software without restriction, including without limitation the
00007  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00008  * sell copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00017  * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00018  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  *
00022  */
00023 
00024 /*
00025  * Panel 3 (Helper Applications) for xdvik preferences dialog.
00026  */
00027 
00028 #include "xdvi-config.h"
00029 #include "xdvi.h"
00030 
00031 #include "x_util.h"
00032 #include "xm_colorsel.h"
00033 #include "topic-window.h"
00034 #include "util.h"
00035 #include "string-utils.h"
00036 #include "message-window.h"
00037 #include "events.h"
00038 #include "xm_menu.h"
00039 
00040 #include "xm_prefsP.h"
00041 #include "xm_prefs.h"
00042 #include "xm_prefs_helpers.h"
00043 
00044 #ifdef MOTIF /* entire file */
00045 
00046 #include <X11/Xatom.h>
00047 
00048 #include <Xm/Xm.h>
00049 #include <Xm/Protocols.h>
00050 #include <Xm/DialogS.h>
00051 #include <Xm/LabelG.h>
00052 #include <Xm/PushB.h>
00053 #include <Xm/Form.h>
00054 #include <Xm/Frame.h>
00055 #include <Xm/PanedW.h>
00056 #include <Xm/DrawnB.h>
00057 #include <Xm/RowColumn.h>
00058 #include <Xm/Scale.h>
00059 #include <Xm/ToggleBG.h>
00060 #include <Xm/PushBG.h>
00061 #include <Xm/Text.h>
00062 #include <Xm/TextF.h>
00063 #include <Xm/FileSB.h>
00064 #include <Xm/SelectioB.h>
00065 
00066 struct choice_dialog_info {
00067     struct topic_info *tinfo;
00068     /*     struct prefs_choice *prefs; */
00069     Widget combo_box;
00070     Widget message_popup;
00071 };
00072 
00073 static char **m_browser_list = NULL;
00074 static char **m_editor_list = NULL;
00075 
00076 /*     "mozilla -remote 'openURL(%s,new-window)'", */
00077 /*     "netscape -raise -remote 'openURL(%s,new-window)'", */
00078 /*     "xterm -e lynx %s", */
00079 /*     Xdvi_ADD_COMMAND_STR, */
00080 /*     NULL /\* terminate *\/ */
00081 /* }; */
00082 
00083 /* static const char *editor_list[] = { */
00084 /*     "gnuclient -q +%l %f", */
00085 /*     "emacsclient --no-wait +%l %f", */
00086 /*     "gvim --servername xdvi --remote +%l %f", */
00087 /*     "nc -noask +%l %f", */
00088 /*     "xterm -e vi +%l %f", */
00089 /*     Xdvi_ADD_COMMAND_STR, */
00090 /*     NULL /\* terminate *\/ */
00091 /* }; */
00092 
00093 /* combo box only available with Motif 2.0;
00094  * the lesstif version is incomplete
00095  */
00096 #if XmVersion >= 2000 && !defined(LESSTIF_VERSION)
00097 #include <Xm/ComboBox.h>
00098 #include <Xm/List.h>
00099 #define USE_COMBOBOX 1
00100 #else
00101 #include <Xm/CascadeBG.h>
00102 #define USE_COMBOBOX 0
00103 #endif
00104 
00105 static void select_browser_cb(Widget w, XtPointer client_data, XtPointer call_data);
00106 static void select_editor_cb(Widget w, XtPointer client_data, XtPointer call_data);
00107 
00108 /*
00109  * Helper functions
00110  */
00111 static char *
00112 flatten_list(char **list, const char *sep)
00113 {
00114     char *result = xstrdup("");
00115     int i;
00116     
00117     for (i = 0; list[i] != NULL; i++) {
00118        result = xstrcat(result, list[i]);
00119        result = xstrcat(result, sep);
00120     }
00121     return result;
00122 }
00123 
00124 static char **
00125 add_to_list(char **list, const char *str)
00126 {
00127     int i, k;
00128     /* reallocate with larger capacity */
00129     for (i = 0; list[i] != NULL; i++) { ; }
00130     i++;
00131     list = xrealloc(list, (i + 1) * sizeof *list);
00132 
00133     /* shift old contents down */
00134     for (k = i; k > 0; k--) {
00135        list[k] = list[k - 1];
00136     }
00137     /* add new element at beginning */
00138     list[0] = xstrdup(str);
00139 
00140     return list;
00141 }
00142 
00143 
00144 /*
00145  * User clicked on `Help' in browser text input prompt
00146  */
00147 static void
00148 help_browser_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
00149 {
00150     Widget popup = popup_message(XtParent(w),
00151                              MSG_HELP,
00152                              NULL,
00153                              "The browser is used by xdvi to browse remote documents. "
00154                              "Please enter the name of the browser (i.e. the executable program) "
00155                              "you want to use. The browser command may optionally contain a string "
00156                              "`%%s' which is replaced by the current URL. If no `%%s' is present, "
00157                              "the URL argument is simply appended to the command.");
00158     UNUSED(client_data);
00159     UNUSED(call_data);
00160 
00161     TRACE_GUI((stderr, "setting user data to %p", (void *)popup));
00162     XtVaSetValues(w, XmNuserData, popup, NULL);
00163 }
00164 
00165 /*
00166  * User clicked on `Help' in editor text input prompt
00167  */
00168 static void
00169 help_editor_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
00170 {
00171     Widget popup = popup_message(XtParent(w),
00172                              MSG_HELP,
00173                              NULL,
00174                              "The editor is used by reverse search to open the TeX source for a DVI file "
00175                              "(see `Help' -> `Source Specials' for details)."
00176                              "Please enter the name of the editor executable you want to use. "
00177                              "The editor command may optionally contain two format strings: "
00178                              "`%%l' is replaced by the line number in the TeX file, and `%%f' by the file name. "
00179                              "(If the format strings are not present, they are appended implicitly.)");
00180     UNUSED(client_data);
00181     UNUSED(call_data);
00182 
00183     TRACE_GUI((stderr, "setting user data to %p", (void *)popup));
00184     XtVaSetValues(w, XmNuserData, popup, NULL);
00185 }
00186 
00187 /*
00188  * User cancelled browser or editor text input prompt
00189  */
00190 static void
00191 destroy_dialog_cb(Widget w, XtPointer client_data, XtPointer call_data)
00192 {
00193 /*     Widget browser_combo = (Widget)client_data; */
00194     struct choice_dialog_info *info = (struct choice_dialog_info *)client_data;
00195     Widget browser_combo = NULL;
00196     Widget help_popup;
00197 #if USE_COMBOBOX
00198     Widget browser_list_w;
00199 #endif
00200     UNUSED(call_data);
00201 
00202     XtVaGetValues(w, XmNuserData, &help_popup, NULL);
00203     TRACE_GUI((stderr, "GOT help_popup: %p", (void *)help_popup));
00204 
00205     if (info != NULL)
00206        browser_combo = info->combo_box;
00207     
00208     if (browser_combo != NULL) {
00209 #if USE_COMBOBOX
00210        /* Need to unselect the `Other...' entry from the list; to do this,
00211           we select the index from XmNuserData if it's >= 0, or the first item. */
00212        int idx;
00213        XtVaGetValues(browser_combo,
00214                     XmNlist, &browser_list_w,
00215                     XmNuserData, &idx,
00216                     NULL);
00217        if (browser_list_w == 0)
00218            XDVI_ERROR((stderr, "couldn't get list component of combo box!\n"));
00219        else {
00220            if (idx < 0)
00221               idx = 0;
00222            XmListSelectPos(browser_list_w, idx + 1, True);
00223        }
00224 #else
00225        Widget parent;
00226        if ((parent = XtParent(w)) != NULL) {
00227            Widget rowcol, child;
00228            if (strcmp(XtName(parent), Xdvi_BROWSER_POPUP) == 0) {
00229               if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_BROWSER_COMBO_NAME, True)) {
00230                   XtVaGetValues(rowcol, XmNuserData, &child, NULL);
00231                   XtVaSetValues(rowcol, XmNmenuHistory, child, NULL);
00232               }
00233            }
00234            else if (strcmp(XtName(parent), Xdvi_EDITOR_POPUP) == 0) {
00235               if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_EDITOR_COMBO_NAME, True)) {
00236                   XtVaGetValues(rowcol, XmNuserData, &child, NULL);
00237                   XtVaSetValues(rowcol, XmNmenuHistory, child, NULL);
00238               }
00239            }
00240            else {
00241               XDVI_WARNING((stderr, "unexpected widget name `%s' in destroy_dialog_cb", XtName(parent)));
00242            }
00243        }
00244 #endif
00245     }
00246 
00247     /*
00248      * Also popdown dependent help window if it exists before destroying the widget;
00249      * otherwise, Motif may even crash in _XmIsFastSubclass() when the help window is moved!
00250      * 
00251      * Since `help_popup' is the top-level xmDialogShellWidget, we need to get its
00252      * xmMessageBoxWidget child (by name ...). Don't report an error if it doesn't
00253      * exist in case the help window has already been closed.
00254     */
00255     if (help_popup != NULL) {
00256        static Widget message;
00257        if (get_widget_by_name(&message, help_popup, Xdvi_MESSAGE_DIALOG_NAME, False))
00258            XtCallCallbacks(message, XmNokCallback, NULL);
00259     }
00260 
00261     if (info != NULL) {
00262        struct prefs_choice *prefs = (struct prefs_choice *)info->tinfo->data;
00263        remove_from_deplist(prefs, w);
00264        free(info);
00265     }
00266     
00267     /* destroy the parent of this dialog (the shell) */
00268     XtDestroyWidget(XtParent(w));
00269 }
00270 
00271 static void
00272 h_get_input_wrapper(const char *listbox_name,
00273                   Widget w, XtPointer client_data, XtPointer call_data)
00274 {
00275 /*     Widget combobox = (Widget)client_data; */
00276     struct choice_dialog_info *info = (struct choice_dialog_info *)client_data;
00277     struct topic_info *tinfo = info->tinfo;
00278     struct prefs_choice *prefs = (struct prefs_choice *)tinfo->data;
00279     Widget combobox, child;
00280     /* following need to be allocated since we want to set resource.xyz to it */
00281     static char *browser_choice= NULL, *editor_choice = NULL;
00282 #if !USE_COMBOBOX
00283     XtCallbackProc select_cb = NULL;
00284 #endif
00285     XmSelectionBoxCallbackStruct *cbs = (XmSelectionBoxCallbackStruct *)call_data;
00286     static char *ptr = NULL;
00287     char *tmp_list;
00288 
00289     if (call_data == NULL) /* widget already being destroyed? */
00290        return;
00291 
00292     ASSERT(info != NULL, "client_data in h_get_input_wrapper mustn't be NULL!");
00293     combobox = info->combo_box;
00294     child = info->message_popup;
00295     XtVaGetValues(w, XmNuserData, &child, NULL);
00296     TRACE_GUI((stderr, "GOT child: %p", (void *)child));
00297 
00298     if (ptr)
00299        XtFree((XtPointer)ptr);
00300     ptr = NULL;
00301     XmStringGetLtoR(cbs->value, G_charset, &ptr);
00302     if (strlen(ptr) == 0 || is_spaces_only(ptr)) {
00303        popup_message(XtParent(w),
00304                     MSG_ERR,
00305                     NULL,
00306                     "Empty input string");
00307        return;
00308     }
00309 
00310     if (strcmp(listbox_name, Xdvi_BROWSER_COMBO_NAME) == 0) {
00311 #if 0
00312        int i;
00313 #endif
00314        
00315        free(browser_choice);
00316        browser_choice = xstrdup(ptr);
00317        resource.browser = browser_choice;
00318 
00319 #if 0
00320        for (i = 0; m_browser_list[i] != NULL; i++) {
00321            fprintf(stderr, "list %d: |%s|\n", i, m_browser_list[i]);
00322        }
00323 #endif
00324        m_browser_list = add_to_list(m_browser_list, ptr);
00325 #if 0
00326        for (i = 0; m_browser_list[i] != NULL; i++) {
00327            fprintf(stderr, "NEW list %d: |%s|\n", i, m_browser_list[i]);
00328        }
00329 #endif
00330        tmp_list = flatten_list(m_browser_list, "\n");
00331 #if 0
00332        fprintf(stderr, "TMP LIST: |%s|\n", tmp_list);
00333 #endif /* 0 */
00334        store_preference(&(prefs->db), "prefsBrowserList", "%s", tmp_list);
00335        free(tmp_list);
00336        
00337        store_preference(&(prefs->db), "wwwBrowser", "%s", ptr);
00338 #if !USE_COMBOBOX
00339        select_cb = select_browser_cb;
00340 #endif
00341     }
00342     else if (strcmp(listbox_name, Xdvi_EDITOR_COMBO_NAME) == 0) {
00343        free(editor_choice);
00344        editor_choice = xstrdup(ptr);
00345        resource.editor = editor_choice;
00346 
00347        m_editor_list = add_to_list(m_editor_list, ptr);
00348        tmp_list = flatten_list(m_editor_list, "\n");
00349        store_preference(&(prefs->db), "prefsEditorList", "%s", tmp_list);
00350        free(tmp_list);
00351        
00352        store_preference(&(prefs->db), "editor", "%s", ptr);
00353 #if !USE_COMBOBOX
00354        select_cb = select_editor_cb;
00355 #endif
00356     }
00357     else
00358        XDVI_WARNING((stderr, "Unexpected name in h_get_input_wrapper: `%s'", listbox_name));
00359 
00360 #if USE_COMBOBOX
00361     UNUSED(listbox_name);
00362     /* add user input to the combo box list, and make it current */
00363     XmComboBoxAddItem(combobox, cbs->value, 1, True);
00364     XmComboBoxSelectItem(combobox, cbs->value);
00365 #else
00366     {
00367        Widget new_menu, parent, grandparent, rowcol;
00368        if ((parent = XtParent(w)) != NULL && (grandparent = XtParent(parent)) != NULL) {
00369            /* add new item to front of list ... */
00370            new_menu = XtVaCreateManagedWidget(ptr, xmPushButtonGadgetClass, grandparent,
00371                                           XmNpositionIndex, 0,
00372                                           XmNuserData, tinfo,
00373                                           NULL);
00374            if (select_cb != NULL) {
00375               XtAddCallback(new_menu, XmNactivateCallback, select_cb, grandparent);
00376            }
00377            /* ... and make it current! */
00378            if (get_widget_by_name(&rowcol, globals.widgets.top_level, listbox_name, True)) {
00379               XtVaSetValues(rowcol, XmNmenuHistory, new_menu, NULL);
00380            }
00381        }
00382     }
00383 #endif
00384 
00385     /* as above: popdown help window */
00386     if (child != NULL) {
00387        Widget message;
00388        if (get_widget_by_name(&message, child, Xdvi_MESSAGE_DIALOG_NAME, False))
00389            XtCallCallbacks(message, XmNokCallback, NULL);
00390     }
00391 
00392     remove_from_deplist(prefs, w);
00393     free(info);
00394     
00395     /* destroy the parent of this dialog (the shell) */
00396     XtDestroyWidget(XtParent(w));
00397 }
00398 
00399 static void
00400 h_selector(const char *prompt_name,
00401           const char *title_str, const char *label_str,
00402           XtCallbackProc ok_cb, 
00403           XtCallbackProc destroy_cb, 
00404           XtCallbackProc help_cb, 
00405           Widget w, XtPointer client_data, XtPointer call_data)
00406 {
00407     struct topic_info *tinfo = NULL;
00408     struct prefs_choice *prefs = NULL;
00409     struct choice_dialog_info *info = NULL;
00410     char *choice;
00411     /* following need to be allocated since we want to set resource.xyz to it */
00412     static char *browser_choice= NULL, *editor_choice = NULL;
00413 
00414 #if USE_COMBOBOX
00415     XmComboBoxCallbackStruct *cb;
00416 #else
00417     XmString str;
00418     UNUSED(client_data);
00419     UNUSED(call_data);
00420 #endif
00421     
00422 #if USE_COMBOBOX
00423     tinfo = (struct topic_info *)client_data;
00424     prefs = (struct prefs_choice *)tinfo->data;
00425 #endif
00426     info = xmalloc(sizeof *info);
00427 #if USE_COMBOBOX
00428     cb = (XmComboBoxCallbackStruct *)call_data;
00429 
00430     if (cb->event == NULL) /* only browsing, no selection */
00431        return;
00432     
00433     choice = (char *)XmStringUnparse(cb->item_or_text, XmFONTLIST_DEFAULT_TAG,
00434                                  XmCHARSET_TEXT, XmCHARSET_TEXT,
00435                                  NULL, 0,
00436                                  XmOUTPUT_ALL);
00437 #else
00438     XtVaGetValues(w, XmNlabelString, &str, NULL);
00439     XmStringGetLtoR(str, G_charset, &choice);
00440     
00441     XtVaGetValues(w, XmNuserData, &tinfo, NULL);
00442     ASSERT(tinfo != NULL, "XmNuserData in callback musn't be NULL!");
00443     prefs = (struct prefs_choice *)tinfo->data;
00444 #endif
00445 
00446     if (strcmp(choice, Xdvi_ADD_COMMAND_STR) == 0) {
00447        Widget prompt_widget;
00448        Arg args[8];
00449        int n = 0;
00450        XmString title = XmStringCreateLocalized((char *)title_str);
00451        XmString label = XmStringCreateLocalized((char *)label_str);
00452        
00453        XtSetArg(args[n], XmNselectionLabelString, label); n++;
00454        XtSetArg(args[n], XmNautoUnmanage, False); n++;
00455        XtSetArg(args[n], XmNdialogTitle, title); n++;
00456        XtSetArg(args[n], XmNuserData, NULL); n++;
00457        prompt_widget = XmCreatePromptDialog(
00458 #if USE_COMBOBOX
00459                                         w,
00460 #else
00461                                         XtParent(w),
00462 #endif
00463                                         (char *)prompt_name, args, n);
00464 /*     XmStringFree(label); */
00465        
00466        add_to_deplist(prefs, prompt_widget);
00467        
00468        info->tinfo = tinfo;
00469        info->combo_box = w;
00470        info->message_popup = NULL;
00471        
00472        /* Note: w is the browser_combo widget */
00473        XtAddCallback(prompt_widget, XmNokCallback, ok_cb, (XtPointer)info);
00474        XtAddCallback(prompt_widget, XmNcancelCallback, destroy_cb, (XtPointer)info);
00475        XtAddCallback(prompt_widget, XmNhelpCallback, help_cb, (XtPointer)info);
00476        
00477        XtManageChild(prompt_widget);
00478     }
00479     else { /* normal item */
00480 #if USE_COMBOBOX
00481        int i;
00482 #endif
00483 
00484        if (strcmp(prompt_name, Xdvi_BROWSER_POPUP_NAME) == 0) {
00485 #if !USE_COMBOBOX
00486            Widget rowcol;
00487            if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_BROWSER_COMBO_NAME, True)) {
00488               XtVaSetValues(rowcol, XmNuserData, w, NULL);
00489            }
00490 #endif
00491            free(browser_choice);
00492            browser_choice = xstrdup(choice);
00493            resource.browser = browser_choice;
00494            store_preference(&(prefs->db), "wwwBrowser", "%s", browser_choice);
00495        }
00496        else if (strcmp(prompt_name, Xdvi_EDITOR_POPUP_NAME) == 0) {
00497 #if !USE_COMBOBOX
00498            Widget rowcol;
00499            if (get_widget_by_name(&rowcol, globals.widgets.top_level, Xdvi_EDITOR_COMBO_NAME, True)) {
00500               XtVaSetValues(rowcol, XmNuserData, w, NULL);
00501            }
00502 #endif
00503            free(editor_choice);
00504            editor_choice = xstrdup(choice);
00505            resource.editor = editor_choice;
00506            store_preference(&(prefs->db), "editor", "%s", editor_choice);
00507        }
00508        else
00509            XDVI_ERROR((stderr, "Unknown category `%s' in h_selector()!", prompt_name));
00510 
00511 
00512 #if USE_COMBOBOX
00513        /* update the currently selected value */
00514        XtVaGetValues(w, XmNselectedPosition, &i, NULL);
00515        XtVaSetValues(w, XmNuserData, i, NULL);
00516 #endif
00517     }
00518 #if USE_COMBOBOX
00519     XtFree(choice);
00520 #endif
00521 }
00522 
00523 /*
00524  * User OK'ed browser text input prompt
00525  */
00526 static void
00527 get_browser_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
00528 {
00529     if (XtIsRealized(w)) {
00530        h_get_input_wrapper(Xdvi_BROWSER_COMBO_NAME, w, client_data, call_data);
00531     }
00532 }
00533 
00534 
00535 /*
00536  * User OK'ed editor text input prompt
00537  */
00538 static void
00539 get_editor_text_cb(Widget w, XtPointer client_data, XtPointer call_data)
00540 {
00541     if (XtIsRealized(w)) {
00542        h_get_input_wrapper(Xdvi_EDITOR_COMBO_NAME, w, client_data, call_data);
00543     }
00544 }
00545 
00546 
00547 /*
00548  * User selected an item from browser combo box pulldown list
00549  */
00550 static void
00551 select_browser_cb(Widget w, XtPointer client_data, XtPointer call_data)
00552 {
00553     h_selector(Xdvi_BROWSER_POPUP_NAME,
00554               "Xdvi: Add Browser Command",
00555               "Browser Command (optional `%s' is replaced by URL): ",
00556               get_browser_text_cb, destroy_dialog_cb, help_browser_dialog_cb,
00557               w, client_data, call_data);
00558 }
00559 
00560 /*
00561  * User selected an item from editor combo box pulldown list
00562  */
00563 static void
00564 select_editor_cb(Widget w, XtPointer client_data, XtPointer call_data)
00565 {
00566     UNUSED(client_data);
00567     h_selector(Xdvi_EDITOR_POPUP_NAME,
00568               "Xdvi: Add Editor Command",
00569               "Editor Command (optional: `%l' = line number, `%f' = file name): ",
00570               get_editor_text_cb, destroy_dialog_cb, help_editor_dialog_cb,
00571               w, client_data, call_data);
00572 }
00573 
00574 void
00575 update_preferences_helpers(void)
00576 {
00577     Widget shell, browser_cascade, editor_cascade;
00578 
00579     if (get_widget_by_name(&shell, globals.widgets.top_level, Xdvi_PREFS_DIALOG_NAME, False)
00580        && get_widget_by_name(&browser_cascade, shell, Xdvi_BROWSER_COMBO_NAME, True)
00581        && get_widget_by_name(&editor_cascade, shell, Xdvi_EDITOR_COMBO_NAME, True)) {
00582 
00583 #if USE_COMBOBOX
00584 
00585        Widget browser_list_w, editor_list_w;
00586        XmString str;
00587        int i;
00588        Boolean found = False;
00589        
00590        XtVaGetValues(browser_cascade, XmNlist, &browser_list_w, NULL);
00591        XtVaGetValues(editor_cascade, XmNlist, &editor_list_w, NULL);
00592 
00593        for (i = 0; m_browser_list[i] != NULL; i++) {
00594            if (globals.curr_browser != NULL) { /* if this is set, ignore browser setting */
00595               if (strcmp(globals.curr_browser, m_browser_list[i]) == 0) {
00596                   found = True;
00597                   break;
00598               }
00599            }
00600            else if (resource.browser != NULL) {
00601               if (strcmp(resource.browser, m_browser_list[i]) == 0) {
00602                   found = True;
00603                   break;
00604               }
00605            }
00606        }
00607        if (!found)
00608            i = 0;
00609        str = XmStringCreateLtoR((char *)m_browser_list[i], "UNMARKED");
00610        XmComboBoxSelectItem(browser_cascade, str);
00611        XmStringFree(str);
00612        
00613        for (i = 0; m_editor_list[i] != NULL; i++) {
00614            if (globals.curr_editor != NULL) { /* if this is set, ignore editor setting */
00615               if (strcmp(globals.curr_editor, m_editor_list[i]) == 0) {
00616                   found = True;
00617                   break;
00618               }
00619            }
00620            else if (resource.editor != NULL) {
00621               if (strcmp(resource.editor, m_editor_list[i]) == 0) {
00622                   found = True;
00623                   break;
00624               }
00625            }
00626        }
00627        if (!found)
00628            i = 0;
00629        str = XmStringCreateLtoR((char *)m_editor_list[i], "UNMARKED");
00630        XmComboBoxSelectItem(editor_cascade, str);
00631        XmStringFree(str);
00632        /*     XmListSetPos(editor_list_w, i); */
00633        /*     fprintf(stderr, "setting editor list index %d, %s\n", */
00634        /*            i, editor_list[i-1]); */
00635 
00636        
00637        /*     if (XmListGetSelectedPos(browser_list_w, &browser_items, &browser_cnt) */
00638        /*         && XmListGetSelectedPos(editor_list_w, &editor_items, &editor_cnt)) { */
00639        /*         if (browser_cnt > 0 && editor_cnt > 0) { */
00640        /*            int browser_idx = browser_items[0] - 1; */
00641        /*            int editor_idx = editor_items[0] - 1; */
00642        /*            fprintf(stderr, "selected: %s, %s\n", */
00643        /*                   browser_list[browser_idx], */
00644        /*                   editor_list[editor_idx]); */
00645        /*         } */
00646        /*         else { */
00647        /*            XDVI_WARNING((stderr, "Shouldn't happen: No items selected in browser list?")); */
00648        /*            return; */
00649        /*         } */
00650        /*         XtFree((XtPointer)browser_items); */
00651        /*         XtFree((XtPointer)editor_items); */
00652        /*     } */
00653 #else
00654        Widget browser_menu, editor_menu;
00655        if (get_widget_by_name(&browser_menu, shell, Xdvi_BROWSER_MENU_NAME, True)
00656            && get_widget_by_name(&editor_menu, shell, Xdvi_EDITOR_MENU_NAME, True)) {
00657            int i, num_buttons;
00658            WidgetList buttons;
00659            
00660            XtVaGetValues(browser_menu,
00661                        XmNnumChildren, &num_buttons,
00662                        XmNchildren, &buttons,
00663                        NULL);
00664            for (i = 0; i < num_buttons; i++) {
00665               XmString str;
00666               char *ptr;
00667               
00668               XtVaGetValues(buttons[i], XmNlabelString, &str, NULL);
00669               XmStringGetLtoR(str, G_charset, &ptr);
00670 /*            fprintf(stderr, "kid %d: %s\n", i, ptr); */
00671               if (globals.curr_browser != NULL) { /* if this is set, ignore browser setting */
00672                   if (strcmp(globals.curr_browser, ptr) == 0) {
00673                      break;
00674                   }
00675               }
00676               else if (resource.browser != NULL) {
00677                   if (strcmp(resource.browser, ptr) == 0) {
00678                      break;
00679                   }
00680               }
00681            }
00682            if (i >= num_buttons) /* not found */
00683               i = 0;
00684            XtVaSetValues(browser_cascade, XmNmenuHistory, buttons[i], NULL);
00685 
00686            /* same for editor */
00687            XtVaGetValues(editor_menu,
00688                        XmNnumChildren, &num_buttons,
00689                        XmNchildren, &buttons, NULL);
00690            for (i = 0; i < num_buttons; i++) {
00691               XmString str;
00692               char *ptr;
00693               
00694               XtVaGetValues(buttons[i], XmNlabelString, &str, NULL);
00695               XmStringGetLtoR(str, G_charset, &ptr);
00696 /*            fprintf(stderr, "kid %d: %s\n", i, ptr); */
00697               if (globals.curr_editor != NULL) { /* if this is set, ignore editor setting */
00698                   if (strcmp(globals.curr_editor, ptr) == 0) {
00699                      break;
00700                   }
00701               }
00702               else if (resource.editor != NULL) {
00703                   if (strcmp(resource.editor, ptr) == 0) {
00704                      break;
00705                   }
00706               }
00707            }
00708            if (i >= num_buttons) /* not found */
00709               i = 0;
00710            XtVaSetValues(editor_cascade, XmNmenuHistory, buttons[i], NULL);
00711 
00712        }
00713 #endif
00714         /* for browser/editor, try:
00715 
00716        Widget      menu;
00717        int         num_buttons;
00718        WidgetList  buttons;
00719        
00720        XtVaGetValues( simple_option_widget, XmNsubMenuId, &menu, NULL);
00721        
00722        XtVaGetValues( menu, XmNnumChildren, &num_buttons,
00723        XmNchildren, &buttons, NULL ) ;
00724        
00725      */
00726     }
00727 }
00728 
00729 static Widget
00730 h_create_command(const char *name,
00731                const char *menu_name,
00732                const char *label,
00733                const char *curr_value,
00734                Widget parent, Widget top,
00735                char **command_list,
00736                XtCallbackProc select_cb,
00737                struct topic_info *tinfo)
00738 {
00739     const char *ptr = NULL;
00740     size_t i;
00741 
00742 #if USE_COMBOBOX
00743     XmStringTable str_list;
00744     Widget text_label, combo_box;
00745     size_t k, num;
00746     int curr_index = -1;
00747 #else
00748     Widget menu, cascade, item;
00749     XmString str;
00750     Arg args[8];
00751     int n;
00752 #endif
00753     
00754     /* check if we need to add the default resource name */
00755     ptr = curr_value;
00756 
00757     /* don't add it if it's already in our list */
00758     for (i = 0; ptr != NULL && command_list[i] != NULL; i++) {
00759        if (strcmp(command_list[i], ptr) == 0) {
00760            ptr = NULL;
00761        }
00762     }
00763 #if USE_COMBOBOX
00764     UNUSED(menu_name);
00765     text_label = XmCreateLabelGadget(parent, (char *)label, NULL, 0);
00766     XtVaSetValues(text_label,
00767                 XmNtopAttachment, XmATTACH_WIDGET,
00768                 XmNtopWidget, top,
00769                 XmNleftAttachment, XmATTACH_FORM,
00770 /*              XmNrightAttachment, XmATTACH_FORM, */
00771                 NULL);
00772 
00773     /* count elements in command_list */
00774     for (num = 0; command_list[num] != NULL; num++) { ; }
00775 
00776     if (ptr != NULL)
00777        num++;
00778        
00779     str_list = (XmStringTable)XtMalloc(num * sizeof(XmString *));
00780 
00781     i = 0;
00782     if (ptr != NULL)
00783        str_list[i++] = XmStringCreateLtoR((char *)ptr, "UNMARKED");
00784     
00785     for (k = 0; i < num; i++, k++) {
00786        if (curr_value != NULL && strcmp(command_list[k], curr_value) == 0) {
00787            curr_index = i;
00788        }
00789        if (strcmp(command_list[k], Xdvi_ADD_COMMAND_STR) == 0)
00790            str_list[i] = XmStringCreateLtoR((char *)command_list[k], "MARKED");
00791        else
00792            str_list[i] = XmStringCreateLtoR((char *)command_list[k], "UNMARKED");
00793     }
00794     combo_box = XtVaCreateWidget(name, xmComboBoxWidgetClass,
00795                              parent,
00796                              XmNtopAttachment, XmATTACH_WIDGET,
00797                              XmNtopWidget, top, /* if top == NULL, this used XmATTACH_FORM */
00798                              XmNleftAttachment, XmATTACH_WIDGET,
00799                              XmNleftWidget, text_label,
00800                              XmNrightAttachment, XmATTACH_FORM,
00801                              XmNcomboBoxType, XmDROP_DOWN_LIST,
00802                              XmNitems, str_list,
00803                              XmNitemCount, num,
00804                              XmNuserData, curr_index,
00805                              NULL);
00806     if (top != NULL) /* FIXME: This assumes we only have 2 items ... */
00807        XtVaSetValues(combo_box,
00808                     XmNbottomAttachment, XmATTACH_FORM,
00809                     NULL);
00810     
00811     /* make resource setting current value */
00812     if (curr_index >= 0) {
00813        XmComboBoxSelectItem(combo_box, str_list[curr_index]);
00814     }
00815        
00816     for (i = 0; i < num; i++)
00817        XmStringFree(str_list[i]);
00818     XtFree((XtPointer)str_list);
00819 
00820     XtAddCallback(combo_box, XmNselectionCallback, select_cb, (XtPointer)tinfo); 
00821     
00822     /*
00823      * workaround for pointer grabbing bug (see xm_menu.c). We need to use
00824      * the popdownCallback of the internal `GrabShell' child of the combo box.
00825      */
00826     {
00827        Widget grab_shell;
00828        if (get_widget_by_name(&grab_shell, combo_box, "GrabShell", True))
00829            XtAddCallback(grab_shell, XtNpopdownCallback, popdown_callback, NULL);
00830     }
00831     adjust_heights(text_label, combo_box, NULL);
00832 
00833     XtManageChild(text_label);
00834     XtManageChild(combo_box);
00835 
00836     return combo_box;
00837 #else
00838     menu = XmCreatePulldownMenu(parent, (char *)menu_name, NULL, 0);
00839 /*     XtVaSetValues(menu, */
00840 /*              XmNtopAttachment, XmATTACH_WIDGET, */
00841 /*              XmNtopWidget, top, */
00842 /*              XmNleftAttachment, XmATTACH_FORM, */
00843 /*              XmNrightAttachment, XmATTACH_FORM, */
00844 /*              NULL); */
00845 
00846     str = XmStringCreateLocalized((char *)label);
00847     n = 0;
00848     XtSetArg(args[n], XmNsubMenuId, menu); n++;
00849     XtSetArg(args[n], XmNlabelString, str); n++;
00850     XtSetArg(args[n], XmNuserData, NULL); n++;
00851     cascade = XmCreateOptionMenu(parent, (char *)name, args, n);
00852     if (top)
00853        XtVaSetValues(cascade,
00854                     XmNtopAttachment, XmATTACH_WIDGET,
00855                     XmNtopWidget, top,
00856                     XmNleftAttachment, XmATTACH_FORM,
00857                     NULL);
00858     else
00859        XtVaSetValues(cascade,
00860                     XmNtopAttachment, XmATTACH_FORM,
00861                     XmNleftAttachment, XmATTACH_FORM,
00862                     NULL);
00863     XmStringFree(str);
00864 
00865     if (ptr != NULL) {
00866        item = XtVaCreateManagedWidget(ptr, xmPushButtonGadgetClass, menu,
00867                                    XmNuserData, tinfo,
00868                                    NULL);
00869        XtAddCallback(item, XmNactivateCallback, select_cb, menu); 
00870     }
00871     
00872     for (i = 0; command_list[i] != NULL; i++) {
00873        item = XtVaCreateManagedWidget(command_list[i], xmPushButtonGadgetClass, menu,
00874                                 XmNuserData, tinfo,
00875                                 NULL);
00876        XtAddCallback(item, XmNactivateCallback, select_cb, menu); 
00877     }
00878     XtManageChild(cascade);
00879     return cascade;
00880 #endif
00881 }
00882 
00883 Widget
00884 prefs_helpers(struct topic_info *tinfo)
00885 {
00886 /*     struct prefs_choice *prefs = (struct prefs_choice *)info->data; */
00887     Widget form, /* frame, */ form1;
00888     Widget browser_command, editor_command;
00889 
00890     form = XmCreateForm(tinfo->right_form, "helpers_form", NULL, 0);
00891 
00892 /*     frame = XmCreateFrame(form, "commands_frame", NULL, 0); */
00893 
00894     form1 = XtVaCreateWidget("commands_form", xmFormWidgetClass,
00895                           form,
00896                           XmNverticalSpacing, 10,
00897                           XmNhorizontalSpacing, 0,
00898                           NULL);
00899 
00900     if (m_browser_list == NULL)
00901        m_browser_list = get_separated_list(resource.prefs_browser_list, "\n", False);
00902     
00903     if (m_editor_list == NULL)
00904        m_editor_list = get_separated_list(resource.prefs_editor_list, "\n", False);
00905     
00906     browser_command = h_create_command(Xdvi_BROWSER_COMBO_NAME,
00907                                    Xdvi_BROWSER_MENU_NAME,
00908                                    "Web Browser: ",
00909                                    resource.browser,
00910                                    form1, NULL,
00911                                    m_browser_list,
00912                                    select_browser_cb, tinfo);
00913     
00914     editor_command = h_create_command(Xdvi_EDITOR_COMBO_NAME,
00915                                   Xdvi_EDITOR_MENU_NAME,
00916                                   "Editor for Source Specials: ",
00917                                   resource.editor,
00918                                   form1, browser_command,
00919                                   m_editor_list,
00920                                   select_editor_cb, tinfo);
00921     
00922 /* #if PS_GS */
00923 /*     Widget b2 = XmCreateLabelGadget(rowcol, "[x] Use Ghostscript to interpret PS specials", NULL, 0); */
00924 
00925     /* TODO: don't need this??? Similar: ps2pdf, dvips conversion?? */
00926     /*     Widget b3 = XmCreateLabelGadget(rowcol, "Path to Ghostscript: ____________", NULL, 0); */
00927     
00928 /* #endif */
00929 /*     Widget b4 = XmCreateLabelGadget(rowcol, "Editor for source specials: <pulldown> [Other ...]", NULL, 0); */
00930 /*     XtManageChild(b1); */
00931 /*     XtManageChild(b2); */
00932 /*     XtManageChild(b3); */
00933 /*     XtManageChild(b4); */
00934 /*     XtManageChild(rowcol); */
00935 
00936     XtManageChild(form1);
00937 /*     XtManageChild(frame); */
00938 
00939     return form;
00940 }
00941 
00942 #else
00943 /* silence `empty compilation unit' warnings */
00944 static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
00945 #endif /* MOTIF */
00946