summaryrefslogtreecommitdiff
path: root/numlib/ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'numlib/ui.c')
-rw-r--r--numlib/ui.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/numlib/ui.c b/numlib/ui.c
new file mode 100644
index 0000000..fefdcc2
--- /dev/null
+++ b/numlib/ui.c
@@ -0,0 +1,238 @@
+
+
+#define __UI_C__
+
+/*
+ * Do OS specific setup for using UI windows.
+ *
+ * Copyright 2014 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ *
+ * Typically we need to set things up and then call the
+ * "normal" main, called "uimain" in ArgyllCMS utils.
+ */
+
+#ifdef UNIX
+
+#if __APPLE__
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* OS X */
+
+/*
+
+ OS X is dumb in relying on an event loop that
+ _has_ to be in the main thread to operate.
+ Since we can invoke UI operations from any thread,
+ the way we work around this is to intercept the
+ main thread, spawn a secondary thread to run the
+ application main(), and then do nothing but
+ service the events in the main thread.
+
+ Note though that Cocoa has poor thread safety :-
+ ie. NSRunLoop can't be used to access events - use CFRunLoop
+
+ Should bracket all drawing code between the lockFocusIfCanDraw and
+ unlockFocus methods of NSView ? Or is this only a problem if
+ different threads try and draw to the same window ?
+
+ */
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <pthread.h>
+
+# include <Foundation/Foundation.h>
+# include <AppKit/AppKit.h>
+
+/* This is a mechanism to force libui to link */
+int ui_initialized = 0;
+
+static int g_argc;
+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 void *callMain(void *p) {
+ int rv;
+
+ ui_main_thid = pthread_self();
+
+ NSAutoreleasePool *tpool = [NSAutoreleasePool new];
+
+ rv = uimain(g_argc, g_argv);
+
+ [tpool release];
+
+ exit(rv);
+}
+
+/* Dumy method for NSThread to start */
+@interface MainClass : NSObject
++(void)dummyfunc:(id)param;
+@end
+
+@implementation MainClass
++(void)dummyfunc:(id)param{
+}
+
+@end
+
+int main(int argc, char ** argv) {
+
+ 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];
+
+ /* We need to create at least one NSThread to tell Cocoa that we are using */
+ /* threads, and to protect Cococa objects. */
+ [NSThread detachNewThreadSelector:@selector(dummyfunc:) toTarget:[MainClass class] withObject:nil];
+
+ /* Call the real main() in another thread */
+ int rv;
+ pthread_t thid;
+ g_argc = argc;
+ g_argv = argv;
+
+ ui_initialized = 1;
+
+ if ((rv = pthread_create(&thid, NULL, callMain, (void *)NULL)) != 0) {
+ fprintf(stderr,"ui: pthread_create failed with %d\n",rv);
+ return -1;
+ }
+
+ /* Service the run queue */
+ [NSApp run];
+
+ /* Note that we don't actually clean this up on exit - */
+ /* possibly we can't. */
+// [NSApp terminate: nil];
+}
+
+#else /* !APPLE */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* UNIX */
+
+/* This is a mechanism to force libui to link */
+int ui_initialized = 1; /* Nothing needs initializing */
+
+#endif /* !APPLE */
+
+#endif /* UNIX */
+
+#ifdef NT
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* NT */
+
+#ifdef NEVER
+
+/*
+ This code isn't generally usable for console programs, because
+ Microsoft changed the default behaviour of cmd.exe in Vista to
+ not wait for a gui mode .exe to terminate. A non-gui .exe always
+ pops a new console if run from explorer.
+
+ So this approach is still viable for primarily gui programs
+ to output debug to stdout, but a different shell or "cmd.exe /E:OFF"
+ is needed to interact with it via the shell.
+
+ Alternatives are messy - mark the exe as console and
+ have it shut down the popup console in gui mode (looks
+ ugly), or have a stub app.bat that invokes the
+ real .exe, forcing cmd.exe to operate in the mode where
+ it waits for execution to finish.
+*/
+
+/* This is a mechanism to force libui to link */
+int ui_initialized = 0;
+
+/*
+
+ On MSWin we can rely on WinMain to be called instead of
+ main(), so that we can re-attache the stdio so that the
+ resulting exe works the same when involked either from
+ a shell, or directly from explorer.
+
+ */
+
+/* May have to add link flag -Wl,-subsystem,windows */
+/* since MingW is stupid about noticing WinMain or pragma */
+
+#include <windows.h>
+#include <stdio.h>
+
+# pragma comment( linker, "/subsystem:windows" )
+//# pragma comment( linker, "/subsystem:console /ENTRY:WinMainCRTStartup" )
+//# pragma comment( linker, "/subsystem:windows /ENTRY:mainCRTStartup" )
+//# pragma comment( linker, "/subsystem:windows /ENTRY:WinMainCRTStartup" )
+
+APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow
+) {
+ { /* Only works on >= XP though */
+ BOOL (WINAPI *AttachConsole)(DWORD dwProcessId);
+
+ *(FARPROC *)&AttachConsole =
+ GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole");
+
+ if (AttachConsole != NULL && AttachConsole(((DWORD)-1)))
+ {
+ if (_fileno(stdout) < 0)
+ freopen("CONOUT$","wb",stdout);
+ if (_fileno(stderr) < 0)
+ freopen("CONOUT$","wb",stderr);
+ if (_fileno(stdin) < 0)
+ freopen("CONIN$","rb",stdin);
+#ifdef __cplusplus
+ // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
+ std::ios::sync_with_stdio();
+#endif
+ }
+ }
+
+ ui_initialized = 1;
+
+ return uimain(__argc, __argv);
+}
+
+#else /* !NEVER */
+
+/* This is a mechanism to force libui to link */
+int ui_initialized = 1; /* Nothing needs initializing */
+
+#endif /* !NEVER */
+
+#endif /* NT */