1 /*
2 * xvevent.c - EventLoop and support routines for XV
3 *
4 * Author: John Bradley, University of Pennsylvania
5 * (bradley@cis.upenn.edu)
6 *
7 * Contains:
8 * int EventLoop()
9 * void DrawWindow(x,y,w,h)
10 * void WResize(w,h)
11 * void WRotate()
12 * void WCrop(w,h,dx,dy)
13 * void WUnCrop()
14 * void GetWindowPos(&xwa)
15 * void SetWindowPos(&xwa)
16 * void SetEpicMode()
17 * int xvErrorHandler(disp, err)
18 */
19
20 #include "copyright.h"
21
22 #define NEEDSTIME /* for -wait handling in eventloop */
23
24 #include "xv.h"
25
26 #include "bits/dropper"
27 #include "bits/dropperm"
28 #include "bits/pen"
29 #include "bits/penm"
30 #include "bits/blur"
31 #include "bits/blurm"
32
33 static int rotatesLeft = 0;
34 static int origcropx, origcropy, origcropvalid=0;
35 static int canstartwait;
36 static int frominterrupt = 0;
37 static char *xevPriSel = NULL;
38 static Time lastEventTime;
39 static Cursor dropper = 0, pen = 0, blur = 0;
40
41
42 static void SelectDispMB PARM((int));
43 static void Select24to8MB PARM((int));
44 static void SelectRootMB PARM((int));
45 static void SelectWindowMB PARM((int));
46 static void SelectSizeMB PARM((int));
47
48 static void DoPrint PARM((void));
49 static void debugEvent PARM((XEvent *));
50 static const char *win2name PARM((Window));
51 static void handleButtonEvent PARM((XEvent *, int *, int *));
52 static void handleKeyEvent PARM((XEvent *, int *, int *));
53 static void zoomCurs PARM((u_int));
54 static void textViewCmd PARM((void));
55 static void setSizeCmd PARM((void));
56 static void WMaximize PARM((void));
57 static void CropKey PARM((int, int, int, int));
58 static void TrackPicValues PARM((int, int));
59 static int CheckForConfig PARM((void));
60 static Bool IsConfig PARM((Display *, XEvent *, char *));
61 static void onInterrupt PARM((int));
62
63 static void Paint PARM((void));
64 static void paintPixel PARM((int, int));
65 static void paintLine PARM((int, int, int, int));
66 static void paintXLine PARM((int, int, int, int, int));
67 static void BlurPaint PARM((void));
68 static int highbit PARM((u_long));
69 static u_long RGBToXColor PARM((int, int, int));
70 static void blurPixel PARM((int, int));
71
72 static void annotatePic PARM((void));
73
74 static int debkludge_offx;
75 static int debkludge_offy;
76
77 /****************/
EventLoop()78 int EventLoop()
79 /****************/
80 {
81 XEvent event;
82 int retval,done,waiting;
83 #ifdef USE_TICKS
84 clock_t waitsec_ticks=0L, orgtime_ticks=0L, curtime_ticks;
85 clock_t elapsed_ticks=0L, remaining_interval;
86 #else
87 time_t orgtime=0L, curtime;
88 #endif
89
90
91 #ifndef NOSIGNAL
92 signal(SIGQUIT, onInterrupt);
93 #endif
94
95 if (startGrab == 1) {
96 startGrab = 2;
97 FakeButtonPress(&but[BGRAB]);
98 FakeKeyPress(ctrlW, XK_Return);
99 return(1);
100 }
101
102 /* note: there's no special event handling if we're using the root window.
103 if we're using the root window, we will recieve NO events for mainW */
104
105 /* note: 'canstartwait' is magically turned 'true' in HandleEvent when I
106 think I've finally gotten 'mainW' drawn. It does not necessarily
107 mean that any waiting is/will be done. Also note that if we're
108 using a root mode, canstartwait is instantly turned on, as we aren't
109 going to be getting Expose/Configure events on the root window */
110
111 done = retval = waiting = canstartwait = 0;
112
113 if (useroot) canstartwait = 1;
114 else if (mainW) { /* if mainW iconified, start wait now */
115 XWindowAttributes xwa;
116 XSync(theDisp, False);
117 if (XGetWindowAttributes(theDisp, mainW, &xwa)) {
118 if (xwa.map_state != IsViewable) canstartwait = 1;
119 }
120 }
121
122 while (!done) {
123
124 if (waitsec >= 0.0 && canstartwait && !waiting && XPending(theDisp)==0) {
125 /* we wanna wait, we can wait, we haven't started waiting yet, and
126 all pending events (ie, drawing the image the first time)
127 have been dealt with: START WAITING */
128 #ifdef USE_TICKS
129 waitsec_ticks = (clock_t)(waitsec * CLK_TCK);
130 orgtime_ticks = times(NULL); /* unclear if NULL valid, but OK on Linux */
131 #else
132 orgtime = time(NULL);
133 #endif
134 waiting = 1;
135 }
136
137
138 /* if there's an XEvent pending *or* we're not doing anything
139 in real-time (polling, flashing the selection, etc.) get next event */
140 if ((waitsec<0.0 && !polling && !HaveSelection()) || XPending(theDisp)>0)
141 {
142 XNextEvent(theDisp, &event);
143 retval = HandleEvent(&event,&done);
144 }
145
146 else { /* no events. check wait status */
147 if (HaveSelection()) {
148 DrawSelection(0);
149 DrawSelection(1);
150 XFlush(theDisp);
151 Timer(200); /* milliseconds */
152 }
153
154 if (polling) {
155 if (CheckPoll(2)) return POLLED;
156 else if (!XPending(theDisp)) sleep(1);
157 }
158
159 if (waitsec>=0.0 && waiting) {
160 #ifdef USE_TICKS
161 curtime_ticks = times(NULL); /* value in ticks */
162 if (curtime_ticks < orgtime_ticks) {
163 /* clock ticks rolled over: need to correct for that (i.e.,
164 * curtime_ticks is presumably quite small, while orgtime_ticks
165 * should be close to LONG_MAX, so do math accordingly--any way
166 * to check whether clock_t is *not* a signed long?) */
167 elapsed_ticks = curtime_ticks + (LONG_MAX - orgtime_ticks);
168 } else
169 elapsed_ticks = curtime_ticks - orgtime_ticks;
170 remaining_interval = waitsec_ticks - elapsed_ticks;
171 if (remaining_interval >= (clock_t)(1 * CLK_TCK))
172 sleep(1);
173 else {
174 /* less than one second remaining: do delay in msec, then return */
175 Timer((remaining_interval * 1000L) / CLK_TCK); /* can't overflow */
176 return waitloop? NEXTLOOP : NEXTQUIT;
177 }
178 #else
179 curtime = time(NULL); /* value in seconds */
180 if (curtime - orgtime < (time_t)waitsec)
181 sleep(1);
182 else
183 return waitloop? NEXTLOOP : NEXTQUIT;
184 #endif
185 }
186 }
187 } /* while (!done) */
188
189 if (!useroot && origcropvalid) WUnCrop();
190 origcropvalid = 0;
191
192 return(retval);
193 }
194
195
196
197 /****************/
HandleEvent(event,donep)198 int HandleEvent(event, donep)
199 XEvent *event;
200 int *donep;
201 {
202 static int wasInfoUp=0, wasCtrlUp=0, wasDirUp=0, wasGamUp=0, wasPsUp=0;
203 #ifdef HAVE_JPEG
204 static int wasJpegUp=0;
205 #endif
206 #ifdef HAVE_JP2K
207 static int wasJp2kUp=0;
208 #endif
209 #ifdef HAVE_TIFF
210 static int wasTiffUp=0;
211 #endif
212 #ifdef HAVE_PNG
213 static int wasPngUp=0;
214 #endif
215 #ifdef HAVE_PCD
216 static int wasPcdUp=0;
217 #endif
218 #ifdef HAVE_PIC2
219 static int wasPic2Up=0;
220 #endif
221 #ifdef HAVE_MGCSFX
222 static int wasMgcSfxUp=0;
223 #endif
224
225 static int mainWKludge=0; /* force first mainW expose after a mainW config
226 to redraw all of mainW */
227
228 int done=0, retval=0;
229
230
231 if (DEBUG) debugEvent((XEvent *) event);
232
233
234 switch (event->type) {
235
236 case ButtonPress:
237 lastEventTime = ((XButtonEvent *) event)->time;
238 handleButtonEvent(event, &done, &retval);
239 break;
240
241
242 case KeyRelease:
243 case KeyPress:
244 lastEventTime = ((XKeyEvent *) event)->time;
245 handleKeyEvent(event, &done, &retval);
246 break;
247
248
249 case Expose: {
250 XExposeEvent *exp_event = (XExposeEvent *) event;
251 int x,y,w,h;
252 Window win;
253
254 #ifdef VMS
255 static int borders_sized = 0;
256
257 if (!borders_sized && !useroot && exp_event->window == mainW) {
258 /*
259 * Initial expose of main window, find the size of the ancestor
260 * window just prior to the root window and adjust saved size
261 * of display so that maximize functions will allow for window
262 * decorations.
263 */
264 int status, count, mwid, mhgt, x, y, w, h, b, d, mbrd;
265 Window root, parent, *children, crw = exp_event->window;
266 borders_sized = 1;
267 status = XGetGeometry(theDisp, crw,
268 &root, &x, &y, &mwid, &mhgt, &mbrd, &d);
269
270 for ( parent = crw, w=mwid, h=mhgt;
271 status && (parent != root) && (parent != vrootW); ) {
272 crw = parent;
273 status = XQueryTree ( theDisp, crw, &root, &parent,
274 &children, &count );
275 if ( children != NULL ) XFree ( children );
276 }
277 status = XGetGeometry(theDisp, crw, &root, &x, &y, &w, &h, &b, &d);
278 if ( status ) {
279 dispWIDE = dispWIDE + mwid - w + (2*b);
280 dispHIGH = dispHIGH + mhgt - h + b;
281 /*printf("New display dims: %d %d\n", dispWIDE, dispHIGH ); */
282 }
283 }
284 #endif
285
286
287 win = exp_event->window;
288 x = exp_event->x; y = exp_event->y;
289 w = exp_event->width; h = exp_event->height;
290
291 if (PUCheckEvent (event)) break; /* event has been processed */
292 if (PSCheckEvent (event)) break; /* event has been processed */
293
294 #ifdef HAVE_JPEG
295 if (JPEGCheckEvent(event)) break; /* event has been processed */
296 #endif
297
298 #ifdef HAVE_JP2K
299 if (JP2KCheckEvent(event)) break; /* event has been processed */
300 #endif
301
302 #ifdef HAVE_TIFF
303 if (TIFFCheckEvent(event)) break; /* event has been processed */
304 #endif
305
306 #ifdef HAVE_PNG
307 if (PNGCheckEvent (event)) break; /* event has been processed */
308 #endif
309
310 if (PCDCheckEvent(event)) break; /* event has been processed */
311
312 #ifdef HAVE_PIC2
313 if (PIC2CheckEvent(event)) break; /* event has been processed */
314 #endif
315
316 #ifdef HAVE_PCD
317 if (PCDCheckEvent (event)) break; /* event has been processed */
318 #endif
319
320 #ifdef HAVE_MGCSFX
321 if (MGCSFXCheckEvent(event)) break; /* event has been processed */
322 #endif
323
324 #ifdef TV_MULTILINGUAL
325 if (CharsetCheckEvent(event)) break; /* event has been processed */
326 #endif
327
328 if (GamCheckEvent (event)) break; /* event has been processed */
329 if (BrowseCheckEvent (event, &retval, &done)) break; /* event eaten */
330 if (TextCheckEvent (event, &retval, &done)) break; /* event eaten */
331
332 /* if the window doesn't do intelligent redraw, drop but last expose */
333 if (exp_event->count>0 &&
334 win != mainW && win != ctrlW && win != dirW && win != infoW) break;
335
336
337
338 if (win == mainW && CheckForConfig()) {
339 if (DEBUG) fprintf(stderr,"Expose mainW ignored. Config pending.\n");
340 break;
341 }
342
343
344
345
346 if (win==mainW || win==ctrlW || win==dirW || win==infoW) {
347 /* must be a 'smart' window. group exposes into an expose 'region' */
348 int count;
349 Region reg;
350 XRectangle rect;
351 XEvent evt;
352
353 xvbcopy((char *) exp_event, (char *) &evt, sizeof(XEvent));
354 reg = XCreateRegion();
355 count = 0;
356
357 do {
358 rect.x = evt.xexpose.x;
359 rect.y = evt.xexpose.y;
360 rect.width = evt.xexpose.width;
361 rect.height = evt.xexpose.height;
362 XUnionRectWithRegion(&rect, reg, reg);
363 count++;
364
365 if (DEBUG) debugEvent((XEvent *) &evt);
366
367 } while (XCheckWindowEvent(theDisp,evt.xexpose.window,
368 ExposureMask, &evt));
369
370 XClipBox(reg, &rect); /* bounding box of region */
371 XSetRegion(theDisp, theGC, reg);
372
373 x = rect.x; y = rect.y;
374 w = rect.width; h = rect.height;
375
376 if (DEBUG) fprintf(stderr,"window: 0x%08x collapsed %d expose events\n",
377 (u_int) exp_event->window, count);
378 if (DEBUG) fprintf(stderr," region bounding box: %d,%d %dx%d\n",
379 x, y, w, h);
380
381
382 if (win == mainW) {
383 if (DEBUG) fprintf(stderr,"EXPOSE: ");
384 if (!CheckForConfig()) {
385
386 if (mainWKludge) {
387 if (DEBUG) fprintf(stderr, "Using mainWKludge\n");
388 x = 0; y = 0; w = eWIDE; h = eHIGH;
389 XSetClipMask(theDisp, theGC, None);
390 mainWKludge = 0;
391 }
392
393 if (DEBUG) fprintf(stderr,"No configs pending.\n");
394 /* if (DEBUG) XClearArea(theDisp, mainW, x,y,w,h, False); */
395 DrawWindow(x,y,w,h);
396
397 if (HaveSelection()) DrawSelection(0);
398
399 canstartwait = 1; /* finished drawing */
400 XSync(theDisp, False);
401 }
402 else
403 if (DEBUG) fprintf(stderr,"Ignored. Config pending\n");
404 }
405
406 else if (win == infoW) RedrawInfo(x,y,w,h);
407 else if (win == ctrlW) RedrawCtrl(x,y,w,h);
408 else if (win == dirW) RedrawDirW(x,y,w,h);
409
410 XSetClipMask(theDisp, theGC, None);
411 XDestroyRegion(reg);
412 }
413
414 else if (win == nList.win) LSRedraw(&nList,0);
415 else if (win == nList.scrl.win) SCRedraw(&nList.scrl);
416 else if (win == dList.win) LSRedraw(&dList,0);
417 else if (win == dList.scrl.win) SCRedraw(&dList.scrl);
418 else if (win == dnamW) RedrawDNamW();
419 }
420 break;
421
422
423
424 case ClientMessage: {
425 Atom proto, delwin;
426 XClientMessageEvent *client_event = (XClientMessageEvent *) event;
427
428 if (PUCheckEvent (event)) break; /* event has been processed */
429
430 proto = XInternAtom(theDisp, "WM_PROTOCOLS", FALSE);
431 delwin = XInternAtom(theDisp, "WM_DELETE_WINDOW", FALSE);
432
433 if (client_event->message_type == proto &&
434 client_event->data.l[0] == delwin) {
435 /* it's a WM_DELETE_WINDOW event */
436
437 if (BrowseDelWin(client_event->window)) break;
438 if (TextDelWin(client_event->window)) break;
439 #ifdef TV_MULTILINGUAL
440 if (CharsetDelWin(client_event->window)) break;
441 #endif
442
443 if (client_event->window == infoW) InfoBox(0);
444 else if (client_event->window == gamW) GamBox(0);
445 else if (client_event->window == ctrlW) CtrlBox(0);
446 else if (client_event->window == dirW) DirBox(0);
447 else if (client_event->window == psW) PSDialog(0);
448
449 #ifdef HAVE_JPEG
450 else if (client_event->window == jpegW) JPEGDialog(0);
451 #endif
452
453 #ifdef HAVE_JP2K
454 else if (client_event->window == jp2kW) JP2KDialog(0);
455 #endif
456
457 #ifdef HAVE_TIFF
458 else if (client_event->window == tiffW) TIFFDialog(0);
459 #endif
460
461 #ifdef HAVE_PNG
462 else if (client_event->window == pngW) PNGDialog(0);
463 #endif
464
465 else if (client_event->window == pcdW) PCDDialog(0);
466
467 #ifdef HAVE_PIC2
468 else if (client_event->window == pic2W) PIC2Dialog(0);
469 #endif
470
471 #ifdef HAVE_PCD
472 else if (client_event->window == pcdW) PCDDialog(0);
473 #endif
474
475 #ifdef HAVE_MGCSFX
476 else if (client_event->window == mgcsfxW) MGCSFXDialog(0);
477 #endif
478
479 else if (client_event->window == mainW) Quit(0);
480 }
481 }
482 break;
483
484
485 case ConfigureNotify: {
486 XConfigureEvent *cevt = (XConfigureEvent *) event;
487 Window win = cevt->window;
488
489 if (BrowseCheckEvent (event, &retval, &done)) break; /* event eaten */
490 if (TextCheckEvent (event, &retval, &done)) break; /* event eaten */
491
492 /*
493 * if it's a configure of one of the 'major' xv windows, update the
494 * NORMAL position hints for this window appropriately (so it can be
495 * iconified and deiconified correctly)
496 */
497
498 if (win==ctrlW || win==gamW || win==infoW || win==mainW || win==dirW) {
499 XSizeHints hints;
500
501 #define BAD_IDEA
502 #ifdef BAD_IDEA
503 /*
504 * if there is a virtual window manager running (e.g., tvtwm / olvwm),
505 * we're going to get 'cevt' values in terms of the
506 * 'real' root window (the one that is the size of the screen).
507 * We'll want to translate them into values that are in terms of
508 * the 'virtual' root window (the 'big' one)
509 */
510
511 if (vrootW != rootW) {
512 int x1,y1;
513 Window child;
514
515 XTranslateCoordinates(theDisp, rootW, vrootW, cevt->x, cevt->y,
516 &x1, &y1, &child);
517 if (DEBUG) fprintf(stderr," CONFIG trans %d,%d root -> %d,%d vroot\n",
518 cevt->x, cevt->y, x1, y1);
519 cevt->x = x1; cevt->y = y1;
520 }
521 #endif
522
523 #ifndef VMS
524 /* read hints for this window and adjust any position hints, but
525 only if this is a 'synthetic' event sent to us by the WM
526 ('real' events from the server have useless x,y info, since the
527 mainW has been reparented by the WM) */
528
529 if (cevt->send_event &&
530 XGetNormalHints(theDisp, cevt->window, &hints)) {
531
532 if (DEBUG) fprintf(stderr," CONFIG got hints (0x%x %d,%d)\n",
533 (u_int) hints.flags, hints.x, hints.y);
534
535 hints.x = cevt->x;
536 hints.y = cevt->y;
537 XSetNormalHints(theDisp, cevt->window, &hints);
538
539 if (DEBUG) fprintf(stderr," CONFIG set hints (0x%x %d,%d)\n",
540 (u_int) hints.flags, hints.x, hints.y);
541 }
542 #endif
543 }
544
545
546 if (cevt->window == mainW) {
547
548 /* when we load a new image, we may get *2* configure events from
549 * the 'XMoveResizeWindow()' call. One at the 'old' size, in the
550 * new position, and one at the new size at the new position.
551 * We want to *IGNORE* the one at the old size, as we don't want to
552 * call Resize() for images that we won't need.
553 *
554 * Note that we may also only get *one* Configure event (if the window
555 * didn't move), and we may also only get *one* Configure event in
556 * some unasked for size (if the asked for size wasn't acceptable to
557 * the window manager), and we may also get *no* Configure event
558 * if the window doesn't move or change size
559 *
560 * This sucks!
561 *
562 * So, if we have just loaded an image, and we get a Synthetic conf
563 * that is not the desired size (eWIDExeHIGH), ignore it, as it's
564 * just the conf generated by moving the old window. And stop
565 * ignoring further config events
566 *
567 * EVIL KLUDGE: do *not* ignore configs that are <100x100. Not
568 * ignoring them won't be a big performance problem, and it'll get
569 * around the 'I only got one config in the wrong size' problem when
570 * initially displaying small images
571 */
572
573 if (cevt->width<100 && cevt->height < 100 ) ignoreConfigs = 0;
574
575 /* fprintf(stderr,"***mainw, ignore=%d, send_event=%d, evtSize=%d,%d, size=%d,%d\n", ignoreConfigs, cevt->send_event, cevt->width, cevt->height, eWIDE, eHIGH); */
576
577 if (ignoreConfigs==1 && cevt->send_event &&
578 (cevt->width != eWIDE || cevt->height != eHIGH)) {
579 ignoreConfigs=0; /* ignore this one only */
580 break;
581 }
582
583 ignoreConfigs = 0;
584
585
586 if (!rotatesLeft) {
587 if (CheckForConfig()) {
588 if (DEBUG) fprintf(stderr,"more configs pending. ignored\n");
589 }
590
591 else {
592 XEvent xev;
593 if (DEBUG) fprintf(stderr,"No configs pend.");
594
595 if (cevt->width == eWIDE && cevt->height == eHIGH) {
596 if (DEBUG) fprintf(stderr,"No redraw\n");
597 }
598 else {
599 if (DEBUG) fprintf(stderr,"Do full redraw\n");
600
601 Resize(cevt->width, cevt->height);
602
603 /* eat any pending expose events and do a full redraw */
604 while (XCheckTypedWindowEvent(theDisp, mainW, Expose, &xev)) {
605 XExposeEvent *exp = (XExposeEvent *) &xev;
606
607 if (DEBUG)
608 fprintf(stderr," ate expose (%s) (count=%d) %d,%d %dx%d\n",
609 exp->send_event ? "synth" : "real", exp->count,
610 exp->x, exp->y, exp->width, exp->height);
611 }
612
613 DrawWindow(0,0,cevt->width, cevt->height);
614
615 if (HaveSelection()) DrawSelection(0);
616 canstartwait=1;
617 XSync(theDisp, False);
618 SetCursors(-1);
619 }
620 }
621 }
622
623 if (rotatesLeft>0) {
624 rotatesLeft--;
625 if (!rotatesLeft) mainWKludge = 1;
626 }
627 if (!rotatesLeft) SetCursors(-1);
628 }
629
630 }
631 break;
632
633
634
635 case CirculateNotify:
636 case DestroyNotify:
637 case GravityNotify: break;
638
639 case MapNotify: {
640 XMapEvent *map_event = (XMapEvent *) event;
641
642 if (map_event->window == mainW ||
643 (map_event->window == ctrlW && dispMode != RMB_WINDOW)) {
644 if (DEBUG) fprintf(stderr,"map event received on mainW/ctrlW\n");
645
646 if (autoclose) {
647 if (autoclose>1) autoclose -= 2; /* grab kludge */
648 if (wasInfoUp) { InfoBox(wasInfoUp); wasInfoUp=0; }
649 if (wasCtrlUp) { CtrlBox(wasCtrlUp); wasCtrlUp=0; }
650 if (wasDirUp) { DirBox(wasDirUp); wasDirUp=0; }
651 UnHideBrowseWindows();
652 UnHideTextWindows();
653 if (wasGamUp) { GamBox(wasGamUp); wasGamUp=0; }
654 if (wasPsUp) { PSDialog(wasPsUp); wasPsUp=0; }
655 #ifdef HAVE_JPEG
656 if (wasJpegUp) { JPEGDialog(wasJpegUp); wasJpegUp=0; }
657 #endif
658 #ifdef HAVE_JP2K
659 if (wasJp2kUp) { JP2KDialog(wasJpegUp); wasJp2kUp=0; }
660 #endif
661 #ifdef HAVE_TIFF
662 if (wasTiffUp) { TIFFDialog(wasTiffUp); wasTiffUp=0; }
663 #endif
664 #ifdef HAVE_PNG
665 if (wasPngUp) { PNGDialog(wasPngUp); wasPngUp=0; }
666 #endif
667 #ifdef HAVE_PCD
668 if (wasPcdUp) { PCDDialog(wasPcdUp); wasPcdUp=0; }
669 #endif
670 #ifdef HAVE_PIC2
671 if (wasPic2Up) { PIC2Dialog(wasPic2Up); wasPic2Up=0; }
672 #endif
673 #ifdef HAVE_MGCSFX
674 if (wasMgcSfxUp) { MGCSFXDialog(wasMgcSfxUp); wasMgcSfxUp=0; }
675 #endif
676 }
677 }
678 }
679 break;
680
681
682 case UnmapNotify: {
683 XUnmapEvent *unmap_event = (XUnmapEvent *) event;
684
685 if (unmap_event->window == mainW ||
686 (unmap_event->window == ctrlW && dispMode != RMB_WINDOW)) {
687 if (DEBUG) fprintf(stderr,"unmap event received on mainW/ctrlW\n");
688 if (DEBUG) fprintf(stderr,"dispMode = %d\n", dispMode);
689
690 /* don't do it if we've just switched to a root mode */
691 if ((unmap_event->window == mainW && dispMode == 0) ||
692 (unmap_event->window == ctrlW && dispMode != 0)) {
693
694 if (autoclose) {
695 if (autoclose>1) autoclose -= 2; /* grab kludge */
696
697 if (unmap_event->window == mainW) {
698 if (ctrlUp) { wasCtrlUp = ctrlUp; CtrlBox(0); }
699 }
700
701 if (infoUp) { wasInfoUp = infoUp; InfoBox(0); }
702 if (dirUp) { wasDirUp = dirUp; DirBox(0); }
703 HideBrowseWindows();
704 HideTextWindows();
705 if (gamUp) { wasGamUp = gamUp; GamBox(0); }
706 if (psUp) { wasPsUp = psUp; PSDialog(0); }
707 #ifdef HAVE_JPEG
708 if (jpegUp) { wasJpegUp = jpegUp; JPEGDialog(0); }
709 #endif
710 #ifdef HAVE_JP2K
711 if (jp2kUp) { wasJp2kUp = jp2kUp; JP2KDialog(0); }
712 #endif
713 #ifdef HAVE_TIFF
714 if (tiffUp) { wasTiffUp = tiffUp; TIFFDialog(0); }
715 #endif
716 #ifdef HAVE_PNG
717 if (pngUp) { wasPngUp = pngUp; PNGDialog(0); }
718 #endif
719 #ifdef HAVE_PCD
720 if (pcdUp) { wasPcdUp = pcdUp; PCDDialog(0); }
721 #endif
722 #ifdef HAVE_PIC2
723 if (pic2Up) { wasPic2Up = pic2Up; PIC2Dialog(0); }
724 #endif
725 #ifdef HAVE_MGCSFX
726 if (mgcsfxUp) { wasMgcSfxUp = mgcsfxUp; MGCSFXDialog(0); }
727 #endif
728 }
729 }
730 }
731 }
732 break;
733
734 case ReparentNotify: {
735 XReparentEvent *reparent_event = (XReparentEvent *) event;
736
737 if (DEBUG) {
738 fprintf(stderr,"Reparent: mainW=%x ->win=%x ->ev=%x ->parent=%x ",
739 (u_int) mainW, (u_int) reparent_event->window,
740 (u_int) reparent_event->event, (u_int) reparent_event->parent);
741 fprintf(stderr,"%d,%d\n", reparent_event->x, reparent_event->y);
742 }
743
744 if (reparent_event->window == mainW) {
745 ch_offx = reparent_event->x; /* offset required for ChangeAttr call */
746 ch_offy = reparent_event->y;
747
748 p_offx = p_offy = 0; /* topleft correction for WMs titlebar */
749
750 if (ch_offx == 0 && ch_offy == 0) {
751 /* looks like the user is running MWM or OLWM */
752
753 XWindowAttributes xwa;
754
755 /* first query the attributes of mainW. x,y should be the offset
756 from the parent's topleft corner to the windows topleft.
757 OLWM puts the info here */
758
759 XSync(theDisp, False);
760 XGetWindowAttributes(theDisp, mainW, &xwa);
761
762 if (DEBUG)
763 fprintf(stderr,"XGetAttr: mainW %d,%d %dx%d\n", xwa.x, xwa.y,
764 xwa.width, xwa.height);
765
766 if (xwa.x == 0 && xwa.y == 0) {
767 /* MWM, at least mine, puts 0's in those fields. To get the
768 info, we'll have to query the parent window */
769
770 XSync(theDisp, False);
771 XGetWindowAttributes(theDisp, reparent_event->parent, &xwa);
772
773 if (DEBUG)
774 fprintf(stderr,"XGetAttr: parent %d,%d %dx%d\n", xwa.x, xwa.y,
775 xwa.width, xwa.height);
776 }
777 else {
778 /* KLUDGE: if we're running olwm, xwa.{x,y} won't be 0,0.
779 in olwm, the window drifts down and right each time
780 SetWindowPos() is called. God knows why. Anyway, I'm
781 inserting a kludge here to increase 'ch_offx' and 'ch_offy'
782 by bwidth so that this drifting won't happen. No doubt this'll
783 screw up behavior on some *other* window manager, but it should
784 work with TWM, OLWM, and MWM (the big three) */
785 ch_offx += bwidth;
786 ch_offy += bwidth;
787 }
788
789 p_offx = xwa.x;
790 p_offy = xwa.y;
791 }
792
793 /* Gather info to keep right border inside */
794 {
795 Window current;
796 Window root_r;
797 Window parent_r;
798 Window *children_r;
799 unsigned int nchildren_r;
800 XWindowAttributes xwa;
801
802 parent_r=mainW;
803 current=mainW;
804 do {
805 current=parent_r;
806 XQueryTree(theDisp, current, &root_r, &parent_r,
807 &children_r, &nchildren_r);
808 if (children_r!=NULL) {
809 XFree(children_r);
810 }
811 } while (parent_r!=root_r && parent_r!=vrootW);
812 XGetWindowAttributes(theDisp, current, &xwa);
813 debkludge_offx = eWIDE-xwa.width+p_offx;
814 debkludge_offy = eHIGH-xwa.height+p_offy;
815 }
816
817 #if 1
818 /* FIXME: if we want to do this, we first have to wait for a configure
819 * notify to avoid a race condition because the location might be in-
820 * correct if the window manager does placement after managing the window.
821 */
822 /* move window around a bit... */
823 {
824 XWindowAttributes xwa;
825
826 GetWindowPos(&xwa);
827 //fprintf(stderr, "RAC: orig window pos %d,%d\n", xwa.x, xwa.y);
828
829 xwa.width = eWIDE; xwa.height = eHIGH;
830 //fprintf(stderr, "RAC: image size now %d,%d\n", xwa.width, xwa.height);
831
832 /* try to keep the damned thing on-screen, if possible */
833 if (xwa.x + xwa.width > vrWIDE) xwa.x = vrWIDE - xwa.width;
834 if (xwa.y + xwa.height > vrHIGH) xwa.y = vrHIGH - xwa.height;
835 if (xwa.x < 0) xwa.x = 0;
836 if (xwa.y < 0) xwa.y = 0;
837
838 //fprintf(stderr, "RAC: moving window to %d,%d\n", xwa.x, xwa.y);
839 SetWindowPos(&xwa);
840 }
841 #endif
842 }
843 }
844 break;
845
846
847 case EnterNotify:
848 case LeaveNotify: {
849 XCrossingEvent *cross_event = (XCrossingEvent *) event;
850 if (cross_event->window == mainW || 0
851 /* (cross_event->window == gamW && cmapInGam) */ ) {
852
853 if (cross_event->type == EnterNotify && cross_event->window == mainW) {
854 zoomCurs(cross_event->state);
855 }
856
857
858 if (cross_event->type == EnterNotify && LocalCmap && !ninstall)
859 XInstallColormap(theDisp,LocalCmap);
860
861 if (cross_event->type == LeaveNotify && LocalCmap && !ninstall)
862 XUninstallColormap(theDisp,LocalCmap);
863 }
864 }
865 break;
866
867
868 case SelectionClear: break;
869
870 case SelectionRequest:
871 {
872 XSelectionRequestEvent *xsrevt = (XSelectionRequestEvent *) event;
873 XSelectionEvent xse;
874
875 if (xsrevt->owner != ctrlW ||
876 xsrevt->selection != XA_PRIMARY ||
877 xsrevt->target != XA_STRING) { /* can't do it. */
878 xse.property = None;
879 }
880 else {
881 if (xsrevt->property == None) xse.property = xsrevt->target;
882 else xse.property = xsrevt->property;
883
884 if (xse.property != None) {
885 xerrcode = 0;
886 XChangeProperty(theDisp, xsrevt->requestor, xse.property,
887 XA_STRING, 8, PropModeReplace,
888 (byte *) ((xevPriSel) ? xevPriSel : "\0"),
889 (int) ((xevPriSel) ? strlen(xevPriSel)+1 : 1));
890 XSync(theDisp, False);
891 if (!xerrcode) xse.property = None;
892 }
893 }
894
895 xse.type = SelectionNotify;
896 xse.send_event = True;
897 xse.display = theDisp;
898 xse.requestor = xsrevt->requestor;
899 xse.selection = xsrevt->selection;
900 xse.target = xsrevt->target;
901 xse.time = xsrevt->time;
902 XSendEvent(theDisp, xse.requestor, False, NoEventMask, (XEvent *) &xse);
903 XSync(theDisp, False);
904 }
905 break;
906
907
908
909 default: break; /* ignore unexpected events */
910 } /* switch */
911
912 frominterrupt = 0;
913 *donep = done;
914 return(retval);
915 }
916
917
918 /***********************************/
SelectDispMB(i)919 static void SelectDispMB(i)
920 int i;
921 {
922 /* called to handle selection of a dispMB item */
923
924 if (i<0 || i>=DMB_MAX) return;
925
926 if (dispMB.dim[i]) return; /* disabled */
927
928 if (i>=DMB_RAW && i<=DMB_SMOOTH) {
929 if (i==DMB_RAW) epicMode = EM_RAW;
930 else if (i==DMB_DITH) epicMode = EM_DITH;
931 else epicMode = EM_SMOOTH;
932
933 SetEpicMode();
934 GenerateEpic(eWIDE, eHIGH);
935 DrawEpic();
936 SetCursors(-1);
937 }
938
939 else if (i==DMB_COLRW) { /* toggle rw on/off */
940 dispMB.flags[i] = !dispMB.flags[i];
941 allocMode = (dispMB.flags[i]) ? AM_READWRITE : AM_READONLY;
942 ChangeCmapMode(colorMapMode, 1, 0);
943 }
944
945 else if (i>=DMB_COLNORM && i<=DMB_COLSTDC && !dispMB.flags[i]) {
946 switch (i) {
947 case DMB_COLNORM:
948 ChangeCmapMode(CM_NORMAL, 1, 0);
949 defaultCmapMode = CM_NORMAL;
950 break;
951 case DMB_COLPERF:
952 ChangeCmapMode(CM_PERFECT,1, 0);
953 defaultCmapMode = CM_PERFECT;
954 break;
955 case DMB_COLOWNC:
956 ChangeCmapMode(CM_OWNCMAP,1, 0);
957 defaultCmapMode = CM_OWNCMAP;
958 break;
959 case DMB_COLSTDC:
960 ChangeCmapMode(CM_STDCMAP,1, 0);
961 defaultCmapMode = CM_STDCMAP;
962 break;
963 }
964 }
965 }
966
967
968 /***********************************/
SelectRootMB(i)969 static void SelectRootMB(i)
970 int i;
971 {
972 /* called to handle selection of a rootMB item */
973
974 if (i<0 || i>=RMB_MAX) return;
975 if (rootMB.flags[i]) return;
976 if (rootMB.dim[i]) return;
977
978 dispMode = i;
979
980 /* move checkmark */
981 for (i=RMB_WINDOW; i<RMB_MAX; i++) rootMB.flags[i] = 0;
982 rootMB.flags[dispMode] = 1;
983
984 HandleDispMode();
985 }
986
987
988 /***********************************/
Select24to8MB(i)989 static void Select24to8MB(i)
990 int i;
991 {
992 if (i<0 || i>=CONV24_MAX) return;
993
994 if (conv24MB.dim[i]) return;
995
996 if (i==CONV24_8BIT || i==CONV24_24BIT) {
997 if (i != picType) {
998 Change824Mode(i);
999 if (i==CONV24_8BIT && state824==0) state824 = 1; /* did 24->8 */
1000 else if (i==CONV24_24BIT && state824==1) {
1001 /* went 24->8->24 */
1002 char buf[512];
1003
1004 sprintf(buf,"Warning: You appear to have taken a 24-bit ");
1005 strcat(buf, "image, turned it to an 8-bit image, and turned ");
1006 strcat(buf, "it back into a 24-bit image. Understand that ");
1007 strcat(buf, "image data has probably been lost in this ");
1008 strcat(buf, "transformation. You *may* want to reload the ");
1009 strcat(buf, "original image to avoid this problem.");
1010
1011 ErrPopUp(buf, "\nI Know!");
1012
1013 state824 = 2; /* shut up until next image is loaded */
1014 }
1015 }
1016 }
1017
1018 else if (i==CONV24_LOCK) {
1019 conv24MB.flags[i] = !conv24MB.flags[i];
1020 }
1021
1022 else if (i>=CONV24_FAST && i<=CONV24_BEST) {
1023 conv24 = i;
1024 for (i=CONV24_FAST; i<=CONV24_BEST; i++) {
1025 conv24MB.flags[i] = (i==conv24);
1026 }
1027 }
1028 }
1029
1030
1031 /***********************************/
SelectWindowMB(i)1032 static void SelectWindowMB(i)
1033 int i;
1034 {
1035 if (i<0 || i>=WMB_MAX) return;
1036 if (windowMB.dim[i]) return;
1037
1038 switch (i) {
1039 case WMB_BROWSE:
1040 if (strlen(searchdir)) chdir(searchdir);
1041 else chdir(initdir);
1042 OpenBrowse();
1043 break;
1044
1045 case WMB_COLEDIT: GamBox (!gamUp); break;
1046 case WMB_INFO: InfoBox(!infoUp); break;
1047
1048 case WMB_COMMENT:
1049 if (!commentUp) OpenCommentText();
1050 else CloseCommentText();
1051 break;
1052
1053 case WMB_TEXTVIEW: textViewCmd(); break;
1054 case WMB_ABOUTXV: ShowLicense(); break;
1055 case WMB_KEYHELP: ShowKeyHelp(); break;
1056
1057 default: break;
1058 }
1059 }
1060
1061
1062 /***********************************/
SelectSizeMB(i)1063 static void SelectSizeMB(i)
1064 int i;
1065 {
1066 int w,h;
1067
1068 if (i<0 || i>=SZMB_MAX) return;
1069 if (sizeMB.dim[i]) return;
1070
1071 switch (i) {
1072 case SZMB_NORM:
1073 if (cWIDE>maxWIDE || cHIGH>maxHIGH) {
1074 double r,wr,hr;
1075 wr = ((double) cWIDE) / maxWIDE;
1076 hr = ((double) cHIGH) / maxHIGH;
1077
1078 r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */
1079 w = (int) ((cWIDE / r) + 0.5);
1080 h = (int) ((cHIGH / r) + 0.5);
1081 }
1082 else { w = cWIDE; h = cHIGH; }
1083
1084 WResize(w, h);
1085 break;
1086
1087 case SZMB_MAXPIC: WMaximize(); break;
1088
1089 case SZMB_MAXPECT:
1090 {
1091 int w1,h1;
1092 w1 = eWIDE; h1 = eHIGH;
1093 eWIDE = dispWIDE; eHIGH = dispHIGH;
1094 FixAspect(0,&w,&h);
1095 eWIDE = w1; eHIGH = h1; /* play it safe */
1096 WResize(w,h);
1097 }
1098 break;
1099
1100 case SZMB_DOUBLE: WResize(eWIDE*2, eHIGH*2); break;
1101 case SZMB_HALF: WResize(eWIDE/2, eHIGH/2); break;
1102 case SZMB_M10: WResize((eWIDE*9)/10, (eHIGH*9)/10); break;
1103
1104 case SZMB_P10:
1105 w = (eWIDE*11)/10; h = (eHIGH*11)/10;
1106 if (w==eWIDE) w++;
1107 if (h==eHIGH) h++;
1108 WResize(w,h);
1109 break;
1110
1111
1112 case SZMB_SETSIZE: setSizeCmd(); break;
1113 case SZMB_ASPECT: FixAspect(1, &w, &h); WResize(w,h); break;
1114
1115 case SZMB_4BY3:
1116 w = eWIDE; h = (w * 3) / 4;
1117 if (h>maxHIGH) { h = eHIGH; w = (h*4)/3; }
1118 WResize(w,h);
1119 break;
1120
1121 case SZMB_INTEXP:
1122 {
1123 /* round (eWIDE/cWIDE),(eHIGH/cHIGH) to nearest
1124 integer expansion/compression values */
1125
1126 double w,h;
1127
1128 if (eWIDE >= cWIDE) {
1129 w = ((double) eWIDE) / cWIDE;
1130 w = floor(w + 0.5);
1131 if (w < 1.0) w = 1.0;
1132 }
1133 else { /* eWIDE < cWIDE */
1134 int i; double t,d,min,pick;
1135
1136 w = (double) eWIDE / (double) cWIDE;
1137 min = 1.0; pick=1.0;
1138 for (i=1; i<cWIDE; i++) {
1139 t = 1.0 / (double) i;
1140 d = fabs(w - t);
1141 if (d < min) { pick = t; min = d; }
1142 if (t < w) break;
1143 }
1144 w = pick;
1145 }
1146
1147 if (eHIGH >= cHIGH) {
1148 h = ((double) eHIGH) / cHIGH;
1149 h = floor(h + 0.5);
1150 if (h<1.0) h = 1.0;
1151 }
1152 else { /* eHIGH < cHIGH */
1153 int i; double t,d,min,pick;
1154
1155 h = (double) eHIGH / (double) cHIGH;
1156 min = 1.0; pick=1.0;
1157 for (i=1; i<cHIGH; i++) {
1158 t = 1.0 / (double) i;
1159 d = fabs(h - t);
1160 if (d < min) { pick = t; min = d; }
1161 if (t < h) break;
1162 }
1163 h = pick;
1164 }
1165
1166 WResize((int) (w*cWIDE), (int) (h*cHIGH));
1167 }
1168 break;
1169
1170 default: break;
1171 }
1172 }
1173
1174
1175 /***********************************/
DoPrint()1176 static void DoPrint()
1177 {
1178 /* pops open appropriate dialog boxes, issues print command */
1179
1180 int i;
1181 char txt[512], str[PRINTCMDLEN + 10];
1182 static const char *labels[] = { "\03Color", "\07Grayscale", " B/W", "\033Cancel" };
1183 /* ^B ("\02") already used for moving cursor back */
1184
1185 strcpy(txt, "Print: Enter a command that will read a PostScript file ");
1186 strcat(txt, "from stdin and print it to the desired printer.\n\n");
1187 #ifndef VMS
1188 strcat(txt, "(e.g., 'lpr -Pname' on Unix systems)");
1189 #else
1190 strcat(txt, "(e.g., 'Print /Queue = XV_Queue' on a VMS system)");
1191 #endif
1192
1193 i = GetStrPopUp(txt, labels, 4, printCmd, PRINTCMDLEN, "", 0);
1194 if (i == 3 || strlen(printCmd)==0) return; /* CANCEL */
1195
1196 if (dirUp == BLOAD) DirBox(0);
1197
1198 SetDirSaveMode(F_FORMAT, F_PS);
1199 SetDirSaveMode(F_COLORS, i);
1200
1201 if (printCmd[0] != '|' && printCmd[0] != '!')
1202 sprintf(str, "| %s", printCmd);
1203 else strcpy(str, printCmd);
1204
1205 DirBox(BSAVE);
1206 SetDirFName(str);
1207
1208 FakeButtonPress(&dbut[S_BOK]);
1209 }
1210
1211
1212 /***********************************/
debugEvent(e)1213 static void debugEvent(e)
1214 XEvent *e;
1215 {
1216 switch (e->type) {
1217 case ButtonPress:
1218 case ButtonRelease:
1219 fprintf(stderr,"DBGEVT: %s %s %d,%d, state=%x, button=%d\n",
1220 (e->type == ButtonPress) ? "ButtonPress " : "ButtonRelease",
1221 win2name(e->xbutton.window), e->xbutton.x, e->xbutton.y,
1222 e->xbutton.state, e->xbutton.button);
1223 break;
1224
1225 case KeyPress:
1226 case KeyRelease:
1227 fprintf(stderr,"DBGEVT: %s %s state=%x, keycode=%d\n",
1228 (e->type == KeyPress) ? "KeyPress " : "KeyRelease",
1229 win2name(e->xkey.window),
1230 e->xkey.state, e->xkey.keycode);
1231 break;
1232
1233 case Expose:
1234 fprintf(stderr,"DBGEVT: Expose %s %d,%d %dx%d count=%d\n",
1235 win2name(e->xexpose.window), e->xexpose.x, e->xexpose.y,
1236 e->xexpose.width, e->xexpose.height, e->xexpose.count);
1237 break;
1238
1239 case ClientMessage:
1240 fprintf(stderr,"DBGEVT: ClientMessage %s\n",win2name(e->xclient.window));
1241 break;
1242
1243 case ConfigureNotify:
1244 fprintf(stderr,"DBGEVT: ConfigureNotify %s %d,%d %dx%d %s\n",
1245 win2name(e->xconfigure.window), e->xconfigure.x, e->xconfigure.y,
1246 e->xconfigure.width, e->xconfigure.height,
1247 (e->xconfigure.send_event) ? "synthetic" : "real");
1248 break;
1249
1250 case MapNotify:
1251 fprintf(stderr,"DBGEVT: MapNotify %s\n", win2name(e->xany.window));
1252 break;
1253
1254 case ReparentNotify:
1255 fprintf(stderr,"DBGEVT: ReparentNotify %s\n", win2name(e->xany.window));
1256 break;
1257
1258 case EnterNotify:
1259 case LeaveNotify:
1260 fprintf(stderr,"DBGEVT: %s %s\n",
1261 (e->type==EnterNotify) ? "EnterNotify" : "LeaveNotify",
1262 win2name(e->xany.window));
1263 break;
1264
1265 default:
1266 fprintf(stderr,"DBGEVT: unknown event type (%d), window %s\n",
1267 e->type, win2name(e->xany.window));
1268 break;
1269 }
1270 }
1271
win2name(win)1272 static const char *win2name(win)
1273 Window win;
1274 {
1275 static char foo[16];
1276
1277 if (win == mainW) return "mainW";
1278 else if (win == rootW) return "rootW";
1279 else if (win == vrootW) return "vrootW";
1280 else if (win == infoW) return "infoW";
1281 else if (win == ctrlW) return "ctrlW";
1282 else if (win == dirW) return "dirW";
1283 else if (win == gamW) return "gamW";
1284 else if (win == psW) return "psW";
1285
1286 else {
1287 sprintf(foo, "0x%08x", (u_int) win);
1288 return foo;
1289 }
1290 }
1291
1292
1293 /***********************************/
handleButtonEvent(event,donep,retvalp)1294 static void handleButtonEvent(event, donep, retvalp)
1295 XEvent *event;
1296 int *donep, *retvalp;
1297 {
1298 XButtonEvent *but_event;
1299 int i,x,y, done, retval, shift;
1300 Window win;
1301
1302 but_event = (XButtonEvent *) event;
1303 done = *donep; retval = *retvalp;
1304
1305 win = but_event->window;
1306 x = but_event->x; y = but_event->y;
1307 shift = but_event->state & ShiftMask;
1308
1309 switch (event->type) {
1310 case ButtonPress:
1311 /* *always* check for pop-up events, as errors can happen... */
1312 if (PUCheckEvent (event)) break;
1313
1314 if (autoquit && win == mainW) Quit(0);
1315
1316 if (viewonly) break; /* ignore all other button presses */
1317
1318 if (win == mainW && !useroot && showzoomcursor) {
1319 DoZoom(x, y, but_event->button);
1320 break;
1321 }
1322
1323 if (PSCheckEvent (event)) break;
1324
1325 #ifdef HAVE_JPEG
1326 if (JPEGCheckEvent(event)) break;
1327 #endif
1328
1329 #ifdef HAVE_JP2K
1330 if (JP2KCheckEvent(event)) break;
1331 #endif
1332
1333 #ifdef HAVE_TIFF
1334 if (TIFFCheckEvent(event)) break;
1335 #endif
1336
1337 #ifdef HAVE_PNG
1338 if (PNGCheckEvent (event)) break;
1339 #endif
1340
1341 #ifdef HAVE_PCD
1342 if (PCDCheckEvent (event)) break; /* event has been processed */
1343 #endif
1344
1345 #ifdef HAVE_PIC2
1346 if (PIC2CheckEvent(event)) break;
1347 #endif
1348
1349 #ifdef HAVE_MGCSFX
1350 if (MGCSFXCheckEvent(event)) break;
1351 #endif
1352
1353 #ifdef TV_MULTILINGUAL
1354 if (CharsetCheckEvent(event)) break;
1355 #endif
1356
1357 if (GamCheckEvent (event)) break;
1358 if (BrowseCheckEvent (event, &retval, &done)) break;
1359 if (TextCheckEvent (event, &retval, &done)) break;
1360
1361 switch (but_event->button) {
1362
1363 case Button1:
1364 if (win == mainW) DoSelection(but_event);
1365
1366 else if (win == ctrlW) {
1367 if (MBClick(&dispMB, x,y)) SelectDispMB (MBTrack(&dispMB) );
1368 else if (MBClick(&conv24MB, x,y)) Select24to8MB (MBTrack(&conv24MB));
1369 else if (MBClick(&rootMB, x,y)) SelectRootMB (MBTrack(&rootMB) );
1370 else if (MBClick(&windowMB, x,y)) SelectWindowMB(MBTrack(&windowMB));
1371 else if (MBClick(&sizeMB, x,y)) SelectSizeMB (MBTrack(&sizeMB) );
1372 else if (MBClick(&algMB, x,y)) {
1373 algMB.dim[ALG_BLEND] = !HaveSelection();
1374 i = MBTrack(&algMB);
1375 if (i>=0) DoAlg(i);
1376 break;
1377 }
1378
1379 i=ClickCtrl(x,y);
1380
1381 switch (i) {
1382 case BNEXT: retval= NEXTPIC; done=1; break;
1383 case BPREV: retval= PREVPIC; done=1; break;
1384 case BLOAD: DirBox(BLOAD); break;
1385 case BSAVE: DirBox(BSAVE); break;
1386 case BDELETE: if (DeleteCmd()) { done = 1; retval = DELETE; } break;
1387 case BPRINT: DoPrint(); break;
1388
1389 case BCOPY: DoImgCopy(); break;
1390 case BCUT: DoImgCut(); break;
1391 case BPASTE: DoImgPaste(); break;
1392 case BCLEAR: DoImgClear(); break;
1393 case BGRAB: if (Grab()) {done=1; retval = GRABBED;} break;
1394 case BUP10: SelectSizeMB(SZMB_P10); break;
1395 case BDN10: SelectSizeMB(SZMB_M10); break;
1396 case BROTL: Rotate(1); break;
1397 case BROTR: Rotate(0); break;
1398 case BFLIPH: Flip(0); break;
1399 case BFLIPV: Flip(1); break;
1400
1401 case BCROP: Crop(); break;
1402 case BUNCROP: UnCrop(); break;
1403 case BACROP: AutoCrop(); break;
1404
1405 case BPAD:
1406 {
1407 int mode, wide, high, opaque, omode; char *str;
1408
1409 while (PadPopUp(&mode, &str, &wide, &high, &opaque, &omode)==0) {
1410 if (DoPad(mode, str, wide, high, opaque, omode)) {
1411 done = 1; retval = PADDED; break;
1412 }
1413 }
1414 }
1415 break;
1416
1417 case BANNOT: annotatePic(); break;
1418
1419 case BABOUT: SelectWindowMB(WMB_ABOUTXV); break;
1420 case BXV: retval = DFLTPIC; done=1; break;
1421 case BQUIT: retval = QUIT; done=1; break;
1422
1423 default: break;
1424 }
1425
1426 if (i==BFLIPH || i==BFLIPV) {
1427 DrawEpic();
1428 SetCursors(-1);
1429 }
1430 }
1431
1432 else if (win == nList.win) {
1433 i=LSClick(&nList,but_event);
1434 if (curname<0) ActivePrevNext();
1435 if (i>=0) { done = 1; retval = i; }
1436 }
1437
1438 else if (win == nList.scrl.win) SCTrack(&nList.scrl, x, y);
1439
1440 else if (win == dirW) {
1441 i=ClickDirW(x,y);
1442
1443 switch (i) {
1444 case S_BOK: if (dirUp == BLOAD) {
1445 if (!DirCheckCD()) {
1446 retval = LOADPIC;
1447 done=1;
1448 }
1449 }
1450 else if (dirUp == BSAVE) {
1451 DoSave();
1452 }
1453 break;
1454
1455 case S_BCANC: DirBox(0); break;
1456
1457 case S_BRESCAN:
1458 WaitCursor(); LoadCurrentDirectory(); SetCursors(-1);
1459 break;
1460 }
1461 }
1462
1463 else if (win == dList.win) {
1464 i=LSClick(&dList,but_event);
1465 SelectDir(i);
1466 }
1467
1468 else if (win == dList.scrl.win) SCTrack(&dList.scrl, x,y);
1469 else if (win == infoW) InfoBox(0); /* close info */
1470
1471 break;
1472
1473
1474 case Button2:
1475 if (win == mainW && !useroot) {
1476 if (!shift && !DoSelection(but_event)) TrackPicValues(x,y);
1477 else if (shift) Paint();
1478 }
1479 break;
1480
1481 case Button3: /* if using root, MUST NOT get rid of ctrlbox. */
1482 if (!shift && !useroot) CtrlBox(!ctrlUp);
1483 else if (shift) BlurPaint();
1484 break;
1485
1486 case Button4: /* note min vs. max, + vs. - */
1487 if (win == ctrlW || win == nList.win || win == nList.scrl.win) {
1488 SCRL *sp=&nList.scrl;
1489 int halfpage=sp->page/2;
1490
1491 if (sp->val > sp->min+halfpage)
1492 SCSetVal(sp,sp->val-halfpage);
1493 else
1494 SCSetVal(sp,sp->min);
1495 }
1496 else if (win == dirW || win == dList.win || win == dList.scrl.win) {
1497 SCRL *sp=&dList.scrl;
1498 int halfpage=sp->page/2;
1499
1500 if (sp->val > sp->min+halfpage)
1501 SCSetVal(sp,sp->val-halfpage);
1502 else
1503 SCSetVal(sp,sp->min);
1504 }
1505 break;
1506
1507 case Button5: /* note max vs. min, - vs. + */
1508 if (win == ctrlW || win == nList.win || win == nList.scrl.win) {
1509 SCRL *sp=&nList.scrl;
1510 int halfpage=sp->page/2;
1511
1512 if (sp->val < sp->max-halfpage)
1513 SCSetVal(sp,sp->val+halfpage);
1514 else
1515 SCSetVal(sp,sp->max);
1516 }
1517 else if (win == dirW || win == dList.win || win == dList.scrl.win) {
1518 SCRL *sp=&dList.scrl;
1519 int halfpage=sp->page/2;
1520
1521 if (sp->val < sp->max-halfpage)
1522 SCSetVal(sp,sp->val+halfpage);
1523 else
1524 SCSetVal(sp,sp->max);
1525 }
1526 break;
1527
1528 default: break;
1529 }
1530 }
1531
1532 *donep = done; *retvalp = retval;
1533 }
1534
1535
1536 /***********************************/
handleKeyEvent(event,donep,retvalp)1537 static void handleKeyEvent(event, donep, retvalp)
1538 XEvent *event;
1539 int *donep, *retvalp;
1540 {
1541 /* handles KeyPress and KeyRelease events, called from HandleEvent */
1542
1543 XKeyEvent *key_event;
1544 KeySym ks;
1545 char buf[128];
1546 int stlen, dealt, done, retval, shift, ctrl, meta, ck;
1547 u_int svkeystate;
1548
1549 key_event = (XKeyEvent *) event;
1550 done = *donep;
1551 retval = *retvalp;
1552
1553 switch (event->type) {
1554 case KeyRelease:
1555 if (viewonly) break; /* ignore all user input */
1556
1557 stlen = XLookupString(key_event,buf,128,&ks,(XComposeStatus *) NULL);
1558 dealt = 0;
1559
1560 if (key_event->window == mainW) {
1561 u_int foo = key_event->state;
1562
1563 if (ks == XK_Shift_L || ks == XK_Shift_R)
1564 foo = foo & (u_int) (~ShiftMask);
1565 if (ks == XK_Control_L || ks == XK_Control_R)
1566 foo = foo & (u_int) (~ControlMask);
1567 if (ks == XK_Meta_L || ks == XK_Meta_R)
1568 foo = foo & (u_int) (~Mod1Mask);
1569 if (ks == XK_Alt_L || ks == XK_Alt_R)
1570 foo = foo & (u_int) (~Mod1Mask);
1571
1572 zoomCurs(foo);
1573 }
1574 break;
1575
1576
1577 case KeyPress:
1578 svkeystate = key_event->state;
1579 key_event->state &= ~Mod1Mask; /* remove meta from translation */
1580 stlen = XLookupString(key_event,buf,128,&ks,(XComposeStatus *) NULL);
1581 key_event->state = svkeystate;
1582
1583 shift = key_event->state & ShiftMask;
1584 ctrl = key_event->state & ControlMask;
1585 meta = key_event->state & Mod1Mask;
1586 dealt = 0;
1587
1588 RemapKeyCheck(ks, buf, &stlen);
1589
1590 if (PUCheckEvent (event)) break; /* always check popups */
1591
1592 if (autoquit && key_event->window == mainW) Quit(0);
1593
1594 if (viewonly && !frominterrupt) break; /* ignore all user input */
1595
1596 if (PSCheckEvent (event)) break;
1597
1598 if (key_event->window == mainW) {
1599 u_int foo = key_event->state;
1600
1601 if (ks == XK_Shift_L || ks == XK_Shift_R) foo = foo | ShiftMask;
1602 if (ks == XK_Control_L || ks == XK_Control_R) foo = foo | ControlMask;
1603 if (ks == XK_Meta_L || ks == XK_Meta_R) foo = foo | Mod1Mask;
1604 if (ks == XK_Alt_L || ks == XK_Alt_R) foo = foo | Mod1Mask;
1605 zoomCurs(foo);
1606 }
1607
1608 #ifdef HAVE_JPEG
1609 if (JPEGCheckEvent(event)) break;
1610 #endif
1611
1612 #ifdef HAVE_JP2K
1613 if (JP2KCheckEvent(event)) break;
1614 #endif
1615
1616 #ifdef HAVE_TIFF
1617 if (TIFFCheckEvent(event)) break;
1618 #endif
1619
1620 #ifdef HAVE_PNG
1621 if (PNGCheckEvent (event)) break;
1622 #endif
1623
1624 if (PCDCheckEvent (event)) break;
1625
1626 #ifdef HAVE_PIC2
1627 if (PIC2CheckEvent(event)) break;
1628 #endif
1629
1630 #ifdef HAVE_PCD
1631 if (PCDCheckEvent (event)) break;
1632 #endif
1633
1634 #ifdef HAVE_MGCSFX
1635 if (MGCSFXCheckEvent(event)) break;
1636 #endif
1637
1638 if (GamCheckEvent (event)) break;
1639 if (BrowseCheckEvent (event, &retval, &done)) break;
1640 if (TextCheckEvent (event, &retval, &done)) break;
1641
1642
1643 /* Support for multi-image files ("multipage docs"). Check for PgUp/PgDn
1644 or 'p' in any window but control or directory; PgUp/PgDn are already
1645 used to page through the file list in those windows. If no cropping
1646 rectangle is active, shift-Up and shift-Down also work. */
1647
1648 if (key_event->window != ctrlW && key_event->window != dirW) {
1649 dealt = 1;
1650
1651 ck = CursorKey(ks, shift, 0);
1652 if (ck==CK_PAGEUP || (ck==CK_UP && shift && !but[BCROP].active)) {
1653 if (strlen(pageBaseName) && numPages>1) {
1654 done = 1; retval = OP_PAGEUP;
1655 }
1656 else XBell(theDisp,0);
1657 }
1658
1659 else if (ck==CK_PAGEDOWN ||
1660 (ck==CK_DOWN && shift && !but[BCROP].active)) {
1661 if (strlen(pageBaseName) && numPages>1) {
1662 done = 1; retval = OP_PAGEDN;
1663 }
1664 else XBell(theDisp,0);
1665 }
1666
1667 else if (buf[0] == 'p' && stlen>0) {
1668 if (strlen(pageBaseName) && numPages>1) {
1669 int i,j, okay;
1670 char buf[64], txt[512];
1671 static const char *labels[] = { "\nOk", "\033Cancel" };
1672
1673 /* ask what page to go to */
1674 sprintf(txt, "Go to page number... (1-%d)", numPages);
1675 sprintf(buf, "%d", curPage + 1);
1676
1677 okay = 0;
1678 do {
1679 i = GetStrPopUp(txt, labels, 2, buf, 64, "0123456789", 1);
1680 if (!i && strlen(buf) > (size_t) 0) {
1681 /* hit 'Ok', had a string entered */
1682 /* check for page in range */
1683 j = atoi(buf);
1684 if (j>=1 && j<=numPages) {
1685 curPage = j; /* one page past desired page */
1686 done = 1;
1687 retval = OP_PAGEUP;
1688 okay=1;
1689 }
1690 else XBell(theDisp, 0);
1691 }
1692 else okay = 1;
1693 } while (!okay);
1694 }
1695 else XBell(theDisp, 0);
1696 }
1697
1698 else dealt = 0;
1699
1700 if (dealt) break;
1701 }
1702
1703
1704
1705 /* check for crop rect keys */
1706 if (key_event->window == mainW) {
1707 dealt = 1;
1708 ck = CursorKey(ks, shift, 0);
1709 if (ck==CK_LEFT) CropKey(-1, 0,shift,ctrl);
1710 else if (ck==CK_RIGHT) CropKey( 1, 0,shift,ctrl);
1711 else if (ck==CK_UP) CropKey( 0,-1,shift,ctrl);
1712 else if (ck==CK_DOWN) CropKey( 0, 1,shift,ctrl);
1713 else dealt = 0;
1714 if (dealt) break;
1715 }
1716
1717
1718 /* check for List keys */
1719 if (key_event->window == ctrlW || key_event->window == dirW) {
1720 LIST *theList;
1721
1722 ck = CursorKey(ks, shift, 1);
1723 if (key_event->window == dirW) theList = &dList;
1724 else theList = &nList;
1725
1726 dealt = 1;
1727
1728 if (ck==CK_PAGEUP) LSKey(theList,LS_PAGEUP);
1729 else if (ck==CK_PAGEDOWN) LSKey(theList,LS_PAGEDOWN);
1730 else if (ck==CK_UP) LSKey(theList,LS_LINEUP);
1731 else if (ck==CK_DOWN) LSKey(theList,LS_LINEDOWN);
1732 else if (ck==CK_HOME) LSKey(theList,LS_HOME);
1733 else if (ck==CK_END) LSKey(theList,LS_END);
1734 else dealt = 0;
1735
1736 if (theList == &nList && dealt && curname<0) ActivePrevNext();
1737
1738 if (theList == &dList && dealt) { /* changed dir selection */
1739 SelectDir(-1); /* nothing was double-clicked */
1740 }
1741
1742 if (dealt) break;
1743 }
1744
1745
1746 /* check dir filename arrows */
1747 if (key_event->window == dirW) {
1748 ck = CursorKey(ks, shift, 1);
1749 if (ck==CK_LEFT) { DirKey('\002'); break; }
1750 if (ck==CK_RIGHT) { DirKey('\006'); break; }
1751 }
1752
1753
1754 /* check for preset keys (meta-1, meta-2, meta-3, meta-4, meta-0)
1755 * and cut/copy/paste/clear (meta-x, meta-c, meta-v, meta-d)
1756 * and 8/24 bit toggle (meta-8)
1757 * and some algorithms (meta-b, meta-t, meta-p, meta-l, etc.)
1758 */
1759
1760 if (meta) { /* meta is down */
1761 dealt = 1;
1762 if (ks==XK_1) FakeButtonPress(&gbut[G_B1]);
1763 else if (ks==XK_2) FakeButtonPress(&gbut[G_B2]);
1764 else if (ks==XK_3) FakeButtonPress(&gbut[G_B3]);
1765 else if (ks==XK_4) FakeButtonPress(&gbut[G_B4]);
1766 else if (ks==XK_r || ks==XK_0)
1767 FakeButtonPress(&gbut[G_BRESET]);
1768
1769 else if (ks==XK_x) FakeButtonPress(&but[BCUT]);
1770 else if (ks==XK_c) FakeButtonPress(&but[BCOPY]);
1771 else if (ks==XK_v) FakeButtonPress(&but[BPASTE]);
1772 else if (ks==XK_d) FakeButtonPress(&but[BCLEAR]);
1773
1774 else if (ks==XK_u) DoAlg(ALG_NONE);
1775 else if (ks==XK_b) DoAlg(ALG_BLUR);
1776 else if (ks==XK_s) DoAlg(ALG_SHARPEN);
1777 else if (ks==XK_e) DoAlg(ALG_EDGE);
1778 else if (ks==XK_m) DoAlg(ALG_TINF);
1779 else if (ks==XK_o) DoAlg(ALG_OIL);
1780 else if (ks==XK_k) DoAlg(ALG_MEDIAN);
1781
1782 else if ((ks==XK_B || (ks==XK_b && shift)) && HaveSelection())
1783 DoAlg(ALG_BLEND);
1784
1785 else if (ks==XK_p) DoAlg(ALG_PIXEL);
1786
1787 else if (ks==XK_S || (ks==XK_s && shift)) DoAlg(ALG_SPREAD);
1788
1789 else if (ks==XK_t || ks==XK_T) {
1790 if (ctrl || shift || ks==XK_T) DoAlg(ALG_ROTATE);
1791 else DoAlg(ALG_ROTATECLR);
1792 }
1793
1794 else if (ks==XK_a) FakeButtonPress(&gbut[G_BAPPLY]);
1795
1796 else if (ks==XK_8) {
1797 if (picType==PIC8) Select24to8MB(CONV24_24BIT);
1798 else Select24to8MB(CONV24_8BIT);
1799 }
1800
1801 else dealt = 0;
1802
1803 if (dealt) break;
1804 }
1805
1806 /* Check for function keys */
1807 if (key_event->window == ctrlW || key_event->window == mainW) {
1808 if (ks >= XK_F1 && ks <= XK_F1 + FSTRMAX - 1) {
1809 int fkey = ks - XK_F1;
1810 if (fkeycmds[fkey] && fullfname[0]) {
1811 #define CMDLEN 4096
1812 char cmd[CMDLEN];
1813 /* If a command begins with '@', we do not reload the current file */
1814 int noreload = (fkeycmds[fkey][0] == '@');
1815 int x = 0, y = 0, w = 0, h = 0;
1816 if (HaveSelection())
1817 GetSelRCoords(&x, &y, &w, &h);
1818 snprintf(cmd, CMDLEN, fkeycmds[fkey] + noreload, fullfname, x, y, w, h);
1819 #undef CMDLEN
1820 if (DEBUG) fprintf(stderr, "Executing '%s'\n", cmd);
1821 WaitCursor();
1822 system(cmd);
1823 SetCursors(-1);
1824 if (!noreload) {
1825 retval = RELOAD;
1826 done = 1;
1827 }
1828 break;
1829 }
1830 }
1831 }
1832
1833 if (!stlen) break;
1834
1835 if (key_event->window == dirW) {
1836 if (DirKey(buf[0])) XBell(theDisp,0);
1837 }
1838 else { /* commands valid in any window */
1839 switch (buf[0]) {
1840
1841 /* things in dispMB */
1842 case 'r': SelectDispMB(DMB_RAW); break;
1843 case 'd': SelectDispMB(DMB_DITH); break;
1844 case 's': SelectDispMB(DMB_SMOOTH); break;
1845
1846 /* things in sizeMB */
1847 case 'n': SelectSizeMB(SZMB_NORM); break;
1848 case 'm': SelectSizeMB(SZMB_MAXPIC); break;
1849 case 'M': SelectSizeMB(SZMB_MAXPECT); break;
1850 case '>': SelectSizeMB(SZMB_DOUBLE); break;
1851 case '<': SelectSizeMB(SZMB_HALF); break;
1852 case '.': SelectSizeMB(SZMB_P10); break;
1853 case ',': SelectSizeMB(SZMB_M10); break;
1854 case 'S': SelectSizeMB(SZMB_SETSIZE); break;
1855 case 'a': SelectSizeMB(SZMB_ASPECT); break;
1856 case '4': SelectSizeMB(SZMB_4BY3); break;
1857 case 'I': SelectSizeMB(SZMB_INTEXP); break;
1858
1859 /* things in windowMB */
1860 case '\026':
1861 case 'V': SelectWindowMB(WMB_BROWSE); break; /* ^V or V */
1862 case 'e': SelectWindowMB(WMB_COLEDIT); break; /* e */
1863 case 'i': SelectWindowMB(WMB_INFO); break; /* i */
1864 case '\003': SelectWindowMB(WMB_COMMENT); break; /* ^C */
1865 case '\024': SelectWindowMB(WMB_TEXTVIEW); break; /* ^T */
1866 case '\001': SelectWindowMB(WMB_ABOUTXV); break; /* ^A */
1867
1868
1869
1870 /* buttons in ctrlW */
1871 case '\t':
1872 case ' ': FakeButtonPress(&but[BNEXT]); break;
1873
1874 case '\r':
1875 case '\n':
1876 if (nList.selected >= 0 && nList.selected < nList.nstr) {
1877 done = 1; retval = nList.selected;
1878 if (frominterrupt) retval = RELOAD;
1879 }
1880 break;
1881
1882 case '\010': FakeButtonPress(&but[BPREV]); break;
1883
1884
1885 case '\014': FakeButtonPress(&but[BLOAD]); break; /* ^L */
1886 case '\023': FakeButtonPress(&but[BSAVE]); break; /* ^S */
1887 case '\020': FakeButtonPress(&but[BPRINT]); break; /* ^P */
1888 case '\177':
1889 case '\004': FakeButtonPress(&but[BDELETE]); break; /* ^D */
1890
1891 /* BCOPY, BCUT, BPASTE, BCLEAR handled in 'meta' case */
1892
1893 case '\007': FakeButtonPress(&but[BGRAB]); break; /* ^G */
1894
1895 /* BUP10, BDN10 handled in sizeMB case */
1896
1897 case 'T': FakeButtonPress(&but[BROTL]); break;
1898 case 't': FakeButtonPress(&but[BROTR]); break;
1899 case 'h': FakeButtonPress(&but[BFLIPH]); break;
1900 case 'v': FakeButtonPress(&but[BFLIPV]); break;
1901 case 'c': FakeButtonPress(&but[BCROP]); break;
1902 case 'u': FakeButtonPress(&but[BUNCROP]); break;
1903 case 'C': FakeButtonPress(&but[BACROP]); break;
1904 case 'P': FakeButtonPress(&but[BPAD]); break;
1905 case 'A': FakeButtonPress(&but[BANNOT]); break;
1906
1907 /* BABOUT handled in windowMB case */
1908
1909 case '\021': /* ^Q */
1910 case 'q': FakeButtonPress(&but[BQUIT]); break;
1911
1912 case '?': if (!useroot) CtrlBox(!ctrlUp); break;
1913
1914 /* things in color editor */
1915 case 'R': FakeButtonPress(&gbut[G_BRESET]); break;
1916 case 'H': FakeButtonPress(&gbut[G_BHISTEQ]); break;
1917 case 'N': FakeButtonPress(&gbut[G_BMAXCONT]); break;
1918
1919 default: break;
1920 }
1921 }
1922 }
1923
1924 *donep = done; *retvalp = retval;
1925 }
1926
1927
1928 /***********************************/
zoomCurs(mask)1929 static void zoomCurs(mask)
1930 u_int mask;
1931 {
1932 int zc;
1933 zc = ((mask & ControlMask) && !(mask & ShiftMask) && !(mask & Mod1Mask));
1934
1935 if (zc != showzoomcursor) {
1936 showzoomcursor = zc;
1937 SetCursors(-1);
1938 }
1939 }
1940
1941
1942 /***********************************/
textViewCmd()1943 static void textViewCmd()
1944 {
1945 int i;
1946 char *name;
1947
1948 i = nList.selected;
1949 if (i<0 || i>=numnames) return; /* shouldn't happen */
1950
1951 if (namelist[i][0] != '/') { /* prepend 'initdir' */
1952 name = (char *) malloc(strlen(namelist[i]) + strlen(initdir) + 2);
1953 if (!name) FatalError("malloc in textViewCmd failed");
1954 sprintf(name,"%s/%s", initdir, namelist[i]);
1955 }
1956 else name = namelist[i];
1957
1958 TextView(name);
1959
1960 if (name != namelist[i]) free(name);
1961 }
1962
1963
1964 /***********************************/
setSizeCmd()1965 static void setSizeCmd()
1966 {
1967 /* open 'set size' prompt window, get a string, parse it, and try to
1968 set the window size accordingly */
1969
1970 int i, arg1, arg2, numargs, pct1, pct2, state, neww, newh;
1971 char txt[512], buf[64], *sp, ch;
1972 static const char *labels[] = { "\nOk", "\033Cancel" };
1973
1974 sprintf(txt, "Enter new image display size (ex. '400 x 300'),\n");
1975 strcat (txt, "expansion ratio (ex. '75%'),\n");
1976 strcat (txt, "or expansion ratios (ex. '200% x 125%'):");
1977
1978 sprintf(buf, "%d x %d", eWIDE, eHIGH); /* current vals */
1979
1980 i = GetStrPopUp(txt, labels, 2, buf, 64, "0123456789x% ", 1);
1981
1982 if (i) return; /* cancelled */
1983 if (strlen(buf) == 0) return; /* no command */
1984
1985
1986 /* attempt to parse the string accordingly...
1987 * parses strings of the type: <num> [%] [ x <num> [%] ]
1988 * (-ish. <num> all by itself isn't legal)
1989 * there may be any # of spaces between items, including zero
1990 */
1991
1992 arg1 = arg2 = numargs = pct1 = pct2 = state = 0;
1993 sp = buf;
1994
1995 do {
1996 ch = *sp++;
1997
1998 switch (state) {
1999 case 0: /* haven't seen arg1 yet */
2000 if (ch == ' ') {}
2001 else if (ch == '%' || ch == 'x' || ch == '\0') state = 99; /* no arg1 */
2002 else { arg1 = (ch - '0'); state = 1; }
2003 break;
2004
2005 case 1: /* parsing arg1 */
2006 numargs = 1;
2007 if (ch == ' ') state = 2;
2008 else if (ch == '%') state = 3;
2009 else if (ch == 'x') state = 4;
2010 else if (ch == '\0') state = 99;
2011 else arg1 = (arg1 * 10) + (ch - '0');
2012 break;
2013
2014 case 2: /* got arg1 and whitespace */
2015 if (ch == ' ') {}
2016 else if (ch == '%') state = 3;
2017 else if (ch == 'x') state = 4;
2018 else state = 99;
2019 break;
2020
2021 case 3: /* got arg1 % */
2022 pct1 = 1;
2023 if (ch == ' ') {}
2024 else if (ch == '%') state = 99;
2025 else if (ch == 'x') state = 4;
2026 else if (ch == '\0') state = 100;
2027 else state = 99;
2028 break;
2029
2030 case 4: /* got arg1 [%] x */
2031 if (ch == ' ') {}
2032 else if (ch == '%' || ch == 'x' || ch == '\0') state = 99;
2033 else { arg2 = (ch - '0'); state = 5; }
2034 break;
2035
2036 case 5: /* parsing arg2 */
2037 numargs = 2;
2038 if (ch == ' ') state = 6;
2039 else if (ch == '%') state = 7;
2040 else if (ch == 'x') state = 99;
2041 else if (ch == '\0') state = 100;
2042 else arg2 = (arg2 * 10) + (ch - '0');
2043 break;
2044
2045 case 6: /* got arg2 and whitespace */
2046 if (ch == ' ') {}
2047 else if (ch == '%') state = 7;
2048 else if (ch == 'x') state = 99;
2049 else if (ch == '\0') state = 100;
2050 else state = 99;
2051 break;
2052
2053 case 7: /* got arg1 [%] x arg2 % */
2054 pct2 = 1;
2055 state = 100;
2056 break;
2057
2058 case 99: /* error in parsing */
2059 break;
2060
2061 case 100: /* successful parse */
2062 break;
2063 }
2064 } while (state!=99 && state!=100);
2065
2066 /* done parsing... */
2067 if (state == 99) {
2068 ErrPopUp("Error: The entered SetSize string is not valid.", "\nRight.");
2069 return;
2070 }
2071
2072 if (DEBUG)
2073 fprintf(stderr,"setSize: arg1=%d, arg2=%d, numargs=%d, pct=%d,%d\n",
2074 arg1, arg2, numargs, pct1, pct2);
2075
2076 /* otherwise... */
2077 if (numargs == 1) {
2078 if (pct1) {
2079 neww = (cWIDE * arg1) / 100;
2080 newh = (cHIGH * arg1) / 100;
2081 }
2082 else return; /* shouldn't happen */
2083 }
2084 else { /* numargs = 2; */
2085 neww = (pct1) ? (cWIDE * arg1) / 100 : arg1;
2086 newh = (pct2) ? (cHIGH * arg2) / 100 : arg2;
2087 }
2088
2089 if (neww < 1 || newh < 1 || neww > 64000 || newh > 64000) {
2090 sprintf(txt, "The new desired image display size of '%d x %d' is %s",
2091 neww, newh, "ludicrous. Ignored.");
2092 ErrPopUp(txt, "\nSez you!");
2093 return;
2094 }
2095
2096 WResize(neww, newh);
2097 }
2098
2099
2100 /***********************************/
NewCutBuffer(str)2101 void NewCutBuffer(str)
2102 char *str;
2103 {
2104 /* called whenever contents of CUT_BUFFER0 and PRIMARY selection should
2105 be changed. Only works for strings. Copies the data, so the string
2106 doesn't have to be static. */
2107
2108 if (!str) return;
2109
2110 XStoreBytes(theDisp, str, (int) strlen(str)); /* CUT_BUFFER0 */
2111 XSetSelectionOwner(theDisp, XA_PRIMARY, ctrlW, lastEventTime);
2112
2113 if (xevPriSel) free(xevPriSel);
2114 xevPriSel = (char *) malloc(strlen(str) + 1);
2115 if (xevPriSel) strcpy(xevPriSel, str);
2116 }
2117
2118 /***********************************/
DrawWindow(x,y,w,h)2119 void DrawWindow(x,y,w,h)
2120 int x,y,w,h;
2121 {
2122 if (x+w < eWIDE) w++; /* add one for broken servers (?) */
2123 if (y+h < eHIGH) h++;
2124
2125 if (theImage)
2126 XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y, (u_int) w, (u_int) h);
2127 else
2128 if (DEBUG) fprintf(stderr,"Tried to DrawWindow when theImage was NULL\n");
2129 }
2130
2131
2132 /***********************************/
WResize(w,h)2133 void WResize(w,h)
2134 int w,h;
2135 {
2136 XWindowAttributes xwa;
2137
2138 RANGE(w,1,maxWIDE); RANGE(h,1,maxHIGH);
2139
2140 if (useroot) {
2141 Resize(w,h);
2142 MakeRootPic();
2143 SetCursors(-1);
2144 return;
2145 }
2146
2147 GetWindowPos(&xwa);
2148
2149 /* determine if new size goes off edge of screen. if so move window so it
2150 doesn't go off screen */
2151 if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
2152 if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
2153 if (xwa.x < 0) xwa.x = 0;
2154 if (xwa.y < 0) xwa.y = 0;
2155
2156 if (DEBUG) fprintf(stderr,"%s: resizing window to %d,%d at %d,%d\n",
2157 cmd,w,h,xwa.x,xwa.y);
2158
2159 /* resize the window */
2160 xwa.width = w; xwa.height = h;
2161
2162 SetWindowPos(&xwa);
2163 }
2164
2165
2166
2167
2168 /***********************************/
WMaximize()2169 static void WMaximize()
2170 {
2171 if (useroot) WResize((int) dispWIDE, (int) dispHIGH);
2172 else {
2173 XWindowAttributes xwa;
2174 xvbzero((char *) &xwa, sizeof(XWindowAttributes));
2175 xwa.x = xwa.y = 0;
2176 xwa.width = dispWIDE;
2177 xwa.height = dispHIGH;
2178 SetWindowPos(&xwa);
2179 }
2180 }
2181
2182
2183
2184
2185 /***********************************/
WRotate()2186 void WRotate()
2187 {
2188 /* rotate the window and redraw the contents */
2189
2190 if (but[BCROP].active) BTSetActive(&but[BCROP],0);
2191
2192 if (useroot || eWIDE == eHIGH) {
2193 /* won't see any configure events. Manually redraw image */
2194 DrawEpic();
2195 SetCursors(-1);
2196 return;
2197 }
2198 else {
2199 rotatesLeft++;
2200 XClearWindow(theDisp, mainW); /* get rid of old bits */
2201 GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
2202 { int ew, eh;
2203 ew = eWIDE; eh = eHIGH;
2204 WResize(eWIDE, eHIGH);
2205 if (ew>maxWIDE || eh>maxHIGH) { /* rotated pic too big, scale down */
2206 double r,wr,hr;
2207 wr = ((double) ew) / maxWIDE;
2208 hr = ((double) eh) / maxHIGH;
2209
2210 r = (wr>hr) ? wr : hr; /* r is the max(wr,hr) */
2211 ew = (int) ((ew / r) + 0.5);
2212 eh = (int) ((eh / r) + 0.5);
2213 WResize(ew,eh);
2214 }
2215 }
2216 }
2217 }
2218
2219
2220 /***********************************/
WCrop(w,h,dx,dy)2221 void WCrop(w,h,dx,dy)
2222 int w,h,dx,dy;
2223 {
2224 int ex, ey;
2225 XWindowAttributes xwa;
2226
2227 if (useroot) {
2228 MakeRootPic();
2229 SetCursors(-1);
2230 }
2231
2232 else {
2233 /* we want to move window to old x,y + dx,dy (in pic coords) */
2234 GetWindowPos(&xwa);
2235
2236 if (!origcropvalid) { /* first crop. remember win pos */
2237 origcropvalid = 1;
2238 origcropx = xwa.x;
2239 origcropy = xwa.y;
2240 }
2241
2242 CoordC2E(dx, dy, &ex, &ey);
2243
2244 xwa.x += ex; xwa.y += ey;
2245 xwa.width = w; xwa.height = h;
2246 GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
2247 SetWindowPos(&xwa);
2248 }
2249 }
2250
2251
2252 /***********************************/
WUnCrop()2253 void WUnCrop()
2254 {
2255 int w,h;
2256 XWindowAttributes xwa;
2257
2258 /* a proper epic has been generated. eWIDE,eHIGH are the new window size */
2259
2260
2261 if (useroot) {
2262 MakeRootPic();
2263 SetCursors(-1);
2264 }
2265
2266 else { /* !useroot */
2267 GetWindowPos(&xwa);
2268
2269 w = eWIDE; h = eHIGH;
2270
2271 /* restore to position when originally cropped */
2272 if (origcropvalid) { /* *should* always be true... */
2273 origcropvalid = 0;
2274 xwa.x = origcropx;
2275 xwa.y = origcropy;
2276 }
2277
2278 /* keep on screen */
2279 if (xwa.x + w > vrWIDE) xwa.x = vrWIDE - w;
2280 if (xwa.y + h > vrHIGH) xwa.y = vrHIGH - h;
2281 if (xwa.x < 0) xwa.x = 0;
2282 if (xwa.y < 0) xwa.y = 0;
2283
2284 xwa.width = w; xwa.height = h;
2285
2286 if (!useroot) {
2287 SetWindowPos(&xwa);
2288 GenExpose(mainW, 0, 0, (u_int) eWIDE, (u_int) eHIGH);
2289 }
2290 }
2291 }
2292
2293
2294
2295 /***********************************/
GetWindowPos(xwa)2296 void GetWindowPos(xwa)
2297 XWindowAttributes *xwa;
2298 {
2299 Window child;
2300
2301 /* returns the x,y,w,h coords of mainW. x,y are relative to rootW
2302 the border is not included (x,y map to top-left pixel in window) */
2303
2304 /* Get the window width/height */
2305 XGetWindowAttributes(theDisp,mainW,xwa);
2306
2307 /* Get the window origin */
2308 XTranslateCoordinates(theDisp,mainW,rootW,0,0,&xwa->x,&xwa->y,&child);
2309 }
2310
2311
2312 /***********************************/
SetWindowPos(xwa)2313 void SetWindowPos(xwa)
2314 XWindowAttributes *xwa;
2315 {
2316 /* sets window x,y,w,h values */
2317 XWindowChanges xwc;
2318
2319 /* Adjust from window origin, to border origin */
2320 xwc.x = xwa->x - xwa->border_width - ch_offx;
2321 xwc.y = xwa->y - xwa->border_width - ch_offy;
2322
2323 if (!xwa->border_width) xwa->border_width = bwidth;
2324 xwc.border_width = xwa->border_width;
2325
2326 /* if we're less than max size in one axis, allow window manager doohickeys
2327 on the screen */
2328
2329 if (xwa->width < dispWIDE && xwc.x < p_offx) xwc.x = p_offx;
2330 if (xwa->height < dispHIGH && xwc.y < p_offy) xwc.y = p_offy;
2331
2332 /* Try to keep bottom right decorations inside */
2333 #ifdef CRAP
2334 if (xwc.x+eWIDE-debkludge_offx>dispWIDE) {
2335 xwc.x=dispWIDE-eWIDE+debkludge_offx;
2336 if (xwc.x<0) xwc.x=0;
2337 }
2338 if (xwc.y+eHIGH-debkludge_offy>dispHIGH) {
2339 xwc.y=dispHIGH-eHIGH+debkludge_offy;
2340 if (xwc.y<0) xwc.y=0;
2341 }
2342 #else
2343 if (xwc.x+eWIDE+p_offx>dispWIDE) {
2344 xwc.x=dispWIDE-(eWIDE+debkludge_offx);
2345 if (xwc.x<0) xwc.x=0;
2346 }
2347 if (xwc.y+eHIGH+p_offy>dispHIGH) {
2348 xwc.y=dispHIGH-(eHIGH+debkludge_offy);
2349 if (xwc.y<0) xwc.y=0;
2350 }
2351 #endif
2352
2353 xwc.width = xwa->width;
2354 xwc.height = xwa->height;
2355
2356 #define BAD_IDEA
2357 #ifdef BAD_IDEA
2358 /* if there is a virtual window manager running, then we should translate
2359 the coordinates that are in terms of 'real' screen into coordinates
2360 that are in terms of the 'virtual' root window
2361 from: Daren W. Latham <dwl@mentat.udev.cdc.com> */
2362
2363 if (vrootW != rootW) { /* virtual window manager running */
2364 int x1,y1;
2365 Window child;
2366
2367 XTranslateCoordinates(theDisp, rootW, vrootW, xwc.x, xwc.y, &x1, &y1, &child);
2368 if (DEBUG) fprintf(stderr,"SWP: translate: %d,%d -> %d,%d\n",
2369 xwc.x, xwc.y, x1, y1);
2370 xwc.x = x1; xwc.y = y1;
2371 }
2372 #endif
2373
2374
2375 if (DEBUG) {
2376 fprintf(stderr,
2377 "SWP: xwa=%d,%d %dx%d xwc=%d,%d %dx%d off=%d,%d bw=%d klg=%d,%d\n",
2378 xwa->x, xwa->y, xwa->width, xwa->height,
2379 xwc.x, xwc.y, xwc.width, xwc.height, p_offx, p_offy,
2380 xwa->border_width, kludge_offx, kludge_offy);
2381 }
2382
2383 xwc.x += kludge_offx;
2384 xwc.y += kludge_offy;
2385
2386 #if defined(DXWM) || defined(HAVE_XUI)
2387 /* dxwm seems to *only* pay attention to the hints */
2388 {
2389 XSizeHints hints;
2390 if (DEBUG) fprintf(stderr,"SWP: doing the DXWM thing\n");
2391 /* read hints for this window and adjust any position hints */
2392 if (XGetNormalHints(theDisp, mainW, &hints)) {
2393 hints.flags |= USPosition | USSize;
2394 hints.x = xwc.x; hints.y = xwc.y;
2395 hints.width = xwc.width; hints.height = xwc.height;
2396 XSetNormalHints(theDisp, mainW, &hints);
2397 }
2398
2399 #ifndef MWM /* don't do this if you're running MWM */
2400 xwc.x -= 5; xwc.y -= 25; /* EVIL KLUDGE */
2401 #endif /* MWM */
2402 }
2403 #endif
2404
2405 /* all non-DXWM window managers (?) */
2406 /* Move/Resize the window. */
2407 XConfigureWindow(theDisp, mainW,
2408 CWX | CWY | CWWidth | CWHeight /*| CWBorderWidth*/, &xwc);
2409 }
2410
2411
2412
2413 /***********************************/
CropKey(dx,dy,grow,crop)2414 static void CropKey(dx,dy,grow,crop)
2415 int dx,dy,grow,crop;
2416 {
2417 int ocx, ocy;
2418
2419 if (crop) { /* chop off a pixel from the appropriate edge */
2420 int dealt=1;
2421
2422 ocx = cXOFF; ocy = cYOFF;
2423 if (dx<0 && cWIDE>1) DoCrop(cXOFF, cYOFF, cWIDE-1, cHIGH);
2424 else if (dx>0 && cWIDE>1) DoCrop(cXOFF+1, cYOFF, cWIDE-1, cHIGH);
2425 else if (dy<0 && cHIGH>1) DoCrop(cXOFF, cYOFF, cWIDE, cHIGH-1);
2426 else if (dy>0 && cHIGH>1) DoCrop(cXOFF, cYOFF+1, cWIDE, cHIGH-1);
2427 else { dealt = 0; XBell(theDisp, 0); }
2428
2429 if (dealt) {
2430 if (useroot) DrawEpic();
2431 else {
2432 if (HaveSelection()) EnableSelection(0);
2433 CreateXImage();
2434 WCrop(eWIDE, eHIGH, cXOFF-ocx, cYOFF-ocy);
2435 }
2436 }
2437 return;
2438 }
2439
2440 if (grow) MoveGrowSelection(0, 0, dx, dy);
2441 else MoveGrowSelection(dx, dy, 0, 0);
2442 }
2443
2444
2445 /***********************************/
TrackPicValues(mx,my)2446 static void TrackPicValues(mx,my)
2447 int mx,my;
2448 {
2449 Window rW,cW;
2450 int rx,ry,ox,oy,x,y, orgx,orgy;
2451 u_int mask;
2452 u_long wh, bl;
2453 int ty, w, ecol, done1;
2454 char foo[128];
2455 const char *str =
2456 "8888,8888 = 123,123,123 #123456 (123,123,123 HSV) [-2345,-2345]";
2457
2458 ecol = 0; wh = infobg; bl = infofg;
2459
2460 if (!dropper) {
2461 Pixmap pix, mask;
2462 XColor cfg, cbg;
2463
2464 cfg.red = cfg.green = cfg.blue = 0x0000;
2465 cbg.red = cbg.green = cbg.blue = 0xffff;
2466
2467 pix = MakePix1(rootW, dropper_bits, dropper_width, dropper_height);
2468 mask= MakePix1(rootW, dropperm_bits, dropperm_width, dropperm_height);
2469 if (pix && mask)
2470 dropper = XCreatePixmapCursor(theDisp, pix, mask, &cfg, &cbg,
2471 dropper_x_hot, dropper_y_hot);
2472 if (pix) XFreePixmap(theDisp, pix);
2473 if (mask) XFreePixmap(theDisp, mask);
2474 }
2475
2476 if (dropper) XDefineCursor(theDisp, mainW, dropper);
2477
2478 /* do a colormap search for black and white if LocalCmap
2479 and use those colors instead of infobg and infofg */
2480
2481 if (LocalCmap) {
2482 XColor ctab[256]; int i; long cval;
2483
2484 for (i=0; i<nfcols; i++) ctab[i].pixel = freecols[i];
2485 XQueryColors(theDisp,LocalCmap,ctab,nfcols);
2486
2487 /* find 'blackest' pixel */
2488 cval = 0x10000 * 3;
2489 for (i=0; i<nfcols; i++)
2490 if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue <cval) {
2491 cval = ctab[i].red + ctab[i].green + ctab[i].blue;
2492 bl = ctab[i].pixel;
2493 }
2494
2495 /* find 'whitest' pixel */
2496 cval = -1;
2497 for (i=0; i<nfcols; i++)
2498 if ((long)ctab[i].red + (long)ctab[i].green + (long)ctab[i].blue >cval) {
2499 cval = ctab[i].red + ctab[i].green + ctab[i].blue;
2500 wh = ctab[i].pixel;
2501 }
2502 }
2503
2504
2505 XSetFont(theDisp, theGC, monofont);
2506 w = XTextWidth(monofinfo, str, (int) strlen(str));
2507
2508 if (my > eHIGH/2) ty = 0;
2509 else ty = eHIGH-(monofinfo->ascent + mfinfo->descent)-4;
2510
2511 XSetForeground(theDisp, theGC, bl);
2512 XFillRectangle(theDisp, mainW, theGC, 0, ty, (u_int) w + 8,
2513 (u_int) (monofinfo->ascent+monofinfo->descent) + 4);
2514 XSetForeground(theDisp, theGC, wh);
2515 XSetBackground(theDisp, theGC, bl);
2516 foo[0] = '\0';
2517
2518
2519 done1 = ox = oy = orgx = orgy = 0;
2520 while (1) {
2521 int px, py, pix;
2522
2523 if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) continue;
2524 if (done1 && !(mask & Button2Mask)) break; /* button released */
2525
2526 CoordE2P(x,y, &px, &py);
2527 RANGE(px,0,pWIDE-1);
2528 RANGE(py,0,pHIGH-1);
2529
2530 if (px!=ox || py!=oy || !done1) { /* moved, or firsttime. erase & draw */
2531 double h1, s1, v1;
2532 int rval, gval, bval;
2533
2534 if (picType == PIC8) {
2535 ecol = pix = pic[py * pWIDE + px];
2536 rval = rcmap[pix]; gval = gcmap[pix]; bval = bcmap[pix];
2537 }
2538 else { /* PIC24 */
2539 rval = pic[py * pWIDE * 3 + px * 3];
2540 gval = pic[py * pWIDE * 3 + px * 3 + 1];
2541 bval = pic[py * pWIDE * 3 + px * 3 + 2];
2542 }
2543
2544 clearR = rval; clearG = gval; clearB = bval;
2545
2546 rgb2hsv(rval, gval, bval, &h1, &s1, &v1);
2547 if (h1<0.0) h1 = 0.0; /* map 'NOHUE' to 0.0 */
2548
2549 if (!done1) { orgx = px; orgy = py; }
2550
2551 sprintf(foo,
2552 "%4d,%4d = %3d,%3d,%3d #%02x%02x%02x (%3d %3d %3d HSV) [%5d,%5d]",
2553 px, py, rval, gval, bval, rval, gval, bval,
2554 (int) h1, (int) (s1 * 100), (int) (v1 * 100),
2555 px-orgx, py-orgy);
2556
2557 XDrawImageString(theDisp,mainW,theGC, 4, ty + 2 + monofinfo->ascent,
2558 foo, (int) strlen(foo));
2559 ox = px; oy = py;
2560 done1 = 1;
2561 }
2562 }
2563 SetCursors(-1);
2564
2565
2566 if (foo[0]) {
2567 strcat(foo, "\n");
2568 NewCutBuffer(foo);
2569 }
2570
2571 XSetFont(theDisp, theGC, mfont);
2572 DrawWindow(0,ty,eWIDE,(monofinfo->ascent+monofinfo->descent)+4);
2573
2574 if (picType == PIC8 && ecol != editColor) ChangeEC(ecol);
2575 }
2576
2577
2578 /***********************************/
IsConfig(dpy,ev,arg)2579 static Bool IsConfig(dpy, ev, arg)
2580 Display *dpy;
2581 XEvent *ev;
2582 char *arg;
2583 {
2584 XConfigureEvent *cev;
2585
2586 if (ev->type == ConfigureNotify) {
2587 cev = (XConfigureEvent *) ev;
2588 if (cev->window == mainW && (cev->width != eWIDE || cev->height != eHIGH))
2589 *arg = 1;
2590 }
2591 return False;
2592 }
2593
2594 /***********************************/
CheckForConfig()2595 static int CheckForConfig()
2596 {
2597 XEvent ev;
2598 char foo;
2599
2600 /* returns true if there's a config event in which mainW changes size
2601 in the event queue */
2602
2603 XSync(theDisp, False);
2604 foo = 0;
2605 XCheckIfEvent(theDisp, &ev, IsConfig, &foo);
2606 return foo;
2607 }
2608
2609
2610 /************************************************************************/
SetEpicMode()2611 void SetEpicMode()
2612 {
2613 if (epicMode == EM_RAW) {
2614 dispMB.dim[DMB_RAW] = 1;
2615 dispMB.dim[DMB_DITH] = !(ncols>0 && picType == PIC8);
2616 dispMB.dim[DMB_SMOOTH] = 0;
2617 }
2618
2619 else if (epicMode == EM_DITH) {
2620 dispMB.dim[DMB_RAW] = 0;
2621 dispMB.dim[DMB_DITH] = 1;
2622 dispMB.dim[DMB_SMOOTH] = 0;
2623 }
2624
2625 else if (epicMode == EM_SMOOTH) {
2626 dispMB.dim[DMB_RAW] = 0;
2627 dispMB.dim[DMB_DITH] = 1;
2628 dispMB.dim[DMB_SMOOTH] = 1;
2629 }
2630 }
2631
2632
2633 /************************************************************************/
xvErrorHandler(disp,err)2634 int xvErrorHandler(disp, err)
2635 Display *disp;
2636 XErrorEvent *err;
2637 {
2638 char buf[128];
2639
2640 /* in case the error occurred during the Grab command... */
2641 XUngrabServer(theDisp);
2642 XUngrabButton(theDisp, (u_int) AnyButton, 0, rootW);
2643
2644 xerrcode = err->error_code;
2645
2646 /* non-fatal errors: (sets xerrcode and returns)
2647 * BadAlloc
2648 * BadAccess errors on XFreeColors call
2649 * Any error on the 'XKillClient()' call
2650 * BadWindow errors (on a GetProperty call) (workaround SGI problem)
2651 * BadLength errors on XChangeProperty
2652 * BadMatch errors on XGetImage
2653 */
2654
2655 if ((xerrcode == BadAlloc) ||
2656 (xerrcode == BadAccess && err->request_code==88 /* X_FreeColors */ ) ||
2657 (err->request_code == 113 /* X_KillClient */ ) ||
2658 (xerrcode == BadLength && err->request_code==18 /* X_ChangeProp */ ) ||
2659 (xerrcode == BadMatch && err->request_code==73 /* X_GetImage */ ) ||
2660 (xerrcode == BadWindow && err->request_code==20 /* X_GetProperty*/))
2661 return 0;
2662
2663 else {
2664 /* all other errors are 'fatal' */
2665 XGetErrorText(disp, xerrcode, buf, 128);
2666 fprintf(stderr,"X Error: %s\n",buf);
2667 fprintf(stderr," Major Opcode: %d\n",err->request_code);
2668
2669 if (DEBUG) { /* crash 'n' burn for debugging purposes */
2670 char *str;
2671 str = NULL;
2672 *str = '0';
2673 }
2674
2675 exit(-1);
2676 }
2677
2678 return 0;
2679 }
2680
2681
2682 /************************************************************************/
onInterrupt(i)2683 static void onInterrupt(i)
2684 int i;
2685 {
2686 /* but first, if any input-grabbing popups are active, we have to 'cancel'
2687 them. */
2688
2689 if (psUp) PSDialog(0); /* close PS window */
2690
2691 #ifdef HAVE_JPEG
2692 if (jpegUp) JPEGDialog(0); /* close jpeg window */
2693 #endif
2694
2695 #ifdef HAVE_JP2K
2696 if (jp2kUp) JP2KDialog(0); /* close jpeg 2000 window */
2697 #endif
2698
2699 #ifdef HAVE_TIFF
2700 if (tiffUp) TIFFDialog(0); /* close tiff window */
2701 #endif
2702
2703 #ifdef HAVE_PNG
2704 if (pngUp) PNGDialog(0); /* close png window */
2705 #endif
2706
2707 if (pcdUp) PCDDialog(0); /* close pcd window */
2708
2709 #ifdef HAVE_PIC2
2710 if (pic2Up) PIC2Dialog(0); /* close pic2 window */
2711 #endif
2712
2713 #ifdef HAVE_PCD
2714 if (pcdUp) PCDDialog(0); /* close pcd window */
2715 #endif
2716
2717 #ifdef HAVE_MGCSFX
2718 if (mgcsfxUp) MGCSFXDialog(0); /* close mgcsfx window */
2719 #endif
2720
2721 ClosePopUp();
2722
2723 /* make the interrupt signal look like a '\n' keypress in ctrlW */
2724 FakeKeyPress(ctrlW, XK_Return);
2725
2726 frominterrupt = 1;
2727 }
2728
2729
2730
2731
2732
2733 /***********************************/
Paint()2734 static void Paint()
2735 {
2736 Window rW,cW;
2737 int rx,ry, x,y, px,py, px1,py1, state;
2738 int lx, ly, line, seenRelease;
2739 u_int mask, nmask;
2740
2741 /* paint pixels in either editCol (PIC8) or clear{R,G,B} (PIC24) until
2742 'shift' key is released. beep on button presses other than B2.
2743 When shift is released, regen all pics (ala 'clearSelectedArea()') */
2744
2745
2746 if (!pen) {
2747 Pixmap pix, pmask;
2748 XColor cfg, cbg;
2749
2750 cfg.red = cfg.green = cfg.blue = 0x0000;
2751 cbg.red = cbg.green = cbg.blue = 0xffff;
2752
2753 pix = MakePix1(rootW, pen_bits, pen_width, pen_height);
2754 pmask= MakePix1(rootW, penm_bits, penm_width, penm_height);
2755 if (pix && pmask)
2756 pen = XCreatePixmapCursor(theDisp, pix, pmask, &cfg, &cbg,
2757 pen_x_hot, pen_y_hot);
2758 if (pix) XFreePixmap(theDisp, pix);
2759 if (pmask) XFreePixmap(theDisp, pmask);
2760 }
2761
2762 if (pen) XDefineCursor(theDisp, mainW, pen);
2763
2764
2765 XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
2766 | StructureNotifyMask /* | ButtonPressMask */
2767 | KeyReleaseMask | ColormapChangeMask
2768 | EnterWindowMask | LeaveWindowMask );
2769
2770
2771
2772 state = 0;
2773 line = lx = ly = seenRelease = 0;
2774
2775 while (state<100) {
2776 if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) continue;
2777
2778 nmask = (~mask);
2779 px1 = px; py1 = py;
2780 CoordE2P(x,y, &px, &py);
2781
2782 switch (state) {
2783 case 0: /* initial state: make sure we do one pixel */
2784 px1 = lx = px; py1 = ly = py;
2785 paintPixel(px, py);
2786
2787 if (nmask & ShiftMask ) state = 99;
2788 else if (nmask & Button2Mask) state = 1;
2789 else if ( mask & ControlMask) state = 20;
2790 else state = 10;
2791 break;
2792
2793
2794 case 1: /* waiting for click */
2795 if (nmask & ShiftMask) state = 99;
2796 else if ( mask & Button2Mask) {
2797 paintPixel(px, py);
2798 if (mask & ControlMask) {
2799 lx = px; ly = py;
2800 paintXLine(lx, ly, px, py, 1);
2801 line = 1;
2802 state = 20;
2803 }
2804 else state = 10;
2805 }
2806 break;
2807
2808
2809 case 10: /* in freehand drawing mode */
2810 if (nmask & ShiftMask ) state = 99;
2811 else if (nmask & Button2Mask) state = 1;
2812 else if ( mask & ControlMask) {
2813 lx = px; ly = py;
2814 paintXLine(lx, ly, px, py, 1);
2815 line = 1;
2816 state = 20;
2817 }
2818 else paintLine(px1,py1,px,py);
2819 break;
2820
2821
2822 case 20: /* in line-drawing mode */
2823 if (nmask & ShiftMask ) state = 99;
2824 else if (nmask & ControlMask) {
2825 /* remove xor-line, switch to freehand drawing mode or click-wait */
2826 paintXLine(lx, ly, px1, py1, 0);
2827 line = 0;
2828 if (mask & Button2Mask) state = 10;
2829 else state = 1;
2830 }
2831
2832 else if ((mask & Button2Mask) && seenRelease) {
2833 /* remove xor-line, draw line to pt, start xor-line from new pt */
2834 paintXLine(lx, ly, px1, py1, 0);
2835 paintLine (lx, ly, px1, py1);
2836 paintXLine(px1,py1,px, py, 1);
2837 line = 1;
2838 lx = px1; ly = py1;
2839
2840 seenRelease = 0;
2841 }
2842
2843 else {
2844 /* if moved, erase old xor-line, draw new xor-line */
2845 if (px != px1 || py != py1) {
2846 paintXLine(lx, ly, px1, py1, 0);
2847 paintXLine(lx, ly, px, py, 1);
2848 line = 1;
2849 }
2850 else {
2851 paintXLine(lx, ly, px1, py1, 0);
2852 paintXLine(lx, ly, px1, py1, 1);
2853 XSync(theDisp, False);
2854 Timer(100);
2855 }
2856
2857 if (nmask & Button2Mask) seenRelease = 1;
2858 }
2859 break;
2860
2861 case 99: /* EXIT loop: cleanup */
2862 if (line) { /* erase old xor-line */
2863 paintXLine(lx, ly, px1, py1, 0);
2864 line = 0;
2865 }
2866 state = 100; /* exit while loop */
2867 break;
2868 }
2869 }
2870
2871
2872 WaitCursor();
2873
2874 XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
2875 | StructureNotifyMask | ButtonPressMask
2876 | KeyReleaseMask | ColormapChangeMask
2877 | EnterWindowMask | LeaveWindowMask );
2878
2879 GenerateCpic();
2880 WaitCursor();
2881 GenerateEpic(eWIDE,eHIGH);
2882 WaitCursor();
2883 DrawEpic(); /* redraws selection, also */
2884 SetCursors(-1);
2885 }
2886
2887
2888 /***********************/
paintPixel(x,y)2889 static void paintPixel(x,y)
2890 int x,y;
2891 {
2892 /* paints pixel x,y (pic coords) into pic in editColor (PIC8) or clearR,G,B
2893 (PIC24) and does appropriate screen feedback. */
2894
2895 int ex,ey,ex1,ey1,ew,eh;
2896
2897 if (!PTINRECT(x,y,0,0,pWIDE,pHIGH)) return;
2898
2899 if (picType == PIC8) {
2900 pic[y * pWIDE + x] = editColor;
2901 }
2902 else { /* PIC24 */
2903 byte *pp = pic + (y * pWIDE + x) * 3;
2904 pp[0] = clearR; pp[1] = clearG; pp[2] = clearB;
2905 }
2906
2907 /* visual feedback */
2908 CoordP2E(x, y, &ex, &ey);
2909 CoordP2E(x+1, y+1, &ex1, &ey1);
2910
2911 ew = ex1-ex; eh = ey1-ey;
2912
2913 if (picType == PIC8) XSetForeground(theDisp, theGC, cols[editColor]);
2914 else XSetForeground(theDisp, theGC, RGBToXColor(clearR, clearG, clearB));
2915
2916 if (ew>0 && eh>0)
2917 XFillRectangle(theDisp,mainW,theGC, ex,ey, (u_int) ew, (u_int) eh);
2918 }
2919
2920
2921 /***********************************/
paintLine(x,y,x1,y1)2922 static void paintLine(x,y,x1,y1)
2923 int x,y,x1,y1;
2924 {
2925 int t,dx,dy,d,dd;
2926
2927 dx = abs(x1-x); dy = abs(y1-y);
2928
2929 if (dx >= dy) { /* X is major axis */
2930 if (x > x1) {
2931 t = x; x = x1; x1 = t;
2932 t = y; y = y1; y1 = t;
2933 }
2934 d = dy + dy - dx;
2935 dd = y < y1 ? 1 : -1;
2936 while (x <= x1) {
2937 paintPixel(x,y);
2938 if (d > 0) {
2939 y += dd;
2940 d -= dx + dx;
2941 }
2942 ++x;
2943 d += dy + dy;
2944 }
2945 }
2946
2947 else { /* Y is major axis */
2948 if (y > y1) {
2949 t = x; x = x1; x1 = t;
2950 t = y; y = y1; y1 = t;
2951 }
2952 d = dx + dx - dy;
2953 dd = x < x1 ? 1 : -1;
2954 while (y <= y1) {
2955 paintPixel(x,y);
2956 if (d > 0) {
2957 x += dd;
2958 d -= dy + dy;
2959 }
2960 ++y;
2961 d += dx + dx;
2962 }
2963 }
2964
2965
2966 }
2967
2968
2969 static int pntxlcol = 0; /* index into xorMasks */
2970
2971 /***********************************/
paintXLine(x,y,x1,y1,newcol)2972 static void paintXLine(x,y,x1,y1,newcol)
2973 int x,y,x1,y1,newcol;
2974 {
2975 /* draws a xor'd line on image from x,y to x1,y1 (pic coords) */
2976 int ex,ey, ex1,ey1, tx,ty,tx1,ty1;
2977
2978 if (newcol) pntxlcol = (pntxlcol+1) & 0x7;
2979
2980 CoordP2E(x, y, &tx, &ty);
2981 CoordP2E(x+1,y+1,&tx1,&ty1);
2982 ex = tx + (tx1 - tx)/2;
2983 ey = ty + (ty1 - ty)/2;
2984
2985 CoordP2E(x1, y1, &tx, &ty);
2986 CoordP2E(x1+1,y1+1,&tx1,&ty1);
2987 ex1 = tx + (tx1 - tx)/2;
2988 ey1 = ty + (ty1 - ty)/2;
2989
2990 if (ex==ex1 && ey==ey1) return;
2991
2992 XSetPlaneMask(theDisp, theGC, xorMasks[pntxlcol]);
2993 XSetFunction(theDisp, theGC, GXinvert);
2994 XDrawLine(theDisp, mainW, theGC, ex, ey, ex1, ey1);
2995 XSetFunction(theDisp, theGC, GXcopy);
2996 XSetPlaneMask(theDisp, theGC, AllPlanes);
2997 }
2998
2999
3000 /***********************************/
BlurPaint()3001 static void BlurPaint()
3002 {
3003 Window rW,cW;
3004 int rx,ry,ox,oy,x,y, px,py, done1, dragging;
3005 u_int mask;
3006
3007 /* blurs pixels in either editCol (PIC8) or clear{R,G,B} (PIC24) until
3008 'shift' key is released. */
3009
3010
3011 /* if PIC8, uprev it to PIC24 */
3012 if (picType == PIC8) Select24to8MB(CONV24_24BIT);
3013
3014 if (!blur) {
3015 Pixmap pix, mask;
3016 XColor cfg, cbg;
3017
3018 cfg.red = cfg.green = cfg.blue = 0x0000;
3019 cbg.red = cbg.green = cbg.blue = 0xffff;
3020
3021 pix = MakePix1(rootW, blur_bits, blur_width, blur_height);
3022 mask= MakePix1(rootW, blurm_bits, blurm_width, blurm_height);
3023 if (pix && mask)
3024 blur = XCreatePixmapCursor(theDisp, pix, mask, &cfg, &cbg,
3025 blur_x_hot, blur_y_hot);
3026 if (pix) XFreePixmap(theDisp, pix);
3027 if (mask) XFreePixmap(theDisp, mask);
3028 }
3029
3030 if (blur) XDefineCursor(theDisp, mainW, blur);
3031
3032
3033 XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
3034 | StructureNotifyMask /* | ButtonPressMask */
3035 | KeyReleaseMask | ColormapChangeMask
3036 | EnterWindowMask | LeaveWindowMask );
3037
3038
3039 done1 = dragging = ox = oy = 0;
3040 while (1) {
3041 if (!XQueryPointer(theDisp,mainW,&rW,&cW,&rx,&ry,&x,&y,&mask)) continue;
3042 if (done1 && !(mask & ShiftMask)) break; /* Shift released */
3043 if (!(mask & Button3Mask)) { dragging = 0; continue; }
3044
3045 CoordE2P(x,y, &px, &py);
3046
3047 if (!dragging || (dragging && (px!=ox || py!=oy))) { /* click or drag */
3048 if (!dragging) blurPixel(px,py);
3049 else {
3050 int dx,dy,i,lx,ly;
3051
3052 dx = px-ox; dy = py-oy; /* at least one will be non-zero */
3053 if (abs(dx) > abs(dy)) { /* X is major axis */
3054 for (i=0; i<=abs(dx); i++) {
3055 lx = ox + (i * dx)/abs(dx);
3056 ly = oy + (i * dy)/abs(dx);
3057 blurPixel(lx,ly);
3058 }
3059 } else { /* Y is major axis */
3060 for (i=0; i<=abs(dy); i++) {
3061 lx = ox + (i * dx)/abs(dy);
3062 ly = oy + (i * dy)/abs(dy);
3063 blurPixel(lx,ly);
3064 }
3065 }
3066 }
3067
3068 done1 = 1; dragging = 1; ox = px; oy = py;
3069 }
3070 }
3071
3072 WaitCursor();
3073
3074 XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask
3075 | StructureNotifyMask | ButtonPressMask
3076 | KeyReleaseMask | ColormapChangeMask
3077 | EnterWindowMask | LeaveWindowMask );
3078
3079 GenerateCpic();
3080 WaitCursor();
3081 GenerateEpic(eWIDE,eHIGH);
3082 WaitCursor();
3083 DrawEpic(); /* redraws selection, also */
3084 SetCursors(-1);
3085 }
3086
3087
3088
3089 /***********************/
highbit(ul)3090 static int highbit(ul)
3091 unsigned long ul;
3092 {
3093 /* returns position of highest set bit in 'ul' as an integer (0-31),
3094 or -1 if none */
3095
3096 int i; unsigned long hb;
3097
3098 hb = 0x80; hb = hb << 24; /* hb = 0x80000000UL */
3099 for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1);
3100 return i;
3101 }
3102
3103
3104 /***********************/
RGBToXColor(r,g,b)3105 static unsigned long RGBToXColor(r,g,b)
3106 int r,g,b;
3107 {
3108 /* converts arbitrary rgb values (0-255) into an appropriate X color value,
3109 suitable for XSetForeground(). Works for ncols==0, all visual types,
3110 etc. Note that it doesn't do the *best* job, it's really only for
3111 visual feedback during Painting, etc. Should call GenEpic and such
3112 after modifying picture to redither, etc. */
3113
3114 unsigned long rv;
3115
3116 if (picType == PIC8) { /* simply find closest color in rgb map */
3117 int i,j,d,di;
3118
3119 d = 3*(256*256); j=0;
3120 for (i=0; i<numcols; i++) {
3121 di = ((r-rMap[i]) * (r-rMap[i])) +
3122 ((g-gMap[i]) + (g-gMap[i])) +
3123 ((b-bMap[i]) * (b-bMap[i]));
3124 if (i==0 || di<d) { j=i; d=di; }
3125 }
3126
3127 rv = cols[j];
3128 }
3129
3130
3131 else { /* PIC24 */
3132 if (theVisual->class==TrueColor || theVisual->class==DirectColor) {
3133 unsigned long rmask, gmask, bmask;
3134 int rshift, gshift, bshift, cshift, maplen;
3135
3136 /* compute various shifting constants that we'll need... */
3137
3138 rmask = theVisual->red_mask;
3139 gmask = theVisual->green_mask;
3140 bmask = theVisual->blue_mask;
3141
3142 rshift = 7 - highbit(rmask);
3143 gshift = 7 - highbit(gmask);
3144 bshift = 7 - highbit(bmask);
3145
3146 if (theVisual->class == DirectColor) {
3147 maplen = theVisual->map_entries;
3148 if (maplen>256) maplen=256;
3149 cshift = 7 - highbit((u_long) (maplen-1));
3150
3151 r = (u_long) directConv[(r>>cshift) & 0xff] << cshift;
3152 g = (u_long) directConv[(g>>cshift) & 0xff] << cshift;
3153 b = (u_long) directConv[(b>>cshift) & 0xff] << cshift;
3154 }
3155
3156
3157 /* shift the bits around */
3158 if (rshift<0) r = r << (-rshift);
3159 else r = r >> rshift;
3160
3161 if (gshift<0) g = g << (-gshift);
3162 else g = g >> gshift;
3163
3164 if (bshift<0) b = b << (-bshift);
3165 else b = b >> bshift;
3166
3167 r = r & rmask;
3168 g = g & gmask;
3169 b = b & bmask;
3170
3171 rv =r | g | b;
3172 }
3173
3174 else { /* non-TrueColor/DirectColor visual */
3175 if (!ncols)
3176 rv = ((r + g + b >= 128*3) ? white : black);
3177 else /* use closest color in stdcmap */
3178 rv = stdcols[(r&0xe0) | ((g&0xe0)>>3) | ((b&0xc0) >> 6)];
3179 }
3180 }
3181
3182 return rv;
3183 }
3184
3185
3186 /***********************/
blurPixel(x,y)3187 static void blurPixel(x,y)
3188 int x,y;
3189 {
3190 /* blurs pixel x,y (pic coords) into pic in editColor (PIC8) or clearR,G,B
3191 (PIC24) and does appropriate screen feedback. Does a 3x3 average
3192 around the pixel, and replaces it with the average value (PIC24), or
3193 the closest existing color to the average value (PIC8) */
3194
3195 byte *pp;
3196 int i, j, d, di;
3197 int ex,ey,ex1,ey1,ew,eh;
3198 int ar,ag,ab,ac;
3199
3200 if (!PTINRECT(x,y,0,0,pWIDE,pHIGH)) return;
3201
3202 ar = ag = ab = ac = 0;
3203 for (i=y-1; i<=y+1; i++) {
3204 for (j=x-1; j<=x+1; j++) {
3205 if (PTINRECT(j,i, 0,0,pWIDE,pHIGH)) {
3206 if (picType == PIC8) {
3207 pp = pic + i * pWIDE + j;
3208 ar += rMap[*pp]; ag += gMap[*pp]; ab += bMap[*pp];
3209 }
3210 else {
3211 pp = pic + (i * pWIDE + j) * 3;
3212 ar += pp[0]; ag += pp[1]; ab += pp[2];
3213 }
3214 ac++;
3215 }
3216 }
3217 }
3218
3219 ar /= ac; ag /= ac; ab /= ac;
3220
3221
3222 if (picType == PIC8) { /* find nearest actual color */
3223 d = 3*(256*256); j=0;
3224 for (i=0; i<numcols; i++) {
3225 di = ((ar-rMap[i]) * (ar-rMap[i])) +
3226 ((ag-gMap[i]) + (ag-gMap[i])) +
3227 ((ab-bMap[i]) * (ab-bMap[i]));
3228 if (i==0 || di<d) { j=i; d=di; }
3229 }
3230
3231 ac = j;
3232 pic[y * pWIDE + x] = ac;
3233 }
3234 else { /* PIC24 */
3235 pp = pic + (y * pWIDE + x) * 3;
3236 pp[0] = ar; pp[1] = ag; pp[2] = ab;
3237 }
3238
3239 /* visual feedback */
3240 CoordP2E(x, y, &ex, &ey);
3241 CoordP2E(x+1, y+1, &ex1, &ey1);
3242
3243 ew = ex1-ex; eh = ey1-ey;
3244
3245 if (picType == PIC8) XSetForeground(theDisp, theGC, cols[ac]);
3246 else XSetForeground(theDisp, theGC, RGBToXColor(ar, ag, ab));
3247
3248 if (ew>0 && eh>0)
3249 XFillRectangle(theDisp,mainW,theGC, ex,ey, (u_int) ew, (u_int) eh);
3250 }
3251
3252
3253
3254
3255
3256 /***********************/
annotatePic()3257 static void annotatePic()
3258 {
3259 int i, w,h, len;
3260 byte *cimg;
3261 char txt[256];
3262 static char buf[256] = {'\0'};
3263 static const char *labels[] = {"\nOk", "\033Cancel" };
3264
3265 sprintf(txt, "Image Annotation:\n\n%s",
3266 "Enter string to be placed on image.");
3267
3268 i = GetStrPopUp(txt, labels, 2, buf, 256, "", 0);
3269 if (i==1 || strlen(buf)==0) return;
3270
3271
3272 /* build a 'cimg' array to be pasted on clipboard */
3273 w = strlen(buf) * 6 - 1; h = 9;
3274 len = CIMG_PIC8 + w*h;
3275
3276 cimg = (byte *) malloc((size_t) len);
3277 if (!cimg) {
3278 ErrPopUp("Error: Unable to allocate memory for this operation.", "\nOk");
3279 return;
3280 }
3281
3282 cimg[CIMG_LEN ] = len & 0xff;
3283 cimg[CIMG_LEN+1] = (len>> 8) & 0xff;
3284 cimg[CIMG_LEN+2] = (len>>16) & 0xff;
3285 cimg[CIMG_LEN+3] = (len>>24) & 0xff;
3286
3287 cimg[CIMG_W ] = w & 0xff;
3288 cimg[CIMG_W+1] = (w>>8) & 0xff;
3289
3290 cimg[CIMG_H ] = h & 0xff;
3291 cimg[CIMG_H+1] = (h>>8) & 0xff;
3292
3293 cimg[CIMG_24] = 0;
3294 cimg[CIMG_TRANS] = 1;
3295 cimg[CIMG_TRVAL] = 0;
3296
3297 xvbzero((char *) cimg + CIMG_PIC8, (size_t) w*h);
3298
3299 if (picType == PIC8) {
3300 cimg[CIMG_CMAP + 3 + 0] = rMap[editColor];
3301 cimg[CIMG_CMAP + 3 + 1] = gMap[editColor];
3302 cimg[CIMG_CMAP + 3 + 2] = bMap[editColor];
3303 } else {
3304 cimg[CIMG_CMAP + 3 + 0] = clearR;
3305 cimg[CIMG_CMAP + 3 + 1] = clearG;
3306 cimg[CIMG_CMAP + 3 + 2] = clearB;
3307 }
3308
3309 DrawStr2Pic(buf, w/2, h/2, cimg+CIMG_PIC8, w,h, 1);
3310
3311 SaveToClip(cimg);
3312 free(cimg);
3313
3314 /* if (HaveSelection()) EnableSelection(0); */
3315 DoImgPaste();
3316 }
3317
3318
3319
3320