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, ¶ms, &num_params); 76 } 77 else if (w == man_globals->manpage_entry) { /* Put Up Man Page */ 78 params = "ManualPage"; 79 GotoPage(XtParent(w), NULL, ¶ms, &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, ¶ms, &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