Since there seems to be so much concern and speculation about the
size, complexity, and implementation of what the patch might look
like, I went ahead and implemented a fully working version for Windows
and GTK to provide something completely concrete to review.

You can find the repo here:
https://github.com/ewmailing/IupCocoa/tree/IupPostMessage
Make sure you clone/switch to the IupPostMessage branch.

The IupPostMessage() as implemented is not intended to be final form.
There are 4 parameters (2 unused) because I didn’t feel like adding a
new callback type to iupcbs.h until we made a final decision on the
API. Also, I decided to rename my proposed “UITHREAD” to
“POSTMESSAGE_CB”.


I’m also attaching the patch for those who find it convenient, as it
is small enough to include in this post without exceeding the mailing
list maximum post size threshold. My source tree was originally based
off of SVN revision 4768.

The repo also contains a test program called postmessage.c in
html/examples/tests. (The diff/patch didn’t capture it since it is a
new file.) It is a single-threaded example showing that it is also
usable in single threaded situations, i.e. those who just want to
schedule an event to fire on the next event-loop pass. Those familiar
with certain async patterns may recognize this.


I also added a version 2 of the IupALmixerThreads example which now
uses this patch as a test and further demonstration.
https://bitbucket.org/ewing/iupalmixerthread2

Thanks,
Eric
diff --git a/html/examples/tests/config.mak b/html/examples/tests/config.mak
index 0910be9..7ab409f 100644
--- a/html/examples/tests/config.mak
+++ b/html/examples/tests/config.mak
@@ -46,6 +46,7 @@ SRC += dialog.c
 SRC += calendar.c
 SRC += predialogs.c
 SRC += timer.c
+SRC += postmessage.c
 SRC += label.c
 SRC += canvas.c
 SRC += frame.c
diff --git a/include/iup.h b/include/iup.h
index 1c67a3f..9eac444 100644
--- a/include/iup.h
+++ b/include/iup.h
@@ -42,6 +42,7 @@ int       IupLoopStepWait  (void);
 int       IupMainLoopLevel (void);
 void      IupFlush         (void);
 void      IupExitLoop      (void);
+void      IupPostMessage   (Ihandle* ih, char*, void* message_data, int);
 
 int       IupRecordInput(const char* filename, int mode);
 int       IupPlayInput(const char* filename);
diff --git a/src/gtk/iupgtk_loop.c b/src/gtk/iupgtk_loop.c
index f156607..61fd14d 100644
--- a/src/gtk/iupgtk_loop.c
+++ b/src/gtk/iupgtk_loop.c
@@ -6,6 +6,7 @@
 
 #include <stdio.h>    
 #include <string.h>    
+#include <stdlib.h>
 
 #include <gtk/gtk.h>
 
@@ -113,3 +114,33 @@ void IupFlush(void)
   if (old_gtk_idle_cb)
     iupdrvSetIdleFunction((Icallback)old_gtk_idle_cb);
 }
+
+
+typedef struct {
+  Ihandle* ih;
+  void* messageData;
+} gtkPostMessageUserData;
+
+static gint gtkPostMessageCallback(void *user_data)
+{
+  gtkPostMessageUserData* message_user_data = 
(gtkPostMessageUserData*)user_data;
+  Ihandle* ih = message_user_data->ih;
+  /* TODO: Figure out callback type. For now, I'm reusing an existing type so 
I don't have to add one until we decide. */
+  IFnsVi post_message_callback = (IFnsVi)IupGetCallback(ih, "POSTMESSAGE_CB");
+  if (post_message_callback)
+  {
+    void* message_data = message_user_data->messageData;
+    post_message_callback(ih, NULL, message_data, 0);
+  }
+  free(user_data);
+  return FALSE; // call only once
+}
+
+/* TODO: Make decision on final API. For now, this API is just to get a usable 
demo. */
+void IupPostMessage(Ihandle* ih, char* unusedchar, void* message_data, int 
unusedint)
+{
+  gtkPostMessageUserData* user_data = 
(gtkPostMessageUserData*)malloc(sizeof(gtkPostMessageUserData));
+  user_data->ih = ih;
+  user_data->messageData = message_data;
+  g_idle_add(gtkPostMessageCallback, user_data);  
+}
diff --git a/src/iup.def b/src/iup.def
index bbbd45a..69b3278 100644
--- a/src/iup.def
+++ b/src/iup.def
@@ -260,6 +260,7 @@ IupDial
 IupGauge
 IupColorbar
 IupColorBrowser
+IupPostMessage
 
 iupdrvSetVisible
 iupdrvSetFontAttrib
diff --git a/src/iup_classbase.c b/src/iup_classbase.c
index 7620c72..95868fc 100644
--- a/src/iup_classbase.c
+++ b/src/iup_classbase.c
@@ -571,6 +571,7 @@ void iupBaseRegisterCommonCallbacks(Iclass* ic)
   iupClassRegisterCallback(ic, "ENTERWINDOW_CB", "");
   iupClassRegisterCallback(ic, "LEAVEWINDOW_CB", "");
   iupClassRegisterCallback(ic, "HELP_CB", "");
+  iupClassRegisterCallback(ic, "POSTMESSAGE_CB", "");
   iupClassRegisterCallback(ic, "K_ANY", "i");
 }
 
diff --git a/src/win/iupwin_drv.h b/src/win/iupwin_drv.h
index ca66b82..22d3eda 100644
--- a/src/win/iupwin_drv.h
+++ b/src/win/iupwin_drv.h
@@ -17,7 +17,8 @@ extern "C" {
 extern HINSTANCE iupwin_hinstance;      /* iupwin_open.c */
 extern int       iupwin_comctl32ver6;   /* iupwin_open.c */
 extern HINSTANCE iupwin_dll_hinstance;  /* iupwindows_main.c */
-
+extern DWORD     iupwin_mainthreadid;   /* iupwin_open.c, iupwin_loop.c */
+extern HHOOK     iupwin_threadmsghook;  /* iupwin_open.c, iupwin_loop.c */
 
 /* open */
 void iupwinShowLastError(void);
@@ -104,6 +105,8 @@ void iupwinRefreshCursor(Ihandle* ih);
 
 int iupwinListDND(Ihandle *ih, UINT uNotification, POINT pt);
 
+LRESULT CALLBACK iupwinPostMessageFilterProc(int code, WPARAM wParam, LPARAM 
lParam);
+
 
 /*********************/
 /* Window Management */
diff --git a/src/win/iupwin_loop.c b/src/win/iupwin_loop.c
index 3ac733e..d282ed8 100644
--- a/src/win/iupwin_loop.c
+++ b/src/win/iupwin_loop.c
@@ -20,6 +20,8 @@
 #include "iupwin_drv.h"
 #include "iupwin_handle.h"
 
+/* This just needs to be a random unique number not used by the OS */
+#define IWIN_POSTMESSAGE_ID 0x4456
 
 static IFidle win_idle_cb = NULL;
 static int win_main_loop = 0;
@@ -56,8 +58,11 @@ static int winLoopProcessMessage(MSG* msg)
     return IUP_CLOSE;
   else
   {
-    TranslateMessage(msg);
-    DispatchMessage(msg);
+    if (!CallMsgFilter(msg, IWIN_POSTMESSAGE_ID))
+    {
+      TranslateMessage(msg);
+      DispatchMessage(msg);
+    }
     return IUP_DEFAULT;
   }
 }
@@ -158,3 +163,43 @@ void IupFlush(void)
   if (post_quit && win_main_loop>0)
     IupExitLoop();
 }
+
+/* Based on Raymond Chen's discussion of PostThreadMessage
+https://blogs.msdn.microsoft.com/oldnewthing/20050428-00/?p=35753
+TODO: Make decision on final API. For now, this API is just to get a usable 
demo.
+*/
+void IupPostMessage(Ihandle* ih, char* unusedchar, void* message_data, int 
unusedint)
+{
+  // REVIEW: I am passing the Ihandle* ih into the WPARAM field because I'm 
using the LPARAM field for message_data.
+  // I think this is okay because the size of WPARAM should be the same as 
LPARAM.
+  PostThreadMessage(iupwin_mainthreadid, WM_APP, (WPARAM)ih, 
(LPARAM)message_data);
+}
+
+LRESULT CALLBACK iupwinPostMessageFilterProc(int code, WPARAM wParam, LPARAM 
lParam)
+{
+  MSG* pmsg = (MSG*)lParam;
+  if (code == IWIN_POSTMESSAGE_ID)
+  {
+    switch (pmsg->message)
+    {
+      case WM_APP: 
+      {
+        Ihandle* ih = (Ihandle*)pmsg->wParam;
+        /* TODO: Figure out callback type. For now, I'm reusing an existing 
type so I don't have to add one until we decide. */
+        IFnsVi post_message_callback = (IFnsVi)IupGetCallback(ih, 
"POSTMESSAGE_CB");
+        if (post_message_callback)
+        {
+          void* message_data = (Ihandle*)pmsg->lParam;
+          post_message_callback(ih, NULL, message_data, 0);
+        }
+        return TRUE;
+      }
+      default:
+      {
+//      return FALSE; /* maybe this can be TRUE because nothing should be 
using code==IWIN_POSTMESSAGE_ID */
+      }                
+    }
+  }
+
+  return CallNextHookEx(iupwin_threadmsghook, code, wParam, lParam);
+}
diff --git a/src/win/iupwin_open.c b/src/win/iupwin_open.c
index 4921ca9..44a1527 100644
--- a/src/win/iupwin_open.c
+++ b/src/win/iupwin_open.c
@@ -33,6 +33,8 @@
 
 HINSTANCE iupwin_hinstance = 0;    
 int       iupwin_comctl32ver6 = 0;
+DWORD     iupwin_mainthreadid = 0;
+HHOOK     iupwin_threadmsghook = 0;
 
 void* iupdrvGetDisplay(void)
 {
@@ -113,6 +115,9 @@ int iupdrvOpen(int *argc, char ***argv)
   if (iupwin_comctl32ver6 && !iupwinIsAppThemed())  /* When the user selected 
the Windows Classic theme or visual styles not active */
     iupwin_comctl32ver6 = 0;
 
+  iupwin_mainthreadid = GetCurrentThreadId();
+  iupwin_threadmsghook = SetWindowsHookEx(WH_MSGFILTER, 
iupwinPostMessageFilterProc, NULL, iupwin_mainthreadid);
+
   IupSetGlobal("SYSTEMLANGUAGE", iupwinGetSystemLanguage());
 
   /* default colors */
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Iup-users mailing list
Iup-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/iup-users

Reply via email to