1 /*
2 * Copyright (c) 1990-2004 Paul Vojta and others
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * NOTE: xdvi is based on prior work, as noted in the modification history in
23 * xdvi.c.
24 *
25 */
26
27 /*
28 * Implementation of the magnifier window.
29 */
30
31 #include <math.h>
32
33 #include "xdvi-config.h"
34 /* one of the following should define OPEN_MAX: */
35 #include <limits.h>
36 #include "c-openmx.h"
37
38 #include "xdvi.h"
39
40 #ifdef MOTIF
41 #include <Xm/Xm.h>
42 #endif
43
44 #include "events.h"
45 #include "dvi-draw.h"
46 #include "dvi-init.h"
47 #include "statusline.h"
48 #include "hypertex.h"
49 #include "mag.h"
50 #include "xm_toolbar.h"
51 #include "xm_menu.h" /* for get_last_ungrab() */
52 #include "util.h"
53 #include "pagesel.h"
54
55 #if HAVE_XKB_BELL_EXT
56 # include <X11/XKBlib.h>
57 # define XdviBell(display, window, percent) \
58 XkbBell(display, window, percent, (Atom) None)
59 #else
60 # define XdviBell(display, window, percent) XBell(display, percent)
61 #endif
62
63 /* to measure distance of pointer from ruler in ruler mode */
64 static int g_ruler_pos_x = 0, g_ruler_pos_y = 0;
65
66 struct WindowRec magnifier = { (Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0 };
67
68 /*
69 * Mechanism to keep track of the magnifier window. The problems are,
70 *
71 * - if the button is released while the window is being drawn, this could
72 * cause an X error if we continue drawing in it after it is destroyed, and
73 *
74 * - creating and destroying the window too quickly confuses the window
75 * manager, which is avoided by waiting for an expose event before destroying
76 * it.
77 */
78
79 short magnifier_stat; /* 1 = wait for expose, -1 = destroy upon expose */
80
81 static Position main_x;
82 static Position main_y;
83
84 static Position mag_x = 0;
85 static Position mag_y = 0;
86
87 /* Under Motif the following two remain always constant */
88 static int mag_conv_x = 0;
89 static int mag_conv_y = 0;
90
91 static Position new_mag_x = 0;
92 static Position new_mag_y = 0;
93
94
95 /* default magnifier dimensions */
96 static struct mg_size_rec {
97 int w;
98 int h;
99 } mg_size[] = {
100 {200, 150}, {400, 250}, {700, 500}, {1000, 800}, {1200, 1200}
101 };
102
get_magglass_items(void)103 size_t get_magglass_items(void) {
104 return XtNumber(mg_size);
105 }
106
get_magglass_width(int idx)107 int get_magglass_width(int idx) {
108 return mg_size[idx].w;
109 }
110
get_magglass_height(int idx)111 int get_magglass_height(int idx) {
112 return mg_size[idx].h;
113 }
114
set_magglass_widht(int idx,int w)115 void set_magglass_widht(int idx, int w) {
116 mg_size[idx].w = w;
117 }
118
set_magglass_height(int idx,int h)119 void set_magglass_height(int idx, int h) {
120 mg_size[idx].h = h;
121 }
122
123
124 static void
can_exposures(struct WindowRec * windowrec)125 can_exposures(struct WindowRec *windowrec)
126 {
127 windowrec->min_x = windowrec->min_y = MAXDIM;
128 windowrec->max_x = windowrec->max_y = 0;
129 }
130
131 static void
mag_motion(XEvent * event)132 mag_motion(XEvent * event)
133 {
134 MYTRACE((stderr, "mag_motion!\n"));
135 new_mag_x = event->xmotion.x + mag_conv_x;
136 main_x = event->xmotion.x_root - new_mag_x;
137 new_mag_y = event->xmotion.y + mag_conv_y;
138 main_y = event->xmotion.y_root - new_mag_y;
139
140 if (new_mag_x != mag_x || new_mag_y != mag_y)
141 globals.ev.flags |= EV_MAG_MOVE;
142 else
143 globals.ev.flags &= ~EV_MAG_MOVE;
144 }
145
146 void
mag_release(XEvent * event)147 mag_release(XEvent * event)
148 {
149 UNUSED(event);
150 if (magnifier.win != (Window) 0) {
151 if (magnifier_stat) {
152 magnifier_stat = -1; /* destroy upon expose */
153 }
154 else {
155 XDestroyWindow(DISP, magnifier.win);
156 if (drawing_mag) {
157 globals.ev.flags |= EV_MAG_GONE;
158 }
159 magnifier.win = (Window) 0;
160 mouse_motion = mouse_release = null_mouse;
161 globals.ev.flags &= ~EV_MAG_MOVE;
162 globals.cursor.flags &= ~CURSOR_MAG;
163 globals.ev.flags |= EV_CURSOR;
164 can_exposures(&magnifier);
165 /*
166 Workaround for bug #703304:
167 For obscure reasons, XFree 3.3.5 (and apparently also Solaris 8)
168 doesn't generate an expose event after the magnifier has beed
169 destroyed. But only a redraw() event caused by expose would reset
170 currwin.win back to mane.win, which is needed e.g. for getting the
171 hyperlink info updated (otherwise, the mouse will not become active
172 over a hyperlink).
173
174 Forcing a redraw with
175 redraw(&mane);
176 may cause a `BadDrawable' X error with color material (e.g. from #702288),
177 or a `draw_part: shouldn't happen: POST encountered' error. Neither do
178 the following work:
179 globals.ev.flags |= EV_EXPOSE; (doesn't fix the bug)
180 draw_page(); (same effect as redraw(&mane))
181 globals.ev.flags |= EV_NEWPAGE; (works, but is crude and causes flicker)
182
183 So I decided to use expose() for the time being, which
184 sets mane.min_x to the current x point (which doesn't happen
185 with EV_EXPOSE; this causes the test for `mane.min_x < MAXDIM'
186 to fail in events.c; look for `see comment in mag.c').
187 */
188 /* fprintf(stderr, "========triggering expose!\n"); */
189 expose(&mane, event->xbutton.x_root, event->xbutton.y_root, 10, 10);
190 }
191 }
192 }
193
194 static int
tick_scale(int k)195 tick_scale(int k)
196 {
197 if (k == 0)
198 return 3;
199 else if ((k % 1000) == 0)
200 return 7;
201 else if ((k % 500) == 0)
202 return 6;
203 else if ((k % 100) == 0)
204 return 5;
205 else if ((k % 50) == 0)
206 return 4;
207 else if ((k % 10) == 0)
208 return 3;
209 else if ((k % 5) == 0)
210 return 2;
211 else
212 return 1;
213 }
214
215 static void
draw_ticks(unsigned int width,unsigned int height,GC ourGC)216 draw_ticks(unsigned int width, unsigned int height, GC ourGC)
217 {
218 int k; /* tick counter */
219 double old_pixels_per_tick;
220 double pixels_per_tick;
221 int scale;
222 int tick_offset; /* offset along axes */
223 int x; /* coordinates of top-left popup */
224 int y; /* window corner */
225 double xx; /* coordinates of tick */
226 double yy; /* coordinates of tick */
227 static char *last_tick_units = ""; /* memory of last tick units */
228
229 if (resource.tick_length <= 0) /* user doesn't want tick marks */
230 return;
231
232 x = 0; /* the pop-up window always has origin (0,0) */
233 y = 0;
234
235 /* We need to clear the existing window to remove old rulers. I think
236 that this could be avoided if draw_ticks() could be invoked earlier.
237 The expose argument in XClearArea() must be True to force redrawing
238 of the text inside the popup window. Also, it would be better to draw
239 the rulers before painting the text, so that rulers would not
240 overwrite the text, but I haven't figured out yet how to arrange
241 that. */
242
243 XClearArea(DISP, magnifier.win, x, y, width, height, True);
244
245 /* The global resource.pixels_per_inch tells us how to find the ruler
246 scale. For example, 300dpi corresponds to these TeX units:
247
248 1 TeX point (pt) = 4.151 pixels
249 1 big point (bp) = 4.167 pixels
250 1 pica (pc) = 49.813 pixels
251 1 cicero (cc) = 53.501 pixels
252 1 didot point (dd) = 4.442 pixels
253 1 millimeter (mm) = 11.811 pixels
254 1 centimeter (cm) = 118.110 pixels
255 1 inch (in) = 300.000 pixels
256 1 scaled point (sp) = 0.00006334 pixels
257
258 The user can select the units via a resource (e.g. XDvi*tickUnits: bp),
259 or a command-line option (e.g. -xrm '*tickUnits: cm'). The length of
260 the ticks can be controlled by a resource (e.g. XDvi*tickLength: 10), or
261 a command-line option (e.g. -xrm '*tickLength: 10000'). Zero, or negative,
262 tick length completely suppresses rulers. */
263
264 pixels_per_tick = (double)resource.pixels_per_inch;
265 if (strcmp(resource.tick_units, "pt") == 0)
266 pixels_per_tick /= 72.27;
267 else if (strcmp(resource.tick_units, "bp") == 0)
268 pixels_per_tick /= 72.0;
269 else if (strcmp(resource.tick_units, "in") == 0)
270 /* NO-OP */ ;
271 else if (strcmp(resource.tick_units, "cm") == 0)
272 pixels_per_tick /= 2.54;
273 else if (strcmp(resource.tick_units, "mm") == 0)
274 pixels_per_tick /= 25.4;
275 else if (strcmp(resource.tick_units, "dd") == 0)
276 pixels_per_tick *= (1238.0 / 1157.0) / 72.27;
277 else if (strcmp(resource.tick_units, "cc") == 0)
278 pixels_per_tick *= 12.0 * (1238.0 / 1157.0) / 72.27;
279 else if (strcmp(resource.tick_units, "pc") == 0)
280 pixels_per_tick *= 12.0 / 72.27;
281 else if (strcmp(resource.tick_units, "sp") == 0)
282 pixels_per_tick /= (65536.0 * 72.27);
283 else if (strcmp(resource.tick_units, "px") == 0)
284 pixels_per_tick = 10;
285 else {
286 XDVI_WARNING((stderr, "Unrecognized tickUnits [%s]: defaulting to TeX points [pt]",
287 resource.tick_units));
288 resource.tick_units = "pt";
289 pixels_per_tick /= 72.27;
290 }
291
292 /* To permit accurate measurement in the popup window, we can reasonably
293 * place tick marks about 3 to 10 pixels apart, so we scale the computed
294 * pixels_per_tick by a power of ten to bring it into that range.
295 */
296
297 old_pixels_per_tick = pixels_per_tick; /* remember the original scale */
298 while (pixels_per_tick < 3.0)
299 pixels_per_tick *= 10.0;
300 while (pixels_per_tick > 30.0)
301 pixels_per_tick /= 10.0;
302
303 /* tell user what the ruler scale is, but only when it changes */
304 if (strcmp(last_tick_units, resource.tick_units) != 0) {
305 if (old_pixels_per_tick != pixels_per_tick)
306 printf("Ruler tick interval adjusted to represent %.2f%s\n",
307 pixels_per_tick / old_pixels_per_tick, resource.tick_units);
308 else if (globals.debug & DBG_EVENT)
309 printf("Ruler tick interval represents 1%s\n", resource.tick_units);
310 }
311
312 /* In order to make the ruler as accurate as possible, given the coarse
313 * screen resolution, we compute tick positions in floating-point
314 * arithmetic, then round to nearest integer values.
315 */
316
317 /* draw vertical ticks on top and bottom */
318 for (k = 0, xx = 0.0; xx < (double)width; k++, xx += pixels_per_tick) {
319 tick_offset = (int)(0.5 + xx); /* round to nearest pixel */
320 scale = tick_scale(k);
321 XDrawLine(DISP, magnifier.win, ourGC,
322 x + tick_offset, y, x + tick_offset, y + scale * resource.tick_length);
323 XDrawLine(DISP, magnifier.win, ourGC,
324 x + tick_offset, y + height,
325 x + tick_offset, y + height - scale * resource.tick_length);
326 }
327
328 /* draw horizontal ticks on left and right */
329 for (k = 0, yy = 0.0; yy < (double)height; k++, yy += pixels_per_tick) {
330 tick_offset = (int)(0.5 + yy); /* round to nearest pixel */
331 scale = tick_scale(k);
332 XDrawLine(DISP, magnifier.win, ourGC,
333 x, y + tick_offset, x + scale * resource.tick_length, y + tick_offset);
334 XDrawLine(DISP, magnifier.win, ourGC,
335 x + width, y + tick_offset,
336 x + width - scale * resource.tick_length, y + tick_offset);
337 }
338
339 last_tick_units = resource.tick_units;
340
341 XFlush(DISP); /* bring window up-to-date */
342 }
343
344 static void
compute_mag_pos(int * xp,int * yp)345 compute_mag_pos(int *xp, int *yp)
346 {
347 int t;
348
349 t = mag_x + main_x - magnifier.width / 2;
350 if (t > WidthOfScreen(SCRN) - (int)magnifier.width - 2 * MAGBORD)
351 t = WidthOfScreen(SCRN) - (int)magnifier.width - 2 * MAGBORD;
352 if (t < 0)
353 t = 0;
354 *xp = t;
355 t = mag_y + main_y - magnifier.height / 2;
356 if (t > HeightOfScreen(SCRN) - (int)magnifier.height - 2 * MAGBORD)
357 t = HeightOfScreen(SCRN) - (int)magnifier.height - 2 * MAGBORD;
358 if (t < 0)
359 t = 0;
360 *yp = t;
361 }
362
363 static void
scroll_window(struct WindowRec * windowrec,int x0,int y0)364 scroll_window(struct WindowRec *windowrec, int x0, int y0)
365 {
366 int x, y;
367 int x2 = 0, y2 = 0;
368 int ww, hh;
369
370 x = x0 - windowrec->base_x;
371 y = y0 - windowrec->base_y;
372 ww = windowrec->width - x;
373 hh = windowrec->height - y;
374 windowrec->base_x = x0;
375 windowrec->base_y = y0;
376 if (currwin.win == windowrec->win) {
377 currwin.base_x = x0;
378 currwin.base_y = y0;
379 }
380 windowrec->min_x -= x;
381 if (windowrec->min_x < 0)
382 windowrec->min_x = 0;
383 windowrec->max_x -= x;
384 if ((unsigned int)windowrec->max_x > windowrec->width)
385 windowrec->max_x = windowrec->width;
386 windowrec->min_y -= y;
387 if (windowrec->min_y < 0)
388 windowrec->min_y = 0;
389 windowrec->max_y -= y;
390 if ((unsigned int)windowrec->max_y > windowrec->height)
391 windowrec->max_y = windowrec->height;
392 if (x < 0) {
393 x2 = -x;
394 x = 0;
395 ww = windowrec->width - x2;
396 }
397 if (y < 0) {
398 y2 = -y;
399 y = 0;
400 hh = windowrec->height - y2;
401 }
402 if (ww <= 0 || hh <= 0) {
403 XClearWindow(DISP, windowrec->win);
404 windowrec->min_x = windowrec->min_y = 0;
405 windowrec->max_x = windowrec->width;
406 windowrec->max_y = windowrec->height;
407 }
408 else {
409 XCopyArea(DISP, windowrec->win, windowrec->win, globals.gc.copy,
410 x, y, (unsigned int)ww, (unsigned int)hh, x2, y2);
411 if (x > 0)
412 clearexpose(windowrec, ww, 0, (unsigned int)x, windowrec->height);
413 if (x2 > 0)
414 clearexpose(windowrec, 0, 0, (unsigned int)x2, windowrec->height);
415 if (y > 0)
416 clearexpose(windowrec, 0, hh, windowrec->width, (unsigned int)y);
417 if (y2 > 0)
418 clearexpose(windowrec, 0, 0, windowrec->width, (unsigned int)y2);
419 }
420 }
421
422 static void
do_movemag(int x,int y)423 do_movemag(int x, int y)
424 {
425 int xx, yy;
426
427 mag_x = x;
428 mag_y = y;
429 if (mag_x == new_mag_x && mag_y == new_mag_y)
430 globals.ev.flags &= ~EV_MAG_MOVE;
431 compute_mag_pos(&xx, &yy);
432 XMoveWindow(DISP, magnifier.win, xx, yy);
433 scroll_window(&magnifier,
434 (x + mane_base_x) * mane.shrinkfactor - (int)magnifier.width / 2,
435 (y + mane_base_y) * mane.shrinkfactor - (int)magnifier.height / 2);
436 draw_ticks(magnifier.width, magnifier.height, globals.gc.ruler);
437 }
438
439 extern jmp_buf next_env;
440
441 void
show_distance_from_ruler(XEvent * event,Boolean to_stdout)442 show_distance_from_ruler(XEvent *event, Boolean to_stdout)
443 {
444 int loc_x, loc_y;
445 int precision = 2;
446 double factor;
447
448 if (event == NULL) /* when option is toggled */
449 return;
450
451 loc_x = event->xbutton.x;
452 loc_y = event->xbutton.y;
453 if (event->xbutton.window != mane.win) {
454 Window ww;
455 (void)XTranslateCoordinates(DISP,
456 RootWindowOfScreen(SCRN), mane.win,
457 event->xbutton.x_root,
458 event->xbutton.y_root,
459 &loc_x,
460 &loc_y,
461 &ww); /* throw away last argument */
462 }
463
464 /* map everything below 0 to the origin */
465 if (loc_x < 0)
466 loc_x = 0;
467 if (loc_y < 0)
468 loc_y = 0;
469
470 if (strcmp(resource.tick_units, "pt") == 0) {
471 factor = 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
472 }
473 else if (strcmp(resource.tick_units, "bp") == 0) {
474 factor = 72.0 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
475 }
476 else if (strcmp(resource.tick_units, "in") == 0) {
477 factor = currwin.shrinkfactor / (double)resource.pixels_per_inch;
478 }
479 else if (strcmp(resource.tick_units, "cm") == 0) {
480 factor = 2.54 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
481 precision = 3;
482 }
483 else if (strcmp(resource.tick_units, "mm") == 0) {
484 factor = 25.4 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
485 }
486 else if (strcmp(resource.tick_units, "dd") == 0) {
487 factor = 72.27 / (1238.0 / 1157.0) * currwin.shrinkfactor / (double)resource.pixels_per_inch;
488 }
489 else if (strcmp(resource.tick_units, "cc") == 0) {
490 factor = 72.27 / (12.0 * (1238.0 / 1157.0)) * currwin.shrinkfactor / (double)resource.pixels_per_inch;
491 }
492 else if (strcmp(resource.tick_units, "pc") == 0) {
493 factor = 72.27 / 12.0 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
494 }
495 else if (strcmp(resource.tick_units, "sp") == 0) {
496 factor = 65536.0 * 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
497 precision = 1;
498 }
499 else if (strcmp(resource.tick_units, "px") == 0) { /* pixel units */
500 factor = 1;
501 }
502 else {
503 XDVI_WARNING((stderr, "Unrecognized tickUnits [%s]: defaulting to TeX points [pt]",
504 resource.tick_units));
505 resource.tick_units = "pt";
506 factor = 72.27 * currwin.shrinkfactor / (double)resource.pixels_per_inch;
507 }
508
509 if (mouse_release != null_mouse) {
510 if (to_stdout) {
511 XDVI_INFO((stdout, "Ruler/Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
512 loc_x, loc_y,
513 precision, 0.000, resource.tick_units,
514 precision, 0.000, resource.tick_units,
515 precision, 0.000, resource.tick_units));
516 }
517 else {
518 statusline_info(STATUS_FOREVER,
519 "Ruler/Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dt: %.*f %s",
520 loc_x, loc_y,
521 precision, 0.000, resource.tick_units,
522 precision, 0.000, resource.tick_units,
523 precision, 0.000, resource.tick_units);
524 }
525 }
526 else {
527 int d_x = loc_x - g_ruler_pos_x;
528 int d_y = loc_y - g_ruler_pos_y;
529 double d_z = sqrt((double)d_x * d_x + (double)d_y * d_y);
530 double unit_x = (double)d_x * factor;
531 double unit_y = (double)d_y * factor;
532 double unit_z = d_z * factor;
533 if (to_stdout) {
534 XDVI_INFO((stdout, "Ruler: %d,%d, Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
535 g_ruler_pos_x, g_ruler_pos_y, loc_x, loc_y,
536 precision, unit_x, resource.tick_units,
537 precision, unit_y, resource.tick_units,
538 precision, unit_z, resource.tick_units));
539 }
540 else {
541 statusline_info(STATUS_FOREVER,
542 "Ruler: %d,%d, Point: %d,%d, dx: %.*f %s, dy: %.*f %s, dr: %.*f %s",
543 g_ruler_pos_x, g_ruler_pos_y, loc_x, loc_y,
544 precision, unit_x, resource.tick_units,
545 precision, unit_y, resource.tick_units,
546 precision, unit_z, resource.tick_units);
547 }
548 }
549 }
550
551 void
move_magnifier(void)552 move_magnifier(void)
553 {
554 if (magnifier.win == (Window) 0)
555 globals.ev.flags &= ~EV_MAG_MOVE;
556 else if (abs(new_mag_x - mag_x) > 2 * abs(new_mag_y - mag_y))
557 do_movemag(new_mag_x, mag_y);
558 else if (abs(new_mag_y - mag_y) > 2 * abs(new_mag_x - mag_x))
559 do_movemag(mag_x, new_mag_y);
560 else
561 do_movemag(new_mag_x, new_mag_y);
562 }
563
564
565 void
clear_ruler(void)566 clear_ruler(void)
567 {
568 /* maybe we should do this only for mouse-1? */
569 clearexpose(&mane, 0, g_ruler_pos_y,
570 ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2, 1);
571 clearexpose(&mane, g_ruler_pos_x, 0,
572 1, ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2);
573 }
574
575 void
show_ruler(XEvent * event)576 show_ruler(XEvent *event)
577 {
578 if (mouse_release == null_mouse) {
579 if (mouse_release != null_mouse && mouse_release != drag_ruler_release)
580 return;
581 if (mouse_release == null_mouse) {
582 mouse_motion = drag_ruler_motion;
583 mouse_release = drag_ruler_release;
584 }
585 drag_ruler_motion(event);
586 }
587 }
588
589 static void
draw_ruler(int x,int y)590 draw_ruler(int x, int y)
591 {
592 /* don't draw if outside page region (will be clipped automatically by Motif,
593 but not by Xaw, where draw widget is entire window) */
594 if (x > (int)ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 1
595 || y > (int)ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 1)
596 return;
597
598 XFillRectangle(DISP, mane.win, globals.gc.high,
599 0, y,
600 ROUNDUP(pageinfo_get_page_width(current_page), currwin.shrinkfactor) + 2, 1);
601 XFillRectangle(DISP, mane.win, globals.gc.high,
602 x, 0,
603 1, ROUNDUP(pageinfo_get_page_height(current_page), currwin.shrinkfactor) + 2);
604 }
605
606
607 /* snap ruler back to origing (0,0) */
608 void
ruler_snap_origin(XEvent * event)609 ruler_snap_origin(XEvent *event)
610 {
611 clear_ruler();
612 g_ruler_pos_x = g_ruler_pos_y = 0;
613 draw_ruler(g_ruler_pos_x, g_ruler_pos_y);
614 /* deactivate mouse dragging */
615 mouse_motion = mouse_release = null_mouse;
616 show_distance_from_ruler(event, False);
617 }
618
619 void
redraw_ruler(void)620 redraw_ruler(void)
621 {
622 draw_ruler(g_ruler_pos_x, g_ruler_pos_y);
623 }
624
magnifier_move(String params,XEvent * event)625 void magnifier_move(String params, XEvent *event)
626 {
627 int x, y;
628 XSetWindowAttributes attr;
629 #ifndef MOTIF
630 Window throwaway;
631 #endif
632 const char *p = params;
633
634 if (*p == '*') {
635 int n = atoi(p + 1) - 1;
636
637 if (n < 0 || n >= (int)get_magglass_items() || get_magglass_width(n) <= 0) {
638 XdviBell(DISP, event->xany.window, 0);
639 return;
640 }
641 magnifier.width = get_magglass_width(n);
642 magnifier.height = get_magglass_height(n);
643 }
644 else {
645 magnifier.width = magnifier.height = atoi(p);
646 p = strchr(p, 'x');
647 if (p != NULL) {
648 magnifier.height = atoi(p + 1);
649 if (magnifier.height == 0)
650 magnifier.width = 0;
651 }
652 if (magnifier.width == 0) {
653 XdviBell(DISP, event->xany.window, 0);
654 return;
655 }
656 }
657 #ifndef MOTIF
658 XTranslateCoordinates(DISP, event->xbutton.window, mane.win,
659 0, 0, &mag_conv_x, &mag_conv_y, &throwaway);
660 #endif
661
662 mag_x = event->xbutton.x + mag_conv_x;
663 mag_y = event->xbutton.y + mag_conv_y;
664 main_x = event->xbutton.x_root - mag_x;
665 main_y = event->xbutton.y_root - mag_y;
666 compute_mag_pos(&x, &y);
667 magnifier.base_x = (mag_x + mane_base_x) * mane.shrinkfactor - magnifier.width / 2;
668 magnifier.base_y = (mag_y + mane_base_y) * mane.shrinkfactor - magnifier.height / 2;
669 attr.save_under = True;
670 attr.border_pixel = resource.rule_pixel;
671 #if COLOR
672 attr.background_pixel = bg_current->pixel;
673 #else
674 attr.background_pixel = resource.back_Pixel;
675 #endif
676 attr.override_redirect = True;
677 #ifdef GREY
678 attr.colormap = G_colormap;
679 #endif
680 magnifier.win = XCreateWindow(DISP, RootWindowOfScreen(SCRN),
681 x, y, magnifier.width, magnifier.height, MAGBORD,
682 G_depth, InputOutput, G_visual,
683 CWSaveUnder | CWBorderPixel | CWBackPixel |
684 #ifdef GREY
685 CWColormap |
686 #endif
687 CWOverrideRedirect, &attr);
688 XSelectInput(DISP, magnifier.win, ExposureMask);
689 XMapWindow(DISP, magnifier.win);
690
691 /*
692 * This call will draw the point rulers when the magnifier first pops up,
693 * if the XDvi*delayRulers resource is false. Some users may prefer rulers
694 * to remain invisible until the magnifier is moved, so the default is
695 * true. Rulers can be suppressed entirely by setting the XDvi*tickLength
696 * resource to zero or negative.
697 */
698
699 if (!resource.delay_rulers)
700 draw_ticks(magnifier.width, magnifier.height, globals.gc.ruler);
701
702 globals.cursor.flags |= CURSOR_MAG;
703 globals.ev.flags |= EV_CURSOR;
704
705 magnifier_stat = 1; /* waiting for exposure */
706 mouse_motion = mag_motion;
707 mouse_release = mag_release;
708 }
709
710 void
drag_ruler_motion(XEvent * event)711 drag_ruler_motion(XEvent *event)
712 {
713 int loc_x, loc_y;
714 if (event == NULL) { /* toggled via menu */
715 /* hack to avoid redrawing ruler at last g_* positions when mode is
716 toggled on via menu, then off via keystroke */
717 g_ruler_pos_x = g_ruler_pos_y = 0;
718 return;
719 }
720
721 loc_x = event->xbutton.x;
722 loc_y = event->xbutton.y;
723
724 if (event->xbutton.window != mane.win) {
725 Window dummy;
726 (void)XTranslateCoordinates(DISP,
727 RootWindowOfScreen(SCRN), mane.win,
728 event->xbutton.x_root,
729 event->xbutton.y_root,
730 &loc_x,
731 &loc_y,
732 &dummy);
733 }
734
735 /* map everything below 0 to the origin */
736 if (loc_x < 0)
737 loc_x = 0;
738 if (loc_y < 0)
739 loc_y = 0;
740
741 clear_ruler();
742 draw_ruler(loc_x, loc_y);
743 g_ruler_pos_x = loc_x;
744 g_ruler_pos_y = loc_y;
745 }
746
747 void
drag_ruler_release(XEvent * event)748 drag_ruler_release(XEvent *event)
749 {
750 UNUSED(event);
751 mouse_motion = mouse_release = null_mouse;
752 }
753
754 /* XtActionsRec mag_actions[] = { */
755 /* {"magnifier", Act_magnifier}, */
756 /* {"do-href", Act_href}, */
757 /* {"do-href-newwindow", Act_href_newwindow}, */
758 /* {"switch-magnifier-units", Act_switch_magnifier_units}, */
759 /* }; */
760
761 /*
762 * This isn't creating the actual magnifier. It is created lazily on demand
763 * if one of the corresponding actions is taken. Therefore we are here
764 * just adding the record of actions related to magnifier handling to the
765 * application.
766 */
767
768 /* void */
769 /* create_magnifier(void) */
770 /* { */
771 /* XtAppAddActions(globals.app, mag_actions, XtNumber(mag_actions)); */
772 /* } */
773