1 /*
2 * Copyright (C) 2002 Sasha Vasko <sasha at aftercode.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 */
19
20 #undef LOCAL_DEBUG
21 #undef DO_CLOCKING
22
23 #include <string.h>
24
25 #include "../configure.h"
26
27 #include "asapp.h"
28 #include "../libAfterImage/afterimage.h"
29 #include "screen.h"
30 #include "shape.h"
31 #include "canvas.h"
32
33
34 inline Bool
get_current_canvas_geometry(ASCanvas * pc,int * px,int * py,unsigned int * pwidth,unsigned int * pheight,unsigned int * pbw)35 get_current_canvas_geometry (ASCanvas * pc, int *px, int *py,
36 unsigned int *pwidth, unsigned int *pheight,
37 unsigned int *pbw)
38 {
39 Window wdumm;
40 unsigned int udumm;
41 int dumm;
42
43 if (pc == NULL)
44 return False;
45
46 if (px == NULL)
47 px = &dumm;
48 if (py == NULL)
49 py = &dumm;
50 if (pwidth == NULL)
51 pwidth = &udumm;
52 if (pheight == NULL)
53 pheight = &udumm;
54 if (pbw == NULL)
55 pbw = &udumm;
56
57 return (XGetGeometry
58 (dpy, pc->w, &wdumm, px, py, pwidth, pheight, pbw, &udumm) != 0);
59 }
60
set_canvas_shape_to_rectangle(ASCanvas * pc)61 static void set_canvas_shape_to_rectangle (ASCanvas * pc)
62 {
63 #ifdef SHAPE
64 unsigned int width, height, bw;
65 XRectangle rect;
66
67 rect.x = 0;
68 rect.y = 0;
69 #ifdef STRICT_GEOMETRY
70 get_current_canvas_geometry (pc, NULL, NULL, &width, &height, &bw);
71 #else
72 width = pc->width;
73 height = pc->height;
74 bw = pc->bw;
75 #endif
76 rect.width = width + bw * 2;
77 rect.height = height + bw * 2;
78 LOCAL_DEBUG_OUT ("XShapeCombineRectangles(%lX) (%dx%d%+d%+d)", pc->w,
79 rect.width, rect.height, -bw, -bw);
80 XShapeCombineRectangles (dpy, pc->w, ShapeBounding, -bw, -bw, &rect, 1,
81 ShapeSet, Unsorted);
82 set_flags (pc->state, CANVAS_SHAPE_SET);
83 #endif
84 }
85
set_canvas_shape_to_nothing(ASCanvas * pc)86 static void set_canvas_shape_to_nothing (ASCanvas * pc)
87 {
88 #ifdef SHAPE
89 LOCAL_DEBUG_OUT ("XShapeCombineMask(%lX) (clearing mask)", pc->w);
90 XShapeCombineMask (dpy, pc->w, ShapeBounding, 0, 0, None, ShapeSet);
91 clear_flags (pc->state, CANVAS_SHAPE_SET);
92 #endif
93 if (pc->shape)
94 destroy_shape (&pc->shape);
95 }
96
97
98
99
100 /********************************************************************/
101 /* ASCanvas : */
102 /********************************************************************/
refresh_canvas_config(ASCanvas * pc)103 static ASFlagType refresh_canvas_config (ASCanvas * pc)
104 {
105 ASFlagType changed = 0;
106
107 if (pc && pc->w != None) {
108 int root_x = pc->root_x, root_y = pc->root_y, dumm;
109 unsigned int width = pc->width, height = pc->height, udumm;
110 Window wdumm;
111 unsigned int bw;
112
113 XTranslateCoordinates (dpy, pc->w, ASDefaultRoot, 0, 0, &root_x,
114 &root_y, &wdumm);
115 XGetGeometry (dpy, pc->w, &wdumm, &dumm, &dumm, &udumm, &udumm, &bw,
116 &udumm);
117 root_x -= bw;
118 root_y -= bw;
119 if (root_x != pc->root_x)
120 set_flags (changed, CANVAS_X_CHANGED);
121 if (root_y != pc->root_y)
122 set_flags (changed, CANVAS_Y_CHANGED);
123 pc->root_x = root_x;
124 pc->root_y = root_y;
125 pc->bw = bw;
126
127 if (!get_drawable_size (pc->w, &width, &height))
128 return 0; /* drawable is bad */
129 if (width != pc->width)
130 set_flags (changed, CANVAS_WIDTH_CHANGED);
131 if (height != pc->height)
132 set_flags (changed, CANVAS_HEIGHT_CHANGED);
133
134 clear_flags (pc->state, CANVAS_CONFIG_INVALID);
135
136 if (width != pc->width || height != pc->height) {
137 destroy_visual_pixmap (ASDefaultVisual, &(pc->saved_canvas));
138 destroy_visual_pixmap (ASDefaultVisual, &(pc->canvas));
139
140 if (pc->saved_shape)
141 destroy_shape (&(pc->saved_shape));
142
143 if (pc->shape) {
144 destroy_shape (&(pc->shape));
145 }
146 set_flags (pc->state, CANVAS_DIRTY | CANVAS_OUT_OF_SYNC);
147 pc->width = width;
148 pc->height = height;
149 }
150 }
151 return changed;
152 }
153
get_canvas_canvas(ASCanvas * pc)154 Pixmap get_canvas_canvas (ASCanvas * pc)
155 {
156 if (pc == NULL)
157 return None;
158 if (get_flags (pc->state, CANVAS_CONTAINER))
159 return None;
160 LOCAL_DEBUG_CALLER_OUT ("ASCanvas(%p)->canvas(%lX)", pc, pc->canvas);
161 if (pc->canvas == None) {
162 pc->canvas =
163 create_visual_pixmap (ASDefaultVisual, ASDefaultRoot, pc->width,
164 pc->height, 0);
165 set_flags (pc->state, CANVAS_DIRTY | CANVAS_OUT_OF_SYNC);
166 XSetWindowBackgroundPixmap (dpy, pc->w, pc->canvas);
167 }
168 return pc->canvas;
169 }
170
create_ascanvas(Window w)171 ASCanvas *create_ascanvas (Window w)
172 {
173 ASCanvas *pc = NULL;
174
175 if (w) {
176 pc = safecalloc (1, sizeof (ASCanvas));
177 pc->w = w;
178 refresh_canvas_config (pc);
179 LOCAL_DEBUG_CALLER_OUT
180 ("<<#########>>canvas %p created for w: %lX; geom = %dx%d%+d%+d, bw = %d",
181 pc, pc->w, pc->width, pc->height, pc->root_x, pc->root_y, pc->bw);
182 }
183 return pc;
184 }
185
create_ascanvas_container(Window w)186 ASCanvas *create_ascanvas_container (Window w)
187 {
188 ASCanvas *pc = NULL;
189
190 if (w) {
191 pc = safecalloc (1, sizeof (ASCanvas));
192 pc->w = w;
193 pc->state = CANVAS_CONTAINER;
194 refresh_canvas_config (pc);
195 LOCAL_DEBUG_CALLER_OUT
196 ("<<#########>>container canvas %p created for w: %lX; geom = %dx%d%+d%+d, bw = %d",
197 pc, pc->w, pc->width, pc->height, pc->root_x, pc->root_y, pc->bw);
198 }
199 return pc;
200 }
201
destroy_ascanvas(ASCanvas ** pcanvas)202 void destroy_ascanvas (ASCanvas ** pcanvas)
203 {
204 if (pcanvas) {
205 ASCanvas *pc = *pcanvas;
206
207 LOCAL_DEBUG_CALLER_OUT
208 ("<<#########>>destroying canvas %p for window %lX", pc,
209 pc ? pc->w : None);
210 if (pc) {
211 destroy_visual_pixmap (ASDefaultVisual, &(pc->saved_canvas));
212 destroy_visual_pixmap (ASDefaultVisual, &(pc->canvas));
213 LOCAL_DEBUG_OUT ("saved_shape = %p, shape = %p", pc->saved_shape,
214 pc->shape);
215 if (pc->saved_shape && pc->saved_shape != pc->shape)
216 destroy_shape (&(pc->saved_shape));
217 if (pc->shape)
218 destroy_shape (&(pc->shape));
219 memset (pc, 0x00, sizeof (ASCanvas));
220 free (pc);
221 }
222 *pcanvas = NULL;
223 }
224 }
225
handle_canvas_config(ASCanvas * canvas)226 ASFlagType handle_canvas_config (ASCanvas * canvas)
227 {
228 ASFlagType res;
229
230 LOCAL_DEBUG_CALLER_OUT
231 ("canvas(%p)->window(%lx)->orig_geom(%ux%u%+d%+d)", canvas,
232 canvas->w, canvas->width, canvas->height, canvas->root_x,
233 canvas->root_y);
234 res = refresh_canvas_config (canvas);
235 LOCAL_DEBUG_CALLER_OUT
236 ("canvas(%p)->window(%lx)->new__geom(%ux%u%+d%+d)->change(0x%lX)",
237 canvas, canvas->w, canvas->width, canvas->height, canvas->root_x,
238 canvas->root_y, res);
239 return res;
240 }
241
invalidate_canvas_config(ASCanvas * pc)242 void invalidate_canvas_config (ASCanvas * pc)
243 {
244 if (pc) {
245 if (get_flags (pc->state, CANVAS_CONFIG_INVALID))
246 return;
247
248 LOCAL_DEBUG_OUT ("resizing to %dx%d", pc->width + 1, pc->height + 1);
249 XResizeWindow (dpy, pc->w, pc->width + 1, pc->height + 1);
250 #ifdef SHAPE
251 if (!get_flags (pc->state, CANVAS_CONTAINER)
252 && get_flags (pc->state, CANVAS_SHAPE_SET))
253 set_canvas_shape_to_nothing (pc);
254 #endif
255
256 pc->width = 0;
257 pc->height = 0;
258 destroy_visual_pixmap (ASDefaultVisual, &(pc->canvas));
259 destroy_visual_pixmap (ASDefaultVisual, &(pc->saved_canvas));
260 if (pc->shape)
261 destroy_shape (&(pc->shape));
262 if (pc->saved_shape)
263 destroy_shape (&(pc->saved_shape));
264 set_flags (pc->state,
265 CANVAS_DIRTY | CANVAS_OUT_OF_SYNC |
266 CANVAS_MASK_OUT_OF_SYNC);
267 set_flags (pc->state, CANVAS_CONFIG_INVALID);
268 }
269 }
270
271 Bool
get_canvas_position(ASCanvas * pc,Window * pparent,int * px,int * py,unsigned int * pbw)272 get_canvas_position (ASCanvas * pc, Window * pparent, int *px, int *py,
273 unsigned int *pbw)
274 {
275 Window wdumm;
276 int dumm;
277 unsigned int udumm;
278
279 if (pparent == NULL)
280 pparent = &wdumm;
281 if (px == NULL)
282 px = &dumm;
283 if (py == NULL)
284 py = &dumm;
285 if (pbw == NULL)
286 pbw = &udumm;
287 if (pc)
288 if (XGetGeometry
289 (dpy, pc->w, pparent, px, py, &udumm, &udumm, pbw, &udumm))
290 return True;
291 return False;
292 }
293
294 Bool
make_canvas_rectangle(ASCanvas * pc,ASImage * im,int x,int y,int * cx,int * cy,int * cwidth,int * cheight)295 make_canvas_rectangle (ASCanvas * pc, ASImage * im, int x, int y, int *cx,
296 int *cy, int *cwidth, int *cheight)
297 {
298 if (pc == NULL || im == NULL || cx == NULL || cy == NULL
299 || cwidth == NULL || cheight == NULL)
300 return False;
301 *cwidth = im->width;
302 *cheight = im->height;
303 *cx = x;
304 *cy = y;
305 if (x + *cwidth <= 0 || x > pc->width)
306 return False;
307 if (y + *cheight <= 0 || y > pc->height)
308 return False;
309
310 if (*cx < 0) {
311 *cwidth += *cx;
312 *cx = 0;
313 }
314 if (*cx + *cwidth > pc->width)
315 *cwidth = pc->width - *cx;
316 if (*cy < 0) {
317 *cheight += *cy;
318 *cy = 0;
319 }
320 if (*cy + *cheight > pc->height)
321 *cheight = pc->height - *cy;
322 return True;
323 }
324
325
draw_canvas_image(ASCanvas * pc,ASImage * im,int x,int y)326 Bool draw_canvas_image (ASCanvas * pc, ASImage * im, int x, int y)
327 {
328 Pixmap p;
329 int real_x, real_y;
330 int width, height;
331 Bool done = False;
332
333 LOCAL_DEBUG_CALLER_OUT ("pc(%p)->im(%p)->x(%d)->y(%d)", pc, im, x, y);
334 if (im == NULL || pc == NULL)
335 return False;
336 if ((p = get_canvas_canvas (pc)) == None)
337 return False;
338
339 if (!make_canvas_rectangle
340 (pc, im, x, y, &real_x, &real_y, &width, &height))
341 return False;
342
343 LOCAL_DEBUG_OUT ("drawing image %dx%d at %dx%d%+d%+d", im->width,
344 im->height, width, height, real_x, real_y);
345 if (get_flags (ASDefaultVisual->glx_support, ASGLX_UseForImageTx))
346 done = asimage2drawable_gl (ASDefaultVisual, p, im,
347 real_x - x, real_y - y, real_x, real_y,
348 width, height, pc->width, pc->height,
349 False);
350 if (!done)
351 done =
352 asimage2drawable (ASDefaultVisual, p, im, ASDefaultDrawGC,
353 real_x - x, real_y - y, real_x, real_y, width,
354 height, True);
355
356 if (done) {
357 set_flags (pc->state, CANVAS_OUT_OF_SYNC);
358 XClearArea (dpy, pc->w, real_x, real_y, width, height, True);
359 XSync (dpy, False);
360 }
361 return done;
362 }
363
364 void
fill_canvas_mask(ASCanvas * pc,int win_x,int win_y,int width,int height)365 fill_canvas_mask (ASCanvas * pc, int win_x, int win_y, int width,
366 int height)
367 {
368 int real_x, real_y;
369 int real_width, real_height;
370
371 if (pc == NULL)
372 return;
373
374 if (pc->shape != None && !get_flags (pc->state, CANVAS_CONTAINER)) {
375 real_x = MAX (win_x, 0);
376 real_y = MAX (win_y, 0);
377 real_width = width - (real_x - win_x);
378 real_height = height - (real_y - win_y);
379 if (real_width > 0 && real_height > 0 && real_x < pc->width
380 && real_y < pc->height) {
381 int res;
382 XRectangle rect;
383
384 rect.x = real_x;
385 rect.y = real_y;
386 rect.width = real_width;
387 rect.height = real_height;
388 LOCAL_DEBUG_OUT ("filling mask at %dx%d%+d%+d", rect.width,
389 rect.height, rect.x, rect.y);
390 res =
391 add_shape_rectangles (pc->shape, &rect, 1, 0, 0, pc->width,
392 pc->height);
393 if (res)
394 set_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC);
395 }
396 }
397 }
398
399
draw_canvas_mask(ASCanvas * pc,ASImage * im,int x,int y)400 Bool draw_canvas_mask (ASCanvas * pc, ASImage * im, int x, int y)
401 {
402 XRectangle *rects;
403 unsigned int rects_count = 0;
404 Bool res = True;
405 int real_x, real_y;
406 int width, height;
407
408 if (im == NULL || pc == NULL)
409 return False;
410
411 if (!make_canvas_rectangle
412 (pc, im, x, y, &real_x, &real_y, &width, &height))
413 return False;
414
415 rects = get_asimage_channel_rects (im, IC_ALPHA, 10, &rects_count);
416 LOCAL_DEBUG_OUT ("%d rectangles generated", rects_count);
417
418 if (pc->shape == NULL)
419 pc->shape = create_shape ();
420
421 if (rects != NULL && rects_count > 0) {
422 res =
423 add_shape_rectangles (pc->shape, rects, rects_count, real_x,
424 real_y, pc->width + pc->bw,
425 pc->height + pc->bw);
426 free (rects);
427 }
428
429 if (res)
430 set_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC);
431 return res;
432 }
433
434 inline Bool
get_current_canvas_size(ASCanvas * pc,unsigned int * pwidth,unsigned int * pheight)435 get_current_canvas_size (ASCanvas * pc, unsigned int *pwidth,
436 unsigned int *pheight)
437 {
438 if (pc == NULL)
439 return False;
440
441 *pwidth = pc->width;
442 *pheight = pc->height;
443 if (get_flags (pc->state, CANVAS_CONFIG_INVALID))
444 return get_drawable_size (pc->w, pwidth, pheight);
445 return True;
446 }
447
448
449
update_canvas_display_mask(ASCanvas * pc,Bool force)450 void update_canvas_display_mask (ASCanvas * pc, Bool force)
451 {
452 #ifdef SHAPE
453 LOCAL_DEBUG_CALLER_OUT ("canvas(%p)", pc);
454 if (pc == NULL)
455 return;
456 LOCAL_DEBUG_OUT ("window(%lx)->canvas_pixmap(%lx)->size(%dx%d)", pc->w,
457 pc->canvas, pc->width, pc->height);
458 if (pc->w != None) {
459 if (force || !get_flags (pc->state, CANVAS_CONTAINER)) {
460 if (pc->shape) {
461 LOCAL_DEBUG_OUT
462 ("XShapeCombineREctangles(%lX)set canvas mask to %d rectangles",
463 pc->w, PVECTOR_USED (pc->shape));
464 if (PVECTOR_USED (pc->shape) > 0)
465 XShapeCombineRectangles (dpy, pc->w, ShapeBounding, 0, 0,
466 PVECTOR_HEAD (XRectangle, pc->shape),
467 PVECTOR_USED (pc->shape), ShapeSet,
468 Unsorted);
469 else { /* we are still shaped - but completely opaque */
470
471 XRectangle nothing;
472
473 nothing.x = pc->width / 2;
474 nothing.y = pc->height / 2;
475 nothing.width = nothing.height = 1;
476 XShapeCombineRectangles (dpy, pc->w, ShapeBounding, 0, 0,
477 ¬hing, 1, ShapeSet, Unsorted);
478 }
479 if (pc->bw > 0) {
480 XRectangle border[4];
481
482 border[0].x = -pc->bw;
483 border[0].y = -pc->bw;
484 border[0].width = pc->width + pc->bw * 2;
485 border[0].height = pc->bw;
486 border[1].x = -pc->bw;
487 border[1].y = -pc->bw;
488 border[1].width = pc->bw;
489 border[1].height = pc->height + pc->bw * 2;
490 border[2].x = -pc->bw;
491 border[2].y = pc->height;
492 border[2].width = pc->width + pc->bw * 2;
493 border[2].height = pc->bw;
494 border[3].x = pc->width;
495 border[3].y = -pc->bw;
496 border[3].width = pc->bw;
497 border[3].height = pc->height + pc->bw * 2;
498 XShapeCombineRectangles (dpy, pc->w, ShapeBounding, 0, 0,
499 &(border[0]), 4, ShapeUnion, Unsorted);
500 }
501 set_flags (pc->state, CANVAS_SHAPE_SET);
502 } else if (get_flags (pc->state, CANVAS_SHAPE_SET))
503 set_canvas_shape_to_nothing (pc);
504 XSync (dpy, False);
505 clear_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC);
506 }
507 }
508 #endif
509 }
510
511
512 #ifdef TRACE_update_canvas_display
513 #undef update_canvas_display
514 void update_canvas_display (ASCanvas * pc);
515 void
trace_update_canvas_display(ASCanvas * pc,const char * file,int line)516 trace_update_canvas_display (ASCanvas * pc, const char *file, int line)
517 {
518 fprintf (stderr, "D>%s(%d):update_canvas_display(%p)\n", file, line, pc);
519 update_canvas_display (pc);
520 }
521 #endif
522
523
update_canvas_display(ASCanvas * pc)524 void update_canvas_display (ASCanvas * pc)
525 {
526 LOCAL_DEBUG_CALLER_OUT ("canvas(%p)", pc);
527 if (pc == NULL)
528 return;
529
530 LOCAL_DEBUG_OUT ("window(%lx)->canvas_pixmap(%lx)->size(%dx%d)", pc->w,
531 pc->canvas, pc->width, pc->height);
532 if (pc && pc->w != None) {
533 if (!get_flags (pc->state, CANVAS_CONTAINER)) {
534 if (pc->canvas) {
535 #ifdef SHAPE
536 update_canvas_display_mask (pc, False);
537 #endif
538 XSetWindowBackgroundPixmap (dpy, pc->w, pc->canvas);
539 XClearWindow (dpy, pc->w);
540
541 XSync (dpy, False);
542 clear_flags (pc->state,
543 CANVAS_DIRTY | CANVAS_OUT_OF_SYNC |
544 CANVAS_MASK_OUT_OF_SYNC);
545 }
546 }
547 }
548 }
549
invalidate_canvas_save(ASCanvas * pc)550 void invalidate_canvas_save (ASCanvas * pc)
551 {
552 if (pc) {
553 destroy_visual_pixmap (ASDefaultVisual, &(pc->saved_canvas));
554 destroy_shape (&(pc->saved_shape));
555 }
556 }
557
558
restore_canvas(ASCanvas * pc)559 Bool restore_canvas (ASCanvas * pc)
560 {
561 if (pc) {
562 if (pc->saved_canvas == None)
563 return False;
564
565 destroy_visual_pixmap (ASDefaultVisual, &(pc->canvas));
566 pc->canvas = pc->saved_canvas;
567 pc->saved_canvas = None;
568
569
570 destroy_shape (&(pc->shape));
571 pc->shape = pc->saved_shape;
572 pc->saved_shape = NULL;
573
574 update_canvas_display (pc);
575 return True;
576 }
577 return False;
578 }
579
save_canvas(ASCanvas * pc)580 Bool save_canvas (ASCanvas * pc)
581 {
582 if (pc) {
583 destroy_visual_pixmap (ASDefaultVisual, &(pc->saved_canvas));
584 pc->saved_canvas = pc->canvas;
585 pc->canvas = None;
586
587 destroy_shape (&(pc->saved_shape));
588 pc->saved_shape = pc->shape;
589 pc->shape = NULL;
590
591 set_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC | CANVAS_OUT_OF_SYNC);
592 return (pc->saved_canvas != None);
593 }
594 return False;
595 }
596
swap_save_canvas(ASCanvas * pc)597 Bool swap_save_canvas (ASCanvas * pc)
598 {
599 Pixmap tmp_canvas;
600 struct ASVector *tmp_shape;
601
602 if (pc) {
603 tmp_canvas = pc->saved_canvas;
604 pc->saved_canvas = pc->canvas;
605 pc->canvas = tmp_canvas;
606
607 tmp_shape = pc->saved_shape;
608 pc->saved_shape = pc->shape;
609 pc->shape = tmp_shape;
610
611 set_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC | CANVAS_OUT_OF_SYNC);
612 return (pc->canvas != None);
613 }
614 return False;
615
616 }
617
618
clear_canvas_shape(ASCanvas * pc,Bool force_for_container)619 void clear_canvas_shape (ASCanvas * pc, Bool force_for_container)
620 {
621 LOCAL_DEBUG_CALLER_OUT ("canvas(%p)", pc);
622 if (pc == NULL)
623 return;
624
625 LOCAL_DEBUG_OUT ("window(%lx)->canvas_pixmap(%lx)->size(%dx%d)", pc->w,
626 pc->canvas, pc->width, pc->height);
627 if (pc->w != None) {
628 if (!get_flags (pc->state, CANVAS_CONTAINER) || force_for_container) {
629 #ifdef SHAPE
630 if (pc->canvas && get_flags (pc->state, CANVAS_SHAPE_SET))
631 set_canvas_shape_to_rectangle (pc); /* just in case */
632 set_canvas_shape_to_nothing (pc);
633 #endif
634 if (pc->shape)
635 destroy_shape (&pc->shape);
636 set_flags (pc->state, CANVAS_DIRTY | CANVAS_OUT_OF_SYNC);
637 }
638 }
639 }
640
check_canvas_shaped(ASCanvas * pc)641 Bool check_canvas_shaped (ASCanvas * pc)
642 {
643 Bool boundingShaped = False;
644
645 #ifdef SHAPE
646 if (pc) {
647 int dumm;
648 unsigned udumm;
649
650 XShapeQueryExtents (dpy, pc->w,
651 &boundingShaped, &dumm, &dumm, &udumm, &udumm,
652 &dumm, &dumm, &dumm, &udumm, &udumm);
653 }
654 #endif
655 return boundingShaped;
656 }
657
refresh_container_shape(ASCanvas * pc)658 Bool refresh_container_shape (ASCanvas * pc)
659 {
660 int res = False;
661
662 if (pc && get_flags (pc->state, CANVAS_CONTAINER)) {
663 int count, order;
664 XRectangle *rects;
665
666 #ifdef SHAPE
667 rects =
668 XShapeGetRectangles (dpy, pc->w, ShapeBounding, &count, &order);
669 #endif
670 if (rects) {
671 unsigned int curr_width = 1, curr_height = 1;
672
673 if (pc->shape == NULL)
674 pc->shape = create_shape ();
675 else
676 flush_vector (pc->shape);
677 get_drawable_size (pc->w, &curr_width, &curr_height);
678 res =
679 add_shape_rectangles (pc->shape, rects, count, 0, 0,
680 curr_width + pc->bw * 2,
681 curr_height + pc->bw * 2);
682 XFree (rects);
683
684 if (res)
685 set_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC);
686 } else if (pc->shape) {
687 destroy_shape (&(pc->shape));
688 set_flags (pc->state, CANVAS_MASK_OUT_OF_SYNC);
689 res = True;
690 }
691 }
692 return res;
693 }
694
695
696 Bool
combine_canvas_shape_at_geom(ASCanvas * parent,ASCanvas * child,int child_x,int child_y,int child_width,int child_height,int child_bw)697 combine_canvas_shape_at_geom (ASCanvas * parent, ASCanvas * child,
698 int child_x, int child_y, int child_width,
699 int child_height, int child_bw)
700 {
701 int res = False;
702
703 #ifdef SHAPE
704 LOCAL_DEBUG_OUT ("parent(%p),child(%p)", parent, child);
705 if (parent && child) {
706 unsigned int parent_width, parent_height;
707
708 LOCAL_DEBUG_OUT ("parent->shape(%p)", parent->shape);
709 if (parent->shape == NULL)
710 return False;
711
712 LOCAL_DEBUG_OUT ("child->shape(%p)", child->shape);
713 if (child->shape != NULL && PVECTOR_USED (child->shape) == 0) {
714 LOCAL_DEBUG_OUT ("child->shape has no rectangles%s", "");
715 return False; /* child has an empty shape */
716 }
717 #ifdef STRICT_GEOMETRY
718 get_current_canvas_size (parent, &parent_width, &parent_height);
719 #else
720 parent_width = parent->width;
721 parent_height = parent->height;
722 #endif
723
724 if (child_x > parent_width || child_y > parent_height ||
725 child_x + child_width <= 0 || child_y + child_height <= 0) {
726 #ifdef LOCAL_DEBUG
727 if (get_flags (child->state, CANVAS_CONTAINER))
728 LOCAL_DEBUG_OUT
729 ("container shape ignored - out of bounds: %dx%d%+d%+d parents: %dx%d%+d%+d",
730 child_width, child_height, child_x, child_y, parent_width,
731 parent_height, parent->root_x, parent->root_y);
732 #endif
733 return False;
734 }
735 #if 1
736 if (child->shape && PVECTOR_USED (child->shape) > 0) {
737 LOCAL_DEBUG_OUT ("adding %d child's shape rectangles",
738 PVECTOR_USED (child->shape));
739 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
740 {
741 int i, max_i = PVECTOR_USED (child->shape);
742 XRectangle *r = PVECTOR_HEAD (XRectangle, child->shape);
743
744 for (i = 0; i < max_i; ++i)
745 fprintf (stderr, "\t\t r[%d] = %dx%d%+d%+d\n", i, r[i].width,
746 r[i].height, r[i].x, r[i].y);
747 }
748 LOCAL_DEBUG_OUT ("child geom = %dx%d%+d%+d, bw = %d", child_width,
749 child_height, child_x, child_y, child_bw);
750 #endif
751 res =
752 add_shape_rectangles (parent->shape,
753 PVECTOR_HEAD (XRectangle, child->shape),
754 PVECTOR_USED (child->shape),
755 child_x + child_bw, child_y + child_bw,
756 parent_width, parent_height);
757 if (res && child_bw > 0) {
758 XRectangle border[4];
759
760 border[0].x = 0;
761 border[0].y = 0;
762 border[0].width = child_width + child_bw;
763 border[0].height = child_bw;
764 border[1].x = 0;
765 border[1].y = child_bw;
766 border[1].width = child_bw;
767 border[1].height = child_height;
768 border[2].x = child_width + child_bw;
769 border[2].y = 0;
770 border[2].width = child_bw;
771 border[2].height = child_height + child_bw * 2;
772 border[3].x = 0;
773 border[3].y = child_height + child_bw;
774 border[3].width = child_width + child_bw * 2;
775 border[3].height = child_bw;
776 res =
777 add_shape_rectangles (parent->shape, &(border[0]), 4, child_x,
778 child_y, parent_width, parent_height);
779 }
780 } else
781 #endif
782 {
783 XRectangle rect;
784
785 rect.x = child_x;
786 rect.y = child_y;
787 rect.width = child_width + child_bw * 2;
788 rect.height = child_height + child_bw * 2;
789 LOCAL_DEBUG_OUT
790 ("adding child's shape as whole rectangle: %dx%d%+d%+d",
791 rect.width, rect.height, rect.x, rect.y);
792
793 res =
794 add_shape_rectangles (parent->shape, &rect, 1, 0, 0,
795 parent_width + parent->bw * 2,
796 parent_height + parent->bw * 2);
797 }
798 }
799 #endif
800 return res;
801 }
802
combine_canvas_shape(ASCanvas * parent,ASCanvas * child)803 Bool combine_canvas_shape (ASCanvas * parent, ASCanvas * child)
804 {
805 int res = False;
806
807 #ifdef SHAPE
808 if (parent && child) {
809 int child_x = 0;
810 int child_y = 0;
811 unsigned int width, height, bw;
812
813 if (parent->shape == NULL)
814 return False;
815 #ifndef STRICT_GEOMETRY
816 get_current_canvas_geometry (child, &child_x, &child_y, &width,
817 &height, &bw);
818 #else
819 child_x = child->root_x - parent->root_x;
820 child_y = child->root_y - parent->root_y;
821 width = child->width;
822 height = child->height;
823 bw = child->bw;
824 #endif
825 res =
826 combine_canvas_shape_at_geom (parent, child, child_x, child_y,
827 width, height, bw);
828 }
829 #endif
830 return res;
831 }
832
833
834 Bool
combine_canvas_shape_at(ASCanvas * parent,ASCanvas * child,int child_x,int child_y)835 combine_canvas_shape_at (ASCanvas * parent, ASCanvas * child, int child_x,
836 int child_y)
837 {
838 #ifdef SHAPE
839 if (child) {
840 unsigned int width, height, bw;
841
842 #ifndef STRICT_GEOMETRY
843 get_current_canvas_geometry (child, NULL, NULL, &width, &height, &bw);
844 #else
845 width = child->width;
846 height = child->height;
847 bw = child->bw;
848 #endif
849
850 return combine_canvas_shape_at_geom (parent, child, child_x, child_y,
851 width, height, bw);
852 }
853 #endif
854 return False;
855 }
856
is_canvas_needs_redraw(ASCanvas * pc)857 Bool is_canvas_needs_redraw (ASCanvas * pc)
858 {
859 return pc ? get_flags (pc->state, CANVAS_DIRTY) : False;
860 }
861
is_canvas_dirty(ASCanvas * pc)862 Bool is_canvas_dirty (ASCanvas * pc)
863 {
864 return pc ? get_flags (pc->state,
865 CANVAS_DIRTY | CANVAS_OUT_OF_SYNC |
866 CANVAS_MASK_OUT_OF_SYNC) : False;
867 }
868
869
870 ASFlagType
configure_canvas(ASCanvas * pc,int x,int y,unsigned int width,unsigned int height,ASFlagType mask)871 configure_canvas (ASCanvas * pc, int x, int y, unsigned int width,
872 unsigned int height, ASFlagType mask)
873 {
874 ASFlagType changes = 0;
875 XWindowChanges xwc;
876 int curr_x, curr_y;
877 unsigned int curr_width, curr_height, curr_bw;
878
879 if (pc == NULL)
880 return 0;
881
882 get_current_canvas_geometry (pc, &curr_x, &curr_y, &curr_width,
883 &curr_height, &curr_bw);
884
885 LOCAL_DEBUG_CALLER_OUT ("canvas(%p)->window(%lx)->geom(%ux%u%+d%+d)", pc,
886 pc->w, width, height, x, y);
887 /* Setting background to None to avoid background pixmap tiling
888 * while resizing */
889 if (!get_flags (mask, CWWidth))
890 width = pc->width;
891 else if (width > MAX_POSITION) {
892 #ifdef DEBUG_ALLOCS
893 AS_ASSERT (0);
894 #endif
895 width = pc->width;
896 } else if (AS_ASSERT (width))
897 width = 1;
898
899 if (!get_flags (mask, CWHeight))
900 height = pc->height;
901 else if (height > MAX_POSITION) {
902 #ifdef DEBUG_ALLOCS
903 AS_ASSERT (0);
904 #endif
905 height = pc->height;
906 } else if (AS_ASSERT (height))
907 height = 1;
908
909 if (get_flags (mask, CWX) && curr_x != x)
910 set_flags (changes, CANVAS_X_CHANGED);
911 if (get_flags (mask, CWY) && curr_y != y)
912 set_flags (changes, CANVAS_Y_CHANGED);
913 if (width != curr_width)
914 set_flags (changes, CANVAS_WIDTH_CHANGED);
915 if (height != curr_height)
916 set_flags (changes, CANVAS_HEIGHT_CHANGED);
917
918 if (changes == 0)
919 return 0;
920 xwc.x = x;
921 xwc.y = y;
922 xwc.width = width;
923 xwc.height = height;
924
925 if ((pc->width < width || pc->height < height)
926 && !get_flags (pc->state, CANVAS_CONTAINER))
927 XSetWindowBackgroundPixmap (dpy, pc->w, None);
928
929 LOCAL_DEBUG_OUT ("XConfigureWindow( %lX, %lX, %dx%d%+d%+d );", pc->w,
930 mask, width, height, x, y);
931 XConfigureWindow (dpy, pc->w, mask, &xwc);
932 /*fprintf( stderr, "client_changes: ( %lX, %lX, %dx%d%+d%+d ); was %dx%d%+d%+d\n", pc->w, mask, width, height, x, y, curr_width, curr_height, curr_x, curr_y );*/
933 return changes;
934 }
935
936 ASFlagType
resize_canvas(ASCanvas * pc,unsigned int width,unsigned int height)937 resize_canvas (ASCanvas * pc, unsigned int width, unsigned int height)
938 {
939 if (pc == NULL)
940 return 0;
941
942 return configure_canvas (pc, 0, 0, width, height, CWWidth | CWHeight);
943 }
944
945
946
947 ASFlagType
moveresize_canvas(ASCanvas * pc,int x,int y,unsigned int width,unsigned int height)948 moveresize_canvas (ASCanvas * pc, int x, int y, unsigned int width,
949 unsigned int height)
950 {
951 if (pc == NULL)
952 return 0;
953 return configure_canvas (pc, x, y, width, height,
954 CWX | CWY | CWWidth | CWHeight);
955 }
956
957
move_canvas(ASCanvas * pc,int x,int y)958 void move_canvas (ASCanvas * pc, int x, int y)
959 {
960 if (pc == NULL)
961 return;
962
963 LOCAL_DEBUG_CALLER_OUT ("canvas(%p)->window(%lx)->geom(%+d%+d)", pc,
964 pc->w, x, y);
965 XMoveWindow (dpy, pc->w, x, y);
966 }
967
968
unmap_canvas_window(ASCanvas * pc)969 void unmap_canvas_window (ASCanvas * pc)
970 {
971 if (pc && pc->w != None) {
972 XUnmapWindow (dpy, pc->w);
973 clear_flags (pc->state, CANVAS_MAPPED);
974 }
975 }
976
map_canvas_window(ASCanvas * pc,Bool raised)977 void map_canvas_window (ASCanvas * pc, Bool raised)
978 {
979 LOCAL_DEBUG_CALLER_OUT ("pc=%p", pc);
980 if (pc == NULL)
981 return;
982
983 LOCAL_DEBUG_OUT ("raised = %s", raised ? "True" : "False");
984 if (pc->w != None) {
985 if (raised)
986 XMapRaised (dpy, pc->w);
987 else
988 XMapWindow (dpy, pc->w);
989 set_flags (pc->state, CANVAS_MAPPED);
990 }
991 }
992
993 void
quietly_reparent_canvas(ASCanvas * pc,Window dst,long event_mask,Bool use_root_pos,Window below)994 quietly_reparent_canvas (ASCanvas * pc, Window dst, long event_mask,
995 Bool use_root_pos, Window below)
996 {
997 if (pc) {
998 int x = 0, y = 0;
999 unsigned int bw = pc->bw;
1000 Window parent = None;
1001
1002 if (dst == None)
1003 dst = ASDefaultRoot;
1004
1005 if (use_root_pos) {
1006 x = pc->root_x;
1007 y = pc->root_y;
1008 } else
1009 get_canvas_position (pc, &parent, &x, &y, &bw);
1010
1011 if (parent != dst) {
1012 /* blocking UnmapNotify events since that may bring us into Withdrawn state */
1013 XSelectInput (dpy, pc->w, event_mask & ~StructureNotifyMask);
1014 LOCAL_DEBUG_OUT ("XReparentWindow( %lX, %lX, %+d%+d ), bw = %d",
1015 pc->w, dst, x, y, bw);
1016 if (below != None && get_flags (pc->state, CANVAS_MAPPED)) {
1017 Window w[2];
1018
1019 XUnmapWindow (dpy, pc->w);
1020 XReparentWindow (dpy, pc->w, (dst != None) ? dst : ASDefaultRoot,
1021 x, y);
1022 w[0] = below;
1023 w[1] = pc->w;
1024 XRestackWindows (dpy, w, 2);
1025 XMapWindow (dpy, pc->w);
1026 } else
1027 XReparentWindow (dpy, pc->w, (dst != None) ? dst : ASDefaultRoot,
1028 x, y);
1029 XSelectInput (dpy, pc->w, event_mask);
1030 }
1031 }
1032 }
1033
reparent_canvas_window(ASCanvas * pc,Window dst,int x,int y)1034 void reparent_canvas_window (ASCanvas * pc, Window dst, int x, int y)
1035 {
1036 if (pc) {
1037 if (dst == None)
1038 dst = ASDefaultRoot;
1039 LOCAL_DEBUG_OUT ("XReparentWindow( %lX, %lX, +0+0 )", pc->w, dst);
1040 XReparentWindow (dpy, pc->w, dst, 0, 0);
1041 }
1042 }
1043
1044 void
add_canvas_grid(ASGrid * grid,ASCanvas * canvas,int outer_gravity,int inner_gravity,Bool absolute)1045 add_canvas_grid (ASGrid * grid, ASCanvas * canvas, int outer_gravity,
1046 int inner_gravity, Bool absolute)
1047 {
1048 if (canvas && grid) {
1049 unsigned long flags = absolute ? ASGL_Absolute : 0;
1050 int x = canvas->root_x;
1051 int y = canvas->root_y;
1052
1053 if (!absolute) {
1054 x += grid->curr_vx;
1055 y += grid->curr_vy;
1056 }
1057
1058 LOCAL_DEBUG_CALLER_OUT ("(%p,%ux%u%+d%+d)", canvas, canvas->width,
1059 canvas->height, canvas->root_x,
1060 canvas->root_y);
1061 add_gridline (grid, y, x, x + canvas->width + canvas->bw * 2,
1062 outer_gravity, inner_gravity, flags);
1063 add_gridline (grid, y + canvas->height + canvas->bw * 2, x,
1064 x + canvas->width + canvas->bw * 2, inner_gravity,
1065 outer_gravity, flags);
1066 set_flags (flags, ASGL_Vertical);
1067 add_gridline (grid, x, y, y + canvas->height + canvas->bw * 2,
1068 outer_gravity, inner_gravity, flags);
1069 add_gridline (grid, x + canvas->width + canvas->bw * 2, y,
1070 y + canvas->height + canvas->bw * 2, inner_gravity,
1071 outer_gravity, flags);
1072 }
1073 }
1074
set_root_clip_area(ASCanvas * canvas)1075 void set_root_clip_area (ASCanvas * canvas)
1076 {
1077 if (canvas) {
1078 ASDefaultScr->RootClipArea.x = canvas->root_x + (int)canvas->bw;
1079 ASDefaultScr->RootClipArea.y = canvas->root_y + (int)canvas->bw;
1080 ASDefaultScr->RootClipArea.width = canvas->width;
1081 ASDefaultScr->RootClipArea.height = canvas->height;
1082 if (ASDefaultScr->RootImage) {
1083 safe_asimage_destroy (ASDefaultScr->RootImage);
1084 ASDefaultScr->RootImage = NULL;
1085 }
1086 }
1087 }
1088
1089 /*************************************************************************/
1090
send_canvas_configure_notify(ASCanvas * parent,ASCanvas * canvas)1091 void send_canvas_configure_notify (ASCanvas * parent, ASCanvas * canvas)
1092 {
1093 LOCAL_DEBUG_CALLER_OUT ("%p,%p", parent, canvas);
1094 if (canvas) {
1095 XEvent client_event;
1096 unsigned int uwidth, uheight, ubw;
1097
1098 client_event.type = ConfigureNotify;
1099 client_event.xconfigure.display = dpy;
1100 client_event.xconfigure.event = canvas->w;
1101 client_event.xconfigure.window = canvas->w;
1102
1103 get_current_canvas_geometry (canvas, &(client_event.xconfigure.x),
1104 &(client_event.xconfigure.y), &uwidth,
1105 &uheight, &ubw);
1106 client_event.xconfigure.width = uwidth;
1107 client_event.xconfigure.height = uheight;
1108 client_event.xconfigure.border_width = ubw;
1109
1110 if (parent) {
1111 #if 1
1112 Window wdumm;
1113
1114 XTranslateCoordinates (dpy, canvas->w, ASDefaultRoot, 0, 0,
1115 &(client_event.xconfigure.x),
1116 &(client_event.xconfigure.y), &wdumm);
1117 #else /* we maybe called before parent's geometry is updated - so don't trust it! */
1118 client_event.xconfigure.x += parent->root_x + (int)parent->bw;
1119 client_event.xconfigure.y += parent->root_y + (int)parent->bw;
1120 #endif
1121 /* Real ConfigureNotify events say we're above title window, so ... */
1122 /* what if we don't have a title ????? */
1123 client_event.xconfigure.above = parent->w;
1124 } else
1125 client_event.xconfigure.above = ASDefaultRoot;
1126 client_event.xconfigure.override_redirect = False;
1127 LOCAL_DEBUG_OUT ("geom= %dx%d%+d%+d", client_event.xconfigure.width,
1128 client_event.xconfigure.height,
1129 client_event.xconfigure.x, client_event.xconfigure.y);
1130 XSendEvent (dpy, canvas->w, False, StructureNotifyMask, &client_event);
1131 }
1132 }
1133