ScrollByL.c revision 1abf7346
1/* $XConsortium: ScrollByL.c,v 1.30 94/04/17 20:43:46 rws Exp $ */ 2/* 3 4Copyright (c) 1987, 1988 X Consortium 5 6Permission is hereby granted, free of charge, to any person obtaining 7a copy of this software and associated documentation files (the 8"Software"), to deal in the Software without restriction, including 9without limitation the rights to use, copy, modify, merge, publish, 10distribute, sublicense, and/or sell copies of the Software, and to 11permit persons to whom the Software is furnished to do so, subject to 12the following conditions: 13 14The above copyright notice and this permission notice shall be included 15in all copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 21OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of the X Consortium shall 26not be used in advertising or otherwise to promote the sale, use or 27other dealings in this Software without prior written authorization 28from the X Consortium. 29 30*/ 31/* $XFree86: xc/programs/xman/ScrollByL.c,v 1.6tsi Exp $ */ 32 33#if !defined(lint) && !defined(SABER) && 0 34 static char rcs_version[] = "$Athena: ScrollByL.c,v 4.5 88/12/19 13:46:04 kit Exp $"; 35#endif 36 37#include <stdio.h> 38#include <ctype.h> 39#include <X11/Xos.h> 40#include <stdlib.h> 41 42#include <X11/IntrinsicP.h> 43#include <sys/stat.h> /* depends on IntrinsicP.h */ 44#include <X11/StringDefs.h> 45 46#include <X11/Xaw/Scrollbar.h> 47#include <X11/Xmu/Misc.h> 48 49#include "ScrollByLP.h" 50 51/* Default Translation Table */ 52 53static char defaultTranslations[] = 54 "<Key>f: Page(Forward) \n\ 55 <Key>b: Page(Back) \n\ 56 <Key>1: Page(Line, 1) \n\ 57 <Key>2: Page(Line, 2) \n\ 58 <Key>3: Page(Line, 3) \n\ 59 <Key>4: Page(Line, 4) \n\ 60 <Key>\\ : Page(Forward)"; 61 62 63/**************************************************************** 64 * 65 * ScrollByLine Resources 66 * 67 ****************************************************************/ 68 69#define Offset(field) XtOffset(ScrollByLineWidget, scroll.field) 70#define CoreOffset(field) XtOffset(ScrollByLineWidget, core.field) 71 72static XtResource resources[] = { 73 {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension), 74 CoreOffset(width), XtRImmediate, (caddr_t) 500}, 75 {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension), 76 CoreOffset(height), XtRImmediate, (caddr_t) 700}, 77 78 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), 79 Offset(foreground), XtRString, "XtDefaultForeground"}, 80 {XtNforceVert, XtCBoolean, XtRBoolean, sizeof(Boolean), 81 Offset(force_vert), XtRImmediate, (caddr_t) FALSE}, 82 {XtNindent, XtCIndent, XtRDimension, sizeof(Dimension), 83 Offset(indent), XtRImmediate, (caddr_t) 15}, 84 {XtNuseRight, XtCBoolean, XtRBoolean, sizeof(Boolean), 85 Offset(use_right), XtRImmediate, (caddr_t) FALSE}, 86 {XtNmanualFontNormal, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 87 Offset(normal_font), XtRString, MANPAGE_NORMAL}, 88 {XtNmanualFontBold, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 89 Offset(bold_font), XtRString, MANPAGE_BOLD}, 90 {XtNmanualFontItalic, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 91 Offset(italic_font), XtRString, MANPAGE_ITALIC}, 92 {XtNmanualFontSymbol, XtCFont, XtRFontStruct, sizeof(XFontStruct *), 93 Offset(symbol_font), XtRString, MANPAGE_SYMBOL}, 94 {XtNfile, XtCFile, XtRFile, sizeof(FILE *), 95 Offset(file), XtRImmediate, (caddr_t) NULL}, 96 {XtNNumTotalLines, XtCNumTotalLines, XtRInt, sizeof(int), 97 Offset(lines), XtRImmediate, (caddr_t) 0}, 98 {XtNNumVisibleLines, XtCNumVisibleLines, XtRInt, sizeof(int), 99 Offset(num_visible_lines), XtRImmediate, (caddr_t) 0}, 100}; 101 102#undef Offset 103#undef CoreOffset 104 105/**************************************************************** 106 * 107 * Full class record constant 108 * 109 ****************************************************************/ 110 111static void CreateScrollbar(Widget w); 112static Boolean ScrollVerticalText(Widget w, int new_line, Boolean force_redisp); 113static void Layout(Widget w); 114static void LoadFile(Widget w); 115static void MoveAndClearText(Widget w, int old_y, int height, int new_y); 116static void PaintText(Widget w, int y_loc, int height); 117static void PrintText(Widget w, int start_line, int num_lines, int location); 118static void SetThumbHeight(Widget w); 119static void VerticalJump(Widget w, XtPointer junk, XtPointer percent_ptr); 120static void VerticalScroll(Widget w, XtPointer client_data, XtPointer call_data); 121 122/* semi - public functions. */ 123 124static void Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes); 125static void Initialize(Widget req, Widget new, ArgList args, Cardinal *num_args); 126static void Destroy(Widget w); 127static void Redisplay(Widget w, XEvent *event, Region region); 128static void Page(Widget w, XEvent * event, String * params, Cardinal *num_params); 129static Boolean SetValuesHook(Widget w, ArgList args, Cardinal *num_args); 130 131static XtActionsRec actions[] = { 132 { "Page", Page}, 133}; 134 135#define superclass (&simpleClassRec) 136#define SuperClass simpleWidgetClass 137 138ScrollByLineClassRec scrollByLineClassRec = { 139 { 140/* core_class fields */ 141 /* superclass */ (WidgetClass) superclass, 142 /* class_name */ "ScrollByLine", 143 /* widget_size */ sizeof(ScrollByLineRec), 144 /* class_initialize */ NULL, 145 /* class_part_init */ NULL, 146 /* class_inited */ FALSE, 147 /* initialize */ Initialize, 148 /* initialize_hook */ NULL, 149 /* realize */ Realize, 150 /* actions */ actions, 151 /* num_actions */ XtNumber(actions), 152 /* resources */ resources, 153 /* num_resources */ XtNumber(resources), 154 /* xrm_class */ NULLQUARK, 155 /* compress_motion */ TRUE, 156 /* compress_exposure */ FALSE, 157 /* compress_enterleave*/ TRUE, 158 /* visible_interest */ FALSE, 159 /* destroy */ Destroy, 160 /* resize */ Layout, 161 /* expose */ Redisplay, 162 /* set_values */ NULL, 163 /* set_values_hook */ SetValuesHook, 164 /* set_values_almost */ XtInheritSetValuesAlmost, 165 /* get_values_hook */ NULL, 166 /* accept_focus */ NULL, 167 /* version */ XtVersion, 168 /* callback_private */ NULL, 169 /* tm_table */ defaultTranslations, 170 /* query_geometry */ XtInheritQueryGeometry, 171 /* display_accelerator*/ XtInheritDisplayAccelerator, 172 /* extension */ NULL, 173 }, 174 { /* simple fields */ 175 /* change_sensitive */ XtInheritChangeSensitive 176 } 177}; 178 179WidgetClass scrollByLineWidgetClass = 180 (WidgetClass) &scrollByLineClassRec; 181 182 183/**************************************************************** 184 * 185 * Private Routines 186 * 187 ****************************************************************/ 188 189/* Function Name: Layout 190 * Description: This function lays out the scroll widget. 191 * Arguments: w - the scroll widget. 192 * key - a boolean: if true then resize the widget to the child 193 * if false the resize children to fit widget. 194 * Returns: TRUE if successful. 195 */ 196 197static void 198Layout(Widget w) 199{ 200 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 201 Dimension width, height; 202 Widget bar; 203 Position bar_bw; 204 205 CreateScrollbar(w); 206 207/* 208 * For now always show the bar. 209 */ 210 211 bar = sblw->scroll.bar; 212 height = sblw->core.height; 213 width = sblw->core.width; 214 bar_bw = bar->core.border_width; 215 216 /* Move child and v_bar to correct location. */ 217 218 if (sblw->scroll.use_right) { 219 XtMoveWidget(bar, width - (bar->core.width + bar_bw), - bar_bw); 220 sblw->scroll.offset = 0; 221 } 222 else { 223 XtMoveWidget(bar, - bar_bw, - bar_bw); 224 sblw->scroll.offset = bar->core.width + bar_bw; 225 } 226 227 /* resize the scrollbar to be the correct height or width. */ 228 229 XtResizeWidget(bar, bar->core.width, height, bar->core.border_width); 230 231 SetThumbHeight(w); 232 233 sblw->scroll.num_visible_lines = height / sblw->scroll.font_height + 1; 234} 235 236/* ARGSUSED */ 237static void 238GExpose(Widget w, XtPointer junk, XEvent *event, Boolean *cont) 239{ 240 241/* 242 * Graphics exposure events are not currently sent to exposure proc. 243 */ 244 245 if (event->type == GraphicsExpose) 246 Redisplay(w, event, NULL); 247 248} /* ChildExpose */ 249 250/* 251 * Repaint the widget's child Window Widget. 252 */ 253 254/* ARGSUSED */ 255static void 256Redisplay(Widget w, XEvent *event, Region region) 257{ 258 int top, height; /* the locations of the top and height 259 of the region that needs to be repainted. */ 260 261/* 262 * This routine tells the client which sections of the window to 263 * repaint in his callback function which does the actual repainting. 264 */ 265 266 if (event->type == Expose) { 267 top = event->xexpose.y; 268 height = event->xexpose.height; 269 } 270 else { 271 top = event->xgraphicsexpose.y; 272 height = event->xgraphicsexpose.height; 273 } 274 275 PaintText(w, top, height); 276} /* redisplay (expose) */ 277 278/* Function Name: PaintText 279 * Description: paints the text at the give location for a given height. 280 * Arguments: w - the sbl widget. 281 * y_loc, height - location and size of area to paint. 282 * Returns: none 283 */ 284 285static void 286PaintText(Widget w, int y_loc, int height) 287{ 288 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 289 int start_line, location; 290 291 start_line = y_loc / sblw->scroll.font_height + sblw->scroll.line_pointer; 292 293 if (start_line >= sblw->scroll.lines) 294 return; 295 296/* 297 * Only integer arithmetic makes this possible. 298 */ 299 300 location = y_loc / sblw->scroll.font_height * sblw->scroll.font_height; 301 302 PrintText(w, start_line, sblw->scroll.num_visible_lines, location); 303} 304 305/* Function Name: Page 306 * Description: This function pages the widget, by the amount it recieves 307 * from the translation Manager. 308 * Arguments: w - the ScrollByLineWidget. 309 * event - the event that caused this return. 310 * params - the parameters passed to it. 311 * num_params - the number of parameters. 312 * Returns: none. 313 */ 314 315/* ARGSUSED */ 316static void 317Page(Widget w, XEvent * event, String * params, Cardinal *num_params) 318{ 319 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 320 Widget bar = sblw->scroll.bar; 321 322 if (*num_params < 1) 323 return; 324/* 325 * If no scroll bar is visible then do not page, as the entire window is shown, 326 * of scrolling has been turned off. 327 */ 328 329 if (bar == (Widget) NULL) 330 return; 331 332 switch ( params[0][0] ) { 333 case 'f': 334 case 'F': 335 /* move one page forward */ 336 VerticalScroll(bar, NULL, (XtPointer)((long) bar->core.height)); 337 break; 338 case 'b': 339 case 'B': 340 /* move one page backward */ 341 VerticalScroll(bar, NULL, (XtPointer)(- (long) bar->core.height)); 342 break; 343 case 'L': 344 case 'l': 345 /* move one line forward */ 346 VerticalScroll(bar, NULL, 347 (XtPointer)((long) atoi(params[1]) * sblw->scroll.font_height)); 348 break; 349 default: 350 return; 351 } 352} 353 354/* Function Name: CreateScrollbar 355 * Description: createst the scrollbar for us. 356 * Arguments: w - sblw widget. 357 * Returns: none. 358 */ 359 360static void 361CreateScrollbar(Widget w) 362{ 363 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 364 Arg args[5]; 365 Cardinal num_args = 0; 366 367 if (sblw->scroll.bar != NULL) 368 return; 369 370 XtSetArg(args[num_args], XtNorientation, XtorientVertical); num_args++; 371 372 sblw->scroll.bar = XtCreateWidget("scrollbar", scrollbarWidgetClass, w, 373 args, num_args); 374 XtAddCallback(sblw->scroll.bar, XtNscrollProc, VerticalScroll, NULL); 375 XtAddCallback(sblw->scroll.bar, XtNjumpProc, VerticalJump, NULL); 376} 377 378/* Function Name: ScrollVerticalText 379 * Description: This accomplished the actual movement of the text. 380 * Arguments: w - the ScrollByLine Widget. 381 * new_line - the new location for the line pointer 382 * force_redisplay - should we force this window to get 383 * redisplayed? 384 * Returns: True if the thumb needs to be moved. 385 */ 386 387static Boolean 388ScrollVerticalText( 389Widget w, 390int new_line, 391Boolean force_redisp) 392{ 393 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 394 int num_lines = sblw->scroll.num_visible_lines; 395 int max_lines, old_line; 396 Boolean move_thumb = FALSE; 397 398/* 399 * Do not let the window extend out of bounds. 400 */ 401 402 if ( new_line < 0) { 403 new_line = 0; 404 move_thumb = TRUE; 405 } 406 else { 407 max_lines = sblw->scroll.lines - (int)w->core.height / sblw->scroll.font_height; 408 AssignMax(max_lines, 0); 409 410 if ( new_line > max_lines ) { 411 new_line = max_lines; 412 move_thumb = TRUE; 413 } 414 } 415 416/* 417 * If forced to redisplay then do a full redisplay and return. 418 */ 419 420 old_line = sblw->scroll.line_pointer; 421 sblw->scroll.line_pointer = new_line; /* Set current top of page. */ 422 423 if (force_redisp) 424 MoveAndClearText(w, 0, /* cause a full redisplay */ 0, 0); 425 426 if (new_line == old_line) 427 return(move_thumb); 428 429/* 430 * Scroll forward. 431 */ 432 433 else if (new_line < old_line) { 434 int lines_to_scroll = old_line - new_line; 435 MoveAndClearText(w, 0, num_lines - lines_to_scroll, lines_to_scroll); 436 } 437 438/* 439 * Scroll back. 440 */ 441 442 else { 443 int lines_to_scroll = new_line - old_line; 444 MoveAndClearText(w, lines_to_scroll, num_lines - lines_to_scroll, 0); 445 } 446 447 return(move_thumb); 448} 449 450/* Function Name: MoveAndClearText 451 * Description: Blits as much text as it can and clear the 452 * remaining area with generate exposures TRUE. 453 * Arguments: w - the sbl widget. 454 * old_y - the old y position. 455 * height - height of area to move. 456 * new_y - new y position. 457 * Returns: none 458 */ 459 460static void 461MoveAndClearText(Widget w, int old_y, int height, int new_y) 462{ 463 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 464 int from_left = sblw->scroll.indent + sblw->scroll.offset - 1; 465 int y_clear; 466 467 old_y *= sblw->scroll.font_height; 468 new_y *= sblw->scroll.font_height; 469 height *= sblw->scroll.font_height; 470 471/* 472 * If we are already at the right location then do nothing. 473 * (height == 0). 474 * 475 * If we have scrolled more than a screen height then just clear 476 * the window. 477 */ 478 479 if (height <= sblw->scroll.font_height) { /* avoid rounding errors. */ 480 XClearArea( XtDisplay(w), XtWindow(w), from_left, 0, 481 (unsigned int) 0, (unsigned int) 0, FALSE); 482 PaintText(w, 0, (int) sblw->core.height); 483 return; 484 } 485 486 if ((int)height + (int)old_y > (int)w->core.height) 487 height = w->core.height - old_y; 488 489 XCopyArea(XtDisplay(w), XtWindow(w), XtWindow(w), sblw->scroll.move_gc, 490 from_left, old_y, 491 (unsigned int) w->core.width - from_left, (unsigned int) height, 492 from_left, new_y); 493 494 if (old_y > new_y) 495 height -= sblw->scroll.font_height/2; /* clear 1/2 font of extra space, 496 to make sure we don't lose or 497 gain decenders. */ 498 else 499 height -= sblw->scroll.font_height; /* clear 1 font of extra space, 500 to make sure we don't overwrite 501 with a last line in buffer. */ 502 503 if (old_y > new_y) 504 y_clear = height; 505 else 506 y_clear = 0; 507 508/* 509 * We cannot use generate exposures, since that may allow another move and 510 * clear before the area get repainted, this would be bad. 511 */ 512 513 XClearArea( XtDisplay(w), XtWindow(w), from_left, y_clear, 514 (unsigned int) 0, (unsigned int) (w->core.height - height), 515 FALSE); 516 PaintText(w, (int) y_clear, (int) (w->core.height - height)); 517} 518 519/* Function Name: SetThumbHeight 520 * Description: Set the height of the thumb. 521 * Arguments: w - the sblw widget. 522 * Returns: none 523 */ 524 525static void 526SetThumbHeight(Widget w) 527{ 528 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 529 float shown; 530 531 if (sblw->scroll.bar == NULL) 532 return; 533 534 if (sblw->scroll.lines == 0) 535 shown = 1.0; 536 else 537 shown = (float) w->core.height / (float) (sblw->scroll.lines * 538 sblw->scroll.font_height); 539 if (shown > 1.0) 540 shown = 1.0; 541 542 XawScrollbarSetThumb( sblw->scroll.bar, (float) -1, shown ); 543} 544 545/* Function Name: SetThumb 546 * Description: Set the thumb location. 547 * Arguments: w - the sblw. 548 * Returns: none 549 */ 550 551static void 552SetThumb(Widget w) 553{ 554 float location; 555 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 556 557 if ( (sblw->scroll.lines == 0) || (sblw->scroll.bar == NULL) ) 558 return; 559 560 location = (float) sblw->scroll.line_pointer / (float) sblw->scroll.lines; 561 XawScrollbarSetThumb( sblw->scroll.bar, location , (float) -1 ); 562} 563 564/* Function Name: VerticalJump. 565 * Description: This function moves the test 566 * as the vertical scroll bar is moved. 567 * Arguments: w - the scrollbar widget. 568 * junk - not used. 569 * percent - the position of the scrollbar. 570 * Returns: none. 571 */ 572 573/* ARGSUSED */ 574static void 575VerticalJump(Widget w, XtPointer junk, XtPointer percent_ptr) 576{ 577 float percent = *((float *) percent_ptr); 578 int new_line; /* The new location for the line pointer. */ 579 ScrollByLineWidget sblw = (ScrollByLineWidget) XtParent(w); 580 581 new_line = (int) ((float) sblw->scroll.lines * percent); 582 if (ScrollVerticalText( (Widget) sblw, new_line, FALSE)) 583 SetThumb((Widget) sblw); 584} 585 586/* Function Name: VerticalScroll 587 * Description: This function moves the postition of the interior window 588 * as the vertical scroll bar is moved. 589 * Arguments: w - the scrollbar widget. 590 * junk - not used. 591 * pos - the position of the cursor. 592 * Returns: none. 593 */ 594 595/* ARGSUSED */ 596static void 597VerticalScroll(Widget w, XtPointer client_data, XtPointer call_data) 598{ 599 int pos = (int)(long) call_data; 600 int new_line; /* The new location for the line pointer. */ 601 ScrollByLineWidget sblw = (ScrollByLineWidget) XtParent(w); 602 603 new_line = sblw->scroll.line_pointer + (pos / sblw->scroll.font_height); 604 (void) ScrollVerticalText( (Widget) sblw, new_line, FALSE); 605 SetThumb( (Widget) sblw); 606} 607 608/* ARGSUSED */ 609static void 610Initialize(Widget req, Widget new, ArgList args, Cardinal *num_args) 611{ 612 ScrollByLineWidget sblw = (ScrollByLineWidget) new; 613 unsigned long figWidth; 614 Atom atomNum; 615 616 sblw->scroll.top_line = NULL; 617 sblw->scroll.line_pointer = 0; 618 LoadFile(new); 619 sblw->scroll.bar = (Widget) NULL; 620 621 sblw->scroll.font_height = (sblw->scroll.normal_font->max_bounds.ascent + 622 sblw->scroll.normal_font->max_bounds.descent); 623 624 atomNum = XInternAtom(XtDisplay(req), "FIGURE_WIDTH", False); 625 626 if (XGetFontProperty(sblw->scroll.normal_font, atomNum, &figWidth)) 627 sblw->scroll.h_width = figWidth; 628 else 629 sblw->scroll.h_width = XTextWidth(sblw->scroll.normal_font, "$", 1); 630} /* Initialize. */ 631 632/* Function Name: CreateGCs 633 * Description: Creates the graphics contexts that we need. 634 * Arguments: w - the sblw. 635 * Returns: none 636 */ 637 638static void 639CreateGCs(Widget w) 640{ 641 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 642 643 XtGCMask mask; 644 XGCValues values; 645 646 values.graphics_exposures = TRUE; 647 sblw->scroll.move_gc = XtGetGC(w, GCGraphicsExposures, &values); 648 649 mask = GCForeground | GCFont; 650 values.foreground = sblw->scroll.foreground; 651 652 values.font = sblw->scroll.normal_font->fid; 653 sblw->scroll.normal_gc = XtGetGC(w, mask, &values); 654 655 values.font = sblw->scroll.italic_font->fid; 656 sblw->scroll.italic_gc = XtGetGC(w, mask, &values); 657 658 values.font = sblw->scroll.bold_font->fid; 659 sblw->scroll.bold_gc = XtGetGC(w, mask, &values); 660 661 values.font = sblw->scroll.symbol_font->fid; 662 sblw->scroll.symbol_gc = XtGetGC(w, mask, &values); 663} 664 665/* Function Name: DestroyGCs 666 * Description: removes all gcs for this widget. 667 * Arguments: w - the widget. 668 * Returns: none 669 */ 670 671static void 672DestroyGCs(Widget w) 673{ 674 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 675 676 XtReleaseGC(w, sblw->scroll.normal_gc); 677 XtReleaseGC(w, sblw->scroll.bold_gc); 678 XtReleaseGC(w, sblw->scroll.italic_gc); 679 XtReleaseGC(w, sblw->scroll.move_gc); 680} 681 682static void 683Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes) 684{ 685 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 686 687 CreateScrollbar(w); 688 CreateGCs(w); 689 Layout(w); 690 (*SuperClass->core_class.realize) (w, valueMask, attributes); 691 XtRealizeWidget(sblw->scroll.bar); /* realize scrollbar. */ 692 XtMapWidget(sblw->scroll.bar); /* map scrollbar. */ 693 694 XtAddEventHandler(w, 0, TRUE, GExpose, NULL); /* Get Graphics Exposures */ 695} /* Realize */ 696 697/* Function Name: Destroy 698 * Description: Cleans up when we are killed. 699 * Arguments: w - the widget. 700 * Returns: none 701 */ 702 703static void 704Destroy(Widget w) 705{ 706 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 707 708 if (sblw->scroll.bar != NULL) 709 XtDestroyWidget(sblw->scroll.bar); /* Destroy scrollbar. */ 710 if (sblw->scroll.file != NULL) 711 fclose(sblw->scroll.file); 712 DestroyGCs(w); 713} 714 715/* 716 * 717 * Set Values 718 * 719 */ 720 721/* ARGSUSED */ 722static Boolean 723SetValuesHook(Widget w, ArgList args, Cardinal *num_args) 724{ 725 Boolean ret = TRUE; 726 Cardinal i; 727 728 for (i = 0; i < *num_args; i++) { 729 if (strcmp(XtNfile, args[i].name) == 0) { 730 LoadFile(w); 731 ret = TRUE; 732 } 733 } 734 735/* 736 * Changing anthing else will have strange effects, I don't need it so 737 * I didn't code it. 738 */ 739 740 return(ret); 741 742} /* Set Values */ 743 744/* 745 * A little design philosophy is probabally wise to include at this point. 746 * 747 * One of the things that I has hoped to achieve with xman is to make the 748 * viewing of manpage not only easy for the nieve user, but also fast for 749 * the experienced user, I wanted to be able to use it too. To achieve this 750 * I end up sacrificing a bit of start up time for the manual data structure. 751 * As well as, the overhead of reading the entire file before putting it up 752 * on the display. This is actually hardly even noticeable since most manual 753 * pages are shots, one to two pages - the notable exception is of course csh, 754 * but then that should be broken up anyway. 755 * 756 * METHOD: 757 * 758 * I allocate a chunk of space that is the size of the file, plus a null for 759 * debugging. Then copiesthe file into this chunk of memory. I then allocate 760 * an array of char*'s that are assigned to the beginning of each line. Yes, 761 * this means that I have to read the file twice, and could probabally be more 762 * clever about it, but once it is in memory the second read is damn fast. 763 * There are a few obsucrities here about guessing the number of lines and 764 * reallocing if I guess wrong, but other than that it is pretty straight 765 * forward. 766 * 767 * Chris Peterson 768 * 1/27/88 769 */ 770 771#define ADD_MORE_MEM 100 /* first guesses for allocations. */ 772#define CHAR_PER_LINE 40 773 774/* Function Name: LoadFile 775 * Description: Loads the current file into the internal memory. 776 * Arguments: w - the sblw. 777 * Returns: none 778 */ 779 780static void 781LoadFile(Widget w) 782{ 783 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 784 FILE * file = sblw->scroll.file; 785 786 char *page; 787 char **line_pointer,**top_line; /* pointers to beginnings of the 788 lines of the file. */ 789 int nlines; /* the current number of allocated lines. */ 790 struct stat fileinfo; /* file information from fstat. */ 791 792 if ( sblw->scroll.top_line != NULL) { 793 XtFree(*(sblw->scroll.top_line)); /* free characters. */ 794 XtFree((char *)(sblw->scroll.top_line)); /* free lines. */ 795 } 796 sblw->scroll.top_line = NULL; 797 798 if (file == NULL) 799 return; 800 801/* 802 * Get file size and allocate a chunk of memory for the file to be 803 * copied into. 804 */ 805 806 if (fstat(fileno(file), &fileinfo)) 807 XtAppError(XtWidgetToApplicationContext(w), 808 "SBLW LoadFile: Failure in fstat."); 809 810/* 811 * Allocate a space for a list of pointer to the beginning of each line. 812 */ 813 814 if ( (nlines = fileinfo.st_size/CHAR_PER_LINE) == 0) 815 return; 816 817 page = XtMalloc(fileinfo.st_size + 1); /* leave space for the NULL */ 818 top_line = line_pointer = (char**) XtMalloc( nlines * sizeof(char *) ); 819 820/* 821 * Copy the file into memory. 822 */ 823 824 fseek(file, 0L, SEEK_SET); 825 if (fread(page, sizeof(char), fileinfo.st_size, file) == 0) 826 XtAppError(XtWidgetToApplicationContext(w), 827 "SBLW LoadFile: Failure in fread."); 828 829 830/* put NULL at end of buffer. */ 831 832 *(page + fileinfo.st_size) = '\0'; 833 834/* 835 * Go through the file setting a line pointer to the character after each 836 * new line. If we run out of line pointer space then realloc that space 837 * with space for more lines. 838 */ 839 840 *line_pointer++ = page; /* first line points to first char in buffer.*/ 841 while (*page != '\0') { 842 843 if ( *page == '\n' ) { 844 *line_pointer++ = page + 1; 845 846 if (line_pointer >= top_line + nlines) { 847 top_line = (char **) XtRealloc( (char *)top_line, (nlines + 848 ADD_MORE_MEM) * sizeof(char *) ); 849 line_pointer = top_line + nlines; 850 nlines += ADD_MORE_MEM; 851 } 852 } 853 page++; 854 } 855 856/* 857 * Realloc the line pointer space to take only the minimum amount of memory 858 */ 859 860 sblw->scroll.lines = nlines = line_pointer - top_line - 1; 861 top_line = (char **) XtRealloc((char *)top_line, nlines * sizeof(char *)); 862 863/* 864 * Store the memory pointers 865 */ 866 867 sblw->scroll.top_line = top_line; 868 sblw->scroll.line_pointer = 0; 869 SetThumbHeight(w); 870 SetThumb(w); 871} 872 873#define NLINES 66 /* This is the number of lines to wait until 874 we boldify the line again, this allows 875 me to bold the first line of each page.*/ 876#define BACKSPACE 010 /* I doubt you would want to change this. */ 877 878#define NORMAL 0 879#define BOLD 1 880#define ITALIC 2 881#define SYMBOL 3 882#define WHICH(italic, bold) ((bold) ? BOLD : ((italic) ? ITALIC : NORMAL)) 883 /* Choose BOLD over ITALICS. If neither */ 884 /* is chosen, use NORMAL. */ 885 886static int DumpText(Widget w, int x_loc, int y_loc, char * buf, int len, int format); 887static Boolean Boldify(char *); 888 889/* Function Name: PrintText 890 * Description: This function actually prints the text. 891 * Arguments: w - the ScrollByLine widget. 892 * start_line - line to start printing, 893 * num_lines - the number of lines to print. 894 * location - the location to print the text. 895 * Returns: none. 896 */ 897 898/* ARGSUSED */ 899 900static void 901PrintText(Widget w, int start_line, int num_lines, int location) 902{ 903 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 904 905 register char *bufp, *c; /* Generic char pointers */ 906 int current_line; /* the number of the currrent line */ 907 char buf[BUFSIZ]; /* Misc. characters */ 908 Boolean italicflag = FALSE; /* Print text in italics?? */ 909 Boolean first = TRUE; /* First line of a manual page??? */ 910 int x_loc, y_loc; /* x and y location of text. */ 911 912/* 913 * For table hack 914 * To get columns to line up reasonably in most cases, make the 915 * assumption that they were lined up using lots of spaces, where 916 * lots is greater than two. Use a space width of 70% of the 917 * widest character in the font. 918 */ 919 int h_col, h_fix; 920 char * h_c; 921 922/* 923 * Nothing loaded, take no action. 924 */ 925 926 if (sblw->scroll.top_line == NULL || num_lines == 0) 927 return; 928 929 current_line = start_line; 930 931/* Set the first character to print at the first line. */ 932 933 c = *(sblw->scroll.top_line + start_line); 934 935/* 936 * Because XDrawString uses the bottom of the text as a position 937 * reference, add the height from the top of the font to the baseline 938 * to the ScollByLine position reference. 939 */ 940 941 y_loc = location + sblw->scroll.normal_font->max_bounds.ascent; 942 943/* 944 * Ok, here's the more than mildly heuristic man page formatter. 945 * We put chars into buf until either a font change or newline 946 * occurs (at which time we flush it to the screen.) 947 */ 948 949 950 bufp = buf; 951 x_loc = sblw->scroll.offset + sblw->scroll.indent; 952 h_col = 0; 953 954/* 955 * A fix: 956 * Assume that we are always starting to print on or before the 957 * first line of a page, and then prove it if we aren't. 958 */ 959 for (h_fix = 1; h_fix <= (start_line % NLINES); h_fix++) 960 if (**(sblw->scroll.top_line + start_line - h_fix) != '\n') 961 { 962 first = FALSE; 963 break; 964 } 965 966 while(TRUE) { 967 if (current_line % NLINES == 0) 968 first = TRUE; 969 970/* 971 * Lets make sure that we do not run out of space in our buffer, making full 972 * use of it is not critical since no window will be wide enough to display 973 * nearly BUFSIZ characters. 974 */ 975 976 if ( (bufp - buf) > (BUFSIZ - 10) ) 977 /* Toss everything until we find a <CR> or the end of the buffer. */ 978 while ( (*c != '\n') && (*c != '\0') ) c++; 979 980 switch(*c) { 981 982 case '\0': /* If we reach the end of the file then return */ 983 DumpText(w, x_loc, y_loc, buf, bufp - buf, WHICH(italicflag, first)); 984 return; 985 986 case '\n': 987 if (bufp != buf) { 988 Boolean bold; 989 *bufp = '\0'; /* for Boldify. */ 990 bold = ( (first) || ((x_loc == (sblw->scroll.offset + 991 sblw->scroll.indent)) && Boldify(buf)) ); 992 993 (void) DumpText(w, x_loc, y_loc, buf, bufp - buf, 994 WHICH(italicflag, bold)); 995 996 if (bold) 997 first = FALSE; 998 } 999 1000/* 1001 * If we have painted the required number of lines then we should now return. 1002 */ 1003 if (++current_line == start_line + num_lines ) 1004 return; 1005 1006 bufp = buf; 1007 italicflag = FALSE; 1008 x_loc = sblw->scroll.offset + sblw->scroll.indent; 1009 h_col = 0; 1010 y_loc += sblw->scroll.font_height; 1011 break; 1012 1013/* 1014 * This tab handling code is not very clever it moves the cursor over 1015 * to the next boundry of eight (8) spaces, as calculated in width just 1016 * before the printing loop started. 1017 */ 1018 1019 case '\t': /* TAB */ 1020 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, 1021 WHICH(italicflag, first)); 1022 h_col += bufp - buf; 1023 bufp = buf; 1024 italicflag = FALSE; 1025 x_loc = sblw->scroll.offset + sblw->scroll.indent; 1026 h_col = h_col + 8 - (h_col%8); 1027 x_loc += sblw->scroll.h_width * h_col; 1028 break; 1029 1030 case ' ': 1031 h_c = c + 1; 1032 while (*h_c == ' ') h_c++; 1033 1034 if (h_c - c < 4) 1035 { 1036 *bufp++ = *c; 1037 break; 1038 } 1039 1040 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, 1041 WHICH(italicflag, first)); 1042 h_col += bufp - buf; 1043 bufp = buf; 1044 italicflag = FALSE; 1045 1046 x_loc = sblw->scroll.offset + sblw->scroll.indent; 1047 h_col += (h_c - c); 1048 x_loc += sblw->scroll.h_width * h_col; 1049 c = h_c - 1; 1050 break; 1051 1052 case '\033': /* ignore esc sequences for now */ 1053 c++; /* should always be esc-x */ 1054 break; 1055 1056/* 1057 * Overstrike code supplied by: cs.utexas.edu!ut-emx!clyde@rutgers.edu 1058 * Since my manual pages do not have overstrike I couldn't test this. 1059 */ 1060 1061 case BACKSPACE: /* Backspacing for nroff bolding */ 1062 if (c[-1] == c[1] && c[1] != BACKSPACE) { /* overstriking one char */ 1063 if (bufp > buf) { 1064 bufp--; /* Zap 1st instance of char to bolden */ 1065 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, 1066 WHICH(italicflag, FALSE)); 1067 h_col += bufp - buf; 1068 } 1069 bufp = buf; 1070 *bufp++ = c[1]; 1071 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, BOLD); 1072 h_col += bufp - buf; 1073 bufp = buf; 1074 first = FALSE; 1075 1076 /* 1077 * Nroff bolding looks like: 1078 * C\bC\bC\bCN... 1079 * c points to ----^ ^ 1080 * it needs to point to --^ 1081 */ 1082 while (*c == BACKSPACE && c[-1] == c[1]) 1083 c += 2; 1084 c--; /* Back up to previous char */ 1085 } 1086 else { 1087 if ((c[-1] == 'o' && c[1] == '+') /* Nroff bullet */ 1088 || (c[-1] == '+' && c[1] == 'o')) { /* Nroff bullet */ 1089 /* If we run into a bullet, print out */ 1090 /* everything that's accumulated to this */ 1091 /* point, then the bullet, then resume. */ 1092 if (bufp>buf) { 1093 bufp--; 1094 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, 1095 WHICH(italicflag, FALSE)); 1096 h_col += bufp - buf; 1097 } 1098 bufp = buf; 1099 *bufp = (char)183; 1100 x_loc = DumpText(w, x_loc, y_loc, buf, 1, SYMBOL); 1101 h_col++; 1102 c++; 1103 } 1104 else { /* 'real' backspace - back up output ptr */ 1105 if (bufp>buf) 1106 bufp--; 1107 } 1108 } 1109 break; 1110 1111/* End of contributed overstrike code. */ 1112 1113 case '_': /* look for underlining [italicize] */ 1114 if(*(c + 1) == BACKSPACE) { 1115 if(!italicflag) { /* font change? */ 1116 if (bufp != buf) { 1117 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, NORMAL); 1118 h_col += bufp - buf; 1119 bufp = buf; 1120 } 1121 italicflag = TRUE; 1122 } 1123 c += 2; 1124 *bufp++ = *c; 1125 break; 1126 } 1127 /* else fall through to default, because this was a real underscore. */ 1128 1129 default: 1130 if(italicflag) { /* font change? */ 1131 if (bufp != buf) { 1132 x_loc = DumpText(w, x_loc, y_loc, buf, bufp - buf, 1133 WHICH(italicflag, FALSE)); 1134 h_col += bufp - buf; 1135 bufp = buf; 1136 } 1137 italicflag = FALSE; 1138 } 1139 *bufp++ = *c; 1140 break; 1141 } 1142 c++; 1143 } 1144} 1145 1146/* Function Name: DumpText 1147 * Description: Dumps text to the screen. 1148 * Arguments: w - the widget. 1149 * x_loc - to dump text at. 1150 * y_loc - the y_location to draw_text. 1151 * buf - buffer to dump. 1152 * italic, bold, boolean that tells us which gc to use. 1153 * Returns: x_location of the end of the text. 1154 */ 1155 1156static int 1157DumpText(Widget w, int x_loc, int y_loc, char * buf, int len, int format) 1158{ 1159 ScrollByLineWidget sblw = (ScrollByLineWidget) w; 1160 GC gc; 1161 XFontStruct * font; 1162 1163 switch(format) { 1164 1165 case ITALIC: 1166 gc = sblw->scroll.italic_gc; 1167 font = sblw->scroll.italic_font; 1168 break; 1169 1170 case BOLD: 1171 gc = sblw->scroll.bold_gc; 1172 font = sblw->scroll.bold_font; 1173 break; 1174 1175 case SYMBOL: 1176 gc = sblw->scroll.symbol_gc; 1177 font = sblw->scroll.symbol_font; 1178 break; 1179 1180 default: 1181 gc = sblw->scroll.normal_gc; 1182 font = sblw->scroll.normal_font; 1183 break; 1184 } 1185 1186 XDrawString(XtDisplay(w), XtWindow(w), gc, x_loc, y_loc, buf, len); 1187 return(x_loc + XTextWidth(font, buf, len)); 1188} 1189 1190/* Function Name: Boldify 1191 * Description: look for keyword. 1192 * Arguments: sp - string pointer. 1193 * Returns: 1 if keyword else 0. 1194 */ 1195 1196static Boolean 1197Boldify(register char *sp) 1198{ 1199 register char *sp_pointer; 1200 int length,count; 1201 1202/* 1203 * If there are not lower case letters in the line the assume it is a 1204 * keyword and boldify it in PrintManpage. 1205 */ 1206 1207 length = strlen(sp); 1208 for (sp_pointer = sp, count = 0; count < length; sp_pointer++,count++) 1209 if ( !isupper(*sp_pointer) && !isspace(*sp_pointer) ) 1210 return(0); 1211 return(1); 1212} 1213 1214#undef superclass 1215#undef SuperClass 1216