1/*
2 * tkMacOSXXStubs.c --
3 *
4 *	This file contains most of the X calls called by Tk. Many of these
5 *	calls are just stubs and either don't make sense on the Macintosh or
6 *	their implamentation just doesn't do anything. Other calls will
7 *	eventually be moved into other files.
8 *
9 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
10 * Copyright 2001-2009, Apple Inc.
11 * Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
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 * RCS: @(#) $Id$
17 */
18
19#include "tkMacOSXPrivate.h"
20#include "tkMacOSXEvent.h"
21
22#include <IOKit/IOKitLib.h>
23#include <IOKit/hidsystem/IOHIDShared.h>
24
25/*
26 * Because this file is still under major development Debugger statements are
27 * used through out this file. The define TCL_DEBUG will decide whether the
28 * debugger statements actually call the debugger or not.
29 */
30
31#ifndef TCL_DEBUG
32#   define Debugger()
33#endif
34
35#define ROOT_ID 10
36
37CGFloat tkMacOSXZeroScreenHeight = 0;
38CGFloat tkMacOSXZeroScreenTop = 0;
39
40/*
41 * Declarations of static variables used in this file.
42 */
43
44static TkDisplay *gMacDisplay = NULL;
45				/* Macintosh display. */
46static const char *macScreenName = ":0";
47				/* Default name of macintosh display. */
48
49/*
50 * Forward declarations of procedures used in this file.
51 */
52
53static XID		MacXIdAlloc(Display *display);
54static int		DefaultErrorHandler(Display *display,
55			    XErrorEvent *err_evt);
56
57/*
58 * Other declarations
59 */
60
61static int		DestroyImage(XImage *image);
62static unsigned long	ImageGetPixel(XImage *image, int x, int y);
63static int		ImagePutPixel(XImage *image, int x, int y,
64			    unsigned long pixel);
65
66/*
67 *----------------------------------------------------------------------
68 *
69 * TkMacOSXDisplayChanged --
70 *
71 *	Called to set up initial screen info or when an event indicated
72 *	display (screen) change.
73 *
74 * Results:
75 *	None.
76 *
77 * Side effects:
78 *	May change info regarding the screen.
79 *
80 *----------------------------------------------------------------------
81 */
82
83void
84TkMacOSXDisplayChanged(
85    Display *display)
86{
87    Screen *screen;
88    NSArray *nsScreens;
89
90
91    if (display == NULL || display->screens == NULL) {
92	return;
93    }
94    screen = display->screens;
95
96    nsScreens = [NSScreen screens];
97    if (nsScreens && [nsScreens count]) {
98	NSScreen *s = [nsScreens objectAtIndex:0];
99	NSRect bounds = [s frame], visible = [s visibleFrame];
100	NSRect maxBounds = NSZeroRect;
101
102	tkMacOSXZeroScreenHeight = bounds.size.height;
103	tkMacOSXZeroScreenTop = tkMacOSXZeroScreenHeight -
104		(visible.origin.y + visible.size.height);
105
106	screen->root_depth = NSBitsPerPixelFromDepth([s depth]);
107	screen->width = bounds.size.width;
108	screen->height = bounds.size.height;
109	screen->mwidth = (bounds.size.width * 254 + 360) / 720;
110	screen->mheight = (bounds.size.height * 254 + 360) / 720;
111
112	for (s in nsScreens) {
113	    maxBounds = NSUnionRect(maxBounds, [s visibleFrame]);
114	}
115	*((NSRect *)screen->ext_data) = maxBounds;
116    }
117}
118
119/*
120 *----------------------------------------------------------------------
121 *
122 * TkpOpenDisplay --
123 *
124 *	Create the Display structure and fill it with device specific
125 *	information.
126 *
127 * Results:
128 *	Returns a Display structure on success or NULL on failure.
129 *
130 * Side effects:
131 *	Allocates a new Display structure.
132 *
133 *----------------------------------------------------------------------
134 */
135
136TkDisplay *
137TkpOpenDisplay(
138    const char *display_name)
139{
140    Display *display;
141    Screen *screen;
142    int fd = 0;
143    static NSRect maxBounds = {{0, 0}, {0, 0}};
144    static char vendor[25] = "";
145    NSArray *cgVers;
146    NSAutoreleasePool *pool;
147
148    if (gMacDisplay != NULL) {
149	if (strcmp(gMacDisplay->display->display_name, display_name) == 0) {
150	    return gMacDisplay;
151	} else {
152	    return NULL;
153	}
154    }
155
156    display = (Display *) ckalloc(sizeof(Display));
157    screen  = (Screen *) ckalloc(sizeof(Screen));
158    bzero(display, sizeof(Display));
159    bzero(screen, sizeof(Screen));
160
161    display->resource_alloc = MacXIdAlloc;
162    display->request	    = 0;
163    display->qlen	    = 0;
164    display->fd		    = fd;
165    display->screens	    = screen;
166    display->nscreens	    = 1;
167    display->default_screen = 0;
168    display->display_name   = (char *) macScreenName;
169
170    pool = [NSAutoreleasePool new];
171    cgVers = [[[NSBundle bundleWithIdentifier:@"com.apple.CoreGraphics"]
172	    objectForInfoDictionaryKey:@"CFBundleShortVersionString"]
173	    componentsSeparatedByString:@"."];
174    if ([cgVers count] >= 2) {
175	display->proto_major_version = [[cgVers objectAtIndex:1] integerValue];
176    }
177    if ([cgVers count] >= 3) {
178	display->proto_minor_version = [[cgVers objectAtIndex:2] integerValue];
179    }
180    if (!vendor[0]) {
181	snprintf(vendor, sizeof(vendor), "Apple AppKit %s %g",
182		([NSGarbageCollector defaultCollector] ? "GC" : "RR"),
183		NSAppKitVersionNumber);
184    }
185    display->vendor = vendor;
186    Gestalt(gestaltSystemVersion, (SInt32 *) &display->release);
187
188    /*
189     * These screen bits never change
190     */
191    screen->root	= ROOT_ID;
192    screen->display	= display;
193    screen->black_pixel = 0x00000000 | PIXEL_MAGIC << 24;
194    screen->white_pixel = 0x00FFFFFF | PIXEL_MAGIC << 24;
195    screen->ext_data	= (XExtData *) &maxBounds;
196
197    screen->root_visual = (Visual *) ckalloc(sizeof(Visual));
198    screen->root_visual->visualid     = 0;
199    screen->root_visual->class	      = TrueColor;
200    screen->root_visual->red_mask     = 0x00FF0000;
201    screen->root_visual->green_mask   = 0x0000FF00;
202    screen->root_visual->blue_mask    = 0x000000FF;
203    screen->root_visual->bits_per_rgb = 24;
204    screen->root_visual->map_entries  = 256;
205
206    /*
207     * Initialize screen bits that may change
208     */
209
210    TkMacOSXDisplayChanged(display);
211
212    gMacDisplay = (TkDisplay *) ckalloc(sizeof(TkDisplay));
213
214    /*
215     * This is the quickest way to make sure that all the *Init flags get
216     * properly initialized
217     */
218
219    bzero(gMacDisplay, sizeof(TkDisplay));
220    gMacDisplay->display = display;
221    [pool drain];
222    return gMacDisplay;
223}
224
225/*
226 *----------------------------------------------------------------------
227 *
228 * TkpCloseDisplay --
229 *
230 *	Deallocates a display structure created by TkpOpenDisplay.
231 *
232 * Results:
233 *	None.
234 *
235 * Side effects:
236 *	Frees memory.
237 *
238 *----------------------------------------------------------------------
239 */
240
241void
242TkpCloseDisplay(
243    TkDisplay *displayPtr)
244{
245    Display *display = displayPtr->display;
246
247    if (gMacDisplay != displayPtr) {
248	Tcl_Panic("TkpCloseDisplay: tried to call TkpCloseDisplay on bad display");
249    }
250
251    gMacDisplay = NULL;
252    if (display->screens != NULL) {
253	if (display->screens->root_visual != NULL) {
254	    ckfree((char *) display->screens->root_visual);
255	}
256	ckfree((char *) display->screens);
257    }
258    ckfree((char *) display);
259}
260
261/*
262 *----------------------------------------------------------------------
263 *
264 * TkClipCleanup --
265 *
266 *	This procedure is called to cleanup resources associated with claiming
267 *	clipboard ownership and for receiving selection get results. This
268 *	function is called in tkWindow.c. This has to be called by the display
269 *	cleanup function because we still need the access display elements.
270 *
271 * Results:
272 *	None.
273 *
274 * Side effects:
275 *	Resources are freed - the clipboard may no longer be used.
276 *
277 *----------------------------------------------------------------------
278 */
279
280void
281TkClipCleanup(
282    TkDisplay *dispPtr)		/* display associated with clipboard */
283{
284    /*
285     * Make sure that the local scrap is transfered to the global scrap if
286     * needed.
287     */
288
289    [NSApp tkProvidePasteboard:dispPtr];
290
291    if (dispPtr->clipWindow != NULL) {
292	Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
293		dispPtr->applicationAtom);
294	Tk_DeleteSelHandler(dispPtr->clipWindow, dispPtr->clipboardAtom,
295		dispPtr->windowAtom);
296
297	Tk_DestroyWindow(dispPtr->clipWindow);
298	Tcl_Release(dispPtr->clipWindow);
299	dispPtr->clipWindow = NULL;
300    }
301}
302
303/*
304 *----------------------------------------------------------------------
305 *
306 * MacXIdAlloc --
307 *
308 *	This procedure is invoked by Xlib as the resource allocator for a
309 *	display.
310 *
311 * Results:
312 *	The return value is an X resource identifier that isn't currently in
313 *	use.
314 *
315 * Side effects:
316 *	The identifier is removed from the stack of free identifiers, if it
317 *	was previously on the stack.
318 *
319 *----------------------------------------------------------------------
320 */
321
322static XID
323MacXIdAlloc(
324    Display *display)		/* Display for which to allocate. */
325{
326    static long int cur_id = 100;
327    /*
328     * Some special XIds are reserved
329     *   - this is why we start at 100
330     */
331
332    return ++cur_id;
333}
334
335/*
336 *----------------------------------------------------------------------
337 *
338 * TkpWindowWasRecentlyDeleted --
339 *
340 *	Tries to determine whether the given window was recently deleted.
341 *	Called from the generic code error handler to attempt to deal with
342 *	async BadWindow errors under some circumstances.
343 *
344 * Results:
345 *	Always 0, we do not keep this information on the Mac, so we do not
346 *	know whether the window was destroyed.
347 *
348 * Side effects:
349 *	None.
350 *
351 *----------------------------------------------------------------------
352 */
353
354int
355TkpWindowWasRecentlyDeleted(
356    Window win,
357    TkDisplay *dispPtr)
358{
359    return 0;
360}
361
362/*
363 *----------------------------------------------------------------------
364 *
365 * DefaultErrorHandler --
366 *
367 *	This procedure is the default X error handler. Tk uses it's own error
368 *	handler so this call should never be called.
369 *
370 * Results:
371 *	None.
372 *
373 * Side effects:
374 *	This function will call panic and exit.
375 *
376 *----------------------------------------------------------------------
377 */
378
379static int
380DefaultErrorHandler(
381    Display* display,
382    XErrorEvent* err_evt)
383{
384    /*
385     * This call should never be called. Tk replaces it with its own error
386     * handler.
387     */
388
389    Tcl_Panic("Warning hit bogus error handler!");
390    return 0;
391}
392
393char *
394XGetAtomName(
395    Display * display,
396    Atom atom)
397{
398    display->request++;
399    return NULL;
400}
401
402int
403_XInitImageFuncPtrs(
404    XImage *image)
405{
406    return 0;
407}
408
409XErrorHandler
410XSetErrorHandler(
411    XErrorHandler handler)
412{
413    return DefaultErrorHandler;
414}
415
416Window
417XRootWindow(
418    Display *display,
419    int screen_number)
420{
421    display->request++;
422    return ROOT_ID;
423}
424
425int
426XGetGeometry(
427    Display *display,
428    Drawable d,
429    Window *root_return,
430    int *x_return,
431    int *y_return,
432    unsigned int *width_return,
433    unsigned int *height_return,
434    unsigned int *border_width_return,
435    unsigned int *depth_return)
436{
437    TkWindow *winPtr = ((MacDrawable *) d)->winPtr;
438
439    display->request++;
440    *root_return = ROOT_ID;
441    if (winPtr) {
442	*x_return = Tk_X(winPtr);
443	*y_return = Tk_Y(winPtr);
444	*width_return = Tk_Width(winPtr);
445	*height_return = Tk_Height(winPtr);
446	*border_width_return = winPtr->changes.border_width;
447	*depth_return = Tk_Depth(winPtr);
448    } else {
449	CGSize size = ((MacDrawable *) d)->size;
450	*x_return = 0;
451	*y_return =  0;
452	*width_return = size.width;
453	*height_return = size.height;
454	*border_width_return = 0;
455	*depth_return = 32;
456    }
457    return 1;
458}
459
460void
461XChangeProperty(
462    Display* display,
463    Window w,
464    Atom property,
465    Atom type,
466    int format,
467    int mode,
468    _Xconst unsigned char* data,
469    int nelements)
470{
471    Debugger();
472}
473
474void
475XSelectInput(
476    Display* display,
477    Window w,
478    long event_mask)
479{
480    Debugger();
481}
482
483void
484XBell(
485    Display* display,
486    int percent)
487{
488    NSBeep();
489}
490
491#if 0
492void
493XSetWMNormalHints(
494    Display* display,
495    Window w,
496    XSizeHints* hints)
497{
498    /*
499     * Do nothing. Shouldn't even be called.
500     */
501}
502
503XSizeHints *
504XAllocSizeHints(void)
505{
506    /*
507     * Always return NULL. Tk code checks to see if NULL is returned & does
508     * nothing if it is.
509     */
510
511    return NULL;
512}
513#endif
514
515GContext
516XGContextFromGC(
517    GC gc)
518{
519    /*
520     * TODO: currently a no-op
521     */
522
523    return 0;
524}
525
526Status
527XSendEvent(
528    Display* display,
529    Window w,
530    Bool propagate,
531    long event_mask,
532    XEvent* event_send)
533{
534    Debugger();
535    return 0;
536}
537
538void
539XClearWindow(
540    Display* display,
541    Window w)
542{
543}
544
545/*
546void
547XDrawPoint(
548    Display* display,
549    Drawable d,
550    GC gc,
551    int x,
552    int y)
553{
554}
555
556void
557XDrawPoints(
558    Display* display,
559    Drawable d,
560    GC gc,
561    XPoint* points,
562    int npoints,
563    int mode)
564{
565}
566*/
567
568void
569XWarpPointer(
570    Display* display,
571    Window src_w,
572    Window dest_w,
573    int src_x,
574    int src_y,
575    unsigned int src_width,
576    unsigned int src_height,
577    int dest_x,
578    int dest_y)
579{
580}
581
582void
583XQueryColor(
584    Display* display,
585    Colormap colormap,
586    XColor* def_in_out)
587{
588    unsigned long p;
589    unsigned char r, g, b;
590    XColor *d = def_in_out;
591
592    p		= d->pixel;
593    r		= (p & 0x00FF0000) >> 16;
594    g		= (p & 0x0000FF00) >> 8;
595    b		= (p & 0x000000FF);
596    d->red	= (r << 8) | r;
597    d->green	= (g << 8) | g;
598    d->blue	= (b << 8) | b;
599    d->flags	= DoRed|DoGreen|DoBlue;
600    d->pad	= 0;
601}
602
603void
604XQueryColors(
605    Display* display,
606    Colormap colormap,
607    XColor* defs_in_out,
608    int ncolors)
609{
610    int i;
611    unsigned long p;
612    unsigned char r, g, b;
613    XColor *d = defs_in_out;
614
615    for (i = 0; i < ncolors; i++, d++) {
616	p		= d->pixel;
617	r		= (p & 0x00FF0000) >> 16;
618	g		= (p & 0x0000FF00) >> 8;
619	b		= (p & 0x000000FF);
620	d->red		= (r << 8) | r;
621	d->green	= (g << 8) | g;
622	d->blue		= (b << 8) | b;
623	d->flags	= DoRed|DoGreen|DoBlue;
624	d->pad		= 0;
625    }
626}
627
628int
629XQueryTree(display, w, root_return, parent_return, children_return,
630	nchildren_return)
631    Display* display;
632    Window w;
633    Window* root_return;
634    Window* parent_return;
635    Window** children_return;
636    unsigned int* nchildren_return;
637{
638    return 0;
639}
640
641
642int
643XGetWindowProperty(
644    Display *display,
645    Window w,
646    Atom property,
647    long long_offset,
648    long long_length,
649    Bool delete,
650    Atom req_type,
651    Atom *actual_type_return,
652    int *actual_format_return,
653    unsigned long *nitems_return,
654    unsigned long *bytes_after_return,
655    unsigned char ** prop_return)
656{
657    display->request++;
658    *actual_type_return = None;
659    *actual_format_return = *bytes_after_return = 0;
660    *nitems_return = 0;
661    return 0;
662}
663
664void
665XRefreshKeyboardMapping(
666    XMappingEvent *x)
667{
668    /* used by tkXEvent.c */
669    Debugger();
670}
671
672void
673XSetIconName(
674    Display* display,
675    Window w,
676    const char *icon_name)
677{
678    /*
679     * This is a no-op, no icon name for Macs.
680     */
681    display->request++;
682}
683
684void
685XForceScreenSaver(
686    Display* display,
687    int mode)
688{
689    /*
690     * This function is just a no-op. It is defined to reset the screen saver.
691     * However, there is no real way to do this on a Mac. Let me know if there
692     * is!
693     */
694
695    display->request++;
696}
697
698void
699Tk_FreeXId(
700    Display *display,
701    XID xid)
702{
703    /* no-op function needed for stubs implementation. */
704}
705
706int
707XSync(
708    Display *display,
709    Bool flag)
710{
711    TkMacOSXFlushWindows();
712    display->request++;
713    return 0;
714}
715
716#if 0
717int
718XSetClipRectangles(
719    Display *d,
720    GC gc,
721    int clip_x_origin,
722    int clip_y_origin,
723    XRectangle* rectangles,
724    int n,
725    int ordering)
726{
727    TkRegion clipRgn = TkCreateRegion();
728
729    while (n--) {
730	XRectangle rect = *rectangles;
731
732	rect.x += clip_x_origin;
733	rect.y += clip_y_origin;
734	TkUnionRectWithRegion(&rect, clipRgn, clipRgn);
735	rectangles++;
736    }
737    TkSetRegion(d, gc, clipRgn);
738    TkDestroyRegion(clipRgn);
739    return 1;
740}
741#endif
742
743/*
744 *----------------------------------------------------------------------
745 *
746 * TkGetServerInfo --
747 *
748 *	Given a window, this procedure returns information about the window
749 *	server for that window. This procedure provides the guts of the "winfo
750 *	server" command.
751 *
752 * Results:
753 *	None.
754 *
755 * Side effects:
756 *	None.
757 *
758 *----------------------------------------------------------------------
759 */
760
761void
762TkGetServerInfo(
763    Tcl_Interp *interp,		/* The server information is returned in this
764				 * interpreter's result. */
765    Tk_Window tkwin)		/* Token for window; this selects a particular
766				 * display and server. */
767{
768    char buffer[5 + TCL_INTEGER_SPACE * 2];
769    char buffer2[11 + TCL_INTEGER_SPACE];
770
771    snprintf(buffer, sizeof(buffer), "CG%d.%d ",
772	    ProtocolVersion(Tk_Display(tkwin)),
773	    ProtocolRevision(Tk_Display(tkwin)));
774    snprintf(buffer2, sizeof(buffer2), " Mac OS X %x",
775	    VendorRelease(Tk_Display(tkwin)));
776    Tcl_AppendResult(interp, buffer, ServerVendor(Tk_Display(tkwin)),
777	    buffer2, NULL);
778}
779
780#pragma mark XImage handling
781
782/*
783 *----------------------------------------------------------------------
784 *
785 * XCreateImage --
786 *
787 *	Allocates storage for a new XImage.
788 *
789 * Results:
790 *	Returns a newly allocated XImage.
791 *
792 * Side effects:
793 *	None.
794 *
795 *----------------------------------------------------------------------
796 */
797
798XImage *
799XCreateImage(
800    Display* display,
801    Visual* visual,
802    unsigned int depth,
803    int format,
804    int offset,
805    char* data,
806    unsigned int width,
807    unsigned int height,
808    int bitmap_pad,
809    int bytes_per_line)
810{
811    XImage *ximage;
812
813    display->request++;
814    ximage = (XImage *) ckalloc(sizeof(XImage));
815
816    ximage->height = height;
817    ximage->width = width;
818    ximage->depth = depth;
819    ximage->xoffset = offset;
820    ximage->format = format;
821    ximage->data = data;
822
823    if (format == ZPixmap) {
824	ximage->bits_per_pixel = 32;
825	ximage->bitmap_unit = 32;
826    } else {
827	ximage->bits_per_pixel = 1;
828	ximage->bitmap_unit = 8;
829    }
830    if (bitmap_pad) {
831	ximage->bitmap_pad = bitmap_pad;
832    } else {
833	/* Use 16 byte alignment for best Quartz perfomance */
834	ximage->bitmap_pad = 128;
835    }
836    if (bytes_per_line) {
837	ximage->bytes_per_line = bytes_per_line;
838    } else {
839	ximage->bytes_per_line = ((width * ximage->bits_per_pixel +
840		(ximage->bitmap_pad - 1)) >> 3) &
841		~((ximage->bitmap_pad >> 3) - 1);
842    }
843#ifdef WORDS_BIGENDIAN
844    ximage->byte_order = MSBFirst;
845    ximage->bitmap_bit_order = MSBFirst;
846#else
847    ximage->byte_order = LSBFirst;
848    ximage->bitmap_bit_order = LSBFirst;
849#endif
850    ximage->red_mask = 0x00FF0000;
851    ximage->green_mask = 0x0000FF00;
852    ximage->blue_mask = 0x000000FF;
853    ximage->obdata = NULL;
854    ximage->f.create_image = NULL;
855    ximage->f.destroy_image = DestroyImage;
856    ximage->f.get_pixel = ImageGetPixel;
857    ximage->f.put_pixel = ImagePutPixel;
858    ximage->f.sub_image = NULL;
859    ximage->f.add_pixel = NULL;
860
861    return ximage;
862}
863
864/*
865 *----------------------------------------------------------------------
866 *
867 * XGetImage --
868 *
869 *	This function copies data from a pixmap or window into an XImage.
870 *
871 * Results:
872 *	Returns a newly allocated image containing the data from the given
873 *	rectangle of the given drawable.
874 *
875 * Side effects:
876 *	None.
877 *
878 *----------------------------------------------------------------------
879 */
880
881XImage *
882XGetImage(
883    Display *display,
884    Drawable d,
885    int x,
886    int y,
887    unsigned int width,
888    unsigned int height,
889    unsigned long plane_mask,
890    int format)
891{
892    MacDrawable *macDraw = (MacDrawable *) d;
893    XImage *   imagePtr = NULL;
894    Pixmap     pixmap = (Pixmap) NULL;
895    Tk_Window  win = (Tk_Window) macDraw->winPtr;
896    GC	       gc;
897    char *     data = NULL;
898    int	       depth = 32;
899    int	       offset = 0;
900    int	       bitmap_pad = 0;
901    int	       bytes_per_line = 0;
902
903    if (format == ZPixmap) {
904	if (width > 0 && height > 0) {
905	    /*
906	     * Tk_GetPixmap fails for zero width or height.
907	     */
908
909	    pixmap = Tk_GetPixmap(display, d, width, height, depth);
910	}
911	if (win) {
912	    XGCValues values;
913
914	    gc = Tk_GetGC(win, 0, &values);
915	} else {
916	    gc = XCreateGC(display, pixmap, 0, NULL);
917	}
918	if (pixmap) {
919	    CGContextRef context;
920
921	    XCopyArea(display, d, pixmap, gc, x, y, width, height, 0, 0);
922	    context = ((MacDrawable *) pixmap)->context;
923	    if (context) {
924		data = CGBitmapContextGetData(context);
925		bytes_per_line = CGBitmapContextGetBytesPerRow(context);
926	    }
927	}
928	if (data) {
929	    imagePtr = XCreateImage(display, NULL, depth, format, offset,
930		    data, width, height, bitmap_pad, bytes_per_line);
931
932	    /*
933	     * Track Pixmap underlying the XImage in the unused obdata field
934	     * so that we can treat XImages coming from XGetImage specially.
935	     */
936
937	    imagePtr->obdata = (XPointer) pixmap;
938	} else if (pixmap) {
939	    Tk_FreePixmap(display, pixmap);
940	}
941	if (!win) {
942	    XFreeGC(display, gc);
943	}
944    } else {
945	TkMacOSXDbgMsg("Invalid image format");
946    }
947    return imagePtr;
948}
949
950/*
951 *----------------------------------------------------------------------
952 *
953 * DestroyImage --
954 *
955 *	Destroys storage associated with an image.
956 *
957 * Results:
958 *	None.
959 *
960 * Side effects:
961 *	Deallocates the image.
962 *
963 *----------------------------------------------------------------------
964 */
965
966static int
967DestroyImage(
968    XImage *image)
969{
970    if (image) {
971	if (image->obdata) {
972	    Tk_FreePixmap((Display*) gMacDisplay, (Pixmap) image->obdata);
973	} else if (image->data) {
974	    ckfree(image->data);
975	}
976	ckfree((char*) image);
977    }
978    return 0;
979}
980
981/*
982 *----------------------------------------------------------------------
983 *
984 * ImageGetPixel --
985 *
986 *	Get a single pixel from an image.
987 *
988 * Results:
989 *	Returns the 32 bit pixel value.
990 *
991 * Side effects:
992 *	None.
993 *
994 *----------------------------------------------------------------------
995 */
996
997static unsigned long
998ImageGetPixel(
999    XImage *image,
1000    int x,
1001    int y)
1002{
1003    unsigned char r = 0, g = 0, b = 0;
1004
1005    if (image && image->data) {
1006	unsigned char *srcPtr = ((unsigned char*) image->data)
1007		+ (y * image->bytes_per_line)
1008		+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
1009
1010	switch (image->bits_per_pixel) {
1011	    case 32: {
1012		r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
1013		g = (*((unsigned int*) srcPtr) >>  8) & 0xff;
1014		b = (*((unsigned int*) srcPtr)      ) & 0xff;
1015		/*if (image->byte_order == LSBFirst) {
1016		    r = srcPtr[2]; g = srcPtr[1]; b = srcPtr[0];
1017		} else {
1018		    r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
1019		}*/
1020		break;
1021	    }
1022	    case 16:
1023		r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
1024		g = (*((unsigned short*) srcPtr) >> 2) & 0xf8;
1025		b = (*((unsigned short*) srcPtr) << 3) & 0xf8;
1026		break;
1027	    case 8:
1028		r = (*srcPtr << 2) & 0xc0;
1029		g = (*srcPtr << 4) & 0xc0;
1030		b = (*srcPtr << 6) & 0xc0;
1031		r |= r >> 2 | r >> 4 | r >> 6;
1032		g |= g >> 2 | g >> 4 | g >> 6;
1033		b |= b >> 2 | b >> 4 | b >> 6;
1034		break;
1035	    case 4: {
1036		unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4);
1037		r = (c & 0x04) ? 0xff : 0;
1038		g = (c & 0x02) ? 0xff : 0;
1039		b = (c & 0x01) ? 0xff : 0;
1040		break;
1041		}
1042	    case 1:
1043		r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0;
1044		break;
1045	}
1046    }
1047    return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b;
1048}
1049
1050/*
1051 *----------------------------------------------------------------------
1052 *
1053 * ImagePutPixel --
1054 *
1055 *	Set a single pixel in an image.
1056 *
1057 * Results:
1058 *	None.
1059 *
1060 * Side effects:
1061 *	None.
1062 *
1063 *----------------------------------------------------------------------
1064 */
1065
1066static int
1067ImagePutPixel(
1068    XImage *image,
1069    int x,
1070    int y,
1071    unsigned long pixel)
1072{
1073    if (image && image->data) {
1074	unsigned char r = ((pixel & image->red_mask)   >> 16) & 0xff;
1075	unsigned char g = ((pixel & image->green_mask) >>  8) & 0xff;
1076	unsigned char b = ((pixel & image->blue_mask)       ) & 0xff;
1077	unsigned char *dstPtr = ((unsigned char*) image->data)
1078		+ (y * image->bytes_per_line)
1079		+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
1080
1081	switch (image->bits_per_pixel) {
1082	    case 32:
1083		*((unsigned int*) dstPtr) = (0xff << 24) | (r << 16) |
1084			(g << 8) | b;
1085		/*if (image->byte_order == LSBFirst) {
1086		    dstPtr[3] = 0xff; dstPtr[2] = r; dstPtr[1] = g; dstPtr[0] = b;
1087		} else {
1088		    dstPtr[0] = 0xff; dstPtr[1] = r; dstPtr[2] = g; dstPtr[3] = b;
1089		}*/
1090		break;
1091	    case 16:
1092		*((unsigned short*) dstPtr) = ((r & 0xf8) << 7) |
1093			((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1094		break;
1095	    case 8:
1096		*dstPtr = ((r & 0xc0) >> 2) | ((g & 0xc0) >> 4) |
1097			((b & 0xc0) >> 6);
1098		break;
1099	    case 4: {
1100		unsigned char c = ((r & 0x80) >> 5) | ((g & 0x80) >> 6) |
1101			((b & 0x80) >> 7);
1102		*dstPtr = (x % 2) ? ((*dstPtr & 0xf0) | (c & 0x0f)) :
1103			((*dstPtr & 0x0f) | ((c << 4) & 0xf0));
1104		break;
1105		}
1106	    case 1:
1107		*dstPtr = ((r|g|b) & 0x80) ? (*dstPtr | (0x80 >> (x % 8))) :
1108			(*dstPtr & ~(0x80 >> (x % 8)));
1109		break;
1110	}
1111    }
1112    return 0;
1113}
1114
1115/*
1116 *----------------------------------------------------------------------
1117 *
1118 * XChangeWindowAttributes, XSetWindowBackground,
1119 * XSetWindowBackgroundPixmap, XSetWindowBorder, XSetWindowBorderPixmap,
1120 * XSetWindowBorderWidth, XSetWindowColormap
1121 *
1122 *	These functions are all no-ops. They all have equivalent Tk calls that
1123 *	should always be used instead.
1124 *
1125 * Results:
1126 *	None.
1127 *
1128 * Side effects:
1129 *	None.
1130 *
1131 *----------------------------------------------------------------------
1132 */
1133
1134void
1135XChangeWindowAttributes(
1136    Display *display,
1137    Window w,
1138    unsigned long value_mask,
1139    XSetWindowAttributes *attributes)
1140{
1141}
1142
1143void
1144XSetWindowBackground(
1145    Display *display,
1146    Window window,
1147    unsigned long value)
1148{
1149}
1150
1151void
1152XSetWindowBackgroundPixmap(
1153    Display *display,
1154    Window w,
1155    Pixmap background_pixmap)
1156{
1157}
1158
1159void
1160XSetWindowBorder(
1161    Display *display,
1162    Window w,
1163    unsigned long border_pixel)
1164{
1165}
1166
1167void
1168XSetWindowBorderPixmap(
1169    Display *display,
1170    Window w,
1171    Pixmap border_pixmap)
1172{
1173}
1174
1175void
1176XSetWindowBorderWidth(
1177    Display *display,
1178    Window w,
1179    unsigned int width)
1180{
1181}
1182
1183void
1184XSetWindowColormap(
1185    Display *display,
1186    Window w,
1187    Colormap colormap)
1188{
1189    Debugger();
1190}
1191
1192Status
1193XStringListToTextProperty(
1194    char **list,
1195    int count,
1196    XTextProperty *text_prop_return)
1197{
1198    Debugger();
1199    return (Status) 0;
1200}
1201
1202void
1203XSetWMClientMachine(
1204    Display *display,
1205    Window w,
1206    XTextProperty *text_prop)
1207{
1208    Debugger();
1209}
1210
1211XIC
1212XCreateIC(void)
1213{
1214    Debugger();
1215    return (XIC) 0;
1216}
1217
1218/*
1219 *----------------------------------------------------------------------
1220 *
1221 * TkGetDefaultScreenName --
1222 *
1223 *	Returns the name of the screen that Tk should use during
1224 *	initialization.
1225 *
1226 * Results:
1227 *	Returns a statically allocated string.
1228 *
1229 * Side effects:
1230 *	None.
1231 *
1232 *----------------------------------------------------------------------
1233 */
1234
1235const char *
1236TkGetDefaultScreenName(
1237    Tcl_Interp *interp,		/* Not used. */
1238    const char *screenName)		/* If NULL, use default string. */
1239{
1240#if 0
1241    if ((screenName == NULL) || (screenName[0] == '\0')) {
1242	screenName = macScreenName;
1243    }
1244    return screenName;
1245#endif
1246    return macScreenName;
1247}
1248
1249/*
1250 *----------------------------------------------------------------------
1251 *
1252 * Tk_GetUserInactiveTime --
1253 *
1254 *	Return the number of milliseconds the user was inactive.
1255 *
1256 * Results:
1257 *	The number of milliseconds the user has been inactive, or -1 if
1258 *	querying the inactive time is not supported.
1259 *
1260 * Side effects:
1261 *	None.
1262 *----------------------------------------------------------------------
1263 */
1264
1265long
1266Tk_GetUserInactiveTime(
1267    Display *dpy)
1268{
1269    io_registry_entry_t regEntry;
1270    CFMutableDictionaryRef props = NULL;
1271    CFTypeRef timeObj;
1272    long ret = -1l;
1273    uint64_t time;
1274    IOReturn result;
1275
1276    regEntry = IOServiceGetMatchingService(kIOMasterPortDefault,
1277	    IOServiceMatching("IOHIDSystem"));
1278
1279    if (regEntry == 0) {
1280	return -1l;
1281    }
1282
1283    result = IORegistryEntryCreateCFProperties(regEntry, &props,
1284	    kCFAllocatorDefault, 0);
1285    IOObjectRelease(regEntry);
1286
1287    if (result != KERN_SUCCESS || props == NULL) {
1288	return -1l;
1289    }
1290
1291    timeObj = CFDictionaryGetValue(props, CFSTR("HIDIdleTime"));
1292
1293    if (timeObj) {
1294	CFTypeID type = CFGetTypeID(timeObj);
1295
1296	if (type == CFDataGetTypeID()) { /* Jaguar */
1297	    CFDataGetBytes((CFDataRef) timeObj,
1298		    CFRangeMake(0, sizeof(time)), (UInt8 *) &time);
1299	    /* Convert nanoseconds to milliseconds. */
1300	    /* ret /= kMillisecondScale; */
1301	    ret = (long) (time/kMillisecondScale);
1302	} else if (type == CFNumberGetTypeID()) { /* Panther+ */
1303	    CFNumberGetValue((CFNumberRef)timeObj,
1304		    kCFNumberSInt64Type, &time);
1305	    /* Convert nanoseconds to milliseconds. */
1306	    /* ret /= kMillisecondScale; */
1307	    ret = (long) (time/kMillisecondScale);
1308	} else {
1309	    ret = -1l;
1310	}
1311    }
1312    /* Cleanup */
1313    CFRelease(props);
1314
1315    return ret;
1316}
1317
1318/*
1319 *----------------------------------------------------------------------
1320 *
1321 * Tk_ResetUserInactiveTime --
1322 *
1323 *	Reset the user inactivity timer
1324 *
1325 * Results:
1326 *	none
1327 *
1328 * Side effects:
1329 *	The user inactivity timer of the underlaying windowing system is reset
1330 *	to zero.
1331 *
1332 *----------------------------------------------------------------------
1333 */
1334
1335void
1336Tk_ResetUserInactiveTime(
1337    Display *dpy)
1338{
1339    IOGPoint loc;
1340    kern_return_t kr;
1341    NXEvent nullEvent = {NX_NULLEVENT, {0, 0}, 0, -1, 0};
1342    enum { kNULLEventPostThrottle = 10 };
1343    static io_connect_t io_connection = MACH_PORT_NULL;
1344
1345    if (io_connection == MACH_PORT_NULL) {
1346	io_service_t service = IOServiceGetMatchingService(
1347		kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass));
1348
1349	if (service == MACH_PORT_NULL) {
1350	    return;
1351	}
1352	kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType,
1353		&io_connection);
1354	IOObjectRelease(service);
1355	if (kr != KERN_SUCCESS) {
1356	    return;
1357	}
1358    }
1359    kr = IOHIDPostEvent(io_connection, NX_NULLEVENT, loc, &nullEvent.data,
1360	    FALSE, 0, FALSE);
1361}
1362
1363/*
1364 * Local Variables:
1365 * mode: c
1366 * c-basic-offset: 4
1367 * fill-column: 79
1368 * coding: utf-8
1369 * End:
1370 */
1371