Dvi.c revision 65912f00
1/* $XConsortium: Dvi.c,v 1.21 94/04/17 20:43:34 keith Exp $ */ 2/* $XdotOrg: $ */ 3/* 4 5Copyright (c) 1991 X Consortium 6 7Permission is hereby granted, free of charge, to any person obtaining 8a copy of this software and associated documentation files (the 9"Software"), to deal in the Software without restriction, including 10without limitation the rights to use, copy, modify, merge, publish, 11distribute, sublicense, and/or sell copies of the Software, and to 12permit persons to whom the Software is furnished to do so, subject to 13the following conditions: 14 15The above copyright notice and this permission notice shall be included 16in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 22OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24OTHER DEALINGS IN THE SOFTWARE. 25 26Except as contained in this notice, the name of the X Consortium shall 27not be used in advertising or otherwise to promote the sale, use or 28other dealings in this Software without prior written authorization 29from the X Consortium. 30 31*/ 32/* $XFree86: xc/programs/xditview/Dvi.c,v 1.3 2001/08/01 00:45:03 tsi Exp $ */ 33 34 35/* 36 * Dvi.c - Dvi display widget 37 */ 38 39#ifdef HAVE_CONFIG_H 40# include "config.h" 41#endif 42 43#define XtStrlen(s) ((s) ? strlen(s) : 0) 44 45 /* The following are defined for the reader's convenience. Any 46 Xt..Field macro in this code just refers to some field in 47 one of the substructures of the WidgetRec. */ 48 49#include <X11/IntrinsicP.h> 50#include <X11/StringDefs.h> 51#include <X11/Xmu/Converters.h> 52#include <stdio.h> 53#include <stdlib.h> 54#include <unistd.h> 55#include <ctype.h> 56#include "DviP.h" 57 58/**************************************************************** 59 * 60 * Full class record constant 61 * 62 ****************************************************************/ 63 64/* Private Data */ 65/* Note: default_font_map was too long a token for some machines... 66 * therefor it has been split in to and assigned to resources 67 * in the ClassInitialize routine. 68 */ 69static char default_font_map_1[] = "\ 70R -*-times-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\ 71I -*-times-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\ 72B -*-times-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\ 73F -*-times-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\ 74TR -*-times-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\ 75TI -*-times-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\ 76TB -*-times-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\ 77TF -*-times-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\ 78BI -*-times-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\ 79C -*-courier-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\ 80CO -*-courier-medium-o-normal--*-*-*-*-*-*-iso8859-1\n\ 81CB -*-courier-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\ 82CF -*-courier-bold-o-normal--*-*-*-*-*-*-iso8859-1\n\ 83H -*-helvetica-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\ 84HO -*-helvetica-medium-o-normal--*-*-*-*-*-*-iso8859-1\n\ 85HB -*-helvetica-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\ 86HF -*-helvetica-bold-o-normal--*-*-*-*-*-*-iso8859-1\n\ 87"; 88static char default_font_map_2[] = "\ 89N -*-new century schoolbook-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\ 90NI -*-new century schoolbook-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\ 91NB -*-new century schoolbook-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\ 92NF -*-new century schoolbook-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\ 93A -*-charter-medium-r-normal--*-*-*-*-*-*-iso8859-1\n\ 94AI -*-charter-medium-i-normal--*-*-*-*-*-*-iso8859-1\n\ 95AB -*-charter-bold-r-normal--*-*-*-*-*-*-iso8859-1\n\ 96AF -*-charter-bold-i-normal--*-*-*-*-*-*-iso8859-1\n\ 97S -*-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific\n\ 98S2 -*-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific\n\ 99"; 100 101#define offset(field) XtOffsetOf(DviRec, field) 102 103static XtResource resources[] = { 104 {XtNfontMap, XtCFontMap, XtRString, sizeof (char *), 105 offset(dvi.font_map_string), XtRString, NULL /* set in code */}, 106 {XtNforeground, XtCForeground, XtRPixel, sizeof (unsigned long), 107 offset(dvi.foreground), XtRString, XtDefaultForeground}, 108 {XtNpageNumber, XtCPageNumber, XtRInt, sizeof (int), 109 offset(dvi.requested_page), XtRImmediate, (XtPointer) 1}, 110 {XtNlastPageNumber, XtCLastPageNumber, XtRInt, sizeof (int), 111 offset (dvi.last_page), XtRImmediate, (XtPointer) 0}, 112 {XtNfile, XtCFile, XtRFile, sizeof (FILE *), 113 offset (dvi.file), XtRFile, (char *) 0}, 114 {XtNseek, XtCSeek, XtRBoolean, sizeof (Boolean), 115 offset(dvi.seek), XtRImmediate, (XtPointer) False}, 116 {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *), 117 offset(dvi.default_font), XtRString, XtDefaultFont}, 118 {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int), 119 offset(dvi.backing_store), XtRString, "default"}, 120 {XtNnoPolyText, XtCNoPolyText, XtRBoolean, sizeof (Boolean), 121 offset(dvi.noPolyText), XtRImmediate, (XtPointer) False}, 122 {XtNscreenResolution, XtCScreenResolution, XtRInt, sizeof (int), 123 offset(dvi.screen_resolution), XtRImmediate, (XtPointer) 75}, 124 {XtNpageWidth, XtCPageWidth, XtRFloat, sizeof (float), 125 offset(dvi.page_width), XtRString, "8.5"}, 126 {XtNpageHeight, XtCPageHeight, XtRFloat, sizeof (float), 127 offset(dvi.page_height), XtRString, "11"}, 128 {XtNsizeScale, XtCSizeScale, XtRInt, sizeof (int), 129 offset(dvi.size_scale_set), XtRImmediate, (XtPointer) 0}, 130}; 131 132#undef offset 133 134static void ClassInitialize(void); 135static void Initialize(Widget, Widget, ArgList, Cardinal *); 136static void Realize(Widget, XtValueMask *, XSetWindowAttributes *); 137static void Destroy(Widget); 138static void Redisplay(Widget, XEvent *, Region); 139static Boolean SetValues(Widget, Widget, Widget, ArgList , Cardinal *); 140static Boolean SetValuesHook(Widget, ArgList, Cardinal *); 141static XtGeometryResult QueryGeometry(Widget, 142 XtWidgetGeometry *, XtWidgetGeometry *); 143static void RequestDesiredSize(DviWidget); 144static void ShowDvi(DviWidget); 145static void CloseFile(DviWidget); 146static void OpenFile(DviWidget); 147 148#define SuperClass ((SimpleWidgetClass)&simpleClassRec) 149 150DviClassRec dviClassRec = { 151{ 152 (WidgetClass) SuperClass, /* superclass */ 153 "Dvi", /* class_name */ 154 sizeof(DviRec), /* size */ 155 ClassInitialize, /* class_initialize */ 156 NULL, /* class_part_initialize */ 157 FALSE, /* class_inited */ 158 Initialize, /* initialize */ 159 NULL, /* initialize_hook */ 160 Realize, /* realize */ 161 NULL, /* actions */ 162 0, /* num_actions */ 163 resources, /* resources */ 164 XtNumber(resources), /* resource_count */ 165 NULLQUARK, /* xrm_class */ 166 FALSE, /* compress_motion */ 167 XtExposeCompressMaximal, /* compress_exposure */ 168 TRUE, /* compress_enterleave */ 169 FALSE, /* visible_interest */ 170 Destroy, /* destroy */ 171 NULL, /* resize */ 172 Redisplay, /* expose */ 173 SetValues, /* set_values */ 174 SetValuesHook, /* set_values_hook */ 175 XtInheritSetValuesAlmost, /* set_values_almost */ 176 NULL, /* get_values_hook */ 177 NULL, /* accept_focus */ 178 XtVersion, /* version */ 179 NULL, /* callback_private */ 180 NULL, /* tm_table */ 181 QueryGeometry, /* query_geometry */ 182 XtInheritDisplayAccelerator, /* display_accelerator */ 183 NULL, /* extension */ 184}, /* CoreClass fields initialization */ 185{ 186 XtInheritChangeSensitive /* change_sensitive */ 187}, /* SimpleClass fields initialization */ 188{ 189 0, /* field not used */ 190}, /* DviClass fields initialization */ 191}; 192 193WidgetClass dviWidgetClass = (WidgetClass) &dviClassRec; 194 195static void 196ClassInitialize (void) 197{ 198 int len1 = strlen(default_font_map_1); 199 int len2 = strlen(default_font_map_2); 200 char *dfm = XtMalloc(len1 + len2 + 1); 201 char *ptr = dfm; 202 strcpy(ptr, default_font_map_1); ptr += len1; 203 strcpy(ptr, default_font_map_2); 204 resources[0].default_addr = dfm; 205 206 XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore, 207 NULL, 0 ); 208} 209 210/**************************************************************** 211 * 212 * Private Procedures 213 * 214 ****************************************************************/ 215 216/* ARGSUSED */ 217static void 218Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args) 219{ 220 DviWidget dw = (DviWidget) new; 221 222 dw->dvi.tmpFile = NULL; 223 dw->dvi.readingTmp = 0; 224 dw->dvi.ungot = 0; 225 dw->dvi.normal_GC = NULL; 226 dw->dvi.file_map = NULL; 227 dw->dvi.fonts = NULL; 228 dw->dvi.font_map = NULL; 229 dw->dvi.current_page = 0; 230 dw->dvi.font_size = 0; 231 dw->dvi.font_number = 0; 232 dw->dvi.device_resolution = 0; 233 dw->dvi.line_width = 0; 234 dw->dvi.line_style = 0; 235 dw->dvi.font = NULL; 236 dw->dvi.display_enable = 0; 237 dw->dvi.scale = 0.0; 238 dw->dvi.state = NULL; 239 dw->dvi.cache.index = 0; 240 dw->dvi.cache.font = NULL; 241 dw->dvi.size_scale = 0; 242 dw->dvi.size_scale_set = 0; 243 RequestDesiredSize (dw); 244} 245 246static void 247Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs) 248{ 249 DviWidget dw = (DviWidget) w; 250 XGCValues values; 251 252 if (dw->dvi.backing_store != Always + WhenMapped + NotUseful) { 253 attrs->backing_store = dw->dvi.backing_store; 254 *valueMask |= CWBackingStore; 255 } 256 XtCreateWindow (w, (unsigned)InputOutput, (Visual *) CopyFromParent, 257 *valueMask, attrs); 258 values.foreground = dw->dvi.foreground; 259 dw->dvi.normal_GC = XCreateGC (XtDisplay (w), XtWindow (w), 260 GCForeground, &values); 261#ifdef USE_XFT 262 { 263 int scr; 264 Visual *visual; 265 Colormap cmap; 266 XRenderColor black; 267 268 scr = XScreenNumberOfScreen (dw->core.screen); 269 visual = DefaultVisual (XtDisplay (w), scr); 270 cmap = DefaultColormap (XtDisplay (w), scr); 271 dw->dvi.draw = XftDrawCreate (XtDisplay (w), XtWindow (w), 272 visual, cmap); 273 274 black.red = black.green = black.blue = 0; 275 black.alpha = 0xffff; 276 XftColorAllocValue (XtDisplay (w), visual, cmap, 277 &black, &dw->dvi.black); 278 dw->dvi.default_font = XftFontOpenName (XtDisplay (w), 279 scr, 280 "serif-12"); 281 } 282#endif 283 if (dw->dvi.file) 284 OpenFile (dw); 285 ParseFontMap (dw); 286} 287 288static void 289Destroy(Widget w) 290{ 291 DviWidget dw = (DviWidget) w; 292 293 XFreeGC (XtDisplay (w), dw->dvi.normal_GC); 294 DestroyFontMap (dw->dvi.font_map); 295 DestroyFileMap (dw->dvi.file_map); 296} 297 298/* 299 * Repaint the widget window 300 */ 301 302/* ARGSUSED */ 303static void 304Redisplay(Widget w, XEvent *event, Region region) 305{ 306 DviWidget dw = (DviWidget) w; 307#ifndef USE_XFT 308 XRectangle extents; 309#endif 310 311#ifdef USE_XFT 312 XClearArea (XtDisplay (dw), 313 XtWindow (dw), 314 0, 0, 0, 0, False); 315 dw->dvi.extents.x1 = 0; 316 dw->dvi.extents.y1 = 0; 317 dw->dvi.extents.x2 = dw->core.width; 318 dw->dvi.extents.y2 = dw->core.height; 319#else 320 XClipBox (region, &extents); 321 dw->dvi.extents.x1 = extents.x; 322 dw->dvi.extents.y1 = extents.y; 323 dw->dvi.extents.x2 = extents.x + extents.width; 324 dw->dvi.extents.y2 = extents.y + extents.height; 325#endif 326 ShowDvi (dw); 327} 328 329static void 330RequestDesiredSize (DviWidget dw) 331{ 332 XtWidgetGeometry req, rep; 333 334 dw->dvi.desired_width = dw->dvi.page_width * 335 dw->dvi.screen_resolution; 336 dw->dvi.desired_height = dw->dvi.page_height * 337 dw->dvi.screen_resolution; 338 req.request_mode = CWWidth|CWHeight; 339 req.width = dw->dvi.desired_width; 340 req.height = dw->dvi.desired_height; 341 XtMakeGeometryRequest ((Widget) dw, &req, &rep); 342} 343 344/* 345 * Set specified arguments into widget 346 */ 347/* ARGSUSED */ 348static Boolean 349SetValues (Widget wcurrent, Widget wrequest, Widget wnew, 350 ArgList args, Cardinal *num_args) 351{ 352 DviWidget current = (DviWidget) wcurrent; 353 DviWidget request = (DviWidget) wrequest; 354 DviWidget new = (DviWidget) wnew; 355 Boolean redisplay = FALSE; 356 char *new_map; 357 int cur, req; 358 359 req = request->dvi.requested_page; 360 cur = current->dvi.requested_page; 361 if (cur != req) { 362 if (req < 1) 363 req = 1; 364 if (request->dvi.file) 365 { 366 if (current->dvi.last_page != 0 && 367 req > current->dvi.last_page) 368 req = current->dvi.last_page; 369 } 370 if (cur != req) 371 redisplay = TRUE; 372 new->dvi.requested_page = req; 373 } 374 375 if (current->dvi.font_map_string != request->dvi.font_map_string) { 376 new_map = XtMalloc (strlen (request->dvi.font_map_string) + 1); 377 if (new_map) { 378 redisplay = TRUE; 379 strcpy (new_map, request->dvi.font_map_string); 380 new->dvi.font_map_string = new_map; 381 if (current->dvi.font_map_string) 382 XtFree (current->dvi.font_map_string); 383 current->dvi.font_map_string = NULL; 384 ParseFontMap (new); 385 } 386 } 387 if (current->dvi.screen_resolution != request->dvi.screen_resolution) 388 { 389 ResetFonts (new); 390 new->dvi.line_width = -1; 391 } 392 if (request->dvi.device_resolution) 393 new->dvi.scale = ((double) request->dvi.screen_resolution) / 394 ((double) request->dvi.device_resolution); 395 if (current->dvi.page_width != request->dvi.page_width || 396 current->dvi.page_height != request->dvi.page_height || 397 current->dvi.screen_resolution != request->dvi.screen_resolution) 398 { 399 RequestDesiredSize (new); 400 redisplay = TRUE; 401 } 402 return redisplay; 403} 404 405/* 406 * use the set_values_hook entry to check when 407 * the file is set 408 */ 409 410static Boolean 411SetValuesHook (Widget widget, ArgList args, Cardinal *num_argsp) 412{ 413 DviWidget dw = (DviWidget) widget; 414 Cardinal i; 415 416 for (i = 0; i < *num_argsp; i++) { 417 if (!strcmp (args[i].name, XtNfile)) { 418 CloseFile (dw); 419 OpenFile (dw); 420 return TRUE; 421 } 422 } 423 return FALSE; 424} 425 426static void 427CloseFile (DviWidget dw) 428{ 429 if (dw->dvi.tmpFile) 430 fclose (dw->dvi.tmpFile); 431 ForgetPagePositions (dw); 432} 433 434static void 435OpenFile (DviWidget dw) 436{ 437 char tmpName[sizeof ("/tmp/dviXXXXXX")]; 438#ifdef HAS_MKSTEMP 439 int fd; 440#endif 441 442 dw->dvi.tmpFile = NULL; 443 if (!dw->dvi.seek) { 444 strcpy (tmpName, "/tmp/dviXXXXXX"); 445#ifndef HAS_MKSTEMP 446 mktemp (tmpName); 447 dw->dvi.tmpFile = fopen (tmpName, "w+"); 448#else 449 fd = mkstemp(tmpName); 450 dw->dvi.tmpFile = fdopen(fd, "w+"); 451#endif 452 unlink (tmpName); 453 } 454 if (dw->dvi.requested_page < 1) 455 dw->dvi.requested_page = 1; 456 dw->dvi.last_page = 0; 457} 458 459static XtGeometryResult 460QueryGeometry (Widget w, XtWidgetGeometry *request, 461 XtWidgetGeometry *geometry_return) 462{ 463 XtGeometryResult ret; 464 DviWidget dw = (DviWidget) w; 465 466 ret = XtGeometryYes; 467 if ((int)request->width < dw->dvi.desired_width 468 || (int)request->height < dw->dvi.desired_height) 469 ret = XtGeometryAlmost; 470 geometry_return->width = dw->dvi.desired_width; 471 geometry_return->height = dw->dvi.desired_height; 472 geometry_return->request_mode = CWWidth|CWHeight; 473 return ret; 474} 475 476void 477SetDeviceResolution (DviWidget dw, int resolution) 478{ 479 if (resolution != dw->dvi.device_resolution) { 480 dw->dvi.device_resolution = resolution; 481 dw->dvi.scale = ((double) dw->dvi.screen_resolution) / 482 ((double) resolution); 483 } 484} 485 486static void 487ShowDvi (DviWidget dw) 488{ 489 int i; 490 long file_position; 491 492 if (!dw->dvi.file) 493 return; 494 495 if (dw->dvi.requested_page < 1) 496 dw->dvi.requested_page = 1; 497 498 if (dw->dvi.last_page != 0 && dw->dvi.requested_page > dw->dvi.last_page) 499 dw->dvi.requested_page = dw->dvi.last_page; 500 501 file_position = SearchPagePosition (dw, dw->dvi.requested_page); 502 if (file_position != -1) { 503 FileSeek(dw, file_position); 504 dw->dvi.current_page = dw->dvi.requested_page; 505 } else { 506 for (i=dw->dvi.requested_page; i > 0; i--) { 507 file_position = SearchPagePosition (dw, i); 508 if (file_position != -1) 509 break; 510 } 511 if (file_position == -1) 512 file_position = 0; 513 FileSeek (dw, file_position); 514 515 dw->dvi.current_page = i; 516 517 dw->dvi.display_enable = 0; 518 while (dw->dvi.current_page != dw->dvi.requested_page) { 519 dw->dvi.current_page = ParseInput (dw); 520 /* 521 * at EOF, seek back to the begining of this page. 522 */ 523 if (feof (dw->dvi.file)) { 524 file_position = SearchPagePosition (dw, 525 dw->dvi.current_page); 526 if (file_position != -1) 527 FileSeek (dw, file_position); 528 break; 529 } 530 } 531 } 532 533 dw->dvi.display_enable = 1; 534 ParseInput (dw); 535 if (dw->dvi.last_page && dw->dvi.requested_page > dw->dvi.last_page) 536 dw->dvi.requested_page = dw->dvi.last_page; 537} 538