def waituntil(conditionfunc, timeout=None):
app = NSApplication.sharedApplication()<EOL>starttime = time.time()<EOL>if timeout is None:<EOL><INDENT>timeout = NSDate.distantFuture().timeIntervalSinceNow()<EOL><DEDENT>if not isinstance(timeout, (int, float)):<EOL><INDENT>raise TypeError("<STR_LIT>" %type(timeout))<EOL><DEDENT>endtime = starttime + timeout<EOL>while True:<EOL><INDENT>currtime = time.time()<EOL>if currtime >= endtime:<EOL><INDENT>return False<EOL><DEDENT>e = app.nextEventMatchingMask_untilDate_inMode_dequeue_(NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_(min(endtime - currtime, WAIT_MAX_TIMEOUT)), NSDefaultRunLoopMode, True)<EOL>if e is not None:<EOL><INDENT>if (e.type() == NSApplicationDefined and e.subtype() == LIGHTBLUE_NOTIFY_ID):<EOL><INDENT>if conditionfunc():<EOL><INDENT>return True<EOL><DEDENT><DEDENT>else:<EOL><INDENT>app.postEvent_atStart_(e, True)<EOL><DEDENT><DEDENT><DEDENT>
Waits until conditionfunc() returns true, or <timeout> seconds have passed.
(If timeout=None, this waits indefinitely until conditionfunc() returns
true.) Returns false if the process timed out, otherwise returns true.

Note!! You must call interruptwait() when you know that conditionfunc()
should be checked (e.g. if you are waiting for data and you know some data
has arrived) so that this can check conditionfunc(); otherwise it will just
continue to wait. (This allows the function to wait for an event that is
sent by interruptwait() instead of polling conditionfunc().)

This allows the caller to wait while the main event loop processes its
events. This must be done for certain situations, e.g. to receive socket
data or to accept client connections on a server socket, since IOBluetooth
requires the presence of an event loop to run these operations.

This function doesn't need to be called if there is something else that is
already processing the main event loop, e.g. if called from within a Cocoa
application.