Back to index

tetex-bin  3.0
search-dialog.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2003-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 #include "xdvi-config.h"
00024 #include "xdvi.h"
00025 
00026 #include "events.h"
00027 #include "dvi-init.h"
00028 #include "search-dialog.h"
00029 #include "search-internal.h"
00030 #include "xlwradio.h"
00031 #include "statusline.h"
00032 #include "string-utils.h"
00033 #include "util.h"
00034 #include "message-window.h"
00035 #include "x_util.h"
00036 
00037 #include <X11/Xatom.h>
00038 #include <X11/StringDefs.h>
00039 
00040 #ifdef MOTIF
00041 #  include <Xm/BulletinB.h>
00042 #  include <Xm/DialogS.h>
00043 #  include <Xm/PanedW.h>
00044 #  include <Xm/MessageB.h>
00045 #  include <Xm/LabelG.h>
00046 #  include <Xm/Form.h>
00047 #  include <Xm/Frame.h>
00048 #  include <Xm/ToggleBG.h>
00049 #  include <Xm/Text.h>
00050 #  include <Xm/TextF.h>
00051 #  include <Xm/PushB.h>
00052 #  include <Xm/Protocols.h>
00053 #  include <Xm/AtomMgr.h>
00054 #else /* MOTIF */
00055 #  include <X11/Shell.h>
00056 #  include <X11/Xaw/Paned.h>
00057 #  include <X11/Xaw/Box.h>
00058 #  include <X11/Xaw/Form.h>
00059 #  include <X11/Xaw/Label.h>
00060 #  include <X11/Xaw/Command.h>
00061 #  include <X11/Xaw/Toggle.h>
00062 #  include <X11/Xaw/AsciiText.h>
00063 #endif /* MOTIF */
00064 
00065 /* #defines for widgets that are used in common code */
00066 #ifdef MOTIF
00067 #  define SHELL_WIDGET xmDialogShellWidgetClass
00068 #  define PANED_WIDGET xmPanedWindowWidgetClass
00069 #  define FORM_WIDGET xmFormWidgetClass
00070 #  define LABEL_WIDGET xmLabelGadgetClass
00071 #  define TEXT_WIDGET xmTextFieldWidgetClass
00072 #  define CHECKBOX_WIDGET xmToggleButtonGadgetClass
00073 #  define CHECKBUTTON_IS_SET XmNset
00074 #  define PUSHBUTTON_WIDGET xmPushButtonWidgetClass
00075 #  define VALUE_CALLBACK_NAME XmNvalueChangedCallback
00076 #  define ACTIVATE_CALLBACK_NAME XmNactivateCallback
00077 #else /* MOTIF */
00078 #  define SHELL_WIDGET transientShellWidgetClass
00079 #  define PANED_WIDGET panedWidgetClass
00080 #  define FORM_WIDGET formWidgetClass
00081 #  define LABEL_WIDGET labelWidgetClass
00082 #  define TEXT_WIDGET asciiTextWidgetClass
00083 #    ifdef XAW
00084 #      define CHECKBOX_WIDGET radioWidgetClass
00085 #    else /* XAW */
00086 #      define CHECKBOX_WIDGET toggleWidgetClass
00087 #    endif /* XAW */
00088 #  define CHECKBUTTON_IS_SET XtNstate
00089 #  define PUSHBUTTON_WIDGET commandWidgetClass
00090 #  define VALUE_CALLBACK_NAME XtNcallback
00091 #  define ACTIVATE_CALLBACK_NAME XtNcallback
00092 #endif /* MOTIF */
00093 
00094 static Boolean m_find_popup_active = False;
00095 
00096 /* flags for setting single bits in resource.search_window_defaults */
00097 static const int SETTINGS_USE_REGEXP_FLAG = 1;
00098 static const int SETTINGS_CASE_SENSITIVE_FLAG = 2;
00099 static const int SETTINGS_BACKWARDS_FLAG = 4;
00100 static const int SETTINGS_IGNORE_LINEBREAKS_FLAG = 8;
00101        
00102 
00103 static void
00104 cb_search_go(Widget w, XtPointer client_data, XtPointer call_data)
00105 {
00106     struct search_settings *settings = (struct search_settings *)client_data;
00107     Widget find_popup;
00108     Position x = 0, y = 0;
00109     
00110     ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
00111     UNUSED(call_data);
00112 
00113     TRACE_FIND((stderr, "cb_search_go: settings: searchterm=|%s|, down = %d, re = %d, case = %d",
00114               settings->term, settings->direction, settings->use_regexp, settings->case_sensitive));
00115 
00116     /* retrieve the find popup window */
00117     if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
00118        XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
00119        x = y = 0;
00120     }
00121     else {
00122        XtVaGetValues(find_popup, XtNx, &x, XtNy, &y, NULL);
00123        /* add some offsets */
00124        settings->x_pos = x + 10;
00125        settings->y_pos = y + 10;
00126        TRACE_GUI((stderr, "SHELL: %ld; x: %d, y: %d", (unsigned long)w, x, y));
00127     }
00128 
00129     settings->from_page = current_page;
00130     settings->message_window = 0;
00131     TRACE_FIND((stderr, "starting search from page: %d", settings->from_page));
00132     search_dvi((XtPointer)settings);
00133 }
00134 
00135 static void
00136 show_settings(const char *func_name, struct search_settings *settings)
00137 {
00138     TRACE_FIND((stderr, "%s: settings: str=|%s|, down = %d, re = %d, "
00139               "case = %d, ignore_hyphens = %d, ignore_linebreaks = %d\n",
00140               func_name,
00141               settings->term,
00142               settings->direction,
00143               settings->use_regexp,
00144               settings->case_sensitive,
00145               settings->ignore_hyphens,
00146               settings->ignore_linebreaks));
00147 
00148 }
00149 
00150 
00151 static void
00152 cb_regexp_search(Widget w, XtPointer client_data, XtPointer call_data)
00153 {
00154     struct search_settings *settings = (struct search_settings *)client_data;
00155     /* Hack: Since XawToggleUnsetCurrent() will invoke this callback again,
00156        return every second time to avoid multiple popups. This is done by
00157        setting the flag `do_return'.
00158     */
00159 #if !HAVE_REGEX_H
00160     static Boolean do_return = False;
00161 #endif
00162     ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
00163     UNUSED(call_data);
00164 
00165 #if !HAVE_REGEX_H
00166     if (do_return) {
00167        do_return = False;
00168        return;
00169     }
00170     
00171     XBell(DISP, 0);
00172     popup_message(get_matching_parent(w, globals.widgets.top_level, "find_popup", NULL),
00173                 MSG_ERR,
00174                 NULL,
00175                 "Sorry, regular expression support (regex.h) is not available on this platform.");
00176     do_return = True;
00177 #ifdef MOTIF
00178     XmToggleButtonGadgetSetState(w, True, False);
00179 #else
00180     XawToggleUnsetCurrent(w);
00181 #endif
00182     
00183 #else
00184     UNUSED(w);
00185     settings->use_regexp = !(settings->use_regexp);
00186 
00187     /* force re-initialization of search term by resetting utf8_term: */
00188     free(settings->utf8_term);
00189     settings->utf8_term = NULL;
00190 
00191     show_settings("cb_regexp_search", settings);
00192 #endif
00193 
00194     if (settings->use_regexp)
00195        resource.search_window_defaults |= SETTINGS_USE_REGEXP_FLAG;
00196     else
00197        resource.search_window_defaults &= ~SETTINGS_USE_REGEXP_FLAG;
00198     store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
00199 }
00200 
00201 static void
00202 cb_backwards_search(Widget w, XtPointer client_data, XtPointer call_data)
00203 {
00204     struct search_settings *settings = (struct search_settings *)client_data;
00205     ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
00206     UNUSED(w);
00207     UNUSED(call_data);
00208 
00209     switch (settings->direction) {
00210     case SEARCH_UP: settings->direction = SEARCH_DOWN; break;
00211     case SEARCH_DOWN: settings->direction = SEARCH_UP; break;
00212     default: ASSERT(0, "shouldn't happen: settings->direction is neither SEARCH_UP nor SEARCH_DOWN!"); break;
00213     }
00214 
00215     show_settings("cb_backwards_search", settings);
00216 
00217     if (settings->direction == SEARCH_UP)
00218        resource.search_window_defaults |= SETTINGS_BACKWARDS_FLAG;
00219     else
00220        resource.search_window_defaults &= ~SETTINGS_BACKWARDS_FLAG;
00221     store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
00222 }
00223 
00224 static void
00225 cb_match_case(Widget w, XtPointer client_data, XtPointer call_data)
00226 {
00227     struct search_settings *settings = (struct search_settings *)client_data;
00228     ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
00229     UNUSED(w);
00230     UNUSED(call_data);
00231 
00232     settings->case_sensitive = !(settings->case_sensitive);
00233 
00234     show_settings("cb_match_case", settings);
00235 
00236     if (settings->case_sensitive)
00237        resource.search_window_defaults |= SETTINGS_CASE_SENSITIVE_FLAG;
00238     else
00239        resource.search_window_defaults &= ~SETTINGS_CASE_SENSITIVE_FLAG;
00240     store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
00241 }
00242 
00243 static void
00244 cb_linebreaks(Widget w, XtPointer client_data, XtPointer call_data)
00245 {
00246     struct search_settings *settings = (struct search_settings *)client_data;
00247     ASSERT(settings != NULL, "client_data cb_search_go mustn't be NULL!");
00248     UNUSED(w);
00249     UNUSED(call_data);
00250 
00251     settings->ignore_linebreaks = !(settings->ignore_linebreaks);
00252     settings->ignore_hyphens = !(settings->ignore_hyphens);
00253     
00254     show_settings("cb_linebreaks", settings);
00255 
00256     if (settings->ignore_linebreaks)
00257        resource.search_window_defaults |= SETTINGS_IGNORE_LINEBREAKS_FLAG;
00258     else
00259        resource.search_window_defaults &= ~SETTINGS_IGNORE_LINEBREAKS_FLAG;
00260     store_preference(NULL, "searchWindowDefaults", "%u", resource.search_window_defaults);
00261 }
00262 
00263 static void
00264 cb_search_cancel(Widget w, XtPointer client_data, XtPointer call_data)
00265 {
00266     Widget find_popup;
00267     struct search_settings *settings = (struct search_settings *)client_data;
00268     
00269     UNUSED(w);
00270     UNUSED(call_data);
00271 
00272     /* retrieve the find popup window */
00273     if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
00274        XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
00275        return;
00276     }
00277 
00278     /* This flag is checked in the scanning routines, and
00279        will be eventually reset by do_pages() in events.c.
00280        (The scanning routines musn't reset it, since they
00281        might not be called again after this point!) */
00282     globals.ev.flags |= EV_FIND_CANCEL;
00283 
00284     search_signal_page_changed(); /* Hack to make search restart anew */
00285     search_erase_highlighting(True);
00286     if (settings->message_window != 0) {
00287        TRACE_GUI((stderr, "kill_message_window: %p\n", (void *)settings->message_window));
00288        kill_message_window(settings->message_window);
00289     }
00290     XtPopdown(find_popup);
00291     m_find_popup_active = False;
00292 }
00293 
00294 static void
00295 cb_search_get_term_button(Widget w, XtPointer client_data, XtPointer call_data)
00296 {
00297     struct search_settings *settings = (struct search_settings *)client_data;
00298     char *searchterm = NULL;
00299 
00300     Widget searchbox_input, paned, box;
00301     UNUSED(call_data);
00302 
00303     box = XtParent(w);
00304     ASSERT(box != 0, "Parent of button widget mustn't be NULL!");
00305     paned = XtParent(box);
00306     ASSERT(paned != 0, "Parent of box widget mustn't be NULL!");
00307 
00308     if ((searchbox_input = XtNameToWidget(paned, "*searchbox_input")) == 0) {
00309        XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
00310        return;
00311     }
00312     
00313 #ifdef MOTIF
00314     XtVaGetValues(searchbox_input, XmNvalue, &searchterm, NULL);
00315 #else
00316     XtVaGetValues(searchbox_input, XtNstring, &searchterm, NULL);
00317 #endif
00318     if (searchterm == NULL) {
00319        XDVI_WARNING((stderr, "Searchterm in cb_search_get_term callback shouldn't be NULL!"));
00320        return;
00321     }
00322     TRACE_FIND((stderr, "searchterm1: |%s|", searchterm));
00323     settings->term = searchterm;
00324     
00325     cb_search_go(w, settings, NULL);
00326 }
00327 
00328 static void
00329 search_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
00330 {
00331     struct search_settings *settings = NULL;
00332     void *ptr;
00333     UNUSED(event);
00334 
00335     ASSERT(*num_params > 0, "params in search_cancel must be > 0!");
00336     ASSERT(*params != NULL, "params in search_cancel mustn't be NULL!");
00337 
00338     /*
00339      * the *params char pointer contains the pointer value (address) of `settings';
00340      * convert it back to a pointer:
00341      */
00342     TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
00343     sscanf(*params, "%p", &ptr);
00344     settings = (struct search_settings *)ptr;
00345     TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
00346     ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
00347 
00348     cb_search_cancel(w, settings, NULL);
00349 }
00350 
00351 #ifdef MOTIF
00352 
00353 static void
00354 cb_search_get_term(Widget w, XtPointer client_data, XtPointer call_data)
00355 {
00356     struct search_settings *settings = (struct search_settings *)client_data;
00357     char *searchterm = NULL;
00358     Widget form, paned, searchbox_form;
00359     Widget button;
00360     XEvent ev;
00361     UNUSED(call_data);
00362 
00363     /* retrieve the `Find' button widget */
00364     searchbox_form = XtParent(w);
00365     ASSERT(searchbox_form != 0, "Parent of button widget mustn't be NULL!");
00366     form = XtParent(searchbox_form);
00367     ASSERT(form != 0, "Parent of searchbox_form widget mustn't be NULL!");
00368     paned = XtParent(form);
00369     ASSERT(paned != 0, "Parent of form widget mustn't be NULL!");
00370     if ((button = XtNameToWidget(paned, "*find_button")) == 0) {
00371        XDVI_WARNING((stderr, "Couldn't find \"find_button\" widget!"));
00372        return;
00373     }
00374 
00375     if (settings != NULL) {
00376        /* retrieve search term from text input field */
00377        XtVaGetValues(w, XmNvalue, &searchterm, NULL);
00378        if (searchterm == NULL) {
00379            XDVI_WARNING((stderr, "Searchterm in cb_search_get_term callback shouldn't be NULL!"));
00380            return;
00381        }
00382        
00383        TRACE_FIND((stderr, "searchterm2: |%s|", searchterm));
00384        settings->term = (const char *)searchterm;
00385     }
00386 
00387     /* make the `Find' button think it got pushed.
00388        Also synthetisize an event, just to be sure ... */
00389     synthetisize_event(&ev, button);
00390     
00391     XtCallActionProc(button, "ArmAndActivate", &ev, NULL, 0);
00392     /* the following don't make the button appear visually pressed: */
00393     /*     XtCallCallbacks(button, XmNarmCallback, NULL); */
00394     /*     XtCallCallbacks(button, XmNactivateCallback, NULL); */
00395 }
00396 
00397 static void
00398 xm_search_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
00399 {
00400     struct search_settings *settings = NULL;
00401     void *ptr;
00402     Widget input;
00403 
00404     UNUSED(w);
00405     UNUSED(event);
00406 
00407     if (params != NULL) { /* re-initialize search term */
00408        ASSERT(*num_params == 1, "num_params in xm_search_go should be 1 if *params != NULL");
00409        /*
00410         * the *params char pointer contains the pointer value (address) of `settings';
00411         * convert it back to a pointer:
00412         */
00413        TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
00414        sscanf(*params, "%p", &ptr);
00415        settings = (struct search_settings *)ptr;
00416        TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
00417        ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
00418     }  
00419 
00420     if ((input = XtNameToWidget(globals.widgets.top_level, "*searchbox_input")) == 0) {
00421        XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
00422        return;
00423     }
00424     cb_search_get_term(input, settings, NULL);    
00425 }
00426 
00427 #else /* MOTIF */
00428 
00429 static void
00430 xaw_unset_button(XtPointer client_data, XtIntervalId *id)
00431 {
00432     XEvent ev;
00433     Widget button = (Widget)client_data;
00434 
00435     UNUSED(id);
00436     
00437     synthetisize_event(&ev, button);
00438     XtCallActionProc(button, "unset", &ev, NULL, 0);
00439 }
00440 
00441 static void
00442 xaw_search_go(Widget w, XEvent *event, String *params, Cardinal *num_params)
00443 {
00444     struct search_settings *settings = NULL;
00445     void *ptr;
00446     char *searchterm = NULL;
00447     Widget button, input;
00448     XtIntervalId timeout;
00449     
00450     UNUSED(w);
00451 
00452     /* retrieve the `Find' button widget */
00453     if ((button = XtNameToWidget(globals.widgets.top_level, "*find_button")) == 0) {
00454        XDVI_WARNING((stderr, "Couldn't find \"find_button\" widget!"));
00455        return;
00456     }
00457     if ((input = XtNameToWidget(globals.widgets.top_level, "*searchbox_input")) == 0) {
00458        XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
00459        return;
00460     }
00461 
00462     XtVaGetValues(input, XtNstring, &searchterm, NULL);
00463     if (searchterm == NULL) {
00464        XDVI_WARNING((stderr, "Searchterm in xaw_search_go callback shouldn't be NULL!"));
00465        return;
00466     }
00467 
00468     if (params != NULL) { /* re-initialize search term */
00469        ASSERT(*num_params == 1, "num_params in xaw_search_go should be 1 if *params != NULL");
00470        /*
00471         * the *params char pointer contains the pointer value (address) of `settings';
00472         * convert it back to a pointer:
00473         */
00474        TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
00475        sscanf(*params, "%p", &ptr);
00476        settings = (struct search_settings *)ptr;
00477        TRACE_GUI((stderr, "Pointer address: |%p|", (void *)settings));
00478        ASSERT(settings != NULL, "Shouldn't happen: Couldn't get string representation of argument pointer.");
00479        
00480        settings->term = (const char *)searchterm;
00481     }
00482 
00483     /*
00484      * Again, we want the button to appear activated when <RETURN> is pressed.
00485      * For this, we explicitly invoke set()notify(), and unset() after a timeout
00486      * of 150 milliseconds, which seems to correspond to the Motif default.
00487      */
00488     XtCallActionProc(button, "set", event, NULL, 0);
00489     XtCallActionProc(button, "notify", event, NULL, 0);
00490     XSync(DISP, False);
00491     timeout = XtAppAddTimeOut(app, 150, xaw_unset_button, (XtPointer)button);
00492 }
00493 
00494 
00495 /*
00496  * Restart search from within another popup (confirmation) window.
00497  */
00498 static void
00499 xaw_search_restart(Widget w, XEvent *event, String *params, Cardinal *num_params)
00500 {
00501     void *ptr;
00502     struct search_settings *settings;
00503 
00504     UNUSED(event);
00505     UNUSED(w);
00506 
00507     ASSERT(*num_params > 0, "params in xaw_search_restart must be > 0!");
00508     ASSERT(*params != NULL, "params in xaw_search_restart mustn't be NULL!");
00509 
00510     TRACE_GUI((stderr, "Pointer string value: |%s|", *params));
00511     sscanf(*params, "%p", &ptr);
00512     settings = (struct search_settings *)ptr;
00513     
00514     search_restart((XtPointer)settings);
00515 }
00516 
00517 static XtActionsRec xaw_search_actions[] = {
00518     { "do-search-restart", xaw_search_restart },
00519     { "do-search", xaw_search_go },
00520 };
00521 #endif /* MOTIF */
00522 
00523 static XtActionsRec search_actions[] = {
00524     { "do-search",
00525 #ifdef MOTIF
00526       xm_search_go
00527 #else
00528       xaw_search_go
00529 #endif
00530     },
00531     { "cancel-search", search_cancel },
00532 };
00533 
00534 static Widget
00535 create_search_window(struct search_settings *settings)
00536 {
00537     Widget top_level_shell;
00538     Atom WM_DELETE_WINDOW;
00539     Widget form, find_paned, box;
00540     unsigned char curr_state;
00541 
00542     Widget searchbox_form, searchbox_label, searchbox_input;
00543     /* left and right column */
00544     Widget options_left_form, options_right_form;
00545     /* checkboxes in left column */
00546     Widget regexp_checkbox, matchcase_checkbox, backwards_checkbox;
00547     /* checkboxes in right column */
00548     Widget linebreaks_checkbox;
00549     Widget find_button, cancel_button;
00550 
00551     XtTranslations xlats;
00552     char *translation_str = NULL;
00553 #ifdef MOTIF
00554     XmString str;
00555 #else /* MOTIF */
00556     XtTranslations wm_translations;
00557     int ddist;
00558 #endif
00559 
00560     XtAddActions(search_actions, XtNumber(search_actions));
00561 
00562 #ifndef MOTIF
00563 
00564     XtAddActions(xaw_search_actions, XtNumber(xaw_search_actions));
00565 #define HORIZONTAL_RESIZING_NO     XtNleft, XtChainLeft, XtNright, XtChainLeft
00566 #define HORIZONTAL_RESIZING_YES XtNleft, XtChainLeft, XtNright, XtChainRight
00567 #define VERTICAL_RESIZING_NO       XtNtop, XtChainTop, XtNbottom, XtChainTop
00568 
00569     /*
00570      * hacky: Since translations can only contain strings, pass
00571      * the pointer address as string in the callback. But the only
00572      * portability problem should be the size of the pointer
00573      * representation, and we deal with that by using VSNPRINTF().
00574      */
00575     translation_str = get_string_va("<Message>WM_PROTOCOLS: cancel-search(%p)\nCtrl<Key>g:find-next()",
00576                                 (void *)settings);
00577     wm_translations = XtParseTranslationTable(translation_str);
00578     free(translation_str);
00579     translation_str = NULL;
00580 #endif /* not MOTIF */
00581     
00582     top_level_shell = XtVaCreatePopupShell("find_popup",
00583                                       SHELL_WIDGET,
00584                                       globals.widgets.top_level,
00585                                       XtNtitle, "xdvik: Find in DVI file",
00586                                       XtNmappedWhenManaged, False, /* so that we can center it first */
00587                                       XtNtransientFor, globals.widgets.top_level,
00588                                       XtNallowShellResize, True,
00589 #ifdef MOTIF
00590                                       XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
00591 #else
00592                                       XtNtranslations, wm_translations,
00593 #endif
00594                                       NULL);
00595 
00596     TRACE_GUI((stderr, "toplevel: %ld", (unsigned long)top_level_shell));
00597     
00598     WM_DELETE_WINDOW = XInternAtom(XtDisplay(top_level_shell), "WM_DELETE_WINDOW", False);
00599 #ifdef MOTIF
00600     XmAddWMProtocolCallback(top_level_shell, WM_DELETE_WINDOW, cb_search_cancel, settings);
00601 #endif
00602     
00603     find_paned = XtVaCreateWidget("find_paned",
00604                               PANED_WIDGET,
00605                               top_level_shell,
00606 #ifdef MOTIF
00607                               /* make sashes invisible */
00608                               XmNsashWidth, 1,
00609                               XmNsashHeight, 1,
00610 #endif
00611                               NULL);
00612        
00613     form = XtVaCreateWidget("form",
00614                          FORM_WIDGET,
00615                          find_paned,
00616 #ifdef MOTIF
00617                          XmNhorizontalSpacing, DDIST_MAJOR,
00618                          XmNverticalSpacing, DDIST_MAJOR,
00619                          XmNautoUnmanage, False,
00620 #else
00621                          XtNallowResize, True,
00622 #endif
00623                          NULL);
00624 
00625 #ifdef MOTIF
00626     str = XmStringCreateLocalized("Find:");
00627 #else
00628     XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL);
00629 #endif
00630     
00631     /* search term input field */
00632     searchbox_form = XtVaCreateWidget("searchbox_form",
00633                                   FORM_WIDGET,
00634                                   form,
00635 #ifdef MOTIF
00636                                   XmNleftAttachment, XmATTACH_FORM,
00637                                   XmNrightAttachment, XmATTACH_FORM,
00638                                   XmNhorizontalSpacing, DDIST,
00639                                   XmNverticalSpacing, DDIST,
00640 #else
00641                                   XtNborderWidth, 0,
00642                                   HORIZONTAL_RESIZING_YES,
00643 #endif
00644                                   NULL);
00645     searchbox_label = XtVaCreateManagedWidget("searchbox_label",
00646                                          LABEL_WIDGET,
00647                                          searchbox_form,
00648 #ifdef MOTIF
00649                                          XmNlabelString, str,
00650                                          XmNtopAttachment, XmATTACH_FORM,
00651                                          XmNleftAttachment, XmATTACH_FORM,
00652                                          XmNbottomAttachment, XmATTACH_FORM,
00653                                          XmNalignment, XmALIGNMENT_BEGINNING,
00654 #else
00655                                          XtNlabel, "Find:",
00656                                          XtNborderWidth, 0,
00657                                          HORIZONTAL_RESIZING_NO,
00658                                          VERTICAL_RESIZING_NO,
00659 #endif
00660                                          NULL);
00661     
00662     searchbox_input = XtVaCreateManagedWidget("searchbox_input",
00663                                          TEXT_WIDGET,
00664                                          searchbox_form,
00665 #ifdef MOTIF
00666                                          XmNtopAttachment, XmATTACH_FORM,
00667                                          XmNrightAttachment, XmATTACH_FORM,
00668                                          XmNleftAttachment, XmATTACH_WIDGET,
00669                                          XmNleftWidget, searchbox_label,
00670                                          XmNbottomAttachment, XmATTACH_FORM,
00671 #else
00672                                          XtNwidth, 260,
00673                                          XtNdataCompression, False,
00674                                          XtNeditType, XawtextEdit,
00675                                          XtNfromHoriz, searchbox_label,
00676                                          HORIZONTAL_RESIZING_YES,
00677                                          VERTICAL_RESIZING_NO,
00678 #endif
00679                                          NULL);
00680 
00681 
00682     if (settings->term != NULL) {
00683        XtVaSetValues(searchbox_input,
00684 #ifdef MOTIF
00685                     XmNvalue,
00686 #else
00687                     XtNstring,
00688 #endif
00689                     settings->term, NULL);
00690     }
00691     
00692     XtManageChild(searchbox_form);
00693     
00694 #ifdef MOTIF
00695     XtAddCallback(searchbox_input, XmNactivateCallback, cb_search_get_term, settings);
00696 #endif
00697     
00698     /*
00699      * form for left row of options checkbuttons
00700      */
00701     options_left_form = XtVaCreateManagedWidget("options_left_form",
00702                                           FORM_WIDGET,
00703                                           form,
00704 #ifdef MOTIF
00705                                           XmNhorizontalSpacing, DDIST,
00706                                           XmNverticalSpacing, DDIST,
00707                                           XmNresizable, True,
00708                                           XmNtopAttachment, XmATTACH_WIDGET,
00709                                           XmNtopWidget, searchbox_form,
00710                                           XmNleftAttachment, XmATTACH_FORM,
00711 /*                                        XmNrightAttachment, XmATTACH_FORM, */
00712 /*                                        XmNbottomAttachment, XmATTACH_FORM, */
00713 #else
00714                                           XtNborderWidth, 0,
00715                                           XtNfromVert, searchbox_form,
00716                                           HORIZONTAL_RESIZING_NO,
00717 #endif
00718                                           NULL);
00719     /*
00720      * form for right row of options checkbuttons
00721      */
00722     options_right_form = XtVaCreateManagedWidget("options_right_form",
00723                                            FORM_WIDGET,
00724                                            form,
00725 #ifdef MOTIF
00726                                            XmNhorizontalSpacing, DDIST,
00727                                            XmNverticalSpacing, DDIST,
00728                                            XmNresizable, True,
00729                                            XmNtopAttachment, XmATTACH_WIDGET,
00730                                            XmNtopWidget, searchbox_form,
00731                                            XmNleftAttachment, XmATTACH_WIDGET,
00732                                            XmNleftWidget, options_left_form,
00733                                            XmNrightAttachment, XmATTACH_FORM,
00734 /*                                         XmNbottomAttachment, XmATTACH_FORM, */
00735 #else
00736                                            XtNborderWidth, 0,
00737                                            XtNfromVert, searchbox_form,
00738                                            XtNfromHoriz, options_left_form,
00739                                            HORIZONTAL_RESIZING_NO,
00740 #endif
00741                                            NULL);
00742 #ifdef MOTIF
00743     XmStringFree(str);
00744     str = XmStringCreateLocalized("Regular expression");
00745 #endif
00746     
00747     regexp_checkbox = XtVaCreateManagedWidget("regexp_checkbox",
00748                                          CHECKBOX_WIDGET,
00749                                          options_left_form,
00750 #ifdef MOTIF
00751                                          XmNlabelString, str,
00752                                          XmNindicatorType, XmN_OF_MANY,
00753                                          XmNtopAttachment, XmATTACH_FORM,
00754                                          XmNleftAttachment, XmATTACH_FORM,
00755 #else
00756                                          XtNlabel, "Regular expression",
00757                                          XtNborderWidth, 0,
00758                                          XtNisRadio, False,
00759                                          XtNhighlightThickness, 1,
00760                                          HORIZONTAL_RESIZING_NO,
00761                                          VERTICAL_RESIZING_NO,
00762 #endif
00763                                          NULL);
00764 
00765     XtAddCallback(regexp_checkbox, VALUE_CALLBACK_NAME, cb_regexp_search, settings);
00766     
00767 #ifdef MOTIF
00768     XmStringFree(str);
00769     str = XmStringCreateLocalized("Find backwards");
00770 #endif
00771 
00772     backwards_checkbox = XtVaCreateManagedWidget("backwards_checkbox",
00773                                            CHECKBOX_WIDGET,
00774                                            options_left_form,
00775 #ifdef MOTIF
00776                                            XmNlabelString, str,
00777                                            XmNindicatorType, XmN_OF_MANY,
00778                                            XmNtopAttachment, XmATTACH_WIDGET,
00779                                            XmNtopWidget, regexp_checkbox,
00780                                            XmNleftAttachment, XmATTACH_FORM,
00781                                            XmNbottomAttachment, XmATTACH_FORM,
00782 #else
00783                                            XtNlabel, "Find backwards",
00784                                            XtNfromVert, regexp_checkbox,
00785                                            XtNborderWidth, 0,
00786                                            XtNisRadio, False,
00787                                            XtNhighlightThickness, 1,
00788                                            HORIZONTAL_RESIZING_NO,
00789                                            VERTICAL_RESIZING_NO,
00790 #endif
00791                                            NULL);
00792 
00793     XtAddCallback(backwards_checkbox, VALUE_CALLBACK_NAME, cb_backwards_search, settings);
00794 
00795 #ifdef MOTIF
00796     XmStringFree(str);
00797     str = XmStringCreateLocalized("Case sensitive");
00798 #endif
00799 
00800     matchcase_checkbox = XtVaCreateManagedWidget("matchcase_checkbox",
00801                                            CHECKBOX_WIDGET,
00802                                            options_right_form,
00803 #ifdef MOTIF
00804                                            XmNlabelString, str,
00805                                            XmNindicatorType, XmN_OF_MANY,
00806                                            XmNtopAttachment, XmATTACH_FORM,
00807                                            XmNleftAttachment, XmATTACH_FORM,
00808 #else
00809                                            XtNlabel, "Case sensitive",
00810                                            XtNborderWidth, 0,
00811                                            XtNisRadio, False,
00812                                            XtNhighlightThickness, 1,
00813                                            HORIZONTAL_RESIZING_NO,
00814                                            VERTICAL_RESIZING_NO,
00815 #endif
00816                                            NULL);
00817 
00818     XtAddCallback(matchcase_checkbox, VALUE_CALLBACK_NAME, cb_match_case, settings);
00819     
00820 #ifdef MOTIF
00821     XmStringFree(str);
00822     str = XmStringCreateLocalized("Ignore newlines/hyphens");
00823 #endif
00824 
00825     linebreaks_checkbox = XtVaCreateManagedWidget("linebreaks_checkbox",
00826                                             CHECKBOX_WIDGET,
00827                                             options_right_form,
00828 #ifdef MOTIF
00829                                             XmNlabelString, str,
00830                                             XmNindicatorType, XmN_OF_MANY,
00831                                             XmNtopAttachment, XmATTACH_WIDGET,
00832                                             XmNtopWidget, matchcase_checkbox,
00833                                             XmNleftAttachment, XmATTACH_FORM,
00834 #else
00835                                             XtNlabel, "Ignore newlines/hyphens",
00836                                             XtNfromVert, matchcase_checkbox,
00837                                             XtNborderWidth, 0,
00838                                             XtNisRadio, False,
00839                                             XtNhighlightThickness, 1,
00840                                             HORIZONTAL_RESIZING_NO,
00841                                             VERTICAL_RESIZING_NO,
00842 #endif
00843                                             NULL);
00844     
00845     XtAddCallback(linebreaks_checkbox, VALUE_CALLBACK_NAME, cb_linebreaks, settings);
00846 
00847     /*
00848      * box for Find/Cancel buttons
00849      */
00850     box = XtVaCreateManagedWidget("box",
00851                               FORM_WIDGET,
00852                               find_paned,
00853 #ifdef MOTIF
00854                               XmNskipAdjust, True, /* don't resize this area */
00855 #else
00856                               /* resizing by user isn't needed */
00857                               XtNshowGrip, False,
00858                               XtNdefaultDistance, 6, /* some padding */
00859                               /* resizing the window shouldn't influence this box,
00860                                * but only the pane widget
00861                                */
00862                               XtNskipAdjust, True,
00863                               XtNaccelerators, G_accels_cr,
00864 #endif
00865                               NULL);
00866     
00867 #ifdef MOTIF
00868     XmStringFree(str);
00869     str = XmStringCreateLocalized("Find");
00870 #endif
00871 
00872     find_button = XtVaCreateManagedWidget("find_button",
00873                                      PUSHBUTTON_WIDGET,
00874                                      box,
00875 #ifdef MOTIF
00876                                      XmNlabelString, str,
00877                                      XmNshowAsDefault, True,
00878                                      XmNdefaultButtonShadowThickness, 1,
00879                                      XmNtopAttachment, XmATTACH_FORM,
00880                                      XmNbottomAttachment, XmATTACH_FORM,
00881                                      XmNleftAttachment, XmATTACH_FORM,
00882                                      /* to mimick appearance of native dialog buttons: */
00883                                      XmNmarginWidth, 6,
00884                                      XmNmarginHeight, 4,
00885                                      XmNtopOffset, 10,
00886                                      XmNbottomOffset, 10,
00887                                      XmNleftOffset, 10,
00888 #else
00889                                      XtNlabel, "Find",
00890                                      XtNaccelerators, G_accels_cr,
00891                                      XtNtop, XtChainTop,
00892                                      XtNbottom, XtChainBottom,
00893                                      HORIZONTAL_RESIZING_NO,
00894 #endif
00895                                      NULL);
00896 #ifdef MOTIF
00897     XmStringFree(str);
00898     str = XmStringCreateLocalized("Cancel");
00899 #endif
00900 
00901     cancel_button = XtVaCreateManagedWidget("cancel_button",
00902                                        PUSHBUTTON_WIDGET,
00903                                        box,
00904 #ifdef MOTIF
00905                                        XmNlabelString, str,
00906                                        XmNdefaultButtonShadowThickness, 1,
00907                                        XmNtopAttachment, XmATTACH_FORM,
00908                                        XmNbottomAttachment, XmATTACH_FORM,
00909                                        XmNrightAttachment, XmATTACH_FORM,
00910                                        /* to mimick appearance of native dialog buttons: */
00911                                        XmNmarginWidth, 6,
00912                                        XmNmarginHeight, 4,
00913                                        XmNtopOffset, 10,
00914                                        XmNbottomOffset, 10,
00915                                        XmNrightOffset, 10,
00916 #else
00917                                        XtNlabel, "Cancel",
00918                                        XtNfromHoriz, find_button,
00919                                        XtNbottom, XtChainBottom,
00920                                        XtNjustify, XtJustifyRight,
00921                                        XtNleft, XtChainRight,
00922                                        XtNright, XtChainRight,
00923 #endif
00924                                        NULL);
00925     
00926 #ifdef MOTIF
00927     XmStringFree(str);
00928 #endif
00929     
00930     XtAddCallback(cancel_button, ACTIVATE_CALLBACK_NAME, cb_search_cancel, settings);
00931     XtAddCallback(find_button, ACTIVATE_CALLBACK_NAME, cb_search_get_term_button, settings);
00932 
00933     translation_str = get_string_va(
00934 #ifdef MOTIF
00935                                 "<Key>osfCancel:cancel-search(%p)\n"
00936 #else
00937                                 "<Key>Escape:cancel-search(%p)\n"
00938 #endif
00939                                 "<Key>Return:do-search(%p)\n"
00940                                 "Ctrl<Key>g:find-next()",
00941                                 (void *)settings, (void *)settings);
00942     
00943     xlats = XtParseTranslationTable(translation_str);
00944     free(translation_str);
00945 
00946     XtOverrideTranslations(searchbox_form, xlats);
00947     XtOverrideTranslations(options_left_form, xlats);
00948     XtOverrideTranslations(options_right_form, xlats);
00949     XtOverrideTranslations(regexp_checkbox, xlats);
00950     XtOverrideTranslations(matchcase_checkbox, xlats);
00951     XtOverrideTranslations(backwards_checkbox, xlats);
00952     XtOverrideTranslations(box, xlats);
00953     XtOverrideTranslations(find_button, xlats);
00954     XtOverrideTranslations(cancel_button, xlats);
00955     XtOverrideTranslations(searchbox_input, xlats);
00956 
00957     /* following doesn't help to force input to textbox in xaw: */
00958     /* XtInstallAllAccelerators(find_paned, find_paned); */
00959     /* XtInstallAllAccelerators(searchbox_input, find_paned); */
00960     
00961     XtManageChild(form);
00962     XtManageChild(find_paned);
00963 
00964     { /* set all buttons to same size */
00965        Dimension w1, w2, max;
00966        XtVaGetValues(find_button, XtNwidth, &w1, NULL);
00967        XtVaGetValues(cancel_button, XtNwidth, &w2, NULL);
00968        max = MAX(w1, w2);
00969        XtVaSetValues(find_button, XtNwidth, max, NULL);
00970        XtVaSetValues(cancel_button, XtNwidth, max, NULL);
00971     }
00972     
00973     XtManageChild(top_level_shell);
00974     /* don't center this one - would just get in the way in this case. */
00975     /* center_window(top_level_shell, globals.widgets.top_level); */
00976     XtPopup(top_level_shell, XtGrabNone);
00977     m_find_popup_active = True;
00978     
00979 #ifdef MOTIF
00980     XmProcessTraversal(searchbox_input, XmTRAVERSE_CURRENT);
00981 /*     XmProcessTraversal(find_button, XmTRAVERSE_CURRENT); */
00982 #endif
00983     XSetWMProtocols(XtDisplay(top_level_shell), XtWindow(top_level_shell), &WM_DELETE_WINDOW, 1);
00984 
00985     /* check if we have default values from resource.search_window_defaults */
00986     if (resource.search_window_defaults & SETTINGS_USE_REGEXP_FLAG)
00987        XtVaSetValues(regexp_checkbox, CHECKBUTTON_IS_SET, True, NULL);
00988     if (resource.search_window_defaults & SETTINGS_CASE_SENSITIVE_FLAG)
00989        XtVaSetValues(matchcase_checkbox, CHECKBUTTON_IS_SET, True, NULL);
00990     if (resource.search_window_defaults & SETTINGS_BACKWARDS_FLAG)
00991        XtVaSetValues(backwards_checkbox, CHECKBUTTON_IS_SET, True, NULL);
00992     if (resource.search_window_defaults & SETTINGS_IGNORE_LINEBREAKS_FLAG)
00993        XtVaSetValues(linebreaks_checkbox, CHECKBUTTON_IS_SET, True, NULL);
00994        
00995     /* initialize `settings' values according to the checkbox states
00996        (in case user has assigned values via X defaults): */
00997     XtVaGetValues(regexp_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
00998     settings->use_regexp = curr_state;
00999     XtVaGetValues(matchcase_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
01000     settings->case_sensitive = curr_state;
01001     XtVaGetValues(backwards_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
01002     settings->direction = curr_state ? SEARCH_UP : SEARCH_DOWN;
01003     XtVaGetValues(linebreaks_checkbox, CHECKBUTTON_IS_SET, &curr_state, NULL);
01004     settings->ignore_hyphens = settings->ignore_linebreaks = curr_state;
01005 
01006 #ifndef MOTIF
01007     
01008 #undef HORIZONTAL_RESIZING_NO
01009 #undef HORIZONTAL_RESIZING_YES
01010 #undef VERTICAL_RESIZING_NO
01011 
01012 #endif /* MOTIF */
01013     return top_level_shell;
01014 }
01015 
01016 void
01017 dvi_find_string(const char *str, Boolean find_next)
01018 {
01019     /* Synthesize a RET keystroke for the find dialog.
01020      * Also pops up the find dialog, to make it easier for user to
01021      * edit options, change direction etc. */
01022     Widget find_popup;
01023     if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
01024        static struct search_settings settings;
01025        static struct search_info searchinfo = { False, False, False, 0, 0, 0, 0 };
01026        settings.term = str;
01027        settings.use_regexp = False;
01028        settings.case_sensitive = False;
01029        settings.direction = SEARCH_DOWN;
01030        settings.ignore_hyphens = False;
01031        settings.ignore_linebreaks = False;
01032        settings.x_pos = -1;
01033        settings.y_pos = -1;
01034        settings.searchinfo = &searchinfo;
01035        settings.hyphen_delta = 0;
01036 
01037        find_popup = create_search_window(&settings);
01038 
01039        if (find_next)
01040            return;
01041     }
01042     else if (str != NULL) { /* change the search term */
01043        Widget searchbox_input;
01044        if ((searchbox_input = XtNameToWidget(find_popup, "*searchbox_input")) == 0) {
01045            XDVI_WARNING((stderr, "Couldn't find \"searchbox_input\" widget!"));
01046            return;
01047        }
01048        XtVaSetValues(searchbox_input,
01049 #ifdef MOTIF
01050                     XmNvalue,
01051 #else
01052                     XtNstring,
01053 #endif
01054                     str, NULL);
01055     }
01056     if (m_find_popup_active) {
01057        XRaiseWindow(DISP, XtWindow(find_popup));
01058     }
01059     else {
01060        XtPopup(find_popup, XtGrabNone);
01061        m_find_popup_active = True;
01062     }
01063 
01064     if (str != NULL || find_next) {
01065 #ifdef MOTIF
01066        xm_search_go(NULL, NULL, NULL, NULL);
01067 #else
01068        xaw_search_go(NULL, NULL, NULL, NULL);
01069 #endif
01070     }
01071 }
01072