Fix wxEventLoopManual implementation check for wxGTK under macOS This was broken by the recent 894a04f914 (Fix using wxConsoleEventLoop in non-GUI applications under macOS, 2026-01-07) which resulted in the test around this class declaration in the header and its implementation in the source file getting out of sync. Fix this by introducing wxHAS_EVENTLOOP_MANUAL symbol, defining it in the header if this class is used and checking for it in the source file to make sure this doesn't happen again. Note that wxHAS_EVENTLOOP_MANUAL is intentionally not documented as it's not clear if there is ever any legitimate need to use wxEventLoopManual directly in the application code, so it's better to not encourage it. Closes #26089.
Fix typo in wxPopupWindow::Ref comment Fix typo in 96eca6412e (Provide safe API for detecting closing wxTipWindow, 2026-01-02). No real changes.
Avoid destroying wxPopupTransientWindow twice in wxMSW Explicitly check that the window is not being already destroyed before scheduling its dismissal. Closes #26083.
Disallow wxSplitterWindow to grab the focus
- There is no keyboard handling in wxSplitterWindow
- Currently, the child windows handled by wxSplitterWindow
lose focus when resizing and e.g. change the colour of
selected items. That is unexpected and other apps keep
the child windows (or one of them) in focus.
- Tested on macOS so far
Closes #26085.
Fix flushing white background for check/radio buttons in dark mode Use correct background brush for erasing wxCheckBox and wxRadioButton background in dark mode even if no custom background brush is specified as we can't rely on the default behaviour, which uses white background brush, when using it. This fixes incorrect flushes of white background when these controls were focused after the containing TLW got focus and before it got repainted again using a different code path which erased background correctly. See #26087. Closes #23380.
Handle font names longer than 31 characters in wxMSW Get the full font name using ::GetOutlineTextMetrics() if the name is exactly 31 characters long, as it may indicate that it was truncated to fit into LOGFONT::lfFaceName buffer which has fixed size of 32. This commit is best viewed with Git --color-moved option. Closes #25333. Closes #26078.
| ... | ... | @@ -229,6 +229,8 @@ private: |
| 229 | 229 | |
| 230 | 230 | #if defined(__WINDOWS__) || defined(__WXDFB__) || (defined(__UNIX__) && !defined(__DARWIN__))
|
| 231 | 231 | |
| 232 | +#define wxHAS_EVENTLOOP_MANUAL
|
|
| 233 | + |
|
| 232 | 234 | // this class can be used to implement a standard event loop logic using
|
| 233 | 235 | // Pending() and Dispatch()
|
| 234 | 236 | //
|
| ... | ... | @@ -186,6 +186,11 @@ public: |
| 186 | 186 | // minimum pane size is zero.
|
| 187 | 187 | virtual void OnDoubleClickSash(int x, int y);
|
| 188 | 188 | |
| 189 | + // Do not allow wxSplitterWindow to get the focus as there is
|
|
| 190 | + // no keyboard handling anyways and the child windows should
|
|
| 191 | + // keep the focus
|
|
| 192 | + bool AcceptsFocus() const override { return false; }
|
|
| 193 | + |
|
| 189 | 194 | ////////////////////////////////////////////////////////////////////////////
|
| 190 | 195 | // Implementation
|
| 191 | 196 |
| ... | ... | @@ -1041,6 +1041,16 @@ WXDLLIMPEXP_CORE wxFont wxCreateFontFromLogFont(const LOGFONT *logFont); |
| 1041 | 1041 | WXDLLIMPEXP_CORE void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font);
|
| 1042 | 1042 | WXDLLIMPEXP_CORE wxFontEncoding wxGetFontEncFromCharSet(int charset);
|
| 1043 | 1043 | |
| 1044 | +// Helper function to check if the facename might be truncated: if it is,
|
|
| 1045 | +// wxGetMSWFaceNameFromHFONT() should be used to get the full name.
|
|
| 1046 | +inline bool wxIsFaceNamePossiblyTruncated(const wxString& facename)
|
|
| 1047 | +{
|
|
| 1048 | + return facename.size() == LF_FACESIZE - 1;
|
|
| 1049 | +}
|
|
| 1050 | + |
|
| 1051 | +// Get full face name (i.e. possibly longer than LF_FACESIZE) from an HFONT.
|
|
| 1052 | +wxString wxGetMSWFaceNameFromHFONT(HFONT hFont);
|
|
| 1053 | + |
|
| 1044 | 1054 | inline void wxSetWindowFont(HWND hwnd, const wxFont& font)
|
| 1045 | 1055 | {
|
| 1046 | 1056 | ::SendMessage(hwnd, WM_SETFONT,
|
| ... | ... | @@ -34,7 +34,7 @@ public: |
| 34 | 34 | //
|
| 35 | 35 | // Note that this is not a wxWeakRef<> because this is set to nullptr when
|
| 36 | 36 | // wxTipWindow is closed, which may be "long" before wxTipWindow is
|
| 37 | - // destroyed, bug wxWeakRef<> is set to nullptr on object destruction
|
|
| 37 | + // destroyed, but wxWeakRef<> is set to nullptr on object destruction
|
|
| 38 | 38 | class WXDLLIMPEXP_CORE Ref
|
| 39 | 39 | {
|
| 40 | 40 | public:
|
| ... | ... | @@ -212,8 +212,8 @@ wxEventLoopBase::AddSourceForFD(int fd, |
| 212 | 212 | }
|
| 213 | 213 | |
| 214 | 214 | #endif // wxUSE_EVENTLOOP_SOURCE
|
| 215 | -// wxEventLoopManual is unused in the other ports
|
|
| 216 | -#if defined(__WINDOWS__) || defined(__WXDFB__) || ( ( defined(__UNIX__) && !defined(__WXOSX__) ) && wxUSE_BASE)
|
|
| 215 | + |
|
| 216 | +#ifdef wxHAS_EVENTLOOP_MANUAL
|
|
| 217 | 217 | |
| 218 | 218 | // ============================================================================
|
| 219 | 219 | // wxEventLoopManual implementation
|
| ... | ... | @@ -400,5 +400,4 @@ void wxEventLoopManual::DoStop(int rc) |
| 400 | 400 | WakeUp();
|
| 401 | 401 | }
|
| 402 | 402 | |
| 403 | -#endif // __WINDOWS__ || __WXMAC__ || __WXDFB__
|
|
| 404 | - |
|
| 403 | +#endif // wxHAS_EVENTLOOP_MANUAL |
| ... | ... | @@ -578,7 +578,17 @@ bool wxMSWOwnerDrawnButtonBase::MSWDrawButton(WXDRAWITEMSTRUCT *item) |
| 578 | 578 | }
|
| 579 | 579 | |
| 580 | 580 | // Erase the background.
|
| 581 | - ::FillRect(hdc, &rect, m_win->MSWGetBgBrush(hdc));
|
|
| 581 | + HBRUSH hbr = m_win->MSWGetBgBrush(hdc);
|
|
| 582 | + if ( !hbr && wxMSWDarkMode::IsActive() )
|
|
| 583 | + {
|
|
| 584 | + // We always need to use custom background in dark mode, default
|
|
| 585 | + // behaviour is never correct.
|
|
| 586 | + auto const colBg = m_win->GetBackgroundColour();
|
|
| 587 | + wxBrush* brush = wxTheBrushList->FindOrCreateBrush(colBg);
|
|
| 588 | + hbr = (WXHBRUSH)brush->GetResourceHandle();
|
|
| 589 | + }
|
|
| 590 | + |
|
| 591 | + ::FillRect(hdc, &rect, hbr);
|
|
| 582 | 592 | |
| 583 | 593 | // draw the button itself
|
| 584 | 594 | wxDCTemp dc(hdc);
|
| ... | ... | @@ -45,6 +45,43 @@ |
| 45 | 45 | // the mask used to extract the pitch from LOGFONT::lfPitchAndFamily field
|
| 46 | 46 | static const int PITCH_MASK = FIXED_PITCH | VARIABLE_PITCH;
|
| 47 | 47 | |
| 48 | +// ----------------------------------------------------------------------------
|
|
| 49 | +// global functions implementation
|
|
| 50 | +// ----------------------------------------------------------------------------
|
|
| 51 | + |
|
| 52 | +wxString wxGetMSWFaceNameFromHFONT(HFONT hFont)
|
|
| 53 | +{
|
|
| 54 | + ScreenHDC hdc;
|
|
| 55 | + SelectInHDC selectFont(hdc, hFont);
|
|
| 56 | + |
|
| 57 | + UINT otmSize = GetOutlineTextMetrics(hdc, 0, nullptr);
|
|
| 58 | + if ( !otmSize )
|
|
| 59 | + {
|
|
| 60 | + wxLogLastError("GetOutlineTextMetrics(nullptr)");
|
|
| 61 | + return wxString();
|
|
| 62 | + }
|
|
| 63 | + |
|
| 64 | + OUTLINETEXTMETRIC * const
|
|
| 65 | + otm = static_cast<OUTLINETEXTMETRIC *>(malloc(otmSize));
|
|
| 66 | + wxON_BLOCK_EXIT1( free, otm );
|
|
| 67 | + |
|
| 68 | + otm->otmSize = otmSize;
|
|
| 69 | + if ( !GetOutlineTextMetrics(hdc, otmSize, otm) )
|
|
| 70 | + {
|
|
| 71 | + wxLogLastError("GetOutlineTextMetrics()");
|
|
| 72 | + return wxString();
|
|
| 73 | + }
|
|
| 74 | + |
|
| 75 | + // in spite of its type, the otmpFamilyName field of OUTLINETEXTMETRIC
|
|
| 76 | + // gives an offset in _bytes_ of the face (not family!) name from the
|
|
| 77 | + // struct start while the name itself is an array of TCHARs
|
|
| 78 | + //
|
|
| 79 | + // FWIW otmpFaceName contains the same thing as otmpFamilyName followed
|
|
| 80 | + // by a possible " Italic" or " Bold" or something else suffix
|
|
| 81 | + return reinterpret_cast<wxChar *>(otm) +
|
|
| 82 | + wxPtrToUInt(otm->otmpFamilyName)/sizeof(wxChar);
|
|
| 83 | +}
|
|
| 84 | + |
|
| 48 | 85 | // ----------------------------------------------------------------------------
|
| 49 | 86 | // wxFontRefData - the internal description of the font
|
| 50 | 87 | // ----------------------------------------------------------------------------
|
| ... | ... | @@ -115,9 +152,9 @@ public: |
| 115 | 152 | wxString GetFaceName() const
|
| 116 | 153 | {
|
| 117 | 154 | wxString facename = m_nativeFontInfo.GetFaceName();
|
| 118 | - if ( facename.empty() )
|
|
| 155 | + if ( facename.empty() || wxIsFaceNamePossiblyTruncated(facename) )
|
|
| 119 | 156 | {
|
| 120 | - facename = GetMSWFaceName();
|
|
| 157 | + facename = wxGetMSWFaceNameFromHFONT((HFONT)GetHFONT());
|
|
| 121 | 158 | if ( !facename.empty() )
|
| 122 | 159 | {
|
| 123 | 160 | // cache the face name, it shouldn't change unless the family
|
| ... | ... | @@ -266,41 +303,6 @@ protected: |
| 266 | 303 | const_cast<wxFontRefData *>(this)->Alloc();
|
| 267 | 304 | }
|
| 268 | 305 | |
| 269 | - // retrieve the face name really being used by the font: this is used to
|
|
| 270 | - // get the face name selected by the system when we don't specify it (but
|
|
| 271 | - // use just the family for example)
|
|
| 272 | - wxString GetMSWFaceName() const
|
|
| 273 | - {
|
|
| 274 | - ScreenHDC hdc;
|
|
| 275 | - SelectInHDC selectFont(hdc, (HFONT)GetHFONT());
|
|
| 276 | - |
|
| 277 | - UINT otmSize = GetOutlineTextMetrics(hdc, 0, nullptr);
|
|
| 278 | - if ( !otmSize )
|
|
| 279 | - {
|
|
| 280 | - wxLogLastError("GetOutlineTextMetrics(nullptr)");
|
|
| 281 | - return wxString();
|
|
| 282 | - }
|
|
| 283 | - |
|
| 284 | - OUTLINETEXTMETRIC * const
|
|
| 285 | - otm = static_cast<OUTLINETEXTMETRIC *>(malloc(otmSize));
|
|
| 286 | - wxON_BLOCK_EXIT1( free, otm );
|
|
| 287 | - |
|
| 288 | - otm->otmSize = otmSize;
|
|
| 289 | - if ( !GetOutlineTextMetrics(hdc, otmSize, otm) )
|
|
| 290 | - {
|
|
| 291 | - wxLogLastError("GetOutlineTextMetrics()");
|
|
| 292 | - return wxString();
|
|
| 293 | - }
|
|
| 294 | - |
|
| 295 | - // in spite of its type, the otmpFamilyName field of OUTLINETEXTMETRIC
|
|
| 296 | - // gives an offset in _bytes_ of the face (not family!) name from the
|
|
| 297 | - // struct start while the name itself is an array of TCHARs
|
|
| 298 | - //
|
|
| 299 | - // FWIW otmpFaceName contains the same thing as otmpFamilyName followed
|
|
| 300 | - // by a possible " Italic" or " Bold" or something else suffix
|
|
| 301 | - return reinterpret_cast<wxChar *>(otm) +
|
|
| 302 | - wxPtrToUInt(otm->otmpFamilyName)/sizeof(wxChar);
|
|
| 303 | - }
|
|
| 304 | 306 | |
| 305 | 307 | // are we using m_nativeFontInfo.lf.lfHeight for point size or pixel size?
|
| 306 | 308 | bool m_sizeUsingPixels;
|
| ... | ... | @@ -155,6 +155,24 @@ void wxFontEnumeratorHelper::DoEnumerate() |
| 155 | 155 | bool wxFontEnumeratorHelper::OnFont(const LPLOGFONT lf,
|
| 156 | 156 | const LPTEXTMETRIC tm) const
|
| 157 | 157 | {
|
| 158 | + wxString facename = lf->lfFaceName;
|
|
| 159 | + if ( facename.empty() || wxIsFaceNamePossiblyTruncated(facename) )
|
|
| 160 | + {
|
|
| 161 | + AutoHFONT hFont(*lf);
|
|
| 162 | + if ( !hFont )
|
|
| 163 | + {
|
|
| 164 | + wxLogLastError("CreateFontIndirect");
|
|
| 165 | + }
|
|
| 166 | + else
|
|
| 167 | + {
|
|
| 168 | + const wxString fullname = wxGetMSWFaceNameFromHFONT(hFont);
|
|
| 169 | + if ( !fullname.empty() )
|
|
| 170 | + {
|
|
| 171 | + facename = fullname;
|
|
| 172 | + }
|
|
| 173 | + }
|
|
| 174 | + }
|
|
| 175 | + |
|
| 158 | 176 | if ( m_enumEncodings )
|
| 159 | 177 | {
|
| 160 | 178 | // is this a new charset?
|
| ... | ... | @@ -165,13 +183,13 @@ bool wxFontEnumeratorHelper::OnFont(const LPLOGFONT lf, |
| 165 | 183 | |
| 166 | 184 | #if wxUSE_FONTMAP
|
| 167 | 185 | wxFontEncoding enc = wxGetFontEncFromCharSet(cs);
|
| 168 | - return m_fontEnum->OnFontEncoding(lf->lfFaceName,
|
|
| 186 | + return m_fontEnum->OnFontEncoding(facename,
|
|
| 169 | 187 | wxFontMapper::GetEncodingName(enc));
|
| 170 | 188 | #else // !wxUSE_FONTMAP
|
| 171 | 189 | // Just use some unique and, hopefully, understandable, name.
|
| 172 | 190 | return m_fontEnum->OnFontEncoding
|
| 173 | 191 | (
|
| 174 | - lf->lfFaceName,
|
|
| 192 | + facename,
|
|
| 175 | 193 | wxString::Format(wxS("Code page %d"), cs)
|
| 176 | 194 | );
|
| 177 | 195 | #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
|
| ... | ... | @@ -207,17 +225,17 @@ bool wxFontEnumeratorHelper::OnFont(const LPLOGFONT lf, |
| 207 | 225 | // we can get the same facename twice or more in this case because it
|
| 208 | 226 | // may exist in several charsets but we only want to return one copy of
|
| 209 | 227 | // it (note that this can't happen for m_charset != DEFAULT_CHARSET)
|
| 210 | - if ( m_facenames.Index(lf->lfFaceName) != wxNOT_FOUND )
|
|
| 228 | + if ( m_facenames.Index(facename) != wxNOT_FOUND )
|
|
| 211 | 229 | {
|
| 212 | 230 | // continue enumeration
|
| 213 | 231 | return true;
|
| 214 | 232 | }
|
| 215 | 233 | |
| 216 | 234 | wxConstCast(this, wxFontEnumeratorHelper)->
|
| 217 | - m_facenames.Add(lf->lfFaceName);
|
|
| 235 | + m_facenames.Add(facename);
|
|
| 218 | 236 | }
|
| 219 | 237 | |
| 220 | - return m_fontEnum->OnFacename(lf->lfFaceName);
|
|
| 238 | + return m_fontEnum->OnFacename(facename);
|
|
| 221 | 239 | }
|
| 222 | 240 | |
| 223 | 241 | // ----------------------------------------------------------------------------
|
| ... | ... | @@ -22,6 +22,7 @@ |
| 22 | 22 | #if wxUSE_POPUPWIN
|
| 23 | 23 | |
| 24 | 24 | #ifndef WX_PRECOMP
|
| 25 | + #include "wx/app.h"
|
|
| 25 | 26 | #endif //WX_PRECOMP
|
| 26 | 27 | |
| 27 | 28 | #include "wx/popupwin.h"
|
| ... | ... | @@ -238,6 +239,14 @@ wxPopupTransientWindow::MSWHandleMessage(WXLRESULT *result, |
| 238 | 239 | case WM_ACTIVATE:
|
| 239 | 240 | if ( wParam == WA_INACTIVE )
|
| 240 | 241 | {
|
| 242 | + if ( wxTheApp->IsScheduledForDestruction(this) )
|
|
| 243 | + {
|
|
| 244 | + // It is possible that we get this message again after
|
|
| 245 | + // already getting it once, avoid scheduling the window for
|
|
| 246 | + // destruction again in this case.
|
|
| 247 | + break;
|
|
| 248 | + }
|
|
| 249 | + |
|
| 241 | 250 | // We need to dismiss this window, however doing it directly
|
| 242 | 251 | // from here seems to confuse ::ShowWindow(), which ends up
|
| 243 | 252 | // calling this handler, and may result in losing activation
|
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help