As we all know xlib handling of multithreaded programs is ... idiotic.

The problem with current solution of using XLockDisplay ... is that XNextEvent 
should also be protected by the XLockDisplay!!!!
Which obviously can not be done since always waiting inside XNextEvent and 
would prevent anything else from getting lock in-time.
Using other functions (for example XTranslateCoordinates) while waiting inside 
XNextEvent is actually a race condition that makes cinelerra's window freeze! 
(as shown in bug http://bugs.cinelerra.org/show_bug.cgi?id=340)

Attached is a braindead fix, that unfortunately includes... looping, which 
noone wants to do.

The problem is that designing proper fix is hard, really HARD, because of the 
following reasons:
1. xlib does not have XTryLockDisplay - we will need to _completely_ implement 
XLockDisplay by ourselves in order to be able to know inside lock_window() if 
we should send a fake event for event loop to drop the lock
2. locking shemantic between lock_window() and BC_WindowEvent::run() will be 
very tricky to avoid race conditions (doable, but lots of thinking)
3. sending an event from lock_window to break out of event loop in 
BC_EventWindow will be have to be done by _separate_ x display connection since 
XSendEvent would also need XLockDisplay, which we naturally cannot get at that 
point!


If someone is really persistent and has time to write proper solution, it would 
be nice, but for now i have applied suboptimal patch which is attached (r941)

Adam, if you find a way to do it, please let me know as soon as possible - and 
before next mainline release.

bye
andraz
--- hvirtual-svn/guicast/bcwindowevents.C	2006-10-14 17:42:10.000000000 +0200
+++ hvirtual-2.1/guicast/bcwindowevents.C	2006-10-18 14:00:48.000000000 +0200
@@ -1,5 +1,6 @@
 #include "bcwindowbase.h"
 #include "bcwindowevents.h"
+#include "bctimer.h"
 
 BC_WindowEvents::BC_WindowEvents(BC_WindowBase *window)
  : Thread(1, 0, 0)
@@ -35,14 +36,31 @@
 
 void BC_WindowEvents::run()
 {
+// Can't cancel in XNextEvent because X server never figures out it's not
+// listening anymore and XCloseDisplay locks up.
 	XEvent *event;
 	while(!done)
 	{
-		event = new XEvent;
-// Can't cancel in XNextEvent because X server never figures out it's not
-// listening anymore and XCloseDisplay locks up.
-		XNextEvent(window->display, event);
-		window->put_event(event);
+// XNextEvent should also be protected by XLockDisplay ...
+// Currently implemented is a hackish solution, FIXME
+// Impact of this solution on the performance has not been analyzed
+
+// The proper solution is HARD because of :
+// 1. idiotic xlib does not have XTryLockDisplay - we will need to _completely_ implement XLockDisplay by ourselves (including cascaded locking - it is not the same as mutex!)
+// 2. the locking shemantic inside new lock_window and here will be really tricky, we should:
+//	in lock_window check wheather BC_WindowEvents is in XNextEvent and it is send custom xevent to break out of the loop and make sure lock is not taken again if lock_window() is waiting on it
+// 3. Send custom events from previous point through _separate_ xwindows display connection since XSendEvent would need to be protected by XLockDisplay which obviously can't be
+
+		window->lock_window();
+		while (XPending(window->display))
+		{
+			event = new XEvent;
+			XNextEvent(window->display, event);
+			window->put_event(event);
+		}
+		
+		window->unlock_window();
+		Timer::delay(20);    // sleep 20ms
 	}
 }
 

Reply via email to