summaryrefslogtreecommitdiff
path: root/spectro/webwin.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/webwin.c')
-rw-r--r--spectro/webwin.c455
1 files changed, 455 insertions, 0 deletions
diff --git a/spectro/webwin.c b/spectro/webwin.c
new file mode 100644
index 0000000..d90239a
--- /dev/null
+++ b/spectro/webwin.c
@@ -0,0 +1,455 @@
+
+
+/*
+ * Argyll Color Correction System
+ * Web Display target patch window
+ *
+ * Author: Graeme W. Gill
+ * Date: 3/4/12
+ *
+ * Copyright 2013 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef NT
+# include <winsock2.h>
+#endif
+#ifdef UNIX
+# include <sys/types.h>
+# include <ifaddrs.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# ifdef __FreeBSD__
+# include <sys/socket.h>
+# endif /* __FreeBSD__ */
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+#include "numsup.h"
+#include "cgats.h"
+#include "conv.h"
+#include "dispwin.h"
+#include "conv.h"
+#include "mongoose.h"
+
+#undef DEBUG
+//#define STANDALONE_TEST
+
+#ifdef DEBUG
+#define errout stderr
+# define debug(xx) fprintf(errout, xx )
+# define debug2(xx) fprintf xx
+# define debugr(xx) fprintf(errout, xx )
+# define debugr2(xx) fprintf xx
+# define debugrr(xx) fprintf(errout, xx )
+# define debugrr2(xx) fprintf xx
+# define debugrr2l(lev, xx) fprintf xx
+#else
+#define errout stderr
+# define debug(xx)
+# define debug2(xx)
+# define debugr(xx) if (p->ddebug) fprintf(errout, xx )
+# define debugr2(xx) if (p->ddebug) fprintf xx
+# define debugrr(xx) if (callback_ddebug) fprintf(errout, xx )
+# define debugrr2(xx) if (callback_ddebug) fprintf xx
+# define debugrr2l(lev, xx) if (callback_ddebug >= lev) fprintf xx
+#endif
+
+// A handler for the /ajax/get_messages endpoint.
+// Return a list of messages with ID greater than requested.
+static void ajax_get_messages(struct mg_connection *conn,
+ const struct mg_request_info *request_info) {
+char src_addr[20];
+
+// dispwin *p = (dispwin *)(request_info->user_data);
+ dispwin *p = (dispwin *)mg_get_user_data(conn);
+
+//sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+
+// printf("ajax_messages query_string '%s'\n",request_info->query_string);
+
+ p->ccix++;
+
+ while(p->ncix == p->ccix && p->mg_stop == 0) {
+ msec_sleep(50);
+ }
+
+ mg_printf(conn,
+ "\r\n#%02X%02X%02X",
+ (int)(p->r_rgb[0] * 255.0 + 0.5),
+ (int)(p->r_rgb[1] * 255.0 + 0.5),
+ (int)(p->r_rgb[2] * 255.0 + 0.5));
+}
+
+/* Event handler */
+static void *webwin_ehandler(enum mg_event event,
+ struct mg_connection *conn) {
+// const struct mg_request_info *request_info) {
+ const struct mg_request_info *request_info = mg_get_request_info(conn);
+
+ if (event != MG_NEW_REQUEST) {
+ return NULL;
+ }
+#ifdef DEBUG
+ printf("Got event with uri = '%s'\n",request_info->uri);
+#endif
+ if (strcmp(request_info->uri, "/ajax/messages") == 0) {
+ ajax_get_messages(conn, request_info);
+ } else if (strcmp(request_info->uri, "/webdisp.js") == 0) {
+#ifndef NEVER
+ char *webdisp_js =
+ "\r\n"
+ "if (typeof XMLHttpRequest == \"undefined\") {\r\n"
+ " XMLHttpRequest = function () {\r\n"
+ " try { return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\"); }\r\n"
+ " catch (e) {}\r\n"
+ " try { return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\"); }\r\n"
+ " catch (e) {}\r\n"
+ " try { return new ActiveXObject(\"Microsoft.XMLHTTP\"); }\r\n"
+ " catch (e) {}\r\n"
+ " throw new Error(\"This browser does not support XMLHttpRequest.\");\r\n"
+ " };\r\n"
+ "}\r\n"
+ "\r\n"
+ "var ccolor = \"\";\r\n"
+ "var oXHR;\r\n"
+ "\r\n"
+ "function XHR_response() {\r\n"
+ " if (oXHR.readyState != 4)\r\n"
+ " return;\r\n"
+ "\r\n"
+ " if (oXHR.status != 200) {\r\n"
+ " return;\r\n"
+ " }\r\n"
+ " var rt = oXHR.responseText;\r\n"
+ " if (rt.charAt(0) == '\\r' && rt.charAt(1) == '\\n')\r\n"
+ " rt = rt.slice(2);\r\n"
+ " if (ccolor != rt) {\r\n"
+ " ccolor = rt;\r\n"
+ " document.body.style.background = ccolor;\r\n"
+ " }\r\n"
+ " oXHR.open(\"GET\", \"/ajax/messages?\" + document.body.style.background + \" \" + Math.random(), true);\r\n"
+ " oXHR.onreadystatechange = XHR_response;\r\n"
+ " oXHR.send();\r\n"
+ "}\r\n"
+ "\r\n"
+ "window.onload = function() {\r\n"
+ " ccolor = \"#808080\";\r\n"
+ " document.body.style.background = ccolor;\r\n"
+ "\r\n"
+ " oXHR = new XMLHttpRequest();\r\n"
+ " oXHR.open(\"GET\", \"/ajax/messages?\" + document.body.style.background, true);\r\n"
+ " oXHR.onreadystatechange = XHR_response;\r\n"
+ " oXHR.send();\r\n"
+ "};\r\n";
+ mg_write(conn, webdisp_js, strlen(webdisp_js));
+#else
+ return NULL; /* Read webdisp.js */
+#endif
+ } else {
+ mg_printf(conn, "HTTP/1.1 200 OK\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Content-Type: text/html\r\n\r\n"
+ "<html>\r\n"
+ "<head>\r\n"
+ "<title>ArgyllCMS Web Display</title>\r\n"
+ "<script src=\"webdisp.js\"></script>\r\n"
+ "</head>\r\n"
+ "</html>\r\n"
+ );
+ }
+
+// "<script type=\"text/javascript\"src=\"webdisp.js\"></script>"
+ return "yes";
+}
+
+/* ----------------------------------------------- */
+
+/* Get RAMDAC values. ->del() when finished. */
+/* Return NULL if not possible */
+static ramdac *webwin_get_ramdac(dispwin *p) {
+ debugr("webdisp doesn't have a RAMDAC\n");
+ return NULL;
+}
+
+/* Set the RAMDAC values. */
+/* Return nz if not possible */
+static int webwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
+ debugr("webdisp doesn't have a RAMDAC\n");
+ return 1;
+}
+
+/* ----------------------------------------------- */
+/* Install a display profile and make */
+/* it the default for this display. */
+/* Return nz if failed */
+int webwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
+ debugr("webdisp doesn't support installing profiles\n");
+ return 1;
+}
+
+/* Un-Install a display profile */
+/* Return nz if failed, */
+int webwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
+ debugr("webdisp doesn't support uninstalling profiles\n");
+ return 1;
+}
+
+/* Get the currently installed display profile. */
+/* Return NULL if failed. */
+icmFile *webwin_get_profile(dispwin *p, char *name, int mxlen) {
+ debugr("webdisp doesn't support getting the current profile\n");
+ return NULL;
+}
+
+/* ----------------------------------------------- */
+
+/* Change the window color. */
+/* Return 1 on error, 2 on window being closed */
+static int webwin_set_color(
+dispwin *p,
+double r, double g, double b /* Color values 0.0 - 1.0 */
+) {
+ int j;
+
+ debugr("webwin_set_color called\n");
+
+ if (p->nowin)
+ return 1;
+
+ p->rgb[0] = r;
+ p->rgb[1] = g;
+ p->rgb[2] = b;
+
+ for (j = 0; j < 3; j++) {
+ if (p->rgb[j] < 0.0)
+ p->rgb[j] = 0.0;
+ else if (p->rgb[j] > 1.0)
+ p->rgb[j] = 1.0;
+ p->r_rgb[j] = p->rgb[j];
+ }
+
+ /* This is probably not actually thread safe... */
+ p->ncix++;
+
+ while(p->ncix != p->ccix) {
+ msec_sleep(50);
+ }
+
+ /* Allow some time for the display to update before */
+ /* a measurement can take place. This allows time for */
+ /* the browser to update the background color, the CRT */
+ /* refresh or LCD processing/update time, + */
+ /* display settling time (quite long for smaller LCD changes). */
+ msec_sleep(200);
+
+ return 0;
+}
+
+/* ----------------------------------------------- */
+/* Set an update delay, and return the previous value */
+/* Value can be set to zero, but othewise will be forced */
+/* to be >= min_update_delay */
+static int webwin_set_update_delay(
+dispwin *p,
+int update_delay) {
+ int cval = p->update_delay;
+ p->update_delay = update_delay;
+ if (update_delay != 0 && p->update_delay < p->min_update_delay)
+ p->update_delay = p->min_update_delay;
+ return cval;
+}
+
+/* ----------------------------------------------- */
+/* Set the shell set color callout */
+void webwin_set_callout(
+dispwin *p,
+char *callout
+) {
+ debugr2((errout,"webwin_set_callout called with '%s'\n",callout));
+
+ p->callout = strdup(callout);
+}
+
+/* ----------------------------------------------- */
+/* Destroy ourselves */
+static void webwin_del(
+dispwin *p
+) {
+
+ debugr("webwin_del called\n");
+
+ if (p == NULL)
+ return;
+
+ p->mg_stop = 1;
+ mg_stop((struct mg_context *)p->pcntx);
+
+ if (p->name != NULL)
+ free(p->name);
+ if (p->description != NULL)
+ free(p->description);
+ if (p->callout != NULL)
+ free(p->callout);
+
+ free(p);
+}
+
+/* ----------------------------------------------- */
+
+/* Create a web display test window, default grey */
+dispwin *new_webwin(
+int webdisp, /* Port number */
+double width, double height, /* Width and height in mm */
+double hoff, double voff, /* Offset from center in fraction of screen, range -1.0 .. 1.0 */
+int nowin, /* NZ if no window should be created - RAMDAC access only */
+int blackbg, /* NZ if whole screen should be filled with black */
+int verb, /* NZ for verbose prompts */
+int ddebug /* >0 to print debug statements to stderr */
+) {
+ dispwin *p = NULL;
+ char *cp;
+ struct mg_context *mg;
+ const char *options[3];
+ char port[50];
+
+ debug("new_webwin called\n");
+
+ if ((p = (dispwin *)calloc(sizeof(dispwin), 1)) == NULL) {
+ if (ddebug) fprintf(stderr,"new_webwin failed because malloc failed\n");
+ return NULL;
+ }
+
+ /* !!!! Make changes in dispwin.c as well !!!! */
+ p->name = strdup("Web Window");
+ p->nowin = nowin;
+ p->native = 0;
+ p->blackbg = blackbg;
+ p->ddebug = ddebug;
+ p->get_ramdac = webwin_get_ramdac;
+ p->set_ramdac = webwin_set_ramdac;
+ p->install_profile = webwin_install_profile;
+ p->uninstall_profile = webwin_uninstall_profile;
+ p->get_profile = webwin_get_profile;
+ p->set_color = webwin_set_color;
+ p->set_update_delay = webwin_set_update_delay;
+ p->set_callout = webwin_set_callout;
+ p->del = webwin_del;
+
+ p->rgb[0] = p->rgb[1] = p->rgb[2] = 0.5; /* Set Grey as the initial test color */
+
+ p->min_update_delay = 20;
+
+ if ((cp = getenv("ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS")) != NULL) {
+ p->min_update_delay = atoi(cp);
+ if (p->min_update_delay < 20)
+ p->min_update_delay = 20;
+ if (p->min_update_delay > 60000)
+ p->min_update_delay = 60000;
+ debugr2((errout, "new_webwin: Minimum display update delay set to %d msec\n",p->min_update_delay));
+ }
+
+ p->update_delay = DISPLAY_UPDATE_DELAY; /* Default update delay */
+ if (p->update_delay < p->min_update_delay)
+ p->update_delay = p->min_update_delay;
+
+ p->ncix = 1;
+
+ /* Basic object is initialised, so create a web server */
+
+ options[0] = "listening_ports";
+ sprintf(port,"%d", webdisp);
+ options[1] = port;
+ options[2] = NULL;
+
+ mg = mg_start(&webwin_ehandler, (void *)p, options);
+ p->pcntx = (void *)mg;
+
+//printf("Domain = %s'\n",mg_get_option(mg, "authentication_domain"));
+
+ /* Create a suitable description */
+#if NT
+ {
+ char szHostName[255];
+ struct hostent *host_entry;
+ char *localIP;
+ char buf[1000];
+
+ /* We assume WinSock has been started by mongoose */
+
+ // Get the local hostname
+ gethostname(szHostName, 255);
+ host_entry=gethostbyname(szHostName);
+ /* Get first entry */
+ localIP = inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list);
+
+ sprintf(buf,"Web Window at http://%s:%d",localIP,webdisp);
+ p->description = strdup(buf);
+
+ if (verb)
+ printf("Created web server at 'http://%s:%d', now waiting for browser to connect\n",localIP,webdisp);
+ }
+#else
+ {
+ struct ifaddrs * ifAddrStruct=NULL;
+ struct ifaddrs * ifa=NULL;
+ void *tmpAddrPtr=NULL;
+ char abuf[INET_ADDRSTRLEN] = "";
+ char abuf6[INET6_ADDRSTRLEN] = "";
+ char *addr = abuf;
+ char buf[1000];
+
+ getifaddrs(&ifAddrStruct);
+
+ /* Stop at the first non local adderss */
+ for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
+#ifdef AF_INET6
+ if (ifa->ifa_addr->sa_family==AF_INET) { /* IP4 ? */
+#endif
+ if (strncmp(ifa->ifa_name, "lo",2) == 0 || abuf[0] != '\000')
+ continue;
+ tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+ inet_ntop(AF_INET, tmpAddrPtr, abuf, INET_ADDRSTRLEN);
+// printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
+#ifdef AF_INET6
+ } else if (ifa->ifa_addr->sa_family==AF_INET6) { /* IP6 ? */
+ if (strncmp(ifa->ifa_name, "lo",2) == 0 || abuf6[0] != '\000')
+ continue;
+ tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ inet_ntop(AF_INET6, tmpAddrPtr, abuf6, INET6_ADDRSTRLEN);
+// printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
+ }
+#endif
+ }
+ if (ifAddrStruct!=NULL)
+ freeifaddrs(ifAddrStruct);
+ if (addr[0] == '\000')
+ addr = abuf6;
+ if (addr[0] == '\000')
+ addr = "Unknown";
+
+ sprintf(buf,"Web Window at http://%s:%d",addr,webdisp);
+ p->description = strdup(buf);
+
+ if (verb)
+ printf("Created web server at 'http://%s:%d', now waiting for browser to connect\n",addr,webdisp);
+ }
+#endif
+
+ /* Wait for the web server to connect */
+ debugr("new_webwin: waiting for web browser to connect\n");
+ while(p->ccix == 0) {
+ msec_sleep(50);
+ }
+
+ debugr("new_webwin: return sucessfully\n");
+
+ return p;
+}
+