1 /*
2  * wmslib/src/but/canvas.c, part of wmslib (Library functions)
3  * Copyright (C) 1994-1996 William Shubert.
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <wms.h>
8 
9 #ifdef  X11_DISP
10 
11 #ifdef  STDC_HEADERS
12 #include <stdlib.h>
13 #include <unistd.h>
14 #endif  /* STDC_HEADERS */
15 #include <stdio.h>
16 #include <X11/Xlib.h>
17 #include <X11/Xutil.h>
18 #include <X11/cursorfont.h>
19 #include <X11/Xatom.h>
20 #include <X11/keysym.h>
21 #include <sys/time.h>
22 #ifdef  HAVE_SYS_SELECT_H
23 #include <sys/select.h>
24 #endif
25 #include <wms.h>
26 #include <but/but.h>
27 #ifdef  _BUT_CANVAS_H_
28   Levelization Error.
29 #endif
30 #include "canvas.h"
31 
32 
33 /**********************************************************************
34  * Data Types
35  **********************************************************************/
36 typedef struct Can_struct  {
37   bool  grabbed;
38   int  grab_mx,grab_my, grab_ox,grab_oy;
39   ButWin  *parent, *win;
40   But  *but;
41   Pixmap  pmap;
42   void  (*change)(void *packet, int xOff, int yOff,
43 		  int w, int h, int viewW, int viewH);
44   MAGIC_STRUCT
45 } Can;
46 
47 
48 /**********************************************************************
49  * Forward Declarations
50  **********************************************************************/
51 static ButOut  mmove(But *but, int x, int y);
52 static ButOut  mleave(But *but);
53 static ButOut  mpress(But *but, int butnum, int x, int y);
54 static ButOut  mrelease(But *but, int butnum, int x, int y);
55 static ButOut  kpress(But *but, const char *keystr, KeySym sym);
56 static ButOut  krelease(But *but, const char *keystr, KeySym sym);
57 static void  draw(But *but, int x, int y, int w, int h);
58 static ButOut  destroy(But *but);
59 static bool  reviseDims(Can *can);
60 
61 
62 /**********************************************************************
63  * Globals
64  **********************************************************************/
65 static const ButAction  action = {
66   mmove, mleave, mpress, mrelease,
67   kpress, krelease, draw, destroy, but_flags, NULL};
68 
69 
70 /**********************************************************************
71  * Functions
72  **********************************************************************/
butCan_create(void * packet,ButWin * parent,int layer,ButWinFunc * resize,ButWinFunc * destroy,void (* change)(void * packet,int xOff,int yOff,int w,int h,int viewW,int viewH))73 ButWin  *butCan_create(void *packet, ButWin *parent, int layer,
74 		       ButWinFunc *resize, ButWinFunc *destroy,
75 		       void (*change)(void *packet, int xOff, int yOff,
76 				      int w, int h,
77 				      int viewW, int viewH))  {
78   ButEnv  *env;
79   ButWin  *win;
80   But  *but;
81   Can  *can;
82 
83   assert(MAGIC(parent));
84   env = parent->env;
85   assert(MAGIC(env));
86 
87   win = wms_malloc(sizeof(ButWin));
88   can = wms_malloc(sizeof(Can));
89   but = but_create(parent, can, &action);
90 
91   MAGIC_SET(win);
92   MAGIC_SET(can);
93   MAGIC_SET(&win->butsNoDraw);
94 
95   win->parent = parent;
96   win->parentBut = but;
97   win->packet = packet;
98   win->iPacket = can;
99   win->win = None;
100   win->physWin = butCan_xWin(parent);
101   win->iconWin = NULL;
102 
103   win->name = NULL;
104   win->iconic = FALSE;
105   win->isIcon = FALSE;
106   win->x = 0;
107   win->y = 0;
108   win->w = win->minW = win->maxW = win->logicalW = 0;
109   win->h = win->minH = win->maxH = win->logicalH = 0;
110   win->wStep = 1;
111   win->hStep = 1;
112   win->xOff = 0;
113   win->yOff = 0;
114   win->minWRatio = win->minHRatio = win->maxWRatio = win->maxHRatio = 0;
115 
116   win->resized = FALSE;
117   win->resizeNeeded = FALSE;
118   win->redrawReady = TRUE;
119   win->redraws = NULL;
120   win->numRedraws = win->maxRedraws = 0;
121 
122   win->id = 0;
123   win->mapped = TRUE;
124   win->unmap = NULL;
125   win->map = NULL;
126   win->resize = resize;
127   win->destroy = destroy;
128   win->quit = NULL;
129   win->env = env;
130   win->minLayer = 1;
131   win->maxLayer = 0;
132   win->butsNoDraw.buts = NULL;
133   win->butsNoDraw.numButs = 0;
134   win->butsNoDraw.maxButs = 0;
135   win->butsNoDraw.dynamic = TRUE;
136   win->lock = NULL;
137   win->butIn = NULL;
138   win->keyBut = NULL;
139   win->numCols = 0;
140   win->maxCols = 0;
141   win->cols = NULL;
142   butWin_addToTable(win);
143 
144   but->uPacket = packet;
145   but->layer = layer;
146   but->flags = BUT_DRAWABLE|BUT_PRESSABLE|BUT_OPAQUE;
147 
148   can->grabbed = FALSE;
149   can->parent = parent;
150   can->win = win;
151   can->but = but;
152   can->pmap = None;
153   can->change = change;
154 
155   but_init(but);
156   return(win);
157 }
158 
159 
butCan_resizeView(ButWin * win,int x,int y,int w,int h,bool propagate)160 void  butCan_resizeView(ButWin *win, int x, int y, int w, int h,
161 			bool propagate)  {
162   int  oldh, oldw, oldx, oldy;
163   Can  *can = win->iPacket;
164   But  *but = can->but;
165 
166   assert(MAGIC(win));
167   assert(MAGIC(can));
168   win->resized = TRUE;
169   oldx = but->x;
170   oldy = but->y;
171   oldw = but->w;
172   oldh = but->h;
173   if (x == BUT_NOCHANGE)
174     x = oldx;
175   if (y == BUT_NOCHANGE)
176     y = oldy;
177   if (w == BUT_NOCHANGE)
178     w = oldw;
179   if (h == BUT_NOCHANGE)
180     h = oldh;
181 
182   /*
183    * Check to see if the porthole size has changed.  If it has, hit it
184    *   with a redraw.  Not real necessary for these, but what the heck.
185    */
186   if ((w != oldw) || (h != oldh))  {
187     win->w = w;
188     win->h = h;
189     reviseDims(can);
190     if (win->resize != NULL)  {
191       win->resize(win);
192     }
193     if (can->pmap != None)  {
194       butWin_rmFromTable(win);
195       XFreePixmap(win->env->dpy, can->pmap);
196     }
197     can->pmap = XCreatePixmap(win->env->dpy, win->physWin,
198 			      w, h, win->env->depth);
199     win->win = can->pmap;
200     butWin_addToTable(win);
201     but_resize(but, x,y, w,h);
202     butWin_redraw(win, win->xOff,win->yOff, w,h);
203     if (propagate && can->change)  {
204       can->change(can->but->uPacket, win->xOff, win->yOff,
205 		  win->logicalW, win->logicalH, win->w, win->h);
206     }
207   } else if ((x != oldx) || (y != oldy))  {
208     /* Check if the porthole geometry has changed, necessitating a redraw. */
209     but_resize(but, x,y, w,h);
210   }
211 }
212 
213 
butCan_slide(ButWin * win,int xOff,int yOff,bool propagate)214 void  butCan_slide(ButWin *win, int xOff, int yOff, bool propagate)  {
215   int  oldox, oldoy;
216   Can  *can = win->iPacket;
217   int  csx, csy, cdx, cdy, cw, ch;
218   int  rdx, rdw;
219 
220   assert(MAGIC(win));
221   assert(MAGIC(can));
222   oldox = win->xOff;
223   oldoy = win->yOff;
224   if (xOff != BUT_NOCHANGE)
225     win->xOff = xOff;
226   if (yOff != BUT_NOCHANGE)
227     win->yOff = yOff;
228   reviseDims(can);
229   if (((oldox == win->xOff) && (oldoy == win->yOff)) || (win->win == None))
230     return;
231 
232   if (win->xOff > oldox)  {
233     csx = win->xOff - oldox;
234     cdx = 0;
235     cw = win->w - csx;
236   } else if (win->xOff == oldox)  {
237     csx = 0;
238     cdx = 0;
239     cw = win->w;
240   } else  {  /* win->xOff < oldox */
241     csx = 0;
242     cdx = oldox - win->xOff;
243     cw = win->w - csx;
244   }
245 
246   if (win->yOff > oldoy)  {
247     csy = win->yOff - oldoy;
248     cdy = 0;
249     ch = win->h - csy;
250   } else if (win->yOff == oldoy)  {
251     csy = 0;
252     cdy = 0;
253     ch = win->h;
254   } else  {  /* win->yOff < oldoy */
255     csy = 0;
256     cdy = oldoy - win->yOff;
257     ch = win->h - csy;
258   }
259 
260   if ((cw < 0) || (ch < 0))  {
261     /* Must redraw entire pixmap. */
262     butWin_redraw(win, win->xOff, win->yOff, win->w, win->h);
263   } else  {
264     XCopyArea(win->env->dpy, can->pmap, can->pmap, win->env->gc,
265 	      csx,csy, cw,ch, cdx,cdy);
266     if (cdx > csx)  {
267       butWin_redraw(win, win->xOff, win->yOff, cdx-csx, win->h);
268       rdx = win->xOff+cdx-csx;
269       rdw = win->w - (cdx-csx);
270       if (rdw < 0)
271 	rdw = 0;
272     } else if (cdx == csx)  {
273       rdx = win->xOff;
274       rdw = win->w;
275     } else  {  /* cdx < csx */
276       butWin_redraw(win, win->xOff+win->w-(csx-cdx), win->yOff,
277 		    csx-cdx, win->h);
278       rdx = win->xOff;
279       rdw = win->w - (csx - cdx);
280       if (rdw < 0)
281 	rdw = 0;
282     }
283     if (cdy > csy)  {
284       butWin_redraw(win, rdx, win->yOff, rdw, cdy-csy);
285     } else if (cdy < csy)  {
286       butWin_redraw(win, rdx, win->yOff+win->h-(csy-cdy), rdw, csy-cdy);
287     }
288   }
289   but_draw(can->but);
290   if (propagate)  {
291     can->change(can->but->uPacket, win->xOff, win->yOff,
292 		win->logicalW, win->logicalH, win->w, win->h);
293   }
294   if (can->parent->butIn == can->but)  {
295     butWin_mMove(win->env->last_mwin, win->env->last_mx, win->env->last_my);
296   }
297 }
298 
299 
butCan_destroy(ButWin * win)300 void  butCan_destroy(ButWin *win)  {
301 }
302 
303 
mmove(But * but,int x,int y)304 static ButOut  mmove(But *but, int x, int y)  {
305   Can  *can = but->iPacket;
306   ButWin  *win = can->win;
307   ButEnv  *env = but->win->env;
308   ButOut  result;
309   int  new_ox, new_oy;
310 
311   assert(MAGIC(but));
312   assert(MAGIC(can));
313   if (can->grabbed)  {
314     if (env->last_mwin != but->win)  {
315       return(0);
316     }
317     new_ox = can->grab_ox + 10*(can->grab_mx - x);
318     new_oy = can->grab_oy + 10*(can->grab_my - y);
319     if ((new_ox != win->xOff) || (new_oy != win->yOff))  {
320       butCan_slide(can->win, new_ox, new_oy, TRUE);
321     }
322     env->last_mwin = but->win;
323     env->last_mx = x - but->x + win->xOff;
324     env->last_my = y - but->y + win->yOff;
325     return(BUTOUT_CAUGHT);
326   } else  {
327     result = butWin_mMove(can->win, x-but->x+win->xOff, y-but->y+win->yOff);
328     return(result | BUTOUT_CAUGHT | BUTOUT_IGNORE);
329   }
330 }
331 
332 
mleave(But * but)333 static ButOut  mleave(But *but)  {
334   /*
335    * This isn't quite right...not sure how to handle this.
336    *   I don't want to get a "leave" when I propogate a mouse move down
337    *   to the area below, but I get one anyway!
338    * can_t  *can = but->iPacket;
339    * int  result;
340    *
341    * assert(MAGIC(can));
342    * result = but_mmove(but->win->env, can->win, 1,-1);
343    * return(result);
344    */
345   return(0);
346 }
347 
348 
mpress(But * but,int butnum,int x,int y)349 static ButOut  mpress(But *but, int butnum, int x, int y)  {
350   Can  *can = but->iPacket;
351   ButWin  *win = can->win;
352   int  result;
353 
354   assert(MAGIC(can));
355   if (butnum == 3)  {
356     can->grabbed = TRUE;
357     can->grab_mx = x;
358     can->grab_my = y;
359     can->grab_ox = win->xOff;
360     can->grab_oy = win->yOff;
361     butEnv_setCursor(but->win->env, but, butCur_grab);
362     but_newFlags(but, but->flags | BUT_LOCKED);
363     return(BUTOUT_CAUGHT);
364   } else  {
365     result = butWin_mPress(can->win, x - but->x + win->xOff,
366 			   y - but->y + win->yOff, butnum);
367     return(result);
368   }
369 }
370 
371 
mrelease(But * but,int butnum,int x,int y)372 static ButOut  mrelease(But *but, int butnum, int x, int y)  {
373   Can  *can = but->iPacket;
374   ButWin  *win = can->win;
375   ButOut  result;
376 
377   assert(MAGIC(can));
378   if (butnum == 3)  {
379     can->grabbed = FALSE;
380     but_newFlags(but, but->flags & ~BUT_LOCKED);
381     butEnv_setCursor(but->win->env, but, butCur_idle);
382     return(BUTOUT_CAUGHT);
383   } else  {
384     result = butWin_mRelease(can->win, x - but->x + win->xOff,
385 			     y - but->y + win->yOff, butnum);
386     return(result);
387   }
388 }
389 
390 
kpress(But * but,const char * keystr,KeySym sym)391 static ButOut  kpress(But *but, const char *keystr, KeySym sym)  {
392   Can  *can = but->iPacket;
393   ButOut  result;
394 
395   assert(MAGIC(can));
396   result = butWin_kPress(can->win, keystr, sym);
397   return(result);
398 }
399 
400 
krelease(But * but,const char * keystr,KeySym sym)401 static ButOut  krelease(But *but, const char *keystr, KeySym sym)  {
402   Can  *can = but->iPacket;
403   ButOut  result;
404 
405   assert(MAGIC(can));
406   result = butWin_kRelease(can->win, keystr, sym);
407   return(result);
408 }
409 
410 
draw(But * but,int x,int y,int w,int h)411 static void  draw(But *but, int x, int y, int w, int h)  {
412   Can  *can = but->iPacket;
413   ButWin  *win = but->win;
414   ButEnv  *env = win->env;
415   int  csx,csy, cdx,cdy, cw,ch;
416 
417   assert(MAGIC(can));
418   assert(MAGIC(win));
419   csx = 0;
420   csy = 0;
421   cdx = but->x;
422   cdy = but->y;
423   cw = but->w;
424   ch = but->h;
425   if (x > cdx)  {
426     csx += x - cdx;
427     cw  -= x - cdx;
428     cdx = x;
429   }
430   if (y > cdy)  {
431     csy += y - cdy;
432     ch  -= y - cdy;
433     cdy = y;
434   }
435   if (x+w < cdx+cw)
436     cw = x+w-cdx;
437   if (y+h < cdy+ch)
438     ch = y+h-cdy;
439   if ((cw > 0) && (ch > 0))
440     XCopyArea(env->dpy, can->pmap, win->win, env->gc, csx,csy, cw,ch, cdx,cdy);
441 }
442 
443 
butCan_redrawn(ButWin * win,int x,int y,int w,int h)444 void  butCan_redrawn(ButWin *win, int x,int y, int w,int h)  {
445   Can  *can = win->iPacket;
446 
447   assert(MAGIC(win));
448   if (can == NULL)
449     return;
450   assert(MAGIC(can));
451   if (can->but == NULL)
452     return;
453   assert(MAGIC(can->but));
454   assert(MAGIC(can->parent));
455   if (x < win->xOff)  {
456     w -= win->xOff - x;
457     x = win->xOff;
458   }
459   if (y < win->yOff)  {
460     h -= win->yOff - y;
461     y = win->yOff;
462   }
463   if (x + w > win->xOff + win->w)
464     w = win->xOff + win->w - x;
465   if (y + h > win->yOff + win->h)
466     h = win->yOff + win->h - y;
467   butWin_redraw(can->parent, can->but->x + x - win->xOff,
468 		can->but->y + y - win->yOff, w, h);
469 }
470 
471 
destroy(But * but)472 static ButOut  destroy(But *but)  {
473   Can  *can = but->iPacket;
474 
475   assert(MAGIC(but));
476   assert(MAGIC(can));
477   assert((can->win == NULL) || MAGIC(can->win));
478   can->but = NULL;
479   but->iPacket = NULL;
480   if (can->win == NULL)  {
481     MAGIC_UNSET(can);
482     wms_free(can);
483   } else
484     butWin_destroy(can->win);
485   return(0);
486 }
487 
488 
butCan_winDead(ButWin * win)489 void  butCan_winDead(ButWin *win)  {
490   Can  *can = win->iPacket;
491 
492   assert(MAGIC(win));
493   assert(MAGIC(can));
494   assert((can->but == NULL) || MAGIC(can->but));
495   can->win = NULL;
496   win->iPacket = NULL;
497   if (can->but == NULL)  {
498     MAGIC_UNSET(can);
499     wms_free(can);
500   } else
501     but_destroy(can->but);
502 }
503 
504 
butCan_resizeWin(ButWin * win,int w,int h,bool propagate)505 void  butCan_resizeWin(ButWin *win, int w, int h, bool propagate)  {
506   Can  *can = win->iPacket;
507   int  oldW, oldH;
508 
509   assert(MAGIC(win));
510   assert(MAGIC(can));
511   oldW = win->logicalW;
512   oldH = win->logicalH;
513   if (w < win->w)
514     w = win->w;
515   if (h < win->h)
516     h = win->h;
517   win->logicalW = w;
518   win->logicalH = h;
519   reviseDims(can);
520   if ((win->logicalW <= 0) || (win->logicalH <= 0))
521     return;
522   if ((win->logicalW != oldW) || (win->logicalH != oldH))  {
523     win->resize(win);
524     if (propagate && can->change)  {
525       can->change(can->but->uPacket, win->xOff, win->yOff,
526 		  win->logicalW, win->logicalH, win->w, win->h);
527     }
528   }
529 }
530 
531 
butCan_xWin(ButWin * win)532 Window  butCan_xWin(ButWin *win)  {
533   assert(MAGIC(win));
534   while (win->parent)  {
535     win = win->parent;
536     assert(MAGIC(win));
537   }
538   return(win->win);
539 }
540 
541 
reviseDims(Can * can)542 static bool  reviseDims(Can *can)  {
543   ButWin  *win = can->win;
544   bool change = FALSE;
545 
546   if (win->logicalW < win->w)  {
547     change = TRUE;
548     win->logicalW = win->w;
549   }
550   if (win->logicalH < win->h)  {
551     change = TRUE;
552     win->logicalH = win->h;
553   }
554   if (win->xOff < 0)  {
555     change = TRUE;
556     win->xOff = 0;
557   } else if (win->xOff + win->w > win->logicalW)  {
558     change = TRUE;
559     win->xOff = win->logicalW - win->w;
560   }
561   if (win->yOff < 0)  {
562     change = TRUE;
563     win->yOff = 0;
564   } else if (win->yOff + win->h > win->logicalH)  {
565     change = TRUE;
566     win->yOff = win->logicalH - win->h;
567   }
568   return(change);
569 }
570 
571 
572 #endif  /* X11_DISP */
573