changeset 12:7a7e5f9bd1ae

Implement invoke() and invokeNow() on Windows.
author Jordan Miner <jminer7@gmail.com>
date Sat, 18 Jul 2009 01:37:06 -0500
parents df1c8e659b75
children a3a2aa21fc52
files dynamin/c/windows.d dynamin/gui/window.d dynamin/gui/windows_window.d
diffstat 3 files changed, 45 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/dynamin/c/windows.d	Thu Jul 16 18:18:22 2009 -0500
+++ b/dynamin/c/windows.d	Sat Jul 18 01:37:06 2009 -0500
@@ -813,7 +813,11 @@
 
 void PostQuitMessage(int nExitCode);
 
-LRESULT SendMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT SendMessageW(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+
+BOOL InSendMessage();
+
+BOOL ReplyMessage(LRESULT lResult);
 //}}}
 
 //{{{ clipboard functions
@@ -1590,6 +1594,7 @@
 //}}}
 
 version(UNICODE) {
+	alias MessageBoxW              MessageBox;
 	alias RegisterClassExW		   RegisterClassEx;
 	alias CreateWindowExW		   CreateWindowEx;
 	alias DefWindowProcW		   DefWindowProc;
@@ -1607,6 +1612,7 @@
 	alias GetSaveFileNameW		   GetSaveFileName;
 	alias GetMessageW			   GetMessage;
 	alias DispatchMessageW		   DispatchMessage;
+	alias SendMessageW             SendMessage;
 	alias LoadImageW			   LoadImage;
 	alias GetObjectW               GetObject;
 	alias EnumFontFamiliesExW	   EnumFontFamiliesEx;
@@ -1629,6 +1635,7 @@
 	alias TEXTMETRICW    TEXTMETRIC;
 	alias OSVERSIONINFOW OSVERSIONINFO;
 } else {
+	alias MessageBoxA              MessageBox;
 	alias RegisterClassExA		   RegisterClassEx;
 	alias CreateWindowExA		   CreateWindowEx;
 	alias DefWindowProcA		   DefWindowProc;
@@ -1646,6 +1653,7 @@
 	alias GetSaveFileNameA		   GetSaveFileName;
 	alias GetMessageA			   GetMessage;
 	alias DispatchMessageA		   DispatchMessage;
+	alias SendMessageA             SendMessage;
 	alias LoadImageA			   LoadImage;
 	alias EnumFontFamiliesExA	   EnumFontFamiliesEx;
 	alias SystemParametersInfoA	   SystemParametersInfo;
--- a/dynamin/gui/window.d	Thu Jul 16 18:18:22 2009 -0500
+++ b/dynamin/gui/window.d	Sat Jul 18 01:37:06 2009 -0500
@@ -37,10 +37,12 @@
 import tango.core.Exception;
 import tango.core.Thread;
 
+///
 static class Application {
 static:
 	mixin ApplicationBackend;
 	package Thread eventThread;
+	/// Starts event processing. Must be called from main().
 	void run(Window w = null) {
 		Window.hasProcessedEvents = true;
 
@@ -51,12 +53,25 @@
 
 		backend_run(w);
 	}
-	//void invoke(void delegate() dg) {
-		//
-	//}
-	//void invokeNow(void delegate() dg)
+	/**
+	 * Calls the specified delegate on the event thread and returns without
+	 * waiting for the delegate to finish. Since the delegate is not called
+	 * immediately, it must not live on the stack. Instead, it could be a
+	 * method of a class. In D2, delegates generally are on the heap.
+	 */
+	void invoke(void delegate() dg) {
+		backend_invoke(dg);
+	}
+	/**
+	 * Calls the specified delegate on the event thread and blocks until
+	 * the delegate finishes.
+	 */
+	void invokeNow(void delegate() dg) {
+		backend_invokeNow(dg);
+	}
 }
 
+///
 enum DialogResult {
 	///
 	OK,
@@ -223,7 +238,7 @@
 			recreateHandle();
 		assert(Thread.getThis() is Application.eventThread ||
 				Application.eventThread is null,
-			"controls must be accessed and changed only on the event thread");
+			"Controls must be accessed and changed only on the event thread. Use invokeNow() from other threads.");
 		return _handle;
 	}
 
--- a/dynamin/gui/windows_window.d	Thu Jul 16 18:18:22 2009 -0500
+++ b/dynamin/gui/windows_window.d	Sat Jul 18 01:37:06 2009 -0500
@@ -34,6 +34,7 @@
 public import dynamin.gui.key;
 public import dynamin.all_painting;
 public import tango.io.Stdout;
+public import tango.core.sync.Semaphore;
 
 ///
 enum WindowsVersion {
@@ -117,8 +118,16 @@
 			DispatchMessage(&msg);
 		}
 	}
+	void backend_invoke(void delegate() dg) {
+		PostMessage(msgWnd, WM_USER + 7,
+			cast(word)dg.ptr, cast(word)dg.funcptr);
+	}
+	void backend_invokeNow(void delegate() dg) {
+		SendMessage(msgWnd, WM_USER + 7,
+			cast(word)dg.ptr, cast(word)dg.funcptr);
+	}
+
 }
-
 /*
  * The reason backends use the backend_ prefix and:
  * mixin Backend();
@@ -966,6 +975,12 @@
 		if(wParam == PBT_APMRESUMESUSPEND || wParam == PBT_APMRESUMECRITICAL)
 			Environment.backend_increaseTimerRes();
 		return 0;
+	case WM_USER + 7:
+		void delegate() dg;
+		dg.ptr = cast(void*)wParam;
+		dg.funcptr = cast(void function())lParam;
+		dg();
+		return 0;
 	case WM_TIMER:
 	case WM_CHANGECBCHAIN:
 	case WM_DRAWCLIPBOARD: