changeset 2088:94ea915bd917

Win: Initial implementation of notifications on Windows. Currently using WinToast. Update readme regarding WinToast support and in-source comments regarding the API. Fix missing "API" calling conventions on OS/2 and Windows.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Fri, 05 Jun 2020 16:27:00 +0000
parents 082d743f3214
children bcc7877dcdac
files gtk/dw.c gtk3/dw.c mac/dw.m makefile.vc os2/dw.c readme.txt win/dw.c win/edge.cpp
diffstat 8 files changed, 119 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/gtk/dw.c	Fri Jun 05 06:00:17 2020 +0000
+++ b/gtk/dw.c	Fri Jun 05 16:27:00 2020 +0000
@@ -13281,7 +13281,7 @@
  * Sets the application ID used by this Dynamic Windows application instance.
  * Parameters:
  *         appid: A string typically in the form: com.company.division.application
- *         appguid: A globally unique identifier required on Windows or NULL.
+ *         appname: The application name used on Windows or NULL.
  * Returns:
  *         DW_ERROR_NONE after successfully setting the application ID.
  *         DW_ERROR_UNKNOWN if unsupported on this system.
@@ -13290,9 +13290,10 @@
  *          This must be called before dw_init().  If dw_init() is called first
  *          it will create a unique ID in the form: org.dbsoft.dwindows.application
  *          or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
- *          The GUID is only required on Windows, NULL can be passed on other platforms.
- */
-int dw_app_id_set(const char *appid, const char *appguid)
+ *          The appname is only required on Windows.  If NULL is passed the detected
+ *          application name will be used, but a prettier name may be desired.
+ */
+int dw_app_id_set(const char *appid, const char *appname)
 {
 #if GLIB_CHECK_VERSION(2,28,0)
    if(g_application_id_is_valid(appid))
--- a/gtk3/dw.c	Fri Jun 05 06:00:17 2020 +0000
+++ b/gtk3/dw.c	Fri Jun 05 16:27:00 2020 +0000
@@ -11778,7 +11778,7 @@
  * Sets the application ID used by this Dynamic Windows application instance.
  * Parameters:
  *         appid: A string typically in the form: com.company.division.application
- *         appguid: A globally unique identifier required on Windows or NULL.
+ *         appname: The application name used on Windows or NULL.
  * Returns:
  *         DW_ERROR_NONE after successfully setting the application ID.
  *         DW_ERROR_UNKNOWN if unsupported on this system.
@@ -11787,9 +11787,10 @@
  *          This must be called before dw_init().  If dw_init() is called first
  *          it will create a unique ID in the form: org.dbsoft.dwindows.application
  *          or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
- *          The GUID is only required on Windows, NULL can be passed on other platforms.
- */
-int dw_app_id_set(const char *appid, const char *appguid)
+ *          The appname is only required on Windows.  If NULL is passed the detected
+ *          application name will be used, but a prettier name may be desired.
+ */
+int dw_app_id_set(const char *appid, const char *appname)
 {
 #if GLIB_CHECK_VERSION(2,28,0)
    if(g_application_id_is_valid(appid))
--- a/mac/dw.m	Fri Jun 05 06:00:17 2020 +0000
+++ b/mac/dw.m	Fri Jun 05 16:27:00 2020 +0000
@@ -3970,7 +3970,7 @@
  * Sets the application ID used by this Dynamic Windows application instance.
  * Parameters:
  *         appid: A string typically in the form: com.company.division.application
- *         appguid: A globally unique identifier required on Windows or NULL.
+ *         appname: The application name used on Windows or NULL.
  * Returns:
  *         DW_ERROR_NONE after successfully setting the application ID.
  *         DW_ERROR_UNKNOWN if unsupported on this system.
@@ -3979,9 +3979,10 @@
  *          This must be called before dw_init().  If dw_init() is called first
  *          it will create a unique ID in the form: org.dbsoft.dwindows.application
  *          or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
- *          The GUID is only required on Windows, NULL can be passed on other platforms.
- */
-int dw_app_id_set(const char *appid, const char *appguid)
+ *          The appname is only required on Windows.  If NULL is passed the detected
+ *          application name will be used, but a prettier name may be desired.
+ */
+int dw_app_id_set(const char *appid, const char *appname)
 {
     strncpy(_dw_app_id, appid, 100);
     return DW_ERROR_NONE;
--- a/makefile.vc	Fri Jun 05 06:00:17 2020 +0000
+++ b/makefile.vc	Fri Jun 05 16:27:00 2020 +0000
@@ -89,8 +89,20 @@
 WEBVIEW2OBJ=edge.obj
 !endif
 
+#
+# Settings for supporting WinToast notifications
+#
+!if "$(WINTOASTDIR)" == ""
+WINTOASTDIR=$(SRCDIR)\packages\WinToast
+!endif
+
+!if exists($(WINTOASTDIR)\src\wintoastlib.h)
+WINTOASTINC=-DBUILD_TOAST -I$(WINTOASTDIR)\src
+WINTOASTOBJ=wintoast.obj wintoastlib.obj
+!endif
+
 CC = cl
-CFLAGS = -c $(PLATFORM_DEF) -D__WIN32__ -DMSVC -DTOOLBAR -DGDIPLUS -DAEROGLASS -D_UNICODE -DUNICODE -DBUILD_DLL -DISOLATION_AWARE_ENABLED=1 -I$(SRCDIR)\platform -I$(SRCDIR) $(WEBVIEW2INC) $(SVNVERSION)
+CFLAGS = -c $(PLATFORM_DEF) -D__WIN32__ -DMSVC -DTOOLBAR -DGDIPLUS -DAEROGLASS -D_UNICODE -DUNICODE -DBUILD_DLL -DISOLATION_AWARE_ENABLED=1 -I$(SRCDIR)\platform -I$(SRCDIR) $(WEBVIEW2INC) $(WINTOASTINC) $(SVNVERSION)
 LIBS = wsock32.lib kernel32.lib user32.lib comctl32.lib gdi32.lib advapi32.lib shell32.lib comdlg32.lib ole32.lib oleaut32.lib userenv.lib msimg32.lib gdiplus.lib $(WEBVIEW2LIB)
 RES =
 LINKFLAGS = -machine:$(TARGET_CPU) -manifest $(LINK_DEBUG)
@@ -99,7 +111,7 @@
 DEFFILE = $(SRCDIR)\win\dw.def
 DEFFILE2 = $(SRCDIR)\win\dwcompat.def
 
-OBJS = dw.obj browser.obj XBrowseForFolder.obj $(WEBVIEW2OBJ)
+OBJS = dw.obj browser.obj XBrowseForFolder.obj $(WEBVIEW2OBJ) $(WINTOASTOBJ)
 
 OBJS2 = dwcompat.obj dirent.obj
 
@@ -167,6 +179,12 @@
 edge.obj: $(SRCDIR)\win\edge.cpp
 	$(CC) $(CFLAGS) $(CFLAGS_DEBUG) $(SRCDIR)\win\edge.cpp
 
+wintoast.obj: $(SRCDIR)\win\wintoast.cpp
+	$(CC) $(CFLAGS) /EHsc $(CFLAGS_DEBUG) $(SRCDIR)\win\wintoast.cpp
+
+wintoastlib.obj: $(WINTOASTDIR)\src\wintoastlib.cpp
+	$(CC) $(CFLAGS) /EHsc $(CFLAGS_DEBUG) $(WINTOASTDIR)\src\wintoastlib.cpp
+
 dirent.obj: $(SRCDIR)\win\dirent.c
 	$(CC) $(CFLAGS) $(CFLAGS_DEBUG) $(SRCDIR)\win\dirent.c
 
--- a/os2/dw.c	Fri Jun 05 06:00:17 2020 +0000
+++ b/os2/dw.c	Fri Jun 05 16:27:00 2020 +0000
@@ -12406,7 +12406,7 @@
  *          This will create a system notification that will show in the notifaction panel
  *          on supported systems, which may be clicked to perform another task.
  */
-HWND dw_notification_new(const char *title, HPIXMAP pixmap, const char *description, ...)
+HWND API dw_notification_new(const char *title, HPIXMAP pixmap, const char *description, ...)
 {
    return NULL;
 }
@@ -12418,7 +12418,7 @@
  * Returns:
  *         DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported.
  */
-int dw_notification_send(HWND notification)
+int API dw_notification_send(HWND notification)
 {
    return DW_ERROR_UNKNOWN;
 }
@@ -13311,7 +13311,7 @@
  * Sets the application ID used by this Dynamic Windows application instance.
  * Parameters:
  *         appid: A string typically in the form: com.company.division.application
- *         appguid: A globally unique identifier required on Windows or NULL.
+ *         appname: The application name used on Windows or NULL.
  * Returns:
  *         DW_ERROR_NONE after successfully setting the application ID.
  *         DW_ERROR_UNKNOWN if unsupported on this system.
@@ -13320,9 +13320,10 @@
  *          This must be called before dw_init().  If dw_init() is called first
  *          it will create a unique ID in the form: org.dbsoft.dwindows.application
  *          or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
- *          The GUID is only required on Windows, NULL can be passed on other platforms.
- */
-int dw_app_id_set(const char *appid, const char *appguid)
+ *          The appname is only required on Windows.  If NULL is passed the detected
+ *          application name will be used, but a prettier name may be desired.
+ */
+int API dw_app_id_set(const char *appid, const char *appname)
 {
     return DW_ERROR_UNKNOWN;
 }
--- a/readme.txt	Fri Jun 05 06:00:17 2020 +0000
+++ b/readme.txt	Fri Jun 05 16:27:00 2020 +0000
@@ -34,7 +34,7 @@
 
 Changes from version 3.0:
 Added support for MacOS versions through Catalina 10.15, 
-    Windows versions through 10 build 1909.
+    Windows versions through 10 build 2004.
 Fixed handle leak on OS/2 when built with (Open)Watcom.
 Added dark mode support on MacOS Mojave 10.14 and later. 
 Added experimental dark mode support on Windows 10 build 1809 (disabled by default).
@@ -46,6 +46,7 @@
     Requires Windows 8 or higher. MacOS 10.8 or higher. GLib 2.40 or higher on Unix.
     MacOS also requires the application bundle being signed or self-signed.
     Unix requires a desktop file link with the application ID used in dw_app_id_set().
+    Unzip WinToast from https://github.com/mohabouje/WinToast into  .\packages\WinToast
 Added webkit2gtk support and removed dead gtkmozembed and libgtkhtml2 support on Unix.
 Added embedded HTML javascript support on Mac, Windows and Unix with webkit(2)gtk. 
     Added function dw_html_javascript_run() to execute javascript code.
--- a/win/dw.c	Fri Jun 05 06:00:17 2020 +0000
+++ b/win/dw.c	Fri Jun 05 16:27:00 2020 +0000
@@ -278,7 +278,10 @@
  */
 static char _dw_alternate_temp_dir[MAX_PATH+1] = {0};
 static char _dw_exec_dir[MAX_PATH+1] = {0};
+#ifdef BUILD_TOAST
 static char _dw_app_id[101]= {0};
+static char _dw_app_name[101]= {0};
+#endif
 
 int main(int argc, char *argv[]);
 
@@ -317,6 +320,11 @@
 LRESULT CALLBACK _edgeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 #endif
 #endif
+#ifdef BUILD_TOAST
+void _dw_toast_init(LPWSTR AppName, LPWSTR AppID);
+void *_dw_notification_new(LPWSTR title, LPWSTR image, LPWSTR description);
+int _dw_notification_send(void *notification);
+#endif 
 LRESULT CALLBACK _colorwndproc(HWND hWnd, UINT msg, WPARAM mp1, LPARAM mp2);
 void _resize_notebook_page(HWND handle, int pageid);
 void _handle_splitbar_resize(HWND hwnd, float percent, int type, int x, int y);
@@ -431,7 +439,7 @@
    }
 
    argv = (char **)malloc(sizeof(char *) * ((*count)+1));
-   argv[0] = malloc(260);
+   argv[0] = calloc(261, 1);
    GetModuleFileNameA(DWInstance, argv[0], 260);
 
    argstart = tmp = start;
@@ -4245,7 +4253,17 @@
          pos = strrchr(argv[0], '/');
 
       if(pos)
+      {
          strncpy(_dw_exec_dir, argv[0], (size_t)(pos - argv[0]));
+#ifdef BUILD_TOAST
+         if((pos++) && !_dw_app_id[0])
+         {
+            /* If we have a binary name, use that for the Application ID instead. */
+            snprintf(_dw_app_id, 100, "%s.%s", DW_APP_DOMAIN_DEFAULT, pos);
+            strncpy(_dw_app_name, pos, 100);
+         }
+#endif
+      }
    }
    /* If that failed... just get the current directory */
    if(!_dw_exec_dir[0])
@@ -4406,13 +4424,13 @@
    /* Check if Microsoft Edge (Chromium) is installed */
    if (_DW_EDGE_DETECTED = _dw_edge_detect())
    {
-	   wc.lpfnWndProc = (WNDPROC)_edgeWindowProc;
-	   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+      wc.lpfnWndProc = (WNDPROC)_edgeWindowProc;
+      //wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    }
    else
 #endif
    {
-	   wc.lpfnWndProc = (WNDPROC)_browserWindowProc;
+      wc.lpfnWndProc = (WNDPROC)_browserWindowProc;
    }
    RegisterClass(&wc);
 #endif
@@ -4464,6 +4482,24 @@
          hrichedit = LoadLibrary(TEXT("riched32"));
    }
 #endif
+#ifdef BUILD_TOAST
+    if(!_dw_app_id[0])
+    {
+        /* Generate an Application ID based on the PID if all else fails. */
+        snprintf(_dw_app_id, 100, "%s.pid.%d", DW_APP_DOMAIN_DEFAULT, getpid());
+    }
+    if(!_dw_app_name[0])
+    {
+       /* If we still don't have an app name, get the executable name */
+       char fullpath[261] = {0}, *pos;
+       GetModuleFileNameA(DWInstance, fullpath, 260);
+       pos = strrchr(fullpath, '\\');
+       if(pos)
+          pos++;
+       strncpy(_dw_app_name, pos ? pos : fullpath, 100);
+    }
+   _dw_toast_init(UTF8toWide(_dw_app_name), UTF8toWide(_dw_app_id));
+#endif
    return 0;
 }
 
@@ -12358,9 +12394,23 @@
  *          This will create a system notification that will show in the notifaction panel
  *          on supported systems, which may be clicked to perform another task.
  */
-HWND dw_notification_new(const char *title, HPIXMAP pixmap, const char *description, ...)
-{
+HWND API dw_notification_new(const char *title, HPIXMAP pixmap, const char *description, ...)
+{
+#ifdef BUILD_TOAST
+   char outbuf[1025] = {0};
+
+   if(description)
+   {
+      va_list args;
+
+      va_start(args, description);
+      vsnprintf(outbuf, 1024, description, args);
+      va_end(args);
+   }
+   return (HWND)_dw_notification_new(UTF8toWide(title), NULL, UTF8toWide(outbuf));
+#else
    return NULL;
+#endif
 }
 
 /*
@@ -12370,9 +12420,13 @@
  * Returns:
  *         DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported.
  */
-int dw_notification_send(HWND notification)
-{
+int API dw_notification_send(HWND notification)
+{
+#ifdef BUILD_TOAST
+   return _dw_notification_send((void *)notification);
+#else
    return DW_ERROR_UNKNOWN;
+#endif
 }
 
 /*
@@ -12829,7 +12883,7 @@
  * Sets the application ID used by this Dynamic Windows application instance.
  * Parameters:
  *         appid: A string typically in the form: com.company.division.application
- *         appguid: A globally unique identifier required on Windows or NULL.
+ *         appname: The application name used on Windows or NULL.
  * Returns:
  *         DW_ERROR_NONE after successfully setting the application ID.
  *         DW_ERROR_UNKNOWN if unsupported on this system.
@@ -12838,11 +12892,19 @@
  *          This must be called before dw_init().  If dw_init() is called first
  *          it will create a unique ID in the form: org.dbsoft.dwindows.application
  *          or if the application name cannot be detected: org.dbsoft.dwindows.pid.#
- *          The GUID is only required on Windows, NULL can be passed on other platforms.
- */
-int dw_app_id_set(const char *appid, const char *appguid)
-{
+ *          The appname is only required on Windows.  If NULL is passed the detected
+ *          application name will be used, but a prettier name may be desired.
+ */
+int API dw_app_id_set(const char *appid, const char *appname)
+{
+#ifdef BUILD_TOAST
+    strncpy(_dw_app_id, appid, 100);
+    if(appname)
+        strncpy(_dw_app_name, appname, 100);
+    return DW_ERROR_NONE;
+#else
     return DW_ERROR_UNKNOWN;
+#endif
 }
 
 /*
--- a/win/edge.cpp	Fri Jun 05 06:00:17 2020 +0000
+++ b/win/edge.cpp	Fri Jun 05 16:27:00 2020 +0000
@@ -5,9 +5,6 @@
  * Requires Windows 10, 8 or 7 with Microsoft Edge (Chromium) installed.
  * 
  * Only included when BUILD_EDGE is defined, will fall back to embedded IE.
- *
- * Currently only buildable with Visual Studio since it requires the EDGE
- * SDK which is currently distributed as a nuget package. 
  */
 #include "dw.h"
 #include "webview2.h"