~lfaraone/ubuntu/lucid/xpdf/lp556483

« back to all changes in this revision

Viewing changes to .pc/xpdf-zoom-height.patch/xpdf/XPDFCore.cc

  • Committer: Luke Faraone
  • Date: 2010-04-06 13:38:25 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: luke@faraone.cc-20100406133825-bshu2k9svh5oje1f
* Merge from Debian unstable. (LP: #556483) Remaining changes: 
  - do-not-make-ps-arrays-bigger-than-64k-from-big-images-in-patterns.dpatch:
    pdftops produced wrong PostScript when a large image is in a
    pattern in the input file
  - Ubuntu maintainer field
[Michael Gilbert]
* Fix multiple security issues (closes: #551287, #575779).
  - CVE-2009-1188: Integer overflow in the JBIG2 decoding feature in the
    SplashBitmap::SplashBitmap function in SplashBitmap.cc.
  - CVE-2009-3603: Additional integer overflows in the
    SplashBitmap::SplashBitmap function.
  - CVE-2009-3604: Null pointer dereference in the Splash::drawImage
    function in Splash.cc.
  - CVE-2009-3606: Integer overflow in the PSOutputDev::doImageL1Sep
    function in PSOutputDev.cc.
  - CVE-2009-3608: Integer overflow in the ObjectStream::ObjectStream
    function in XRef.cc.
  - CVE-2009-3609: Integer overflow in the ImageStream::ImageStream
    function in Stream.cc.
* Bump standards version to 3.8.4 (no changes required).
* Use ${misc:Depends}.
* Adopt the package (closes: #535261, #527840).
[Rogério Brito]
* debian/copyright:
  + include versioned link to the GPL.
* debian/*
  + convert to source format "3.0 (quilt)".
* debian/{control,compat}:
  + bump compat to 5.
* debian/control:
  + remove dpatch build-dep and calls in debian/rules.
  + include Homepage field.
  + build-depend on unversioned automake.
  + build-depend on versioned lesstif.
  + wrap build-depends line to keep sanity.
  + change build-dependency on x-dev to x11proto-core-dev. (Closes: #515495).
  + remove debian revision from versioned build-deps.
  + update standards-version to 3.8.3, with no extra changes required.
* debian/rules:
  + remove commented lines.
  + fix the includes for lesstif. (See below).
  + remove deprecated dh_desktop helper.
  + don't ignore errors when calling "make -i distclean".
  + separate configuration from package compilation to keep things tidy.
  + don't remove recursively things that are only files.
* debian/patches:
  + rename 00list to series.
  + disable patches 40 and 41, lesstif is fixed. (Closes: #458763, #528807).
  + refresh enabled patches to avoid potential problems with buildds.
  + escape minus signs from manpages.
  + fix path to configuration files. Tks Andrew Price. (Closes: #424747).
  + flexibilize the print dialog. Tks Dmitry Oboukhov. (Closes: #408502).
  + implement "Fit to Height". Tks Josh Triplett. (Closes: #424178).
* debian/xpdf-common.postint:
  + don't use command with path in maintainer script.
* debian/watch:
  + create watch file.
* debian/xpdf.desktop:
  + remove obsolete indication of encoding.
  + remove custom category "PDFViewer".
* debian/xpdf-reader.menu:
  + update obsolete section Apps -> Applications.
* debian/xpdf-reader.dirs:
  + remove empty dir usr/lib/menu. Tks Nelson Oliveira. (Closes: #495150).
* avoid conflict with poppler-utils. Tks Luca Capello. (Closes: #558020).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//========================================================================
 
2
//
 
3
// XPDFCore.cc
 
4
//
 
5
// Copyright 2002-2003 Glyph & Cog, LLC
 
6
//
 
7
// Modified for Debian by Hamish Moffatt, 22 May 2002.
 
8
//
 
9
//========================================================================
 
10
 
 
11
#include <aconf.h>
 
12
 
 
13
#ifdef USE_GCC_PRAGMAS
 
14
#pragma implementation
 
15
#endif
 
16
 
 
17
#include <X11/keysym.h>
 
18
#include <X11/cursorfont.h>
 
19
#include <string.h>
 
20
#include "gmem.h"
 
21
#include "GString.h"
 
22
#include "GList.h"
 
23
#include "Error.h"
 
24
#include "GlobalParams.h"
 
25
#include "PDFDoc.h"
 
26
#include "Link.h"
 
27
#include "ErrorCodes.h"
 
28
#include "GfxState.h"
 
29
#include "CoreOutputDev.h"
 
30
#include "PSOutputDev.h"
 
31
#include "TextOutputDev.h"
 
32
#include "SplashBitmap.h"
 
33
#include "SplashPattern.h"
 
34
#include "XPDFApp.h"
 
35
#include "XPDFCore.h"
 
36
 
 
37
// these macro defns conflict with xpdf's Object class
 
38
#ifdef LESSTIF_VERSION
 
39
#undef XtDisplay
 
40
#undef XtScreen
 
41
#undef XtWindow
 
42
#undef XtParent
 
43
#undef XtIsRealized
 
44
#endif
 
45
 
 
46
//------------------------------------------------------------------------
 
47
 
 
48
// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
 
49
static inline Guchar div255(int x) {
 
50
  return (Guchar)((x + (x >> 8) + 0x80) >> 8);
 
51
}
 
52
 
 
53
//------------------------------------------------------------------------
 
54
 
 
55
GString *XPDFCore::currentSelection = NULL;
 
56
XPDFCore *XPDFCore::currentSelectionOwner = NULL;
 
57
Atom XPDFCore::targetsAtom;
 
58
 
 
59
//------------------------------------------------------------------------
 
60
// XPDFCoreTile
 
61
//------------------------------------------------------------------------
 
62
 
 
63
class XPDFCoreTile: public PDFCoreTile {
 
64
public:
 
65
  XPDFCoreTile(int xDestA, int yDestA);
 
66
  virtual ~XPDFCoreTile();
 
67
  XImage *image;
 
68
};
 
69
 
 
70
XPDFCoreTile::XPDFCoreTile(int xDestA, int yDestA):
 
71
  PDFCoreTile(xDestA, yDestA)
 
72
{
 
73
  image = NULL;
 
74
}
 
75
 
 
76
XPDFCoreTile::~XPDFCoreTile() {
 
77
  if (image) {
 
78
    gfree(image->data);
 
79
    image->data = NULL;
 
80
    XDestroyImage(image);
 
81
  }
 
82
}
 
83
 
 
84
//------------------------------------------------------------------------
 
85
// XPDFCore
 
86
//------------------------------------------------------------------------
 
87
 
 
88
XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA,
 
89
                   SplashColorPtr paperColorA, Gulong paperPixelA,
 
90
                   Gulong mattePixelA, GBool fullScreenA, GBool reverseVideoA,
 
91
                   GBool installCmap, int rgbCubeSizeA):
 
92
  PDFCore(splashModeRGB8, 4, reverseVideoA, paperColorA, !fullScreenA)
 
93
{
 
94
  GString *initialZoom;
 
95
 
 
96
  shell = shellA;
 
97
  parentWidget = parentWidgetA;
 
98
  display = XtDisplay(parentWidget);
 
99
  screenNum = XScreenNumberOfScreen(XtScreen(parentWidget));
 
100
  targetsAtom = XInternAtom(display, "TARGETS", False);
 
101
 
 
102
  paperPixel = paperPixelA;
 
103
  mattePixel = mattePixelA;
 
104
  fullScreen = fullScreenA;
 
105
 
 
106
  setupX(installCmap, rgbCubeSizeA);
 
107
 
 
108
  scrolledWin = NULL;
 
109
  hScrollBar = NULL;
 
110
  vScrollBar = NULL;
 
111
  drawAreaFrame = NULL;
 
112
  drawArea = NULL;
 
113
 
 
114
  // get the initial zoom value
 
115
  if (fullScreen) {
 
116
    zoom = zoomPage;
 
117
  } else {
 
118
    initialZoom = globalParams->getInitialZoom();
 
119
    if (!initialZoom->cmp("page")) {
 
120
      zoom = zoomPage;
 
121
    } else if (!initialZoom->cmp("width")) {
 
122
      zoom = zoomWidth;
 
123
    } else {
 
124
      zoom = atoi(initialZoom->getCString());
 
125
      if (zoom <= 0) {
 
126
        zoom = defZoom;
 
127
      }
 
128
    }
 
129
    delete initialZoom;
 
130
  }
 
131
 
 
132
  linkAction = NULL;
 
133
 
 
134
  panning = gFalse;
 
135
 
 
136
  updateCbk = NULL;
 
137
  actionCbk = NULL;
 
138
  keyPressCbk = NULL;
 
139
  mouseCbk = NULL;
 
140
 
 
141
  // optional features default to on
 
142
  hyperlinksEnabled = gTrue;
 
143
  selectEnabled = gTrue;
 
144
 
 
145
  // do X-specific initialization and create the widgets
 
146
  initWindow();
 
147
  initPasswordDialog();
 
148
}
 
149
 
 
150
XPDFCore::~XPDFCore() {
 
151
  if (currentSelectionOwner == this && currentSelection) {
 
152
    delete currentSelection;
 
153
    currentSelection = NULL;
 
154
    currentSelectionOwner = NULL;
 
155
  }
 
156
  if (drawAreaGC) {
 
157
    XFreeGC(display, drawAreaGC);
 
158
  }
 
159
  if (scrolledWin) {
 
160
    XtDestroyWidget(scrolledWin);
 
161
  }
 
162
  if (busyCursor) {
 
163
    XFreeCursor(display, busyCursor);
 
164
  }
 
165
  if (linkCursor) {
 
166
    XFreeCursor(display, linkCursor);
 
167
  }
 
168
  if (selectCursor) {
 
169
    XFreeCursor(display, selectCursor);
 
170
  }
 
171
}
 
172
 
 
173
//------------------------------------------------------------------------
 
174
// loadFile / displayPage / displayDest
 
175
//------------------------------------------------------------------------
 
176
 
 
177
int XPDFCore::loadFile(GString *fileName, GString *ownerPassword,
 
178
                       GString *userPassword) {
 
179
  int err;
 
180
 
 
181
  err = PDFCore::loadFile(fileName, ownerPassword, userPassword);
 
182
  if (err == errNone) {
 
183
    // save the modification time
 
184
    modTime = getModTime(doc->getFileName()->getCString());
 
185
 
 
186
    // update the parent window
 
187
    if (updateCbk) {
 
188
      (*updateCbk)(updateCbkData, doc->getFileName(), -1,
 
189
                   doc->getNumPages(), NULL);
 
190
    }
 
191
  }
 
192
  return err;
 
193
}
 
194
 
 
195
int XPDFCore::loadFile(BaseStream *stream, GString *ownerPassword,
 
196
                       GString *userPassword) {
 
197
  int err;
 
198
 
 
199
  err = PDFCore::loadFile(stream, ownerPassword, userPassword);
 
200
  if (err == errNone) {
 
201
    // no file
 
202
    modTime = 0;
 
203
 
 
204
    // update the parent window
 
205
    if (updateCbk) {
 
206
      (*updateCbk)(updateCbkData, doc->getFileName(), -1,
 
207
                   doc->getNumPages(), NULL);
 
208
    }
 
209
  }
 
210
  return err;
 
211
}
 
212
 
 
213
void XPDFCore::loadDoc(PDFDoc *docA) {
 
214
  PDFCore::loadDoc(docA);
 
215
 
 
216
  // save the modification time
 
217
  if (doc->getFileName()) {
 
218
    modTime = getModTime(doc->getFileName()->getCString());
 
219
  }
 
220
 
 
221
  // update the parent window
 
222
  if (updateCbk) {
 
223
    (*updateCbk)(updateCbkData, doc->getFileName(), -1,
 
224
                 doc->getNumPages(), NULL);
 
225
  }
 
226
}
 
227
 
 
228
void XPDFCore::resizeToPage(int pg) {
 
229
  Dimension width, height;
 
230
  double width1, height1;
 
231
  Dimension topW, topH, topBorder, daW, daH;
 
232
  Dimension displayW, displayH;
 
233
 
 
234
  displayW = DisplayWidth(display, screenNum);
 
235
  displayH = DisplayHeight(display, screenNum);
 
236
  if (fullScreen) {
 
237
    width = displayW;
 
238
    height = displayH;
 
239
  } else {
 
240
    if (!doc || pg <= 0 || pg > doc->getNumPages()) {
 
241
      width1 = 612;
 
242
      height1 = 792;
 
243
    } else if (doc->getPageRotate(pg) == 90 ||
 
244
               doc->getPageRotate(pg) == 270) {
 
245
      width1 = doc->getPageCropHeight(pg);
 
246
      height1 = doc->getPageCropWidth(pg);
 
247
    } else {
 
248
      width1 = doc->getPageCropWidth(pg);
 
249
      height1 = doc->getPageCropHeight(pg);
 
250
    }
 
251
    if (zoom == zoomPage || zoom == zoomWidth) {
 
252
      width = (Dimension)(width1 * 0.01 * defZoom + 0.5);
 
253
      height = (Dimension)(height1 * 0.01 * defZoom + 0.5);
 
254
    } else {
 
255
      width = (Dimension)(width1 * 0.01 * zoom + 0.5);
 
256
      height = (Dimension)(height1 * 0.01 * zoom + 0.5);
 
257
    }
 
258
    if (continuousMode) {
 
259
      height += continuousModePageSpacing;
 
260
    }
 
261
    if (width > displayW - 100) {
 
262
      width = displayW - 100;
 
263
    }
 
264
    if (height > displayH - 100) {
 
265
      height = displayH - 100;
 
266
    }
 
267
  }
 
268
 
 
269
  if (XtIsRealized(shell)) {
 
270
    XtVaGetValues(shell, XmNwidth, &topW, XmNheight, &topH,
 
271
                  XmNborderWidth, &topBorder, NULL);
 
272
    XtVaGetValues(drawArea, XmNwidth, &daW, XmNheight, &daH, NULL);
 
273
    XtVaSetValues(shell, XmNwidth, width + (topW - daW),
 
274
                  XmNheight, height + (topH - daH), NULL);
 
275
  } else {
 
276
    XtVaSetValues(drawArea, XmNwidth, width, XmNheight, height, NULL);
 
277
  }
 
278
}
 
279
 
 
280
void XPDFCore::update(int topPageA, int scrollXA, int scrollYA,
 
281
                      double zoomA, int rotateA,
 
282
                      GBool force, GBool addToHist) {
 
283
  int oldPage;
 
284
 
 
285
  oldPage = topPage;
 
286
  PDFCore::update(topPageA, scrollXA, scrollYA, zoomA, rotateA,
 
287
                  force, addToHist);
 
288
  linkAction = NULL;
 
289
  if (doc && topPage != oldPage) {
 
290
    if (updateCbk) {
 
291
      (*updateCbk)(updateCbkData, NULL, topPage, -1, "");
 
292
    }
 
293
  }
 
294
}
 
295
 
 
296
GBool XPDFCore::checkForNewFile() {
 
297
  time_t newModTime;
 
298
 
 
299
  if (doc->getFileName()) {
 
300
    newModTime = getModTime(doc->getFileName()->getCString());
 
301
    if (newModTime != modTime) {
 
302
      modTime = newModTime;
 
303
      return gTrue;
 
304
    }
 
305
  }
 
306
  return gFalse;
 
307
}
 
308
 
 
309
//------------------------------------------------------------------------
 
310
// page/position changes
 
311
//------------------------------------------------------------------------
 
312
 
 
313
GBool XPDFCore::gotoNextPage(int inc, GBool top) {
 
314
  if (!PDFCore::gotoNextPage(inc, top)) {
 
315
    XBell(display, 0);
 
316
    return gFalse;
 
317
  }
 
318
  return gTrue;
 
319
}
 
320
 
 
321
GBool XPDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) {
 
322
  if (!PDFCore::gotoPrevPage(dec, top, bottom)) {
 
323
    XBell(display, 0);
 
324
    return gFalse;
 
325
  }
 
326
  return gTrue;
 
327
}
 
328
 
 
329
GBool XPDFCore::goForward() {
 
330
  if (!PDFCore::goForward()) {
 
331
    XBell(display, 0);
 
332
    return gFalse;
 
333
  }
 
334
  return gTrue;
 
335
}
 
336
 
 
337
GBool XPDFCore::goBackward() {
 
338
  if (!PDFCore::goBackward()) {
 
339
    XBell(display, 0);
 
340
    return gFalse;
 
341
  }
 
342
  return gTrue;
 
343
}
 
344
 
 
345
void XPDFCore::startPan(int wx, int wy) {
 
346
  panning = gTrue;
 
347
  panMX = wx;
 
348
  panMY = wy;
 
349
}
 
350
 
 
351
void XPDFCore::endPan(int wx, int wy) {
 
352
  panning = gFalse;
 
353
}
 
354
 
 
355
//------------------------------------------------------------------------
 
356
// selection
 
357
//------------------------------------------------------------------------
 
358
 
 
359
void XPDFCore::startSelection(int wx, int wy) {
 
360
  int pg, x, y;
 
361
 
 
362
  takeFocus();
 
363
  if (doc && doc->getNumPages() > 0) {
 
364
    if (selectEnabled) {
 
365
      if (cvtWindowToDev(wx, wy, &pg, &x, &y)) {
 
366
        setSelection(pg, x, y, x, y);
 
367
        setCursor(selectCursor);
 
368
        dragging = gTrue;
 
369
      }
 
370
    }
 
371
  }
 
372
}
 
373
 
 
374
void XPDFCore::endSelection(int wx, int wy) {
 
375
  int pg, x, y;
 
376
  GBool ok;
 
377
 
 
378
  if (doc && doc->getNumPages() > 0) {
 
379
    ok = cvtWindowToDev(wx, wy, &pg, &x, &y);
 
380
    if (dragging) {
 
381
      dragging = gFalse;
 
382
      setCursor(None);
 
383
      if (ok) {
 
384
        moveSelection(pg, x, y);
 
385
      }
 
386
#ifndef NO_TEXT_SELECT
 
387
      if (selectULX != selectLRX &&
 
388
          selectULY != selectLRY) {
 
389
#ifdef ENFORCE_PERMISSIONS
 
390
        if (doc->okToCopy()) {
 
391
          copySelection();
 
392
        } else {
 
393
          error(-1, "Copying of text from this document is not allowed.");
 
394
        }
 
395
#else
 
396
        copySelection();
 
397
#endif
 
398
      }
 
399
#endif
 
400
    }
 
401
  }
 
402
}
 
403
 
 
404
// X's copy-and-paste mechanism is brain damaged.  Xt doesn't help
 
405
// any, but doesn't make it too much worse, either.  Motif, on the
 
406
// other hand, adds significant complexity to the mess.  So here we
 
407
// blow off the Motif junk and stick to plain old Xt.  The next two
 
408
// functions (copySelection and convertSelectionCbk) implement the
 
409
// magic needed to deal with Xt's mechanism.  Note that this requires
 
410
// global variables (currentSelection and currentSelectionOwner).
 
411
 
 
412
void XPDFCore::copySelection() {
 
413
  int pg;
 
414
  double ulx, uly, lrx, lry;
 
415
 
 
416
#ifdef ENFORCE_PERMISSIONS
 
417
  if (!doc->okToCopy()) {
 
418
    return;
 
419
  }
 
420
#endif
 
421
  if (getSelection(&pg, &ulx, &uly, &lrx, &lry)) {
 
422
    //~ for multithreading: need a mutex here
 
423
    if (currentSelection) {
 
424
      delete currentSelection;
 
425
    }
 
426
    currentSelection = extractText(pg, ulx, uly, lrx, lry);
 
427
    currentSelectionOwner = this;
 
428
    XtOwnSelection(drawArea, XA_PRIMARY, XtLastTimestampProcessed(display),
 
429
                   &convertSelectionCbk, NULL, NULL);
 
430
  }
 
431
}
 
432
 
 
433
Boolean XPDFCore::convertSelectionCbk(Widget widget, Atom *selection,
 
434
                                      Atom *target, Atom *type,
 
435
                                      XtPointer *value, unsigned long *length,
 
436
                                      int *format) {
 
437
  Atom *array;
 
438
 
 
439
  // send back a list of supported conversion targets
 
440
  if (*target == targetsAtom) {
 
441
    if (!(array = (Atom *)XtMalloc(sizeof(Atom)))) {
 
442
      return False;
 
443
    }
 
444
    array[0] = XA_STRING;
 
445
    *value = (XtPointer)array;
 
446
    *type = XA_ATOM;
 
447
    *format = 32;
 
448
    *length = 1;
 
449
    return True;
 
450
 
 
451
  // send the selected text
 
452
  } else if (*target == XA_STRING) {
 
453
    //~ for multithreading: need a mutex here
 
454
    *value = XtNewString(currentSelection->getCString());
 
455
    *length = currentSelection->getLength();
 
456
    *type = XA_STRING;
 
457
    *format = 8; // 8-bit elements
 
458
    return True;
 
459
  }
 
460
 
 
461
  return False;
 
462
}
 
463
 
 
464
//------------------------------------------------------------------------
 
465
// hyperlinks
 
466
//------------------------------------------------------------------------
 
467
 
 
468
void XPDFCore::doAction(LinkAction *action) {
 
469
  LinkActionKind kind;
 
470
  LinkDest *dest;
 
471
  GString *namedDest;
 
472
  char *s;
 
473
  GString *fileName, *fileName2;
 
474
  GString *cmd;
 
475
  GString *actionName;
 
476
  Object movieAnnot, obj1, obj2;
 
477
  GString *msg;
 
478
  int i;
 
479
 
 
480
  switch (kind = action->getKind()) {
 
481
 
 
482
  // GoTo / GoToR action
 
483
  case actionGoTo:
 
484
  case actionGoToR:
 
485
    if (kind == actionGoTo) {
 
486
      dest = NULL;
 
487
      namedDest = NULL;
 
488
      if ((dest = ((LinkGoTo *)action)->getDest())) {
 
489
        dest = dest->copy();
 
490
      } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) {
 
491
        namedDest = namedDest->copy();
 
492
      }
 
493
    } else {
 
494
      dest = NULL;
 
495
      namedDest = NULL;
 
496
      if ((dest = ((LinkGoToR *)action)->getDest())) {
 
497
        dest = dest->copy();
 
498
      } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) {
 
499
        namedDest = namedDest->copy();
 
500
      }
 
501
      s = ((LinkGoToR *)action)->getFileName()->getCString();
 
502
      //~ translate path name for VMS (deal with '/')
 
503
      if (isAbsolutePath(s)) {
 
504
        fileName = new GString(s);
 
505
      } else {
 
506
        fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
 
507
      }
 
508
      if (loadFile(fileName) != errNone) {
 
509
        if (dest) {
 
510
          delete dest;
 
511
        }
 
512
        if (namedDest) {
 
513
          delete namedDest;
 
514
        }
 
515
        delete fileName;
 
516
        return;
 
517
      }
 
518
      delete fileName;
 
519
    }
 
520
    if (namedDest) {
 
521
      dest = doc->findDest(namedDest);
 
522
      delete namedDest;
 
523
    }
 
524
    if (dest) {
 
525
      displayDest(dest, zoom, rotate, gTrue);
 
526
      delete dest;
 
527
    } else {
 
528
      if (kind == actionGoToR) {
 
529
        displayPage(1, zoom, 0, gFalse, gTrue);
 
530
      }
 
531
    }
 
532
    break;
 
533
 
 
534
  // Launch action
 
535
  case actionLaunch:
 
536
    fileName = ((LinkLaunch *)action)->getFileName();
 
537
    s = fileName->getCString();
 
538
    if (!strcmp(s + fileName->getLength() - 4, ".pdf") ||
 
539
        !strcmp(s + fileName->getLength() - 4, ".PDF")) {
 
540
      //~ translate path name for VMS (deal with '/')
 
541
      if (isAbsolutePath(s)) {
 
542
        fileName = fileName->copy();
 
543
      } else {
 
544
        fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s);
 
545
      }
 
546
      if (loadFile(fileName) != errNone) {
 
547
        delete fileName;
 
548
        return;
 
549
      }
 
550
      delete fileName;
 
551
      displayPage(1, zoom, rotate, gFalse, gTrue);
 
552
    } else {
 
553
      fileName = fileName->copy();
 
554
      if (((LinkLaunch *)action)->getParams()) {
 
555
        fileName->append(' ');
 
556
        fileName->append(((LinkLaunch *)action)->getParams());
 
557
      }
 
558
#ifdef VMS
 
559
      fileName->insert(0, "spawn/nowait ");
 
560
#elif defined(__EMX__)
 
561
      fileName->insert(0, "start /min /n ");
 
562
#else
 
563
      fileName->append(" &");
 
564
#endif
 
565
      msg = new GString("About to execute the command:\n");
 
566
      msg->append(fileName);
 
567
      if (doQuestionDialog("Launching external application", msg)) {
 
568
        system(fileName->getCString());
 
569
      }
 
570
      delete fileName;
 
571
      delete msg;
 
572
    }
 
573
    break;
 
574
 
 
575
  // URI action
 
576
  case actionURI:
 
577
    if (!(cmd = globalParams->getURLCommand())) {
 
578
      error(-1, "No urlCommand defined in config file");
 
579
      break;
 
580
    }
 
581
    runCommand(cmd, ((LinkURI *)action)->getURI());
 
582
    break;
 
583
 
 
584
  // Named action
 
585
  case actionNamed:
 
586
    actionName = ((LinkNamed *)action)->getName();
 
587
    if (!actionName->cmp("NextPage")) {
 
588
      gotoNextPage(1, gTrue);
 
589
    } else if (!actionName->cmp("PrevPage")) {
 
590
      gotoPrevPage(1, gTrue, gFalse);
 
591
    } else if (!actionName->cmp("FirstPage")) {
 
592
      if (topPage != 1) {
 
593
        displayPage(1, zoom, rotate, gTrue, gTrue);
 
594
      }
 
595
    } else if (!actionName->cmp("LastPage")) {
 
596
      if (topPage != doc->getNumPages()) {
 
597
        displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue);
 
598
      }
 
599
    } else if (!actionName->cmp("GoBack")) {
 
600
      goBackward();
 
601
    } else if (!actionName->cmp("GoForward")) {
 
602
      goForward();
 
603
    } else if (!actionName->cmp("Quit")) {
 
604
      if (actionCbk) {
 
605
        (*actionCbk)(actionCbkData, actionName->getCString());
 
606
      }
 
607
    } else {
 
608
      error(-1, "Unknown named action: '%s'", actionName->getCString());
 
609
    }
 
610
    break;
 
611
 
 
612
  // Movie action
 
613
  case actionMovie:
 
614
    if (!(cmd = globalParams->getMovieCommand())) {
 
615
      error(-1, "No movieCommand defined in config file");
 
616
      break;
 
617
    }
 
618
    if (((LinkMovie *)action)->hasAnnotRef()) {
 
619
      doc->getXRef()->fetch(((LinkMovie *)action)->getAnnotRef()->num,
 
620
                            ((LinkMovie *)action)->getAnnotRef()->gen,
 
621
                            &movieAnnot);
 
622
    } else {
 
623
      //~ need to use the correct page num here
 
624
      doc->getCatalog()->getPage(topPage)->getAnnots(&obj1);
 
625
      if (obj1.isArray()) {
 
626
        for (i = 0; i < obj1.arrayGetLength(); ++i) {
 
627
          if (obj1.arrayGet(i, &movieAnnot)->isDict()) {
 
628
            if (movieAnnot.dictLookup("Subtype", &obj2)->isName("Movie")) {
 
629
              obj2.free();
 
630
              break;
 
631
            }
 
632
            obj2.free();
 
633
          }
 
634
          movieAnnot.free();
 
635
        }
 
636
        obj1.free();
 
637
      }
 
638
    }
 
639
    if (movieAnnot.isDict()) {
 
640
      if (movieAnnot.dictLookup("Movie", &obj1)->isDict()) {
 
641
        if (obj1.dictLookup("F", &obj2)) {
 
642
          if ((fileName = LinkAction::getFileSpecName(&obj2))) {
 
643
            if (!isAbsolutePath(fileName->getCString())) {
 
644
              fileName2 = appendToPath(
 
645
                              grabPath(doc->getFileName()->getCString()),
 
646
                              fileName->getCString());
 
647
              delete fileName;
 
648
              fileName = fileName2;
 
649
            }
 
650
            runCommand(cmd, fileName);
 
651
            delete fileName;
 
652
          }
 
653
          obj2.free();
 
654
        }
 
655
        obj1.free();
 
656
      }
 
657
    }
 
658
    movieAnnot.free();
 
659
    break;
 
660
 
 
661
  // unknown action type
 
662
  case actionUnknown:
 
663
    error(-1, "Unknown link action type: '%s'",
 
664
          ((LinkUnknown *)action)->getAction()->getCString());
 
665
    break;
 
666
  }
 
667
}
 
668
 
 
669
// Run a command, given a <cmdFmt> string with one '%s' in it, and an
 
670
// <arg> string to insert in place of the '%s'.
 
671
void XPDFCore::runCommand(GString *cmdFmt, GString *arg) {
 
672
  GString *cmd;
 
673
  char *s;
 
674
 
 
675
  if ((s = strstr(cmdFmt->getCString(), "%s"))) {
 
676
    cmd = mungeURL(arg);
 
677
    cmd->insert(0, cmdFmt->getCString(),
 
678
                s - cmdFmt->getCString());
 
679
    cmd->append(s + 2);
 
680
  } else {
 
681
    cmd = cmdFmt->copy();
 
682
  }
 
683
#ifdef VMS
 
684
  cmd->insert(0, "spawn/nowait ");
 
685
#elif defined(__EMX__)
 
686
  cmd->insert(0, "start /min /n ");
 
687
#else
 
688
  cmd->append(" &");
 
689
#endif
 
690
  system(cmd->getCString());
 
691
  delete cmd;
 
692
}
 
693
 
 
694
// Escape any characters in a URL which might cause problems when
 
695
// calling system().
 
696
GString *XPDFCore::mungeURL(GString *url) {
 
697
  static char *allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
698
                         "abcdefghijklmnopqrstuvwxyz"
 
699
                         "0123456789"
 
700
                         "-_.~/?:@&=+,#%";
 
701
  GString *newURL;
 
702
  char c;
 
703
  char buf[4];
 
704
  int i;
 
705
 
 
706
  newURL = new GString();
 
707
  for (i = 0; i < url->getLength(); ++i) {
 
708
    c = url->getChar(i);
 
709
    if (strchr(allowed, c)) {
 
710
      newURL->append(c);
 
711
    } else {
 
712
      sprintf(buf, "%%%02x", c & 0xff);
 
713
      newURL->append(buf);
 
714
    }
 
715
  }
 
716
  return newURL;
 
717
}
 
718
 
 
719
//------------------------------------------------------------------------
 
720
// find
 
721
//------------------------------------------------------------------------
 
722
 
 
723
GBool XPDFCore::find(char *s, GBool caseSensitive,
 
724
                     GBool next, GBool backward, GBool onePageOnly) {
 
725
  if (!PDFCore::find(s, caseSensitive, next, backward, onePageOnly)) {
 
726
    XBell(display, 0);
 
727
    return gFalse;
 
728
  }
 
729
#ifndef NO_TEXT_SELECT
 
730
  copySelection();
 
731
#endif
 
732
  return gTrue;
 
733
}
 
734
 
 
735
GBool XPDFCore::findU(Unicode *u, int len, GBool caseSensitive,
 
736
                      GBool next, GBool backward, GBool onePageOnly) {
 
737
  if (!PDFCore::findU(u, len, caseSensitive, next, backward, onePageOnly)) {
 
738
    XBell(display, 0);
 
739
    return gFalse;
 
740
  }
 
741
#ifndef NO_TEXT_SELECT
 
742
  copySelection();
 
743
#endif
 
744
  return gTrue;
 
745
}
 
746
 
 
747
//------------------------------------------------------------------------
 
748
// misc access
 
749
//------------------------------------------------------------------------
 
750
 
 
751
void XPDFCore::setBusyCursor(GBool busy) {
 
752
  setCursor(busy ? busyCursor : None);
 
753
}
 
754
 
 
755
void XPDFCore::takeFocus() {
 
756
  XmProcessTraversal(drawArea, XmTRAVERSE_CURRENT);
 
757
}
 
758
 
 
759
//------------------------------------------------------------------------
 
760
// GUI code
 
761
//------------------------------------------------------------------------
 
762
 
 
763
void XPDFCore::setupX(GBool installCmap, int rgbCubeSizeA) {
 
764
  XVisualInfo visualTempl;
 
765
  XVisualInfo *visualList;
 
766
  Gulong mask;
 
767
  int nVisuals;
 
768
  XColor xcolor;
 
769
  XColor *xcolors;
 
770
  int r, g, b, n, m;
 
771
  GBool ok;
 
772
 
 
773
  // for some reason, querying XmNvisual doesn't work (even if done
 
774
  // after the window is mapped)
 
775
  visual = DefaultVisual(display, screenNum);
 
776
  XtVaGetValues(shell, XmNcolormap, &colormap, NULL);
 
777
 
 
778
  // check for TrueColor visual
 
779
  //~ this should scan the list, not just look at the first one
 
780
  visualTempl.visualid = XVisualIDFromVisual(visual);
 
781
  visualList = XGetVisualInfo(display, VisualIDMask,
 
782
                              &visualTempl, &nVisuals);
 
783
  if (nVisuals < 1) {
 
784
    // this shouldn't happen
 
785
    XFree((XPointer)visualList);
 
786
    visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
 
787
                                &nVisuals);
 
788
  }
 
789
  depth = visualList->depth;
 
790
  if (visualList->c_class == TrueColor) {
 
791
    trueColor = gTrue;
 
792
    for (mask = visualList->red_mask, rShift = 0;
 
793
         mask && !(mask & 1);
 
794
         mask >>= 1, ++rShift) ;
 
795
    for (rDiv = 8; mask; mask >>= 1, --rDiv) ;
 
796
    for (mask = visualList->green_mask, gShift = 0;
 
797
         mask && !(mask & 1);
 
798
         mask >>= 1, ++gShift) ;
 
799
    for (gDiv = 8; mask; mask >>= 1, --gDiv) ;
 
800
    for (mask = visualList->blue_mask, bShift = 0;
 
801
         mask && !(mask & 1);
 
802
         mask >>= 1, ++bShift) ;
 
803
    for (bDiv = 8; mask; mask >>= 1, --bDiv) ;
 
804
  } else {
 
805
    trueColor = gFalse;
 
806
  }
 
807
  XFree((XPointer)visualList);
 
808
 
 
809
  // allocate a color cube
 
810
  if (!trueColor) {
 
811
 
 
812
    // set colors in private colormap
 
813
    if (installCmap) {
 
814
      for (rgbCubeSize = xMaxRGBCube; rgbCubeSize >= 2; --rgbCubeSize) {
 
815
        m = rgbCubeSize * rgbCubeSize * rgbCubeSize;
 
816
        if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) {
 
817
          break;
 
818
        }
 
819
      }
 
820
      if (rgbCubeSize >= 2) {
 
821
        m = rgbCubeSize * rgbCubeSize * rgbCubeSize;
 
822
        xcolors = (XColor *)gmallocn(m, sizeof(XColor));
 
823
        n = 0;
 
824
        for (r = 0; r < rgbCubeSize; ++r) {
 
825
          for (g = 0; g < rgbCubeSize; ++g) {
 
826
            for (b = 0; b < rgbCubeSize; ++b) {
 
827
              xcolors[n].pixel = colors[n];
 
828
              xcolors[n].red = (r * 65535) / (rgbCubeSize - 1);
 
829
              xcolors[n].green = (g * 65535) / (rgbCubeSize - 1);
 
830
              xcolors[n].blue = (b * 65535) / (rgbCubeSize - 1);
 
831
              xcolors[n].flags = DoRed | DoGreen | DoBlue;
 
832
              ++n;
 
833
            }
 
834
          }
 
835
        }
 
836
        XStoreColors(display, colormap, xcolors, m);
 
837
        gfree(xcolors);
 
838
      } else {
 
839
        rgbCubeSize = 1;
 
840
        colors[0] = BlackPixel(display, screenNum);
 
841
        colors[1] = WhitePixel(display, screenNum);
 
842
      }
 
843
 
 
844
    // allocate colors in shared colormap
 
845
    } else {
 
846
      if (rgbCubeSize > xMaxRGBCube) {
 
847
        rgbCubeSize = xMaxRGBCube;
 
848
      }
 
849
      ok = gFalse;
 
850
      for (rgbCubeSize = rgbCubeSizeA; rgbCubeSize >= 2; --rgbCubeSize) {
 
851
        ok = gTrue;
 
852
        n = 0;
 
853
        for (r = 0; r < rgbCubeSize && ok; ++r) {
 
854
          for (g = 0; g < rgbCubeSize && ok; ++g) {
 
855
            for (b = 0; b < rgbCubeSize && ok; ++b) {
 
856
              if (n == 0) {
 
857
                colors[n] = BlackPixel(display, screenNum);
 
858
                ++n;
 
859
              } else {
 
860
                xcolor.red = (r * 65535) / (rgbCubeSize - 1);
 
861
                xcolor.green = (g * 65535) / (rgbCubeSize - 1);
 
862
                xcolor.blue = (b * 65535) / (rgbCubeSize - 1);
 
863
                if (XAllocColor(display, colormap, &xcolor)) {
 
864
                  colors[n++] = xcolor.pixel;
 
865
                } else {
 
866
                  ok = gFalse;
 
867
                }
 
868
              }
 
869
            }
 
870
          }
 
871
        }
 
872
        if (ok) {
 
873
          break;
 
874
        }
 
875
        XFreeColors(display, colormap, &colors[1], n-1, 0);
 
876
      }
 
877
      if (!ok) {
 
878
        rgbCubeSize = 1;
 
879
        colors[0] = BlackPixel(display, screenNum);
 
880
        colors[1] = WhitePixel(display, screenNum);
 
881
      }
 
882
    }
 
883
  }
 
884
}
 
885
 
 
886
void XPDFCore::initWindow() {
 
887
  Arg args[20];
 
888
  int n;
 
889
 
 
890
  // create the cursors
 
891
  busyCursor = XCreateFontCursor(display, XC_watch);
 
892
  linkCursor = XCreateFontCursor(display, XC_hand2);
 
893
  selectCursor = XCreateFontCursor(display, XC_cross);
 
894
  currentCursor = 0;
 
895
 
 
896
  // create the scrolled window and scrollbars
 
897
  n = 0;
 
898
  XtSetArg(args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++n;
 
899
  XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n;
 
900
  scrolledWin = XmCreateScrolledWindow(parentWidget, "scroll", args, n);
 
901
  XtManageChild(scrolledWin);
 
902
  n = 0;
 
903
  XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
 
904
  XtSetArg(args[n], XmNminimum, 0); ++n;
 
905
  XtSetArg(args[n], XmNmaximum, 1); ++n;
 
906
  XtSetArg(args[n], XmNsliderSize, 1); ++n;
 
907
  XtSetArg(args[n], XmNvalue, 0); ++n;
 
908
  XtSetArg(args[n], XmNincrement, 1); ++n;
 
909
  XtSetArg(args[n], XmNpageIncrement, 1); ++n;
 
910
  hScrollBar = XmCreateScrollBar(scrolledWin, "hScrollBar", args, n);
 
911
  if (!fullScreen) {
 
912
    XtManageChild(hScrollBar);
 
913
  }
 
914
  XtAddCallback(hScrollBar, XmNvalueChangedCallback,
 
915
                &hScrollChangeCbk, (XtPointer)this);
 
916
#ifndef DISABLE_SMOOTH_SCROLL
 
917
  XtAddCallback(hScrollBar, XmNdragCallback,
 
918
                &hScrollDragCbk, (XtPointer)this);
 
919
#endif
 
920
  n = 0;
 
921
  XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n;
 
922
  XtSetArg(args[n], XmNminimum, 0); ++n;
 
923
  XtSetArg(args[n], XmNmaximum, 1); ++n;
 
924
  XtSetArg(args[n], XmNsliderSize, 1); ++n;
 
925
  XtSetArg(args[n], XmNvalue, 0); ++n;
 
926
  XtSetArg(args[n], XmNincrement, 1); ++n;
 
927
  XtSetArg(args[n], XmNpageIncrement, 1); ++n;
 
928
  vScrollBar = XmCreateScrollBar(scrolledWin, "vScrollBar", args, n);
 
929
  if (!fullScreen) {
 
930
    XtManageChild(vScrollBar);
 
931
  }
 
932
  XtAddCallback(vScrollBar, XmNvalueChangedCallback,
 
933
                &vScrollChangeCbk, (XtPointer)this);
 
934
#ifndef DISABLE_SMOOTH_SCROLL
 
935
  XtAddCallback(vScrollBar, XmNdragCallback,
 
936
                &vScrollDragCbk, (XtPointer)this);
 
937
#endif
 
938
 
 
939
  // create the drawing area
 
940
  n = 0;
 
941
  XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); ++n;
 
942
  XtSetArg(args[n], XmNmarginWidth, 0); ++n;
 
943
  XtSetArg(args[n], XmNmarginHeight, 0); ++n;
 
944
  if (fullScreen) {
 
945
    XtSetArg(args[n], XmNshadowThickness, 0); ++n;
 
946
  }
 
947
  drawAreaFrame = XmCreateFrame(scrolledWin, "drawAreaFrame", args, n);
 
948
  XtManageChild(drawAreaFrame);
 
949
  n = 0;
 
950
  XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); ++n;
 
951
  XtSetArg(args[n], XmNwidth, 700); ++n;
 
952
  XtSetArg(args[n], XmNheight, 500); ++n;
 
953
  drawArea = XmCreateDrawingArea(drawAreaFrame, "drawArea", args, n);
 
954
  XtManageChild(drawArea);
 
955
  XtAddCallback(drawArea, XmNresizeCallback, &resizeCbk, (XtPointer)this);
 
956
  XtAddCallback(drawArea, XmNexposeCallback, &redrawCbk, (XtPointer)this);
 
957
  XtAddCallback(drawArea, XmNinputCallback, &inputCbk, (XtPointer)this);
 
958
  resizeCbk(drawArea, this, NULL);
 
959
 
 
960
  // set up mouse motion translations
 
961
  XtOverrideTranslations(drawArea, XtParseTranslationTable(
 
962
      "<Btn1Down>:DrawingAreaInput()\n"
 
963
      "<Btn1Up>:DrawingAreaInput()\n"
 
964
      "<Btn1Motion>:DrawingAreaInput()\n"
 
965
      "<Motion>:DrawingAreaInput()"));
 
966
 
 
967
  // can't create a GC until the window gets mapped
 
968
  drawAreaGC = NULL;
 
969
}
 
970
 
 
971
void XPDFCore::hScrollChangeCbk(Widget widget, XtPointer ptr,
 
972
                             XtPointer callData) {
 
973
  XPDFCore *core = (XPDFCore *)ptr;
 
974
  XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
 
975
 
 
976
  core->scrollTo(data->value, core->scrollY);
 
977
}
 
978
 
 
979
void XPDFCore::hScrollDragCbk(Widget widget, XtPointer ptr,
 
980
                              XtPointer callData) {
 
981
  XPDFCore *core = (XPDFCore *)ptr;
 
982
  XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
 
983
 
 
984
  core->scrollTo(data->value, core->scrollY);
 
985
}
 
986
 
 
987
void XPDFCore::vScrollChangeCbk(Widget widget, XtPointer ptr,
 
988
                             XtPointer callData) {
 
989
  XPDFCore *core = (XPDFCore *)ptr;
 
990
  XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
 
991
 
 
992
  core->scrollTo(core->scrollX, data->value);
 
993
}
 
994
 
 
995
void XPDFCore::vScrollDragCbk(Widget widget, XtPointer ptr,
 
996
                              XtPointer callData) {
 
997
  XPDFCore *core = (XPDFCore *)ptr;
 
998
  XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData;
 
999
 
 
1000
  core->scrollTo(core->scrollX, data->value);
 
1001
}
 
1002
 
 
1003
void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) {
 
1004
  XPDFCore *core = (XPDFCore *)ptr;
 
1005
  XEvent event;
 
1006
  Widget top;
 
1007
  Window rootWin;
 
1008
  int x1, y1;
 
1009
  Guint w1, h1, bw1, depth1;
 
1010
  Arg args[2];
 
1011
  int n;
 
1012
  Dimension w, h;
 
1013
  int sx, sy;
 
1014
 
 
1015
  // find the top-most widget which has an associated window, and look
 
1016
  // for a pending ConfigureNotify in the event queue -- if there is
 
1017
  // one, and it specifies a different width or height, that means
 
1018
  // we're still resizing, and we want to skip the current event
 
1019
  for (top = core->parentWidget;
 
1020
       XtParent(top) && XtWindow(XtParent(top));
 
1021
       top = XtParent(top)) ;
 
1022
  if (XCheckTypedWindowEvent(core->display, XtWindow(top),
 
1023
                             ConfigureNotify, &event)) {
 
1024
    XPutBackEvent(core->display, &event);
 
1025
    XGetGeometry(core->display, event.xconfigure.window,
 
1026
                 &rootWin, &x1, &y1, &w1, &h1, &bw1, &depth1);
 
1027
    if ((Guint)event.xconfigure.width != w1 ||
 
1028
        (Guint)event.xconfigure.height != h1) {
 
1029
      return;
 
1030
    }
 
1031
  }
 
1032
 
 
1033
  n = 0;
 
1034
  XtSetArg(args[n], XmNwidth, &w); ++n;
 
1035
  XtSetArg(args[n], XmNheight, &h); ++n;
 
1036
  XtGetValues(core->drawArea, args, n);
 
1037
  core->drawAreaWidth = (int)w;
 
1038
  core->drawAreaHeight = (int)h;
 
1039
  if (core->zoom == zoomPage || core->zoom == zoomWidth) {
 
1040
    sx = sy = -1;
 
1041
  } else {
 
1042
    sx = core->scrollX;
 
1043
    sy = core->scrollY;
 
1044
  }
 
1045
  core->update(core->topPage, sx, sy, core->zoom, core->rotate, gTrue, gFalse);
 
1046
}
 
1047
 
 
1048
void XPDFCore::redrawCbk(Widget widget, XtPointer ptr, XtPointer callData) {
 
1049
  XPDFCore *core = (XPDFCore *)ptr;
 
1050
  XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
 
1051
  int x, y, w, h;
 
1052
 
 
1053
  if (data->reason == XmCR_EXPOSE) {
 
1054
    x = data->event->xexpose.x;
 
1055
    y = data->event->xexpose.y;
 
1056
    w = data->event->xexpose.width;
 
1057
    h = data->event->xexpose.height;
 
1058
  } else {
 
1059
    x = 0;
 
1060
    y = 0;
 
1061
    w = core->drawAreaWidth;
 
1062
    h = core->drawAreaHeight;
 
1063
  }
 
1064
  core->redrawWindow(x, y, w, h, gFalse);
 
1065
}
 
1066
 
 
1067
void XPDFCore::inputCbk(Widget widget, XtPointer ptr, XtPointer callData) {
 
1068
  XPDFCore *core = (XPDFCore *)ptr;
 
1069
  XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData;
 
1070
  LinkAction *action;
 
1071
  int pg, x, y;
 
1072
  double xu, yu;
 
1073
  char *s;
 
1074
  KeySym key;
 
1075
  GBool ok;
 
1076
 
 
1077
  switch (data->event->type) {
 
1078
  case ButtonPress:
 
1079
    if (*core->mouseCbk) {
 
1080
      (*core->mouseCbk)(core->mouseCbkData, data->event);
 
1081
    }
 
1082
    break;
 
1083
  case ButtonRelease:
 
1084
    if (*core->mouseCbk) {
 
1085
      (*core->mouseCbk)(core->mouseCbkData, data->event);
 
1086
    }
 
1087
    break;
 
1088
  case MotionNotify:
 
1089
    if (core->doc && core->doc->getNumPages() > 0) {
 
1090
      ok = core->cvtWindowToDev(data->event->xmotion.x, data->event->xmotion.y,
 
1091
                                &pg, &x, &y);
 
1092
      if (core->dragging) {
 
1093
        if (ok) {
 
1094
          core->moveSelection(pg, x, y);
 
1095
        }
 
1096
      } else if (core->hyperlinksEnabled) {
 
1097
        core->cvtDevToUser(pg, x, y, &xu, &yu);
 
1098
        if (ok && (action = core->findLink(pg, xu, yu))) {
 
1099
          core->setCursor(core->linkCursor);
 
1100
          if (action != core->linkAction) {
 
1101
            core->linkAction = action;
 
1102
            if (core->updateCbk) {
 
1103
              s = "";
 
1104
              switch (action->getKind()) {
 
1105
              case actionGoTo:
 
1106
                s = "[internal link]";
 
1107
                break;
 
1108
              case actionGoToR:
 
1109
                s = ((LinkGoToR *)action)->getFileName()->getCString();
 
1110
                break;
 
1111
              case actionLaunch:
 
1112
                s = ((LinkLaunch *)action)->getFileName()->getCString();
 
1113
                break;
 
1114
              case actionURI:
 
1115
                s = ((LinkURI *)action)->getURI()->getCString();
 
1116
                break;
 
1117
              case actionNamed:
 
1118
                s = ((LinkNamed *)action)->getName()->getCString();
 
1119
                break;
 
1120
              case actionMovie:
 
1121
                s = "[movie]";
 
1122
                break;
 
1123
              case actionUnknown:
 
1124
                s = "[unknown link]";
 
1125
                break;
 
1126
              }
 
1127
              (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, s);
 
1128
            }
 
1129
          }
 
1130
        } else {
 
1131
          core->setCursor(None);
 
1132
          if (core->linkAction) {
 
1133
            core->linkAction = NULL;
 
1134
            if (core->updateCbk) {
 
1135
              (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, "");
 
1136
            }
 
1137
          }
 
1138
        }
 
1139
      }
 
1140
    }
 
1141
    if (core->panning) {
 
1142
      core->scrollTo(core->scrollX - (data->event->xmotion.x - core->panMX),
 
1143
                     core->scrollY - (data->event->xmotion.y - core->panMY));
 
1144
      core->panMX = data->event->xmotion.x;
 
1145
      core->panMY = data->event->xmotion.y;
 
1146
    }
 
1147
    break;
 
1148
  case KeyPress:
 
1149
    if (core->keyPressCbk) {
 
1150
      key = XLookupKeysym(&data->event->xkey,
 
1151
                          (data->event->xkey.state & ShiftMask) ? 1 : 0);
 
1152
      (*core->keyPressCbk)(core->keyPressCbkData,
 
1153
                           key, data->event->xkey.state, data->event);
 
1154
    }
 
1155
    break;
 
1156
  }
 
1157
}
 
1158
 
 
1159
PDFCoreTile *XPDFCore::newTile(int xDestA, int yDestA) {
 
1160
  return new XPDFCoreTile(xDestA, yDestA);
 
1161
}
 
1162
 
 
1163
void XPDFCore::updateTileData(PDFCoreTile *tileA, int xSrc, int ySrc,
 
1164
                              int width, int height, GBool composited) {
 
1165
  XPDFCoreTile *tile = (XPDFCoreTile *)tileA;
 
1166
  XImage *image;
 
1167
  SplashColorPtr dataPtr, p;
 
1168
  Gulong pixel;
 
1169
  Guchar *ap;
 
1170
  Guchar alpha, alpha1;
 
1171
  int w, h, bw, x, y, r, g, b, gray;
 
1172
  int *errDownR, *errDownG, *errDownB;
 
1173
  int errRightR, errRightG, errRightB;
 
1174
  int errDownRightR, errDownRightG, errDownRightB;
 
1175
  int r0, g0, b0, re, ge, be;
 
1176
 
 
1177
  if (!tile->image) {
 
1178
    w = tile->xMax - tile->xMin;
 
1179
    h = tile->yMax - tile->yMin;
 
1180
    image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, w, h, 8, 0);
 
1181
    image->data = (char *)gmalloc(h * image->bytes_per_line);
 
1182
    tile->image = image;
 
1183
  } else {
 
1184
    image = (XImage *)tile->image;
 
1185
  }
 
1186
 
 
1187
  //~ optimize for known XImage formats
 
1188
  bw = tile->bitmap->getRowSize();
 
1189
  dataPtr = tile->bitmap->getDataPtr();
 
1190
 
 
1191
  if (trueColor) {
 
1192
    for (y = 0; y < height; ++y) {
 
1193
      p = dataPtr + (ySrc + y) * bw + xSrc * 3;
 
1194
      if (!composited && tile->bitmap->getAlphaPtr()) {
 
1195
        ap = tile->bitmap->getAlphaPtr() +
 
1196
               (ySrc + y) * tile->bitmap->getWidth() + xSrc;
 
1197
      } else {
 
1198
        ap = NULL;
 
1199
      }
 
1200
      for (x = 0; x < width; ++x) {
 
1201
        r = splashRGB8R(p);
 
1202
        g = splashRGB8G(p);
 
1203
        b = splashRGB8B(p);
 
1204
        if (ap) {
 
1205
          alpha = *ap++;
 
1206
          alpha1 = 255 - alpha;
 
1207
          r = div255(alpha1 * paperColor[0] + alpha * r);
 
1208
          g = div255(alpha1 * paperColor[1] + alpha * g);
 
1209
          b = div255(alpha1 * paperColor[2] + alpha * b);
 
1210
        }
 
1211
        r >>= rDiv;
 
1212
        g >>= gDiv;
 
1213
        b >>= bDiv;
 
1214
        pixel = ((Gulong)r << rShift) +
 
1215
                ((Gulong)g << gShift) +
 
1216
                ((Gulong)b << bShift);
 
1217
        XPutPixel(image, xSrc + x, ySrc + y, pixel);
 
1218
        p += 3;
 
1219
      }
 
1220
    }
 
1221
  } else if (rgbCubeSize == 1) {
 
1222
    //~ this should really use splashModeMono, with non-clustered dithering
 
1223
    for (y = 0; y < height; ++y) {
 
1224
      p = dataPtr + (ySrc + y) * bw + xSrc * 3;
 
1225
      if (!composited && tile->bitmap->getAlphaPtr()) {
 
1226
        ap = tile->bitmap->getAlphaPtr() +
 
1227
               (ySrc + y) * tile->bitmap->getWidth() + xSrc;
 
1228
      } else {
 
1229
        ap = NULL;
 
1230
      }
 
1231
      for (x = 0; x < width; ++x) {
 
1232
        r = splashRGB8R(p);
 
1233
        g = splashRGB8G(p);
 
1234
        b = splashRGB8B(p);
 
1235
        if (ap) {
 
1236
          alpha = *ap++;
 
1237
          alpha1 = 255 - alpha;
 
1238
          r = div255(alpha1 * paperColor[0] + alpha * r);
 
1239
          g = div255(alpha1 * paperColor[1] + alpha * g);
 
1240
          b = div255(alpha1 * paperColor[2] + alpha * b);
 
1241
        }
 
1242
        gray = (int)(0.299 * r + 0.587 * g + 0.114 * b + 0.5);
 
1243
        if (gray < 128) {
 
1244
          pixel = colors[0];
 
1245
        } else {
 
1246
          pixel = colors[1];
 
1247
        }
 
1248
        XPutPixel(image, xSrc + x, ySrc + y, pixel);
 
1249
        p += 3;
 
1250
      }
 
1251
    }
 
1252
  } else {
 
1253
    // do Floyd-Steinberg dithering on the whole bitmap
 
1254
    errDownR = (int *)gmallocn(width + 2, sizeof(int));
 
1255
    errDownG = (int *)gmallocn(width + 2, sizeof(int));
 
1256
    errDownB = (int *)gmallocn(width + 2, sizeof(int));
 
1257
    errRightR = errRightG = errRightB = 0;
 
1258
    errDownRightR = errDownRightG = errDownRightB = 0;
 
1259
    memset(errDownR, 0, (width + 2) * sizeof(int));
 
1260
    memset(errDownG, 0, (width + 2) * sizeof(int));
 
1261
    memset(errDownB, 0, (width + 2) * sizeof(int));
 
1262
    for (y = 0; y < height; ++y) {
 
1263
      p = dataPtr + (ySrc + y) * bw + xSrc * 3;
 
1264
      if (!composited && tile->bitmap->getAlphaPtr()) {
 
1265
        ap = tile->bitmap->getAlphaPtr() +
 
1266
               (ySrc + y) * tile->bitmap->getWidth() + xSrc;
 
1267
      } else {
 
1268
        ap = NULL;
 
1269
      }
 
1270
      for (x = 0; x < width; ++x) {
 
1271
        r = splashRGB8R(p);
 
1272
        g = splashRGB8G(p);
 
1273
        b = splashRGB8B(p);
 
1274
        if (ap) {
 
1275
          alpha = *ap++;
 
1276
          alpha1 = 255 - alpha;
 
1277
          r = div255(alpha1 * paperColor[0] + alpha * r);
 
1278
          g = div255(alpha1 * paperColor[1] + alpha * g);
 
1279
          b = div255(alpha1 * paperColor[2] + alpha * b);
 
1280
        }
 
1281
        r0 = r + errRightR + errDownR[x+1];
 
1282
        g0 = g + errRightG + errDownG[x+1];
 
1283
        b0 = b + errRightB + errDownB[x+1];
 
1284
        if (r0 < 0) {
 
1285
          r = 0;
 
1286
        } else if (r0 >= 255) {
 
1287
          r = rgbCubeSize - 1;
 
1288
        } else {
 
1289
          r = div255(r0 * (rgbCubeSize - 1));
 
1290
        }
 
1291
        if (g0 < 0) {
 
1292
          g = 0;
 
1293
        } else if (g0 >= 255) {
 
1294
          g = rgbCubeSize - 1;
 
1295
        } else {
 
1296
          g = div255(g0 * (rgbCubeSize - 1));
 
1297
        }
 
1298
        if (b0 < 0) {
 
1299
          b = 0;
 
1300
        } else if (b0 >= 255) {
 
1301
          b = rgbCubeSize - 1;
 
1302
        } else {
 
1303
          b = div255(b0 * (rgbCubeSize - 1));
 
1304
        }
 
1305
        re = r0 - ((r << 8) - r) / (rgbCubeSize - 1);
 
1306
        ge = g0 - ((g << 8) - g) / (rgbCubeSize - 1);
 
1307
        be = b0 - ((b << 8) - b) / (rgbCubeSize - 1);
 
1308
        errRightR = (re * 7) >> 4;
 
1309
        errRightG = (ge * 7) >> 4;
 
1310
        errRightB = (be * 7) >> 4;
 
1311
        errDownR[x] += (re * 3) >> 4;
 
1312
        errDownG[x] += (ge * 3) >> 4;
 
1313
        errDownB[x] += (be * 3) >> 4;
 
1314
        errDownR[x+1] = ((re * 5) >> 4) + errDownRightR;
 
1315
        errDownG[x+1] = ((ge * 5) >> 4) + errDownRightG;
 
1316
        errDownB[x+1] = ((be * 5) >> 4) + errDownRightB;
 
1317
        errDownRightR = re >> 4;
 
1318
        errDownRightG = ge >> 4;
 
1319
        errDownRightB = be >> 4;
 
1320
        pixel = colors[(r * rgbCubeSize + g) * rgbCubeSize + b];
 
1321
        XPutPixel(image, xSrc + x, ySrc + y, pixel);
 
1322
        p += 3;
 
1323
      }
 
1324
    }
 
1325
    gfree(errDownR);
 
1326
    gfree(errDownG);
 
1327
    gfree(errDownB);
 
1328
  }
 
1329
}
 
1330
 
 
1331
void XPDFCore::redrawRect(PDFCoreTile *tileA, int xSrc, int ySrc,
 
1332
                          int xDest, int yDest, int width, int height,
 
1333
                          GBool composited) {
 
1334
  XPDFCoreTile *tile = (XPDFCoreTile *)tileA;
 
1335
  Window drawAreaWin;
 
1336
  XGCValues gcValues;
 
1337
 
 
1338
  // create a GC for the drawing area
 
1339
  drawAreaWin = XtWindow(drawArea);
 
1340
  if (!drawAreaGC) {
 
1341
    gcValues.foreground = mattePixel;
 
1342
    drawAreaGC = XCreateGC(display, drawAreaWin, GCForeground, &gcValues);
 
1343
  }
 
1344
 
 
1345
  // draw the document
 
1346
  if (tile) {
 
1347
    XPutImage(display, drawAreaWin, drawAreaGC, tile->image,
 
1348
              xSrc, ySrc, xDest, yDest, width, height);
 
1349
 
 
1350
  // draw the background
 
1351
  } else {
 
1352
    XFillRectangle(display, drawAreaWin, drawAreaGC,
 
1353
                   xDest, yDest, width, height);
 
1354
  }
 
1355
}
 
1356
 
 
1357
void XPDFCore::updateScrollbars() {
 
1358
  Arg args[20];
 
1359
  int n;
 
1360
  int maxPos;
 
1361
 
 
1362
  if (pages->getLength() > 0) {
 
1363
    if (continuousMode) {
 
1364
      maxPos = maxPageW;
 
1365
    } else {
 
1366
      maxPos = ((PDFCorePage *)pages->get(0))->w;
 
1367
    }
 
1368
  } else {
 
1369
    maxPos = 1;
 
1370
  }
 
1371
  if (maxPos < drawAreaWidth) {
 
1372
    maxPos = drawAreaWidth;
 
1373
  }
 
1374
  n = 0;
 
1375
  XtSetArg(args[n], XmNvalue, scrollX); ++n;
 
1376
  XtSetArg(args[n], XmNmaximum, maxPos); ++n;
 
1377
  XtSetArg(args[n], XmNsliderSize, drawAreaWidth); ++n;
 
1378
  XtSetArg(args[n], XmNincrement, 16); ++n;
 
1379
  XtSetArg(args[n], XmNpageIncrement, drawAreaWidth); ++n;
 
1380
  XtSetValues(hScrollBar, args, n);
 
1381
 
 
1382
  if (pages->getLength() > 0) {
 
1383
    if (continuousMode) {
 
1384
      maxPos = totalDocH;
 
1385
    } else {
 
1386
      maxPos = ((PDFCorePage *)pages->get(0))->h;
 
1387
    }
 
1388
  } else {
 
1389
    maxPos = 1;
 
1390
  }
 
1391
  if (maxPos < drawAreaHeight) {
 
1392
    maxPos = drawAreaHeight;
 
1393
  }
 
1394
  n = 0;
 
1395
  XtSetArg(args[n], XmNvalue, scrollY); ++n;
 
1396
  XtSetArg(args[n], XmNmaximum, maxPos); ++n;
 
1397
  XtSetArg(args[n], XmNsliderSize, drawAreaHeight); ++n;
 
1398
  XtSetArg(args[n], XmNincrement, 16); ++n;
 
1399
  XtSetArg(args[n], XmNpageIncrement, drawAreaHeight); ++n;
 
1400
  XtSetValues(vScrollBar, args, n);
 
1401
}
 
1402
 
 
1403
void XPDFCore::setCursor(Cursor cursor) {
 
1404
  Window topWin;
 
1405
 
 
1406
  if (cursor == currentCursor) {
 
1407
    return;
 
1408
  }
 
1409
  if (!(topWin = XtWindow(shell))) {
 
1410
    return;
 
1411
  }
 
1412
  if (cursor == None) {
 
1413
    XUndefineCursor(display, topWin);
 
1414
  } else {
 
1415
    XDefineCursor(display, topWin, cursor);
 
1416
  }
 
1417
  XFlush(display);
 
1418
  currentCursor = cursor;
 
1419
}
 
1420
 
 
1421
GBool XPDFCore::doQuestionDialog(char *title, GString *msg) {
 
1422
  return doDialog(XmDIALOG_QUESTION, gTrue, title, msg);
 
1423
}
 
1424
 
 
1425
void XPDFCore::doInfoDialog(char *title, GString *msg) {
 
1426
  doDialog(XmDIALOG_INFORMATION, gFalse, title, msg);
 
1427
}
 
1428
 
 
1429
void XPDFCore::doErrorDialog(char *title, GString *msg) {
 
1430
  doDialog(XmDIALOG_ERROR, gFalse, title, msg);
 
1431
}
 
1432
 
 
1433
GBool XPDFCore::doDialog(int type, GBool hasCancel,
 
1434
                         char *title, GString *msg) {
 
1435
  Widget dialog, scroll, text;
 
1436
  XtAppContext appContext;
 
1437
  Arg args[20];
 
1438
  int n;
 
1439
  XmString s1, s2;
 
1440
  XEvent event;
 
1441
 
 
1442
  n = 0;
 
1443
  XtSetArg(args[n], XmNdialogType, type); ++n;
 
1444
  XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
 
1445
  s1 = XmStringCreateLocalized(title);
 
1446
  XtSetArg(args[n], XmNdialogTitle, s1); ++n;
 
1447
  s2 = NULL; // make gcc happy
 
1448
  if (msg->getLength() <= 80) {
 
1449
    s2 = XmStringCreateLocalized(msg->getCString());
 
1450
    XtSetArg(args[n], XmNmessageString, s2); ++n;
 
1451
  }
 
1452
  dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n);
 
1453
  XmStringFree(s1);
 
1454
  if (msg->getLength() <= 80) {
 
1455
    XmStringFree(s2);
 
1456
  } else {
 
1457
    n = 0;
 
1458
    XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n;
 
1459
    if (drawAreaWidth > 300) {
 
1460
      XtSetArg(args[n], XmNwidth, drawAreaWidth - 100); ++n;
 
1461
    }
 
1462
    scroll = XmCreateScrolledWindow(dialog, "scroll", args, n);
 
1463
    XtManageChild(scroll);
 
1464
    n = 0;
 
1465
    XtSetArg(args[n], XmNeditable, False); ++n;
 
1466
    XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); ++n;
 
1467
    XtSetArg(args[n], XmNvalue, msg->getCString()); ++n;
 
1468
    XtSetArg(args[n], XmNshadowThickness, 0); ++n;
 
1469
    text = XmCreateText(scroll, "text", args, n);
 
1470
    XtManageChild(text);
 
1471
  }
 
1472
  XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
 
1473
  XtAddCallback(dialog, XmNokCallback,
 
1474
                &dialogOkCbk, (XtPointer)this);
 
1475
  if (hasCancel) {
 
1476
    XtAddCallback(dialog, XmNcancelCallback,
 
1477
                  &dialogCancelCbk, (XtPointer)this);
 
1478
  } else {
 
1479
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
 
1480
  }
 
1481
 
 
1482
  XtManageChild(dialog);
 
1483
 
 
1484
  appContext = XtWidgetToApplicationContext(dialog);
 
1485
  dialogDone = 0;
 
1486
  do {
 
1487
    XtAppNextEvent(appContext, &event);
 
1488
    XtDispatchEvent(&event);
 
1489
  } while (!dialogDone);
 
1490
 
 
1491
  XtUnmanageChild(dialog);
 
1492
  XtDestroyWidget(dialog);
 
1493
 
 
1494
  return dialogDone > 0;
 
1495
}
 
1496
 
 
1497
void XPDFCore::dialogOkCbk(Widget widget, XtPointer ptr,
 
1498
                           XtPointer callData) {
 
1499
  XPDFCore *core = (XPDFCore *)ptr;
 
1500
 
 
1501
  core->dialogDone = 1;
 
1502
}
 
1503
 
 
1504
void XPDFCore::dialogCancelCbk(Widget widget, XtPointer ptr,
 
1505
                               XtPointer callData) {
 
1506
  XPDFCore *core = (XPDFCore *)ptr;
 
1507
 
 
1508
  core->dialogDone = -1;
 
1509
}
 
1510
 
 
1511
//------------------------------------------------------------------------
 
1512
// password dialog
 
1513
//------------------------------------------------------------------------
 
1514
 
 
1515
void XPDFCore::initPasswordDialog() {
 
1516
  Widget row, label, okBtn, cancelBtn;
 
1517
  Arg args[20];
 
1518
  int n;
 
1519
  XmString s;
 
1520
 
 
1521
  //----- dialog
 
1522
  n = 0;
 
1523
  s = XmStringCreateLocalized(xpdfAppName ": Password");
 
1524
  XtSetArg(args[n], XmNdialogTitle, s); ++n;
 
1525
  XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n;
 
1526
  passwordDialog = XmCreateFormDialog(drawArea, "passwordDialog", args, n);
 
1527
  XmStringFree(s);
 
1528
 
 
1529
  //----- message
 
1530
  n = 0;
 
1531
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n;
 
1532
  XtSetArg(args[n], XmNtopOffset, 4); ++n;
 
1533
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
 
1534
  XtSetArg(args[n], XmNleftOffset, 4); ++n;
 
1535
  s = XmStringCreateLocalized("This document requires a password.");
 
1536
  XtSetArg(args[n], XmNlabelString, s); ++n;
 
1537
  label = XmCreateLabel(passwordDialog, "msg", args, n);
 
1538
  XmStringFree(s);
 
1539
  XtManageChild(label);
 
1540
 
 
1541
  //----- label and password entry
 
1542
  n = 0;
 
1543
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
 
1544
  XtSetArg(args[n], XmNtopWidget, label); ++n;
 
1545
  XtSetArg(args[n], XmNtopOffset, 4); ++n;
 
1546
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
 
1547
  XtSetArg(args[n], XmNleftOffset, 4); ++n;
 
1548
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
 
1549
  XtSetArg(args[n], XmNleftOffset, 4); ++n;
 
1550
  XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;
 
1551
  XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n;
 
1552
  row = XmCreateRowColumn(passwordDialog, "row", args, n);
 
1553
  XtManageChild(row);
 
1554
  n = 0;
 
1555
  s = XmStringCreateLocalized("Password: ");
 
1556
  XtSetArg(args[n], XmNlabelString, s); ++n;
 
1557
  label = XmCreateLabel(row, "label", args, n);
 
1558
  XmStringFree(s);
 
1559
  XtManageChild(label);
 
1560
  n = 0;
 
1561
  XtSetArg(args[n], XmNcolumns, 16); ++n;
 
1562
  passwordText = XmCreateTextField(row, "text", args, n);
 
1563
  XtManageChild(passwordText);
 
1564
  XtAddCallback(passwordText, XmNmodifyVerifyCallback,
 
1565
                &passwordTextVerifyCbk, this);
 
1566
 
 
1567
  //----- "Ok" and "Cancel" buttons
 
1568
  n = 0;
 
1569
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
 
1570
  XtSetArg(args[n], XmNtopWidget, row); ++n;
 
1571
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n;
 
1572
  XtSetArg(args[n], XmNleftOffset, 4); ++n;
 
1573
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
 
1574
  XtSetArg(args[n], XmNbottomOffset, 4); ++n;
 
1575
  XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
 
1576
  okBtn = XmCreatePushButton(passwordDialog, "Ok", args, n);
 
1577
  XtManageChild(okBtn);
 
1578
  XtAddCallback(okBtn, XmNactivateCallback,
 
1579
                &passwordOkCbk, (XtPointer)this);
 
1580
  n = 0;
 
1581
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n;
 
1582
  XtSetArg(args[n], XmNtopWidget, row); ++n;
 
1583
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n;
 
1584
  XtSetArg(args[n], XmNrightOffset, 4); ++n;
 
1585
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n;
 
1586
  XtSetArg(args[n], XmNbottomOffset, 4); ++n;
 
1587
  XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n;
 
1588
  cancelBtn = XmCreatePushButton(passwordDialog, "Cancel", args, n);
 
1589
  XtManageChild(cancelBtn);
 
1590
  XtAddCallback(cancelBtn, XmNactivateCallback,
 
1591
                &passwordCancelCbk, (XtPointer)this);
 
1592
  n = 0;
 
1593
  XtSetArg(args[n], XmNdefaultButton, okBtn); ++n;
 
1594
  XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n;
 
1595
#if XmVersion > 1001
 
1596
  XtSetArg(args[n], XmNinitialFocus, passwordText); ++n;
 
1597
#endif
 
1598
  XtSetValues(passwordDialog, args, n);
 
1599
}
 
1600
 
 
1601
void XPDFCore::passwordTextVerifyCbk(Widget widget, XtPointer ptr,
 
1602
                                     XtPointer callData) {
 
1603
  XPDFCore *core = (XPDFCore *)ptr;
 
1604
  XmTextVerifyCallbackStruct *data =
 
1605
      (XmTextVerifyCallbackStruct *)callData;
 
1606
  int i, n;
 
1607
 
 
1608
  i = (int)data->startPos;
 
1609
  n = (int)data->endPos - i;
 
1610
  if (i > core->password->getLength()) {
 
1611
    i = core->password->getLength();
 
1612
  }
 
1613
  if (i + n > core->password->getLength()) {
 
1614
    n = core->password->getLength() - i;
 
1615
  }
 
1616
  core->password->del(i, n);
 
1617
  core->password->insert(i, data->text->ptr, data->text->length);
 
1618
 
 
1619
  for (i = 0; i < data->text->length; ++i) {
 
1620
    data->text->ptr[i] = '*';
 
1621
  }
 
1622
  data->doit = True;
 
1623
}
 
1624
 
 
1625
void XPDFCore::passwordOkCbk(Widget widget, XtPointer ptr,
 
1626
                             XtPointer callData) {
 
1627
  XPDFCore *core = (XPDFCore *)ptr;
 
1628
 
 
1629
  core->dialogDone = 1;
 
1630
}
 
1631
 
 
1632
void XPDFCore::passwordCancelCbk(Widget widget, XtPointer ptr,
 
1633
                                 XtPointer callData) {
 
1634
  XPDFCore *core = (XPDFCore *)ptr;
 
1635
 
 
1636
  core->dialogDone = -1;
 
1637
}
 
1638
 
 
1639
GString *XPDFCore::getPassword() {
 
1640
  XtAppContext appContext;
 
1641
  XEvent event;
 
1642
 
 
1643
  // NB: set <password> before calling XmTextFieldSetString, because
 
1644
  // SetString will trigger a call to passwordTextVerifyCbk, which
 
1645
  // expects <password> to be valid
 
1646
  password = new GString();
 
1647
  XmTextFieldSetString(passwordText, "");
 
1648
  XtManageChild(passwordDialog);
 
1649
 
 
1650
  appContext = XtWidgetToApplicationContext(passwordDialog);
 
1651
  dialogDone = 0;
 
1652
  do {
 
1653
    XtAppNextEvent(appContext, &event);
 
1654
    XtDispatchEvent(&event);
 
1655
  } while (!dialogDone);
 
1656
  XtUnmanageChild(passwordDialog);
 
1657
 
 
1658
  if (dialogDone < 0) {
 
1659
    delete password;
 
1660
    return NULL;
 
1661
  }
 
1662
  return password;
 
1663
}