summaryrefslogtreecommitdiff
path: root/numlib
diff options
context:
space:
mode:
Diffstat (limited to 'numlib')
-rw-r--r--numlib/numsup.c304
-rw-r--r--numlib/numsup.h85
-rw-r--r--numlib/ui.c205
-rw-r--r--numlib/ui.h13
4 files changed, 542 insertions, 65 deletions
diff --git a/numlib/numsup.c b/numlib/numsup.c
index c08ed99..39011ae 100644
--- a/numlib/numsup.c
+++ b/numlib/numsup.c
@@ -51,6 +51,7 @@ char *exe_path = "\000"; /* Directory executable resides in ('/' dir separator
//char *error_program = "Unknown"; /* Name to report as responsible for an error */
static int g_log_init = 0; /* Initialised ? */
+static int g_deb_init = 0; /* Debug output Initialised ? */
extern a1log default_log;
extern a1log *g_log;
@@ -247,9 +248,11 @@ typedef struct {
BYTE wReserved;
} osversioninfoexw;
-#define VER_NT_DOMAIN_CONTROLLER 0x0000002
-#define VER_NT_SERVER 0x0000003
-#define VER_NT_WORKSTATION 0x0000001
+#ifndef VER_NT_DOMAIN_CONTROLLER
+# define VER_NT_DOMAIN_CONTROLLER 0x0000002
+# define VER_NT_SERVER 0x0000003
+# define VER_NT_WORKSTATION 0x0000001
+#endif
static char *get_sys_info() {
static char sysinfo[100] = { "Unknown" };
@@ -328,14 +331,17 @@ static char *get_sys_info() {
}
-# define A1LOG_LOCK(log) \
+# define A1LOG_LOCK(log, deb) \
if (g_log_init == 0) { \
InitializeCriticalSection(&log->lock); \
EnterCriticalSection(&log->lock); \
g_log_init = 1; \
- va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
} else { \
EnterCriticalSection(&log->lock); \
+ } \
+ if (deb && !g_deb_init) { \
+ va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
+ g_deb_init = 1; \
}
# define A1LOG_UNLOCK(log) LeaveCriticalSection(&log->lock)
#endif
@@ -350,14 +356,17 @@ static char *get_sys_info() {
return sysinfo;
}
-# define A1LOG_LOCK(log) \
+# define A1LOG_LOCK(log, deb) \
if (g_log_init == 0) { \
pthread_mutex_init(&log->lock, NULL); \
pthread_mutex_lock(&log->lock); \
g_log_init = 1; \
- va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
} else { \
pthread_mutex_lock(&log->lock); \
+ } \
+ if (deb && !g_deb_init) { \
+ va_loge(log, "Argyll 'V%s' Build '%s' System '%s'\n",ARGYLL_VERSION_STR,ARGYLL_BUILD_STR, get_sys_info()); \
+ g_deb_init = 1; \
}
# define A1LOG_UNLOCK(log) pthread_mutex_unlock(&log->lock)
#endif
@@ -485,7 +494,7 @@ void a1logv(a1log *log, int level, char *fmt, ...) {
if (log->verb >= level) {
va_list args;
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->logv(log->cntx, log, fmt, args);
va_end(args);
@@ -500,7 +509,7 @@ void a1logd(a1log *log, int level, char *fmt, ...) {
if (log->debug >= level) {
va_list args;
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 1);
va_start(args, fmt);
log->loge(log->cntx, log, fmt, args);
va_end(args);
@@ -515,20 +524,20 @@ void a1logw(a1log *log, char *fmt, ...) {
va_list args;
/* log to all the outputs, but only log once */
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->loge(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
if (log->logd != log->loge) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 1);
va_start(args, fmt);
log->logd(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
}
if (log->logv != log->loge && log->logv != log->logd) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->logv(log->cntx, log, fmt, args);
va_end(args);
@@ -545,7 +554,7 @@ void a1loge(a1log *log, int ecode, char *fmt, ...) {
va_list args;
if (log->errc == 0) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
log->errc = ecode;
va_start(args, fmt);
vsnprintf(log->errm, A1_LOG_BUFSIZE, fmt, args);
@@ -554,20 +563,20 @@ void a1loge(a1log *log, int ecode, char *fmt, ...) {
}
va_start(args, fmt);
/* log to all the outputs, but only log once */
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->loge(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
if (log->logd != log->loge) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 1);
va_start(args, fmt);
log->logd(log->cntx, log, fmt, args);
va_end(args);
A1LOG_UNLOCK(log);
}
if (log->logv != log->loge && log->logv != log->logd) {
- A1LOG_LOCK(log);
+ A1LOG_LOCK(log, 0);
va_start(args, fmt);
log->logv(log->cntx, log, fmt, args);
va_end(args);
@@ -640,7 +649,7 @@ verbose(int level, char *fmt, ...) {
if (g_log->verb >= level) {
va_list args;
- A1LOG_LOCK(g_log);
+ A1LOG_LOCK(g_log, 0);
g_logv("%s: ",g_log->tag);
va_start(args, fmt);
g_log->logv(g_log->cntx, g_log, fmt, args);
@@ -654,7 +663,7 @@ void
warning(char *fmt, ...) {
va_list args;
- A1LOG_LOCK(g_log);
+ A1LOG_LOCK(g_log, 0);
g_loge("%s: Warning - ",g_log->tag);
va_start(args, fmt);
g_log->loge(g_log->cntx, g_log, fmt, args);
@@ -667,7 +676,7 @@ ATTRIBUTE_NORETURN void
error(char *fmt, ...) {
va_list args;
- A1LOG_LOCK(g_log);
+ A1LOG_LOCK(g_log, 0);
g_loge("%s: Error - ",g_log->tag);
va_start(args, fmt);
g_log->loge(g_log->cntx, g_log, fmt, args);
@@ -789,7 +798,7 @@ void osx_userinitiated_start() {
Class pic; /* Process info class */
SEL pis; /* Process info selector */
SEL bawo; /* Begin Activity With Options selector */
- id pi; /* Process info */
+ id pi; /* Process info */
id str;
if (osx_userinitiated_cnt++ != 0)
@@ -797,7 +806,8 @@ void osx_userinitiated_start() {
a1logd(g_log, 7, "OS X - User Initiated Activity start\n");
- /* We have to be conservative to avoid triggering an exception when run on older OS X */
+ /* We have to be conservative to avoid triggering an exception when run on older OS X, */
+ /* since beginActivityWithOptions is only available in >= 10.9 */
if ((pic = (Class)objc_getClass("NSProcessInfo")) == nil) {
return;
}
@@ -2200,3 +2210,255 @@ void write_INR64_le(ORD8 *p, INR64 d) {
p[7] = (ORD8)(d >> 56);
}
+/*******************************/
+/* System independent timing */
+
+#ifdef NT
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec) {
+ Sleep(msec);
+}
+
+/* Return the current time in msec since */
+/* the first invokation of msec_time() */
+/* (Is this based on timeGetTime() ? ) */
+unsigned int msec_time() {
+ unsigned int rv;
+ static unsigned int startup = 0;
+
+ rv = GetTickCount();
+ if (startup == 0)
+ startup = rv;
+
+ return rv - startup;
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+/* Return -1.0 if not available */
+double usec_time() {
+ double rv;
+ LARGE_INTEGER val;
+ static double scale = 0.0;
+ static LARGE_INTEGER startup;
+
+ if (scale == 0.0) {
+ if (QueryPerformanceFrequency(&val) == 0)
+ return -1.0;
+ scale = 1000000.0/val.QuadPart;
+ QueryPerformanceCounter(&val);
+ startup.QuadPart = val.QuadPart;
+
+ } else {
+ QueryPerformanceCounter(&val);
+ }
+ val.QuadPart -= startup.QuadPart;
+
+ rv = val.QuadPart * scale;
+
+ return rv;
+}
+
+#endif /* NT */
+
+#if defined(UNIX)
+
+/* Sleep for the given number of msec */
+/* (Note that OS X 10.9+ App Nap can wreck this, unless */
+/* it is turned off.) */
+void msec_sleep(unsigned int msec) {
+#ifdef NEVER
+ if (msec > 1000) {
+ unsigned int secs;
+ secs = msec / 1000;
+ msec = msec % 1000;
+ sleep(secs);
+ }
+ usleep(msec * 1000);
+#else
+ struct timespec ts;
+
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+ nanosleep(&ts, NULL);
+#endif
+}
+
+
+#if defined(__APPLE__) && !defined(CLOCK_MONOTONIC)
+
+#include <mach/mach_time.h>
+
+unsigned int msec_time() {
+ mach_timebase_info_data_t timebase;
+ static uint64_t startup = 0;
+ uint64_t time;
+ double msec;
+
+ time = mach_absolute_time();
+ if (startup == 0)
+ startup = time;
+
+ mach_timebase_info(&timebase);
+ time -= startup;
+ msec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e6);
+
+ return (unsigned int)floor(msec + 0.5);
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+double usec_time() {
+ mach_timebase_info_data_t timebase;
+ static uint64_t startup = 0;
+ uint64_t time;
+ double usec;
+
+ time = mach_absolute_time();
+ if (startup == 0)
+ startup = time;
+
+ mach_timebase_info(&timebase);
+ time -= startup;
+ usec = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e3);
+
+ return usec;
+}
+
+#else
+
+/* Return the current time in msec */
+/* since the first invokation of msec_time() */
+unsigned int msec_time() {
+ unsigned int rv;
+ static struct timespec startup = { 0, 0 };
+ struct timespec cv;
+
+ clock_gettime(CLOCK_MONOTONIC, &cv);
+
+ /* Set time to 0 on first invocation */
+ if (startup.tv_sec == 0 && startup.tv_nsec == 0)
+ startup = cv;
+
+ /* Subtract, taking care of carry */
+ cv.tv_sec -= startup.tv_sec;
+ if (startup.tv_nsec > cv.tv_nsec) {
+ cv.tv_sec--;
+ cv.tv_nsec += 1000000000;
+ }
+ cv.tv_nsec -= startup.tv_nsec;
+
+ /* Convert nsec to msec */
+ rv = cv.tv_sec * 1000 + cv.tv_nsec / 1000000;
+
+ return rv;
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+double usec_time() {
+ double rv;
+ static struct timespec startup = { 0, 0 };
+ struct timespec cv;
+
+ clock_gettime(CLOCK_MONOTONIC, &cv);
+
+ /* Set time to 0 on first invocation */
+ if (startup.tv_sec == 0 && startup.tv_nsec == 0)
+ startup = cv;
+
+ /* Subtract, taking care of carry */
+ cv.tv_sec -= startup.tv_sec;
+ if (startup.tv_nsec > cv.tv_nsec) {
+ cv.tv_sec--;
+ cv.tv_nsec += 1000000000;
+ }
+ cv.tv_nsec -= startup.tv_nsec;
+
+ /* Convert to usec */
+ rv = cv.tv_sec * 1000000.0 + cv.tv_nsec/1000;
+
+ return rv;
+}
+
+#endif
+
+#endif /* UNIX */
+
+/*******************************/
+/* Debug convenience functions */
+/*******************************/
+
+#define DEB_MAX_CHAN 15
+
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPiv(int di, int *p) {
+ static char buf[5][DEB_MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > DEB_MAX_CHAN)
+ di = DEB_MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%d", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPdv(int di, double *p) {
+ static char buf[5][DEB_MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > DEB_MAX_CHAN)
+ di = DEB_MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPfv(int di, float *p) {
+ static char buf[5][DEB_MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > DEB_MAX_CHAN)
+ di = DEB_MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%.8f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+#undef DEB_MAX_CHAN
diff --git a/numlib/numsup.h b/numlib/numsup.h
index 366763d..9d55daf 100644
--- a/numlib/numsup.h
+++ b/numlib/numsup.h
@@ -43,9 +43,9 @@
/* so long shouldn't really be used in any code.... */
/* (duplicated in icc.h) */
-/* Use __LP64__ as cross platform 64 bit pointer #define */
-#if !defined(__LP64__) && defined(_WIN64)
-# define __LP64__ 1
+/* Use __P64__ as cross platform 64 bit pointer #define */
+#if defined(__LP64__) || defined(__ILP64__) || defined(__LLP64__) || defined(_WIN64)
+# define __P64__ 1
#endif
#ifndef ORD32
@@ -59,17 +59,25 @@
#define INR8 int8_t /* 8 bit signed */
#define INR16 int16_t /* 16 bit signed */
#define INR32 int32_t /* 32 bit signed */
-#define INR64 int64_t /* 64 bit signed - not used in icclib */
+#define INR64 int64_t /* 64 bit signed */
#define ORD8 uint8_t /* 8 bit unsigned */
#define ORD16 uint16_t /* 16 bit unsigned */
#define ORD32 uint32_t /* 32 bit unsigned */
-#define ORD64 uint64_t /* 64 bit unsigned - not used in icclib */
+#define ORD64 uint64_t /* 64 bit unsigned */
#define PNTR intptr_t
#define PF64PREC "ll" /* printf format precision specifier */
#define CF64PREC "LL" /* Constant precision specifier */
+#ifndef ATTRIBUTE_NORETURN
+# ifdef _MSC_VER
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+# else
+# define ATTRIBUTE_NORETURN __attribute__((noreturn))
+# endif
+#endif
+
#else /* !__STDC_VERSION__ */
#ifdef _MSC_VER
@@ -77,17 +85,21 @@
#define INR8 __int8 /* 8 bit signed */
#define INR16 __int16 /* 16 bit signed */
#define INR32 __int32 /* 32 bit signed */
-#define INR64 __int64 /* 64 bit signed - not used in icclib */
+#define INR64 __int64 /* 64 bit signed */
#define ORD8 unsigned __int8 /* 8 bit unsigned */
#define ORD16 unsigned __int16 /* 16 bit unsigned */
#define ORD32 unsigned __int32 /* 32 bit unsigned */
-#define ORD64 unsigned __int64 /* 64 bit unsigned - not used in icclib */
+#define ORD64 unsigned __int64 /* 64 bit unsigned */
#define PNTR UINT_PTR
#define PF64PREC "I64" /* printf format precision specifier */
#define CF64PREC "LL" /* Constant precision specifier */
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+#endif
+
#else /* !_MSC_VER */
/* The following works on a lot of modern systems, including */
@@ -101,29 +113,28 @@
#define ORD32 unsigned int /* 32 bit unsigned */
#ifdef __GNUC__
-# define INR64 long long /* 64 bit signed - not used in icclib */
-# define ORD64 unsigned long long /* 64 bit unsigned - not used in icclib */
-# define PF64PREC "ll" /* printf format precision specifier */
-# define CF64PREC "LL" /* Constant precision specifier */
+# ifdef __LP64__ /* long long could be 128 bit ? */
+# define INR64 long /* 64 bit signed */
+# define ORD64 unsigned long /* 64 bit unsigned */
+# define PF64PREC "l" /* printf format precision specifier */
+# define CF64PREC "L" /* Constant precision specifier */
+# else
+# define INR64 long long /* 64 bit signed */
+# define ORD64 unsigned long long /* 64 bit unsigned */
+# define PF64PREC "ll" /* printf format precision specifier */
+# define CF64PREC "LL" /* Constant precision specifier */
+# endif /* !__LP64__ */
#endif /* __GNUC__ */
#define PNTR unsigned long
-#endif /* !_MSC_VER */
-#endif /* !__STDC_VERSION__ */
-#endif /* !ORD32 */
-
-#ifdef _MSC_VER
-#ifndef ATTRIBUTE_NORETURN
-# define ATTRIBUTE_NORETURN __declspec(noreturn)
-#endif
-#endif
-
-#ifdef __GNUC__
#ifndef ATTRIBUTE_NORETURN
# define ATTRIBUTE_NORETURN __attribute__((noreturn))
#endif
-#endif
+
+#endif /* !_MSC_VER */
+#endif /* !__STDC_VERSION__ */
+#endif /* !ORD32 */
/* =========================================================== */
/* System compatibility #defines */
@@ -517,6 +528,34 @@ void write_INR64_be(ORD8 *p, INR64 d);
void write_INR64_le(ORD8 *p, INR64 d);
/*******************************************/
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec);
+
+/* Return the current time in msec since */
+/* the first invokation of msec_time() */
+unsigned int msec_time();
+
+/* Return the current time in usec */
+/* (The first invokation of usec_time() returns zero) */
+double usec_time();
+
+/*******************************************/
+/* Debug convenience functions (duplicated in icc) */
+
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPiv(int di, int *p);
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPdv(int di, double *p);
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *debPfv(int di, float *p);
+
+/*******************************************/
/* Numerical diagnostics */
#ifndef isNan
diff --git a/numlib/ui.c b/numlib/ui.c
index a3cdbe8..390a332 100644
--- a/numlib/ui.c
+++ b/numlib/ui.c
@@ -32,6 +32,8 @@
main thread, spawn a secondary thread to run the
application main(), and then do nothing but
service the events in the main thread.
+ We can also pass functions back to be run in the main thread,
+ and wait for events in the main thread to be processed.
Note though that Cocoa has poor thread safety :-
ie. NSRunLoop can't be used to access events - use CFRunLoop
@@ -45,6 +47,7 @@
# include <stdio.h>
# include <stdlib.h>
# include <pthread.h>
+# include "ui.h"
# include <Foundation/Foundation.h>
# include <AppKit/AppKit.h>
@@ -66,6 +69,10 @@ static char **g_argv;
pthread_t ui_thid = 0; /* Thread ID of main thread running io run loop */
pthread_t ui_main_thid = 0; /* Thread ID of thread running application main() */
+static pthread_mutex_t ui_lock1, ui_lock2; /* Protect wait code */
+static pthread_cond_t ui_cond1, ui_cond2; /* Signal to waiting thread */
+static int ui_event1 = 0, ui_event2 = 0; /* Sync event was received */
+
extern int uimain(int argc, char *argv[]);
/* Thread that calls the real application main() */
@@ -79,12 +86,21 @@ static void *callMain(void *p) {
/* Turn App Nap off */
osx_userinitiated_start();
+ /* Should we catch and report exceptions ? */
+
rv = uimain(g_argc, g_argv);
+ /* Restore App Nap state */
osx_userinitiated_end();
[tpool release];
+ /* Cleanup, since main thread won't return */
+ pthread_cond_destroy(&ui_cond1);
+ pthread_cond_destroy(&ui_cond2);
+ pthread_mutex_destroy(&ui_lock1);
+ pthread_mutex_destroy(&ui_lock2);
+
exit(rv);
}
@@ -101,37 +117,24 @@ static void *callMain(void *p) {
int main(int argc, char ** argv) {
+ pthread_mutex_init(&ui_lock1, NULL);
+ pthread_mutex_init(&ui_lock2, NULL);
+ pthread_cond_init(&ui_cond1, NULL);
+ pthread_cond_init(&ui_cond2, NULL);
+
ui_thid = pthread_self();
/* Create an NSApp */
static NSAutoreleasePool *pool = nil;
- ProcessSerialNumber psn = { 0, 0 };
-
- /* Transform the process so that the desktop interacts with it properly. */
- /* We don't need resources or a bundle if we do this. */
- if (GetCurrentProcess(&psn) == noErr) {
- OSStatus stat;
- if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
- kProcessTransformToForegroundApplication)) != noErr) {
-// fprintf(stderr,"TransformProcess failed with code %d\n",stat);
- } else {
-// fprintf(stderr,"TransformProcess suceeded\n");
- }
-// if ((stat = SetFrontProcess(&psn)) != noErr) {
-// fprintf(stderr,"SetFrontProcess returned error %d\n",stat);
-// }
- }
pool = [NSAutoreleasePool new];
[NSApplication sharedApplication]; /* Creates NSApp */
- [NSApp finishLaunching];
- /* We seem to need this, because otherwise we don't get focus automatically */
- [NSApp activateIgnoringOtherApps: YES];
+ [NSApp finishLaunching];
/* We need to create at least one NSThread to tell Cocoa that we are using */
- /* threads, and to protect Cococa objects. */
+ /* threads, and to protect Cococa objects. (We don't actually have to start the thread.) */
[NSThread detachNewThreadSelector:@selector(dummyfunc:) toTarget:[MainClass class] withObject:nil];
/* Call the real main() in another thread */
@@ -156,13 +159,163 @@ int main(int argc, char ** argv) {
}
/* Service the run queue */
- [NSApp run];
+ {
+ NSEvent *event;
+ NSDate *to;
+
+ /* Process events, looking for application events. */
+ for (;;) {
+ /* Hmm. Assume to is autorelease */
+ to = [NSDate dateWithTimeIntervalSinceNow:1.0];
+ /* Hmm. Assume event is autorelease */
+ if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:to inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) {
+
+ /* call function message */
+ if ([event type] == NSApplicationDefined
+ && [event subtype] == 1) {
+ void *cntx = (void *)[event data1];
+ void (*function)(void *cntx) = (void (*)(void *)) [event data2];
+
+ function(cntx);
+
+ pthread_mutex_lock(&ui_lock1);
+ ui_event1 = 1;
+ pthread_cond_signal(&ui_cond1);
+ pthread_mutex_unlock(&ui_lock1);
+ [event release];
+
+ /* event flush message */
+ } else if ([event type] == NSApplicationDefined
+ && [event subtype] == 2) {
+ pthread_mutex_lock(&ui_lock2);
+ ui_event2 = 1;
+ pthread_cond_signal(&ui_cond2);
+ pthread_mutex_unlock(&ui_lock2);
+ [event release];
+
+ /* Everything else */
+ } else {
+ [NSApp sendEvent:event];
+ }
+ }
+ }
+ }
/* Note that we don't actually clean this up on exit - */
/* possibly we can't. */
// [NSApp terminate: nil];
}
+/* Call this if we decide we are actually going to display something in the GUI. */
+/* We switch to "interact with the Dock" mode. */
+void ui_UsingGUI() {
+ static int attached = 0;
+ ProcessSerialNumber psn = { 0, 0 };
+
+ if (!attached) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ /* Make the application appear in the Dock, and interact with the desktop properly. */
+ /* (Unbundled applications default to NSApplicationActivationPolicyProhibited) */
+ [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
+
+#else
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+ /* Make the application appear in the Dock, and interact with the desktop properly. */
+ /* We don't need resources or a bundle if we do this. */
+ if (GetCurrentProcess(&psn) == noErr) {
+ OSStatus stat;
+ if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
+ kProcessTransformToForegroundApplication)) != noErr) {
+ fprintf(stderr,"TransformProcess failed with code %d\n",stat);
+
+ /* An older trick uses an undocumented API:
+ CPSEnableForegroundOperation(&processSerialNum, 0, 0, 0, 0);
+ */
+ } else {
+ // fprintf(stderr,"TransformProcess suceeded\n");
+ }
+ }
+# endif /* OS X 10.3 */
+#endif /* !OS X 10.6 */
+
+ /* We seem to need this, because otherwise we don't get focus automatically */
+ [NSApp activateIgnoringOtherApps: YES];
+
+ attached = 1;
+ }
+}
+
+/* Run a function in the main thread and return when it is complete. */
+/* (It's up to the function to record it's result status in its context) */
+void ui_runInMainThreadAndWait(void *cntx, void (*function)(void *cntx)) {
+
+ NSEvent *event;
+ NSPoint point = { 0.0, 0.0 };
+ int rv;
+
+ pthread_mutex_lock(&ui_lock1);
+ ui_event1 = 0;
+
+ event = [NSEvent otherEventWithType:NSApplicationDefined
+ location:point
+ modifierFlags:0
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ subtype:1
+ data1:(long)cntx /* long same size as * */
+ data2:(long)function];
+ [NSApp postEvent:event atStart:NO];
+
+ // unlock and wait for signal
+ for (;;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_wait(&ui_cond1, &ui_lock1)) != 0) {
+ break; // Hmm.
+ }
+ if (ui_event1) /* Got what we were waiting for */
+ break;
+ }
+ pthread_mutex_unlock(&ui_lock1);
+}
+
+
+/* We are about to change the UI */
+void ui_aboutToWait() {
+
+ pthread_mutex_lock(&ui_lock2);
+ ui_event2 = 0;
+}
+
+/* Wait until we are sure our UI change is complete, */
+/* because our event has trickled through. */
+void ui_waitForEvents() {
+ NSEvent *event;
+ NSPoint point = { 0.0, 0.0 };
+ int rv;
+
+ event = [NSEvent otherEventWithType:NSApplicationDefined
+ location:point
+ modifierFlags:0
+ timestamp:0.0
+ windowNumber:0
+ context:nil
+ subtype:2
+ data1:0
+ data2:0];
+ [NSApp postEvent:event atStart:NO];
+
+ // unlock and wait for signal
+ for (;;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_wait(&ui_cond2, &ui_lock2)) != 0) {
+ break; // Hmm.
+ }
+ if (ui_event2) /* Got what we were waiting for */
+ break;
+ }
+ pthread_mutex_unlock(&ui_lock2);
+}
+
#else /* !APPLE */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@@ -171,6 +324,11 @@ int main(int argc, char ** argv) {
/* This is a mechanism to force libui to link */
int ui_initialized = 1; /* Nothing needs initializing */
+/* Call this if we decide we are actually going to display */
+/* something in the GUI */
+void ui_UsingGUI() {
+}
+
#endif /* !APPLE */
#endif /* UNIX */
@@ -262,4 +420,9 @@ int ui_initialized = 1; /* Nothing needs initializing */
#endif /* !NEVER */
+/* Call this if we decide we are actually going to display */
+/* something in the GUI */
+void ui_UsingGUI() {
+}
+
#endif /* NT */
diff --git a/numlib/ui.h b/numlib/ui.h
index e1d7a58..a282c26 100644
--- a/numlib/ui.h
+++ b/numlib/ui.h
@@ -21,12 +21,25 @@
extern int ui_initialized;
static int *pui_initialized = &ui_initialized;
+/* Call this if we decide we are actually going to display */
+/* something in the GUI */
+void ui_UsingGUI();
+
#ifdef UNIX
# ifdef __APPLE__
extern pthread_t ui_thid; /* Thread ID of main thread running io run loop */
extern pthread_t ui_main_thid; /* Thread ID of thread running application main() */
+/* Run a function in the main thread and return when it is complete */
+void ui_runInMainThreadAndWait(void *cntx, void (*function)(void *context));
+
+/* We are about to change the UI */
+void ui_aboutToWait();
+
+/* Wait until we are sure our UI change is complete */
+void ui_waitForEvents();
+
#ifndef __UI_C__
# define main uimain
#endif