Author: bgstack15
Last-Modified: 2026-07-02
Last-Version: 14.10
Description:
 Disable some functionality that depends on wx3.3 which is not yet in Debian. Unfortunately, this includes dark mode. See also the second patch appended to the bottom of this one.
--- a/wx+/darkmode.h
+++ b/wx+/darkmode.h
@@ -9,6 +9,7 @@
 
 #include <zen/file_error.h>
 #include <wx/app.h>
+#include <wx/settings.h>
 
 
 namespace zen
@@ -16,7 +17,8 @@ namespace zen
 bool darkModeAvailable();
 
 //support not only "dark mode" but dark themes in general
-using ColorTheme = wxApp::Appearance; //why reinvent the wheel?
+enum Appearance { System, Light, Dark };
+using ColorTheme = Appearance; //why reinvent the wheel?
 
 void colorThemeInit(wxApp& app, ColorTheme colTheme); //throw FileError
 void colorThemeCleanup();
@@ -25,4 +27,28 @@ bool equalAppearance(ColorTheme colTheme
 void changeColorTheme(ColorTheme colTheme); //throw FileError
 }
 
+struct wxColorHook
+{
+    virtual ~wxColorHook() {}
+    virtual wxColour getColor(wxSystemColour index) const = 0;
+};
+WXDLLIMPEXP_CORE inline std::unique_ptr<wxColorHook>& refGlobalColorHook()
+{
+    static std::unique_ptr<wxColorHook> globalColorHook;
+    return globalColorHook;
+}
+
+
+class WXDLLIMPEXP_CORE wxSystemSettings2 : public wxSystemSettingsNative
+{
+public:
+    static wxColour GetColour(wxSystemColour index)
+    {
+        if (refGlobalColorHook())
+			return refGlobalColorHook()->getColor(index);
+
+        return wxSystemSettingsNative::GetColour(index);
+    }
+};
+
 #endif //DARKMODE_H_754298057018
--- a/FreeFileSync/Source/ui/cfg_grid.cpp
+++ b/FreeFileSync/Source/ui/cfg_grid.cpp
@@ -531,7 +531,7 @@ private:
             }
     }
 
-    int getBestSize(const wxReadOnlyDC& dc, size_t row, ColumnType colType) override
+    int getBestSize(wxDC& dc, size_t row, ColumnType colType) override
     {
         // -> synchronize renderCell() <-> getBestSize()
 
@@ -550,7 +550,7 @@ private:
         return 0;
     }
 
-    HoverArea getMouseHover(const wxReadOnlyDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) override
+    HoverArea getMouseHover(wxDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) override
     {
         if (const ConfigView::Details* item = cfgView_.getItem(row))
         {
--- a/FreeFileSync/Source/ui/log_panel.cpp
+++ b/FreeFileSync/Source/ui/log_panel.cpp
@@ -245,7 +245,7 @@ public:
             }
     }
 
-    int getBestSize(const wxReadOnlyDC& dc, size_t row, ColumnType colType) override
+    int getBestSize(wxDC& dc, size_t row, ColumnType colType) override
     {
         // -> synchronize renderCell() <-> getBestSize()
 
@@ -266,7 +266,7 @@ public:
 
     static int getColumnTimeDefaultWidth(Grid& grid)
     {
-        wxInfoDC dc(&grid.getMainWin());
+        wxClientDC dc(&grid.getMainWin());
         dc.SetFont(grid.getMainWin().GetFont());
         return 2 * getColumnGapLeft() + dc.GetTextExtent(utfTo<wxString>(formatTime(formatTimeTag))).GetWidth();
     }
--- a/FreeFileSync/Source/ui/rename_dlg.cpp
+++ b/FreeFileSync/Source/ui/rename_dlg.cpp
@@ -155,7 +155,7 @@ public:
         }
     }
 
-    int getBestSize(const wxReadOnlyDC& dc, size_t row, ColumnType colType) override
+    int getBestSize(wxDC& dc, size_t row, ColumnType colType) override
     {
         // -> synchronize renderCell() <-> getBestSize()
         return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * getColumnGapLeft() + dipToWxsize(1); //gap on left and right side + border
@@ -282,12 +282,13 @@ RenameDialog::RenameDialog(wxWindow* par
             longNames.resize(10);
         }
 
-        wxInfoDC infoDc(m_gridRenamePreview);
-        infoDc.SetFont(m_gridRenamePreview->GetFont()); //the font parameter of GetTextExtent() is not evaluated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
+        wxMemoryDC dc;
+        setScaleFactor(dc, getScreenDpiScale());
+        dc.SetFont(m_gridRenamePreview->GetFont()); //the font parameter of GetTextExtent() is not evaluated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
 
         int maxStringWidth = 0;
         for (const std::wstring& str : longNames)
-            maxStringWidth = std::max(maxStringWidth, infoDc.GetTextExtent(str).GetWidth());
+            maxStringWidth = std::max(maxStringWidth, dc.GetTextExtent(str).GetWidth());
 
         const int defaultColWidthOld = maxStringWidth + 2 * GridData::getColumnGapLeft() + dipToWxsize(1) /*border*/ + dipToWxsize(10) /*extra space: less cramped*/;
         const int defaultColWidthNew = maxStringWidth + 2 * GridData::getColumnGapLeft() + dipToWxsize(1) /*border*/ + dipToWxsize(50) /*extra space: for longer new name*/;
@@ -315,10 +316,11 @@ RenameDialog::RenameDialog(wxWindow* par
         m_staticlinePreview               ->Hide();
         m_staticTextPlaceholderDescription->Hide();
 
-        wxInfoDC infoDc(m_textCtrlNewName);
-        infoDc.SetFont(m_textCtrlNewName->GetFont()); //the font parameter of GetTextExtent() is not evaluated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
+        wxMemoryDC dc; //the context used for bitmaps
+        setScaleFactor(dc, getScreenDpiScale());
+        dc.SetFont(m_textCtrlNewName->GetFont()); //the font parameter of GetTextExtent() is not evaluated on OS X, wxWidgets 2.9.5, so apply it to the DC directly!
 
-        const int textCtrlDefaultWidth = std::min(infoDc.GetTextExtent(renamePhrase).GetWidth() + 20 /*borders (non-DIP!)*/ +
+        const int textCtrlDefaultWidth = std::min(dc.GetTextExtent(renamePhrase).GetWidth() + 20 /*borders (non-DIP!)*/ +
                                                   dipToWxsize(50) /*extra space: for longer new name*/,
                                                   dipToWxsize(900));
         m_textCtrlNewName->SetMinSize({textCtrlDefaultWidth, -1});
--- a/FreeFileSync/Source/ui/tree_grid.cpp
+++ b/FreeFileSync/Source/ui/tree_grid.cpp
@@ -935,7 +935,7 @@ private:
         }
     }
 
-    int getBestSize(const wxReadOnlyDC& dc, size_t row, ColumnType colType) override
+    int getBestSize(wxDC& dc, size_t row, ColumnType colType) override
     {
         // -> synchronize renderCell() <-> getBestSize() <-> getMouseHover()
 
@@ -953,7 +953,7 @@ private:
                    2 * gapSize_; //include gap from right!
     }
 
-    HoverArea getMouseHover(const wxReadOnlyDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) override
+    HoverArea getMouseHover(wxDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) override
     {
         if (static_cast<ColumnTypeOverview>(colType) == ColumnTypeOverview::folder)
             if (std::unique_ptr<TreeView::Node> node = getDataView().getLine(row))
--- a/wx+/grid.cpp
+++ b/wx+/grid.cpp
@@ -61,6 +61,10 @@ namespace
 {
 //------------------------------ Grid Parameters --------------------------------
 wxColor getColorLabelText(bool enabled) { return wxSystemSettings::GetColour(enabled ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_GRAYTEXT); }
+#if !wxCHECK_VERSION(3,3,2)
+wxColor getColorGridLine()              { return wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW); }
+#endif
+
 
 wxColor getColorLabelGradientFrom()
 {
@@ -164,7 +168,7 @@ void GridData::renderCell(wxDC& dc, cons
 }
 
 
-int GridData::getBestSize(const wxReadOnlyDC& dc, size_t row, ColumnType colType)
+int GridData::getBestSize(wxDC& dc, size_t row, ColumnType colType)
 {
     return dc.GetTextExtent(getValue(row, colType)).GetWidth() + 2 * getColumnGapLeft() + dipToWxsize(1); //gap on left and right side + border
 }
@@ -172,7 +176,11 @@ int GridData::getBestSize(const wxReadOn
 
 wxRect GridData::drawCellBorder(wxDC& dc, const wxRect& rect) //returns remaining rectangle
 {
+#if wxCHECK_VERSION(3,3,2)
     drawRectangleBorder(dc, rect, wxSystemSettings::GetColour(wxSYS_COLOUR_GRIDLINES), dipToWxsize(1), wxRIGHT | wxBOTTOM);
+#else
+    drawRectangleBorder(dc, rect, getColorGridLine(), dipToWxsize(1), wxRIGHT | wxBOTTOM);
+#endif
 
     return {rect.x, rect.y, rect.width - dipToWxsize(1), rect.height - dipToWxsize(1)};
 }
@@ -471,7 +479,7 @@ public:
 
     int getBestWidth(ptrdiff_t rowFrom, ptrdiff_t rowTo)
     {
-        wxInfoDC dc(this);
+        wxClientDC dc(this);
         dc.SetFont(GetFont()); //harmonize with RowLabelWin::render()!
 
         int bestWidth = 0;
@@ -1106,7 +1114,7 @@ private:
             {
                 if (0 <= row && row < rowCount && cpi.colType != ColumnType::none)
                 {
-                    wxInfoDC dc(this);
+                    wxClientDC dc(this);
                     dc.SetFont(GetFont());
                     return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth);
                 }
@@ -1147,7 +1155,7 @@ private:
             {
                 if (0 <= row && row < rowCount && cpi.colType != ColumnType::none)
                 {
-                    wxInfoDC dc(this);
+                    wxClientDC dc(this);
                     dc.SetFont(GetFont());
                     return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth);
                 }
@@ -1277,7 +1285,7 @@ private:
             {
                 if (0 <= row && row < rowCount && cpi.colType != ColumnType::none)
                 {
-                    wxInfoDC dc(this);
+                    wxClientDC dc(this);
                     dc.SetFont(GetFont());
                     return prov->getMouseHover(dc, row, cpi.colType, cpi.cellRelativePosX, cpi.colWidth);
                 }
@@ -2266,7 +2274,8 @@ int Grid::getBestColumnSize(size_t col)
     {
         const ColumnType type = visibleCols_[col].type;
 
-        wxInfoDC dc(mainWin_);
+        //wxInfoDC dc(mainWin_);
+        wxClientDC dc(mainWin_);
         dc.SetFont(mainWin_->GetFont()); //harmonize with MainWin::render()
 
         const auto& [rowFirst, rowLast] = getVisibleRows(mainWin_->GetClientRect());
--- a/wx+/grid.h
+++ b/wx+/grid.h
@@ -107,8 +107,8 @@ public:
     virtual std::wstring getValue(size_t row, ColumnType colType) const = 0;
     virtual void         renderRowBackgound(wxDC& dc, const wxRect& rect, size_t row,                     bool enabled, bool selected, HoverArea rowHover); //default implementation
     virtual void         renderCell        (wxDC& dc, const wxRect& rect, size_t row, ColumnType colType, bool enabled, bool selected, HoverArea rowHover);
-    virtual int          getBestSize  (const wxReadOnlyDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()!
-    virtual HoverArea    getMouseHover(const wxReadOnlyDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) { return HoverArea::none; }
+    virtual int          getBestSize  (wxDC& dc, size_t row, ColumnType colType); //must correspond to renderCell()!
+    virtual HoverArea    getMouseHover(wxDC& dc, size_t row, ColumnType colType, int cellRelativePosX, int cellWidth) { return HoverArea::none; }
     virtual std::wstring getToolTip                           (size_t row, ColumnType colType, HoverArea rowHover) { return std::wstring(); }
 
     //label area:
--- a/FreeFileSync/Source/ui/gui_status_handler.cpp
+++ b/FreeFileSync/Source/ui/gui_status_handler.cpp
@@ -70,27 +70,34 @@ void StatusHandlerTemporaryPanel::showSt
                 //case wxAUI_DOCK_CENTRE:
         }
 
+        wxAuiPaneInfoArray& paneArray = mainDlg_.auiMgr_.GetAllPanes();
         const bool statusRowTaken = [&]
         {
-            for (wxAuiPaneInfo& paneInfo : mainDlg_.auiMgr_.GetAllPanes())
+            for (size_t i = 0; i < paneArray.size(); ++i)
+            {
+                const wxAuiPaneInfo& paneInfo = paneArray[i];
                 //doesn't matter if paneInfo.IsShown() or not! => move down in either case!
                 if (&paneInfo != &statusPanel &&
                     paneInfo.dock_layer     == statusPanel.dock_layer &&
                     paneInfo.dock_direction == statusPanel.dock_direction &&
                     paneInfo.dock_row       == statusPanel.dock_row)
                     return true;
+            }
 
             return false;
         }();
 
         //move all rows that are in the way one step further
         if (statusRowTaken)
-            for (wxAuiPaneInfo& paneInfo : mainDlg_.auiMgr_.GetAllPanes())
+            for (size_t i = 0; i < paneArray.size(); ++i)
+            {
+                wxAuiPaneInfo& paneInfo = paneArray[i];
                 if (&paneInfo != &statusPanel &&
                     paneInfo.dock_layer     == statusPanel.dock_layer &&
                     paneInfo.dock_direction == statusPanel.dock_direction &&
                     paneInfo.dock_row       >= statusPanel.dock_row)
                     ++paneInfo.dock_row;
+            }
         //------------------------------------------------------------------
 
         statusPanel.Show();
--- a/FreeFileSync/Source/ui/main_dlg.cpp
+++ b/FreeFileSync/Source/ui/main_dlg.cpp
@@ -1274,8 +1274,9 @@ void MainDialog::setGlobalCfgOnInit(cons
 
     //work around wxAuiManager::LoadPerspective overwriting pane captions with old values (might be different language!)
     std::vector<std::pair<wxAuiPaneInfo*, wxString>> paneCaptions;
-    for (wxAuiPaneInfo& paneInfo : auiMgr_.GetAllPanes())
-        paneCaptions.emplace_back(&paneInfo, paneInfo.caption);
+    wxAuiPaneInfoArray& paneArray = auiMgr_.GetAllPanes();
+    for (size_t i = 0; i < paneArray.size(); ++i)
+        paneCaptions.emplace_back(&paneArray[i], paneArray[i].caption);
 
     //compare progress dialog minimum sizes are layout-dependent + can't be changed by user => don't load stale values from config
     std::vector<std::tuple<wxAuiPaneInfo*, wxSize /*min size*/, wxSize /*best size*/>> paneConstraints;
@@ -3142,7 +3143,14 @@ void MainDialog::onSetLayoutContext(wxMo
 
     bool addedSeparator = false;
 
+#if wxCHECK_VERSION(3,3,0)
     for (wxAuiPaneInfo& paneInfo : auiMgr_.GetAllPanes())
+#else
+    const wxAuiPaneInfoArray& paneArray = auiMgr_.GetAllPanes();
+    for (size_t i = 0; i < paneArray.size(); ++i)
+    {
+        wxAuiPaneInfo& paneInfo = paneArray[i];
+#endif
         if (!paneInfo.IsShown() &&
             paneInfo.window != compareStatus_->getAsWindow() &&
             paneInfo.window != m_panelLog                    &&
@@ -3160,6 +3168,9 @@ void MainDialog::onSetLayoutContext(wxMo
                 this->auiMgr_.Update();
             });
         }
+#if !wxCHECK_VERSION(3,3,0)
+    }
+#endif
 
     menu.popup(*this);
 }
--- a/FreeFileSync/Source/ui/small_dlgs.cpp
+++ b/FreeFileSync/Source/ui/small_dlgs.cpp
@@ -1566,7 +1566,7 @@ OptionsDlg::OptionsDlg(wxWindow* parent,
 
         class : public wxGridColumnHeaderRendererDefault
         {
-            void DrawHighlighted(const wxGrid& grid, wxDC& dc, wxRect& rect, int col, int flags) const override { DrawBorder(grid, dc, rect); }
+            void DrawHighlighted(const wxGrid& grid, wxDC& dc, wxRect& rect, int col, int flags) const { DrawBorder(grid, dc, rect); }
         } colRenderNoHighlight_;
     };
     m_gridCustomCommand->GetTable()->SetAttrProvider(new wxGridCellAttrProviderNoColHighlight);
--- a/wx+/darkmode.cpp
+++ b/wx+/darkmode.cpp
@@ -53,7 +53,8 @@ void zen::colorThemeInit(wxApp& app, Col
 {
     assert(!refGlobalColorHook());
 
-    globalDefaultThemeIsDark = wxSystemSettings::GetAppearance().AreAppsDark();
+    //globalDefaultThemeIsDark = wxSystemSettings2::GetAppearance().AreAppsDark();
+    globalDefaultThemeIsDark = false;
     ZEN_ON_SCOPE_EXIT(if (!refGlobalColorHook()) refGlobalColorHook() = std::make_unique<SysColorsHook>()); //*after* SetAppearance() and despite errors
 
     //caveat: on macOS there are more themes than light/dark: https://developer.apple.com/documentation/appkit/nsappearance/name-swift.struct
@@ -86,10 +87,10 @@ void zen::changeColorTheme(ColorTheme co
     try
     {
         ZEN_ON_SCOPE_SUCCESS(refGlobalColorHook() = std::make_unique<SysColorsHook>()); //*after* SetAppearance()
-        if (wxApp::AppearanceResult rv = wxTheApp->SetAppearance(colTheme);
-            rv != wxApp::AppearanceResult::Ok)
-            throw SysError(formatSystemError("wxApp::SetAppearance",
-                                             rv == wxApp::AppearanceResult::CannotChange ? L"CannotChange" : L"Failure", L"" /*errorMsg*/));
+        //if (wxApp::AppearanceResult rv = wxTheApp->SetAppearance(colTheme);
+        //    rv != wxApp::AppearanceResult::Ok)
+        //    throw SysError(formatSystemError("wxApp::SetAppearance",
+        //                                     rv == wxApp::AppearanceResult::CannotChange ? L"CannotChange" : L"Failure", L"" /*errorMsg*/));
     }
     catch (const SysError& e) { throw FileError(_("Failed to update the color theme."), e.toString()); }
 }
--- a/wx+/dc.h
+++ b/wx+/dc.h
@@ -333,7 +333,9 @@ public:
     {
         assert(wnd.IsDoubleBuffered());
         dc_.emplace<wxPaintDC>(&wnd);
+#if wxCHECK_VERSION(3,3,2)
         static_cast<wxDC&>(*this).DisableAutomaticBoundingBoxUpdates(); //MOOOAAAR perf!?
+#endif
     }
 
     operator wxDC& ()
This is <https://salsa.debian.org/bastif/freefilesync/-/blob/debian/latest/debian/patches/03-deps/wxwidgets-no-wx3.3.1-WxLogCollector.patch?ref_type=heads> which for some reason is not incorporated into his main no-wx patch.
From: Fab Stz <fabstz-it@yahoo.fr>
Date: Wed, 1 Jul 2026 10:26:39 +0200
Subject: Revert to WxLog instead of WxLogCollector

WxLogCollector appeared is wxWidgets 3.3.1 & FreeFileSync 14.10

This reverts to the way it worked in FreeFileSync 14.9
---
 FreeFileSync/Source/localization.cpp            | 8 +-------
 FreeFileSync/Source/ui/batch_status_handler.cpp | 6 +++---
 FreeFileSync/Source/ui/gui_status_handler.cpp   | 7 +++----
 FreeFileSync/Source/ui/main_dlg.cpp             | 7 +++----
 wx+/image_resources.cpp                         | 8 +-------
 5 files changed, 11 insertions(+), 25 deletions(-)

diff --git a/FreeFileSync/Source/localization.cpp b/FreeFileSync/Source/localization.cpp
index 31379c5..5d8dac6 100644
--- a/FreeFileSync/Source/localization.cpp
+++ b/FreeFileSync/Source/localization.cpp
@@ -8,7 +8,6 @@
 #include <clocale> //setlocale
 #include <zen/file_traverser.h>
 #include <zen/file_io.h>
-#include <wx/log.h>
 #include <wx/zipstrm.h>
 #include <wx/mstream.h>
 #include <wx/uilocale.h>
@@ -129,8 +128,6 @@ std::vector<TranslationInfo> loadTranslations(const Zstring& zipPath) //throw Fi
         }
         //-------------------------------------------------------------
 
-        wxLogCollector zipLog; //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
-
         wxMemoryInputStream byteStream(rawStream.c_str(), rawStream.size()); //does not take ownership
         wxZipInputStream zipStream(byteStream, wxConvUTF8);
 
@@ -151,11 +148,8 @@ std::vector<TranslationInfo> loadTranslations(const Zstring& zipPath) //throw Fi
                 streams.emplace_back(zipPath + Zstr(':') + utfTo<Zstring>(entry->GetName()), std::move(stream));
             }
             else
-                break; //error
+                assert(false);
         }
-
-        if (zipStream.GetLastError() != wxSTREAM_EOF || !zipLog.GetMessages().empty())
-             throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(zipPath)), utfTo<std::wstring>(zipLog.GetMessages()));
     }();
     //--------------------------------------------------------------------
 
diff --git a/FreeFileSync/Source/ui/batch_status_handler.cpp b/FreeFileSync/Source/ui/batch_status_handler.cpp
index 88f722b..b065b3b 100644
--- a/FreeFileSync/Source/ui/batch_status_handler.cpp
+++ b/FreeFileSync/Source/ui/batch_status_handler.cpp
@@ -190,12 +190,12 @@ BatchStatusHandler::DlgOptions BatchStatusHandler::showResult()
     else if (!suspend && !autoClose && //only play when actually showing results dialog
              !soundFileSyncComplete_.empty())
     {
-        wxLogCollector soundLog; //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+        //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+        wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
+        ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
 
         wxSound::Play(utfTo<wxString>(soundFileSyncComplete_), wxSOUND_ASYNC);
 
-        if (!soundLog.GetMessages().empty())
-            logMsg(errorLog_.ref(), utfTo<std::wstring>(soundLog.GetMessages()), MSG_TYPE_INFO);
     }
     //if (::GetForegroundWindow() != GetHWND())
     //    RequestUserAttention(); -> probably too much since task bar is already colorized with Taskbar::Status::error or Status::normal
diff --git a/FreeFileSync/Source/ui/gui_status_handler.cpp b/FreeFileSync/Source/ui/gui_status_handler.cpp
index 15fed1f..3dce443 100644
--- a/FreeFileSync/Source/ui/gui_status_handler.cpp
+++ b/FreeFileSync/Source/ui/gui_status_handler.cpp
@@ -515,12 +515,11 @@ StatusHandlerFloatingDialog::DlgOptions StatusHandlerFloatingDialog::showResult(
     if (!taskCancelled() && !suspend && !autoClose && //only play when actually showing results dialog
         !soundFileSyncComplete_.empty())
     {
-                wxLogCollector soundLog; //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+        //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+        wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
+        ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
 
         wxSound::Play(utfTo<wxString>(soundFileSyncComplete_), wxSOUND_ASYNC);
-
-        if (!soundLog.GetMessages().empty())
-            logMsg(errorLog_.ref(), utfTo<std::wstring>(soundLog.GetMessages()), MSG_TYPE_INFO);
     }
     //if (::GetForegroundWindow() != GetHWND())
     //    RequestUserAttention(); -> probably too much since task bar is already colorized with Taskbar::Status::error or Status::normal
diff --git a/FreeFileSync/Source/ui/main_dlg.cpp b/FreeFileSync/Source/ui/main_dlg.cpp
index 9300767..bc3e88d 100644
--- a/FreeFileSync/Source/ui/main_dlg.cpp
+++ b/FreeFileSync/Source/ui/main_dlg.cpp
@@ -4622,12 +4622,11 @@ void MainDialog::onCompare(wxCommandEvent& event)
         //play (optional) sound notification
         if (!globalCfg_.soundFileCompareFinished.empty())
         {
-            wxLogCollector soundLog; //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+            //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
+            wxLog* oldLogTarget = wxLog::SetActiveTarget(new wxLogStderr); //transfer and receive ownership!
+            ZEN_ON_SCOPE_EXIT(delete wxLog::SetActiveTarget(oldLogTarget));
 
             wxSound::Play(utfTo<wxString>(globalCfg_.soundFileCompareFinished), wxSOUND_ASYNC);
-
-            if (!soundLog.GetMessages().empty())
-                statusHandler.logMessage(utfTo<std::wstring>(soundLog.GetMessages()), PhaseCallback::MsgType::info);
         }
     }
     catch (CancelProcess&) {}
diff --git a/wx+/image_resources.cpp b/wx+/image_resources.cpp
index 2df8282..e672d05 100644
--- a/wx+/image_resources.cpp
+++ b/wx+/image_resources.cpp
@@ -9,7 +9,6 @@
 #include <zen/thread.h>
 #include <zen/file_io.h>
 #include <zen/file_traverser.h>
-#include <wx/log.h>
 #include <wx/mstream.h>
 #include <wx/zipstrm.h>
 #include <xBRZ/src/xbrz.h>
@@ -202,8 +201,6 @@ ImageBuffer::ImageBuffer(const Zstring& zipPath) //throw FileError
         }
     //--------------------------------------------------------------------
 
-        wxLogCollector zipLog; //wxWidgets shows modal error dialog by default => "no, wxWidgets, NO!"
-
         //wxFFileInputStream/wxZipInputStream loads in junks of 512 bytes => WTF!!! => implement sane file loading:
         wxMemoryInputStream memStream(rawStream.c_str(), rawStream.size()); //does not take ownership
         wxZipInputStream zipStream(memStream, wxConvUTF8);
@@ -220,10 +217,7 @@ ImageBuffer::ImageBuffer(const Zstring& zipPath) //throw FileError
                 streams.emplace_back(utfTo<Zstring>(entry->GetName()), std::move(stream));
             }
             else
-                break; //error
-
-        if (zipStream.GetLastError() != wxSTREAM_EOF || !zipLog.GetMessages().empty())
-            throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(zipPath)), utfTo<std::wstring>(zipLog.GetMessages()));
+                assert(false);
     }();
     //--------------------------------------------------------------------
 
