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