From abd07eef4df050481377c285cff3e4437e6e954a Mon Sep 17 00:00:00 2001
From: TwinFan <twinfan@sonux.net>
Date: Sat, 11 Jul 2020 00:00:47 +0200
Subject: [PATCH] Create/show Msg Area only from XP main thread / fix welcome
 msg

not showing during startup
---
 Include/Constants.h |   2 +-
 Include/DataRefs.h  |   3 ++
 Include/TextIO.h    |   3 ++
 LiveTraffic.aps     | Bin 2720 -> 2720 bytes
 LiveTraffic.rc      | Bin 5254 -> 5254 bytes
 Src/LTAircraft.cpp  |   3 ++
 Src/LTMain.cpp      |   3 ++
 Src/LiveTraffic.cpp |  19 ++++----
 Src/TextIO.cpp      | 108 +++++++++++++++++++++++++++-----------------
 docs/readme.html    |  14 +++++-
 10 files changed, 104 insertions(+), 51 deletions(-)

diff --git a/Include/Constants.h b/Include/Constants.h
index 1f28ce21..b1979e9c 100644
--- a/Include/Constants.h
+++ b/Include/Constants.h
@@ -29,7 +29,7 @@
 //
 // MARK: Version Information (CHANGE VERSION HERE)
 //
-constexpr float VERSION_NR = 2.06f;
+constexpr float VERSION_NR = 2.07f;
 constexpr bool VERSION_BETA = true;
 extern float verXPlaneOrg;          // version on X-Plane.org
 extern int verDateXPlaneOrg;        // and its date
diff --git a/Include/DataRefs.h b/Include/DataRefs.h
index 1f6fa0bd..249e0aae 100644
--- a/Include/DataRefs.h
+++ b/Include/DataRefs.h
@@ -488,6 +488,7 @@ class DataRefs
 
 //MARK: Provided Data, i.e. global variables
 protected:
+    std::thread::id xpThread;        ///< id of X-Plane's thread (when it is OK to use XP API calls)
     XPLMPluginID pluginID       = 0;
     logLevelTy iLogLevel        = logWARN;
     logLevelTy iMsgAreaLevel    = logINFO;
@@ -587,6 +588,8 @@ class DataRefs
 
 //MARK: DataRef access
 public:
+    void ThisThreadIsXP() { xpThread = std::this_thread::get_id();  }
+    bool IsXPThread() const { return std::this_thread::get_id() == xpThread; }
     inline float GetMiscNetwTime() const        { return XPLMGetDataf(adrXP[DR_MISC_NETW_TIME]); }
     inline float GetLocalTimeSec() const        { return XPLMGetDataf(adrXP[DR_LOCAL_TIME_SEC]); }
     inline int   GetLocalDateDays() const       { return XPLMGetDatai(adrXP[DR_LOCAL_DATE_DAYS]); }
diff --git a/Include/TextIO.h b/Include/TextIO.h
index f2d5448a..312e1903 100644
--- a/Include/TextIO.h
+++ b/Include/TextIO.h
@@ -106,6 +106,9 @@ XPLMWindowID CreateMsgWindow(float fTimeToDisplay, logLevelTy lvl, const char* s
 /// Show the special text "Seeing aircraft...showing..."
 XPLMWindowID CreateMsgWindow(float fTimeToDisplay, int numSee, int numShow, int bufTime);
 
+/// Check if message wait to be shown, then show
+bool CheckThenShowMsgWindow();
+
 // Destroys the windows (if still active)
 void DestroyWindow();
 
diff --git a/LiveTraffic.aps b/LiveTraffic.aps
index e104c1f730dca26d9e472dd5f6b637d22b4a212f..2dcda47191590b6e715af14cb15b8dc11d9f594d 100644
GIT binary patch
delta 36
ocmZ1=x<GV88!IO}0|NsS5VLRYXJuq$G~Yat%^gJDWIxUX0FbN*W&i*H

delta 36
ocmZ1=x<GV88!IOp0|NsS5VLLWXJuq$G}}Cp%^gJDWIxUX0FY@2VgLXD

diff --git a/LiveTraffic.rc b/LiveTraffic.rc
index 210835bebf096497f793de8b9542a561524b91c1..bc5c7a5fc971f065f5ed15ae61ae1ef52db67cb9 100644
GIT binary patch
delta 38
rcmZqEY}4FuiIvfO@?};-M)S?AY|oj1)LRZwAT{|dhxBGS?hH-<^sx)L

delta 38
rcmZqEY}4FuiIvf8@?};-MzhVVY|oj1)LRZwAT{|dhxBGS?hH-<^k56L

diff --git a/Src/LTAircraft.cpp b/Src/LTAircraft.cpp
index 90701b8e..f318fcc1 100644
--- a/Src/LTAircraft.cpp
+++ b/Src/LTAircraft.cpp
@@ -73,6 +73,9 @@ bool NextCycle (int newCycle)
     
     // the time that has passed since the last cycle
     currCycle.diffTime  = currCycle.simTime - prevCycle.simTime;
+
+    // Quickly test if we need to show a window
+    CheckThenShowMsgWindow();
     
     // tell multiplayer lib if we want to see labels
     // (these are very quick calls only setting a variable)
diff --git a/Src/LTMain.cpp b/Src/LTMain.cpp
index 6d807d89..201fc4a0 100644
--- a/Src/LTMain.cpp
+++ b/Src/LTMain.cpp
@@ -290,6 +290,9 @@ float LoopCBAircraftMaintenance (float inElapsedSinceLastCall, float, int, void*
         // *** check for new positons that require terrain altitude (Y Probes) ***
         // LiveTraffic Top Level Exception handling: catch all, reinit if something happens
         try {
+            // Check if some msg window needs to show
+            CheckThenShowMsgWindow();
+
             // handle new network data (that func has a short-cut exit if nothing to do)
             LTFlightData::AppendAllNewPos();
             
diff --git a/Src/LiveTraffic.cpp b/Src/LiveTraffic.cpp
index 841ae7d2..ed635c77 100755
--- a/Src/LiveTraffic.cpp
+++ b/Src/LiveTraffic.cpp
@@ -384,6 +384,14 @@ float LoopCBOneTimeSetup (float, float, int, void*)
     
     switch (eOneTimeState) {
         case ONCE_CB_ADD_DREFS:
+            // Create a message window and say hello
+            SHOW_MSG(logINFO, MSG_WELCOME, LT_VERSION_FULL);
+            if constexpr (VERSION_BETA)
+                SHOW_MSG(logWARN, BETA_LIMITED_VERSION, LT_BETA_VER_LIMIT_TXT);
+#ifdef DEBUG
+            SHOW_MSG(logWARN, DBG_DEBUG_BUILD);
+#endif
+
             // loop over all available data ref editor signatures
             for (const char* szDREditor: DATA_REF_EDITORS) {
                 // find the plugin by signature
@@ -452,6 +460,9 @@ PLUGIN_API int XPluginStart(
         strncpy_s(outName, 255, LIVE_TRAFFIC,       100);
         strncpy_s(outSig,  255, PLUGIN_SIGNATURE,   100);
         strncpy_s(outDesc, 255, PLUGIN_DESCRIPTION, 100);
+
+        // Keep track of this thread's id
+        dataRefs.ThisThreadIsXP();
         
 #ifdef DEBUG
         // install error handler
@@ -518,14 +529,6 @@ PLUGIN_API int  XPluginEnable(void)
         // Enable showing aircraft
         if (!LTMainEnable()) return 0;
 
-        // Create a message window and say hello
-        SHOW_MSG(logINFO, MSG_WELCOME, LT_VERSION_FULL);
-        if constexpr (VERSION_BETA)
-            SHOW_MSG(logWARN, BETA_LIMITED_VERSION, LT_BETA_VER_LIMIT_TXT);
-#ifdef DEBUG
-        SHOW_MSG(logWARN, DBG_DEBUG_BUILD);
-#endif
-        
         // Success
         return 1;
 
diff --git a/Src/TextIO.cpp b/Src/TextIO.cpp
index ca8cd086..fb54bc34 100644
--- a/Src/TextIO.cpp
+++ b/Src/TextIO.cpp
@@ -82,6 +82,7 @@ posStr(_fd.Positions2String())
 
 // An opaque handle to the window we will create
 XPLMWindowID    g_window = 0;
+bool            g_visible = false;      ///< window visible? (locally to avoid API calls)
 // when to remove the window
 float           fTimeRemove = NAN;
 
@@ -176,7 +177,7 @@ void    draw_msg(XPLMWindowID in_window_id, void * /*in_refcon*/)
             fTimeRemove = currTime + WIN_TIME_REMAIN;
         else if (currTime >= fTimeRemove) {
             // time's up: remove
-            XPLMSetWindowIsVisible ( g_window, false );
+            XPLMSetWindowIsVisible ( g_window, g_visible=false );
             fTimeRemove = NAN;
         }
     }
@@ -194,38 +195,12 @@ int dummy_wheel_handler(XPLMWindowID /*in_window_id*/, int /*x*/, int /*y*/, int
 void dummy_key_handler(XPLMWindowID /*in_window_id*/, char /*key*/, XPLMKeyFlags /*flags*/, char /*virtual_key*/, void * /*in_refcon*/, int /*losing_focus*/)
 { }
 
-
-//MARK: custom X-Plane message Window - Create / Destroy
-XPLMWindowID CreateMsgWindow(float fTimeToDisplay, logLevelTy lvl, const char* szMsg, ...)
+/// Create/show the message window
+XPLMWindowID DoShowMsgWindow()
 {
-    // consider configured level for msg area
-    if ( lvl < dataRefs.GetMsgAreaLevel())
-        return g_window;
-    
-    // put together the formatted message if given
-    if (szMsg) {
-        va_list args;
-        char aszMsgTxt[500];
-        va_start (args, szMsg);
-        vsnprintf(aszMsgTxt,
-                  sizeof(aszMsgTxt),
-                  szMsg,
-                  args);
-        va_end (args);
-    
-        // define the text to display:
-        dispTextTy dispTxt = {
-            // set the timer if a limit is given
-            fTimeToDisplay >= 0.0f ? dataRefs.GetMiscNetwTime() + fTimeToDisplay : 0,
-            // log level to define the color
-            lvl,
-            // finally the text
-            aszMsgTxt
-        };
-        
-        // add to list of display texts
-        listTexts.emplace_back(std::move(dispTxt));
-    }
+    // must only do so if executed from XP's main thread
+    if (!dataRefs.IsXPThread())
+        return nullptr;
 
     // Create the message window
     XPLMCreateWindow_t params;
@@ -243,26 +218,26 @@ XPLMWindowID CreateMsgWindow(float fTimeToDisplay, logLevelTy lvl, const char* s
     params.layer = xplm_WindowLayerFloatingWindows;
     // No decoration...this is just message output and shall stay where it is
     params.decorateAsFloatingWindow = xplm_WindowDecorationNone;
-    
+
     // Set the window's initial bounds
     // Note that we're not guaranteed that the main monitor's lower left is at (0, 0)...
     // We'll need to query for the global desktop bounds!
     LT_GetScreenSize(params.left, params.top, params.right, params.bottom,
-                     LT_SCR_RIGHT_TOP_MOST);
-    
+        LT_SCR_RIGHT_TOP_MOST);
+
     // define a window in the top right corner,
     // WIN_FROM_TOP point down from the top, WIN_WIDTH points wide,
     // enough height for all lines of text
     params.top -= WIN_FROM_TOP;
     params.right -= WIN_FROM_RIGHT;
     params.left = params.right - WIN_WIDTH;
-    params.bottom = params.top - (WIN_ROW_HEIGHT * (2*int(listTexts.size())+1+
-                                                    (needSeeingShowMsg() ? 2 : 0)));
-    
+    params.bottom = params.top - (WIN_ROW_HEIGHT * (2 * int(listTexts.size()) + 1 +
+        (needSeeingShowMsg() ? 2 : 0)));
+
     // if the window still exists just resize it
     if (g_window) {
-        if (!XPLMGetWindowIsVisible( g_window))
-            XPLMSetWindowIsVisible ( g_window, true );
+        if (!XPLMGetWindowIsVisible(g_window))
+            XPLMSetWindowIsVisible(g_window, true);
         XPLMSetWindowGeometry(g_window, params.left, params.top, params.right, params.bottom);
     }
     else {
@@ -270,10 +245,47 @@ XPLMWindowID CreateMsgWindow(float fTimeToDisplay, logLevelTy lvl, const char* s
         g_window = XPLMCreateWindowEx(&params);
         LOG_ASSERT(g_window);
     }
-    
+    g_visible = true;
+
     return g_window;
 }
 
+//MARK: custom X-Plane message Window - Create / Destroy
+XPLMWindowID CreateMsgWindow(float fTimeToDisplay, logLevelTy lvl, const char* szMsg, ...)
+{
+    // consider configured level for msg area
+    if ( lvl < dataRefs.GetMsgAreaLevel())
+        return g_window;
+    
+    // put together the formatted message if given
+    if (szMsg) {
+        va_list args;
+        char aszMsgTxt[500];
+        va_start (args, szMsg);
+        vsnprintf(aszMsgTxt,
+                  sizeof(aszMsgTxt),
+                  szMsg,
+                  args);
+        va_end (args);
+    
+        // define the text to display:
+        dispTextTy dispTxt = {
+            // set the timer if a limit is given
+            fTimeToDisplay >= 0.0f ? dataRefs.GetMiscNetwTime() + fTimeToDisplay : 0,
+            // log level to define the color
+            lvl,
+            // finally the text
+            aszMsgTxt
+        };
+        
+        // add to list of display texts
+        listTexts.emplace_back(std::move(dispTxt));
+    }
+
+    // Show the window
+    return DoShowMsgWindow();
+}
+
 
 // Show the special text "Seeing aircraft...showing..."
 XPLMWindowID CreateMsgWindow(float fTimeToDisplay, int numSee, int numShow, int bufTime)
@@ -285,12 +297,26 @@ XPLMWindowID CreateMsgWindow(float fTimeToDisplay, int numSee, int numShow, int
 }
 
 
+// Check if message wait to be shown, then show
+bool CheckThenShowMsgWindow()
+{
+    if ((!listTexts.empty() || needSeeingShowMsg()) &&      // something to show
+        (!g_window || !g_visible))                          // no window/visible
+    {
+        DoShowMsgWindow();
+        return true;
+    }
+    return false;
+}
+
+
 void DestroyWindow()
 {
     if ( g_window )
     {
         XPLMDestroyWindow(g_window);
         g_window = NULL;
+        g_visible = false;
         listTexts.clear();
    }
 }
diff --git a/docs/readme.html b/docs/readme.html
index d5a52b1d..15af306a 100755
--- a/docs/readme.html
+++ b/docs/readme.html
@@ -85,13 +85,25 @@ <h1>Release Notes</h1>
 
     <h2>v2.0</h2>
 
-    <h3>v2.06</h3>
+    <h3>v2.07</h3>
 
     <P>Please follow
         <a href="https://twinfan.gitbook.io/livetraffic/setup/installation/upgrading-from-v1.5-to-v2.0">upgrade instructions</a>
         for upgrading an existing LiveTraffic v1.5 (or earlier) installation to version 2.0.
     </P>
 
+    <P>For updating coming from v2.06 just copy <code>lin|mac|win_x64/LiveTraffic.xpl</code>.
+	
+    <P>Change log:</P>
+
+    <ul>
+		<li>FIXED a crash when entering/changing the ADS-B Exchange API key that came up with XP11.50b14.
+		    <a href="https://forums.x-plane.org/index.php?/forums/topic/221016-adsbx-key-test-ctd-xplane-11b13/&do=findComment&comment=1988830">See here.</a></li>
+		<li>FIXED welcome message and beta warning not showing on startup.</li>
+	</ul>
+
+    <h3>v2.06</h3>
+
     <P>For updating coming from v2.05
        <ul>
            <li>copy