X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=OSX%2FXScreenSaverView.m;h=7173d86d21700531e430bf370448cf25cf8ee017;hb=50be9bb40dc60130c99ffa568e6677779904ff70;hp=2baf2c69f9e3575cc026671e2d44f2b5e8e5147d;hpb=de460e831dc8578acfa8b72251ab9346c99c1f96;p=xscreensaver diff --git a/OSX/XScreenSaverView.m b/OSX/XScreenSaverView.m index 2baf2c69..7173d86d 100644 --- a/OSX/XScreenSaverView.m +++ b/OSX/XScreenSaverView.m @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 2006, 2007 Jamie Zawinski +/* xscreensaver, Copyright (c) 2006-2010 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -21,6 +21,17 @@ #import "xlockmoreI.h" #import "jwxyz-timers.h" +/* Garbage collection only exists if we are being compiled against the + 10.6 SDK or newer, not if we are building against the 10.4 SDK. + */ +#ifndef MAC_OS_X_VERSION_10_6 +# define MAC_OS_X_VERSION_10_6 1060 /* undefined in 10.4 SDK, grr */ +#endif +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 /* 10.6 SDK */ +# import +# define DO_GC_HACKERY +#endif + extern struct xscreensaver_function_table *xscreensaver_function_table; /* Global variables used by the screen savers @@ -53,6 +64,7 @@ int mono_p = 0; void *addr = CFBundleGetDataPointerForName (cfb, (CFStringRef) table_name); NSAssert2 (addr, @"no symbol \"%@\" in bundle %@", table_name, path); + CFRelease (cfb); // NSLog (@"%@ = 0x%08X", table_name, (unsigned long) addr); return (struct xscreensaver_function_table *) addr; @@ -81,7 +93,8 @@ int mono_p = 0; perror ("putenv"); abort(); } - free (npath); + + /* Don't free (npath) -- MacOS's putenv() does not copy it. */ } @@ -101,7 +114,7 @@ int mono_p = 0; perror ("putenv"); abort(); } - free (env); + /* Don't free (env) -- MacOS's putenv() does not copy it. */ } @@ -126,9 +139,13 @@ add_default_options (const XrmOptionDescRec *opts, { "-choose-random-images", ".chooseRandomImages",XrmoptionNoArg, "True" }, { "-no-choose-random-images",".chooseRandomImages",XrmoptionNoArg, "False"}, { "-image-directory", ".imageDirectory", XrmoptionSepArg, 0 }, + { "-fps", ".doFPS", XrmoptionNoArg, "True" }, + { "-no-fps", ".doFPS", XrmoptionNoArg, "False"}, { 0, 0, 0, 0 } }; static const char *default_defaults [] = { + ".doFPS: False", + ".doubleBuffer: True", // for most OpenGL hacks ".textMode: date", // ".textLiteral: ", // ".textFile: ", @@ -262,6 +279,13 @@ add_default_options (const XrmOptionDescRec *opts, [self lockFocus]; // in case something tries to draw from here [self prepareContext]; + + /* I considered just not even calling the free callback at all... + But webcollage-cocoa needs it, to kill the inferior webcollage + processes (since the screen saver framework never generates a + SIGPIPE for them...) Instead, I turned off the free call in + xlockmore.c, which is where all of the bogus calls are anyway. + */ xsft->free_cb (xdpy, xwindow, xdata); [self unlockFocus]; @@ -286,6 +310,15 @@ add_default_options (const XrmOptionDescRec *opts, { } + +static void +screenhack_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure) +{ + fps_compute (fpst, 0); + fps_draw (fpst); +} + + - (void) animateOneFrame { if (!initted_p) { @@ -333,6 +366,11 @@ add_default_options (const XrmOptionDescRec *opts, (void *(*) (Display *, Window, void *)) xsft->init_cb; xdata = init_cb (xdpy, xwindow, xsft->setup_arg); + + if (get_boolean_resource (xdpy, "doFPS", "DoFPS")) { + fpst = fps_init (xdpy, xwindow); + if (! xsft->fps_cb) xsft->fps_cb = screenhack_do_fps; + } } /* I don't understand why we have to do this *every frame*, but we do, @@ -341,6 +379,18 @@ add_default_options (const XrmOptionDescRec *opts, if (![self isPreview]) [NSCursor setHiddenUntilMouseMoves:YES]; + + if (fpst) + { + /* This is just a guess, but the -fps code wants to know how long + we were sleeping between frames. + */ + unsigned long usecs = 1000000 * [self animationTimeInterval]; + usecs -= 200; // caller apparently sleeps for slightly less sometimes... + fps_slept (fpst, usecs); + } + + /* It turns out that [ScreenSaverView setAnimationTimeInterval] does nothing. This is bad, because some of the screen hacks want to delay for long periods (like 5 seconds or a minute!) between frames, and running them @@ -386,12 +436,44 @@ add_default_options (const XrmOptionDescRec *opts, // NSDisableScreenUpdates(); unsigned long delay = xsft->draw_cb (xdpy, xwindow, xdata); + if (fpst) xsft->fps_cb (xdpy, xwindow, fpst, xdata); XSync (xdpy, 0); NSEnableScreenUpdates(); gettimeofday (&tv, 0); now = tv.tv_sec + (tv.tv_usec / 1000000.0); next_frame_time = now + (delay / 1000000.0); + + +# ifdef DO_GC_HACKERY + /* Current theory is that the 10.6 garbage collector sucks in the + following way: + + It only does a collection when a threshold of outstanding + collectable allocations has been surpassed. However, CoreGraphics + creates lots of small collectable allocations that contain pointers + to very large non-collectable allocations: a small CG object that's + collectable referencing large malloc'd allocations (non-collectable) + containing bitmap data. So the large allocation doesn't get freed + until GC collects the small allocation, which triggers its finalizer + to run which frees the large allocation. So GC is deciding that it + doesn't really need to run, even though the process has gotten + enormous. GC eventually runs once pageouts have happened, but by + then it's too late, and the machine's resident set has been + sodomized. + + So, we force an exhaustive garbage collection in this process + approximately every 5 seconds whether the system thinks it needs + one or not. + */ + { + static int tick = 0; + if (++tick > 5*30) { + tick = 0; + objc_collect (OBJC_EXHAUSTIVE_COLLECTION); + } + } +# endif // DO_GC_HACKERY } @@ -517,7 +599,7 @@ add_default_options (const XrmOptionDescRec *opts, case KeyRelease: { NSString *nss = [e characters]; - const char *s = [nss cStringUsingEncoding:NSUTF8StringEncoding]; + const char *s = [nss cStringUsingEncoding:NSISOLatin1StringEncoding]; xe.xkey.keycode = (s && *s ? *s : 0); xe.xkey.state = state; break;