1 /*
2 **
3 ** misc.c
4 **
5 ** Copyright (C) 1995, 1996, 1997 Johannes Plass
6 ** Copyright (C) 2004 Jose E. Marchesi
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with GNU gv; see the file COPYING. If not, write to
20 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 ** Boston, MA 02111-1307, USA.
22 **
23 ** Author: Johannes Plass (plass@thep.physik.uni-mainz.de)
24 ** Department of Physics
25 ** Johannes Gutenberg-University
26 ** Mainz, Germany
27 **
28 ** Jose E. Marchesi (jemarch@gnu.org)
29 ** GNU Project
30 **
31 */
32 /* for canonicalize_file_name: */
33 #define _GNU_SOURCE 1
34 #include "ac_config.h"
35
36 /*
37 * This code is derived from:
38 */
39
40 /*
41 * misc.c -- Everything that isn't a callback or action.
42 * Copyright (C) 1992 Timothy O. Theisen
43 * Author: Tim Theisen Systems Programmer
44 * Internet: tim@cs.wisc.edu Department of Computer Sciences
45 * UUCP: uwvax!tim University of Wisconsin-Madison
46 * Phone: (608)262-0438 1210 West Dayton Street
47 * FAX: (608)262-9777 Madison, WI 53706
48 *
49 * This program is free software; you can redistribute it and/or modify
50 * it under the terms of the GNU General Public License as published by
51 * the Free Software Foundation; either version 3 of the License, or
52 * (at your option) any later version.
53 *
54 * This program is distributed in the hope that it will be useful,
55 * but WITHOUT ANY WARRANTY; without even the implied warranty of
56 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57 * GNU General Public License for more details.
58 *
59 */
60
61 /*
62 #define MESSAGES
63 */
64 #include "message.h"
65
66 #include "config.h"
67
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <ctype.h>
71
72 #include "ac_config.h"
73 #include <inttypes.h>
74
75 #ifndef SEEK_SET
76 # define SEEK_SET 0
77 #endif
78
79 #include <gv_signal.h>
80 #ifdef SIGNALRETURNSINT
81 # define SIGVAL int
82 #else
83 # define SIGVAL void
84 #endif
85
86 #define GV_MAXLENGTH 512
87
88
89 # include <sys/types.h>
90 # include <sys/stat.h>
91 # include <unistd.h>
92
93
94 #include <math.h>
95
96 #include "paths.h"
97 #include INC_X11(Xos.h)
98 #include INC_X11(Xatom.h)
99 #include INC_X11(Intrinsic.h)
100 #include INC_X11(StringDefs.h)
101 #include INC_X11(Shell.h)
102 #include INC_XAW(Cardinals.h)
103 #include INC_XAW(SimpleMenu.h)
104 #include INC_XAW(SmeBSB.h)
105 #include INC_XAW(SmeLine.h)
106 #include INC_X11(IntrinsicP.h)
107 #include INC_XAW(TextP.h)
108 #include INC_XAW(Scrollbar.h)
109 #include INC_XMU(StdCmap.h)
110 #include "Aaa.h"
111 #include "Button.h"
112 #include "Clip.h"
113 #include "Frame.h"
114 #include "Ghostview.h"
115 #include "Vlist.h"
116
117
118 #include "types.h"
119 #include "actions.h"
120 #include "callbacks.h"
121 #include "file.h"
122 #include "ps.h"
123 #include "doc_misc.h"
124 #include "info.h"
125 #include "main_resources.h"
126 #include "main_globals.h"
127 #include "misc.h"
128 #include "note.h"
129 #include "error.h"
130 #include "save.h"
131 #include "widgets_misc.h"
132
133 #ifndef max
134 # define max(a, b) ((a) > (b) ? (a) : (b))
135 #endif
136 #ifndef min
137 # define min(a, b) ((a) < (b) ? (a) : (b))
138 #endif
139
140 #define UNMAP_CONTROL (1<<0)
141 #define UNMAP_PAGEVIEW (1<<1)
142 #define UNMAP_PAGE (1<<2)
143 #define MAP_CONTROL (1<<3)
144 #define MAP_PAGEVIEW (1<<4)
145 #define MAP_PAGE (1<<5)
146
147 static Boolean set_new_scale (void);
148 static Boolean set_new_orientation (int);
149 static Boolean set_new_pagemedia (int);
150 static void layout_ghostview (void);
151
152 /*############################################################*/
153 /* misc_drawEyeGuide */
154 /*############################################################*/
155
156 typedef struct
157 {
158 Widget w;
159 int drawn;
160 int x,y,width,height;
161 XtIntervalId timer;
162 } EyeGuideDataStruct,*EyeGuideData;
163
164 static void
misc_catchEyeGuideTimer(XtPointer client_data,XtIntervalId * idp _GL_UNUSED)165 misc_catchEyeGuideTimer(XtPointer client_data, XtIntervalId *idp _GL_UNUSED)
166 {
167 EyeGuideData egd = (EyeGuideData) client_data;
168
169 BEGINMESSAGE(misc_catchEyeGuideTimer)
170 if (egd->timer) misc_drawEyeGuide(egd->w,EYEGUIDE_REMOVE,0,0);
171 ENDMESSAGE(misc_catchEyeGuideTimer)
172 }
173
174 void
misc_drawEyeGuide(Widget w,int d,int x,int y)175 misc_drawEyeGuide(Widget w, int d, int x, int y)
176 {
177 unsigned long t = (unsigned long) 1000;
178 static EyeGuideData egd = NULL;
179
180 BEGINMESSAGE(misc_drawEyeGuide)
181 if (!app_res.scrolling_eye_guide) {
182 ENDMESSAGE(misc_drawEyeGuide)
183 return;
184 }
185 if (!egd) {
186 egd = (EyeGuideData) XtMalloc(sizeof(EyeGuideDataStruct));
187 egd->w = w;
188 egd->drawn = 0;
189 egd->timer = (XtIntervalId) 0;
190 }
191 if (d & EYEGUIDE_DRAW) {
192 if (egd->timer) XtRemoveTimeOut(egd->timer);
193 egd->timer = XtAppAddTimeOut(app_con,t,misc_catchEyeGuideTimer,(XtPointer)egd);
194 if (!egd->drawn) {
195 int x_1,y_1,x_2,y_2,nx,ny;
196 Widget clip = XtParent(XtParent(w));
197 INFMESSAGE(drawing)
198 nx = (int)w->core.x + (int) w->core.border_width;
199 ny = (int)w->core.y + (int) w->core.border_width;
200 if (-x>nx) x_1 = -x - nx; else x_1=0;
201 if (-y>ny) y_1 = -y - ny; else y_1=0;
202 x_2 = x_1 + (int)clip->core.width -1;
203 if (-x<nx) x_2 -= nx;
204 if (x_2 > w->core.width) x_2 = w->core.width;
205 y_2 = y_1 + (int)clip->core.height - 1;
206 if (-y<ny) y_2 -= ny;
207 if (y_2 > w->core.height) y_2 = w->core.height;
208 if (x_1==0) x_1 = -1;
209 if (y_1==0) y_1 = -1;
210 egd->x = x_1;
211 egd->y = y_1;
212 egd->width = x_2-x_1;
213 egd->height = y_2-y_1;
214 GhostviewDrawRectangle(w,egd->x,egd->y,egd->width,egd->height);
215 egd->drawn=1;
216 }
217 }
218 if (d & EYEGUIDE_REMOVE) {
219 if (egd->drawn) {
220 INFMESSAGE(removing)
221 GhostviewDrawRectangle(w,egd->x,egd->y,egd->width,egd->height);
222 }
223 }
224 if (d & (EYEGUIDE_REMOVE|EYEGUIDE_RESET)) {
225 if (egd->timer) XtRemoveTimeOut(egd->timer);
226 XtFree((char*)egd);
227 egd = NULL;
228 }
229 ENDMESSAGE(misc_drawEyeGuide)
230 }
231
232 /*############################################################*/
233 /* misc_savePagePosition */
234 /*############################################################*/
235
236 static int pagepos_x,pagepos_y,pagepos_saved=0;
237
238 void
misc_savePagePosition(void)239 misc_savePagePosition(void)
240 {
241 int x,y,psx,psy;
242 BEGINMESSAGE(misc_savePagePosition)
243 x = ((int)viewClip->core.width)/2 - viewControl->core.x - page->core.x;
244 y = ((int)viewClip->core.height)/2 - viewControl->core.y - page->core.y;
245 GhostviewCoordsXtoPS(page,x,y,&psx,&psy);
246 pagepos_x = psx;
247 pagepos_y = psy;
248 pagepos_saved = 1;
249 ENDMESSAGE(misc_savePagePosition)
250 }
251
252 /*############################################################*/
253 /* misc_restorePagePosition */
254 /*############################################################*/
255
256 int
misc_restorePagePosition(int * xP,int * yP)257 misc_restorePagePosition(int *xP, int *yP)
258 {
259 BEGINMESSAGE(misc_restorePagePosition)
260 if (pagepos_saved) {
261 *xP = pagepos_x;
262 *yP = pagepos_y;
263 ENDMESSAGE(misc_restorePagePosition)
264 return(1);
265 }
266 ENDMESSAGE(misc_restorePagePosition)
267 return(0);
268 }
269
270 /*############################################################*/
271 /* misc_restorePagePosition */
272 /*############################################################*/
273
274 void
misc_resetPagePosition(void)275 misc_resetPagePosition(void)
276 {
277 BEGINMESSAGE(misc_resetPagePosition)
278 pagepos_saved = 0;
279 ENDMESSAGE(misc_resetPagePosition)
280 }
281
282 /*############################################################*/
283 /* misc_setPageMarker */
284 /*############################################################*/
285
286 void
misc_setPageMarker(int entry,int kind,XEvent * event,Boolean check_toc)287 misc_setPageMarker(int entry, int kind, XEvent *event, Boolean check_toc)
288 /* kind: 0 = selected, 1 = highlighted , 2 = bring selected in sight*/
289 {
290 int firstvisible, lastvisible;
291 int maxvisible, numentries;
292 Boolean b = False;
293 INFMESSAGE(misc_setPageMarker)
294 if (toc_text && (entry >= 0)) {
295 if (kind == 0 && VlistSelected(newtoc) != entry)
296 VlistChangeSelected(newtoc,entry,XawVlistSet);
297 else if (kind == 1 && VlistHighlighted(newtoc) != entry)
298 VlistChangeHighlighted(newtoc,entry,XawVlistSet);
299 else if (kind == 2) {
300 entry=VlistSelected(newtoc);
301 if (entry<0) return;
302 }
303 firstvisible = VlistGetFirstVisible(newtoc);
304 maxvisible = VlistMaxEntriesVisible(newtoc, newtocClip->core.height);
305 numentries = VlistEntries(newtoc);
306 IIMESSAGE(entry,firstvisible)
307 IIMESSAGE(maxvisible,numentries)
308 if (numentries < maxvisible) {
309 /* check if everything fits */
310 /* this can happen if the window size is increased */
311 if (entry != 0) {
312 VlistSetFirstVisible(newtoc, 0);
313 b = True;
314 }
315 } else if (firstvisible > entry || (entry > 0 && firstvisible >= entry)) {
316 if (entry > 0)
317 VlistSetFirstVisible(newtoc, entry - 1);
318 else
319 VlistSetFirstVisible(newtoc, entry);
320 b = True;
321 } else {
322 /* sadly newtoc does not know it's height, so it cannot be told
323 * to made an item visible and we need to trick: */
324 lastvisible = VlistEntryOfPosition(newtoc, newtocClip->core.height);
325 IIMESSAGE(lastvisible,maxvisible)
326 if (entry > firstvisible && entry >= lastvisible) {
327 int firstentry;
328 firstentry = entry - (lastvisible - firstvisible - 1); /* make the entry second last */
329 if (firstentry > numentries - maxvisible) firstentry = numentries - maxvisible; /* avoid empty holes at the end */
330 if (firstentry < 0) firstentry = 0; /* keep in range */
331 VlistSetFirstVisible(newtoc, firstentry);
332 b = True;
333 }
334 }
335 /* if this happened by mouse, we have the information to get the
336 * highlight up to date again: */
337 if (b) {
338 if (event)
339 {
340 entry = VlistEntryOfPosition(newtoc, (int)event->xbutton.y);
341 if (entry != VlistHighlighted(newtoc) && check_toc)
342 VlistChangeHighlighted(newtoc,entry,XawVlistSet);
343 }
344 }
345 }
346 }
347
348 /*------------------------------------------------------------*/
349 /* misc_openFile */
350 /*------------------------------------------------------------*/
351
352 static String
misc_openFile(String name,FILE ** fpP)353 misc_openFile(String name, FILE **fpP)
354 {
355 char *str,*error=NULL;
356 FILE *fp=NULL;
357
358 BEGINMESSAGE(misc_openFile)
359
360 if (!name) name = "";
361 if (strcmp(name, "-")) {
362 INFSMESSAGE(trying to open,name)
363 if (file_fileIsNotUseful(name)) {
364 size_t l;
365 INFMESSAGE(file is not useful)
366 str="Invalid file: %s";
367 l = strlen(str) + strlen(name) + 1;
368 error = XtMalloc(l*sizeof(char));
369 sprintf(error,str,name);
370 }
371 else if ((fp = fopen(name, "r")) == NULL) {
372 INFMESSAGE(failed to open)
373 INFIMESSAGE(error number,errno)
374 error = open_fail_error(errno,GV_ERROR_OPEN_FAIL,name,0);
375 }
376 }
377 if (fpP) *fpP=fp;
378 else if (fp) fclose(fp);
379
380 ENDMESSAGE(misc_openFile)
381 return(error);
382 }
383
384 /*############################################################*/
385 /* misc_testFile */
386 /*############################################################*/
387
388 String
misc_testFile(String name)389 misc_testFile(String name)
390 {
391 char *error;
392 BEGINMESSAGE(misc_testFile)
393 error = misc_openFile(name,NULL);
394 ENDMESSAGE(misc_testFile)
395 return(error);
396 }
397
398 /*############################################################*/
399 /* misc_changeFile */
400 /*############################################################*/
401
misc_changeFile(String name)402 String misc_changeFile(String name)
403 {
404 FILE *fp=NULL;
405 String error=NULL;
406 char *p;
407 Boolean b = False;
408
409 BEGINMESSAGE(misc_changeFile)
410
411 if (!name) name="";
412 p = XtMalloc((strlen(name)+5)*sizeof(char));
413 strcpy(p,name);
414 if (strcmp(name,"-")) {
415 if (!b && file_fileIsNotUseful(p)) sprintf(p,"%s.ps",name); else b = True;
416 if (!b && file_fileIsNotUseful(p)) sprintf(p,"%s.pdf",name); else b = True;
417 if (!b) strcpy(p,name);
418 name = canonicalize_file_name(p);
419 if (name)
420 p = name;
421 }
422 name = p;
423 INFSMESSAGE(trying to open,name)
424 error = misc_openFile(name,&fp);
425 if (error) {
426 ENDMESSAGE(misc_changeFile)
427 XtFree(name);
428 return(error);
429 }
430
431 XtFree(gv_filename_old);
432 XtFree(gv_filename_raw);
433 gv_filename_old = gv_filename;
434 if (gv_filename_dsc) {
435 unlink(gv_filename_dsc);
436 XtFree(gv_filename_dsc);
437 gv_filename_dsc=NULL;
438 }
439 if (gv_filename_unc) {
440 unlink(gv_filename_unc);
441 XtFree(gv_filename_unc);
442 gv_filename_unc=NULL;
443 }
444 if (gv_psfile) fclose(gv_psfile);
445
446 gv_filename = XtNewString(name);
447 gv_filename_raw = XtNewString(name);
448 gv_filename_raw = file_getUsefulName(gv_filename_raw);
449 gv_psfile = fp;
450 if (strcmp(name,"-")) {
451 struct stat sbuf;
452 stat(gv_filename, &sbuf);
453 mtime = sbuf.st_mtime;
454 INFSMESSAGE(new,gv_filename)
455 }
456 XtFree(name);
457 ENDMESSAGE(misc_changeFile)
458 return(error);
459 }
460
461 /*############################################################*/
462 /* close_file */
463 /*############################################################*/
464
close_file(FILE * file,String name)465 String close_file(FILE *file, String name)
466 {
467 char *error=NULL;
468
469 BEGINMESSAGE(close_file)
470 if (file && fclose(file)!=0) {
471 char *error_close_fail = "Cannot close file %s\n";
472 size_t l;
473 l = strlen(error_close_fail) + strlen(name) + 1;
474 error = XtMalloc(l*sizeof(char));
475 sprintf(error,error_close_fail,name);
476 }
477 ENDMESSAGE(close_file)
478 return(error);
479 }
480
481 /*############################################################*/
482 /* check_file */
483 /* check if there is a new version of the file */
484 /* returns -1 if no filename or error in checking file */
485 /* 0 if no new version exists */
486 /* 1 if new version exists */
487 /*############################################################*/
488
489 int
check_file(int mode)490 check_file(int mode)
491 {
492 int status=0;
493 struct stat sbuf;
494 char *tmpname;
495 int r = -1;
496
497 BEGINMESSAGE(check_file)
498
499 if (!gv_filename) {
500 INFMESSAGE(file not useful)
501 ENDMESSAGE(check_file)
502 return(r);
503 }
504 if (!strcmp(gv_filename,"-")) {
505 INFMESSAGE(reading from stdin; nothing to update)
506 ENDMESSAGE(check_file)
507 return(0);
508 }
509
510
511 if (1) {
512
513 INFMESSAGE(checking file date)
514 status = stat(gv_filename, &sbuf);
515 if (!status && mtime != sbuf.st_mtime) {
516 INFMESSAGE(file has changed)
517 ENDMESSAGE(check_file)
518 return(1);
519 }
520 }
521
522 tmpname=gv_filename;
523 r=status;
524
525
526
527 if (r<0) {
528 char message[GV_MAXLENGTH];
529 if (r != -2) {
530 INFSMESSAGE(cannot access file:,tmpname)
531 sprintf(message,"Unable to access file '%s'\n",tmpname);
532 } else { /* privilege violation */
533 INFSMESSAGE(user not authorized to access file:,tmpname)
534 sprintf(message,"User is not authorized to access file '%s'\n",tmpname);
535 }
536 NotePopupShowMessage(message);
537 }
538 if (gv_filename!=tmpname) XtFree(tmpname);
539 ENDMESSAGE(check_file)
540 return(r);
541 }
542
543 /*------------------------------------------------------------*/
544 /* render_page */
545 /* Start rendering a new page */
546 /*------------------------------------------------------------*/
547
548 static void
render_page(Widget gvw)549 render_page(Widget gvw)
550 {
551 int i;
552
553 BEGINMESSAGE(render_page)
554
555 if (!gv_filename) { INFMESSAGE(no file) ENDMESSAGE(render_page) return; }
556
557 INFIMESSAGE(displaying page,current_page)
558
559 if (toc_text) {
560 Boolean processflag;
561 Boolean idleflag;
562 Boolean noinputflag;
563 INFMESSAGE(toc available)
564 GhostviewState(gvw,&processflag,&idleflag,&noinputflag);
565 # ifdef MESSAGES
566 if (processflag) {INFMESSAGE(interpreter running)}
567 else {INFMESSAGE(no interpreter running)}
568 if (idleflag) {INFMESSAGE(widget is idle)}
569 else {INFMESSAGE(widget is busy)}
570 if (noinputflag) {INFMESSAGE(interpreter has no input)}
571 else {INFMESSAGE(interpreter has input)}
572 # endif
573 /* Check first what the state of the ghostview widget is.
574 Some documents show additional lines between
575 the 'showpage' and the next '%%Page' comment.
576 In this case the 'noinputflag' is 'False' but the additional
577 lines are not really of significance (at least in no document I have
578 encountered).
579 So we ignore this flag and start from scratch only if the widget is
580 busy or if no interpreter is running.
581 Only if 'GV_RESTART_IF_CBUSY' is defined the noinputflag will be
582 considered.
583 */
584 #ifdef GV_RESTART_IF_BUSY /* ###jp### added 1.2.95 */
585 if (processflag && idleflag && noinputflag) {
586 #else
587 if (processflag && idleflag) {
588 #endif
589 INFMESSAGE(displaying next page)
590 GhostviewNextPage(gvw);
591 } else {
592 INFMESSAGE(starting new interpreter)
593 GhostviewEnableInterpreter(gvw);
594 GhostviewSendPS(gvw, gv_psfile, doc->beginprolog,
595 doc->lenprolog, False);
596 GhostviewSendPS(gvw, gv_psfile, doc->beginsetup,
597 doc->lensetup, False);
598 }
599 if (doc->pageorder == DESCEND) i = (doc->numpages - 1) - current_page;
600 else i = current_page;
601 GhostviewSendPS(gvw, gv_psfile, doc->pages[i].begin,doc->pages[i].len, False);
602 } else {
603 INFMESSAGE(no toc available)
604 if (!GhostviewIsInterpreterRunning(gvw)) {
605 INFMESSAGE(enabling interpreter for unstructured document)
606 GhostviewEnableInterpreter(gvw);
607 }
608 else if (GhostviewIsInterpreterReady(gvw)) {
609 INFMESSAGE(displaying page of unstructured document)
610 GhostviewNextPage(gvw);
611 }
612 else {
613 INFMESSAGE(interpreter running but not ready)
614 XBell(XtDisplay(gvw), 0);
615 }
616 }
617
618 if (gvw == page) {
619 if (toc_text) {
620 if (show_prevPage) {
621 if (current_page == 0) ButtonReset(w_prevPage,NULL,NULL,NULL);
622 XtSetSensitive(w_prevPage, current_page != 0);
623 }
624 if (show_nextPage) {
625 if (current_page == doc->numpages-1) ButtonReset(w_nextPage,NULL,NULL,NULL);
626 XtSetSensitive(w_nextPage, current_page != doc->numpages-1);
627 }
628 XtSetSensitive(prevEntry, current_page != 0);
629 XtSetSensitive(nextEntry, current_page != doc->numpages-1);
630 }
631 {
632 int n = doc ? doc->nummedia : 0;
633 Boolean b = (doc_mediaIsOk(doc,current_page,n) ? True : False);
634 XtSetSensitive(pagemediaEntry[n],b);
635 }
636 if (toc_text) {
637 INFMESSAGE(marking current_page as current)
638 misc_setPageMarker(current_page,0,NULL,True);
639 }
640 }
641
642 ENDMESSAGE(render_page)
643 }
644
645 /*############################################################*/
646 /* show_page */
647 /* This routine is probably the heart of GV */
648 /* It receives requests from the various callbacks and actions, */
649 /* maps them onto three flags (need_layout, need_setup, need_render) */
650 /* and calls the necessary subroutines */
651 /*############################################################*/
652
653 void
654 show_page(int number, XtPointer data1)
655 {
656 Bool need_layout = False;
657 Bool need_setup = False;
658 Bool need_render = False;
659 int request=number;
660 int ori_request=number;
661
662 BEGINMESSAGE(show_page)
663 INFIMESSAGE(received,request)
664
665 if ( /* check if file has changed */
666 gv_filename &&
667 (request != REQUEST_NEW_FILE) &&
668 (request != REQUEST_REOPEN) &&
669 (request != REQUEST_TOGGLE_RESIZE) &&
670 (request != REQUEST_SETUP)
671 ) {
672 int changed = check_file(CHECK_FILE_DATE);
673 if (changed==1) {
674 INFMESSAGE(file has changed; requesting new file)
675 request = REQUEST_NEW_FILE;
676 if (number < NO_CURRENT_PAGE) number = current_page;
677 } else if (changed == -1) {
678 INFMESSAGE(file is not accessible)
679 ENDMESSAGE(show_page)
680 return;
681 }
682 }
683
684 if (!toc_text && (request==REQUEST_REDISPLAY)) {
685 INFMESSAGE(request to redisplay non DSC file; changing to request for new file)
686 request=REQUEST_NEW_FILE;
687 }
688
689 if (request >= NO_CURRENT_PAGE) {
690 INFMESSAGE(request for new page)
691 if (GhostviewIsBusy(page)) {
692 INFMESSAGE(busy state)
693 if (toc_text) {
694 number = doc_putPageInRange(doc,number);
695 gv_pending_page_request=number;
696 INFIMESSAGE(will remember,gv_pending_page_request)
697 }
698 ENDMESSAGE(show_page)
699 return;
700 }
701 need_layout = need_setup =
702 set_new_orientation(number)|set_new_pagemedia(number);
703 if (need_layout && !app_res.auto_resize && gv_scales[gv_scale]->scale <= 0)
704 set_new_scale();
705 need_render = True;
706 } else if (request<NO_CURRENT_PAGE) {
707 INFIMESSAGE(analyzing,request)
708 switch (request) {
709 case REQUEST_TOGGLE_RESIZE:
710 INFMESSAGE(### request for change of resize behaviour)
711 number=current_page;
712 need_layout = True;
713 need_setup = False;
714 need_render = False;
715 break;
716 case REQUEST_REDISPLAY:
717 INFMESSAGE(### request for redisplay)
718 number=current_page;
719 need_layout = False;
720 need_setup = False;
721 need_render = True;
722 break;
723 case REQUEST_SETUP:
724 INFMESSAGE(### request for setup)
725 number=current_page;
726 need_layout = set_new_orientation(number)
727 |set_new_pagemedia(number)
728 |set_new_scale();
729 need_setup = True;
730 need_render = True;
731 break;
732 case REQUEST_NEW_SCALE:
733 INFMESSAGE(### request for new scale)
734 number=current_page;
735 need_layout = need_setup = need_render =
736 set_new_scale();
737 if (!need_layout) {ENDMESSAGE(show_page) return;}
738 break;
739 case REQUEST_NEW_PAGEMEDIA:
740 INFMESSAGE(### request for new pagemedia)
741 number=current_page;
742 need_layout = need_setup = need_render =
743 set_new_pagemedia(number);
744 if (!need_layout) {ENDMESSAGE(show_page) return;}
745 break;
746 case REQUEST_NEW_ORIENTATION:
747 INFMESSAGE(### request for new orientation)
748 number=current_page;
749 need_layout = need_setup = need_render =
750 set_new_orientation(number);
751 if (!need_layout) {ENDMESSAGE(show_page) return;}
752 break;
753 case REQUEST_OPTION_CHANGE:
754 {
755 INFMESSAGE(### request by options menu)
756 cb_popdownNotePopup((Widget)NULL,(XtPointer)NULL,NULL);
757 number=current_page;
758 number = doc_putPageInRange(doc,number);
759 need_setup = need_layout = need_render =
760 set_new_orientation(number) |
761 set_new_pagemedia(number) |
762 set_new_scale();
763 }
764 break;
765 case REQUEST_REOPEN:
766 case REQUEST_NEW_FILE:
767 {
768 String filename;
769 String error = NULL;
770 if (data1) filename = (String) data1;
771 else filename = gv_filename;
772 INFMESSAGE(### request to open or reopen file)
773 error = misc_changeFile(filename);
774 if (error) {
775 NotePopupShowMessage(error);
776 XtFree(error);
777 ENDMESSAGE(show_page)
778 return;
779 }
780 if (request==REQUEST_REOPEN) {
781 INFMESSAGE(request to reopen file)
782 number=current_page;
783 }
784 need_layout = setup_ghostview();
785 number = doc_putPageInRange(doc,number);
786 need_layout = need_layout
787 |set_new_orientation(number)
788 |set_new_pagemedia(number)
789 |set_new_scale();
790 need_setup = True;
791 need_render = True;
792 break;
793 }
794 default:
795 INFMESSAGE(### unknown request)
796 fprintf(stderr," %s: Unknown request in show_page\n",gv_name);
797 ENDMESSAGE(show_page)
798 return;
799 }
800 }
801
802 if (!gv_psfile && need_render) {
803 INFMESSAGE(no gv_psfile; forcing setup and layout)
804 need_setup=True;
805 need_layout=True;
806 }
807
808 # ifdef MESSAGES
809 if (need_layout) {INFMESSAGE(### need layout)} else {INFMESSAGE(### do not layout)}
810 if (need_setup) {INFMESSAGE(### need setup)} else {INFMESSAGE(### do not setup)}
811 if (need_render) {INFMESSAGE(### need render)} else {INFMESSAGE(### do not render)}
812 # endif
813
814 if (need_layout) layout_ghostview();
815
816 if (need_setup) GhostviewSetup(page);
817 if (!gv_filename) {
818 need_render=False;
819 INFMESSAGE(no filename; forcing no render)
820 }
821 if (toc_text) {
822 number = doc_putPageInRange(doc,number);
823 current_page = number;
824 }
825 if (need_render) {
826 render_page(page);
827 misc_drawEyeGuide(page,EYEGUIDE_RESET,0,0);
828 if (ori_request == REQUEST_NEW_FILE && !need_layout)
829 cb_positionPage(page,(XtPointer)NULL,(XtPointer)NULL);
830 }
831
832 gv_pending_page_request=NO_CURRENT_PAGE; /* eliminate any pending requests now */
833
834 ENDMESSAGE(show_page)
835 }
836
837 /*############################################################*/
838 /* setup_ghostview */
839 /* This includes:
840 * scanning the PostScript file,
841 * setting the title and date labels,
842 * building the pagemedia menu,
843 * building the toc (table of contents)
844 * sensitizing the appropriate menu buttons,
845 * popping down and erasing the infotext popup.
846 */
847 /*############################################################*/
848
849 static void misc_setSensitive(Widget w, Boolean s, Boolean b)
850 {
851 if (s) {
852 if (!b) ButtonReset(w,NULL,NULL,NULL);
853 XtSetSensitive(w,b);
854 }
855 }
856
857 static void misc_setBitmap(Widget w, Boolean s, Pixmap b)
858 {
859 Arg args[1];
860 if (s) {
861 if (b != None) {
862 XtSetArg(args[0],XtNbitmap,(toc_text ? b :app_res.mark_empty_bitmap));
863 XtSetValues(w,args,(Cardinal)1);
864 }
865 }
866 }
867
868 Boolean
869 setup_ghostview(void)
870 {
871 Arg args[10];
872 Cardinal n;
873 int oldtoc_entry_length;
874 int toc_length;
875 char *tocp;
876 Pixmap bitmap;
877 String label;
878
879 BEGINMESSAGE(setup_ghostview)
880 /* Reset to a known state. */
881 psfree(olddoc);
882 olddoc = doc;
883 doc = NULL;
884 current_page = NO_CURRENT_PAGE;
885 XtFree(toc_text);
886 oldtoc_entry_length = toc_entry_length;
887 toc_text = NULL;
888
889 INFMESSAGE(scanning file for structure information)
890 gv_filename_dsc = gv_filename_unc = NULL;
891 {
892 char* tmp = malloc(1512);
893 char* src = gv_gs_cmd_scan_pdf;
894 char* dest = tmp;
895 int spaceFound = 0;
896
897 if (strstr(gv_gs_cmd_scan_pdf, "-P") || !gv_gs_safer)
898 strcpy(tmp, gv_gs_cmd_scan_pdf);
899 else
900 {
901 while (*src)
902 {
903 int isSpace = *src == ' ';
904 *(dest++) = *(src++);
905 if (!spaceFound && isSpace)
906 {
907 strcpy(dest, "-P- -dSAFER -dDELAYSAFER ");
908 dest+=25;
909 spaceFound = 1;
910 }
911 }
912 *dest = 0;
913 }
914
915 doc_scanFile( &gv_psfile,&doc,
916 gv_filename,
917 gv_filename_raw,
918 &gv_filename_dsc,tmp,
919 &gv_filename_unc,gv_uncompress_command,
920 gv_scanstyle, gv_gs_safeDir);
921
922 free(tmp);
923 }
924 {
925 int m;
926 m = gv_pagemedia;
927 if (olddoc && olddoc->nummedia && m >= 0) {
928 if (m >= olddoc->nummedia) m = m - olddoc->nummedia;
929 else m = MEDIA_ID_INVALID;
930 }
931 if (doc && doc->nummedia && m >= 0) {
932 m = m + doc->nummedia;
933 }
934 if (m != gv_pagemedia) gv_pagemedia = gv_pagemedia_old = m;
935 }
936 if (gv_pagemedia == MEDIA_ID_INVALID) {
937 int m;
938 gv_pagemedia_old = MEDIA_ID_INVALID;
939 m = doc_convStringToPageMedia(doc,app_res.default_pagemedia);
940 if (m== MEDIA_ID_AUTO) {
941 gv_pagemedia_auto = 1;
942 gv_pagemedia_auto_old = 0;
943 gv_pagemedia = MEDIA_ID_INVALID;
944 } else {
945 gv_pagemedia_auto = 0;
946 gv_pagemedia_auto_old = 1;
947 gv_pagemedia = m;
948 }
949 }
950 cb_showTitle(toplevel,NULL,NULL);
951
952 if (show_date) {
953 if (doc && doc->date) {
954 label = doc->date;
955 bitmap = app_res.document_bitmap;
956 }
957 else {
958 if (gv_psfile) { label = ctime(&mtime); }
959 else { label = ""; }
960 bitmap = None;
961 }
962
963 n=0;
964 XtSetArg(args[n], XtNlabel, label); n++;
965 XtSetValues(datebutton, args, n);
966 if (datemenu) XtDestroyWidget(datemenu);
967 datemenu = build_label_menu(datebutton, "date", label, bitmap);
968 }
969
970 misc_buildPagemediaMenu();
971 {
972 int media_bbox = doc ? doc->nummedia : 0;
973 Boolean b = (doc_mediaIsOk(doc,current_page,media_bbox) ? True : False);
974 XtSetSensitive(pagemediaEntry[media_bbox], b);
975 }
976
977 /* Reset ghostscript and output messages popup */
978
979 if (!doc || !olddoc ||
980 strcmp(gv_filename_old, gv_filename) ||
981 olddoc->beginprolog != doc->beginprolog ||
982 olddoc->endprolog != doc->endprolog ||
983 olddoc->beginsetup != doc->beginsetup ||
984 olddoc->endsetup != doc->endsetup) {
985 INFMESSAGE(disabling interpreter)
986 GhostviewDisableInterpreter(page);
987 cb_popdownInfoPopup((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
988 cb_resetInfoPopup((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL);
989 }
990
991 /* Build table of contents */
992 if (doc && doc->structured) {
993 int maxlen = 0;
994 int i, j;
995
996 INFMESSAGE(toc available)
997 if (doc->labels_useful) {
998 for (i = 0; i < doc->numpages; i++)
999 maxlen = max(maxlen, (int)strlen(doc->pages[i].label));
1000 } else {
1001 double x;
1002 x = doc->numpages;
1003 maxlen = log10(x) + 1;
1004 }
1005 toc_entry_length = maxlen + 1;
1006 toc_length = doc->numpages * toc_entry_length - 1;
1007 toc_text = XtMalloc(toc_length + 2); /* include final NULL */
1008
1009 for (i = 0, tocp = toc_text; i < doc->numpages;
1010 i++, tocp += toc_entry_length) {
1011 if (doc->labels_useful) {
1012 if (doc->pageorder == DESCEND) {
1013 j = (doc->numpages - 1) - i;
1014 } else {
1015 j = i;
1016 }
1017 sprintf(tocp, "%*s\n", maxlen, doc->pages[j].label);
1018 } else {
1019 sprintf(tocp, "%*d\n", maxlen, i+1);
1020 }
1021 }
1022 toc_text[toc_length] = '\0';
1023 n=0;
1024 XtSetArg(args[n], XtNfilename, NULL); n++;
1025 XtSetValues(page, args, n);
1026 } else {
1027 String fn;
1028 fn = gv_filename_unc ? gv_filename_unc : gv_filename;
1029 INFMESSAGE(toc not available)
1030 toc_length = 0;
1031 toc_entry_length = 1;
1032 n=0;
1033 XtSetArg(args[n], XtNfilename, fn); n++;
1034 XtSetValues(page, args, n);
1035 }
1036
1037 {
1038 String s;
1039 int i=0;
1040 if (toc_text) {
1041 s = (char*)XtMalloc((doc->numpages+1)*sizeof(char));
1042 while (i < doc->numpages) {
1043 s[i] = 'p';
1044 i++;
1045 }
1046 s[i] = '\0';
1047 n=0;
1048 if ( (!gv_filename_old) ||
1049 (!olddoc) ||
1050 (strcmp(gv_filename_old, gv_filename)) ||
1051 (doc->numpages != olddoc->numpages) )
1052 XtSetArg(args[n], XtNvlist, s); n++;
1053 XtSetArg(args[n], XtNlabel, toc_text); n++;
1054 } else {
1055 s = NULL;
1056 XtSetArg(args[n], XtNvlist, ""); n++;
1057 XtSetArg(args[n], XtNlabel, ""); n++;
1058 }
1059 XtSetValues(newtoc, args, n);
1060 ClipWidgetSetCoordinates(newtocClip,0,0);
1061 INFMESSAGE(setup_ghostview calling XawScrollbarSetThumb)
1062 XawScrollbarSetThumb(newtocScroll,
1063 VlistScrollPosition(newtoc),
1064 VlistVisibleLength(newtoc,newtocClip->core.height));
1065 XtFree(s);
1066 }
1067
1068 misc_setBitmap(w_toggleCurrentPage , show_toggleCurrentPage , app_res.mark_current_bitmap);
1069 misc_setBitmap(w_toggleEvenPages , show_toggleEvenPages , app_res.mark_even_bitmap);
1070 misc_setBitmap(w_toggleOddPages , show_toggleOddPages , app_res.mark_odd_bitmap);
1071 misc_setBitmap(w_unmarkAllPages , show_unmarkAllPages , app_res.mark_unmark_bitmap);
1072
1073 misc_setSensitive(w_saveMarkedPages , show_saveMarkedPages , (toc_text != NULL));
1074 misc_setSensitive(w_saveAllPages , show_saveAllPages , (gv_psfile != NULL));
1075 misc_setSensitive(w_printMarkedPages , show_printMarkedPages , (toc_text != NULL));
1076 misc_setSensitive(w_printAllPages , show_printAllPages , (gv_psfile != NULL));
1077 misc_setSensitive(w_checkFile , show_checkFile , (gv_filename != NULL));
1078 misc_setSensitive(w_updateFile , show_updateFile , (gv_filename != NULL));
1079 misc_setSensitive(w_showThisPage , show_showThisPage , (gv_psfile != NULL || (gv_gs_arguments && *gv_gs_arguments)));
1080 misc_setSensitive(w_prevPage , show_prevPage , (toc_text != NULL));
1081 misc_setSensitive(w_nextPage , show_nextPage , (gv_filename != NULL));
1082 misc_setSensitive(w_toggleCurrentPage , show_toggleCurrentPage , (toc_text != NULL));
1083 misc_setSensitive(w_toggleEvenPages , show_toggleEvenPages , (toc_text != NULL));
1084 misc_setSensitive(w_toggleOddPages , show_toggleOddPages , (toc_text != NULL));
1085 misc_setSensitive(w_unmarkAllPages , show_unmarkAllPages , (toc_text != NULL));
1086
1087 XtSetSensitive(reopenEntry, (gv_psfile != NULL));
1088 XtSetSensitive(saveposEntry, (gv_psfile != NULL));
1089 XtSetSensitive(presentationEntry, (gv_psfile != NULL));
1090 XtSetSensitive(printAllEntry, (gv_psfile != NULL));
1091 XtSetSensitive(printMarkedEntry, (toc_text != NULL));
1092 XtSetSensitive(saveAllEntry, (gv_psfile != NULL));
1093 XtSetSensitive(saveMarkedEntry, (toc_text != NULL));
1094 XtSetSensitive(nextEntry, (gv_filename != NULL));
1095 XtSetSensitive(redisplayEntry, (gv_psfile != NULL || (gv_gs_arguments && *gv_gs_arguments)));
1096 XtSetSensitive(prevEntry, (toc_text != NULL));
1097 XtSetSensitive(currentEntry, (toc_text != NULL));
1098 XtSetSensitive(oddEntry, (toc_text != NULL));
1099 XtSetSensitive(evenEntry, (toc_text != NULL));
1100 XtSetSensitive(unmarkEntry, (toc_text != NULL));
1101
1102 ENDMESSAGE(setup_ghostview)
1103 return oldtoc_entry_length != toc_entry_length;
1104 }
1105
1106 Dimension view_width, view_height, view_border;
1107 Dimension control_width, control_height;
1108
1109 /*------------------------------------------------------------*/
1110 /* layout_ghostview */
1111 /*------------------------------------------------------------*/
1112
1113 static void
1114 layout_ghostview(void)
1115 {
1116 Arg args[10];
1117 Cardinal n;
1118 Dimension page_prefWidth, page_prefHeight;
1119 Dimension page_width, page_height;
1120 static Boolean firsttime=True;
1121 Boolean auto_resize;
1122
1123 BEGINMESSAGE(layout_ghostview)
1124
1125 if (!firsttime) {
1126 XtSetArg(args[0], XtNallowShellResize,&auto_resize);
1127 XtGetValues(toplevel, args,ONE);
1128 if (auto_resize != app_res.auto_resize) {
1129 INFMESSAGE(######## changing resize behaviour)
1130 # ifdef MESSAGES
1131 if (app_res.auto_resize) {INFMESSAGE(shell is allowed to resize)}
1132 else {INFMESSAGE(shell must not resize)}
1133 # endif
1134 XtSetArg(args[0], XtNallowShellResize,app_res.auto_resize);
1135 XtSetValues(toplevel, args,ONE);
1136 if (app_res.auto_resize==False) {
1137 ENDMESSAGE(layout_ghostview)
1138 return;
1139 }
1140 INFIMESSAGE(setting tocFrame height:,TOC3D_INITIAL_HEIGHT)
1141 XtSetArg(args[0], XtNheight,TOC3D_INITIAL_HEIGHT);
1142 XtSetValues(newtocFrame, args, ONE);
1143 }
1144 }
1145
1146 INFMESSAGE(#### retrieving dimensions)
1147 XtSetArg(args[0], XtNpreferredWidth, &page_prefWidth);
1148 XtSetArg(args[1], XtNpreferredHeight, &page_prefHeight);
1149 XtSetArg(args[2], XtNwidth, &page_width);
1150 XtSetArg(args[3], XtNheight, &page_height);
1151 XtGetValues(page, args, FOUR);
1152 INFIIMESSAGE(## preferred,page_prefWidth,page_prefHeight)
1153 INFIIMESSAGE(## actual,page_width,page_height)
1154
1155 if (page_prefWidth != page_width || page_prefHeight != page_height) {
1156 INFMESSAGE(#### setting ghostview widget size to its preferred size)
1157 XtSetArg(args[0], XtNwidth, page_prefWidth);
1158 XtSetArg(args[1], XtNheight, page_prefHeight);
1159 XtSetValues(page, args, TWO);
1160 }
1161 cb_positionPage(page,(XtPointer)NULL,(XtPointer)NULL);
1162
1163 if (firsttime) {
1164 n=0;
1165 XtSetArg(args[n], XtNminWidth, (Dimension)app_res.minimum_width); n++;
1166 XtSetArg(args[n], XtNminHeight,(Dimension)app_res.minimum_height);n++;
1167 if (app_res.auto_resize==False) {
1168 INFMESSAGE(switching to No-Resize mode)
1169 XtSetArg(args[n], XtNallowShellResize,app_res.auto_resize); n++;
1170 }
1171 XtSetValues(toplevel, args,n);
1172 firsttime=False;
1173 }
1174
1175 ENDMESSAGE(layout_ghostview)
1176 }
1177
1178 /*############################################################*/
1179 /* setup_layout_ghostview */
1180 /*############################################################*/
1181
1182 void
1183 setup_layout_ghostview(void)
1184 {
1185 BEGINMESSAGE(setup_layout_ghostview )
1186 ENDMESSAGE(setup_layout_ghostview)
1187 }
1188
1189 /*------------------------------------------------------------*/
1190 /* set_new_scale */
1191 /*------------------------------------------------------------*/
1192
1193 static Boolean
1194 set_new_scale(void)
1195 {
1196 int new_scale,new_scale_base;
1197 Boolean changed = False;
1198 Arg args[2];
1199 Cardinal n;
1200 Scale scale;
1201 float ascale;
1202
1203 BEGINMESSAGE(set_new_scale)
1204
1205 new_scale_base = gv_scale_base;
1206 if (!default_xdpi || !default_ydpi || new_scale_base != gv_scale_base_current) {
1207 scale = gv_scales[new_scale_base];
1208 ascale = scale->scale;
1209 if ((scale->is_base)&SCALE_IS_REAL_BASED) {
1210 default_xdpi = gv_real_xdpi;
1211 default_ydpi = gv_real_ydpi;
1212 } else {
1213 default_xdpi = gv_pixel_xdpi;
1214 default_ydpi = gv_pixel_ydpi;
1215 }
1216 default_xdpi *= ascale;
1217 default_ydpi *= ascale;
1218 INFIMESSAGE(old scale base,gv_scale_base_current);
1219 INFIMESSAGE(new scale base,new_scale_base);
1220 XtSetArg(args[0], XtNleftBitmap, None);
1221 if (gv_scale_base_current >=0) XtSetValues(scaleEntry[gv_scale_base_current],args, ONE);
1222 XtSetArg(args[0], XtNleftBitmap, app_res.selected_bitmap);
1223 XtSetValues(scaleEntry[new_scale_base],args, ONE);
1224 gv_scale_base_current = new_scale_base;
1225 changed=True;
1226 }
1227
1228 new_scale = gv_scale;
1229 if (changed || new_scale != gv_scale_current || gv_scales[new_scale]->scale <=0) {
1230 float xdpi, ydpi;
1231 GhostviewDisableInterpreter(page);
1232 scale = gv_scales[new_scale];
1233 ascale = scale->scale;
1234
1235 if (!ascale)
1236 {
1237 int dx = current_urx - current_llx + 1;
1238 int dy = current_ury - current_lly + 1;
1239 float ascale1;
1240 float ascale2;
1241
1242 if (gv_orientation == 2 || gv_orientation == 3)
1243 {
1244 int hlp = dx;
1245 dx = dy;
1246 dy = hlp;
1247 }
1248
1249 ascale1 = (float)viewClip->core.width / dx / 72.0 * default_xdpi;
1250 ascale2 = (float)viewClip->core.height / dy / 72.0 * default_ydpi;
1251
1252 ascale = ascale1 < ascale2 ? ascale1 : ascale2;
1253 }
1254 else if (fabs(ascale+1) <= 0.001)
1255 {
1256 int dx = current_urx - current_llx + 1;
1257 int dy = current_ury - current_lly + 1;
1258
1259 if (gv_orientation == 2 || gv_orientation == 3)
1260 {
1261 int hlp = dx;
1262 dx = dy;
1263 dy = hlp;
1264 }
1265
1266 ascale = (float)viewClip->core.width / dx / 72.0 * default_xdpi;
1267 }
1268 else if (fabs(ascale+3) <= 0.001)
1269 {
1270 int dx = current_urx - current_llx + 1;
1271 int dy = current_ury - current_lly + 1;
1272
1273 if (gv_orientation == 2 || gv_orientation == 3)
1274 {
1275 int hlp = dx;
1276 dx = dy;
1277 dy = hlp;
1278 }
1279
1280 ascale = (float)viewClip->core.height / dy / 72.0 * default_xdpi;
1281 }
1282 else if (fabs(ascale+2) <= 0.001)
1283 {
1284 ascale = gv_ascale;
1285 }
1286
1287 xdpi = default_xdpi / ascale;
1288 ydpi = default_ydpi / ascale;
1289 n=0;
1290 XtSetArg(args[n], XtNlabel, scale->name); n++;
1291 XtSetValues(scaleButton, args, n);
1292 n=0;
1293 XtSetArg(args[n], XtNlxdpi, (1000*xdpi)); n++;
1294 XtSetArg(args[n], XtNlydpi, (1000*ydpi)); n++;
1295 XtSetValues(page, args, n);
1296 n=0;
1297 XtSetArg(args[n], XtNleftBitmap, None); n++;
1298 if (gv_scale_current >=0) XtSetValues(scaleEntry[gv_scale_current],args, n);
1299 n=0;
1300 XtSetArg(args[n], XtNleftBitmap, app_res.selected_bitmap); n++;
1301 XtSetValues(scaleEntry[new_scale],args, n);
1302 gv_scale_current = new_scale;
1303 changed=True;
1304 }
1305 ENDMESSAGE(set_new_scale)
1306 return changed;
1307 }
1308
1309 /*------------------------------------------------------------*/
1310 /* set_orientationButton_label */
1311 /*------------------------------------------------------------*/
1312
1313 static void
1314 set_orientationButton_label(int orientation)
1315 {
1316 Arg args[1];
1317 Widget w = portraitEntry;
1318 String label;
1319
1320 BEGINMESSAGE(set_orientationButton_label)
1321 if (orientation == O_LANDSCAPE) w = landscapeEntry;
1322 else if (orientation == O_UPSIDEDOWN) w = upsidedownEntry;
1323 else if (orientation == O_SEASCAPE) w = seascapeEntry;
1324 XtSetArg(args[0], XtNlabel,&label);
1325 XtGetValues(w, args, ONE);
1326 XtSetArg(args[0], XtNlabel,label);
1327 XtSetValues(orientationButton, args, ONE);
1328 ENDMESSAGE(set_orientationButton_label)
1329 }
1330
1331 /*------------------------------------------------------------*/
1332 /* set_newBitmapIfChanged */
1333 /*------------------------------------------------------------*/
1334
1335 static void
1336 set_newBitmapIfChanged(Widget w, Pixmap new_bitmap)
1337 {
1338 Arg args[1];
1339 Pixmap old_bitmap;
1340
1341 BEGINMESSAGE(set_newBitmapIfChanged)
1342 if (!w) return; /* continuing will eventually cause a core dump */
1343 XtSetArg(args[0], XtNleftBitmap, &old_bitmap);
1344 XtGetValues(w, args, ONE);
1345 if (new_bitmap != old_bitmap) {
1346 XtSetArg(args[0], XtNleftBitmap, new_bitmap);
1347 XtSetValues(w, args, ONE);
1348 }
1349 ENDMESSAGE(set_newBitmapIfChanged)
1350 }
1351
1352 /*------------------------------------------------------------*/
1353 /* set_new_orientation */
1354 /*------------------------------------------------------------*/
1355
1356 static Boolean
1357 set_new_orientation(int pagenumber)
1358 {
1359 Boolean changed = False;
1360 int from_doc = 0;
1361 int no;
1362 Widget w;
1363 Pixmap bitmap;
1364 XtPageOrientation xto,xto_old;
1365
1366 BEGINMESSAGE(set_new_orientation)
1367
1368 no = O_UNSPECIFIED;
1369 if (no == O_UNSPECIFIED && gv_orientation != gv_orientation_old) {
1370 INFIMESSAGE(forcing new orientation to be,no)
1371 no = gv_orientation;
1372 INFMESSAGE(disabling automatic orientation)
1373 gv_orientation_auto = 0;
1374 }
1375 if (no == O_UNSPECIFIED && gv_orientation_auto) {
1376 int po;
1377 po = doc_preferredOrientationOfPage(doc,pagenumber);
1378 INFIMESSAGE(using orientation from doc, po)
1379 if (po != O_UNSPECIFIED) {
1380 INFIMESSAGE(using orientation from doc, po)
1381 no = po;
1382 from_doc = 1;
1383 }
1384 }
1385 if (no==O_UNSPECIFIED) no = gv_orientation_old;
1386 if (no!=O_PORTRAIT && no!=O_LANDSCAPE && no!=O_SEASCAPE && no!=O_UPSIDEDOWN)
1387 no = gv_fallback_orientation;
1388 gv_orientation = no;
1389
1390 xto = doc_convDocOrientToXtOrient(gv_orientation, gv_swap_landscape );
1391 xto_old = doc_convDocOrientToXtOrient(gv_orientation_old,gv_swap_landscape_old);
1392 IIMESSAGE(xto,xto_old)
1393
1394 if (xto != xto_old) {
1395 Arg args[1];
1396 if (gv_orientation_old == O_PORTRAIT) w = portraitEntry;
1397 else if (gv_orientation_old == O_LANDSCAPE) w = landscapeEntry;
1398 else if (gv_orientation_old == O_UPSIDEDOWN) w = upsidedownEntry;
1399 else w = seascapeEntry;
1400 widgets_setSelectedBitmap(w,0);
1401
1402 INFIMESSAGE(changing orientation for page to be,xto)
1403 GhostviewDisableInterpreter(page);
1404 XtSetArg(args[0], XtNorientation, xto);
1405 XtSetValues(page, args, ONE);
1406 changed = True;
1407 set_orientationButton_label(gv_orientation);
1408 }
1409
1410 if (from_doc) bitmap = app_res.document_bitmap;
1411 else bitmap = app_res.selected_bitmap;
1412 if ( no == O_PORTRAIT) w = portraitEntry;
1413 else if ( no == O_LANDSCAPE) w = landscapeEntry;
1414 else if ( no == O_UPSIDEDOWN) w = upsidedownEntry;
1415 else w = seascapeEntry;
1416 if (w)
1417 set_newBitmapIfChanged(w,bitmap);
1418
1419 if (gv_swap_landscape != gv_swap_landscape_old)
1420 widgets_setSelectedBitmap(swapEntry,gv_swap_landscape);
1421 if (gv_orientation_auto != gv_orientation_auto_old)
1422 widgets_setSelectedBitmap(autoOrientEntry,gv_orientation_auto);
1423
1424 gv_orientation_old = gv_orientation;
1425 gv_orientation_auto_old = gv_orientation_auto;
1426 gv_swap_landscape_old = gv_swap_landscape;
1427
1428 ENDMESSAGE(set_new_orientation)
1429 return(changed);
1430
1431 }
1432
1433 /*------------------------------------------------------------*/
1434 /* set_pagemediaButton */
1435 /*------------------------------------------------------------*/
1436
1437 static void
1438 set_pagemediaButton_label(int media_id)
1439 {
1440 String s = NULL;
1441 Arg args[1];
1442
1443 BEGINMESSAGE(set_pagemediaButton_label)
1444 if (media_id>=0) {
1445 Widget w;
1446 if (pagemediaEntry[media_id]) w = pagemediaEntry[media_id];
1447 else if (media_id <= 0) w = NULL;
1448 else w = pagemediaEntry[media_id-1];
1449 if (!w)
1450 goto out;
1451 XtSetArg(args[0], XtNlabel, &s);
1452 XtGetValues(w, args, ONE);
1453 }
1454 else s = "?";
1455 XtSetArg(args[0], XtNlabel, s);
1456 XtSetValues(pagemediaButton, args, ONE);
1457 out:
1458 ENDMESSAGE(set_pagemediaButton_label)
1459 return;
1460 }
1461
1462 /*------------------------------------------------------------*/
1463 /* set_new_pagemedia */
1464 /*------------------------------------------------------------*/
1465
1466 static Boolean
1467 set_new_pagemedia(int pagenumber)
1468 {
1469 int new_llx,new_lly,new_urx,new_ury;
1470 Boolean changed = False;
1471 int from_doc = 0;
1472 Arg args[4];
1473 Widget w = NULL;
1474 Pixmap bitmap;
1475 int num_doc_media;
1476 int nm;
1477 int media_bbox;
1478
1479 BEGINMESSAGE(set_new_pagemedia)
1480
1481 num_doc_media=0;
1482 if (doc) num_doc_media = doc->nummedia;
1483 media_bbox = num_doc_media;
1484
1485 nm = MEDIA_ID_INVALID;
1486 if (gv_pagemedia != gv_pagemedia_old) {
1487 if (doc_mediaIsOk(doc,pagenumber,gv_pagemedia)) {
1488 nm = gv_pagemedia;
1489 INFIMESSAGE(forcing new pagemedia to be,nm)
1490 INFMESSAGE(disabling automatic pagemedia)
1491 gv_pagemedia_auto = 0;
1492 }
1493 }
1494 else if (gv_pagemedia==media_bbox && !gv_pagemedia_auto) {
1495 if (doc_mediaIsOk(doc,pagenumber,gv_pagemedia))
1496 nm = gv_pagemedia;
1497 }
1498 else if (gv_pagemedia_auto) {
1499 nm = doc_preferredMediaOfPage(doc,pagenumber,&new_llx,&new_lly,&new_urx,&new_ury);
1500 if (nm != MEDIA_ID_INVALID) {
1501 INFIMESSAGE(using pagemedia preferred from doc, nm)
1502 from_doc = 1;
1503 }
1504 }
1505 if (nm==MEDIA_ID_INVALID && doc_mediaIsOk(doc,pagenumber,gv_pagemedia_old))
1506 nm = gv_pagemedia_old;
1507 if (nm==MEDIA_ID_INVALID) nm = gv_fallback_pagemedia;
1508 gv_pagemedia = nm;
1509
1510 /* If pagemedia changed, remove the old marker. */
1511 IIMESSAGE(gv_pagemedia,gv_pagemedia_old)
1512 if (gv_pagemedia != gv_pagemedia_old) {
1513 if (gv_pagemedia_old>=0) {
1514 if (pagemediaEntry[gv_pagemedia_old]) w = pagemediaEntry[gv_pagemedia_old];
1515 else w = pagemediaEntry[gv_pagemedia_old-1];
1516 widgets_setSelectedBitmap(w,0);
1517 }
1518 set_pagemediaButton_label(gv_pagemedia);
1519 }
1520
1521 if (gv_pagemedia >= 0) {
1522 if (from_doc) bitmap = app_res.document_bitmap;
1523 else bitmap = app_res.selected_bitmap;
1524 if (pagemediaEntry[gv_pagemedia]) w = pagemediaEntry[gv_pagemedia];
1525 else w = pagemediaEntry[gv_pagemedia-1];
1526 if (w)
1527 set_newBitmapIfChanged(w,bitmap);
1528 }
1529
1530 if (gv_pagemedia_auto != gv_pagemedia_auto_old) widgets_setSelectedBitmap(autoMediaEntry,gv_pagemedia_auto);
1531
1532 if (gv_pagemedia == num_doc_media) {
1533 doc_boundingBoxOfPage(doc,pagenumber,&new_llx,&new_lly,&new_urx,&new_ury);
1534 } else {
1535 new_llx = new_lly = 0;
1536 if (gv_pagemedia < num_doc_media) {
1537 new_urx = doc->media[gv_pagemedia].width-1;
1538 new_ury = doc->media[gv_pagemedia].height-1;
1539 } else {
1540 new_urx = gv_medias[gv_pagemedia-num_doc_media]->width-1;
1541 new_ury = gv_medias[gv_pagemedia-num_doc_media]->height-1;
1542 }
1543 }
1544
1545 /* If bounding box changed, setup for new size. */
1546 if ((new_llx != current_llx) || (new_lly != current_lly) ||
1547 (new_urx != current_urx) || (new_ury != current_ury)) {
1548 INFMESSAGE(bounding box changed)
1549 INFIIMESSAGE(lower left:,new_llx,new_lly)
1550 INFIIMESSAGE(upper right:,new_urx,new_ury)
1551 GhostviewDisableInterpreter(page);
1552 changed = True;
1553 current_llx = new_llx;
1554 current_lly = new_lly;
1555 current_urx = new_urx;
1556 current_ury = new_ury;
1557 XtSetArg(args[0], XtNllx, current_llx);
1558 XtSetArg(args[1], XtNlly, current_lly);
1559 XtSetArg(args[2], XtNurx, current_urx);
1560 XtSetArg(args[3], XtNury, current_ury);
1561 XtSetValues(page, args, FOUR);
1562 }
1563
1564 gv_pagemedia_old = gv_pagemedia;
1565 gv_pagemedia_auto_old = gv_pagemedia_auto;
1566
1567 ENDMESSAGE(set_new_pagemedia)
1568 return changed;
1569 }
1570
1571 /*------------------------------------------------------------*/
1572 /* same_document_media */
1573 /*------------------------------------------------------------*/
1574
1575 static Boolean
1576 same_document_media(void)
1577 {
1578 int i;
1579 Boolean same = True;
1580
1581 BEGINMESSAGE(same_document_media)
1582 if (olddoc == NULL && doc == NULL) same=True;
1583 else if (olddoc == NULL || doc == NULL) same=False;
1584 else if (olddoc->nummedia != doc->nummedia) same=False;
1585 else for (i = 0; i < doc->nummedia; i++) {
1586 if (strcmp(olddoc->media[i].name, doc->media[i].name)) {
1587 same=False;
1588 break;
1589 }
1590 }
1591 ENDMESSAGE(same_document_media)
1592 return(same);
1593 }
1594
1595 /*############################################################*/
1596 /* misc_buildPagemediaMenu */
1597 /*############################################################*/
1598
1599 void misc_buildPagemediaMenu(void)
1600 {
1601 Widget w;
1602 int i,num_doc_media;
1603
1604 BEGINMESSAGE(misc_buildPagemediaMenu)
1605 if (pagemediaMenu && same_document_media()) {
1606 ENDMESSAGE(misc_buildPagemediaMenu)
1607 return;
1608 }
1609 if (pagemediaMenu) XtDestroyWidget(pagemediaMenu);
1610 pagemediaMenu = XtCreatePopupShell("menu", simpleMenuWidgetClass,pagemediaButton, NULL,(Cardinal)0);
1611
1612 autoMediaEntry = XtCreateManagedWidget("automatic",smeBSBObjectClass,pagemediaMenu,NULL,(Cardinal)0);
1613 XtAddCallback(autoMediaEntry,XtNcallback,cb_setPagemedia,(XtPointer)MEDIA_ID_AUTO);
1614 widgets_setSelectedBitmap(autoMediaEntry,gv_pagemedia_auto);
1615 XtCreateManagedWidget("line",smeLineObjectClass,pagemediaMenu,NULL,(Cardinal)0);
1616
1617 /* Build the Page Media menu */
1618 /* the Page media menu has three parts.
1619 * - the automatic media detection entry.
1620 * - the document defined page medias
1621 * - the standard page medias
1622 */
1623 num_doc_media = 0;
1624 if (doc) num_doc_media = doc->nummedia;
1625
1626 i = gv_num_std_pagemedia + num_doc_media;
1627 XtFree((XtPointer)pagemediaEntry);
1628 pagemediaEntry = (Widget *) XtMalloc(i * sizeof(Widget));
1629
1630 if (doc && doc->nummedia) {
1631 for (i = 0; i < doc->nummedia; i++) {
1632 pagemediaEntry[i] = XtCreateManagedWidget(doc->media[i].name,smeBSBObjectClass, pagemediaMenu,NULL,(Cardinal)0);
1633 XtAddCallback(pagemediaEntry[i], XtNcallback,cb_setPagemedia, (XtPointer)(intptr_t)i);
1634 }
1635 w = XtCreateManagedWidget("line", smeLineObjectClass, pagemediaMenu,NULL,(Cardinal)0);
1636 }
1637
1638 for (i = 0; gv_medias[i]; i++) {
1639 pagemediaEntry[i+num_doc_media] = NULL;
1640 if (!(gv_medias[i]->used)) continue;
1641 pagemediaEntry[i+num_doc_media] =
1642 XtCreateManagedWidget(gv_medias[i]->name,smeBSBObjectClass, pagemediaMenu,NULL,(Cardinal)0);
1643 XtAddCallback(pagemediaEntry[i+num_doc_media], XtNcallback,cb_setPagemedia, (XtPointer)(intptr_t)(i+num_doc_media));
1644 }
1645 {
1646 Boolean b = (doc_mediaIsOk(doc,current_page,num_doc_media) ? True : False);
1647 XtSetSensitive(pagemediaEntry[num_doc_media],b);
1648 }
1649
1650 ENDMESSAGE(misc_buildPagemediaMenu)
1651 }
1652
1653 /*------------------------------------------------------------*/
1654 /* build_label_menu */
1655 /*------------------------------------------------------------*/
1656
1657 Widget
1658 build_label_menu(Widget parent, String name, String label, Pixmap bitmap)
1659 {
1660 Arg args[5];
1661 Cardinal n;
1662 Widget menu, entry;
1663
1664 BEGINMESSAGE(build_label_menu)
1665 n=0;
1666 menu = XtCreatePopupShell("menu", simpleMenuWidgetClass,parent, args, n);
1667 n=0;
1668 XtSetArg(args[n], XtNlabel, label); n++;
1669 if (bitmap) {
1670 XtSetArg(args[n], XtNleftMargin, 20); n++;
1671 XtSetArg(args[n], XtNleftBitmap, bitmap); n++;
1672 }
1673 XtSetArg(args[n], XtNjustify, XtJustifyCenter); n++;
1674 entry = XtCreateManagedWidget(name, smeBSBObjectClass,menu, args, n);
1675 ENDMESSAGE(build_label_menu)
1676 return menu;
1677 }
1678
1679 /*############################################################*/
1680 /* catch_Xerror */
1681 /* Catch X errors die gracefully if one occurs */
1682 /*############################################################*/
1683
1684 int
1685 catch_Xerror(Display *dpy, XErrorEvent *err)
1686 {
1687 BEGINMESSAGE(catch_Xerror)
1688 if (err->error_code == BadImplementation) {
1689 old_Xerror(dpy, err);
1690 return 0;
1691 }
1692 if (dying) return 0;
1693 dying = True;
1694 bomb = *err;
1695 XtDestroyWidget(toplevel);
1696 ENDMESSAGE(catch_Xerror)
1697 return 0;
1698 }
1699
1700 /*############################################################*/
1701 /* quote_filename */
1702 /* Quotes special characters in filenames */
1703 /* (taken from bash sources) */
1704 /*############################################################*/
1705
1706 char *
1707 quote_filename (char *string)
1708 {
1709 int c;
1710 char *result, *r, *s;
1711
1712 BEGINMESSAGE(quote_filename)
1713
1714 result = (char*) XtMalloc((2 * strlen (string) + 1) * sizeof(char));
1715
1716 for (r = result, s = string; s && (c = *s); s++)
1717 {
1718 switch (c)
1719 {
1720 case ' ': case '\t': case '\n': /* IFS white space */
1721 case '\'': case '"': case '\\': /* quoting chars */
1722 case '|': case '&': case ';': /* shell metacharacters */
1723 case '(': case ')': case '<': case '>':
1724 case '!': case '{': case '}': /* reserved words */
1725 case '*': case '[': case '?': case ']': /* globbing chars */
1726 case '^':
1727 case '$': case '`': /* expansion chars */
1728 *r++ = '\\';
1729 *r++ = c;
1730 break;
1731 case '#': /* comment char */
1732 if (s == string)
1733 *r++ = '\\';
1734 /* FALLTHROUGH */
1735 default:
1736 *r++ = c;
1737 break;
1738 }
1739 }
1740 *r = '\0';
1741
1742 ENDMESSAGE(quote_filename)
1743
1744 return (result);
1745 }
1746