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