1 #include "unix/guts.h"
2 #include "Icon.h"
3
4 #define pREGION GET_REGION(self)->region
5 #define pAPERTURE GET_REGION(self)->aperture
6
7 Region
prima_region_create(Handle mask)8 prima_region_create( Handle mask)
9 {
10 unsigned long w, h, x, y, size = 256, count = 0;
11 Region rgn = None;
12 Byte * idata;
13 XRectangle * current, * rdata;
14 Bool set = 0;
15
16 if ( !mask)
17 return None;
18
19 w = PImage( mask)-> w;
20 h = PImage( mask)-> h;
21 /*
22 XUnionRegion is actually SLOWER than the image scan -
23 - uncomment if this is wrong
24 if ( X( mask)-> cached_region) {
25 rgn = XCreateRegion();
26 XUnionRegion( rgn, X( mask)-> cached_region, rgn);
27 return rgn;
28 }
29 */
30
31 idata = PImage( mask)-> data + PImage( mask)-> dataSize - PImage( mask)-> lineSize;
32
33 rdata = ( XRectangle*) malloc( size * sizeof( XRectangle));
34 if ( !rdata) {
35 warn("Not enough memory");
36 return None;
37 }
38
39 count = 0;
40 current = rdata;
41 current--;
42
43 for ( y = 0; y < h; y++) {
44 for ( x = 0; x < w; x++) {
45 if ( idata[ x >> 3] == 0) {
46 x += 7;
47 continue;
48 }
49 if ( idata[ x >> 3] & ( 1 << ( 7 - ( x & 7)))) {
50 if ( set && current-> y == y && current-> x + current-> width == x)
51 current-> width++;
52 else {
53 set = 1;
54 if ( count >= size) {
55 void * xrdata = realloc( rdata, ( size *= 3) * sizeof( XRectangle));
56 if ( !xrdata) {
57 warn("Not enough memory");
58 free( rdata);
59 return None;
60 }
61 rdata = xrdata;
62 current = rdata;
63 current += count - 1;
64 }
65 count++;
66 current++;
67 current-> x = x;
68 current-> y = y;
69 current-> width = 1;
70 current-> height = 1;
71 }
72 }
73 }
74 idata -= PImage( mask)-> lineSize;
75 }
76
77 if ( set) {
78 rgn = XCreateRegion();
79 for ( x = 0, current = rdata; x < count; x++, current++)
80 XUnionRectWithRegion( current, rgn, rgn);
81
82 /*
83 X( mask)-> cached_region = XCreateRegion();
84 XUnionRegion( X( mask)-> cached_region, rgn, X( mask)-> cached_region);
85 */
86 }
87 free( rdata);
88
89 return rgn;
90 }
91
92 static Bool
rgn_empty(Handle self)93 rgn_empty(Handle self)
94 {
95 XRectangle xr;
96 pREGION = XCreateRegion();
97 xr. x = 0;
98 xr. y = 0;
99 xr. width = 1;
100 xr. height = 1;
101 XUnionRectWithRegion( &xr, pREGION, pREGION);
102 XXorRegion( pREGION, pREGION, pREGION);
103 pAPERTURE = 0;
104 return true;
105 }
106
107 static Bool
rgn_rect(Handle self,int count,Box * r)108 rgn_rect(Handle self, int count, Box * r)
109 {
110 int i, aperture;
111 Box * rr;
112 pREGION = XCreateRegion();
113
114 aperture = r->y + r->height;
115 for ( i = 0, rr = r; i < count; i++, rr++) {
116 if ( aperture < rr->y + rr->height)
117 aperture = rr->y + rr->height;
118 }
119
120 for ( i = 0; i < count; i++, r++) {
121 XRectangle xr;
122 xr. x = r-> x;
123 xr. y = aperture - r->y - r->height;
124 xr. width = r-> width;
125 xr. height = r-> height;
126 XUnionRectWithRegion( &xr, pREGION, pREGION);
127 }
128 pAPERTURE = aperture;
129 return true;
130 }
131
132 static Bool
rgn_polygon(Handle self,PolygonRegionRec * r)133 rgn_polygon(Handle self, PolygonRegionRec * r)
134 {
135 int i, max, open, xp_points;
136 XPoint * xp;
137
138 open =
139 r->points[r->n_points-1].x != r->points[0].x ||
140 r->points[r->n_points-1].y != r->points[0].y;
141 xp_points = r->n_points + (open ? 1 : 0);
142
143 if ( !( xp = malloc( sizeof(XPoint) * xp_points ))) {
144 warn("Not enough memory");
145 return false;
146 }
147
148 for ( i = 0, max = 0; i < r->n_points; i++) {
149 if ( max < r->points[i].y)
150 max = r->points[i].y;
151 }
152 max++;
153 for ( i = 0; i < r->n_points; i++) {
154 xp[i].x = r->points[i].x;
155 xp[i].y = max - r->points[i].y - 1;
156 }
157 if ( open ) {
158 xp[i].x = r->points[0].x;
159 xp[i].y = max - r->points[0].y - 1;
160 }
161
162 pAPERTURE = max;
163 pREGION = XPolygonRegion( xp, r->n_points,
164 ((r-> fill_mode & fmWinding) == fmAlternate) ? EvenOddRule : WindingRule);
165
166 if (( r->fill_mode & fmOverlay) == 0) goto NO_OVERLAY;
167
168 /* superimpose polyline points using Bresenham
169 because x11 regions are as broken as filled shapes */
170 for ( i = 0; i < xp_points-1; i++) {
171 int curr_maj, curr_min, to_maj, delta_maj, delta_min;
172 int delta_y, delta_x;
173 int dir = 0, d, d_inc1, d_inc2;
174 int inc_maj, inc_min;
175 int x, y, acc_x = 0, acc_y = INT_MIN, ox;
176 XPoint a = xp[i], b = xp[i+1];
177 delta_y = b.y - a.y;
178 delta_x = b.x - a.x;
179 if (abs(delta_y) > abs(delta_x)) dir = 1;
180
181 if (dir) {
182 curr_maj = a.y;
183 curr_min = a.x;
184 to_maj = b.y;
185 delta_maj = delta_y;
186 delta_min = delta_x;
187 } else {
188 curr_maj = a.x;
189 curr_min = a.y;
190 to_maj = b.x;
191 delta_maj = delta_x;
192 delta_min = delta_y;
193 }
194
195 if (delta_maj != 0)
196 inc_maj = (abs(delta_maj)==delta_maj ? 1 : -1);
197 else
198 inc_maj = 0;
199
200 if (delta_min != 0)
201 inc_min = (abs(delta_min)==delta_min ? 1 : -1);
202 else
203 inc_min = 0;
204
205 delta_maj = abs(delta_maj);
206 delta_min = abs(delta_min);
207
208 d = (delta_min << 1) - delta_maj;
209 d_inc1 = (delta_min << 1);
210 d_inc2 = ((delta_min - delta_maj) << 1);
211
212 x = INT_MIN;
213 while(1) {
214 ox = x;
215 if (dir) {
216 x = curr_min;
217 y = curr_maj;
218 } else {
219 x = curr_maj;
220 y = curr_min;
221 }
222 if ( acc_y != y ) {
223 if ( acc_y > INT_MIN) {
224 XRectangle xr;
225 xr. y = acc_y;
226 xr. height = 1;
227 if (ox < acc_x) {
228 xr.x = ox;
229 xr.width = acc_x - ox + 1;
230 } else {
231 xr.x = acc_x;
232 xr.width = ox - acc_x + 1;
233 }
234 XUnionRectWithRegion( &xr, pREGION, pREGION);
235 }
236 acc_x = x;
237 acc_y = y;
238 }
239
240 if (curr_maj == to_maj) break;
241 curr_maj += inc_maj;
242 if (d < 0) {
243 d += d_inc1;
244 } else {
245 d += d_inc2;
246 curr_min += inc_min;
247 }
248 }
249 if ( acc_y > INT_MIN) {
250 XRectangle xr;
251 xr. y = acc_y;
252 xr. height = 1;
253 if (x < acc_x) {
254 xr.x = x;
255 xr.width = acc_x - x + 1;
256 } else {
257 xr.x = acc_x;
258 xr.width = x - acc_x + 1;
259 }
260 XUnionRectWithRegion( &xr, pREGION, pREGION);
261 }
262 }
263
264 NO_OVERLAY:
265 free( xp );
266 return true;
267 }
268
269 static Bool
rgn_image(Handle self,Handle image)270 rgn_image(Handle self, Handle image)
271 {
272 pREGION = prima_region_create(image);
273
274 if ( !pREGION )
275 pREGION = XCreateRegion();
276 else
277 pAPERTURE = PImage(image)->h;
278 return true;
279 }
280
281 Bool
apc_region_create(Handle self,PRegionRec rec)282 apc_region_create( Handle self, PRegionRec rec)
283 {
284 switch( rec-> type ) {
285 case rgnEmpty:
286 return rgn_empty(self);
287 case rgnRectangle:
288 return rgn_rect(self, rec->data.box.n_boxes, rec->data.box.boxes);
289 case rgnPolygon:
290 return rgn_polygon(self, &rec->data.polygon);
291 case rgnImage:
292 return rgn_image(self, rec->data.image);
293 default:
294 return false;
295 }
296 }
297
298 Bool
apc_region_destroy(Handle self)299 apc_region_destroy( Handle self)
300 {
301 if ( pREGION ) {
302 XDestroyRegion(pREGION);
303 pREGION = NULL;
304 }
305 return true;
306 }
307
308 ApiHandle
apc_region_get_handle(Handle self)309 apc_region_get_handle( Handle self)
310 {
311 return (ApiHandle) pREGION;
312 }
313
314 Bool
apc_region_offset(Handle self,int dx,int dy)315 apc_region_offset( Handle self, int dx, int dy)
316 {
317 XOffsetRegion(pREGION, dx, -dy);
318 return true;
319 }
320
321 Bool
apc_region_combine(Handle self,Handle other_region,int rgnop)322 apc_region_combine( Handle self, Handle other_region, int rgnop)
323 {
324 PRegionSysData r2;
325 int d;
326 Bool ok = true;
327
328 r2 = GET_REGION(other_region);
329
330 if ( rgnop == rgnopCopy ) {
331 if ( pREGION ) XDestroyRegion( pREGION );
332 pREGION = XCreateRegion();
333 XUnionRegion( pREGION, r2->region, pREGION);
334 pAPERTURE = r2-> aperture;
335 return true;
336 }
337
338 d = pAPERTURE - r2-> aperture;
339 if ( d > 0 )
340 XOffsetRegion( r2-> region, 0, d);
341 else
342 XOffsetRegion( pREGION, 0, -d);
343
344 switch (rgnop) {
345 case rgnopIntersect:
346 XIntersectRegion( pREGION, r2->region, pREGION);
347 break;
348 case rgnopUnion:
349 XUnionRegion( pREGION, r2->region, pREGION);
350 break;
351 case rgnopXor:
352 XXorRegion( pREGION, r2->region, pREGION);
353 break;
354 case rgnopDiff:
355 XSubtractRegion( pREGION, r2->region, pREGION);
356 break;
357 default:
358 ok = false;
359 }
360 if ( d > 0 )
361 XOffsetRegion( r2-> region, 0, -d);
362 else
363 pAPERTURE = r2-> aperture;
364
365 return ok;
366 }
367
368 Bool
apc_region_point_inside(Handle self,Point p)369 apc_region_point_inside( Handle self, Point p)
370 {
371 return XPointInRegion( pREGION, p.x, pAPERTURE - p.y - 1);
372 }
373
374 int
apc_region_rect_inside(Handle self,Rect r)375 apc_region_rect_inside( Handle self, Rect r)
376 {
377 int res = XRectInRegion(
378 pREGION,
379 r. left, pAPERTURE - r. bottom - 1,
380 r. right - r.left + 1, r.top - r.bottom + 1
381 );
382 switch (res) {
383 case RectangleIn: return rgnInside;
384 case RectanglePart: return rgnPartially;
385 default: return rgnOutside;
386 }
387 }
388
389 Bool
apc_region_equals(Handle self,Handle other_region)390 apc_region_equals( Handle self, Handle other_region)
391 {
392 return XEqualRegion( pREGION, GET_REGION(other_region)->region);
393 }
394
395 Bool
apc_region_is_empty(Handle self)396 apc_region_is_empty( Handle self)
397 {
398 return XEmptyRegion( pREGION );
399 }
400
401 Box
apc_region_get_box(Handle self)402 apc_region_get_box( Handle self)
403 {
404 Box box;
405 XRectangle xr;
406 XClipBox( pREGION, &xr);
407 box. x = xr. x;
408 box. y = pAPERTURE - xr. height - xr.y;
409 box. width = xr. width;
410 box. height = xr. height;
411 return box;
412 }
413
414 #define REVERT(a) (XX-> size. y - (a) - 1)
415 #define SORT(a,b) { int swp; if ((a) > (b)) { swp=(a); (a)=(b); (b)=swp; }}
416
417 /* returns rect in X coordinates BUT without menuHeight deviation */
418 void
prima_gp_get_clip_rect(Handle self,XRectangle * cr,Bool for_internal_paints)419 prima_gp_get_clip_rect( Handle self, XRectangle *cr, Bool for_internal_paints)
420 {
421 DEFXX;
422 XRectangle r;
423
424 cr-> x = 0;
425 cr-> y = 0;
426 cr-> width = XX-> size.x;
427 cr-> height = XX-> size.y;
428 if ( XF_IN_PAINT(XX) && XX-> paint_region) {
429 XClipBox( XX-> paint_region, &r);
430 prima_rect_intersect( cr, &r);
431 }
432 if ( XX-> clip_rect. x != 0
433 || XX-> clip_rect. y != 0
434 || XX-> clip_rect. width != XX-> size.x
435 || XX-> clip_rect. height != XX-> size.y) {
436 prima_rect_intersect( cr, &XX-> clip_rect);
437 }
438
439 if ( for_internal_paints) {
440 cr-> x += XX-> btransform. x;
441 cr-> y -= XX-> btransform. y;
442 }
443 }
444
445 Rect
apc_gp_get_clip_rect(Handle self)446 apc_gp_get_clip_rect( Handle self)
447 {
448 DEFXX;
449 XRectangle cr;
450 Rect r;
451
452 prima_gp_get_clip_rect( self, &cr, 0);
453 r. left = cr. x;
454 r. top = XX-> size. y - cr. y - 1;
455 r. bottom = r. top - cr. height + 1;
456 r. right = cr. x + cr. width - 1;
457 return r;
458 }
459
460
461 Bool
apc_gp_set_clip_rect(Handle self,Rect clipRect)462 apc_gp_set_clip_rect( Handle self, Rect clipRect)
463 {
464 DEFXX;
465 Region region;
466 XRectangle r;
467
468 if ( !XF_IN_PAINT(XX))
469 return false;
470
471 SORT( clipRect. left, clipRect. right);
472 SORT( clipRect. bottom, clipRect. top);
473 r. x = clipRect. left;
474 r. y = REVERT( clipRect. top);
475 r. width = clipRect. right - clipRect. left+1;
476 r. height = clipRect. top - clipRect. bottom+1;
477 XX-> clip_rect = r;
478 XX-> clip_mask_extent. x = r. width;
479 XX-> clip_mask_extent. y = r. height;
480 region = XCreateRegion();
481 XUnionRectWithRegion( &r, region, region);
482 if ( XX-> paint_region)
483 XIntersectRegion( region, XX-> paint_region, region);
484 if ( XX-> btransform. x != 0 || XX-> btransform. y != 0) {
485 XOffsetRegion( region, XX-> btransform. x, -XX-> btransform. y);
486 }
487 XSetRegion( DISP, XX-> gc, region);
488 if ( XX-> flags. kill_current_region)
489 XDestroyRegion( XX-> current_region);
490 XX-> flags. kill_current_region = 1;
491 XX-> current_region = region;
492 XX-> flags. xft_clip = 0;
493 #ifdef USE_XFT
494 if ( XX-> xft_drawable) prima_xft_update_region( self);
495 #endif
496 CLIP_ARGB_PICTURE(XX->argb_picture, region);
497 return true;
498 }
499
500 Bool
apc_gp_set_region(Handle self,Handle rgn)501 apc_gp_set_region( Handle self, Handle rgn)
502 {
503 DEFXX;
504 Region region;
505 PRegionSysData r;
506
507 if ( PObject( self)-> options. optInDrawInfo) return false;
508 if ( !XF_IN_PAINT(XX)) return false;
509
510 if (rgn == NULL_HANDLE) {
511 Rect r;
512 r. left = 0;
513 r. bottom = 0;
514 r. right = XX-> size. x - 1;
515 r. top = XX-> size. y - 1;
516 return apc_gp_set_clip_rect( self, r);
517 }
518
519 r = GET_REGION(rgn);
520
521 XClipBox( r-> region, &XX-> clip_rect);
522 XX-> clip_rect. y += XX-> size. y - r-> aperture;
523 XX-> clip_mask_extent. x = XX-> clip_rect. width;
524 XX-> clip_mask_extent. y = XX-> clip_rect. height;
525 if ( XX-> clip_rect. width == 0 || XX-> clip_rect. height == 0) {
526 Rect r;
527 r. left = -1;
528 r. bottom = -1;
529 r. right = -1;
530 r. top = -1;
531 return apc_gp_set_clip_rect( self, r);
532 }
533
534 region = XCreateRegion();
535 XUnionRegion( region, r-> region, region);
536 /* offset region if drawable is buffered */
537 XOffsetRegion( region, XX-> btransform. x, XX-> size.y - r-> aperture - XX-> btransform. y);
538 /* otherwise ( and only otherwise ), and if there's a
539 X11 clipping, intersect the region with it. X11 clipping
540 must not mix with the buffer clipping */
541 if (( !XX-> udrawable || XX-> udrawable == XX-> gdrawable) &&
542 XX-> paint_region)
543 XIntersectRegion( region, XX-> paint_region, region);
544 XSetRegion( DISP, XX-> gc, region);
545 if ( XX-> flags. kill_current_region)
546 XDestroyRegion( XX-> current_region);
547 XX-> flags. kill_current_region = 1;
548 XX-> current_region = region;
549 XX-> flags. xft_clip = 0;
550 #ifdef USE_XFT
551 if ( XX-> xft_drawable) prima_xft_update_region( self);
552 #endif
553 CLIP_ARGB_PICTURE(XX->argb_picture, region);
554 return true;
555 }
556
557 Bool
apc_gp_get_region(Handle self,Handle rgn)558 apc_gp_get_region( Handle self, Handle rgn)
559 {
560 DEFXX;
561 GC gc;
562 XGCValues gcv;
563 int w, h;
564 Pixmap pixmap;
565 XImage * i;
566 Image pi;
567 Region rgn2;
568
569 if ( !XF_IN_PAINT(XX)) return false;
570
571 if ( !rgn)
572 return XX-> clip_mask_extent. x != 0 && XX-> clip_mask_extent. y != 0;
573
574 if ( XX-> clip_mask_extent. x == 0 || XX-> clip_mask_extent. y == 0)
575 return false;
576
577 w = XX-> clip_mask_extent. x;
578 h = XX-> clip_mask_extent. y;
579
580 pixmap = XCreatePixmap( DISP, guts.root, w, h,
581 XF_LAYERED(XX) ? guts. argb_depth :
582 ( XT_IS_BITMAP(XX) ? 1 : guts. depth )
583 );
584 XCHECKPOINT;
585
586 gcv. graphics_exposures = false;
587 gcv. fill_style = FillSolid;
588 gcv. foreground = 0;
589 gcv. clip_y_origin = -XX-> clip_rect. y + XX-> btransform. y;
590 gcv. clip_x_origin = -XX-> clip_rect. x - XX-> btransform. x;
591 XCHECKPOINT;
592 gc = XCreateGC( DISP, pixmap, GCGraphicsExposures|GCFillStyle|GCForeground|GCClipXOrigin|GCClipYOrigin, &gcv);
593 XFillRectangle( DISP, pixmap, gc, 0, 0, w, h);
594 XSetForeground( DISP, gc, 1 );
595 XCopyGC( DISP, XX->gc, GCClipMask, gc);
596 XFillRectangle( DISP, pixmap, gc, 0, 0, w, h);
597 XFreeGC( DISP, gc);
598 XCHECKPOINT;
599
600 i = XGetImage( DISP, pixmap, 0, 0, w, h, 1, XYPixmap);
601 XFreePixmap( DISP, pixmap);
602 if ( !i ) {
603 warn("Cannot query image");
604 return false;
605 }
606
607 img_fill_dummy( &pi, w, h, imBW | imGrayScale, NULL, NULL);
608 if ( !( pi.data = malloc(pi.lineSize * h))) {
609 XDestroyImage( i);
610 warn("Not enough memory");
611 return false;
612 }
613
614 prima_copy_xybitmap( pi.data, (Byte*)i-> data, w, h, pi.lineSize, i-> bytes_per_line);
615 XDestroyImage( i);
616
617 rgn2 = prima_region_create((Handle) &pi);
618 free(pi.data);
619
620 if ( GET_REGION(rgn)-> region )
621 XDestroyRegion( GET_REGION(rgn)-> region );
622 if ( rgn2 ) {
623 XOffsetRegion( rgn2, XX-> clip_rect.x, 0);
624 GET_REGION(rgn)-> aperture = XX-> size.y - XX-> clip_rect.y;
625 GET_REGION(rgn)-> region = rgn2;
626 } else {
627 GET_REGION(rgn)-> aperture = 0;
628 GET_REGION(rgn)-> region = XCreateRegion();
629 }
630 return true;
631 }
632
633 PRegionRec
apc_region_copy_rects(Handle self)634 apc_region_copy_rects( Handle self)
635 {
636 int i, aperture;
637 PRegionRec ret;
638 Box *dst;
639 BoxRec *src;
640 REGION *region;
641
642 region = (REGION*) pREGION;
643 ret = malloc(sizeof(RegionRec) + sizeof(Box) * region->numRects);
644 if ( ret == NULL ) {
645 warn("Not enough memory\n");
646 return NULL;
647 }
648
649 ret-> type = rgnRectangle;
650 ret-> data. box. n_boxes = region-> numRects;
651 src = region->rects;
652 dst = ret-> data. box. boxes = (Box*) (((Byte*)ret) + sizeof(RegionRec));
653 aperture = pAPERTURE;
654 for ( i = 0; i < ret->data. box. n_boxes; i++, src++, dst++) {
655 dst-> x = src-> x1;
656 dst-> y = aperture - src-> y2;
657 dst-> width = src-> x2 - src->x1;
658 dst-> height = src-> y2 - src->y1;
659 /* printf("%d: %d %d %d %d => %d %d %d %d\n", aperture, src->x1, src->y1, src->x2, src->y2, dst->x, dst->y, dst-> width, dst->height); */
660 }
661
662 return ret;
663 }
664
665