From 8f9bfcc8e3fc93cd5c9fffdec63cb00a7bb45dcb Mon Sep 17 00:00:00 2001 From: cxl Date: Sat, 6 Jul 2013 12:32:06 +0000 Subject: [PATCH] CtrlCore: New MT rules implemented in X11 and GTK git-svn-id: svn://ultimatepp.org/upp/trunk@6170 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Core/srcdoc.tpp/AboutStream$en-us.tpp | 2 +- uppsrc/CtrlCore/GtkCreate.cpp | 9 ++--- uppsrc/CtrlCore/GtkEvent.cpp | 7 ++-- uppsrc/CtrlCore/GtkTop.cpp | 6 ++-- uppsrc/CtrlCore/GtkWnd.cpp | 19 +++++----- uppsrc/CtrlCore/Win32Wnd.cpp | 2 +- uppsrc/CtrlCore/X11Top.cpp | 17 ++++----- uppsrc/CtrlCore/X11Wnd.cpp | 38 +++++++++----------- uppsrc/CtrlCore/src.tpp/Ctrl$en-us.tpp | 23 +++++++----- 9 files changed, 59 insertions(+), 64 deletions(-) diff --git a/uppsrc/Core/srcdoc.tpp/AboutStream$en-us.tpp b/uppsrc/Core/srcdoc.tpp/AboutStream$en-us.tpp index 8c10c16c1..919d0c175 100644 --- a/uppsrc/Core/srcdoc.tpp/AboutStream$en-us.tpp +++ b/uppsrc/Core/srcdoc.tpp/AboutStream$en-us.tpp @@ -138,4 +138,4 @@ somewhere or what ever..)&] again, and when time has come, pushes it to 2 other streams..(so a little `'data latency`' is expected..if you want to make the data be available at once, call Flush() after your operations..&] -[s0; ] \ No newline at end of file +[s0; ]] \ No newline at end of file diff --git a/uppsrc/CtrlCore/GtkCreate.cpp b/uppsrc/CtrlCore/GtkCreate.cpp index ea58c9859..15b10e84a 100644 --- a/uppsrc/CtrlCore/GtkCreate.cpp +++ b/uppsrc/CtrlCore/GtkCreate.cpp @@ -9,7 +9,7 @@ NAMESPACE_UPP void Ctrl::Create(Ctrl *owner, bool popup) { GuiLock __; - ASSERT(IsMainThread()); + ASSERT_(IsMainThread(), "Only the main thread can open a window"); LLOG("Create " << Name() << " " << GetRect()); ASSERT(!IsChild() && !IsOpen()); LLOG("Ungrab1"); @@ -117,12 +117,7 @@ void Ctrl::GuiPlatformRemove() i++; } -void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, bool topmost) -{ - Call(callback2(this, &Ctrl::PopUp0, owner, activate)); -} - -void Ctrl::PopUp0(Ctrl *owner, bool activate) +void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool, bool) { GuiLock __; LLOG("POPUP " << Name() << ", " << GetRect() << ", activate " << activate); diff --git a/uppsrc/CtrlCore/GtkEvent.cpp b/uppsrc/CtrlCore/GtkEvent.cpp index 270816787..21887bda5 100644 --- a/uppsrc/CtrlCore/GtkEvent.cpp +++ b/uppsrc/CtrlCore/GtkEvent.cpp @@ -581,10 +581,10 @@ void WakeUpGuiThread() g_main_context_wakeup(g_main_context_default()); } -void Ctrl::EventLoop0(Ctrl *ctrl) +void Ctrl::EventLoop(Ctrl *ctrl) { GuiLock __; - ASSERT(IsMainThread()); + ASSERT_(IsMainThread(), "Event loop can only run in the main thread"); ASSERT(LoopLevel == 0 || ctrl); LoopLevel++; LLOG("Entering event loop at level " << LoopLevel << LOG_BEGIN); @@ -614,9 +614,10 @@ gboolean sOnce(GtkWidget *) return false; } -void Ctrl::GuiSleep0(int ms) +void Ctrl::GuiSleep(int ms) { GuiLock __; + ASSERT_(IsMainThread(), "Only the main thread can perform GuiSleep"); if(ms < 20) // Periodic timer is each 20ms, so that is the longest possible wait g_timeout_add(ms, (GSourceFunc) sOnce, NULL); // otherwise setup shorter timer FetchEvents(TRUE); diff --git a/uppsrc/CtrlCore/GtkTop.cpp b/uppsrc/CtrlCore/GtkTop.cpp index c04accb0d..fc7274d95 100644 --- a/uppsrc/CtrlCore/GtkTop.cpp +++ b/uppsrc/CtrlCore/GtkTop.cpp @@ -36,17 +36,17 @@ void TopWindow::SyncSizeHints() GdkWindowHints(GDK_HINT_MIN_SIZE|GDK_HINT_MAX_SIZE)); } -void TopWindow::SyncTitle0() +void TopWindow::SyncTitle() { GuiLock __; if(top) gtk_window_set_title(gtk(), FromUnicode(title, CHARSET_UTF8)); } -void TopWindow::SyncCaption0() +void TopWindow::SyncCaption() { GuiLock __; - SyncTitle0(); + SyncTitle(); if(top) { if(gdk_icon.Set(icon)) gtk_window_set_icon(gtk(), gdk_icon); diff --git a/uppsrc/CtrlCore/GtkWnd.cpp b/uppsrc/CtrlCore/GtkWnd.cpp index 867c579b5..a3d1a2d65 100644 --- a/uppsrc/CtrlCore/GtkWnd.cpp +++ b/uppsrc/CtrlCore/GtkWnd.cpp @@ -191,7 +191,7 @@ Rect Ctrl::GetWndScreenRect() const return Null; } -void Ctrl::WndShow0(bool b) +void Ctrl::WndShow(bool b) { GuiLock __; LLOG("WndShow " << Name() << ", " << b); @@ -301,7 +301,7 @@ int Ctrl::GetKbdSpeed() return 1000 / 32; } -void Ctrl::SetWndForeground0() +void Ctrl::SetWndForeground() { GuiLock __; if(top) @@ -343,18 +343,19 @@ void Ctrl::FocusSync() } } -void Ctrl::SetWndFocus(bool *b) +bool Ctrl::SetWndFocus() { GuiLock __; LLOG("SetWndFocus0 " << Upp::Name(this) << ", top: " << top); if(top) { LLOG("SetWndFocus0 DO gdk: " << gdk()); - SetWndForeground0(); + SetWndForeground(); int t0 = msecs(); while(!gtk_window_is_active(gtk()) && msecs() - t0 < 500) // Wait up to 500ms for window to become active - not ideal, but only possibility FetchEvents(true); FocusSync(); } + return true; } void Ctrl::WndInvalidateRect(const Rect& r) @@ -365,7 +366,7 @@ void Ctrl::WndInvalidateRect(const Rect& r) // gtk_widget_queue_draw_area(top->window, r.left, r.top, r.GetWidth(), r.GetHeight()); } -void Ctrl::WndScrollView0(const Rect& r, int dx, int dy) +void Ctrl::WndScrollView(const Rect& r, int dx, int dy) { GuiLock __; LLOG("ScrollView " << rect); @@ -391,7 +392,7 @@ bool Ctrl::SweepConfigure(bool wait) return r; } -void Ctrl::WndSetPos0(const Rect& rect) +void Ctrl::WndSetPos(const Rect& rect) { LLOG("WndSetPos0 " << rect); GuiLock __; @@ -413,11 +414,11 @@ void Ctrl::WndSetPos0(const Rect& rect) LLOG("-- WndSetPos0 " << rect << " " << msecs() - t0); } -void Ctrl::WndEnable(bool *b) +void Ctrl::WndEnable(bool b) { GuiLock __; if(top) { - gtk_widget_set_sensitive(top->window, *b); + gtk_widget_set_sensitive(top->window, b); StateH(ENABLE); } } @@ -426,7 +427,7 @@ void Ctrl::WndUpdate(const Rect& r) { GuiLock __; LLOG("WndUpdate0r " << r); - WndUpdate0(); // Not found a way how to update only part of window + WndUpdate(); // Not found a way how to update only part of window } void Ctrl::WndUpdate() diff --git a/uppsrc/CtrlCore/Win32Wnd.cpp b/uppsrc/CtrlCore/Win32Wnd.cpp index 1888c7229..2066a9339 100644 --- a/uppsrc/CtrlCore/Win32Wnd.cpp +++ b/uppsrc/CtrlCore/Win32Wnd.cpp @@ -843,7 +843,7 @@ void Ctrl::EventLoop(Ctrl *ctrl) void Ctrl::GuiSleep(int ms) { GuiLock __; - ASSERT(IsMainThread()); + ASSERT_(IsMainThread(), "Only the main thread can perform GuiSleep"); ELOG("GuiSleep"); int level = LeaveGuiMutexAll(); #if !defined(flagDLL) && !defined(PLATFORM_WINCE) diff --git a/uppsrc/CtrlCore/X11Top.cpp b/uppsrc/CtrlCore/X11Top.cpp index 0222d3e96..8ac532db9 100644 --- a/uppsrc/CtrlCore/X11Top.cpp +++ b/uppsrc/CtrlCore/X11Top.cpp @@ -105,7 +105,7 @@ void TopWindow::DefSyncTitle() } } -void TopWindow::SyncTitle0() +void TopWindow::SyncTitle() { GuiLock __; LLOG("SyncTitle: " << title); @@ -129,7 +129,7 @@ void WmState(Window w, bool set, Atom a1, Atom a2 = 0) XSendEvent(Xdisplay, Xroot, false, SubstructureNotifyMask | SubstructureRedirectMask, &e); } -void TopWindow::SyncState0() +void TopWindow::SyncState() { GuiLock __; LLOG("SyncState"); @@ -160,11 +160,11 @@ typedef struct { #define PROP_MOTIF_WM_HINTS_ELEMENTS 5 #define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS -void TopWindow::SyncCaption0() +void TopWindow::SyncCaption() { GuiLock __; LLOG("SyncCaption0"); - SyncTitle0(); + SyncTitle(); if(IsOpen() && GetWindow()) { unsigned long wina[6]; memset(wina, 0, sizeof(wina)); @@ -256,11 +256,6 @@ void TopWindow::CenterRect(Ctrl *owner) } void TopWindow::Open(Ctrl *owner) -{ - Open0(owner); -} - -void TopWindow::Open0(Ctrl *owner) { LLOG("TopWindow::Open"); GuiLock __; @@ -281,7 +276,7 @@ void TopWindow::Open0(Ctrl *owner) title2.Clear(); if(!weplace) { LLOG("SyncCaption"); - SyncCaption0(); + SyncCaption(); } LLOG("SyncSizeHints"); size_hints->flags = 0; @@ -382,7 +377,7 @@ void TopWindow::Open0(Ctrl *owner) XChangeProperty(Xdisplay, win, XAtom("XdndAware"), XA_ATOM, 32, 0, (byte *)&version, 1); - SyncState0(); + SyncState(); FixIcons(); } diff --git a/uppsrc/CtrlCore/X11Wnd.cpp b/uppsrc/CtrlCore/X11Wnd.cpp index 60ed981a9..0de6b1204 100644 --- a/uppsrc/CtrlCore/X11Wnd.cpp +++ b/uppsrc/CtrlCore/X11Wnd.cpp @@ -71,7 +71,7 @@ void Ctrl::DoPaint(const Vector& invalid) } } -void Ctrl::WndScrollView0(const Rect& r, int dx, int dy) +void Ctrl::WndScrollView(const Rect& r, int dx, int dy) { GuiLock __; if(r.IsEmpty() || !GetWindow()) return; @@ -383,11 +383,11 @@ void WakeUpGuiThread() IGNORE_RESULT(write(WakePipe[1], "\1", 1)); } -void Ctrl::GuiSleep0(int ms) +void Ctrl::GuiSleep(int ms) { GuiLock __; LLOG(GetTickCount() << " GUISLEEP " << ms); - ASSERT(IsMainThread()); + ASSERT_(IsMainThread(), "Only main thread can perform GuiSleep"); timeval timeout; timeout.tv_sec = ms / 1000; timeout.tv_usec = ms % 1000 * 1000; @@ -417,7 +417,7 @@ void Ctrl::SysEndLoop() { } -void Ctrl::EventLoop0(Ctrl *ctrl) +void Ctrl::EventLoop(Ctrl *ctrl) { GuiLock __; ASSERT_(IsMainThread(), "Event loop can only run in the main thread"); @@ -434,7 +434,7 @@ void Ctrl::EventLoop0(Ctrl *ctrl) while(loopno > EndSessionLoopNo && (ctrl ? ctrl->InLoop() && ctrl->IsOpen() : GetTopCtrls().GetCount())) { XEvent event; - GuiSleep0(granularity); + GuiSleep(granularity); SyncMousePos(); while(IsWaitingEvent()) { LTIMING("XNextEvent"); @@ -466,7 +466,7 @@ void Ctrl::SyncExpose() void Ctrl::Create(Ctrl *owner, bool redirect, bool savebits) { GuiLock __; - ASSERT(IsMainThread(), "Only main thread can create windows"); + ASSERT_(IsMainThread(), "Only main thread can create windows"); LLOG("Create " << Name() << " " << GetRect()); ASSERT(!IsChild() && !IsOpen()); LLOG("Ungrab1"); @@ -682,7 +682,7 @@ Ctrl *Ctrl::GetOwner() return q >= 0 ? Xwindow()[q].owner : NULL; } -void Ctrl::WndShow0(bool b) +void Ctrl::WndShow(bool b) { GuiLock __; LLOG("WndShow " << b); @@ -700,7 +700,7 @@ void Ctrl::WndShow0(bool b) } } -void Ctrl::WndUpdate0() +void Ctrl::WndUpdate() { GuiLock __; LTIMING("WndUpdate"); @@ -718,7 +718,7 @@ void Ctrl::WndUpdate0() } } -void Ctrl::WndUpdate0r(const Rect& r) +void Ctrl::WndUpdate(const Rect& r) { GuiLock __; LTIMING("WndUpdate Rect"); @@ -734,7 +734,7 @@ void Ctrl::WndUpdate0r(const Rect& r) xw.invalid = Subtract(xw.invalid, r, dummy); } -void Ctrl::WndSetPos0(const Rect& r) +void Ctrl::WndSetPos(const Rect& r) { GuiLock __; if(!top) return; @@ -882,11 +882,10 @@ void Ctrl::KillFocus(Window window) w.ctrl->KillFocusWnd(); } -void Ctrl::SetWndFocus0(bool *b) +bool Ctrl::SetWndFocus() { GuiLock __; LLOG("SetWndFocus " << Name()); - *b = false; if(top && top->window != focusWindow && IsEnabled() && IsVisible()) { LLOG("Setting focus... "); LTIMING("XSetInfputFocus"); @@ -897,8 +896,9 @@ void Ctrl::SetWndFocus0(bool *b) focusWindow = top->window; SetFocusWnd(); } - *b = true; + return true; } + return false; } bool Ctrl::HasWndFocus() const @@ -1010,7 +1010,7 @@ void Ctrl::WndInvalidateRect(const Rect& r) Invalidate(Xwindow().Get(top->window), r); } -void Ctrl::SetWndForeground0() +void Ctrl::SetWndForeground() { GuiLock __; LLOG("SetWndForeground " << Name()); @@ -1037,20 +1037,16 @@ bool Ctrl::IsWndForeground() const return ~focusCtrlWnd == (q ? q : GetTopCtrl()); } -void Ctrl::WndEnable0(bool *b) +void Ctrl::WndEnable(bool b) { GuiLock __; LLOG("WndEnable"); - if(!top) { - *b = false; - return; - } - if(!*b) { + if(!top) return; + if(!b) { ReleaseCapture(); if(HasWndFocus()) XSetInputFocus(Xdisplay, None, RevertToPointerRoot, CurrentTime); } - *b = true; } // 01/12/2007 - mdelfede diff --git a/uppsrc/CtrlCore/src.tpp/Ctrl$en-us.tpp b/uppsrc/CtrlCore/src.tpp/Ctrl$en-us.tpp index bc21fea66..5fdd81a7e 100644 --- a/uppsrc/CtrlCore/src.tpp/Ctrl$en-us.tpp +++ b/uppsrc/CtrlCore/src.tpp/Ctrl$en-us.tpp @@ -2298,7 +2298,8 @@ view or frame coordinates.&] HWND_[*@3 hwnd], [@(0.0.255) bool]_[*@3 savebits]_`=_[@(0.0.255) true], [@(0.0.255) bool]_[*@3 activate]_`=_[@(0.0.255) true], [@(0.0.255) bool]_[*@3 dropshadow]_`= _[@(0.0.255) false], [@(0.0.255) bool]_[*@3 topmost]_`=_[@(0.0.255) false])&] -[s2;b17;a17; Opens top`-level Ctrl as pop`-up window.&] +[s2;b17;a17; Opens top`-level Ctrl as pop`-up window. [*/ This method +can only be invoked in the main thread.]&] [s6; [2 Win32 specific.]&] [s7;i1120;a17; [%-*C@3 hwnd]-|Win32 handle of owner window.&] [s7;i1120;a17; [%-*C@3 savebits]-|Indicates that system should try to @@ -2313,7 +2314,8 @@ preserve background bits.&] trl]_`*[*@3 owner]_`=_NULL, [@(0.0.255) bool]_[*@3 savebits]_`=_[@(0.0.255) true], [@(0.0.255) bool]_[*@3 activate]_`=_[@(0.0.255) true], [@(0.0.255) bool]_[*@3 dropshadow]_`= _[@(0.0.255) false], [@(0.0.255) bool]_[*@3 topmost]_`=_[@(0.0.255) false])&] -[s2;b17;a17; Opens top`-level Ctrl as pop`-up window.&] +[s2;b17;a17; Opens top`-level Ctrl as pop`-up window. [*/ This method +can only be invoked in the main thread.]&] [s7;i1120;a17; [%-*C@3 owner]-|Owner.&] [s7;i1120;a17; [%-*C@3 savebits]-|Indicates that system should try to preserve background bits.&] @@ -2362,15 +2364,16 @@ were processed, false that queue was empty.&] [s4;%- &] [s5;:Ctrl`:`:IsPopUp`(`)const:%- [@(0.0.255) bool]_[* IsPopUp]()_[@(0.0.255) const]&] [s7;i1120;a17; [*/ Return value]-|True if Ctrl is pop`-up window.&] -[s3;%- &] +[s3; &] [s4;%- &] -[s5;:Ctrl`:`:EventLoop`(`:`:Ctrl`*`):%- [@(0.0.255) static] [@(0.0.255) void]_[* EventLoop]( -[_^`:`:Ctrl^ Ctrl]_`*[*@3 loopctrl]_`=_NULL)&] +[s5;:Ctrl`:`:EventLoop`(Ctrl`*`):%- [@(0.0.255) static] [@(0.0.255) void]_[* EventLoop]([_^`:`:Ctrl^ C +trl]_`*[*@3 loopctrl]_`=_NULL)&] [s2;b17;a17; Executes event`-loop. If [*@3 loopctrl ]is not NULL, it must be opened top`-level Ctrl and loop is executed until EndLoop method for [*@3 loopctrl ]is invoked. If [*@3 loopctrl] is NULL, loop is executed as long as any top`-level Ctrl exists or application -is terminated by OS specific `"shutdown`" event.&] +is terminated by OS specific `"shutdown`" event. [*/ This method +can only be invoked in the main thread.]&] [s7;i1120;a17; [%-*C@3 loopctrl]-|Looping Ctrl.&] [s3;%- &] [s4;%- &] @@ -2612,7 +2615,7 @@ does is platform specific).&] nt]_[*@3 ms])&] [s2;b17;a17; Sleeps (while allowing other applications or threads to run) for at least [*@3 ms] milliseconds or until new input event -is available.&] +is available. [*/ This method can only be invoked in the main thread.]&] [s7;i1120;a17; [%-*@3 ms]-|Time to sleep.&] [s3; &] [s4;%- &] @@ -2622,7 +2625,11 @@ allback]_[*@3 cb])&] for GUI). It works by posting callback into timer queue (with zero delay), then waits its completion using Semaphore. Main GUI thread has to run timer queue management for callback to -be executed (by running event`-loop (TopWindow`::Run) or ProcessEvents).&] +be executed (by running event`-loop (TopWindow`::Run) or ProcessEvents). +Warning: Call unlocks GuiLock so that the main thread can run +on GUI, this is possible source of race`-conditions. Be prepared +that some other code can run on GUI between call to Call and +cb being executed!&] [s3; &] [s4;%- &] [s5;:Ctrl`:`:IsShutdownThreads`(`):%- [@(0.0.255) static] [@(0.0.255) bool]_[* IsShutdownTh