1 /*
2 * tkMacOSXDraw.c --
3 *
4 * This file contains functions that perform drawing to
5 * Xlib windows. Most of the functions simple emulate
6 * Xlib functions.
7 *
8 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
9 * Copyright 2001-2009, Apple Inc.
10 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
11 * Copyright 2014 Marc Culler.
12 *
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 */
16
17 #include "tkMacOSXPrivate.h"
18 #include "tkMacOSXDebug.h"
19 #include "xbytes.h"
20 #include "tkButton.h"
21
22 /*
23 #ifdef TK_MAC_DEBUG
24 #define TK_MAC_DEBUG_DRAWING
25 #define TK_MAC_DEBUG_IMAGE_DRAWING
26 #endif
27 */
28
29 #define radians(d) ((d) * (M_PI/180.0))
30
31 /*
32 * Non-antialiased CG drawing looks better and more like X11 drawing when using
33 * very fine lines, so decrease all linewidths by the following constant.
34 */
35 #define NON_AA_CG_OFFSET .999
36
37 static int cgAntiAliasLimit = 0;
38 #define notAA(w) ((w) < cgAntiAliasLimit)
39
40 static int useThemedToplevel = 0;
41 static int useThemedFrame = 0;
42
43 /*
44 * Prototypes for functions used only in this file.
45 */
46
47 static void ClipToGC(Drawable d, GC gc, HIShapeRef *clipRgnPtr);
48 static CGImageRef CreateCGImageWithXImage(XImage *ximage);
49 static CGContextRef GetCGContextForDrawable(Drawable d);
50 static void DrawCGImage(Drawable d, GC gc, CGContextRef context, CGImageRef image,
51 unsigned long imageForeground, unsigned long imageBackground,
52 CGRect imageBounds, CGRect srcBounds, CGRect dstBounds);
53
54
55 /*
56 *----------------------------------------------------------------------
57 *
58 * TkMacOSXInitCGDrawing --
59 *
60 * Initializes link vars that control CG drawing.
61 *
62 * Results:
63 * None.
64 *
65 * Side effects:
66 * None.
67 *
68 *----------------------------------------------------------------------
69 */
70
71 MODULE_SCOPE int
TkMacOSXInitCGDrawing(Tcl_Interp * interp,int enable,int limit)72 TkMacOSXInitCGDrawing(
73 Tcl_Interp *interp,
74 int enable,
75 int limit)
76 {
77 static Boolean initialized = FALSE;
78
79 if (!initialized) {
80 initialized = TRUE;
81
82 if (Tcl_CreateNamespace(interp, "::tk::mac", NULL, NULL) == NULL) {
83 Tcl_ResetResult(interp);
84 }
85
86 if (Tcl_LinkVar(interp, "::tk::mac::CGAntialiasLimit",
87 (char *) &cgAntiAliasLimit, TCL_LINK_INT) != TCL_OK) {
88 Tcl_ResetResult(interp);
89 }
90 cgAntiAliasLimit = limit;
91
92 /*
93 * Piggy-back the themed drawing var init here.
94 */
95
96 if (Tcl_LinkVar(interp, "::tk::mac::useThemedToplevel",
97 (char *) &useThemedToplevel, TCL_LINK_BOOLEAN) != TCL_OK) {
98 Tcl_ResetResult(interp);
99 }
100 if (Tcl_LinkVar(interp, "::tk::mac::useThemedFrame",
101 (char *) &useThemedFrame, TCL_LINK_BOOLEAN) != TCL_OK) {
102 Tcl_ResetResult(interp);
103 }
104 }
105 return TCL_OK;
106 }
107
108 /*
109 *----------------------------------------------------------------------
110 *
111 * BitmapRepFromDrawableRect
112 *
113 * Extract bitmap data from a MacOSX drawable as an NSBitmapImageRep.
114 *
115 * Results:
116 * Returns an autoreleased NSBitmapRep representing the image of the given
117 * rectangle of the given drawable.
118 *
119 * NOTE: The x,y coordinates should be relative to a coordinate system with
120 * origin at the top left, as used by XImage and CGImage, not bottom
121 * left as used by NSView.
122 *
123 * Side effects:
124 * None
125 *
126 *----------------------------------------------------------------------
127 */
128 NSBitmapImageRep*
BitmapRepFromDrawableRect(Drawable drawable,int x,int y,unsigned int width,unsigned int height)129 BitmapRepFromDrawableRect(
130 Drawable drawable,
131 int x,
132 int y,
133 unsigned int width,
134 unsigned int height)
135 {
136 MacDrawable *mac_drawable = (MacDrawable *) drawable;
137 CGContextRef cg_context=NULL;
138 CGImageRef cg_image=NULL, sub_cg_image=NULL;
139 NSBitmapImageRep *bitmap_rep=NULL;
140 NSView *view=NULL;
141 if ( mac_drawable->flags & TK_IS_PIXMAP ) {
142 /*
143 This means that the MacDrawable is functioning as a Tk Pixmap, so its view
144 field is NULL.
145 */
146 cg_context = GetCGContextForDrawable(drawable);
147 CGRect image_rect = CGRectMake(x, y, width, height);
148 cg_image = CGBitmapContextCreateImage( (CGContextRef) cg_context);
149 sub_cg_image = CGImageCreateWithImageInRect(cg_image, image_rect);
150 if ( sub_cg_image ) {
151 /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
152 bitmap_rep = [NSBitmapImageRep alloc];
153 [bitmap_rep initWithCGImage:sub_cg_image];
154 }
155 if ( cg_image ) {
156 CGImageRelease(cg_image);
157 }
158 } else if ( (view = TkMacOSXDrawableView(mac_drawable)) ) {
159 /* convert top-left coordinates to NSView coordinates */
160 int view_height = [view bounds].size.height;
161 NSRect view_rect = NSMakeRect(x + mac_drawable->xOff,
162 view_height - height - y - mac_drawable->yOff,
163 width,height);
164
165 if ( [view lockFocusIfCanDraw] ) {
166 /*This can be dealloc'ed prematurely if set for autorelease, causing crashes.*/
167 bitmap_rep = [NSBitmapImageRep alloc];
168 bitmap_rep = [bitmap_rep initWithFocusedViewRect:view_rect];
169 [view unlockFocus];
170 } else {
171 TkMacOSXDbgMsg("Could not lock focus on view.");
172 }
173
174 } else {
175 TkMacOSXDbgMsg("Invalid source drawable");
176 }
177 return bitmap_rep;
178 }
179
180 /*
181 *----------------------------------------------------------------------
182 *
183 * XCopyArea --
184 *
185 * Copies data from one drawable to another.
186 *
187 * Results:
188 * None.
189 *
190 * Side effects:
191 * Data is moved from a window or bitmap to a second window or
192 * bitmap.
193 *
194 *----------------------------------------------------------------------
195 */
196
197 void
XCopyArea(Display * display,Drawable src,Drawable dst,GC gc,int src_x,int src_y,unsigned int width,unsigned int height,int dest_x,int dest_y)198 XCopyArea(
199 Display *display, /* Display. */
200 Drawable src, /* Source drawable. */
201 Drawable dst, /* Destination drawable. */
202 GC gc, /* GC to use. */
203 int src_x, /* X & Y, width & height */
204 int src_y, /* define the source rectangle */
205 unsigned int width, /* that will be copied. */
206 unsigned int height,
207 int dest_x, /* Dest X & Y on dest rect. */
208 int dest_y)
209 {
210 TkMacOSXDrawingContext dc;
211 MacDrawable *srcDraw = (MacDrawable *) src;
212 NSBitmapImageRep *bitmap_rep = NULL;
213 CGImageRef img = NULL;
214
215 display->request++;
216
217 if (!width || !height) {
218 /* This happens all the time.
219 TkMacOSXDbgMsg("Drawing of empty area requested");
220 */
221 return;
222 }
223
224 if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
225 return;
226 /*TkMacOSXDbgMsg("Failed to setup drawing context.");*/
227 }
228
229 if ( dc.context ) {
230 if (srcDraw->flags & TK_IS_PIXMAP) {
231 img = TkMacOSXCreateCGImageWithDrawable(src);
232 }else if (TkMacOSXDrawableWindow(src)) {
233 bitmap_rep = BitmapRepFromDrawableRect(src, src_x, src_y, width, height);
234 if ( bitmap_rep ) {
235 img = [bitmap_rep CGImage];
236 }
237 } else {
238 TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap.");
239 }
240
241 if (img) {
242 DrawCGImage(dst, gc, dc.context, img, gc->foreground, gc->background,
243 CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
244 CGRectMake(src_x, src_y, width, height),
245 CGRectMake(dest_x, dest_y, width, height));
246 CFRelease(img);
247
248
249 } else {
250 TkMacOSXDbgMsg("Failed to construct CGImage.");
251 }
252
253 } else {
254 TkMacOSXDbgMsg("Invalid destination drawable - no context.");
255 return;
256 }
257
258 TkMacOSXRestoreDrawingContext(&dc);
259 }
260
261 /*
262 *----------------------------------------------------------------------
263 *
264 * XCopyPlane --
265 *
266 * Copies a bitmap from a source drawable to a destination
267 * drawable. The plane argument specifies which bit plane of
268 * the source contains the bitmap. Note that this implementation
269 * ignores the gc->function.
270 *
271 * Results:
272 * None.
273 *
274 * Side effects:
275 * Changes the destination drawable.
276 *
277 *----------------------------------------------------------------------
278 */
279
280 void
XCopyPlane(Display * display,Drawable src,Drawable dst,GC gc,int src_x,int src_y,unsigned int width,unsigned int height,int dest_x,int dest_y,unsigned long plane)281 XCopyPlane(
282 Display *display, /* Display. */
283 Drawable src, /* Source drawable. */
284 Drawable dst, /* Destination drawable. */
285 GC gc, /* GC to use. */
286 int src_x, /* X & Y, width & height */
287 int src_y, /* define the source rectangle */
288 unsigned int width, /* that will be copied. */
289 unsigned int height,
290 int dest_x, /* Dest X & Y on dest rect. */
291 int dest_y,
292 unsigned long plane) /* Which plane to copy. */
293 {
294 TkMacOSXDrawingContext dc;
295 MacDrawable *srcDraw = (MacDrawable *) src;
296 MacDrawable *dstDraw = (MacDrawable *) dst;
297
298 display->request++;
299 if (!width || !height) {
300 /* TkMacOSXDbgMsg("Drawing of empty area requested"); */
301 return;
302 }
303 if (plane != 1) {
304 Tcl_Panic("Unexpected plane specified for XCopyPlane");
305 }
306 if (srcDraw->flags & TK_IS_PIXMAP) {
307 if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) {
308 return;
309 }
310 CGContextRef context = dc.context;
311 if (context) {
312 CGImageRef img = TkMacOSXCreateCGImageWithDrawable(src);
313 if (img) {
314 TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
315 unsigned long imageBackground = gc->background;
316 if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP){
317 CGImageRef mask = TkMacOSXCreateCGImageWithDrawable(clipPtr->value.pixmap);
318 CGRect rect = CGRectMake(dest_x, dest_y, width, height);
319 rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff);
320 CGContextSaveGState(context);
321 /* Move the origin of the destination to top left. */
322 CGContextTranslateCTM(context, 0, rect.origin.y + CGRectGetMaxY(rect));
323 CGContextScaleCTM(context, 1, -1);
324 /* Fill with the background color, clipping to the mask. */
325 CGContextClipToMask(context, rect, mask);
326 TkMacOSXSetColorInContext(gc, gc->background, dc.context);
327 CGContextFillRect(dc.context, rect);
328 /* Fill with the foreground color, clipping to the intersection of img and mask. */
329 CGContextClipToMask(context, rect, img);
330 TkMacOSXSetColorInContext(gc, gc->foreground, context);
331 CGContextFillRect(context, rect);
332 CGContextRestoreGState(context);
333 CGImageRelease(mask);
334 CGImageRelease(img);
335 } else {
336 DrawCGImage(dst, gc, dc.context, img, gc->foreground, imageBackground,
337 CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height),
338 CGRectMake(src_x, src_y, width, height),
339 CGRectMake(dest_x, dest_y, width, height));
340 CGImageRelease(img);
341 }
342 } else { /* no image */
343 TkMacOSXDbgMsg("Invalid source drawable");
344 }
345 } else {
346 TkMacOSXDbgMsg("Invalid destination drawable - could not get a bitmap context.");
347 }
348 TkMacOSXRestoreDrawingContext(&dc);
349 } else { /* source drawable is a window, not a Pixmap */
350 XCopyArea(display, src, dst, gc, src_x, src_y, width, height, dest_x, dest_y);
351 }
352 }
353
354 /*
355 *----------------------------------------------------------------------
356 *
357 * TkPutImage --
358 *
359 * Copies a subimage from an in-memory image to a rectangle of
360 * of the specified drawable.
361 *
362 * Results:
363 * None.
364 *
365 * Side effects:
366 * Draws the image on the specified drawable.
367 *
368 *----------------------------------------------------------------------
369 */
370
371 int
TkPutImage(unsigned long * colors,int ncolors,Display * display,Drawable d,GC gc,XImage * image,int src_x,int src_y,int dest_x,int dest_y,unsigned int width,unsigned int height)372 TkPutImage(
373 unsigned long *colors, /* Unused on Macintosh. */
374 int ncolors, /* Unused on Macintosh. */
375 Display* display, /* Display. */
376 Drawable d, /* Drawable to place image on. */
377 GC gc, /* GC to use. */
378 XImage* image, /* Image to place. */
379 int src_x, /* Source X & Y. */
380 int src_y,
381 int dest_x, /* Destination X & Y. */
382 int dest_y,
383 unsigned int width, /* Same width & height for both */
384 unsigned int height) /* distination and source. */
385 {
386 TkMacOSXDrawingContext dc;
387
388 display->request++;
389 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
390 return BadDrawable;
391 }
392 if (dc.context) {
393 CGImageRef img = CreateCGImageWithXImage(image);
394
395 if (img) {
396 DrawCGImage(d, gc, dc.context, img, gc->foreground, gc->background,
397 CGRectMake(0, 0, image->width, image->height),
398 CGRectMake(src_x, src_y, width, height),
399 CGRectMake(dest_x, dest_y, width, height));
400 CFRelease(img);
401 } else {
402 TkMacOSXDbgMsg("Invalid source drawable");
403 }
404 } else {
405 TkMacOSXDbgMsg("Invalid destination drawable");
406 }
407 TkMacOSXRestoreDrawingContext(&dc);
408 return Success;
409 }
410
411 /*
412 *----------------------------------------------------------------------
413 *
414 * CreateCGImageWithXImage --
415 *
416 * Create CGImage from XImage, copying the image data.
417 *
418 * Results:
419 * CGImage, release after use.
420 *
421 * Side effects:
422 * None.
423 *
424 *----------------------------------------------------------------------
425 */
426
ReleaseData(void * info,const void * data,size_t size)427 static void ReleaseData(void *info, const void *data, size_t size) {
428 ckfree(info);
429 }
430
431 CGImageRef
CreateCGImageWithXImage(XImage * image)432 CreateCGImageWithXImage(
433 XImage *image)
434 {
435 CGImageRef img = NULL;
436 size_t bitsPerComponent, bitsPerPixel;
437 size_t len = image->bytes_per_line * image->height;
438 const CGFloat *decode = NULL;
439 CGBitmapInfo bitmapInfo;
440 CGDataProviderRef provider = NULL;
441 char *data = NULL;
442 CGDataProviderReleaseDataCallback releaseData = ReleaseData;
443
444 if (image->bits_per_pixel == 1) {
445 /*
446 * BW image
447 */
448
449 /* Reverses the sense of the bits */
450 static const CGFloat decodeWB[2] = {1, 0};
451 decode = decodeWB;
452
453 bitsPerComponent = 1;
454 bitsPerPixel = 1;
455 if (image->bitmap_bit_order != MSBFirst) {
456 char *srcPtr = image->data + image->xoffset;
457 char *endPtr = srcPtr + len;
458 char *destPtr = (data = ckalloc(len));
459
460 while (srcPtr < endPtr) {
461 *destPtr++ = xBitReverseTable[(unsigned char)(*(srcPtr++))];
462 }
463 } else {
464 data = memcpy(ckalloc(len), image->data + image->xoffset, len);
465 }
466 if (data) {
467 provider = CGDataProviderCreateWithData(data, data, len, releaseData);
468 }
469 if (provider) {
470 img = CGImageMaskCreate(image->width, image->height, bitsPerComponent,
471 bitsPerPixel, image->bytes_per_line, provider, decode, 0);
472 }
473 } else if (image->format == ZPixmap && image->bits_per_pixel == 32) {
474 /*
475 * Color image
476 */
477
478 CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
479
480 bitsPerComponent = 8;
481 bitsPerPixel = 32;
482 bitmapInfo = (image->byte_order == MSBFirst ?
483 kCGBitmapByteOrder32Big : kCGBitmapByteOrder32Little) |
484 kCGImageAlphaNoneSkipFirst;
485 data = memcpy(ckalloc(len), image->data + image->xoffset, len);
486 if (data) {
487 provider = CGDataProviderCreateWithData(data, data, len, releaseData);
488 }
489 if (provider) {
490 img = CGImageCreate(image->width, image->height, bitsPerComponent,
491 bitsPerPixel, image->bytes_per_line, colorspace, bitmapInfo,
492 provider, decode, 0, kCGRenderingIntentDefault);
493 CFRelease(provider);
494 }
495 if (colorspace) {
496 CFRelease(colorspace);
497 }
498 } else {
499 TkMacOSXDbgMsg("Unsupported image type");
500 }
501 return img;
502 }
503
504 /*
505 *----------------------------------------------------------------------
506 *
507 * TkMacOSXCreateCGImageWithDrawable --
508 *
509 * Create a CGImage from the given Drawable.
510 *
511 * Results:
512 * CGImage, release after use.
513 *
514 * Side effects:
515 * None.
516 *
517 *----------------------------------------------------------------------
518 */
519
520 CGImageRef
TkMacOSXCreateCGImageWithDrawable(Drawable drawable)521 TkMacOSXCreateCGImageWithDrawable(
522 Drawable drawable)
523 {
524 CGImageRef img = NULL;
525 CGContextRef context = GetCGContextForDrawable(drawable);
526
527 if (context) {
528 img = CGBitmapContextCreateImage(context);
529 }
530 return img;
531 }
532
533 /*
534 *----------------------------------------------------------------------
535 *
536 * CreateNSImageWithPixmap --
537 *
538 * Create NSImage for Pixmap.
539 *
540 * Results:
541 * NSImage.
542 *
543 * Side effects:
544 * None.
545 *
546 *----------------------------------------------------------------------
547 */
548
549 static NSImage*
CreateNSImageWithPixmap(Pixmap pixmap,int width,int height)550 CreateNSImageWithPixmap(
551 Pixmap pixmap,
552 int width,
553 int height)
554 {
555 CGImageRef cgImage;
556 NSImage *nsImage;
557 NSBitmapImageRep *bitmapImageRep;
558
559 cgImage = TkMacOSXCreateCGImageWithDrawable(pixmap);
560 nsImage = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
561 bitmapImageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
562 [nsImage addRepresentation:bitmapImageRep];
563 [bitmapImageRep release];
564 CFRelease(cgImage);
565
566 return nsImage;
567 }
568
569 /*
570 *----------------------------------------------------------------------
571 *
572 * TkMacOSXGetNSImageWithTkImage --
573 *
574 * Get autoreleased NSImage for Tk_Image.
575 *
576 * Results:
577 * NSImage.
578 *
579 * Side effects:
580 * None.
581 *
582 *----------------------------------------------------------------------
583 */
584
585 NSImage*
TkMacOSXGetNSImageWithTkImage(Display * display,Tk_Image image,int width,int height)586 TkMacOSXGetNSImageWithTkImage(
587 Display *display,
588 Tk_Image image,
589 int width,
590 int height)
591 {
592 Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
593 NSImage *nsImage;
594
595 Tk_RedrawImage(image, 0, 0, width, height, pixmap, 0, 0);
596 nsImage = CreateNSImageWithPixmap(pixmap, width, height);
597 Tk_FreePixmap(display, pixmap);
598
599 return [nsImage autorelease];
600 }
601
602 /*
603 *----------------------------------------------------------------------
604 *
605 * TkMacOSXGetNSImageWithBitmap --
606 *
607 * Get autoreleased NSImage for Bitmap.
608 *
609 * Results:
610 * NSImage.
611 *
612 * Side effects:
613 * None.
614 *
615 *----------------------------------------------------------------------
616 */
617
618 NSImage*
TkMacOSXGetNSImageWithBitmap(Display * display,Pixmap bitmap,GC gc,int width,int height)619 TkMacOSXGetNSImageWithBitmap(
620 Display *display,
621 Pixmap bitmap,
622 GC gc,
623 int width,
624 int height)
625 {
626 Pixmap pixmap = Tk_GetPixmap(display, None, width, height, 0);
627 NSImage *nsImage;
628
629 unsigned long origBackground = gc->background;
630
631 gc->background = TRANSPARENT_PIXEL << 24;
632 XSetClipOrigin(display, gc, 0, 0);
633 XCopyPlane(display, bitmap, pixmap, gc, 0, 0, width, height, 0, 0, 1);
634 gc->background = origBackground;
635 nsImage = CreateNSImageWithPixmap(pixmap, width, height);
636 Tk_FreePixmap(display, pixmap);
637
638 return [nsImage autorelease];
639 }
640
641 /*
642 *----------------------------------------------------------------------
643 *
644 * GetCGContextForDrawable --
645 *
646 * Get CGContext for given Drawable, creating one if necessary.
647 *
648 * Results:
649 * CGContext.
650 *
651 * Side effects:
652 * None.
653 *
654 *----------------------------------------------------------------------
655 */
656
657 CGContextRef
GetCGContextForDrawable(Drawable d)658 GetCGContextForDrawable(
659 Drawable d)
660 {
661 MacDrawable *macDraw = (MacDrawable *) d;
662
663 if (macDraw && (macDraw->flags & TK_IS_PIXMAP) && !macDraw->context) {
664 const size_t bitsPerComponent = 8;
665 size_t bitsPerPixel, bytesPerRow, len;
666 CGColorSpaceRef colorspace = NULL;
667 CGBitmapInfo bitmapInfo =
668 #ifdef __LITTLE_ENDIAN__
669 kCGBitmapByteOrder32Host;
670 #else
671 kCGBitmapByteOrderDefault;
672 #endif
673 char *data;
674 CGRect bounds = CGRectMake(0, 0, macDraw->size.width, macDraw->size.height);
675
676 if (macDraw->flags & TK_IS_BW_PIXMAP) {
677 bitsPerPixel = 8;
678 bitmapInfo = (CGBitmapInfo)kCGImageAlphaOnly;
679 } else {
680 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
681 bitsPerPixel = 32;
682 bitmapInfo |= kCGImageAlphaPremultipliedFirst;
683 }
684 bytesPerRow = ((size_t) macDraw->size.width * bitsPerPixel + 127) >> 3
685 & ~15;
686 len = macDraw->size.height * bytesPerRow;
687 data = ckalloc(len);
688 bzero(data, len);
689 macDraw->context = CGBitmapContextCreate(data, macDraw->size.width,
690 macDraw->size.height, bitsPerComponent, bytesPerRow,
691 colorspace, bitmapInfo);
692 if (macDraw->context) {
693 CGContextClearRect(macDraw->context, bounds);
694 }
695 if (colorspace) {
696 CFRelease(colorspace);
697 }
698 }
699
700 return (macDraw ? macDraw->context : NULL);
701 }
702
703 /*
704 *----------------------------------------------------------------------
705 *
706 * DrawCGImage --
707 *
708 * Draw CG image into drawable.
709 *
710 * Results:
711 * None.
712 *
713 * Side effects:
714 * None.
715 *
716 *----------------------------------------------------------------------
717 */
718
719 void
DrawCGImage(Drawable d,GC gc,CGContextRef context,CGImageRef image,unsigned long imageForeground,unsigned long imageBackground,CGRect imageBounds,CGRect srcBounds,CGRect dstBounds)720 DrawCGImage(
721 Drawable d,
722 GC gc,
723 CGContextRef context,
724 CGImageRef image,
725 unsigned long imageForeground,
726 unsigned long imageBackground,
727 CGRect imageBounds,
728 CGRect srcBounds,
729 CGRect dstBounds)
730 {
731 MacDrawable *macDraw = (MacDrawable *) d;
732
733 if (macDraw && context && image) {
734 CGImageRef subImage = NULL;
735
736 if (!CGRectEqualToRect(imageBounds, srcBounds)) {
737 if (!CGRectContainsRect(imageBounds, srcBounds)) {
738 TkMacOSXDbgMsg("Mismatch of sub CGImage bounds");
739 }
740 subImage = CGImageCreateWithImageInRect(image, CGRectOffset(
741 srcBounds, -imageBounds.origin.x, -imageBounds.origin.y));
742 if (subImage) {
743 image = subImage;
744 }
745 }
746 dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff);
747
748 if (CGImageIsMask(image)) {
749 /*CGContextSaveGState(context);*/
750 if (macDraw->flags & TK_IS_BW_PIXMAP) {
751 /* Set fill color to black, background comes from the context, or is transparent. */
752 if (imageBackground != TRANSPARENT_PIXEL << 24) {
753 CGContextClearRect(context, dstBounds);
754 }
755 CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
756 } else {
757 if (imageBackground != TRANSPARENT_PIXEL << 24) {
758 TkMacOSXSetColorInContext(gc, imageBackground, context);
759 CGContextFillRect(context, dstBounds);
760 }
761 TkMacOSXSetColorInContext(gc, imageForeground, context);
762 }
763 }
764
765 #ifdef TK_MAC_DEBUG_IMAGE_DRAWING
766 CGContextSaveGState(context);
767 CGContextSetLineWidth(context, 1.0);
768 CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.1);
769 CGContextSetRGBFillColor(context, 0, 1, 0, 0.1);
770 CGContextFillRect(context, dstBounds);
771 CGContextStrokeRect(context, dstBounds);
772 CGPoint p[4] = {dstBounds.origin,
773 CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMaxY(dstBounds)),
774 CGPointMake(CGRectGetMinX(dstBounds), CGRectGetMaxY(dstBounds)),
775 CGPointMake(CGRectGetMaxX(dstBounds), CGRectGetMinY(dstBounds))
776 };
777 CGContextStrokeLineSegments(context, p, 4);
778 CGContextRestoreGState(context);
779 TkMacOSXDbgMsg("Drawing CGImage at (x=%f, y=%f), (w=%f, h=%f)",
780 dstBounds.origin.x, dstBounds.origin.y,
781 dstBounds.size.width, dstBounds.size.height);
782 #else /* TK_MAC_DEBUG_IMAGE_DRAWING */
783 CGContextSaveGState(context);
784 CGContextTranslateCTM(context, 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds));
785 CGContextScaleCTM(context, 1, -1);
786 CGContextDrawImage(context, dstBounds, image);
787 CGContextRestoreGState(context);
788 #endif /* TK_MAC_DEBUG_IMAGE_DRAWING */
789 /*if (CGImageIsMask(image)) {
790 CGContextRestoreGState(context);
791 }*/
792 if (subImage) {
793 CFRelease(subImage);
794 }
795 } else {
796 TkMacOSXDbgMsg("Drawing of empty CGImage requested");
797 }
798 }
799
800 /*
801 *----------------------------------------------------------------------
802 *
803 * XDrawLines --
804 *
805 * Draw connected lines.
806 *
807 * Results:
808 * None.
809 *
810 * Side effects:
811 * Renders a series of connected lines.
812 *
813 *----------------------------------------------------------------------
814 */
815
816 int
XDrawLines(Display * display,Drawable d,GC gc,XPoint * points,int npoints,int mode)817 XDrawLines(
818 Display *display, /* Display. */
819 Drawable d, /* Draw on this. */
820 GC gc, /* Use this GC. */
821 XPoint *points, /* Array of points. */
822 int npoints, /* Number of points. */
823 int mode) /* Line drawing mode. */
824 {
825 MacDrawable *macWin = (MacDrawable *) d;
826 TkMacOSXDrawingContext dc;
827 int i, lw = gc->line_width;
828
829 if (npoints < 2) {
830 return BadValue;
831 }
832
833 display->request++;
834 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
835 return BadDrawable;
836 }
837 if (dc.context) {
838 double prevx, prevy;
839 double o = (lw % 2) ? .5 : 0;
840
841 CGContextBeginPath(dc.context);
842 prevx = macWin->xOff + points[0].x + o;
843 prevy = macWin->yOff + points[0].y + o;
844 CGContextMoveToPoint(dc.context, prevx, prevy);
845 for (i = 1; i < npoints; i++) {
846 if (mode == CoordModeOrigin) {
847 CGContextAddLineToPoint(dc.context,
848 macWin->xOff + points[i].x + o,
849 macWin->yOff + points[i].y + o);
850 } else {
851 prevx += points[i].x;
852 prevy += points[i].y;
853 CGContextAddLineToPoint(dc.context, prevx, prevy);
854 }
855 }
856 CGContextStrokePath(dc.context);
857 }
858 TkMacOSXRestoreDrawingContext(&dc);
859 return Success;
860 }
861
862 /*
863 *----------------------------------------------------------------------
864 *
865 * XDrawSegments --
866 *
867 * Draw unconnected lines.
868 *
869 * Results:
870 * None.
871 *
872 * Side effects:
873 * Renders a series of unconnected lines.
874 *
875 *----------------------------------------------------------------------
876 */
877
878 void
XDrawSegments(Display * display,Drawable d,GC gc,XSegment * segments,int nsegments)879 XDrawSegments(
880 Display *display,
881 Drawable d,
882 GC gc,
883 XSegment *segments,
884 int nsegments)
885 {
886 MacDrawable *macWin = (MacDrawable *) d;
887 TkMacOSXDrawingContext dc;
888 int i, lw = gc->line_width;
889
890 display->request++;
891 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
892 return;
893 }
894 if (dc.context) {
895 double o = (lw % 2) ? .5 : 0;
896
897 for (i = 0; i < nsegments; i++) {
898 CGContextBeginPath(dc.context);
899 CGContextMoveToPoint(dc.context,
900 macWin->xOff + segments[i].x1 + o,
901 macWin->yOff + segments[i].y1 + o);
902 CGContextAddLineToPoint(dc.context,
903 macWin->xOff + segments[i].x2 + o,
904 macWin->yOff + segments[i].y2 + o);
905 CGContextStrokePath(dc.context);
906 }
907 }
908 TkMacOSXRestoreDrawingContext(&dc);
909 }
910
911 /*
912 *----------------------------------------------------------------------
913 *
914 * XFillPolygon --
915 *
916 * Draws a filled polygon.
917 *
918 * Results:
919 * None.
920 *
921 * Side effects:
922 * Draws a filled polygon on the specified drawable.
923 *
924 *----------------------------------------------------------------------
925 */
926
927 void
XFillPolygon(Display * display,Drawable d,GC gc,XPoint * points,int npoints,int shape,int mode)928 XFillPolygon(
929 Display* display, /* Display. */
930 Drawable d, /* Draw on this. */
931 GC gc, /* Use this GC. */
932 XPoint* points, /* Array of points. */
933 int npoints, /* Number of points. */
934 int shape, /* Shape to draw. */
935 int mode) /* Drawing mode. */
936 {
937 MacDrawable *macWin = (MacDrawable *) d;
938 TkMacOSXDrawingContext dc;
939 int i;
940
941 display->request++;
942 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
943 return;
944 }
945 if (dc.context) {
946 double prevx, prevy;
947 double o = (gc->line_width % 2) ? .5 : 0;
948
949 CGContextBeginPath(dc.context);
950 prevx = macWin->xOff + points[0].x + o;
951 prevy = macWin->yOff + points[0].y + o;
952 CGContextMoveToPoint(dc.context, prevx, prevy);
953 for (i = 1; i < npoints; i++) {
954 if (mode == CoordModeOrigin) {
955 CGContextAddLineToPoint(dc.context,
956 macWin->xOff + points[i].x + o,
957 macWin->yOff + points[i].y + o);
958 } else {
959 prevx += points[i].x;
960 prevy += points[i].y;
961 CGContextAddLineToPoint(dc.context, prevx, prevy);
962 }
963 }
964 CGContextEOFillPath(dc.context);
965 }
966 TkMacOSXRestoreDrawingContext(&dc);
967 }
968
969 /*
970 *----------------------------------------------------------------------
971 *
972 * XDrawRectangle --
973 *
974 * Draws a rectangle.
975 *
976 * Results:
977 * None.
978 *
979 * Side effects:
980 * Draws a rectangle on the specified drawable.
981 *
982 *----------------------------------------------------------------------
983 */
984
985 void
XDrawRectangle(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height)986 XDrawRectangle(
987 Display *display, /* Display. */
988 Drawable d, /* Draw on this. */
989 GC gc, /* Use this GC. */
990 int x, int y, /* Upper left corner. */
991 unsigned int width, /* Width & height of rect. */
992 unsigned int height)
993 {
994 MacDrawable *macWin = (MacDrawable *) d;
995 TkMacOSXDrawingContext dc;
996 int lw = gc->line_width;
997
998 if (width == 0 || height == 0) {
999 return;
1000 }
1001
1002 display->request++;
1003 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1004 return;
1005 }
1006 if (dc.context) {
1007 CGRect rect;
1008 double o = (lw % 2) ? .5 : 0;
1009
1010 rect = CGRectMake(
1011 macWin->xOff + x + o,
1012 macWin->yOff + y + o,
1013 width, height);
1014 CGContextStrokeRect(dc.context, rect);
1015 }
1016 TkMacOSXRestoreDrawingContext(&dc);
1017 }
1018
1019 #ifdef TK_MACOSXDRAW_UNUSED
1020 /*
1021 *----------------------------------------------------------------------
1022 *
1023 * XDrawRectangles --
1024 *
1025 * Draws the outlines of the specified rectangles as if a
1026 * five-point PolyLine protocol request were specified for each
1027 * rectangle:
1028 *
1029 * [x,y] [x+width,y] [x+width,y+height] [x,y+height] [x,y]
1030 *
1031 * For the specified rectangles, these functions do not draw a
1032 * pixel more than once. XDrawRectangles draws the rectangles in
1033 * the order listed in the array. If rectangles intersect, the
1034 * intersecting pixels are drawn multiple times. Draws a
1035 * rectangle.
1036 *
1037 * Results:
1038 * None.
1039 *
1040 * Side effects:
1041 * Draws rectangles on the specified drawable.
1042 *
1043 *----------------------------------------------------------------------
1044 */
1045
1046 void
XDrawRectangles(Display * display,Drawable drawable,GC gc,XRectangle * rectArr,int nRects)1047 XDrawRectangles(
1048 Display *display,
1049 Drawable drawable,
1050 GC gc,
1051 XRectangle *rectArr,
1052 int nRects)
1053 {
1054 MacDrawable *macWin = (MacDrawable *) drawable;
1055 TkMacOSXDrawingContext dc;
1056 XRectangle * rectPtr;
1057 int i, lw = gc->line_width;
1058
1059 display->request++;
1060 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1061 return;
1062 }
1063 if (dc.context) {
1064 CGRect rect;
1065 double o = (lw % 2) ? .5 : 0;
1066
1067 for (i = 0, rectPtr = rectArr; i < nRects; i++, rectPtr++) {
1068 if (rectPtr->width == 0 || rectPtr->height == 0) {
1069 continue;
1070 }
1071 rect = CGRectMake(
1072 macWin->xOff + rectPtr->x + o,
1073 macWin->yOff + rectPtr->y + o,
1074 rectPtr->width, rectPtr->height);
1075 CGContextStrokeRect(dc.context, rect);
1076 }
1077 }
1078 TkMacOSXRestoreDrawingContext(&dc);
1079 }
1080 #endif
1081
1082 /*
1083 *----------------------------------------------------------------------
1084 *
1085 * XFillRectangles --
1086 *
1087 * Fill multiple rectangular areas in the given drawable.
1088 *
1089 * Results:
1090 * None.
1091 *
1092 * Side effects:
1093 * Draws onto the specified drawable.
1094 *
1095 *----------------------------------------------------------------------
1096 */
1097
1098 int
XFillRectangles(Display * display,Drawable d,GC gc,XRectangle * rectangles,int n_rectangles)1099 XFillRectangles(
1100 Display* display, /* Display. */
1101 Drawable d, /* Draw on this. */
1102 GC gc, /* Use this GC. */
1103 XRectangle *rectangles, /* Rectangle array. */
1104 int n_rectangles) /* Number of rectangles. */
1105 {
1106 MacDrawable *macWin = (MacDrawable *) d;
1107 TkMacOSXDrawingContext dc;
1108 XRectangle * rectPtr;
1109 int i;
1110
1111 display->request++;
1112 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1113 return BadDrawable;
1114 }
1115 if (dc.context) {
1116 CGRect rect;
1117
1118 for (i = 0, rectPtr = rectangles; i < n_rectangles; i++, rectPtr++) {
1119 if (rectPtr->width == 0 || rectPtr->height == 0) {
1120 continue;
1121 }
1122 rect = CGRectMake(
1123 macWin->xOff + rectPtr->x,
1124 macWin->yOff + rectPtr->y,
1125 rectPtr->width, rectPtr->height);
1126 CGContextFillRect(dc.context, rect);
1127 }
1128 }
1129 TkMacOSXRestoreDrawingContext(&dc);
1130 return Success;
1131 }
1132
1133 /*
1134 *----------------------------------------------------------------------
1135 *
1136 * XDrawArc --
1137 *
1138 * Draw an arc.
1139 *
1140 * Results:
1141 * None.
1142 *
1143 * Side effects:
1144 * Draws an arc on the specified drawable.
1145 *
1146 *----------------------------------------------------------------------
1147 */
1148
1149 void
XDrawArc(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height,int angle1,int angle2)1150 XDrawArc(
1151 Display* display, /* Display. */
1152 Drawable d, /* Draw on this. */
1153 GC gc, /* Use this GC. */
1154 int x, int y, /* Upper left of bounding rect. */
1155 unsigned int width, /* Width & height. */
1156 unsigned int height,
1157 int angle1, /* Staring angle of arc. */
1158 int angle2) /* Extent of arc. */
1159 {
1160 MacDrawable *macWin = (MacDrawable *) d;
1161 TkMacOSXDrawingContext dc;
1162 int lw = gc->line_width;
1163
1164 if (width == 0 || height == 0 || angle2 == 0) {
1165 return;
1166 }
1167
1168 display->request++;
1169 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1170 return;
1171 }
1172 if (dc.context) {
1173 CGRect rect;
1174 double o = (lw % 2) ? .5 : 0;
1175
1176 rect = CGRectMake(
1177 macWin->xOff + x + o,
1178 macWin->yOff + y + o,
1179 width, height);
1180 if (angle1 == 0 && angle2 == 23040) {
1181 CGContextStrokeEllipseInRect(dc.context, rect);
1182 } else {
1183 CGMutablePathRef p = CGPathCreateMutable();
1184 CGAffineTransform t = CGAffineTransformIdentity;
1185 CGPoint c = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
1186 double w = CGRectGetWidth(rect);
1187
1188 if (width != height) {
1189 t = CGAffineTransformMakeScale(1.0, CGRectGetHeight(rect)/w);
1190 c = CGPointApplyAffineTransform(c, CGAffineTransformInvert(t));
1191 }
1192 CGPathAddArc(p, &t, c.x, c.y, w/2, radians(-angle1/64.0),
1193 radians(-(angle1 + angle2)/64.0), angle2 > 0);
1194 CGContextAddPath(dc.context, p);
1195 CGPathRelease(p);
1196 CGContextStrokePath(dc.context);
1197 }
1198 }
1199 TkMacOSXRestoreDrawingContext(&dc);
1200 }
1201
1202 #ifdef TK_MACOSXDRAW_UNUSED
1203 /*
1204 *----------------------------------------------------------------------
1205 *
1206 * XDrawArcs --
1207 *
1208 * Draws multiple circular or elliptical arcs. Each arc is
1209 * specified by a rectangle and two angles. The center of the
1210 * circle or ellipse is the center of the rect- angle, and the
1211 * major and minor axes are specified by the width and height.
1212 * Positive angles indicate counterclock- wise motion, and
1213 * negative angles indicate clockwise motion. If the magnitude
1214 * of angle2 is greater than 360 degrees, XDrawArcs truncates it
1215 * to 360 degrees.
1216 *
1217 * Results:
1218 * None.
1219 *
1220 * Side effects:
1221 * Draws an arc for each array element on the specified drawable.
1222 *
1223 *----------------------------------------------------------------------
1224 */
1225
1226 void
XDrawArcs(Display * display,Drawable d,GC gc,XArc * arcArr,int nArcs)1227 XDrawArcs(
1228 Display *display,
1229 Drawable d,
1230 GC gc,
1231 XArc *arcArr,
1232 int nArcs)
1233 {
1234
1235 MacDrawable *macWin = (MacDrawable *) d;
1236 TkMacOSXDrawingContext dc;
1237 XArc *arcPtr;
1238 int i, lw = gc->line_width;
1239
1240 display->request++;
1241 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1242 return;
1243 }
1244 if (dc.context) {
1245 CGRect rect;
1246 double o = (lw % 2) ? .5 : 0;
1247
1248 for (i=0, arcPtr = arcArr; i < nArcs; i++, arcPtr++) {
1249 if (arcPtr->width == 0 || arcPtr->height == 0
1250 || arcPtr->angle2 == 0) {
1251 continue;
1252 }
1253 rect = CGRectMake(
1254 macWin->xOff + arcPtr->x + o,
1255 macWin->yOff + arcPtr->y + o,
1256 arcPtr->width, arcPtr->height);
1257
1258 if (arcPtr->angle1 == 0 && arcPtr->angle2 == 23040) {
1259 CGContextStrokeEllipseInRect(dc.context, rect);
1260 } else {
1261 CGMutablePathRef p = CGPathCreateMutable();
1262 CGAffineTransform t = CGAffineTransformIdentity;
1263 CGPoint c = CGPointMake(CGRectGetMidX(rect),
1264 CGRectGetMidY(rect));
1265 double w = CGRectGetWidth(rect);
1266
1267 if (arcPtr->width != arcPtr->height) {
1268 t = CGAffineTransformMakeScale(1, CGRectGetHeight(rect)/w);
1269 c = CGPointApplyAffineTransform(c,
1270 CGAffineTransformInvert(t));
1271 }
1272 CGPathAddArc(p, &t, c.x, c.y, w/2,
1273 radians(-arcPtr->angle1/64.0),
1274 radians(-(arcPtr->angle1 + arcPtr->angle2)/64.0),
1275 arcPtr->angle2 > 0);
1276 CGContextAddPath(dc.context, p);
1277 CGPathRelease(p);
1278 CGContextStrokePath(dc.context);
1279 }
1280 }
1281 }
1282 TkMacOSXRestoreDrawingContext(&dc);
1283 }
1284 #endif
1285
1286 /*
1287 *----------------------------------------------------------------------
1288 *
1289 * XFillArc --
1290 *
1291 * Draw a filled arc.
1292 *
1293 * Results:
1294 * None.
1295 *
1296 * Side effects:
1297 * Draws a filled arc on the specified drawable.
1298 *
1299 *----------------------------------------------------------------------
1300 */
1301
1302 void
XFillArc(Display * display,Drawable d,GC gc,int x,int y,unsigned int width,unsigned int height,int angle1,int angle2)1303 XFillArc(
1304 Display* display, /* Display. */
1305 Drawable d, /* Draw on this. */
1306 GC gc, /* Use this GC. */
1307 int x, int y, /* Upper left of bounding rect. */
1308 unsigned int width, /* Width & height. */
1309 unsigned int height,
1310 int angle1, /* Staring angle of arc. */
1311 int angle2) /* Extent of arc. */
1312 {
1313 MacDrawable *macWin = (MacDrawable *) d;
1314 TkMacOSXDrawingContext dc;
1315 int lw = gc->line_width;
1316
1317 if (width == 0 || height == 0 || angle2 == 0) {
1318 return;
1319 }
1320
1321 display->request++;
1322 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1323 return;
1324 }
1325 if (dc.context) {
1326 CGRect rect;
1327 double o = (lw % 2) ? .5 : 0, u = 0;
1328
1329 if (notAA(lw)) {
1330 o += NON_AA_CG_OFFSET/2;
1331 u += NON_AA_CG_OFFSET;
1332 }
1333 rect = CGRectMake(
1334 macWin->xOff + x + o,
1335 macWin->yOff + y + o,
1336 width - u, height - u);
1337
1338 if (angle1 == 0 && angle2 == 23040) {
1339 CGContextFillEllipseInRect(dc.context, rect);
1340 } else {
1341 CGMutablePathRef p = CGPathCreateMutable();
1342 CGAffineTransform t = CGAffineTransformIdentity;
1343 CGPoint c = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
1344 double w = CGRectGetWidth(rect);
1345
1346 if (width != height) {
1347 t = CGAffineTransformMakeScale(1, CGRectGetHeight(rect)/w);
1348 c = CGPointApplyAffineTransform(c, CGAffineTransformInvert(t));
1349 }
1350 if (gc->arc_mode == ArcPieSlice) {
1351 CGPathMoveToPoint(p, &t, c.x, c.y);
1352 }
1353 CGPathAddArc(p, &t, c.x, c.y, w/2, radians(-angle1/64.0),
1354 radians(-(angle1 + angle2)/64.0), angle2 > 0);
1355 CGPathCloseSubpath(p);
1356 CGContextAddPath(dc.context, p);
1357 CGPathRelease(p);
1358 CGContextFillPath(dc.context);
1359 }
1360 }
1361 TkMacOSXRestoreDrawingContext(&dc);
1362 }
1363
1364 #ifdef TK_MACOSXDRAW_UNUSED
1365 /*
1366 *----------------------------------------------------------------------
1367 *
1368 * XFillArcs --
1369 *
1370 * Draw a filled arc.
1371 *
1372 * Results:
1373 * None.
1374 *
1375 * Side effects:
1376 * Draws a filled arc for each array element on the specified drawable.
1377 *
1378 *----------------------------------------------------------------------
1379 */
1380
1381 void
XFillArcs(Display * display,Drawable d,GC gc,XArc * arcArr,int nArcs)1382 XFillArcs(
1383 Display *display,
1384 Drawable d,
1385 GC gc,
1386 XArc *arcArr,
1387 int nArcs)
1388 {
1389 MacDrawable *macWin = (MacDrawable *) d;
1390 TkMacOSXDrawingContext dc;
1391 XArc * arcPtr;
1392 int i, lw = gc->line_width;
1393
1394 display->request++;
1395 if (!TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
1396 return;
1397 }
1398 if (dc.context) {
1399 CGRect rect;
1400 double o = (lw % 2) ? .5 : 0, u = 0;
1401
1402 if (notAA(lw)) {
1403 o += NON_AA_CG_OFFSET/2;
1404 u += NON_AA_CG_OFFSET;
1405 }
1406 for (i = 0, arcPtr = arcArr; i < nArcs; i++, arcPtr++) {
1407 if (arcPtr->width == 0 || arcPtr->height == 0
1408 || arcPtr->angle2 == 0) {
1409 continue;
1410 }
1411 rect = CGRectMake(
1412 macWin->xOff + arcPtr->x + o,
1413 macWin->yOff + arcPtr->y + o,
1414 arcPtr->width - u, arcPtr->height - u);
1415 if (arcPtr->angle1 == 0 && arcPtr->angle2 == 23040) {
1416 CGContextFillEllipseInRect(dc.context, rect);
1417 } else {
1418 CGMutablePathRef p = CGPathCreateMutable();
1419 CGAffineTransform t = CGAffineTransformIdentity;
1420 CGPoint c = CGPointMake(CGRectGetMidX(rect),
1421 CGRectGetMidY(rect));
1422 double w = CGRectGetWidth(rect);
1423
1424 if (arcPtr->width != arcPtr->height) {
1425 t = CGAffineTransformMakeScale(1, CGRectGetHeight(rect)/w);
1426 c = CGPointApplyAffineTransform(c,
1427 CGAffineTransformInvert(t));
1428 }
1429 if (gc->arc_mode == ArcPieSlice) {
1430 CGPathMoveToPoint(p, &t, c.x, c.y);
1431 }
1432 CGPathAddArc(p, &t, c.x, c.y, w/2,
1433 radians(-arcPtr->angle1/64.0),
1434 radians(-(arcPtr->angle1 + arcPtr->angle2)/64.0),
1435 arcPtr->angle2 > 0);
1436 CGPathCloseSubpath(p);
1437 CGContextAddPath(dc.context, p);
1438 CGPathRelease(p);
1439 CGContextFillPath(dc.context);
1440 }
1441 }
1442 }
1443 TkMacOSXRestoreDrawingContext(&dc);
1444 }
1445 #endif
1446
1447 #ifdef TK_MACOSXDRAW_UNUSED
1448 /*
1449 *----------------------------------------------------------------------
1450 *
1451 * XMaxRequestSize --
1452 *
1453 *----------------------------------------------------------------------
1454 */
1455
1456 long
XMaxRequestSize(Display * display)1457 XMaxRequestSize(
1458 Display *display)
1459 {
1460 return (SHRT_MAX / 4);
1461 }
1462 #endif
1463
1464 /*
1465 *----------------------------------------------------------------------
1466 *
1467 * TkScrollWindow --
1468 *
1469 * Scroll a rectangle of the specified window and accumulate
1470 * a damage region.
1471 *
1472 * Results:
1473 * Returns 0 if the scroll genereated no additional damage.
1474 * Otherwise, sets the region that needs to be repainted after
1475 * scrolling and returns 1.
1476 *
1477 * Side effects:
1478 * Scrolls the bits in the window.
1479 *
1480 *----------------------------------------------------------------------
1481 */
1482
1483 int
TkScrollWindow(Tk_Window tkwin,GC gc,int x,int y,int width,int height,int dx,int dy,TkRegion damageRgn)1484 TkScrollWindow(
1485 Tk_Window tkwin, /* The window to be scrolled. */
1486 GC gc, /* GC for window to be scrolled. */
1487 int x, int y, /* Position rectangle to be scrolled. */
1488 int width, int height,
1489 int dx, int dy, /* Distance rectangle should be moved. */
1490 TkRegion damageRgn) /* Region to accumulate damage in. */
1491 {
1492 Drawable drawable = Tk_WindowId(tkwin);
1493 MacDrawable *macDraw = (MacDrawable *) drawable;
1494 TKContentView *view = (TKContentView *)TkMacOSXDrawableView(macDraw);
1495 CGRect srcRect, dstRect;
1496 HIShapeRef dmgRgn = NULL, extraRgn = NULL;
1497 NSRect bounds, visRect, scrollSrc, scrollDst;
1498 int result = 0;
1499
1500 if ( view ) {
1501 /* Get the scroll area in NSView coordinates (origin at bottom left). */
1502 bounds = [view bounds];
1503 scrollSrc = NSMakeRect(
1504 macDraw->xOff + x,
1505 bounds.size.height - height - (macDraw->yOff + y),
1506 width, height);
1507 scrollDst = NSOffsetRect(scrollSrc, dx, -dy);
1508
1509 /* Limit scrolling to the window content area. */
1510 visRect = [view visibleRect];
1511 scrollSrc = NSIntersectionRect(scrollSrc, visRect);
1512 scrollDst = NSIntersectionRect(scrollDst, visRect);
1513 if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) {
1514
1515 /*
1516 * Mark the difference between source and destination as damaged.
1517 * This region is described in NSView coordinates (y=0 at the bottom)
1518 * and converted to Tk coordinates later.
1519 */
1520
1521 srcRect = CGRectMake(x, y, width, height);
1522 dstRect = CGRectOffset(srcRect, dx, dy);
1523
1524 /* Expand the rectangles slightly to avoid degeneracies. */
1525 srcRect.origin.y -= 1;
1526 srcRect.size.height += 2;
1527 dstRect.origin.y += 1;
1528 dstRect.size.height -= 2;
1529
1530 /* Compute the damage. */
1531 dmgRgn = HIShapeCreateMutableWithRect(&srcRect);
1532 extraRgn = HIShapeCreateWithRect(&dstRect);
1533 ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn);
1534 result = HIShapeIsEmpty(dmgRgn) ? 0 : 1;
1535
1536 /* Convert to Tk coordinates. */
1537 TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
1538 if (extraRgn) {
1539 CFRelease(extraRgn);
1540 }
1541
1542 /* Scroll the rectangle. */
1543 [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)];
1544
1545 /* Shift the Tk children which meet the source rectangle. */
1546 TkWindow *winPtr = (TkWindow *)tkwin;
1547 TkWindow *childPtr;
1548 CGRect childBounds;
1549 for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) {
1550 if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) {
1551 TkMacOSXWinCGBounds(childPtr, &childBounds);
1552 if (CGRectIntersectsRect(srcRect, childBounds)) {
1553 MacDrawable *macChild = childPtr->privatePtr;
1554 if (macChild) {
1555 macChild->yOff += dy;
1556 macChild->xOff += dx;
1557 childPtr->changes.y = macChild->yOff;
1558 childPtr->changes.x = macChild->xOff;
1559 }
1560 }
1561 }
1562 }
1563
1564 /* Queue up Expose events for the damage region. */
1565 int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
1566 [view generateExposeEvents:dmgRgn childrenOnly:1];
1567 Tcl_SetServiceMode(oldMode);
1568
1569 /* Belt and suspenders: make the AppKit request a redraw
1570 when it gets control again. */
1571 }
1572 } else {
1573 dmgRgn = HIShapeCreateEmpty();
1574 TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn);
1575 }
1576
1577 if (dmgRgn) {
1578 CFRelease(dmgRgn);
1579 }
1580 return result;
1581 }
1582
1583 /*
1584 *----------------------------------------------------------------------
1585 *
1586 * TkMacOSXSetUpGraphicsPort --
1587 *
1588 * Set up the graphics port from the given GC.
1589 *
1590 * Results:
1591 * None.
1592 *
1593 * Side effects:
1594 * None.
1595 *
1596 *----------------------------------------------------------------------
1597 */
1598
1599 void
TkMacOSXSetUpGraphicsPort(GC gc,void * destPort)1600 TkMacOSXSetUpGraphicsPort(
1601 GC gc, /* GC to apply to current port. */
1602 void *destPort)
1603 {
1604 Tcl_Panic("TkMacOSXSetUpGraphicsPort: Obsolete, no more QD!");
1605 }
1606
1607
1608 /*
1609 *----------------------------------------------------------------------
1610 *
1611 * TkMacOSXSetUpDrawingContext --
1612 *
1613 * Set up a drawing context for the given drawable and GC.
1614 *
1615 * Results:
1616 * Boolean indicating whether it is ok to draw; if false, drawing
1617 * context was not setup, so do not attempt to draw and do not call
1618 * TkMacOSXRestoreDrawingContext().
1619 *
1620 * Side effects:
1621 * None.
1622 *
1623 *----------------------------------------------------------------------
1624 */
1625
1626 int
TkMacOSXSetupDrawingContext(Drawable d,GC gc,int useCG,TkMacOSXDrawingContext * dcPtr)1627 TkMacOSXSetupDrawingContext(
1628 Drawable d,
1629 GC gc,
1630 int useCG, /* advisory only ! */
1631 TkMacOSXDrawingContext *dcPtr)
1632 {
1633 MacDrawable *macDraw = ((MacDrawable*)d);
1634 int dontDraw = 0, isWin = 0;
1635 TkMacOSXDrawingContext dc = {};
1636 CGRect clipBounds;
1637
1638 dc.clipRgn = TkMacOSXGetClipRgn(d);
1639 if (!dontDraw) {
1640 ClipToGC(d, gc, &dc.clipRgn);
1641 dontDraw = dc.clipRgn ? HIShapeIsEmpty(dc.clipRgn) : 0;
1642 }
1643 if (dontDraw) {
1644 goto end;
1645 }
1646 if (useCG) {
1647 dc.context = GetCGContextForDrawable(d);
1648 }
1649 if (!dc.context || !(macDraw->flags & TK_IS_PIXMAP)) {
1650 isWin = (TkMacOSXDrawableWindow(d) != nil);
1651 }
1652 if (dc.context) {
1653 dc.portBounds = clipBounds = CGContextGetClipBoundingBox(dc.context);
1654 } else if (isWin) {
1655 NSView *view = TkMacOSXDrawableView(macDraw);
1656 if (view) {
1657 if (view != [NSView focusView]) {
1658 dc.focusLocked = [view lockFocusIfCanDraw];
1659 dontDraw = !dc.focusLocked;
1660 } else {
1661 dontDraw = ![view canDraw];
1662 }
1663 if (dontDraw) {
1664 goto end;
1665 }
1666 [[view window] disableFlushWindow];
1667 dc.view = view;
1668 dc.context = [[NSGraphicsContext currentContext] graphicsPort];
1669 dc.portBounds = NSRectToCGRect([view bounds]);
1670 if (dc.clipRgn) {
1671 clipBounds = CGContextGetClipBoundingBox(dc.context);
1672 }
1673 } else {
1674 Tcl_Panic("TkMacOSXSetupDrawingContext(): "
1675 "no NSView to draw into !");
1676 }
1677 } else {
1678 Tcl_Panic("TkMacOSXSetupDrawingContext(): "
1679 "no context to draw into !");
1680 }
1681 if (dc.context) {
1682 CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
1683 .ty = dc.portBounds.size.height};
1684 dc.portBounds.origin.x += macDraw->xOff;
1685 dc.portBounds.origin.y += macDraw->yOff;
1686 if (!dc.focusLocked) {
1687 CGContextSaveGState(dc.context);
1688 }
1689 CGContextSetTextDrawingMode(dc.context, kCGTextFill);
1690 CGContextConcatCTM(dc.context, t);
1691 if (dc.clipRgn) {
1692 #ifdef TK_MAC_DEBUG_DRAWING
1693 CGContextSaveGState(dc.context);
1694 ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
1695 CGContextSetRGBFillColor(dc.context, 1.0, 0.0, 0.0, 0.1);
1696 CGContextEOFillPath(dc.context);
1697 CGContextRestoreGState(dc.context);
1698 #endif /* TK_MAC_DEBUG_DRAWING */
1699 CGRect r;
1700 if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect(
1701 *HIShapeGetBounds(dc.clipRgn, &r),
1702 CGRectApplyAffineTransform(clipBounds, t))) {
1703 ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
1704 CGContextEOClip(dc.context);
1705 }
1706 }
1707 if (gc) {
1708 static const CGLineCap cgCap[] = {
1709 [CapNotLast] = kCGLineCapButt,
1710 [CapButt] = kCGLineCapButt,
1711 [CapRound] = kCGLineCapRound,
1712 [CapProjecting] = kCGLineCapSquare,
1713 };
1714 static const CGLineJoin cgJoin[] = {
1715 [JoinMiter] = kCGLineJoinMiter,
1716 [JoinRound] = kCGLineJoinRound,
1717 [JoinBevel] = kCGLineJoinBevel,
1718 };
1719 bool shouldAntialias;
1720 double w = gc->line_width;
1721
1722 TkMacOSXSetColorInContext(gc, gc->foreground, dc.context);
1723 if (isWin) {
1724 CGContextSetPatternPhase(dc.context, CGSizeMake(
1725 dc.portBounds.size.width, dc.portBounds.size.height));
1726 }
1727 if(gc->function != GXcopy) {
1728 TkMacOSXDbgMsg("Logical functions other than GXcopy are "
1729 "not supported for CG drawing!");
1730 }
1731 /* When should we antialias? */
1732 shouldAntialias = !notAA(gc->line_width);
1733 if (!shouldAntialias) {
1734 /* Make non-antialiased CG drawing look more like X11 */
1735 w -= (gc->line_width ? NON_AA_CG_OFFSET : 0);
1736 }
1737 CGContextSetShouldAntialias(dc.context, shouldAntialias);
1738 CGContextSetLineWidth(dc.context, w);
1739 if (gc->line_style != LineSolid) {
1740 int num = 0;
1741 char *p = &(gc->dashes);
1742 CGFloat dashOffset = gc->dash_offset;
1743 CGFloat lengths[10];
1744
1745 while (p[num] != '\0' && num < 10) {
1746 lengths[num] = p[num];
1747 num++;
1748 }
1749 CGContextSetLineDash(dc.context, dashOffset, lengths, num);
1750 }
1751 if ((unsigned)gc->cap_style < sizeof(cgCap)/sizeof(CGLineCap)) {
1752 CGContextSetLineCap(dc.context,
1753 cgCap[(unsigned)gc->cap_style]);
1754 }
1755 if ((unsigned)gc->join_style < sizeof(cgJoin)/sizeof(CGLineJoin)) {
1756 CGContextSetLineJoin(dc.context,
1757 cgJoin[(unsigned)gc->join_style]);
1758 }
1759 }
1760 }
1761 end:
1762 if (dontDraw && dc.clipRgn) {
1763 CFRelease(dc.clipRgn);
1764 dc.clipRgn = NULL;
1765 }
1766 *dcPtr = dc;
1767 return !dontDraw;
1768 }
1769
1770 /*
1771 *----------------------------------------------------------------------
1772 *
1773 * TkMacOSXRestoreDrawingContext --
1774 *
1775 * Restore drawing context.
1776 *
1777 * Results:
1778 * None.
1779 *
1780 * Side effects:
1781 * None.
1782 *
1783 *----------------------------------------------------------------------
1784 */
1785
1786 void
TkMacOSXRestoreDrawingContext(TkMacOSXDrawingContext * dcPtr)1787 TkMacOSXRestoreDrawingContext(
1788 TkMacOSXDrawingContext *dcPtr)
1789 {
1790 if (dcPtr->context) {
1791 CGContextSynchronize(dcPtr->context);
1792 [[dcPtr->view window] setViewsNeedDisplay:YES];
1793 [[dcPtr->view window] enableFlushWindow];
1794 if (dcPtr->focusLocked) {
1795 [dcPtr->view unlockFocus];
1796 } else {
1797 CGContextRestoreGState(dcPtr->context);
1798 }
1799 }
1800 if (dcPtr->clipRgn) {
1801 CFRelease(dcPtr->clipRgn);
1802 }
1803 #ifdef TK_MAC_DEBUG
1804 bzero(dcPtr, sizeof(TkMacOSXDrawingContext));
1805 #endif /* TK_MAC_DEBUG */
1806 }
1807
1808 /*
1809 *----------------------------------------------------------------------
1810 *
1811 * TkMacOSXGetClipRgn --
1812 *
1813 * Get the clipping region needed to restrict drawing to the given
1814 * drawable.
1815 *
1816 * Results:
1817 * Clipping region. If non-NULL, CFRelease it when done.
1818 *
1819 * Side effects:
1820 * None.
1821 *
1822 *----------------------------------------------------------------------
1823 */
1824
1825 HIShapeRef
TkMacOSXGetClipRgn(Drawable drawable)1826 TkMacOSXGetClipRgn(
1827 Drawable drawable) /* Drawable. */
1828 {
1829 MacDrawable *macDraw = (MacDrawable *) drawable;
1830 HIShapeRef clipRgn = NULL;
1831
1832 if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
1833 TkMacOSXUpdateClipRgn(macDraw->winPtr);
1834 #ifdef TK_MAC_DEBUG_DRAWING
1835 TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName);
1836 NSView *view = TkMacOSXDrawableView(macDraw);
1837 if ([view lockFocusIfCanDraw]) {
1838 CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
1839 CGContextSaveGState(context);
1840 CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
1841 -1.0, 0.0, [view bounds].size.height));
1842 ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
1843 CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
1844 CGContextEOFillPath(context);
1845 CGContextRestoreGState(context);
1846 [view unlockFocus];
1847 }
1848 #endif /* TK_MAC_DEBUG_DRAWING */
1849 }
1850
1851 if (macDraw->drawRgn) {
1852 clipRgn = HIShapeCreateCopy(macDraw->drawRgn);
1853 } else if (macDraw->visRgn) {
1854 clipRgn = HIShapeCreateCopy(macDraw->visRgn);
1855 }
1856 return clipRgn;
1857 }
1858
1859 /*
1860 *----------------------------------------------------------------------
1861 *
1862 * TkMacOSXSetUpClippingRgn --
1863 *
1864 * Set up the clipping region so that drawing only occurs on the
1865 * specified X subwindow.
1866 *
1867 * Results:
1868 * None.
1869 *
1870 * Side effects:
1871 * None.
1872 *
1873 *----------------------------------------------------------------------
1874 */
1875
1876 void
TkMacOSXSetUpClippingRgn(Drawable drawable)1877 TkMacOSXSetUpClippingRgn(
1878 Drawable drawable) /* Drawable to update. */
1879 {
1880 }
1881
1882 /*
1883 *----------------------------------------------------------------------
1884 *
1885 * TkpClipDrawableToRect --
1886 *
1887 * Clip all drawing into the drawable d to the given rectangle.
1888 * If width or height are negative, reset to no clipping.
1889 *
1890 * Results:
1891 * None.
1892 *
1893 * Side effects:
1894 * Subsequent drawing into d is offset and clipped as specified.
1895 *
1896 *----------------------------------------------------------------------
1897 */
1898
1899 void
TkpClipDrawableToRect(Display * display,Drawable d,int x,int y,int width,int height)1900 TkpClipDrawableToRect(
1901 Display *display,
1902 Drawable d,
1903 int x, int y,
1904 int width, int height)
1905 {
1906 MacDrawable *macDraw = (MacDrawable *) d;
1907 NSView *view = TkMacOSXDrawableView(macDraw);
1908
1909 if (macDraw->drawRgn) {
1910 CFRelease(macDraw->drawRgn);
1911 macDraw->drawRgn = NULL;
1912 }
1913
1914 if (width >= 0 && height >= 0) {
1915 CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff,
1916 width, height);
1917 HIShapeRef drawRgn = HIShapeCreateWithRect(&clipRect);
1918
1919 if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
1920 TkMacOSXUpdateClipRgn(macDraw->winPtr);
1921 }
1922 if (macDraw->visRgn) {
1923 macDraw->drawRgn = HIShapeCreateIntersection(macDraw->visRgn,
1924 drawRgn);
1925 CFRelease(drawRgn);
1926 } else {
1927 macDraw->drawRgn = drawRgn;
1928 }
1929 if (view && view != [NSView focusView] && [view lockFocusIfCanDraw]) {
1930 clipRect.origin.y = [view bounds].size.height -
1931 (clipRect.origin.y + clipRect.size.height);
1932 NSRectClip(NSRectFromCGRect(clipRect));
1933 macDraw->flags |= TK_FOCUSED_VIEW;
1934 }
1935 } else {
1936 if (view && (macDraw->flags & TK_FOCUSED_VIEW)) {
1937 [view unlockFocus];
1938 macDraw->flags &= ~TK_FOCUSED_VIEW;
1939 }
1940 }
1941 }
1942
1943 /*
1944 *----------------------------------------------------------------------
1945 *
1946 * ClipToGC --
1947 *
1948 * Helper function to intersect given region with gc clip region.
1949 *
1950 * Results:
1951 * None.
1952 *
1953 * Side effects:
1954 * None.
1955 *
1956 *----------------------------------------------------------------------
1957 */
1958
1959 static void
ClipToGC(Drawable d,GC gc,HIShapeRef * clipRgnPtr)1960 ClipToGC(
1961 Drawable d,
1962 GC gc,
1963 HIShapeRef *clipRgnPtr) /* must point to initialized variable */
1964 {
1965 if (gc && gc->clip_mask &&
1966 ((TkpClipMask*)gc->clip_mask)->type == TKP_CLIP_REGION) {
1967 TkRegion gcClip = ((TkpClipMask*)gc->clip_mask)->value.region;
1968 int xOffset = ((MacDrawable *) d)->xOff + gc->clip_x_origin;
1969 int yOffset = ((MacDrawable *) d)->yOff + gc->clip_y_origin;
1970 HIShapeRef clipRgn = *clipRgnPtr, gcClipRgn;
1971
1972 TkMacOSXOffsetRegion(gcClip, xOffset, yOffset);
1973 gcClipRgn = TkMacOSXGetNativeRegion(gcClip);
1974 if (clipRgn) {
1975 *clipRgnPtr = HIShapeCreateIntersection(gcClipRgn, clipRgn);
1976 CFRelease(clipRgn);
1977 } else {
1978 *clipRgnPtr = HIShapeCreateCopy(gcClipRgn);
1979 }
1980 CFRelease(gcClipRgn);
1981 TkMacOSXOffsetRegion(gcClip, -xOffset, -yOffset);
1982 }
1983 }
1984
1985 /*
1986 *----------------------------------------------------------------------
1987 *
1988 * TkMacOSXMakeStippleMap --
1989 *
1990 * Given a drawable and a stipple pattern this function draws the
1991 * pattern repeatedly over the drawable. The drawable can then
1992 * be used as a mask for bit-bliting a stipple pattern over an
1993 * object.
1994 *
1995 * Results:
1996 * A BitMap data structure.
1997 *
1998 * Side effects:
1999 * None.
2000 *
2001 *----------------------------------------------------------------------
2002 */
2003
2004 void *
TkMacOSXMakeStippleMap(Drawable drawable,Drawable stipple)2005 TkMacOSXMakeStippleMap(
2006 Drawable drawable, /* Window to apply stipple. */
2007 Drawable stipple) /* The stipple pattern. */
2008 {
2009 return NULL;
2010 }
2011
2012 /*
2013 *----------------------------------------------------------------------
2014 *
2015 * TkpDrawHighlightBorder --
2016 *
2017 * This procedure draws a rectangular ring around the outside of
2018 * a widget to indicate that it has received the input focus.
2019 *
2020 * On the Macintosh, this puts a 1 pixel border in the bgGC color
2021 * between the widget and the focus ring, except in the case where
2022 * highlightWidth is 1, in which case the border is left out.
2023 *
2024 * For proper Mac L&F, use highlightWidth of 3.
2025 *
2026 * Results:
2027 * None.
2028 *
2029 * Side effects:
2030 * A rectangle "width" pixels wide is drawn in "drawable",
2031 * corresponding to the outer area of "tkwin".
2032 *
2033 *----------------------------------------------------------------------
2034 */
2035
2036 void
TkpDrawHighlightBorder(Tk_Window tkwin,GC fgGC,GC bgGC,int highlightWidth,Drawable drawable)2037 TkpDrawHighlightBorder (
2038 Tk_Window tkwin,
2039 GC fgGC,
2040 GC bgGC,
2041 int highlightWidth,
2042 Drawable drawable)
2043 {
2044 if (highlightWidth == 1) {
2045 TkDrawInsetFocusHighlight (tkwin, fgGC, highlightWidth, drawable, 0);
2046 } else {
2047 TkDrawInsetFocusHighlight (tkwin, bgGC, highlightWidth, drawable, 0);
2048 if (fgGC != bgGC) {
2049 TkDrawInsetFocusHighlight (tkwin, fgGC, highlightWidth - 1,
2050 drawable, 0);
2051 }
2052 }
2053 }
2054
2055 /*
2056 *----------------------------------------------------------------------
2057 *
2058 * TkpDrawFrame --
2059 *
2060 * This procedure draws the rectangular frame area. If the user
2061 * has requested themeing, it draws with the background theme.
2062 *
2063 * Results:
2064 * None.
2065 *
2066 * Side effects:
2067 * Draws inside the tkwin area.
2068 *
2069 *----------------------------------------------------------------------
2070 */
2071
2072 void
TkpDrawFrame(Tk_Window tkwin,Tk_3DBorder border,int highlightWidth,int borderWidth,int relief)2073 TkpDrawFrame(
2074 Tk_Window tkwin,
2075 Tk_3DBorder border,
2076 int highlightWidth,
2077 int borderWidth,
2078 int relief)
2079 {
2080 if (useThemedToplevel && Tk_IsTopLevel(tkwin)) {
2081 static Tk_3DBorder themedBorder = NULL;
2082
2083 if (!themedBorder) {
2084 themedBorder = Tk_Get3DBorder(NULL, tkwin,
2085 "systemWindowHeaderBackground");
2086 }
2087 if (themedBorder) {
2088 border = themedBorder;
2089 }
2090 }
2091
2092 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
2093 border, highlightWidth, highlightWidth,
2094 Tk_Width(tkwin) - 2 * highlightWidth,
2095 Tk_Height(tkwin) - 2 * highlightWidth,
2096 borderWidth, relief);
2097 }
2098
2099 /*
2100 * Local Variables:
2101 * mode: objc
2102 * c-basic-offset: 4
2103 * fill-column: 79
2104 * coding: utf-8
2105 * End:
2106 */
2107