handler.c revision 6448b35c
1/*
2
3Copyright (c) 1987, 1988  X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be included
14in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of the X Consortium shall
25not be used in advertising or otherwise to promote the sale, use or
26other dealings in this Software without prior written authorization
27from the X Consortium.
28
29*/
30
31/*
32 * xman - X window system manual page display program.
33 * Author:    Chris D. Peterson, MIT Project Athena
34 * Created:   October 29, 1987
35 */
36#ifdef HAVE_CONFIG_H
37# include "config.h"
38#endif
39
40#include <sys/types.h>
41#include <sys/stat.h>
42#include "globals.h"
43#include "vendor.h"
44
45#ifdef RELEASE_VERSION
46#define XMAN_VERSION "Xman Version " PACKAGE_VERSION " - X11R" RELEASE_VERSION
47#else
48#define XMAN_VERSION "Xman Version " PACKAGE_VERSION
49#endif
50
51static void PutUpManpage(ManpageGlobals * man_globals, FILE * file);
52static void ToggleBothShownState(ManpageGlobals * man_globals);
53
54/*	Function Name: OptionCallback
55 *	Description: This is the callback function for the callback menu.
56 *	Arguments: w - the widget we are calling back from.
57 *                 globals_pointer - a pointer to the pseudo globals structure
58 *                                  for this manpage.
59 *                 junk - (call data) not used.
60 *	Returns: none.
61 */
62
63/*ARGSUSED*/
64void
65OptionCallback(Widget w, XtPointer pointer, XtPointer junk)
66{
67    ManpageGlobals *man_globals = (ManpageGlobals *) pointer;
68    String params;
69    Cardinal num_params = 1;
70
71    if (w == man_globals->search_entry)
72        PopupSearch(XtParent(w), NULL, NULL, NULL);
73    else if (w == man_globals->dir_entry) {     /* Put Up Directory */
74        params = "Directory";
75        GotoPage(XtParent(w), NULL, &params, &num_params);
76    }
77    else if (w == man_globals->manpage_entry) { /* Put Up Man Page */
78        params = "ManualPage";
79        GotoPage(XtParent(w), NULL, &params, &num_params);
80    }
81    else if (w == man_globals->help_entry)      /* Help */
82        PopupHelp(XtParent(w), NULL, NULL, NULL);
83    else if (w == man_globals->both_screens_entry)      /*Toggle Both_Shown State. */
84        ToggleBothShownState(man_globals);
85    else if (w == man_globals->remove_entry)    /* Kill the manpage */
86        RemoveThisManpage(XtParent(w), NULL, NULL, NULL);
87    else if (w == man_globals->open_entry)      /* Open new manpage */
88        CreateNewManpage(XtParent(w), NULL, NULL, NULL);
89    else if (w == man_globals->version_entry)   /* Get version */
90        ShowVersion(XtParent(w), NULL, NULL, NULL);
91    else if (w == man_globals->quit_entry)      /* Quit. */
92        Quit(XtParent(w), NULL, NULL, NULL);
93}
94
95/*      Function Name: ToggleBothShownState;
96 *      Description: toggles the state of the both shown feature.
97 *      Arguments: man_globals - the man globals structure.
98 *      Returns: none.
99 */
100
101/*
102 * I did not have a two state widget, which is the way this
103 * should really be done.  1/22/88 - CDP.
104 */
105
106static void
107ToggleBothShownState(ManpageGlobals * man_globals)
108{
109    const char *label_str;
110    Arg arglist[1];
111
112    if (man_globals->both_shown == TRUE) {
113        label_str = SHOW_BOTH;
114        if (man_globals->dir_shown)
115            XtUnmanageChild(man_globals->manpagewidgets.manpage);
116        else
117            XtUnmanageChild(man_globals->manpagewidgets.directory);
118    }
119    else {
120        Widget manpage = man_globals->manpagewidgets.manpage;
121        Widget dir = man_globals->manpagewidgets.directory;
122
123        label_str = SHOW_ONE;
124
125        XtSetArg(arglist[0], XtNpreferredPaneSize, resources.directory_height);
126        XtSetValues(dir, arglist, (Cardinal) 1);
127
128        if (!man_globals->dir_shown) {
129            XtUnmanageChild(manpage);
130            XtManageChild(dir);
131        }
132        XtManageChild(manpage);
133    }
134    man_globals->both_shown = !man_globals->both_shown;
135
136    if (man_globals->dir_shown)
137        ChangeLabel(man_globals->label,
138                    man_globals->section_name[man_globals->current_directory]);
139    else
140        ChangeLabel(man_globals->label, man_globals->manpage_title);
141
142    XtSetArg(arglist[0], XtNlabel, label_str);
143    XtSetValues(man_globals->both_screens_entry, arglist, ONE);
144
145    /* if both are shown there is no need to switch between the two. */
146
147    XtSetArg(arglist[0], XtNsensitive, !man_globals->both_shown);
148    XtSetValues(man_globals->manpage_entry, arglist, ONE);
149    XtSetValues(man_globals->dir_entry, arglist, ONE);
150}
151
152/*	Function Name: Popup
153 *	Description: This function pops up the given widget under the cursor.
154 *	Arguments: w - the widget to popup.
155 *                 grab_kind - the kind of grab to register.
156 *	Returns: none
157 */
158
159/* How far off the top of the widget to have the initial cursor position. */
160
161#define OFF_OF_TOP 25
162
163void
164Popup(Widget w, XtGrabKind grab_kind)
165{
166    int x_root, y_root, y_pos, garbage;
167    unsigned int mask;
168    Window junk_window;
169
170    XQueryPointer(XtDisplay(w), XtWindow(w), &junk_window, &junk_window,
171                  &x_root, &y_root, &garbage, &garbage, &mask);
172
173    y_pos = OFF_OF_TOP - Height(w) / 2 - BorderWidth(w);
174    PositionCenter(w, x_root, y_root, y_pos, 0, 2, 2);
175    XtPopup(w, grab_kind);
176}
177
178/*	Function Name: PutUpManpage
179 *	Description: Puts the manpage on the display.
180 *	Arguments: man_globals - a pointer to the pseudo globals structure
181 *                                  for this manpage.
182 *                 file - the file to display.
183 *	Returns: none.
184 */
185
186static void
187PutUpManpage(ManpageGlobals * man_globals, FILE * file)
188{
189    String params = "ManualPage";
190    Cardinal num_params = 1;
191
192    if (file == NULL)
193        return;
194
195    OpenFile(man_globals, file);
196
197    if (!man_globals->both_shown) {
198        Arg arglist[1];
199
200        XtSetArg(arglist[0], XtNsensitive, TRUE);
201        XtSetValues(man_globals->manpage_entry, arglist, ONE);
202        XtSetValues(man_globals->both_screens_entry, arglist, ONE);
203    }
204    GotoPage(man_globals->manpagewidgets.manpage, NULL, &params, &num_params);
205}
206
207/*	Function Name: DirectoryHandler
208 *	Description: This is the callback function for the directory listings.
209 *	Arguments: w - the widget we are calling back from.
210 *                 global_pointer - the pointer to the pseudo global structure
211 *                                  associated with this manpage.
212 *                 ret_val - return value from the list widget.
213 *	Returns: none.
214 */
215
216void
217DirectoryHandler(Widget w, XtPointer global_pointer, XtPointer ret_val)
218{
219    FILE *file;                 /* The manpage file. */
220    ManpageGlobals *man_globals = (ManpageGlobals *) global_pointer;
221    XawListReturnStruct *ret_struct = (XawListReturnStruct *) ret_val;
222
223    file = FindManualFile(man_globals, man_globals->current_directory,
224                          ret_struct->list_index);
225    PutUpManpage(man_globals, file);
226    if ((file != NULL) && (file != man_globals->curr_file)) {
227        fclose(file);
228    }
229}
230
231/*	Function Name: DirPopupCallback
232 *	Description: This is the callback function for the callback menu.
233 *	Arguments: w - the widget we are calling back from.
234 *                 pointer - a pointer to the pseudo globals structure
235 *                                  for this manpage.
236 *                 junk - (call data) not used.
237 *	Returns: none.
238 */
239
240/*ARGSUSED*/
241void
242DirPopupCallback(Widget w, XtPointer pointer, XtPointer junk)
243{
244    ManpageGlobals *man_globals;
245    MenuStruct *menu_struct;
246    Widget parent;
247    int number;
248    int current_box;
249
250    menu_struct = (MenuStruct *) pointer;
251    man_globals = (ManpageGlobals *) menu_struct->data;
252
253    number = menu_struct->number;
254    current_box = man_globals->current_directory;
255
256    /* We have used this guy, pop down the menu. */
257
258    if (number != current_box) {
259        /* This is the only one that we know has a parent. */
260        parent = XtParent(man_globals->manpagewidgets.box[INITIAL_DIR]);
261
262        MakeDirectoryBox(man_globals, parent,
263                         man_globals->manpagewidgets.box + number, number);
264        XtUnmanageChild(man_globals->manpagewidgets.box[current_box]);
265        XtManageChild(man_globals->manpagewidgets.box[number]);
266
267        XawListUnhighlight(man_globals->manpagewidgets.box[current_box]);
268        ChangeLabel(man_globals->label, man_globals->section_name[number]);
269        man_globals->current_directory = number;
270    }
271
272    /* put up directory. */
273    if (!man_globals->both_shown) {
274        XtUnmanageChild(man_globals->manpagewidgets.manpage);
275        XtManageChild(man_globals->manpagewidgets.directory);
276    }
277}
278
279/************************************************************
280 *
281 * Action Routines.
282 *
283 ************************************************************/
284
285/*	Function Name: SaveFormattedPage
286 *	Description: This is the action routine may save the manpage.
287 *      Arguments: w - any widget in the widget tree.
288 *                 event - NOT USED.
289 *                 params, num_params - the parameters passed to the action
290 *                                      routine, can be either Manpage or
291 *                                      Directory.
292 *      Returns: none.
293 */
294
295/*ARGSUSED*/
296void
297SaveFormattedPage(Widget w, XEvent * event, String * params,
298                  Cardinal * num_params)
299{
300    ManpageGlobals *man_globals;
301    char cmdbuf[BUFSIZ], error_buf[BUFSIZ];
302
303    if (*num_params != 1) {
304        XtAppWarning(XtWidgetToApplicationContext(w),
305                     "Xman - SaveFormattedPage: This action routine requires one argument.");
306        return;
307    }
308
309    man_globals = GetGlobals(w);
310
311/*
312 * If we are not active then take no action.
313 */
314
315    if (man_globals->tempfile[0] == '\0')
316        return;
317
318    switch (params[0][0]) {
319    case 'S':
320    case 's':
321
322        if (!man_globals->compress)
323            snprintf(cmdbuf, sizeof(cmdbuf), "%s %s %s", COPY,
324                     man_globals->tempfile, man_globals->save_file);
325        else if (man_globals->gzip)
326            snprintf(cmdbuf, sizeof(cmdbuf), "%s < %s > %s", GZIP_COMPRESS,
327                     man_globals->tempfile, man_globals->save_file);
328        else
329            snprintf(cmdbuf, sizeof(cmdbuf), "%s < %s > %s", COMPRESS,
330                     man_globals->tempfile, man_globals->save_file);
331
332        if (!system(cmdbuf)) {
333            /* make sure the formatted man page is fully accessible by the world */
334            if (chmod(man_globals->save_file, CHMOD_MODE) != 0) {
335                snprintf(error_buf, sizeof(error_buf),
336                         "Couldn't set permissions on formatted man page '%s'.\n",
337                         man_globals->save_file);
338                PopupWarning(man_globals, error_buf);
339            }
340        }
341        else {
342            snprintf(error_buf, sizeof(error_buf),
343                     "Error while executing the command '%s'.\n", cmdbuf);
344            PopupWarning(man_globals, error_buf);
345        }
346        break;
347    case 'C':
348    case 'c':
349        break;
350    default:
351        PopupWarning(man_globals, "Xman - SaveFormattedPage: "
352                     "Unknown argument must be either 'Save' or 'Cancel'.");
353        return;
354    }
355
356/*
357 * We do not need the filename anymore, and have the fd open.
358 * We will remove it.
359 */
360
361    remove(man_globals->tempfile);
362    XtPopdown(XtParent(XtParent(w)));
363}
364
365/*      Function Name: GotoPage
366 *      Description: The Action routine that switches over to the manpage
367 *                   or directory.
368 *      Arguments: w - any widget in the widget tree.
369 *                 event - NOT USED.
370 *                 params, num_params - the parameters passed to the action
371 *                                      routine, can be either Manpage or
372 *                                      Directory.
373 *      Returns: none.
374 */
375
376/*ARGSUSED*/
377void
378GotoPage(Widget w, XEvent * event, String * params, Cardinal * num_params)
379{
380    ManpageGlobals *man_globals;
381    Arg arglist[1];
382    Boolean sensitive;
383
384    if (*num_params != 1) {
385        XtAppWarning(XtWidgetToApplicationContext(w),
386                     "Xman - GotoPage: This action routine requires one argument.");
387        return;
388    }
389
390    man_globals = GetGlobals(w);
391
392    if (man_globals->both_shown) {
393        ChangeLabel(man_globals->label,
394                    man_globals->section_name[man_globals->current_directory]);
395        return;
396    }
397
398    switch (params[0][0]) {
399    case 'M':
400    case 'm':
401        XtSetArg(arglist[0], XtNsensitive, &sensitive);
402        XtGetValues(man_globals->manpage_entry, arglist, ONE);
403        if (sensitive) {
404            ChangeLabel(man_globals->label, man_globals->manpage_title);
405            XtUnmanageChild(man_globals->manpagewidgets.directory);
406            XtManageChild(man_globals->manpagewidgets.manpage);
407            man_globals->dir_shown = FALSE;
408        }
409        break;
410    case 'D':
411    case 'd':
412        ChangeLabel(man_globals->label,
413                    man_globals->section_name[man_globals->current_directory]);
414        XtUnmanageChild(man_globals->manpagewidgets.manpage);
415        XtManageChild(man_globals->manpagewidgets.directory);
416        man_globals->dir_shown = TRUE;
417        break;
418    default:
419        XtAppWarning(XtWidgetToApplicationContext(w),
420                     "Xman - GotoPage: Unknown argument must be "
421                     "either Manpage or Directory.");
422        return;
423    }
424}
425
426/*      Function Name: Quit.
427 *      Description: Quits Xman.
428 *      Arguments: w - any widget.
429 *                 event - NOT USED.
430 *                 params, num_params - NOT USED.
431 *      Returns: none.
432 */
433
434/*ARGSUSED*/
435void
436Quit(Widget w, XEvent * event, String * params, Cardinal * num_params)
437{
438    XtAppSetExitFlag(XtWidgetToApplicationContext(w));
439}
440
441/*      Function Name: PopupHelp
442 *      Description: Pops up xman's help.
443 *      Arguments: w - NOT USED.
444 *                 event - NOT USED.
445 *                 params, num_params - NOT USED.
446 *      Returns: none.
447 */
448
449/*ARGSUSED*/
450void
451PopupHelp(Widget w, XEvent * event, String * params, Cardinal * num_params)
452{
453    if (MakeHelpWidget())
454        XtPopup(help_widget, XtGrabNone);
455}
456
457/*      Function Name: PopupSearch
458 *      Description: Pops up this manual pages search widget.
459 *      Arguments: w - any widget in this manpage.
460 *                 event - NOT USED.
461 *                 params, num_params - NOT USED.
462 *      Returns: none.
463 */
464
465/*ARGSUSED*/
466void
467PopupSearch(Widget w, XEvent * event, String * params, Cardinal * num_params)
468{
469    ManpageGlobals *man_globals = GetGlobals(w);
470
471    if (man_globals->search_widget) {
472        if (!XtIsRealized(man_globals->search_widget)) {
473            XtRealizeWidget(man_globals->search_widget);
474            AddCursor(man_globals->search_widget,
475                      resources.cursors.search_entry);
476/*
477 * Set up ICCCM delete window.
478 */
479            XtOverrideTranslations(man_globals->search_widget,
480              XtParseTranslationTable("<Message>WM_PROTOCOLS: RemoveSearch()"));
481            XSetWMProtocols(XtDisplay(man_globals->search_widget),
482                            XtWindow(man_globals->search_widget),
483                            &wm_delete_window, 1);
484        }
485        Popup(man_globals->search_widget, XtGrabNone);
486    }
487}
488
489/*      Function Name: RemoveSearch
490 *      Description: Removes this search widget.
491 *      Arguments: w - search widget
492 *                 event - NOT USED.
493 *                 params, num_params - NOT USED.
494 *      Returns: none.
495 */
496
497/*ARGSUSED*/
498void
499RemoveSearch(Widget w, XEvent * event, String * params, Cardinal * num_params)
500{
501    XtPopdown(w);
502}
503
504/*      Function Name: CreateNewManpage
505 *      Description: Creates A New Manual Page.
506 *      Arguments: w - NOT USED.
507 *                 event - NOT USED.
508 *                 params, num_params - NOT USED.
509 *      Returns: none.
510 */
511
512/*ARGSUSED*/
513void
514CreateNewManpage(Widget w, XEvent * event, String * params,
515                 Cardinal * num_params)
516{
517    if (CreateManpage(NULL))
518        man_pages_shown++;
519}
520
521/*      Function Name: RemoveThisManpage
522 *      Description: Removes a manual page.
523 *      Arguments: w - any widget in the manpage.
524 *                 event - NOT USED.
525 *                 params, num_params - NOT USED.
526 *      Returns: none.
527 */
528
529/*ARGSUSED*/
530void
531RemoveThisManpage(Widget w, XEvent * event, String * params,
532                  Cardinal * num_params)
533{
534    ManpageGlobals *man_globals = GetGlobals(w);
535
536    if (man_globals->This_Manpage != help_widget) {
537        RemoveGlobals(man_globals->This_Manpage);
538        XtDestroyWidget(man_globals->This_Manpage);
539
540        XtFree((char *) man_globals->section_name);
541        XtFree((char *) man_globals->manpagewidgets.box);
542        XtFree((char *) man_globals);
543
544        if ((--man_pages_shown) == 0)
545            Quit(w, NULL, NULL, NULL);
546    }
547    else
548        XtPopdown(help_widget);
549}
550
551/*      Function Name: Search
552 *      Description: Actually performs a search.
553 *      Arguments: w - any widget in the manpage.
554 *                 event - NOT USED.
555 *                 params, num_params - NOT USED.
556 *      Returns: none.
557 */
558
559/*ARGSUSED*/
560void
561Search(Widget w, XEvent * event, String * params, Cardinal * num_params)
562{
563    ManpageGlobals *man_globals = GetGlobals(w);
564    FILE *file = NULL;
565
566    XtPopdown(XtParent(XtParent(w)));   /* popdown the search widget */
567
568    if ((*num_params < 1) || (*num_params > 2)) {
569        XtAppWarning(XtWidgetToApplicationContext(w),
570                     "Xman - Search: This action routine requires one or two arguments.");
571        return;
572    }
573
574    switch (params[0][0]) {
575    case 'a':
576    case 'A':
577        file = DoSearch(man_globals, APROPOS);
578        break;
579    case 'm':
580    case 'M':
581        file = DoSearch(man_globals, MANUAL);
582        break;
583    case 'c':
584    case 'C':
585        file = NULL;
586        break;
587    default:
588        XtAppWarning(XtWidgetToApplicationContext(w),
589                     "Xman - Search: First parameter unknown.");
590        file = NULL;
591        break;
592    }
593
594    if (*num_params == 2)
595        switch (params[1][0]) {
596        case 'O':
597        case 'o':
598            if (file != NULL) {
599                Widget w2;
600                char *label;
601
602                w2 = CreateManpage(file);
603                if (w2) {
604                    man_pages_shown++;
605
606                    /* Put title into new manual page. */
607
608                    label = man_globals->manpage_title;
609                    man_globals = GetGlobals(w2);
610                    strcpy(man_globals->manpage_title, label);
611                    ChangeLabel(man_globals->label, label);
612                }
613            }
614            break;
615        default:
616            XtAppWarning(XtWidgetToApplicationContext(w),
617                         "Xman - Search: Second parameter unknown.");
618            break;
619        }
620    else {
621        PutUpManpage(man_globals, file);
622    }
623    if ((file != NULL) && (file != man_globals->curr_file)) {
624        fclose(file);
625    }
626}
627
628
629/*      Function Name: ShowVersion
630 *      Description: Show current version.
631 *      Arguments: w - any widget in the manpage.
632 *                 event - NOT USED.
633 *                 params, num_params - NOT USED.
634 *      Returns: none.
635 */
636
637/*ARGSUSED*/
638void
639ShowVersion(Widget w, XEvent * event, String * params, Cardinal * num_params)
640{
641    ManpageGlobals *man_globals = GetGlobals(w);
642
643    ChangeLabel(man_globals->label, XMAN_VERSION);
644}
645