Compare commits

...
Author SHA1 Message Date
Lam Wei Lun 2c97343811 Replace wxGridCellChoiceEditor::OnComboCloseUp() with wxGridCellChoiceEditor::DismissEditor() 2026-10-11 22:50:07 +08:00
Lam Wei Lun cff514cd15 build(wx): move to upstream wxWidgets 3.3.4
Orca pinned the SoftFever fork at branch v3.3.2. That tracks a moving tip and
leaves the 3.3.3 image-decoder buffer overflows unfixed. Build upstream
wxWidgets at tag v3.3.4 instead and carry the fork's one extra commit as an
in-tree patch.

- deps/wxWidgets: GIT_REPOSITORY -> wxWidgets/wxWidgets, GIT_TAG -> v3.3.4
- add 0002-clang-cl-sibling-compiler-prefix.patch (fork PR #7, WIN32 only):
  the generated wxWidgetsConfig.cmake must search the sibling vc_/clang_
  install layout, because cl and clang-cl share an ABI but wx names the
  layout after the compiler that built it
- flatpak: upstream git source, tag v3.3.4, commit 6a42a4b9
- skill: update the pin, add the 3.3.3/3.3.4 sections, re-base the
  changes.txt line citations, and retire the wxGetTranslation() by-value rule
  (3.3.2 returned by value, 3.3.3 reverted to const wxString&)
2026-10-11 22:19:16 +08:00
HanifKoh 7369674d8f Add #pragma once to Headers Without an Include Guard (#16362) 2026-10-11 17:26:05 +08:00
HanifKoh 70da7e89bb Release the Slice Button's Mouse Capture When a Press Loses Its Release (#16358) 2026-10-11 15:49:04 +08:00
HanifKoh a671bf605d Dismiss the Slice-Plate Popup on Every Path Into the Filament Grouping Dialog (#16359)
#16284 closed the Slice-plate hover popup only when the Slice button opened
the filament grouping dialog. The dialog also opens from the plate's filament
grouping icon, the preview legend, slicing notification links and the send
dialog, and a popup still shown on those paths keeps the mouse capture on
macOS and starves the modal dialog of clicks. Dismiss it in
FilamentMapDialog::ShowModal() instead, so every path is covered.

The popup could also stay up on its own on macOS: an enter event stopped its
close timer, and when the timer fired with the cursor inside it returned
without re-arming, so without a later leave event the popup never closed. On
macOS the timer now keeps running while the popup is shown and closes it once
the cursor is outside. The popup also stops and frees its timer when destroyed.
2026-10-11 15:48:49 +08:00
SoftFever bae8f64b8b Complete and refine Simplified Chinese translations (#16356)
* Complete Simplified Chinese translations

* Fix Simplified Chinese 3D view, camera and extruder terms

* Use Chinese CAD view names on the navigator cube
2026-10-11 15:35:29 +08:00
34 changed files with 1082 additions and 570 deletions
+11 -7
View File
@@ -6,7 +6,7 @@ description: Use when writing, modifying, reviewing or debugging any OrcaSlicer
# OrcaSlicer wxWidgets GUI # OrcaSlicer wxWidgets GUI
This skill is how OrcaSlicer's wxWidgets GUI is written, changed, fixed and reviewed. Its core is This skill is how OrcaSlicer's wxWidgets GUI is written, changed, fixed and reviewed. Its core is
**wxWidgets 3.3.2 API usage** — the documented contracts, the per-platform behaviour and the known **wxWidgets 3.3.4 API usage** — the documented contracts, the per-platform behaviour and the known
limitations of the wx version Orca pins — layered with the OrcaSlicer conventions, wrappers, custom limitations of the wx version Orca pins — layered with the OrcaSlicer conventions, wrappers, custom
widget library and stable component designs a contributor must follow. Every reference file opens widget library and stable component designs a contributor must follow. Every reference file opens
with a numbered **Rules** checklist (what a diff is checked against), followed by sections that give with a numbered **Rules** checklist (what a diff is checked against), followed by sections that give
@@ -15,9 +15,12 @@ wrong → right pairs with the commit that fixed each one.
## Ground truth: the wx tree in deps/ ## Ground truth: the wx tree in deps/
Orca pins **wxWidgets 3.3.2** from the fork `github.com/SoftFever/Orca-deps-wxWidgets` (tag `v3.3.2`, Orca pins upstream **wxWidgets 3.3.4** (`github.com/wxWidgets/wxWidgets`, tag `v3.3.4`,
`deps/wxWidgets/wxWidgets.cmake`), built static (Flatpak: shared). Facts about this build that change `deps/wxWidgets/wxWidgets.cmake`), built static (Flatpak: shared). Two in-tree patches are applied: an
how you read the wx docs: Apple-only sRGB colour-component fix (`0001-macos-use-srgb-colour-components.patch`) and a Windows-only
clang-cl sibling-compiler search fix for the installed `wxWidgetsConfig.cmake`
(`0002-clang-cl-sibling-compiler-prefix.patch`); neither applies on Linux. Facts about this build that
change how you read the wx docs:
- **Linux builds against GTK3** (`DEP_WX_GTK3` defaults ON in `deps/CMakeLists.txt`). Target GTK3 on - **Linux builds against GTK3** (`DEP_WX_GTK3` defaults ON in `deps/CMakeLists.txt`). Target GTK3 on
both X11 and Wayland; GTK-guarded code must still compile on GTK2, an opt-out build Orca does not ship. both X11 and Wayland; GTK-guarded code must still compile on GTK2, an opt-out build Orca does not ship.
@@ -33,7 +36,7 @@ Look things up in the source the app is built from — it beats memory, and 3.3
WX=$(find -L deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets' 2>/dev/null | head -1) WX=$(find -L deps -maxdepth 5 -type d -path '*dep_wxWidgets-prefix/src/dep_wxWidgets' 2>/dev/null | head -1)
# macOS: deps/build/<arch>/dep_wxWidgets-prefix/src/dep_wxWidgets Linux, Windows: deps/<tree>/dep_wxWidgets-prefix/... # macOS: deps/build/<arch>/dep_wxWidgets-prefix/src/dep_wxWidgets Linux, Windows: deps/<tree>/dep_wxWidgets-prefix/...
# -L follows a worktree's deps/<tree> symlinked to the main checkout. Not a glob: zsh aborts on one that matches nothing. # -L follows a worktree's deps/<tree> symlinked to the main checkout. Not a glob: zsh aborts on one that matches nothing.
# If deps are not built: git clone --depth 1 -b v3.3.2 https://github.com/SoftFever/Orca-deps-wxWidgets # If deps are not built: git clone --depth 1 -b v3.3.4 https://github.com/wxWidgets/wxWidgets
grep -n "CaptureMouse" -A 30 $WX/interface/wx/window.h # documented contract (doxygen source) grep -n "CaptureMouse" -A 30 $WX/interface/wx/window.h # documented contract (doxygen source)
grep -rn "@onlyfor\|not implemented" $WX/interface/wx/popupwin.h # documented platform limits grep -rn "@onlyfor\|not implemented" $WX/interface/wx/popupwin.h # documented platform limits
ls $WX/docs/doxygen/overviews/ # eventhandling.h, sizer.h, high_dpi.md, windowdeletion.h, ... ls $WX/docs/doxygen/overviews/ # eventhandling.h, sizer.h, high_dpi.md, windowdeletion.h, ...
@@ -219,14 +222,15 @@ known class with a pitfall entry and a fixing commit.
any wx key event; Control+click arrives as a right-click. any wx key event; Control+click arrives as a right-click.
- **Windows:** `IsDark()` and `wxSYS_COLOUR_*` follow the system app mode, not Orca's theme — use - **Windows:** `IsDark()` and `wxSYS_COLOUR_*` follow the system app mode, not Orca's theme — use
`dark_mode()`; menu bitmaps follow `check_dark_mode()`; windows are not double-buffered by default in `dark_mode()`; menu bitmaps follow `check_dark_mode()`; windows are not double-buffered by default in
3.3.2; `ProcessLeftDown` is never called for popups; a popup that must close with the frame calls 3.3.4; `ProcessLeftDown` is never called for popups; a popup that must close with the frame calls
`BindUnfocusEvent()`. `BindUnfocusEvent()`.
- **Linux GTK3:** dialogs without size hints collapse (only sizer-fitting calls, not `Fit()`, are - **Linux GTK3:** dialogs without size hints collapse (only sizer-fitting calls, not `Fit()`, are
replayed at the first `Show()`); command events from a popup's children are not stopped at the popup replayed at the first `Show()`); command events from a popup's children are not stopped at the popup
(MSW/macOS stop them); chained popups need `transient_for` set to the mapped parent right before (MSW/macOS stop them); chained popups need `transient_for` set to the mapped parent right before
showing; native borders leak through custom widgets (`RemoveButtonBorder`/`RemoveInputBorder`). showing; native borders leak through custom widgets (`RemoveButtonBorder`/`RemoveInputBorder`).
- **Wayland:** no global pointer position, no window positioning, `wxClientDC`, `Update()` and `SetIcon` - **Wayland:** no global pointer position, no window positioning, `wxClientDC`, `Update()` and `SetIcon`
do nothing, no floating AUI panes, GL is EGL only. do nothing, AUI floating is disabled (wx 3.3.4 can drag a floating frame via system drag sessions, but
its docking hints still need global positions), GL is EGL only.
## Editing this skill ## Editing this skill
@@ -59,7 +59,7 @@ Contents: [Rules](#rules) · [wxColour](#wxcolour) · [System colours and appear
**Contract.** Constructors: `()`, `(r, g, b, a = wxALPHA_OPAQUE)`, `(unsigned long|long|int|unsigned int)` ("A **Contract.** Constructors: `()`, `(r, g, b, a = wxALPHA_OPAQUE)`, `(unsigned long|long|int|unsigned int)` ("A
packed RGB value", `interface/wx/colour.h:98-101`), `(const wxString&|const char*|const wchar_t*)`; packed RGB value", `interface/wx/colour.h:98-101`), `(const wxString&|const char*|const wchar_t*)`;
`wxColour(bool) = delete` (`include/wx/colour.h:225-240`; `docs/changes.txt:246-248`: code "unintentionally `wxColour(bool) = delete` (`include/wx/colour.h:225-240`; `docs/changes.txt:278-280`: code "unintentionally
and mistakenly using wxColour ctor from bool … doesn't compile any longer"). and mistakenly using wxColour ctor from bool … doesn't compile any longer").
| Fact | Cite | | Fact | Cite |
@@ -121,7 +121,7 @@ returned colour is always valid" (`interface/wx/settings.h:44-48`, `:398-407`).
| Method | Contract | | Method | Contract |
|---|---| |---|---|
| `IsDark()` | "checks the appearance of the current application and not the other applications on the system, so under MSW … will return false even if dark mode is used system-wide unless the application opted in using dark mode using wxApp::MSWEnableDarkMode()" (`:332-346`). An incompatible 3.3 change (`docs/changes.txt:71-73`). | | `IsDark()` | "checks the appearance of the current application and not the other applications on the system, so under MSW … will return false even if dark mode is used system-wide unless the application opted in using dark mode using wxApp::MSWEnableDarkMode()" (`:332-346`). An incompatible 3.3 change (`docs/changes.txt:77-79`). |
| `AreAppsDark()` (3.3.0) | system-wide app dark mode "even if it's not enabled for this particular application"; same as `IsDark()` off MSW (`:308-321`). | | `AreAppsDark()` (3.3.0) | system-wide app dark mode "even if it's not enabled for this particular application"; same as `IsDark()` off MSW (`:308-321`). |
| `IsSystemDark()` (3.3.0) | the "Windows mode", which can differ from the "app mode" (`:348-358`). | | `IsSystemDark()` (3.3.0) | the "Windows mode", which can differ from the "app mode" (`:348-358`). |
| `IsUsingDarkBackground()` | luminance fallback, "generally not very useful to call directly" (`:360-370`). | | `IsUsingDarkBackground()` | luminance fallback, "generally not very useful to call directly" (`:360-370`). |
@@ -233,25 +233,25 @@ child handlers.
`@onlyfor{wxmsw}`, `interface/wx/app.h:1418-1465`): `@onlyfor{wxmsw}`, `interface/wx/app.h:1418-1465`):
- "experimental"; uses "undocumented, and unsupported by Microsoft, functions"; works on Windows 10 later than - "experimental"; uses "undocumented, and unsupported by Microsoft, functions"; works on Windows 10 later than
v1809 (including LTSC 2019) and all Windows 11; testing before 20H1 (v2004) "has been limited". v1809 (including LTSC 2019) and all Windows 11; testing before 20H1 (v2004) "has been limited".
- Flags: default follows the system ("dark mode is only used if it is the default mode for the applications on - Flags: `DarkMode_Auto` (default) follows the system ("dark mode is only used if it is the default mode
the current system"); `DarkMode_Always` forces dark. **[source]** `DarkMode_Auto = 0` exists in for the applications on the current system"); `DarkMode_Always` forces dark, `DarkMode_Never` forces
`include/wx/msw/app.h:48` although only `DarkMode_Always` is documented. light. **[source]** the enum also names `DarkMode_Auto = 0` in `include/wx/msw/app.h:46-52`;
`DarkMode_Never` is new in 3.3.4 (documented at `interface/wx/app.h:1450-1454`).
- Returns `true` if enabled, `false` "most likely because the system doesn't support dark mode". - Returns `true` if enabled, `false` "most likely because the system doesn't support dark mode".
- Alternatives: the `msw.dark-mode` system option (1 = `MSWEnableDarkMode()`, 2 = `DarkMode_Always`, settable by - Alternatives: the `msw.dark-mode` system option (1 = `MSWEnableDarkMode()`, 2 = `DarkMode_Always`, settable by
environment variable from outside the app, `interface/wx/sysopt.h:85-89`), or `SetAppearance(System|Dark)`. environment variable from outside the app, `interface/wx/sysopt.h:85-89`), or `SetAppearance(System|Light|Dark)`.
- Known limitations (`interface/wx/app.h:1434-1448`): anything `TaskDialog()`-based has no dark mode — - Known limitations (`interface/wx/app.h:1442-1448`): `wxTimePickerCtrl`, `wxDatePickerCtrl` and
`wxMessageBox()`, `wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`, simple `wxAboutBox()` (wx suggests `wxCalendarCtrl` stay light; `wxPrintDialog` on Windows 10 stays light; MDI applications are not
`wxGenericMessageDialog`/`wxGenericProgressDialog`); common-dialog wrappers `wxColourDialog`, `wxFindReplaceDialog`, recommended in dark mode. `wxMessageDialog` gained dark mode in 3.3.3 (#26570) and the common dialogs
`wxFontDialog`, `wxPageSetupDialog`, `wxPrintDialog`; `wxTimePickerCtrl`, `wxDatePickerCtrl`, `wxCalendarCtrl` in 3.3.4 (#26780), so the older "anything `TaskDialog()`-based and the common dialogs stay light" note
stay light; toolbar items with `wxToolBar::SetDropdownMenu()` draw the drop-down "almost invisible". no longer applies.
`AppearanceResult wxApp::SetAppearance(Appearance::System|Light|Dark)` (3.3.0, `interface/wx/app.h:1152-1190`): `AppearanceResult wxApp::SetAppearance(Appearance::System|Light|Dark)` (3.3.0, `interface/wx/app.h:1130-1187`):
GTK/macOS follow the system by default and the call is immediate and "affects all the existing windows as well GTK/macOS follow the system by default and the call is immediate and "affects all the existing windows as well
as any windows created after this call"; "Under MSW, the default appearance is always light" and an app that as any windows created after this call"; "Under MSW, the default appearance is always light" and an app that
wants to follow the system must call it with `Appearance::System`; "the appearance can be only set before any wants to follow the system must call it with `Appearance::System`; on MSW it maps to `MSWEnableDarkMode()` and
windows are created and calling this function too late will return AppearanceResult::CannotChange" (only wxMSW returns `Ok`/`Failure` (`interface/wx/app.h:1166-1169`). `Failure` e.g. "because `GTK_THEME` is defined";
returns it); `AppearanceResult::CannotChange` is "currently never returned" (`interface/wx/app.h:1151, 1179-1183`).
`Failure` e.g. "because `GTK_THEME` is defined".
`wxDarkModeSettings` (`interface/wx/msw/darkmode.h:30-111`), passed to `MSWEnableDarkMode()`: `GetColour(wxSystemColour)` `wxDarkModeSettings` (`interface/wx/msw/darkmode.h:30-111`), passed to `MSWEnableDarkMode()`: `GetColour(wxSystemColour)`
(defaults "not documented and are subject to change"; the doc example names `0x202020` as the default background); (defaults "not documented and are subject to change"; the doc example names `0x202020` as the default background);
@@ -260,34 +260,40 @@ returns it);
which "doesn't look very well in dark mode"; the base returns grey. which "doesn't look very well in dark mode"; the base returns grey.
**[source] facts the docs do not state:** **[source] facts the docs do not state:**
- `SetAppearance` on MSW returns `CannotChange` when any TLW exists **or `MSWEnableDarkMode` was already called** - As of 3.3.3 (#26516) and 3.3.4 (#26734), MSW dark mode can be switched at runtime: `SetAppearance()` maps to
(`gs_appMode != AppMode_Default`); `SetAppearance(Light)` returns `Ok` without doing anything `MSWEnableDarkMode()` and returns `Ok`/`Failure`, never `CannotChange` (`src/msw/darkmode.cpp:354-375`).
(`src/msw/darkmode.cpp` `wxApp::SetAppearance`). macOS `System` sets `NSApp.appearance` to `MSWEnableDarkMode()` re-applies the mode to an existing window by sending it `WM_SYSCOLORCHANGE` (`:345-349`),
`[NSAppearance currentAppearance]` rather than nil, pinning the current look (`src/osx/cocoa/utils.mm:485-513`); and the window restyles through `wxMSWDarkMode::HasChanged()`/`NotifySysColorChange()`
GTK3 maps to the portal colour-scheme machinery; GTK2 always returns `Failure` (`src/gtk/app.cpp:355-381`). (`src/msw/window.cpp:5337, 5528-5534`), so a control created before the switch is re-themed too. macOS `System`
- `MSWEnableDarkMode` may be called any time, but dark title bars are applied only to TLWs **created** afterwards sets `NSApp.appearance` to `[NSAppearance currentAppearance]` rather than nil, pinning the current look
(`src/osx/cocoa/utils.mm:485-513`); GTK3 maps to the portal colour-scheme machinery; GTK2 always returns
`Failure` (`src/gtk/app.cpp:355-381`).
- `MSWEnableDarkMode` may be called any time; dark title bars are applied when a TLW is created
(`EnableForTLW` at the end of TLW creation, `src/msw/toplevel.cpp:513`) and controls are dark-enabled at creation (`EnableForTLW` at the end of TLW creation, `src/msw/toplevel.cpp:513`) and controls are dark-enabled at creation
(`MSWCreateControl` → `AllowForWindow` and, for some controls, `SetForegroundColour(LISTBOXTEXT)`, (`MSWCreateControl` → `AllowForWindow` and, for some controls, `SetForegroundColour(LISTBOXTEXT)`,
`src/msw/control.cpp:133-140`). wx cannot flip existing windows — the reason `SetAppearance` refuses late calls. `src/msw/control.cpp:133-140`).
- wx takes ownership of the settings pointer (`wxDarkModeModule::SetSettings`) — allocate it with `new`. - wx takes ownership of the settings pointer (`wxDarkModeModule::SetSettings`) — allocate it with `new`.
- `msw.dark-mode` is read in `wxApp::Initialize` (`src/msw/app.cpp:492-494`): a user's `WX_MSW_DARK_MODE` - `msw.dark-mode` is read in `wxApp::Initialize` (`src/msw/app.cpp:492-494`): a user's `WX_MSW_DARK_MODE`
environment variable enables wx dark mode before Orca's own call. environment variable enables wx dark mode before Orca's own call.
- wx's owner-drawn menu path keys on `wxMSWDarkMode::IsActive()` (`src/msw/menuitem.cpp` `wxMenuItem::OnDrawItem`, - wx's owner-drawn menu path keys on `wxMSWDarkMode::IsActive()` (`src/msw/menuitem.cpp` `wxMenuItem::OnDrawItem`,
`GetColourToUse`; `src/msw/menu.cpp`; menu-bar UAH drawing in `src/msw/darkmode.cpp`). `GetColourToUse`; `src/msw/menu.cpp`; menu-bar UAH drawing in `src/msw/darkmode.cpp`).
3.3.x dark-mode fix log: 3.3.2 wxMSW (`docs/changes.txt:297-308`: checkbox accessibility in dark mode, rendering of 3.3.x dark-mode fix log: 3.3.4 wxMSW (`docs/changes.txt:349-358`: dynamic dark mode, dark mode for
several controls, toolbar, menus; also "Revert use of WS_EX_COMPOSITED"), 3.3.1 (`:358-372`: wxStaticBitmap-in-notebook wxFontPickerCtrl, wxNotebook, wxSpinButton and the common dialogs), 3.3.3 (`:433` "Implement support for
crash, disabled wxButton bitmaps and wxStaticText, notebook high-contrast background, wxDataViewCtrl light-mode switching between light/dark modes"; `:426` wxMessageDialog, `:429` combo/listbox on Windows 11, `:431`
border regression, selected toolbar buttons, wxComboCtrl, wxTE_RICH wxTextCtrl), 3.3.0 (`:385` "Add experimental dark wxCheckBox label in screen readers), 3.3.2 (`:492-501`: checkbox accessibility in dark mode, rendering of
mode support to wxMSW"); XRC dark colour variants (`:494`). several controls, toolbar, menus; also "Revert use of WS_EX_COMPOSITED"), 3.3.1 (`:553-565`:
wxStaticBitmap-in-notebook crash, disabled wxButton bitmaps and wxStaticText, notebook high-contrast
background, wxDataViewCtrl light-mode border regression, selected toolbar buttons, wxComboCtrl, wxTE_RICH
wxTextCtrl), 3.3.0 (`:578` "Add experimental dark mode support to wxMSW"); XRC dark colour variants (`:687`).
**OrcaSlicer.** `GUI_App::on_init_inner` (`#ifdef __WINDOWS__`) calls `MSWEnableDarkMode(DarkMode_Auto)` and then **OrcaSlicer.** `GUI_App::on_init_inner` (`#ifdef __WINDOWS__`) calls `MSWEnableDarkMode(DarkMode_Auto)` and then
`NppDarkMode::InitDarkMode(init_dark_color_mode, init_sys_menu_enabled)`. wx's call exists only so that wx-drawn `NppDarkMode::InitDarkMode(init_dark_color_mode, init_sys_menu_enabled)`. wx's call exists so that wx-drawn
menus get dark borders; NppDarkMode does the theming (title bars, explorer theme, scrollbars, list headers) because menus get dark borders; NppDarkMode does Orca's theming (title bars, explorer theme, scrollbars, list headers).
it can switch live and wx cannot. The code comment "Orca: todo switch to native dark mode support in wxWidgets and The code comment "Orca: todo switch to native dark mode support in wxWidgets and remove NppDarkMode" records the
remove NppDarkMode" records the intent; the blocker is that a live Preferences toggle would become restart-only intent. The old blocker — a live Preferences toggle would be restart-only because `SetAppearance` returned
(`SetAppearance` returns `CannotChange` after startup, existing windows cannot be restyled) and TaskDialog/common `CannotChange` and existing windows could not be restyled — is gone as of 3.3.3/3.3.4 (above). Orca still keeps
dialogs/pickers stay light anyway — which is also why Orca has its own `MsgDialog` family and `ProgressDialog`. NppDarkMode, and Orca's own `MsgDialog` family and `ProgressDialog` remain its message/progress UI.
**[source]** consequences of `DarkMode_Auto`: wx's internal "dark" stays `AllowDark` and follows the **system app **[source]** consequences of `DarkMode_Auto`: wx's internal "dark" stays `AllowDark` and follows the **system app
mode**; NppDarkMode's later `SetPreferredAppMode` call does not touch wx's `gs_appMode`. So with Windows light + mode**; NppDarkMode's later `SetPreferredAppMode` call does not touch wx's `gs_appMode`. So with Windows light +
Orca dark, wx's dark machinery (menus, `GetColour()`, `IsDark()`) stays off; with Windows dark + Orca light it is Orca dark, wx's dark machinery (menus, `GetColour()`, `IsDark()`) stays off; with Windows dark + Orca light it is
@@ -312,11 +318,15 @@ on: `GetColour()` returns the dark palette, new native controls are dark-enabled
``` ```
Cite: bf397a0632 (`GUI_App.cpp`, `GUI_App::on_init_inner`). Cite: bf397a0632 (`GUI_App.cpp`, `GUI_App::on_init_inner`).
- **Rule:** Do not call `wxTheApp->SetAppearance(...)` in Orca. - **Rule:** Do not call `wxTheApp->SetAppearance(...)` in Orca.
**Why:** MSW returns `CannotChange` (Orca already called `MSWEnableDarkMode`), GTK2 fails, and macOS pins **Why:** MSW would switch wx's own mode out of step with NppDarkMode and `dark_color_mode` (wx's mode is driven
by `MSWEnableDarkMode(DarkMode_Auto)` and follows the system), GTK2 fails, and macOS pins
`NSApp.appearance` while `GUI_App::dark_mode()` keeps reading the system `AppleInterfaceStyle` — the two would `NSApp.appearance` while `GUI_App::dark_mode()` keeps reading the system `AppleInterfaceStyle` — the two would
disagree. disagree.
- **Rule:** Do not show wx's TaskDialog-based or common dialogs where dark mode matters; use `MessageDialog` and - **Rule:** Do not show wx's TaskDialog-based or common dialogs; use `MessageDialog` and friends
friends (`MsgDialog.hpp`, see `references/windows-dialogs.md`). (`MsgDialog.hpp`, see `references/windows-dialogs.md`).
**Why:** Orca's dialogs are owner-drawn and consistent with the rest of the UI. The old dark-mode gap
closed — `wxMessageDialog` gained dark mode in 3.3.3 (#26570) and the common dialogs in 3.3.4 (#26780) —
but the convention stands.
## Window colours, inheritance and native-control limits ## Window colours, inheritance and native-control limits
@@ -371,7 +381,7 @@ macOS paints the system grey.
| Port | Behaviour | | Port | Behaviour |
|---|---| |---|---|
| MSW | `wxButton`/`wxToggleButton` `SetBackgroundColour`/`SetForegroundColour` switch the native button to `BS_OWNERDRAW` (`src/msw/anybutton.cpp` `wxAnyButton::MakeOwnerDrawn`, `:1324-1390`) — the colour works but native theming is gone. `wxCheckBox`/`wxRadioButton` foreground makes them owner-drawn when themes are active (`src/msw/control.cpp` `MSWMakeOwnerDrawnIfNecessary`); 3.3.2 fixed checkbox accessibility in that mode (`docs/changes.txt:299-300`). Static-text-like children paint the ancestor brush only if that ancestor's background is inheritable. | | MSW | `wxButton`/`wxToggleButton` `SetBackgroundColour`/`SetForegroundColour` switch the native button to `BS_OWNERDRAW` (`src/msw/anybutton.cpp` `wxAnyButton::MakeOwnerDrawn`, `:1324-1390`) — the colour works but native theming is gone. `wxCheckBox`/`wxRadioButton` foreground makes them owner-drawn when themes are active (`src/msw/control.cpp` `MSWMakeOwnerDrawnIfNecessary`); 3.3.2 fixed checkbox accessibility in that mode (`docs/changes.txt:492-493`). Static-text-like children paint the ancestor brush only if that ancestor's background is inheritable. |
| macOS | `SetBackgroundColour` reaches the NSView only if it `respondsToSelector:setBackgroundColor:` and the style is not `wxBG_STYLE_TRANSPARENT` (`src/osx/cocoa/window.mm:3514-3531`): **NSButton (`wxButton`) ignores the background colour**. Foreground uses `setTextColor:` when the view has it (`:3885-3887`); stock NSButton has none. `wxStaticText` is an NSTextField with `setDrawsBackground:NO` — its background is never painted (`src/osx/cocoa/stattext.mm:154`). `wxTextCtrl`'s `setEnabled:` resets the text colour: multi-line (`wxNSTextView`) always, to `controlTextColor`/`disabledControlTextColor`; single-line (`wxNSTextField`) when it does not draw its background, to `controlTextColor`/`secondarySelectedControlColor` (`src/osx/cocoa/textctrl.mm`). | | macOS | `SetBackgroundColour` reaches the NSView only if it `respondsToSelector:setBackgroundColor:` and the style is not `wxBG_STYLE_TRANSPARENT` (`src/osx/cocoa/window.mm:3514-3531`): **NSButton (`wxButton`) ignores the background colour**. Foreground uses `setTextColor:` when the view has it (`:3885-3887`); stock NSButton has none. `wxStaticText` is an NSTextField with `setDrawsBackground:NO` — its background is never painted (`src/osx/cocoa/stattext.mm:154`). `wxTextCtrl`'s `setEnabled:` resets the text colour: multi-line (`wxNSTextView`) always, to `controlTextColor`/`disabledControlTextColor`; single-line (`wxNSTextField`) when it does not draw its background, to `controlTextColor`/`secondarySelectedControlColor` (`src/osx/cocoa/textctrl.mm`). |
| GTK3 | `SetBackgroundColour/SetForegroundColour/SetFont` install a per-widget CSS provider `*{color:..;background:..;font:..}` at `GTK_STYLE_PROVIDER_PRIORITY_APPLICATION` (`src/gtk/window.cpp` `wxWindowGTK::GTKApplyStyle`); `wxButton`/`wxCheckBox` apply it to their inner label too (`src/gtk/button.cpp:325-335`, `src/gtk/checkbox.cpp:233-237`). User CSS (priority USER) can still override. | | GTK3 | `SetBackgroundColour/SetForegroundColour/SetFont` install a per-widget CSS provider `*{color:..;background:..;font:..}` at `GTK_STYLE_PROVIDER_PRIORITY_APPLICATION` (`src/gtk/window.cpp` `wxWindowGTK::GTKApplyStyle`); `wxButton`/`wxCheckBox` apply it to their inner label too (`src/gtk/button.cpp:325-335`, `src/gtk/checkbox.cpp:233-237`). User CSS (priority USER) can still override. |
| GTK2 | colours applied with `gtk_widget_modify_style` — pixmap-engine themes may ignore them. | | GTK2 | colours applied with `gtk_widget_modify_style` — pixmap-engine themes may ignore them. |
@@ -106,7 +106,7 @@ The general wx rule is that setters do not send events. The exceptions are the b
| `wxTextEntry::SetValue(s)` | **yes**, one `wxEVT_TEXT`, even when `s` equals the current text | `interface/wx/textentry.h:539-542`; [source] `src/common/textentrycmn.cpp:236-254`, `src/msw/textctrl.cpp:1133-1145` | | `wxTextEntry::SetValue(s)` | **yes**, one `wxEVT_TEXT`, even when `s` equals the current text | `interface/wx/textentry.h:539-542`; [source] `src/common/textentrycmn.cpp:236-254`, `src/msw/textctrl.cpp:1133-1145` |
| `wxTextEntry::ChangeValue(s)` | no | `interface/wx/textentry.h:177-178` | | `wxTextEntry::ChangeValue(s)` | no | `interface/wx/textentry.h:177-178` |
| `wxTextEntry::Clear()` | yes (= `SetValue("")`) | `interface/wx/textentry.h:193-194` | | `wxTextEntry::Clear()` | yes (= `SetValue("")`) | `interface/wx/textentry.h:193-194` |
| `wxTextCtrl::SetLabel/SetLabelText` | nothing at all (3.3) | `docs/changes.txt:111-113`; `src/common/textcmn.cpp:934-937` | | `wxTextCtrl::SetLabel/SetLabelText` | nothing at all (3.3) | `docs/changes.txt:117-119`; `src/common/textcmn.cpp:934-937` |
| `SetSelection/SetStringSelection` on wxChoice, wxComboBox, wxListBox, wxRadioBox | no | `interface/wx/ctrlsub.h:102-103,126` | | `SetSelection/SetStringSelection` on wxChoice, wxComboBox, wxListBox, wxRadioBox | no | `interface/wx/ctrlsub.h:102-103,126` |
| `wxComboBox::SetValue` | `wxEVT_TEXT` if editable; none with `wxCB_READONLY` | `interface/wx/combobox.h:256-272` | | `wxComboBox::SetValue` | `wxEVT_TEXT` if editable; none with `wxCB_READONLY` | `interface/wx/combobox.h:256-272` |
| `wxComboBox::Popup()/Dismiss()` | DROPDOWN/CLOSEUP, except on wxOSX | `interface/wx/combobox.h:279-281,292-294` | | `wxComboBox::Popup()/Dismiss()` | DROPDOWN/CLOSEUP, except on wxOSX | `interface/wx/combobox.h:279-281,292-294` |
@@ -184,7 +184,7 @@ Pitfalls:
ctrl->GetTextCtrl()->SetLabel(s); // Wrong: no-op ctrl->GetTextCtrl()->SetLabel(s); // Wrong: no-op
ctrl->GetTextCtrl()->ChangeValue(s); // Right (or SetValue if listeners must react) ctrl->GetTextCtrl()->ChangeValue(s); // Right (or SetValue if listeners must react)
``` ```
Cite: `docs/changes.txt:111-113`. Cite: `docs/changes.txt:117-119`.
- **Rule:** Handle `wxEVT_TEXT_ENTER` without `Skip()` unless you want the default button activated as well. - **Rule:** Handle `wxEVT_TEXT_ENTER` without `Skip()` unless you want the default button activated as well.
**Why:** a skipped Enter falls through to the dialog's default button and closes it. **Why:** a skipped Enter falls through to the dialog's default button and closes it.
```cpp ```cpp
@@ -213,7 +213,7 @@ Contract:
verbatim, and `wxControl::EscapeMnemonics()` escapes it (`interface/wx/control.h:174-195, 379-387`). This applies verbatim, and `wxControl::EscapeMnemonics()` escapes it (`interface/wx/control.h:174-195, 379-387`). This applies
to `wxStaticText`, `wxCheckBox`, `wxRadioButton`, `wxButton` labels and to book page titles: all `wx*book` to `wxStaticText`, `wxCheckBox`, `wxRadioButton`, `wxButton` labels and to book page titles: all `wx*book`
classes interpret mnemonics in page text (`interface/wx/bookctrl.h:141-147`), and since 3.3 wxListbook and classes interpret mnemonics in page text (`interface/wx/bookctrl.h:141-147`), and since 3.3 wxListbook and
wxChoicebook do too (`docs/changes.txt:128-130`). wxChoicebook do too (`docs/changes.txt:134-136`).
- `SetLabelMarkup()` needs well-formed markup or the label "won't be shown at all" (returns false, keeps the old - `SetLabelMarkup()` needs well-formed markup or the label "won't be shown at all" (returns false, keeps the old
label). A bare `&` is still a mnemonic. Multi-line markup works only on GTK and macOS; the generic version used on label). A bare `&` is still a mnemonic. Multi-line markup works only on GTK and macOS; the generic version used on
MSW handles single lines (`interface/wx/control.h:338-347`). Quote untrusted text with MSW handles single lines (`interface/wx/control.h:338-347`). Quote untrusted text with
@@ -383,10 +383,10 @@ Pitfalls:
- Virtual list (`wxLC_REPORT|wxLC_VIRTUAL`): call `SetItemCount()` and override `OnGetItemText` (optionally - Virtual list (`wxLC_REPORT|wxLC_VIRTUAL`): call `SetItemCount()` and override `OnGetItemText` (optionally
`OnGetItemImage`/`OnGetItemAttr`) (`interface/wx/listctrl.h:128-134`). `EditLabel()` asserts without `OnGetItemImage`/`OnGetItemAttr`) (`interface/wx/listctrl.h:128-134`). `EditLabel()` asserts without
`wxLC_EDIT_LABELS` (`docs/changes.txt:68-69`). `wxLC_EDIT_LABELS` (`docs/changes.txt:74-75`).
- Images: prefer `SetImages(std::vector<wxBitmapBundle>)`; `wxImageList` is discouraged - Images: prefer `SetImages(std::vector<wxBitmapBundle>)`; `wxImageList` is discouraged
(`interface/wx/withimages.h:21-40`) and is measured in physical pixels in 3.3 (`docs/changes.txt:85-88`); calling (`interface/wx/withimages.h:21-40`) and is measured in physical pixels in 3.3 (`docs/changes.txt:91-94`); calling
its methods on an invalid (unsized) list now asserts, i.e. fails silently in Orca (`docs/changes.txt:53-56`). its methods on an invalid (unsized) list now asserts, i.e. fails silently in Orca (`docs/changes.txt:59-62`).
`Assign*` transfers ownership, `Set*ImageList` does not (`interface/wx/withimages.h:90-110`). Sizing: `Assign*` transfers ownership, `Set*ImageList` does not (`interface/wx/withimages.h:90-110`). Sizing:
`references/dpi-bitmaps-fonts.md`. `references/dpi-bitmaps-fonts.md`.
- `wxTreeCtrl`: `SelectItem` emits events ([table](#events-from-programmatic-changes)). - `wxTreeCtrl`: `SelectItem` emits events ([table](#events-from-programmatic-changes)).
@@ -402,7 +402,7 @@ Contract:
selection's blocks). selection's blocks).
- `FreezeTo(row, col)` returns false (an assert, silent in Orca) for out-of-range values, merged cells or the native - `FreezeTo(row, col)` returns false (an assert, silent in Orca) for out-of-range values, merged cells or the native
header (`interface/wx/grid.h:5747-5772`); [source] also when rows/columns were reordered or drag-moving is enabled header (`interface/wx/grid.h:5747-5772`); [source] also when rows/columns were reordered or drag-moving is enabled
(`src/generic/grid.cpp:5742-5750`). In 3.3 it freezes even when the grid is too small (`docs/changes.txt:48-51`). (`src/generic/grid.cpp:5742-5750`). In 3.3 it freezes even when the grid is too small (`docs/changes.txt:54-57`).
- Editor contract: `EndEdit` must not modify the grid — it stores the value and returns true if it changed; - Editor contract: `EndEdit` must not modify the grid — it stores the value and returns true if it changed;
`ApplyEdit` writes it after `wxEVT_GRID_CELL_CHANGING` was not vetoed (`interface/wx/grid.h:610-638`). Editors, `ApplyEdit` writes it after `wxEVT_GRID_CELL_CHANGING` was not vetoed (`interface/wx/grid.h:610-638`). Editors,
renderers and attrs are ref-counted and the setters take ownership (`:1263-1305, 1739-1770, 2681-2701`). renderers and attrs are ref-counted and the setters take ownership (`:1263-1305, 1739-1770, 2681-2701`).
@@ -492,7 +492,7 @@ All cites `interface/wx/dataview.h`. MSW uses the generic implementation; wxGTK
Other per-port facts: editing starts on a slow double-click or a platform key — "F2 is typical on Windows, Space Other per-port facts: editing starts on a slow double-click or a platform key — "F2 is typical on Windows, Space
and/or Enter is common elsewhere" (2604-2607, 1915-1918); a custom renderer's `StartDrag()` is "Not yet supported" and/or Enter is common elsewhere" (2604-2607, 1915-1918); a custom renderer's `StartDrag()` is "Not yet supported"
(2717-2719); `RenderText()` should be used inside `Render()` so text matches native renderers (2708-2714). Calling (2717-2719); `RenderText()` should be used inside `Render()` so text matches native renderers (2708-2714). Calling
`Collapse()` from an event handler was fixed in 3.3.1 (`docs/changes.txt:346`; the generic re-check is described `Collapse()` from an event handler was fixed in 3.3.1 (`docs/changes.txt:539`; the generic re-check is described
under [DVC control API](#wxdataviewctrl-control-api)). under [DVC control API](#wxdataviewctrl-control-api)).
OrcaSlicer: `ParamsViewCtrl` (`EditGCodeDialog`) and `DiffViewCtrl` (`UnsavedChangesDialog`) use OrcaSlicer: `ParamsViewCtrl` (`EditGCodeDialog`) and `DiffViewCtrl` (`UnsavedChangesDialog`) use
@@ -1,6 +1,6 @@
# DPI, bitmaps and fonts # DPI, bitmaps and fonts
How wx 3.3.2 maps DIP, logical and physical pixels on each platform, how DPI changes reach a window, How wx 3.3.4 maps DIP, logical and physical pixels on each platform, how DPI changes reach a window,
and how OrcaSlicer sizes layout (`FromDIP`, `em_unit`), rescales (`DPIAware`), rasterizes icons and how OrcaSlicer sizes layout (`FromDIP`, `em_unit`), rescales (`DPIAware`), rasterizes icons
(`BitmapCache`, `create_scaled_bitmap`, `ScalableBitmap`) and chooses fonts (`Label` table). Read it (`BitmapCache`, `create_scaled_bitmap`, `ScalableBitmap`) and chooses fonts (`Label` table). Read it
for any fixed size, icon, bitmap, image list, font, or `on_dpi_changed` work, and when a bug looks for any fixed size, icon, bitmap, image list, font, or `on_dpi_changed` work, and when a bug looks
@@ -488,7 +488,7 @@ handler bound there runs once more after every DPI change.
inherits the DC's scale (`interface/wx/bitmap.h:370-385`). inherits the DC's scale (`interface/wx/bitmap.h:370-385`).
- `wxBitmap(const wxCursor&)` is invalid on GTK under Wayland (`interface/wx/bitmap.h:388-401`). - `wxBitmap(const wxCursor&)` is invalid on GTK under Wayland (`interface/wx/bitmap.h:388-401`).
- wxMSW `wxBitmap::Create(size, dc)` no longer multiplies by the DC's content scale - wxMSW `wxBitmap::Create(size, dc)` no longer multiplies by the DC's content scale
(`docs/changes.txt:94-96`). (`docs/changes.txt:100-102`).
**Offscreen drawing.** "The scaling factor of the bitmap determines the scaling factor used by **Offscreen drawing.** "The scaling factor of the bitmap determines the scaling factor used by
this device context" (`interface/wx/dcmemory.h:41-58`); `wxMemoryDC(wxDC*)` does **not** inherit this device context" (`interface/wx/dcmemory.h:41-58`); `wxMemoryDC(wxDC*)` does **not** inherit
@@ -740,7 +740,7 @@ are in `references/popups-menus.md`.
in the new code as it doesn't support showing DPI-dependent bitmaps. Please use in the new code as it doesn't support showing DPI-dependent bitmaps. Please use
wxWithImages::SetImages() instead"; "the size is specified in physical pixels and must correspond wxWithImages::SetImages() instead"; "the size is specified in physical pixels and must correspond
to the size of bitmaps … that will be added". 3.3 made the size physical and makes calls on an to the size of bitmaps … that will be added". 3.3 made the size physical and makes calls on an
invalid list assert (`docs/changes.txt:53-56, 85-88`) — silently in Orca's assert-free build. invalid list assert (`docs/changes.txt:59-62, 91-94`) — silently in Orca's assert-free build.
When a list is unavoidable, `wxBitmapBundle::CreateImageList(win, bundles)` builds one at the When a list is unavoidable, `wxBitmapBundle::CreateImageList(win, bundles)` builds one at the
consensus size (public but undocumented, [source] `include/wx/bmpbndl.h`). consensus size (public but undocumented, [source] `include/wx/bmpbndl.h`).
```cpp ```cpp
@@ -761,7 +761,7 @@ wxArtProvider::GetBitmapBundle(wxART_WARNING, wxART_OTHER, wxSize(16, 16));
``` ```
**`wxImage`** resizing (`interface/wx/image.h:28-89`): `wxIMAGE_QUALITY_NEAREST` is no longer an **`wxImage`** resizing (`interface/wx/image.h:28-89`): `wxIMAGE_QUALITY_NEAREST` is no longer an
alias of `NORMAL` since 3.3.0 (`docs/changes.txt:98-99`; `wxIMAGE_QUALITY_FAST` is the speed alias of `NORMAL` since 3.3.0 (`docs/changes.txt:104-105`; `wxIMAGE_QUALITY_FAST` is the speed
synonym). `NORMAL` (default) = bilinear down to an integer multiple, then box average; `HIGH` = synonym). `NORMAL` (default) = bilinear down to an integer multiple, then box average; `HIGH` =
box average when shrinking, bicubic when enlarging; `BILINEAR`, `BICUBIC`, `BOX_AVERAGE` explicit. box average when shrinking, bicubic when enlarging; `BILINEAR`, `BICUBIC`, `BOX_AVERAGE` explicit.
High-quality scaling "may not work as expected when using a single mask colour for High-quality scaling "may not work as expected when using a single mask colour for
@@ -1,6 +1,6 @@
# Events: binding, dispatch, posting and deferred calls # Events: binding, dispatch, posting and deferred calls
How wx 3.3.2 finds, runs, propagates, queues and drops event handlers, and how OrcaSlicer code How wx 3.3.4 finds, runs, propagates, queues and drops event handlers, and how OrcaSlicer code
binds, emits and defers. Read it before writing any `Bind`/`Unbind`, `Skip()`, `ProcessEvent`, binds, emits and defers. Read it before writing any `Bind`/`Unbind`, `Skip()`, `ProcessEvent`,
`wxPostEvent`/`wxQueueEvent` or `CallAfter`, before defining a custom event, and when debugging a `wxPostEvent`/`wxQueueEvent` or `CallAfter`, before defining a custom event, and when debugging a
handler that never runs, runs twice, runs on a dead object, or swallows a widget's own behaviour. handler that never runs, runs twice, runs on a dead object, or swallows a widget's own behaviour.
@@ -1,6 +1,6 @@
# Mouse, keyboard and focus # Mouse, keyboard and focus
How input reaches wx windows in the wxWidgets 3.3.2 build Orca ships, and the Orca conventions on How input reaches wx windows in the wxWidgets 3.3.4 build Orca ships, and the Orca conventions on
top: mouse capture, mouse and key events, accelerators and Orca's shortcut registry, focus, top: mouse capture, mouse and key events, accelerators and Orca's shortcut registry, focus,
tooltips and cursors. Read it when a widget captures the mouse or tracks hover, when adding or tooltips and cursors. Read it when a widget captures the mouse or tracks hover, when adding or
changing a keyboard shortcut, when touching focus, tooltip or cursor code, and when debugging an changing a keyboard shortcut, when touching focus, tooltip or cursor code, and when debugging an
@@ -297,7 +297,7 @@ Per port [source]:
non-enter event while the cached position is invalid is treated as the enter. non-enter event while the cached position is invalid is treated as the enter.
- **GTK:** crossing events with a grab/ungrab mode are ignored; outside capture wx re-derives the - **GTK:** crossing events with a grab/ungrab mode are ignored; outside capture wx re-derives the
window under the pointer on each motion (`src/gtk/window.cpp:2073-2117, 2384-2456`; fixes #24339 window under the pointer on each motion (`src/gtk/window.cpp:2073-2117, 2384-2456`; fixes #24339
and #24931–#24933 are in this release, `docs/changes.txt:537, 547`). and #24931–#24933 are in this release, `docs/changes.txt:730, 740`).
- **macOS:** each view's `NSTrackingArea` uses `NSTrackingInVisibleRect` - **macOS:** each view's `NSTrackingArea` uses `NSTrackingInVisibleRect`
(`src/osx/cocoa/window.mm:3924`) and covers its children, so do not rely on the parent getting (`src/osx/cocoa/window.mm:3924`) and covers its children, so do not rely on the parent getting
LEAVE when the pointer moves onto a child. `NSMouseMoved` is delivered only to the deepest view LEAVE when the pointer moves onto a child. `NSMouseMoved` is delivered only to the deepest view
@@ -334,7 +334,7 @@ A composite's hover state must therefore track its children. Orca's `StateHandle
`CS_DBLCLKS`, `src/msw/app.cpp:584`). GTK drops the surplus press before `GDK_2BUTTON_PRESS` `CS_DBLCLKS`, `src/msw/app.cpp:584`). GTK drops the surplus press before `GDK_2BUTTON_PRESS`
(`src/gtk/window.cpp:1798-1817`), and GTK2 also suppresses triple clicks (`:1818-1829`). On wxOSX the (`src/gtk/window.cpp:1798-1817`), and GTK2 also suppresses triple clicks (`:1818-1829`). On wxOSX the
third press of a triple click is a DOWN again, as on MSW (`src/osx/cocoa/window.mm:4105-4140`; third press of a triple click is a DOWN again, as on MSW (`src/osx/cocoa/window.mm:4105-4140`;
#25886, `docs/changes.txt:316`). `GetClickCount()` is "implemented only in wxMac and returns -1 #25886, `docs/changes.txt:509`). `GetClickCount()` is "implemented only in wxMac and returns -1
for the other platforms" (`interface/wx/event.h:2965-2974`). for the other platforms" (`interface/wx/event.h:2965-2974`).
- **Context menu:** "under MSW the context menu event is generated after EVT_RIGHT_UP … but under - **Context menu:** "under MSW the context menu event is generated after EVT_RIGHT_UP … but under
GTK … after EVT_RIGHT_DOWN", so a window handling `wxEVT_CONTEXT_MENU` must not handle (or must GTK … after EVT_RIGHT_DOWN", so a window handling `wxEVT_CONTEXT_MENU` must not handle (or must
@@ -398,7 +398,7 @@ A diagonal trackpad scroll on macOS sends two events, vertical first, then one w
| `ClientToScreen()`, `ScreenToClient()`, `GetScreenRect()` | — | add the top-level window's `gdk_window_get_origin()` (`src/gtk/window.cpp:4630-4698`). Without a global origin the result is only meaningful relative to the same top-level window: fine for deltas and hit tests inside one window, wrong across windows or for absolute placement | | `ClientToScreen()`, `ScreenToClient()`, `GetScreenRect()` | — | add the top-level window's `gdk_window_get_origin()` (`src/gtk/window.cpp:4630-4698`). Without a global origin the result is only meaningful relative to the same top-level window: fine for deltas and hit tests inside one window, wrong across windows or for absolute placement |
| `wxFindWindowAtPoint(pt)` | deepest window at a screen point; disabled children count, hidden ones are skipped (`interface/wx/utils.h:385-394`) | built on screen rectangles, so unreliable. On GTK it is `wxGenericFindWindowAtPoint`, a walk over every top-level window and child (`src/gtk/utilsgtk.cpp:98-101`, `src/common/utilscmn.cpp:1294-1345`) | | `wxFindWindowAtPoint(pt)` | deepest window at a screen point; disabled children count, hidden ones are skipped (`interface/wx/utils.h:385-394`) | built on screen rectangles, so unreliable. On GTK it is `wxGenericFindWindowAtPoint`, a walk over every top-level window and child (`src/gtk/utilsgtk.cpp:98-101`, `src/common/utilscmn.cpp:1294-1345`) |
| `wxGetKeyState(key)` | "In wxGTK, this function can be only used with modifier keys … when not using X11 backend" (`interface/wx/utils.h:352-358`) | Ctrl/Alt/Shift and Caps/Num/Scroll Lock only; any other key returns false (`src/unix/utilsx11.cpp:2596-2662`) | | `wxGetKeyState(key)` | "In wxGTK, this function can be only used with modifier keys … when not using X11 backend" (`interface/wx/utils.h:352-358`) | Ctrl/Alt/Shift and Caps/Num/Scroll Lock only; any other key returns false (`src/unix/utilsx11.cpp:2596-2662`) |
| `WarpPointer()` | Apple's HIG forbids it; on Wayland it works only with a compositor implementing the pointer-warp protocol, and mutter also needs a pressed button (`interface/wx/window.h:3895-3914`; `docs/changes.txt:294`) | — | | `WarpPointer()` | Apple's HIG forbids it; on Wayland it works only with a compositor implementing the pointer-warp protocol, and mutter also needs a pressed button (`interface/wx/window.h:3895-3914`; `docs/changes.txt:487`) | — |
| `wxUIActionSimulator` | "doesn't work when using Wayland" (`interface/wx/uiaction.h:20`) | — | | `wxUIActionSimulator` | "doesn't work when using Wayland" (`interface/wx/uiaction.h:20`) | — |
| `PopupMenu(x, y)` | — | GTK ≥ 3.22 positions it relative to the window (`gtk_menu_popup_at_rect`, `src/gtk/window.cpp:6520-6565`), so it is safe | | `PopupMenu(x, y)` | — | GTK ≥ 3.22 positions it relative to the window (`gtk_menu_popup_at_rect`, `src/gtk/window.cpp:6520-6565`), so it is safe |
@@ -540,7 +540,7 @@ The full Esc/close path is in `references/windows-dialogs.md`.
layout"; specials are their `WXK_*` (`:1371-1394`). A Cyrillic `ц` gives `'W'`, so Ctrl+letter layout"; specials are their `WXK_*` (`:1371-1394`). A Cyrillic `ц` gives `'W'`, so Ctrl+letter
shortcuts work across layouts, but an AZERTY key reports its own label (`$` where US has `]`), so shortcuts work across layouts, but an AZERTY key reports its own label (`$` where US has `]`), so
`Ctrl-;`-style punctuation accelerators may be untypeable on some layouts (`:1396-1407`). wxGTK `Ctrl-;`-style punctuation accelerators may be untypeable on some layouts (`:1396-1407`). wxGTK
got the non-Latin mapping in 3.3.0 (#23379, `docs/changes.txt:540`). got the non-Latin mapping in 3.3.0 (#23379, `docs/changes.txt:733`).
- `wxEVT_CHAR` reflects Shift and the layout. Ctrl+letter gives 1..26 (`WXK_CONTROL_A` …, - `wxEVT_CHAR` reflects Shift and the layout. Ctrl+letter gives 1..26 (`WXK_CONTROL_A` …,
`:1409-1421`). Exception: on macOS Cmd+letter's CHAR is the letter itself (`'a'`/`'A'`); only the `:1409-1421`). Exception: on macOS Cmd+letter's CHAR is the letter itself (`'a'`/`'A'`); only the
physical Control key yields 1..26 (`src/osx/cocoa/window.mm:304-307`). physical Control key yields 1..26 (`src/osx/cocoa/window.mm:304-307`).
@@ -629,8 +629,14 @@ Space/Return holds the mouse capture until its KEY_UP reaches the button. On MSW
### Contract ### Contract
- "An accelerator takes precedence over normal processing" (`interface/wx/accel.h:178`), but it - "An accelerator takes precedence over normal processing" (`interface/wx/accel.h:178`). Since 3.3.4 this
runs after `wxEVT_CHAR_HOOK` on every port (table above). holds on every port (wxGTK used to let the focused window handle the key first), unless the focused
window claims the key. The accelerator walk still runs after `wxEVT_CHAR_HOOK` (table above). The new
`wxEVT_ACCELERATOR_KEY` event (`interface/wx/event.h:1740-1801`, `@since 3.3.4`) is sent to the focus
window — and propagated to its parents — before an accelerator is used; it is sent after
`wxEVT_CHAR_HOOK` on most ports and before it on macOS. Its handler can call `UseAccelerator()`, and a
window that must keep the key overrides `wxWindow::ClaimsKeyBeforeAccelerator()`
(`interface/wx/window.h:4554-4583`).
- [source] On GTK and macOS a hit is sent as `wxEVT_MENU` with the entry's id and, if unprocessed, - [source] On GTK and macOS a hit is sent as `wxEVT_MENU` with the entry's id and, if unprocessed,
retried as `wxEVT_BUTTON`; macOS treats the key as consumed either way retried as `wxEVT_BUTTON`; macOS treats the key as consumed either way
(`src/gtk/window.cpp:1340-1366`, `src/osx/window_osx.cpp:2563-2590`). On MSW the `WM_COMMAND` goes to (`src/gtk/window.cpp:1340-1366`, `src/osx/window_osx.cpp:2563-2590`). On MSW the `WM_COMMAND` goes to
@@ -654,11 +660,16 @@ Space/Return holds the mouse capture until its KEY_UP reaches the button. On MSW
them in `wxMenuBar::RebuildAccelTable` (`src/msw/menu.cpp:1264-1292`); GTK adds the menu's accel them in `wxMenuBar::RebuildAccelTable` (`src/msw/menu.cpp:1264-1292`); GTK adds the menu's accel
group to the top-level window in `AttachToFrame` (`src/gtk/menu.cpp:239-247`). A menu shown with group to the top-level window in `AttachToFrame` (`src/gtk/menu.cpp:239-247`). A menu shown with
`PopupMenu` treats `"\tCtrl+X"` as display text. `PopupMenu` treats `"\tCtrl+X"` as display text.
- **MSW:** accelerators are not translated while a `wxTextCtrl`/`wxComboBox`/`wxSpinCtrl` has focus and - **Text-entry controls claim their editing keys on every port since 3.3.4.** A `wxTextCtrl`, a
the key is a text-editing key: Ctrl+A/C/V/X/Ins/Del/Home/End/Left/Right, Shift+those navigation non-read-only `wxComboBox` or a `wxSpinCtrl` overrides `ClaimsKeyBeforeAccelerator()` to return
keys, bare Del/Home/End, Alt+Backspace (`src/msw/textentry.cpp:1073-1150`). Multi-line controls also `wxTextEntryBase::IsUsedForEditing()` (`src/common/textcmn.cpp:136-140`;
keep Enter (`src/msw/textctrl.cpp:2110-2135`). `src/common/spinctrlcmn.cpp:160-167`; `src/msw/combobox.cpp:389-395`, `src/gtk/combobox.cpp:205-211`):
- **GTK:** the accelerator walk has no such exemption (`src/gtk/window.cpp:1340-1366`). As menu Alt+Backspace; any printable key with no modifier or Shift (except Delete, so Esc/Enter/Tab stay
usable); Backspace/Delete/Home/End with no modifier or Shift; Ctrl+A/C/V/X; and Insert/Delete/Home/
End/Left/Right with Ctrl or Shift. A matching menu accelerator does not fire while such a control has
focus. The set lives in `IsUsedForEditing` (`src/common/textentrycmn.cpp:441-509`).
- **GTK:** the accelerator walk now consults `ClaimsKeyBeforeAccelerator()` too
(`src/gtk/window.cpp:1524-1539`), so the text-control exemption above applies here since 3.3.4. As menu
accelerators, Shift with non-alphabetic keys does not work, bare arrow keys do not work, and the accelerators, Shift with non-alphabetic keys does not work, bare arrow keys do not work, and the
listed keys (Tab, the modifiers, locks …) are unsupported (`interface/wx/menuitem.h:562-575`). listed keys (Tab, the modifiers, locks …) are unsupported (`interface/wx/menuitem.h:562-575`).
- **macOS:** menu-bar items become `NSMenuItem` key equivalents - **macOS:** menu-bar items become `NSMenuItem` key equivalents
@@ -69,9 +69,12 @@ Contents: [The stack](#the-stack-orcas-gui-is-built-on) ·
## The stack Orca's GUI is built on ## The stack Orca's GUI is built on
- **wxWidgets 3.3.2, SoftFever fork.** `deps/wxWidgets/wxWidgets.cmake` fetches - **wxWidgets 3.3.4, upstream.** `deps/wxWidgets/wxWidgets.cmake` fetches
`https://github.com/SoftFever/Orca-deps-wxWidgets` at tag `v3.3.2` and builds it static `https://github.com/wxWidgets/wxWidgets` at tag `v3.3.4` and builds it static
(`-DwxBUILD_SHARED=OFF`); Flatpak builds build it shared. Linux builds against **GTK3** by default (`-DwxBUILD_SHARED=OFF`); Flatpak builds build it shared. Two in-tree platform patches apply on
Apple and Windows only (`0001-macos-use-srgb-colour-components.patch`,
`0002-clang-cl-sibling-compiler-prefix.patch`) — `references/platforms.md`. Linux builds against
**GTK3** by default
(`option(DEP_WX_GTK3 "Build wxWidgets against GTK3" ON)` in `deps/CMakeLists.txt`, `SLIC3R_GTK` (`option(DEP_WX_GTK3 "Build wxWidgets against GTK3" ON)` in `deps/CMakeLists.txt`, `SLIC3R_GTK`
default `"3"`, Flatpak uses gtk3). GTK2 exists only as an opt-out (`-DDEP_WX_GTK3=OFF`) and loses default `"3"`, Flatpak uses gtk3). GTK2 exists only as an opt-out (`-DDEP_WX_GTK3=OFF`) and loses
EGL, WebKit2 and DIP pixels. Code guarded for GTK should still compile on GTK2, but GTK3 under X11 EGL, WebKit2 and DIP pixels. Code guarded for GTK should still compile on GTK2, but GTK3 under X11
@@ -85,11 +88,12 @@ Contents: [The stack](#the-stack-orcas-gui-is-built-on) ·
- **Orca's own widget library.** New UI code largely does not use raw wx controls: the owner-drawn - **Orca's own widget library.** New UI code largely does not use raw wx controls: the owner-drawn
widgets in `src/slic3r/GUI/Widgets/` (`Button`, `CheckBox`, `ComboBox`, `TextInput`, `SpinInput`, widgets in `src/slic3r/GUI/Widgets/` (`Button`, `CheckBox`, `ComboBox`, `TextInput`, `SpinInput`,
`SwitchButton`, `RadioGroup`, `Label`, `DialogButtons`, …) replace them. Reasons: native controls `SwitchButton`, `RadioGroup`, `Label`, `DialogButtons`, …) replace them. Reasons: native controls
cannot follow Orca's look or its app-level dark-mode toggle; on Windows wx's native dark mode does cannot follow Orca's look or its app-level dark-mode toggle; on Windows wx's native dark mode reaches
not reach anything built on `TaskDialog()` (`wxMessageBox`, `wxMessageDialog`, `wxRichMessageDialog`, the `TaskDialog()`-based boxes (`wxMessageBox`, `wxMessageDialog`, `wxRichMessageDialog`,
`wxProgressDialog`) nor the wrapped common dialogs (`wxColourDialog`, `wxFontDialog`, …) `wxProgressDialog`) since 3.3.3 and the wrapped common dialogs (`wxColourDialog`, `wxFontDialog`, …)
(`interface/wx/app.h:1434-1443`), so Orca shows the `MsgDialog` family and its own generic since 3.3.4, but the date/time/calendar controls, `wxPrintDialog` on Windows 10 and MDI applications
`Widgets/ProgressDialog` instead; and on GTK the theme's borders bleed through wrapped native stay light (`interface/wx/app.h:1442-1448`), so Orca shows the `MsgDialog` family and its own generic
`Widgets/ProgressDialog` for a consistent look; and on GTK the theme's borders bleed through wrapped native
controls (the widgets call `RemoveButtonBorder` / `RemoveInputBorder` under `__WXGTK__`). controls (the widgets call `RemoveButtonBorder` / `RemoveInputBorder` under `__WXGTK__`).
Plain containers stay raw (`wxPanel`, `wxBoxSizer`, `wxScrolledWindow`). Plain containers stay raw (`wxPanel`, `wxBoxSizer`, `wxScrolledWindow`).
- **Namespaces.** Most widgets are in the global namespace; a few (`DialogButtons`, `HyperLink`, - **Namespaces.** Most widgets are in the global namespace; a few (`DialogButtons`, `HyperLink`,
@@ -67,9 +67,10 @@ Contents: [Rules](#rules) · [Why the library exists](#why-the-library-exists)
Native controls cannot carry Orca's flat, rounded, palette-coloured look, and they cannot follow all of Orca's Native controls cannot carry Orca's flat, rounded, palette-coloured look, and they cannot follow all of Orca's
theming: theming:
- On Windows the theme is an app-level setting (Preferences "Enable dark Mode", Windows-only) layered on - On Windows the theme is an app-level setting (Preferences "Enable dark Mode", Windows-only) layered on
`MSWEnableDarkMode`, and wx's MSW dark mode does not reach `TaskDialog()`-based dialogs (`wxMessageBox`, `MSWEnableDarkMode`; wx's MSW dark mode now reaches the `TaskDialog()`-based dialogs (`wxMessageBox`,
`wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`), the common dialogs or the date/time pickers `wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`) since 3.3.3 and the common dialogs since 3.3.4,
(`interface/wx/app.h:1436-1445`). Hence the `MsgDialog` family (`references/windows-dialogs.md`) and Orca's own but the date/time pickers, `wxPrintDialog` on Windows 10 and MDI applications stay light
(`interface/wx/app.h:1442-1448`). Hence the `MsgDialog` family (`references/windows-dialogs.md`) and Orca's own
`ProgressDialog`. `ProgressDialog`.
- On macOS and Linux Orca follows the system appearance; native controls are themed by the toolkit, but any - On macOS and Linux Orca follows the system appearance; native controls are themed by the toolkit, but any
light palette colour set on them still needs the `UpdateDarkUI` pass (`references/colours-dark-mode.md`). light palette colour set on them still needs the `UpdateDarkUI` pass (`references/colours-dark-mode.md`).
@@ -6,7 +6,7 @@ to write a custom control on the wx side and how to author an Orca widget on the
`StaticBox`/`StateHandler` foundation. Read it before writing or reviewing any `wxEVT_PAINT` `StaticBox`/`StateHandler` foundation. Read it before writing or reviewing any `wxEVT_PAINT`
handler, `render`/`doRender` method, `messureSize`, or a new class under `src/slic3r/GUI/Widgets/`. handler, `render`/`doRender` method, `messureSize`, or a new class under `src/slic3r/GUI/Widgets/`.
wx cites are relative to the pinned wx 3.3.2 tree (located as in `SKILL.md` §Ground truth). wx cites are relative to the pinned wx 3.3.4 tree (located as in `SKILL.md` §Ground truth).
Orca builds wx with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`: every Orca builds wx with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`: every
wx assert below is compiled out and `wxCHECK*` returns silently, so paint misuse shows up only as wx assert below is compiled out and `wxCHECK*` returns silently, so paint misuse shows up only as
wrong, missing or stale pixels, never as an assert dialog. wrong, missing or stale pixels, never as an assert dialog.
@@ -116,7 +116,7 @@ Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
| Situation | MSW | macOS | GTK3 (X11 and Wayland) | GTK2 (opt-out build) | | Situation | MSW | macOS | GTK3 (X11 and Wayland) | GTK2 (opt-out build) |
|---|---|---|---|---| |---|---|---|---|---|
| Handler creates no `wxPaintDC` | `wxWindowMSW::HandlePaint` sees no DC and lets `DefWindowProc` validate the region: no `WM_PAINT` storm in 3.3.2, but drawing is unclipped and the contract is broken (`src/msw/window.cpp` `HandlePaint`) | no error; the window shows only what the background step left (undetermined under `wxBG_STYLE_PAINT`) | same | same | | Handler creates no `wxPaintDC` | `wxWindowMSW::HandlePaint` sees no DC and lets `DefWindowProc` validate the region: no `WM_PAINT` storm in 3.3.4, but drawing is unclipped and the contract is broken (`src/msw/window.cpp` `HandlePaint`) | no error; the window shows only what the background step left (undetermined under `wxBG_STYLE_PAINT`) | same | same |
| Handler creates a DC, then `Skip()`s | default `OnPaint` (native painting) runs as well | — | — | — | | Handler creates a DC, then `Skip()`s | default `OnPaint` (native painting) runs as well | — | — | — |
| `wxPaintDC` outside a paint event | `wxCHECK_RET(!paintStack.empty(), "wxPaintDC can't be created outside wxEVT_PAINT handler")` (also for a window other than the one being repainted): the DC gets no HDC and every draw call is a silent no-op (`src/msw/dcclient.cpp` `wxPaintDCImpl::wxPaintDCImpl`) | no visible effect | `wxCHECK_RET(cr, "using wxPaintDC without being in a native paint event")`, every draw call is a silent no-op (`src/gtk/dc.cpp:518`) | works (GDK) | | `wxPaintDC` outside a paint event | `wxCHECK_RET(!paintStack.empty(), "wxPaintDC can't be created outside wxEVT_PAINT handler")` (also for a window other than the one being repainted): the DC gets no HDC and every draw call is a silent no-op (`src/msw/dcclient.cpp` `wxPaintDCImpl::wxPaintDCImpl`) | no visible effect | `wxCHECK_RET(cr, "using wxPaintDC without being in a native paint event")`, every draw call is a silent no-op (`src/gtk/dc.cpp:518`) | works (GDK) |
| `wxClientDC` drawing | works on non-composited windows; the doc lists "wxMSW when using double buffering" (`WS_EX_COMPOSITED`, see below) as non-working (`interface/wx/dcclient.h:82-84`), yet `CanBeUsedForDrawing` returns `true` unconditionally (`include/wx/msw/dcclient.h:60`), so it cannot detect that case | never; `CanBeUsedForDrawing` is `false` (`include/wx/osx/dcclient.h:58`) | X11 works; Wayland has no effect, `CanBeUsedForDrawing` is `false` on `wxDisplayWayland` (`src/gtk/dc.cpp` `wxClientDCImpl::CanBeUsedForDrawing`) | works | | `wxClientDC` drawing | works on non-composited windows; the doc lists "wxMSW when using double buffering" (`WS_EX_COMPOSITED`, see below) as non-working (`interface/wx/dcclient.h:82-84`), yet `CanBeUsedForDrawing` returns `true` unconditionally (`include/wx/msw/dcclient.h:60`), so it cannot detect that case | never; `CanBeUsedForDrawing` is `false` (`include/wx/osx/dcclient.h:58`) | X11 works; Wayland has no effect, `CanBeUsedForDrawing` is `false` on `wxDisplayWayland` (`src/gtk/dc.cpp` `wxClientDCImpl::CanBeUsedForDrawing`) | works |
@@ -283,8 +283,8 @@ void MyCard::OnPaint(wxPaintEvent&) {
ancestor up to the TLW (`src/msw/window.cpp` `wxWindowMSW::IsDoubleBuffered`); ancestor up to the TLW (`src/msw/window.cpp` `wxWindowMSW::IsDoubleBuffered`);
`SetDoubleBuffered(on)` toggles that style; `MSWDisableComposited()` removes it up the chain. `SetDoubleBuffered(on)` toggles that style; `MSWDisableComposited()` removes it up the chain.
`WS_EX_COMPOSITED` makes the whole subtree paint bottom-up into one buffer. `WS_EX_COMPOSITED` makes the whole subtree paint bottom-up into one buffer.
- wx 3.3.0 enabled double buffering for all MSW windows (#22851, `docs/changes.txt:557`) and 3.3.2 - wx 3.3.0 enabled double buffering for all MSW windows (#22851, `docs/changes.txt:750`) and 3.3.2
reverted it (#25808, `docs/changes.txt:308`). In 3.3.2 nothing in wx sets `WS_EX_COMPOSITED` reverted it (#25808, `docs/changes.txt:501`). In 3.3.4 nothing in wx sets `WS_EX_COMPOSITED`
unless the app calls `SetDoubleBuffered(true)`: MSW windows are not double-buffered by default, unless the app calls `SetDoubleBuffered(true)`: MSW windows are not double-buffered by default,
exactly as in 3.2. exactly as in 3.2.
- macOS: always double-buffered, `IsDoubleBuffered()` returns `true` (`include/wx/osx/window.h:161`); - macOS: always double-buffered, `IsDoubleBuffered()` returns `true` (`include/wx/osx/window.h:161`);
@@ -439,7 +439,7 @@ Two variants exist:
(`src/msw/gdiimage.cpp` `wxGDIImage::GetScaleFactor`, `src/msw/dcmemory.cpp`; details in (`src/msw/gdiimage.cpp` `wxGDIImage::GetScaleFactor`, `src/msw/dcmemory.cpp`; details in
`references/dpi-bitmaps-fonts.md §wxBitmap`), while `GetLogicalSize()` stays the physical size there. `references/dpi-bitmaps-fonts.md §wxBitmap`), while `GetLogicalSize()` stays the physical size there.
- MSW `wxBitmap::Create(size, dc)` no longer multiplies by the DC content scale; the size is - MSW `wxBitmap::Create(size, dc)` no longer multiplies by the DC content scale; the size is
physical (`docs/changes.txt:94-96`). physical (`docs/changes.txt:100-102`).
**Usage — portable back buffer.** **Usage — portable back buffer.**
```cpp ```cpp
@@ -556,7 +556,7 @@ already prepared ([Buffered painting](#buffered-painting-and-double-buffering)).
must set the appropriate fonts and colours" (`interface/wx/dc.h:775-780`). `GetFont()` returns `wxNullFont` until must set the appropriate fonts and colours" (`interface/wx/dc.h:775-780`). `GetFont()` returns `wxNullFont` until
`SetFont()` is called (`interface/wx/dc.h:715-720`). `SetFont()` is called (`interface/wx/dc.h:715-720`).
- wx 3.3 moved the non-drawing members to `wxReadOnlyDC` and several overridable measuring virtuals - wx 3.3 moved the non-drawing members to `wxReadOnlyDC` and several overridable measuring virtuals
now take it (`docs/changes.txt:228-231`); see `references/wx-33-changes.md`. now take it (`docs/changes.txt:260-263`); see `references/wx-33-changes.md`.
**OrcaSlicer.** Orca widgets measure in `messureSize()`. A `messureSize()` that builds a **OrcaSlicer.** Orca widgets measure in `messureSize()`. A `messureSize()` that builds a
`wxClientDC dc(this)` (`Button::messureSize`, `TextInput::messureSize`) measures correctly on every `wxClientDC dc(this)` (`Button::messureSize`, `TextInput::messureSize`) measures correctly on every
@@ -1,7 +1,7 @@
# Platforms, the wx build, and platform-specific code # Platforms, the wx build, and platform-specific code
Read this when code has to differ per platform, when a bug shows up on only one OS, toolkit or display Read this when code has to differ per platform, when a bug shows up on only one OS, toolkit or display
server, or when you need to know how Orca's wxWidgets is built. It covers the wx fork and its build server, or when you need to know how Orca's wxWidgets is built. It covers the wx source pin and its build
options, platform macros, per-platform summaries that point into the topic files, and where options, platform macros, per-platform summaries that point into the topic files, and where
platform-specific code lives. It also owns runtime X11/Wayland detection, the Wayland gap list, custom platform-specific code lives. It also owns runtime X11/Wayland detection, the Wayland gap list, custom
title bars and window decoration, GTK native-chrome removal, and the cross-platform test checklist. title bars and window decoration, GTK native-chrome removal, and the cross-platform test checklist.
@@ -58,37 +58,46 @@ Contents: [Rules](#rules) · [The wx build Orca uses](#the-wx-build-orca-uses)
## The wx build Orca uses ## The wx build Orca uses
### Source, pin and local patch ### Source, pin and local patches
- `deps/wxWidgets/wxWidgets.cmake` builds `https://github.com/SoftFever/Orca-deps-wxWidgets` at tag - `deps/wxWidgets/wxWidgets.cmake` builds upstream `https://github.com/wxWidgets/wxWidgets` at tag
**`v3.3.2`** (`GIT_SHALLOW ON`, submodules `3rdparty/catch`, `3rdparty/pcre` and `3rdparty/libwebp` **`v3.3.4`** (`GIT_SHALLOW ON`, submodules `3rdparty/catch`, `3rdparty/pcre` and `3rdparty/libwebp`
only). The fork carries Orca's build fixes, the clang-cl fix among them; do not duplicate only). Two in-tree patches under `deps/wxWidgets/` are applied, one per platform, so neither applies
a fork fix as a local patch under `deps/wxWidgets/` (cc390f11ee removed the local on Linux: `0001-macos-use-srgb-colour-components.patch` on Apple and
`0001-Clang-CL-fix.patch` once the fork carried the fix). The fork's clang-cl fix is the MSVC lib-dir `0002-clang-cl-sibling-compiler-prefix.patch` on Windows. The clang-cl patch is the old fork's
selection in the installed `wxWidgetsConfig.cmake`: it looks for `<prefix>_<arch>_lib` (or `_dll`) clang-cl fix ported back to a local patch: it changes the MSVC lib-dir selection in the installed
under the consuming compiler's prefix first and then the sibling one (`clang` ↔ `vc`), because cl `wxWidgetsConfig.cmake` so it looks for `<prefix>_<arch>_lib` (or `_dll`) under the consuming
and clang-cl share an ABI and either can consume either build compiler's prefix first and then the sibling one (`clang` ↔ `vc`), because cl and clang-cl share an
(`build/cmake/wxWidgetsConfig.cmake.in:53-73`). ABI and either can consume either build (`build/cmake/wxWidgetsConfig.cmake.in:53-73`). Because the
- **The one local patch** is `deps/wxWidgets/0001-macos-use-srgb-colour-components.patch`, applied pin is upstream, every other build fix must live as a local patch under `deps/wxWidgets/`.
- **The Apple patch** is `deps/wxWidgets/0001-macos-use-srgb-colour-components.patch`, applied
only `if (APPLE)`. The `PATCH_COMMAND` first runs `git checkout -f -- src/osx/cocoa/colour.mm` and only `if (APPLE)`. The `PATCH_COMMAND` first runs `git checkout -f -- src/osx/cocoa/colour.mm` and
then `git apply`, so the step can run again safely (a7775296b0). The patch makes the wxOSX then `git apply`, so the step can run again safely (a7775296b0). The patch makes the wxOSX
`wxColour` component getters (`wxNSColorRefData::Red/Green/Blue/Alpha` and `IsSolid`) convert the `wxColour` component getters (`wxNSColorRefData::Red/Green/Blue/Alpha` and `IsSolid`) convert the
`NSColor` with `[NSColorSpace sRGBColorSpace]` instead of `NSCalibratedRGBColorSpace`, so colours `NSColor` with `[NSColorSpace sRGBColorSpace]` instead of `NSCalibratedRGBColorSpace`, so colours
read back on macOS match their sRGB values (custom-colour accuracy). Colour usage: read back on macOS match their sRGB values (custom-colour accuracy). Colour usage:
`references/colours-dark-mode.md`. `references/colours-dark-mode.md`.
- **The Windows patch** is `deps/wxWidgets/0002-clang-cl-sibling-compiler-prefix.patch`, applied only
`if (WIN32)`. Its `PATCH_COMMAND` first runs
`git checkout -f -- build/cmake/wxWidgetsConfig.cmake.in` and then `git apply`, so the step can run
again safely. It rewrites the `WIN32_MSVC_NAMING` branch of `build/cmake/wxWidgetsConfig.cmake.in`
to try the consuming compiler's prefix first and then the sibling one (`clang` ↔ `vc`) when locating
the installed `<prefix>_<arch>_lib`/`_dll` directory.
- The checked-out source is the tree that every wx citation in this skill refers to: - The checked-out source is the tree that every wx citation in this skill refers to:
`deps/build/<arch>/dep_wxWidgets-prefix/src/dep_wxWidgets` on macOS and `deps/build/<arch>/dep_wxWidgets-prefix/src/dep_wxWidgets` on macOS and
`deps/<tree>/dep_wxWidgets-prefix/src/dep_wxWidgets` on Linux and Windows (`deps/build` for a `deps/<tree>/dep_wxWidgets-prefix/src/dep_wxWidgets` on Linux and Windows (`deps/build` for a
release build; `build_win.bat` names the others). Locate it with the bash or PowerShell lookup in release build; `build_win.bat` names the others). Locate it with the bash or PowerShell lookup in
`SKILL.md` §Ground truth. On macOS its `SKILL.md` §Ground truth. On macOS its
`src/osx/cocoa/colour.mm` already has the patch applied. `src/osx/cocoa/colour.mm` already has the Apple patch applied; on Windows its
`build/cmake/wxWidgetsConfig.cmake.in` already has the clang-cl patch applied.
- **Flatpak builds wx separately.** `deps/CMakeLists.txt` leaves `dep_wxWidgets` out of the deps - **Flatpak builds wx separately.** `deps/CMakeLists.txt` leaves `dep_wxWidgets` out of the deps
target when `FLATPAK` is set. Instead, `scripts/flatpak/com.orcaslicer.OrcaSlicer.yml` has its own target when `FLATPAK` is set. Instead, `scripts/flatpak/com.orcaslicer.OrcaSlicer.yml` has its own
`wxWidgets` module whose config-opts "mirror deps/wxWidgets/wxWidgets.cmake with FLATPAK=ON, `wxWidgets` module whose config-opts "mirror deps/wxWidgets/wxWidgets.cmake with FLATPAK=ON,
DEP_WX_GTK3=ON": `-DwxBUILD_TOOLKIT=gtk3`, a shared build (`wxBUILD_SHARED=ON`, DEP_WX_GTK3=ON": `-DwxBUILD_TOOLKIT=gtk3`, a shared build (`wxBUILD_SHARED=ON`,
`BUILD_SHARED_LIBS=ON`, `d` debug postfix), and `wxUSE_LIBWEBP=sys`, because the builtin webp `BUILD_SHARED_LIBS=ON`, `d` debug postfix), and `wxUSE_LIBWEBP=sys`, because the builtin webp
libraries are installed only by static builds. It links with lld and pins the fork's tag libraries are installed only by static builds. It links with lld and pins upstream `v3.3.4` at
`orca-3.3.2` at a fixed commit. Option and version changes must be made in both files. commit `6a42a4b999b127cf28a8b5fe686da6b8ca93a9b8`. Option and version changes must be made in both
files; it applies neither patch (GTK3, no MSVC).
### Toolkit per platform ### Toolkit per platform
@@ -188,7 +197,7 @@ Its `wx/gtk/private*` includes are commented out. The per-port headers outside t
`wx/msw/private.h` (`BitmapComboBox.cpp`, `PresetComboBoxes.cpp`, Windows-guarded) and `wx/msw/private.h` (`BitmapComboBox.cpp`, `PresetComboBoxes.cpp`, Windows-guarded) and
`wx/osx/private.h` (`Utils/MacDarkMode.mm`), come with the regular wx install. Private headers are `wx/osx/private.h` (`Utils/MacDarkMode.mm`), come with the regular wx install. Private headers are
port-specific and unversioned. Include one only under the same macro wx uses for that port or port-specific and unversioned. Include one only under the same macro wx uses for that port or
feature, and re-check it whenever the fork is bumped. feature, and re-check it whenever the wx pin is bumped.
### wxInspector ### wxInspector
@@ -268,8 +277,8 @@ Each bullet names the mechanism and the file that owns it.
popups with it are dismissed on deactivation, deferred through `CallAfter`. No key dismisses a popups with it are dismissed on deactivation, deferred through `CallAfter`. No key dismisses a
popup, and `ProcessLeftDown` is never called. `PopupWindow::BindUnfocusEvent` is MSW-only → popup, and `ProcessLeftDown` is never called. `PopupWindow::BindUnfocusEvent` is MSW-only →
`references/popups-menus.md` §5. `references/popups-menus.md` §5.
- **Painting:** in 3.3.2 windows are not double-buffered by default (the 3.3.0 global - **Painting:** in 3.3.4 windows are not double-buffered by default (the 3.3.0 global
`WS_EX_COMPOSITED` was reverted, `docs/changes.txt:308`). Custom widgets buffer by hand → `WS_EX_COMPOSITED` was reverted, `docs/changes.txt:501`). Custom widgets buffer by hand →
`references/painting-custom-widgets.md`. `references/painting-custom-widgets.md`.
- **Building large panels:** every control is a native child window, and outside a sizer pass a move - **Building large panels:** every control is a native child window, and outside a sizer pass a move
or resize is immediate, repainting when the window is shown [source: `src/msw/window.cpp:2036` or resize is immediate, repainting when the window is shown [source: `src/msw/window.cpp:2036`
@@ -284,8 +293,9 @@ Each bullet names the mechanism and the file that owns it.
- **Mouse capture:** `wxEVT_MOUSE_CAPTURE_LOST` and `wxEVT_MOUSE_CAPTURE_CHANGED` are delivered → - **Mouse capture:** `wxEVT_MOUSE_CAPTURE_LOST` and `wxEVT_MOUSE_CAPTURE_CHANGED` are delivered →
`references/mouse-keyboard-focus.md`. `references/mouse-keyboard-focus.md`.
- **Controls:** `wxDataViewCtrl` is the generic implementation (`references/controls-dataview.md`). - **Controls:** `wxDataViewCtrl` is the generic implementation (`references/controls-dataview.md`).
TaskDialog-based dialogs and common dialogs stay light in wx dark mode TaskDialog-based dialogs (since 3.3.3) and common dialogs (since 3.3.4) follow wx dark mode; the
(`interface/wx/app.h:1434-1448`); Orca's `MsgDialog` family is owner-drawn → date/time/calendar controls, `wxPrintDialog` on Windows 10 and MDI applications stay light
(`interface/wx/app.h:1442-1448`); Orca's `MsgDialog` family is owner-drawn →
`references/windows-dialogs.md`. `references/windows-dialogs.md`.
- **WebView:** Edge (WebView2). It needs the runtime (checked by `GUI_App::init_webview_runtime`), - **WebView:** Edge (WebView2). It needs the runtime (checked by `GUI_App::init_webview_runtime`),
creates asynchronously, serves custom schemes as `https://<scheme>.wxsite`, and allows one script creates asynchronously, serves custom schemes as `https://<scheme>.wxsite`, and allows one script
@@ -616,16 +626,16 @@ headers. Rows marked [source] or "protocol" come from the implementation or from
| Area | What happens on Wayland | Cite | Orca handling / owner | | Area | What happens on Wayland | Cite | Orca handling / owner |
|---|---|---|---| |---|---|---|---|
| Global pointer position | `wxGetMousePosition()` / `wxGetMouseState()` call `gdk_device_get_position` [source], but Wayland gives clients no global pointer position, so the result is not a screen position | `src/gtk/window.cpp` `wxGetMousePosition` | use event coordinates + `ClientToScreen` (`BBLTopbar`); dismiss popups by focus tracking (`SearchDialog::Dismiss`) → `references/mouse-keyboard-focus.md` | | Global pointer position | `wxGetMousePosition()` / `wxGetMouseState()` call `gdk_device_get_position` [source], but Wayland gives clients no global pointer position, so the result is not a screen position | `src/gtk/window.cpp` `wxGetMousePosition` | use event coordinates + `ClientToScreen` (`BBLTopbar`); dismiss popups by focus tracking (`SearchDialog::Dismiss`) → `references/mouse-keyboard-focus.md` |
| Top-level position | the compositor places windows, and `SetPosition()` / `Move()` on a TLW have no effect (protocol) | — | `GUI_App::window_pos_restore` restores only size and maximised state; moves go through `gtk_window_begin_move_drag` | | Top-level position | the compositor places windows, and `SetPosition()` / `Move()` on a TLW have no effect (protocol). 3.3.4 added geometry restore through the Wayland XDG session-management protocol (`SaveGeometry`/`RestoreToGeometry` with the new `SaveString`/`RestoreString` fields) | `interface/wx/toplevel.h:439-455, 474-490` | `GUI_App::window_pos_restore` restores only size and maximised state; moves go through `gtk_window_begin_move_drag` |
| Window icon | `SetIcon()` / `SetIcons()` "doesn't do anything when using Wayland … create a `.desktop` file" | `interface/wx/toplevel.h:517-521, 538-542` | `src/dev-utils/platform/unix/com.orcaslicer.OrcaSlicer.desktop` (`Icon=OrcaSlicer`, `StartupWMClass=orca-slicer`) | | Window icon | `SetIcon()` / `SetIcons()` "doesn't do anything when using Wayland … create a `.desktop` file" | `interface/wx/toplevel.h:517-521, 538-542` | `src/dev-utils/platform/unix/com.orcaslicer.OrcaSlicer.desktop` (`Icon=OrcaSlicer`, `StartupWMClass=orca-slicer`) |
| App id | `wxAppConsole::SetClassName()` is the xdg `app_id` with GTK ≥ 3.24.22 (and the AUMID on Windows); it must be set before any TLW. wx applies it when a TLW is mapped, and only if it is non-empty [source: `wxTopLevelWindowGTK::GTKHandleMapped`] | `interface/wx/app.h:765-812` | Orca calls only `SetAppName(SLIC3R_APP_KEY)`, so GTK's default applies. On Windows, `SetClassName` would also change shell behaviour (MRU, Shift+middle-click) | | App id | `wxAppConsole::SetClassName()` is the xdg `app_id` with GTK ≥ 3.24.22 (and the AUMID on Windows); it must be set before any TLW. wx applies it when a TLW is mapped, and only if it is non-empty [source: `wxTopLevelWindowGTK::GTKHandleMapped`] | `interface/wx/app.h:765-812` | Orca calls only `SetAppName(SLIC3R_APP_KEY)`, so GTK's default applies. On Windows, `SetClassName` would also change shell behaviour (MRU, Shift+middle-click) |
| `wxClientDC` | deprecated in 3.3 ("please use wxInfoDC instead for obtaining information", `interface/wx/dcclient.h:43-46`). Drawing through it "simply doesn't have any effect" on GTK3/Wayland or wxOSX. `CanBeUsedForDrawing()` [source]: false on Wayland only for wxGTK (`src/gtk/dc.cpp`), always false on wxOSX, always true on wxMSW (`include/wx/{osx,msw}/dcclient.h`), although its doc also lists "wxMSW when using double buffering" | `interface/wx/dcclient.h:48-53, 80-88` | draw only in `wxPaintDC` after `Refresh()`/`RefreshRect()` → `references/painting-custom-widgets.md` | | `wxClientDC` | deprecated in 3.3 ("please use wxInfoDC instead for obtaining information", `interface/wx/dcclient.h:43-46`). Drawing through it "simply doesn't have any effect" on GTK3/Wayland or wxOSX. `CanBeUsedForDrawing()` [source]: false on Wayland only for wxGTK (`src/gtk/dc.cpp`), always false on wxOSX, always true on wxMSW (`include/wx/{osx,msw}/dcclient.h`), although its doc also lists "wxMSW when using double buffering" | `interface/wx/dcclient.h:48-53, 80-88` | draw only in `wxPaintDC` after `Refresh()`/`RefreshRect()` → `references/painting-custom-widgets.md` |
| `wxWindow::Update()` | "doesn't do anything in wxGTK port when using Wayland". [source] wx skips the GDK update calls there because they broke later updates (#25036) | `interface/wx/window.h:2405-2407` | never rely on `Update()` to paint synchronously | | `wxWindow::Update()` | "doesn't do anything in wxGTK port when using Wayland". [source] wx skips the GDK update calls there because they broke later updates (#25036) | `interface/wx/window.h:2405-2407` | never rely on `Update()` to paint synchronously |
| `WarpPointer()` | works only if the compositor implements the pointer-warp protocol; mutter also needs a mouse button held | `interface/wx/window.h:3902-3907`; `docs/changes.txt:294` | Orca never warps the pointer | | `WarpPointer()` | works only if the compositor implements the pointer-warp protocol; mutter also needs a mouse button held | `interface/wx/window.h:3902-3907`; `docs/changes.txt:487` | Orca never warps the pointer |
| `wxUIActionSimulator` | "currently doesn't work when using Wayland with wxGTK" | `interface/wx/uiaction.h:20` | not used; Orca also builds `wxUSE_XTEST=OFF` | | `wxUIActionSimulator` | "currently doesn't work when using Wayland with wxGTK" | `interface/wx/uiaction.h:20` | not used; Orca also builds `wxUSE_XTEST=OFF` |
| `wxBitmap(const wxCursor&)` | creates an invalid bitmap | `interface/wx/bitmap.h:393-395` | — | | `wxBitmap(const wxCursor&)` | creates an invalid bitmap | `interface/wx/bitmap.h:393-395` | — |
| OpenGL | only EGL; `PreferGLX()` has no effect. Without EGL in the build, wxGTK's `wxGLCanvas` shows a fatal message and refuses to work [source: `src/gtk/glcanvas.cpp` `IsAvailable`]. The EGL surface is a subsurface over the canvas, ready only after map and a frame callback [source: `src/unix/glegl.cpp`] | `interface/wx/glcanvas.h:1094-1095` | `CLI::run` forces X11 when wx lacks EGL; overlays are drawn in GL/ImGui, never as wx children over the canvas → `references/webview-gl-aui-media.md` | | OpenGL | only EGL; `PreferGLX()` has no effect. Without EGL in the build, wxGTK's `wxGLCanvas` shows a fatal message and refuses to work [source: `src/gtk/glcanvas.cpp` `IsAvailable`]. The EGL surface is a subsurface over the canvas, ready only after map and a frame callback [source: `src/unix/glegl.cpp`] | `interface/wx/glcanvas.h:1094-1095` | `CLI::run` forces X11 when wx lacks EGL; overlays are drawn in GL/ImGui, never as wx children over the canvas → `references/webview-gl-aui-media.md` |
| AUI | the doc note "live resize is always used … for wxOSX and wxGTK3 when using Wayland" is obsolete: "As of wxWidgets 3.3.0 this function always returns false", and `wxAUI_MGR_LIVE_RESIZE` is in the default flags. Floating panes need global positions | `interface/wx/aui/framemanager.h:336-345` | `Plater::priv::priv` clears `wxAUI_MGR_ALLOW_FLOATING`; `sanitize_window_layout_for_wayland` strips floating state from the saved layout → `references/webview-gl-aui-media.md` §wxAuiManager | | AUI | the doc note "live resize is always used … for wxOSX and wxGTK3 when using Wayland" is obsolete: "As of wxWidgets 3.3.0 this function always returns false", and `wxAUI_MGR_LIVE_RESIZE` is in the default flags. AUI's docking-hint logic still needs global positions; 3.3.4 added system drag sessions (`StartDragSession`) so wx can move a pane's floating frame under Wayland anyway | `interface/wx/aui/framemanager.h:336-345`; `src/aui/framemanager.cpp:4574-4599` | `Plater::priv::priv` clears `wxAUI_MGR_ALLOW_FLOATING`; `sanitize_window_layout_for_wayland` strips floating state from the saved layout → `references/webview-gl-aui-media.md` §wxAuiManager |
| Popups | a GTK popup is an `xdg_popup` only for COMBO/DROPDOWN/POPUP_MENU hints, so wx creates popups with `GDK_WINDOW_TYPE_HINT_COMBO` [source]. A chained popup's parent must be the mapped popup, and mapping it with a grab deactivates the toplevel (Orca's comments in `DropDown::mouseMove`, `DropDown::ShouldDismissOnTopWindowDeactivate`) | `src/gtk/popupwin.cpp:110-114` | `DropDown` transient-for chain, `ShouldDismissOnTopWindowDeactivate` → `references/popups-menus.md` | | Popups | a GTK popup is an `xdg_popup` only for COMBO/DROPDOWN/POPUP_MENU hints, so wx creates popups with `GDK_WINDOW_TYPE_HINT_COMBO` [source]. A chained popup's parent must be the mapped popup, and mapping it with a grab deactivates the toplevel (Orca's comments in `DropDown::mouseMove`, `DropDown::ShouldDismissOnTopWindowDeactivate`) | `src/gtk/popupwin.cpp:110-114` | `DropDown` transient-for chain, `ShouldDismissOnTopWindowDeactivate` → `references/popups-menus.md` |
| Fractional scale | arrives as an integer GDK scale | `docs/doxygen/overviews/high_dpi.md:348-351` | → `references/dpi-bitmaps-fonts.md` | | Fractional scale | arrives as an integer GDK scale | `docs/doxygen/overviews/high_dpi.md:348-351` | → `references/dpi-bitmaps-fonts.md` |
| Window decorations | some desktop environments draw a title bar on undecorated windows anyway | — | [Undecorated windows](#wayland-undecorated-top-level-windows-splash) | | Window decorations | some desktop environments draw a title bar on undecorated windows anyway | — | [Undecorated windows](#wayland-undecorated-top-level-windows-splash) |
@@ -636,7 +646,9 @@ were two-finger scrolling (703, 3.1.3), the EGL-based `wxGLCanvas` for Wayland (
support (498, both 3.1.5). New with the upgrade: "Many bug fixes for Wayland-specific problem" (397) support (498, both 3.1.5). New with the upgrade: "Many bug fixes for Wayland-specific problem" (397)
and a `wxMediaCtrl` fix (402) in 3.1.6, GDK errors from `PopupMenu()` avoided (317, 3.1.7), and a `wxMediaCtrl` fix (402) in 3.1.6, GDK errors from `PopupMenu()` avoided (317, 3.1.7),
`wxCURSOR_SIZING` fixed (261, 3.2.0). In 3.3, `WarpPointer()` on supported compositors `wxCURSOR_SIZING` fixed (261, 3.2.0). In 3.3, `WarpPointer()` on supported compositors
(`docs/changes.txt:294`) and the EGL/Wayland high-DPI scale fix (`changes.txt:538`). (`docs/changes.txt:487`) and the EGL/Wayland high-DPI scale fix (`changes.txt:731`); in 3.3.4, a fix for
the crash on pointer/seat disconnect (`changes.txt:371`), AUI pane dragging via system drag sessions
(`:372`) and window-geometry restore via XDG session management (`:373`).
## Window decoration and custom title bars ## Window decoration and custom title bars
@@ -658,7 +670,7 @@ There is no `wxCAPTION` on any platform; each port then needs its own handling.
**Contract** [source + documented]. Since wx **3.3.0**, `wxTopLevelWindowMSW::MSWGetStyle` adds **Contract** [source + documented]. Since wx **3.3.0**, `wxTopLevelWindowMSW::MSWGetStyle` adds
`WS_CAPTION` whenever any of `wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX` is set `WS_CAPTION` whenever any of `wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX` is set
(`src/msw/toplevel.cpp:133-135`). The 3.3.0 wxMSW change list says "Turn wxCAPTION on automatically if (`src/msw/toplevel.cpp:133-135`). The 3.3.0 wxMSW change list says "Turn wxCAPTION on automatically if
required by other styles (#23575)" (`docs/changes.txt:581`). Commit eefdabcd98 attributes this to required by other styles (#23575)" (`docs/changes.txt:774`). Commit eefdabcd98 attributes this to
3.3.2, but it is a 3.3.0 change. `SetWindowStyleFlag()` recomputes the native style through 3.3.2, but it is a 3.3.0 change. `SetWindowStyleFlag()` recomputes the native style through
`MSWGetStyle` and turns the bits back on (`src/msw/window.cpp` `wxWindowMSW::MSWUpdateStyle`). `MSWGetStyle` and turns the bits back on (`src/msw/window.cpp` `wxWindowMSW::MSWUpdateStyle`).
@@ -868,10 +880,11 @@ do both). Cite: 6148ba16b3, 988b500f33.
## wx 3.3 migration notes ## wx 3.3 migration notes
Orca moved from **3.1.5** to 3.3.2 in 8248b06337 ("Updated wxWidgets to 3.3.2", #12941; build system Orca moved from **3.1.5** to **3.3.2** in 8248b06337 ("Updated wxWidgets to 3.3.2", #12941; build system
in 2d7e26292b), so the 3.1.6–3.2.0 incompatible changes (`docs/changes_32.txt`) apply as well as in 2d7e26292b); the pin is now upstream **3.3.4** (`deps/wxWidgets/wxWidgets.cmake`, tag `v3.3.4`), so
`docs/changes.txt`. The version digest, every migration commit as a rule for new code, and the the 3.1.6–3.2.0 incompatible changes (`docs/changes_32.txt`) apply as well as `docs/changes.txt`. The
post-upgrade regressions to watch are owned by `references/wx-33-changes.md` (§8). The version digest, every migration commit as a rule for new code, and the post-upgrade regressions to
watch are owned by `references/wx-33-changes.md` (§10); the 3.3.3 and 3.3.4 changes are its §8–§9. The
platform-specific ones are described in this file: the `MainFrame` `WS_CAPTION` handling platform-specific ones are described in this file: the `MainFrame` `WS_CAPTION` handling
([MSW title bar](#msw-the-mainframe-custom-title-bar)), the macOS `kAEGetURL` re-registration and the ([MSW title bar](#msw-the-mainframe-custom-title-bar)), the macOS `kAEGetURL` re-registration and the
`SidePopup` anchoring ([ifdef landscape](#the-ifdef-landscape)), and the GTK criticals filter `SidePopup` anchoring ([ifdef landscape](#the-ifdef-landscape)), and the GTK criticals filter
@@ -1,6 +1,6 @@
# Popups, transient windows and menus # Popups, transient windows and menus
How wx 3.3.2 popups and menus behave on each port, and the Orca wrappers built on them: `PopupWindow`, How wx 3.3.4 popups and menus behave on each port, and the Orca wrappers built on them: `PopupWindow`,
`DropDown`/`ComboBox`, `SidePopup`, the search popups, frameless dialogs used as popups, `MenuFactory`, `DropDown`/`ComboBox`, `SidePopup`, the search popups, frameless dialogs used as popups, `MenuFactory`,
`append_menu_item`, `Plater::PopupMenu` and the macOS menubar versus `BBLTopbar`. Read it before you add `append_menu_item`, `Plater::PopupMenu` and the macOS menubar versus `BBLTopbar`. Read it before you add
or change anything that opens over other UI and must close by itself, or any context menu or menubar item. or change anything that opens over other UI and must close by itself, or any context menu or menubar item.
@@ -791,7 +791,7 @@ created with `wxBORDER_NONE | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT | wxF
`wxWindow`. "The window automatically destroys itself when the user clicks on it or it loses the focus" `wxWindow`. "The window automatically destroys itself when the user clicks on it or it loses the focus"
(`interface/wx/tipwin.h:13-14`). Since 3.3.2 use `static Ref New(parent, text, maxLength, rectBound)`. The (`interface/wx/tipwin.h:13-14`). Since 3.3.2 use `static Ref New(parent, text, maxLength, rectBound)`. The
returned `wxTipWindow::Ref` is "guaranteed to become invalid when the tip window is closed", and the raw returned `wxTipWindow::Ref` is "guaranteed to become invalid when the tip window is closed", and the raw
constructor is deprecated (`tipwin.h:27-132`; `docs/changes.txt:286`). `Create` positions the tip at the mouse constructor is deprecated (`tipwin.h:27-132`; `docs/changes.txt:479`). `Create` positions the tip at the mouse
and pops it up immediately (`src/generic/tipwin.cpp:171-240`); on GTK it also captures the mouse. and pops it up immediately (`src/generic/tipwin.cpp:171-240`); on GTK it also captures the mouse.
`SetBoundingRect` closes the tip when the mouse leaves that rectangle (`tipwin.h:160-172`). Orca: `SetBoundingRect` closes the tip when the mouse leaves that rectangle (`tipwin.h:160-172`). Orca:
`Button::OnParentMotion` (MSW-only tooltips for disabled buttons) keeps a `wxTipWindow::Ref`. `Button::OnParentMotion` (MSW-only tooltips for disabled buttons) keeps a `wxTipWindow::Ref`.
@@ -800,11 +800,11 @@ created with `wxBORDER_NONE | wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT | wxF
`wxRichToolTipPopup` (`src/generic/richtooltipg.cpp`). Re-check it on every wx update. `wxRichToolTipPopup` (`src/generic/richtooltipg.cpp`). Re-check it on every wx update.
- **`wxInfoBar`** "calls its parent wxWindow::Layout() method and assumes that it will change the parent - **`wxInfoBar`** "calls its parent wxWindow::Layout() method and assumes that it will change the parent
layout": add it to the parent's sizer (`interface/wx/infobar.h:38-44`). It is generic on all ports and native layout": add it to the parent's sizer (`interface/wx/infobar.h:38-44`). It is generic on all ports and native
in wxGTK. Use `ShowMessage(msg, flags)`/`Dismiss()`. 3.3 adds `ShowCheckBox` (`docs/changes.txt:460`). in wxGTK. Use `ShowMessage(msg, flags)`/`Dismiss()`. 3.3 adds `ShowCheckBox` (`docs/changes.txt:653`).
- **`wxNotificationMessage`** is "not a window", native on MSW, macOS and GTK (`interface/wx/notifmsg.h:12-18`). - **`wxNotificationMessage`** is "not a window", native on MSW, macOS and GTK (`interface/wx/notifmsg.h:12-18`).
MSW recommends `MSWUseToasts()` before the first notification, macOS needs the alert notification style for MSW recommends `MSWUseToasts()` before the first notification, macOS needs the alert notification style for
actions, and GTK ignores the timeout for warnings and errors (`notifmsg.h:23-38`, 179-182). 3.3 reports the actions, and GTK ignores the timeout for warnings and errors (`notifmsg.h:23-38`, 179-182). 3.3 reports the
dismissal reason (`docs/changes.txt:488`). Orca does not use it. Its in-app notifications are the GL-canvas dismissal reason (`docs/changes.txt:681`). Orca does not use it. Its in-app notifications are the GL-canvas
`NotificationManager`. `NotificationManager`.
## 13. wxMenu and wxMenuItem ## 13. wxMenu and wxMenuItem
@@ -862,7 +862,7 @@ submenu (it leaks), `Destroy(id)` deletes it, and `Remove()` returns ownership (
an item switch it to owner-drawn (`MSWMustUseOwnerDrawn`, `src/msw/menuitem.cpp:1371-1377`). "Owner drawn items an item switch it to owner-drawn (`MSWMustUseOwnerDrawn`, `src/msw/menuitem.cpp:1371-1377`). "Owner drawn items
are also incompatible with dark mode support and using them makes the entire menu containing them to use are also incompatible with dark mode support and using them makes the entire menu containing them to use
standard light mode colours even in dark mode." 3.3.2 reworked MSW dark-mode menu rendering standard light mode colours even in dark mode." 3.3.2 reworked MSW dark-mode menu rendering
(`docs/changes.txt:305-306`); owner-drawn items still opt out of it. (`docs/changes.txt:498-499`); owner-drawn items still opt out of it.
**Labels and accelerators** (`menuitem.h:460-490`, 555-570). **Labels and accelerators** (`menuitem.h:460-490`, 555-570).
- The syntax is `"&Label\tCtrl+X"`; `&&` is a literal ampersand. `CTRL` means Cmd on macOS, and `RAWCTRL` gives - The syntax is `"&Label\tCtrl+X"`; `&&` is a literal ampersand. `CTRL` means Cmd on macOS, and `RAWCTRL` gives
@@ -1,6 +1,6 @@
# Sizers and layout # Sizers and layout
How wx 3.3.2 computes window sizes and lays out children, and how OrcaSlicer builds layouts on top of How wx 3.3.4 computes window sizes and lays out children, and how OrcaSlicer builds layouts on top of
that: sizers and flags, best/min size, the fitting functions (`SetSizerAndFit`, `SetSizeHints`, `Fit`, that: sizers and flags, best/min size, the fitting functions (`SetSizerAndFit`, `SetSizeHints`, `Fit`,
`Layout`, `FitInside`) per platform, show/hide relayout, Freeze/Thaw, scrolled windows, `wxStaticText` `Layout`, `FitInside`) per platform, show/hide relayout, Freeze/Thaw, scrolled windows, `wxStaticText`
wrapping, layout on DPI change, and Orca's layout idioms. Read it when building or reviewing any dialog wrapping, layout on DPI change, and Orca's layout idioms. Read it when building or reviewing any dialog
@@ -604,7 +604,7 @@ Ordinary dialogs and the sidebar use plain `wxScrolledWindow`.
without spaces never wraps with `wxStaticText::Wrap`. without spaces never wraps with `wxStaticText::Wrap`.
- `wxST_WRAP` (new in 3.3.2): "Wrap label text on multiple lines if necessary, using the available - `wxST_WRAP` (new in 3.3.2): "Wrap label text on multiple lines if necessary, using the available
horizontal space. This style only works when the control is used inside a sizer" horizontal space. This style only works when the control is used inside a sizer"
(`interface/wx/stattext.h:46-49`; `docs/changes.txt:280`). It is opt-in; labels without it are (`interface/wx/stattext.h:46-49`; `docs/changes.txt:473`). It is opt-in; labels without it are
unaffected. It is implemented with `GetMinSizeFromKnownDirection` (`stattextcmn.cpp:285-312`). unaffected. It is implemented with `GetMinSizeFromKnownDirection` (`stattextcmn.cpp:285-312`).
**[source]** The initial `CalcMin` still uses the unwrapped best size, so a fitted dialog grows to the **[source]** The initial `CalcMin` still uses the unwrapped best size, so a fitted dialog grows to the
full one-line width and nothing wraps; constrain the width another way (a fixed or min width on the full one-line width and nothing wraps; constrain the width another way (a fixed or min width on the
@@ -44,7 +44,8 @@ Contents: [Rules](#rules) · [Build facts](#build-facts-that-decide-string-behav
12. One complete sentence per msgid, placeholders instead of concatenated fragments, the number 12. One complete sentence per msgid, placeholders instead of concatenated fragments, the number
placeholder in both plural forms, `// TRN` for ambiguous strings, a context for homonyms. placeholder in both plural forms, `// TRN` for ambiguous strings, a context for homonyms.
→ §Plurals and contexts → §Plurals and contexts
13. A wrapper around `wxGetTranslation` returns `wxString` by value. → §Translation 13. A wrapper that converts a translation (`wxString::FromUTF8`, `ToUTF8()`, `format_wxstr`) returns
by value; `wxGetTranslation()` itself returns `const wxString&`. → §Translation
14. User-supplied text (preset, filament, file, printer names) in a mnemonic-interpreting label 14. User-supplied text (preset, filament, file, printer names) in a mnemonic-interpreting label
goes through `SetLabelText` or `wxControl::EscapeMnemonics`. → §Labels goes through `SetLabelText` or `wxControl::EscapeMnemonics`. → §Labels
15. File dialogs: filters from `file_wildcards(FT_*)`, default dir `from_u8(app_config->get_last_dir())`, 15. File dialogs: filters from `file_wildcards(FT_*)`, default dir `from_u8(app_config->get_last_dir())`,
@@ -186,11 +187,11 @@ was the splash screen's event filter, fixed in 4088a36095; see `references/threa
**modifies the string**. Use `s[n].GetValue()` or an explicit `int`/`wchar_t` type **modifies the string**. Use `s[n].GetValue()` or an explicit `int`/`wchar_t` type
(`interface/wx/string.h:171-226`). (`interface/wx/string.h:171-226`).
- Since 3.3 `wxstr = {"Hello", 2}` is ambiguous (the `string_view` constructor); write - Since 3.3 `wxstr = {"Hello", 2}` is ambiguous (the `string_view` constructor); write
`wxString{"Hello", 2}` (`docs/changes.txt:191-194`). `wxString{"Hello", 2}` (`docs/changes.txt:223-226`).
- Never pass a `wxString`, `c_str()` or `mb_str()` to a real C vararg function (`printf`); use - Never pass a `wxString`, `c_str()` or `mb_str()` to a real C vararg function (`printf`); use
`wxString::Format`/`wxPrintf` or convert explicitly (`interface/wx/string.h:262-300`). `wxString::Format`/`wxPrintf` or convert explicitly (`interface/wx/string.h:262-300`).
- `wxUSE_STL` no longer exists; wx 3.3 re-enables implicit `wxString` → `std::string` only through - `wxUSE_STL` no longer exists; wx 3.3 re-enables implicit `wxString` → `std::string` only through
`wxUSE_STD_STRING_CONV_IN_WXSTRING=1` (`docs/changes.txt:163-166`). Orca keeps it 0 and adds `wxUSE_STD_STRING_CONV_IN_WXSTRING=1` (`docs/changes.txt:195-198`). Orca keeps it 0 and adds
`wxNO_UNSAFE_WXSTRING_CONV`; do not enable either conversion, the compile error is the guard. `wxNO_UNSAFE_WXSTRING_CONV`; do not enable either conversion, the compile error is the guard.
### Pitfalls ### Pitfalls
@@ -322,10 +323,13 @@ language's decimal separator; `wxString::ToCDouble`/`FromCDouble` do not.
**wx contract** (`interface/wx/translation.h:577-640`): `wxGetTranslation(string, domain = "", **wx contract** (`interface/wx/translation.h:577-640`): `wxGetTranslation(string, domain = "",
context = "")` returns the original string when no catalog has it; a non-empty context needs a context = "")` returns the original string when no catalog has it; a non-empty context needs a
matching `msgctxt` in the catalog; the plural overload returns `string` for `n == 1` and `plural` matching `msgctxt` in the catalog; the plural overload returns `string` for `n == 1` and `plural`
otherwise when no catalog is found; "This function is thread-safe". Since 3.3 it returns otherwise when no catalog is found; "This function is thread-safe". It returns **`const wxString&`**
**`wxString` by value**, not a const reference: "please change the return type of the function to (`interface/wx/translation.h:615`; `include/wx/translation.h:277-309`). 3.3.2 changed this to a
wxString" (`docs/changes.txt:139-142`). Orca's `I18N::translate` overloads already return by value; by-value `wxString` and **3.3.3 reverted it** to the 3.2.x reference, so the reference points at the
keep any new wrapper that way, a `const wxString&` return now dangles. catalog's own string or at `wxTranslations::GetUntranslatedString()`, both of which outlive the call.
Forwarding that reference is therefore safe; what must return by value is a wrapper that constructs a
temporary — `wxString::FromUTF8`, `ToUTF8()`, `format_wxstr`. Orca's `I18N::translate` overloads
return `wxString` by value and `translate_utf8`/`_u8L` return `std::string`.
**OrcaSlicer macros** (`src/slic3r/GUI/I18N.hpp`): **OrcaSlicer macros** (`src/slic3r/GUI/I18N.hpp`):
@@ -429,7 +433,7 @@ using this class doesn't affect the native controls and dialogs", and on macOS 1
C locale can break the menus (`interface/wx/intl.h:282-292`): native file dialogs, the app menu and C locale can break the menus (`interface/wx/intl.h:282-292`): native file dialogs, the app menu and
standard buttons follow the system language. `wxLocale::IsAvailable` builds a region tag and asks standard buttons follow the system language. `wxLocale::IsAvailable` builds a region tag and asks
`wxUILocale(...).IsSupported()` (`src/common/intl.cpp` `wxLocale::IsAvailable`), which on Unix no `wxUILocale(...).IsSupported()` (`src/common/intl.cpp` `wxLocale::IsAvailable`), which on Unix no
longer falls back to another region of the same language (`docs/changes.txt:75-79`); keep the longer falls back to another region of the same language (`docs/changes.txt:81-85`); keep the
fallbacks in `load_language`. fallbacks in `load_language`.
- **Rule:** translate at use; never store a translated string in a namespace-scope or function-local - **Rule:** translate at use; never store a translated string in a namespace-scope or function-local
@@ -457,7 +461,7 @@ call `SetLabel(label)`) [source]. `SetLabelMarkup` also treats an
unescaped `&` as a mnemonic, needs `&amp;`/`&lt;` for literal characters, strips the markup where it unescaped `&` as a mnemonic, needs `&amp;`/`&lt;` for literal characters, strips the markup where it
is unsupported, and leaves the label unchanged (returns false) when the string is not well-formed is unsupported, and leaves the label unchanged (returns false) when the string is not well-formed
(`interface/wx/control.h:200-360`); user text inside markup must be XML-escaped. (`interface/wx/control.h:200-360`); user text inside markup must be XML-escaped.
Since 3.3 wxListbook/wxChoicebook also interpret mnemonics in page titles (`docs/changes.txt:128-130`); Since 3.3 wxListbook/wxChoicebook also interpret mnemonics in page titles (`docs/changes.txt:134-136`);
Orca uses neither, but the rule is the same for every book control. Orca uses neither, but the rule is the same for every book control.
**OrcaSlicer.** `Label` (`Widgets/Label.cpp`) derives from `wxStaticText`; `Label::SetLabel` stores **OrcaSlicer.** `Label` (`Widgets/Label.cpp`) derives from `wxStaticText`; `Label::SetLabel` stores
@@ -495,7 +499,7 @@ so build it from the wide form (`into_path(w).wstring()`) or stay with boost. At
expands `$VAR`/`%VAR%` inside file names (`interface/wx/filename.h:90-103`); use `MakeAbsolute()` or expands `$VAR`/`%VAR%` inside file names (`interface/wx/filename.h:90-103`); use `MakeAbsolute()` or
explicit `wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE`. 3.3 adds `IsMSWExtendedLengthPath()` for `\\?\` explicit `wxPATH_NORM_DOTS | wxPATH_NORM_ABSOLUTE`. 3.3 adds `IsMSWExtendedLengthPath()` for `\\?\`
paths "avoiding the 260 character path length restriction" (`interface/wx/filename.h:1040-1051`, paths "avoiding the 260 character path length restriction" (`interface/wx/filename.h:1040-1051`,
`docs/changes.txt:551`). `wxFileSystem::FileNameToURL`/`URLToFileName` convert to and from `file:` `docs/changes.txt:744`). `wxFileSystem::FileNameToURL`/`URLToFileName` convert to and from `file:`
URLs (`interface/wx/filesys.h:96-103, 175-180`). URLs (`interface/wx/filesys.h:96-103, 175-180`).
**`wxStandardPaths`** (`interface/wx/stdpaths.h`): the directories "may or may not exist" **`wxStandardPaths`** (`interface/wx/stdpaths.h`): the directories "may or may not exist"
@@ -552,9 +556,9 @@ for (const wxString& p : paths)
| | Behaviour | | | Behaviour |
|---|---| |---|---|
| MSW | New-style `IFileDialog`: wx calls `SetDefaultExtension` with the selected filter's first extension and no longer calls `AppendExtension` itself (`src/msw/filedlg.cpp:1644-1656, 1738-1740`; `docs/changes.txt:556`). `SetExtraControlCreator` → XP-style dialog. | | MSW | New-style `IFileDialog`: wx calls `SetDefaultExtension` with the selected filter's first extension and no longer calls `AppendExtension` itself (`src/msw/filedlg.cpp:1644-1656, 1738-1740`; `docs/changes.txt:749`). `SetExtraControlCreator` → XP-style dialog. |
| macOS | Open dialogs show **no filter choice** and apply all wildcards at once unless `wxSystemOptions::SetOption(wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1)`, and even then non-matching files are only greyed (`interface/wx/filedlg.h:117-128`). Matching compares the lower-cased last path extension (`wxOpenSavePanelDelegate panel:shouldEnableURL:`, `src/osx/cocoa/filedlg.mm:58-88`) [source]: case-insensitive, and a multi-dot pattern such as `*.gcode.3mf` or `*.zip.amf` never matches by itself. `wxFD_OVERWRITE_PROMPT` is always on (`:172-175`); `wxFD_OPEN` always behaves as `wxFD_FILE_MUST_EXIST` (`:184-189`). The save panel replaces the initial file name's extension with the first one in the wildcard (Orca's comment on `file_wildcards`). The native panel runs `runModal` and does not re-raise the parent dialog afterwards (`src/osx/cocoa/filedlg.mm` `ShowModal`); see `references/windows-dialogs.md` for the deferred re-raise. | | macOS | Open dialogs show **no filter choice** and apply all wildcards at once unless `wxSystemOptions::SetOption(wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1)`, and even then non-matching files are only greyed (`interface/wx/filedlg.h:117-128`). Matching compares the lower-cased last path extension (`wxOpenSavePanelDelegate panel:shouldEnableURL:`, `src/osx/cocoa/filedlg.mm:58-88`) [source]: case-insensitive, and a multi-dot pattern such as `*.gcode.3mf` or `*.zip.amf` never matches by itself. `wxFD_OVERWRITE_PROMPT` is always on (`:172-175`); `wxFD_OPEN` always behaves as `wxFD_FILE_MUST_EXIST` (`:184-189`). The save panel replaces the initial file name's extension with the first one in the wildcard (Orca's comment on `file_wildcards`). The native panel runs `runModal` and does not re-raise the parent dialog afterwards (`src/osx/cocoa/filedlg.mm` `ShowModal`); see `references/windows-dialogs.md` for the deferred re-raise. |
| GTK3 | `GtkFileChooserNative` (portal-capable, e.g. Flatpak) when GTK ≥ 3.20 at runtime and neither `wxFD_PREVIEW` nor an extra control/customize hook is used (`src/gtk/filedlg.cpp:265-274, 437-443`; `src/gtk/dirdlg.cpp:122-130`; `docs/changes.txt:393`). It runs through `gtk_native_dialog_run`: there is no wx window, so size/position calls do nothing (`wxFileDialog::DoSetSize` is empty). Patterns go to `gtk_file_filter_add_pattern` per token and are **case-sensitive** (`src/gtk/filectrl.cpp:169`). The chooser is transient for the parent left after `GetParentForModalDialog`, which replaces a null (or hidden, dying or `wxWS_EX_TRANSIENT`) parent with the active top-level window, else the app's main top window (`src/gtk/filedlg.cpp:206, 223-225`; `src/common/dlgcmn.cpp:180-203` `DoGetParentForDialog`) [source]. `wxFD_PREVIEW` is GTK-only (`interface/wx/filedlg.h:195-197`). | | GTK3 | `GtkFileChooserNative` (portal-capable, e.g. Flatpak) when GTK ≥ 3.20 at runtime and neither `wxFD_PREVIEW` nor an extra control/customize hook is used (`src/gtk/filedlg.cpp:265-274, 437-443`; `src/gtk/dirdlg.cpp:122-130`; `docs/changes.txt:586`). It runs through `gtk_native_dialog_run`: there is no wx window, so size/position calls do nothing (`wxFileDialog::DoSetSize` is empty). Patterns go to `gtk_file_filter_add_pattern` per token and are **case-sensitive** (`src/gtk/filectrl.cpp:169`). The chooser is transient for the parent left after `GetParentForModalDialog`, which replaces a null (or hidden, dying or `wxWS_EX_TRANSIENT`) parent with the active top-level window, else the app's main top window (`src/gtk/filedlg.cpp:206, 223-225`; `src/common/dlgcmn.cpp:180-203` `DoGetParentForDialog`) [source]. `wxFD_PREVIEW` is GTK-only (`interface/wx/filedlg.h:195-197`). |
| GTK2 (opt-out build) | never uses the native chooser; patterns case-sensitive. | | GTK2 (opt-out build) | never uses the native chooser; patterns case-sensitive. |
**OrcaSlicer:** **OrcaSlicer:**
@@ -650,7 +654,7 @@ dtor, and `!lock` tests `IsOpened()`.
| | Behaviour | | | Behaviour |
|---|---| |---|---|
| MSW | `SetData`/`GetData` do not check `Open()` (`src/msw/clipbrd.cpp` `wxClipboard::SetData`), so code that forgets it works here only. `wxTextDataObject::SetData()` size must now include the 2-byte NUL (`docs/changes.txt:62-66`); use `SetText()` or the ctor. | | MSW | `SetData`/`GetData` do not check `Open()` (`src/msw/clipbrd.cpp` `wxClipboard::SetData`), so code that forgets it works here only. `wxTextDataObject::SetData()` size must now include the 2-byte NUL (`docs/changes.txt:68-72`); use `SetText()` or the ctor. |
| macOS | without `Open()`, `SetData`/`AddData`/`GetData` return false through `wxCHECK_MSG(m_open, …)` without taking the object (`src/osx/carbon/clipbrd.cpp:84-105, 140-147`); a successful write is flushed to the pasteboard immediately (`:110-114`). | | macOS | without `Open()`, `SetData`/`AddData`/`GetData` return false through `wxCHECK_MSG(m_open, …)` without taking the object (`src/osx/carbon/clipbrd.cpp:84-105, 140-147`); a successful write is flushed to the pasteboard immediately (`:110-114`). |
| GTK | same `wxCHECK_MSG(m_open, …)` early return (`src/gtk/clipbrd.cpp:643-647, 775`). `GetData`/`IsSupported` are asynchronous underneath: `wxClipboardSync` spins `YieldFor(wxEVT_CATEGORY_CLIPBOARD)` until GTK answers and forbids re-entrancy (`src/gtk/clipbrd.cpp:68-92`). PRIMARY selection exists. Under Wayland, Wayland MIME types are advertised next to the X11 atoms (`src/gtk/clipbrd.cpp:655-700`). | | GTK | same `wxCHECK_MSG(m_open, …)` early return (`src/gtk/clipbrd.cpp:643-647, 775`). `GetData`/`IsSupported` are asynchronous underneath: `wxClipboardSync` spins `YieldFor(wxEVT_CATEGORY_CLIPBOARD)` until GTK answers and forbids re-entrancy (`src/gtk/clipbrd.cpp:68-92`). PRIMARY selection exists. Under Wayland, Wayland MIME types are advertised next to the X11 atoms (`src/gtk/clipbrd.cpp:655-700`). |
@@ -793,8 +797,8 @@ from a non-main thread on wxOSX (`:39-40`); `wxCANCEL_DEFAULT` is ignored on wxO
`wxID_OK/wxID_CANCEL/wxID_YES/wxID_NO/wxID_HELP` (`:269-275`), but **`wxMessageBox()` returns `wxID_OK/wxID_CANCEL/wxID_YES/wxID_NO/wxID_HELP` (`:269-275`), but **`wxMessageBox()` returns
`wxYES/wxNO/wxCANCEL/wxOK/wxHELP`** (`:308-312`). `wxRichMessageDialog` is native only on MSW and `wxYES/wxNO/wxCANCEL/wxOK/wxHELP`** (`:308-312`). `wxRichMessageDialog` is native only on MSW and
generic elsewhere (`interface/wx/richmsgdlg.h:18-23`). On MSW every `TaskDialog`-based dialog generic elsewhere (`interface/wx/richmsgdlg.h:18-23`). On MSW every `TaskDialog`-based dialog
(`wxMessageBox`, `wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`) ignores dark mode (`wxMessageBox`, `wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`) has followed dark mode
(`interface/wx/app.h:1436-1440`). since 3.3.3 (`interface/wx/app.h:1442-1448`).
**OrcaSlicer.** UI code uses the MsgDialog family (`MessageDialog`, `RichMessageDialog`, **OrcaSlicer.** UI code uses the MsgDialog family (`MessageDialog`, `RichMessageDialog`,
`WarningDialog`, `ErrorDialog`, `InfoDialog`; `references/windows-dialogs.md` §MsgDialog family) for `WarningDialog`, `ErrorDialog`, `InfoDialog`; `references/windows-dialogs.md` §MsgDialog family) for
@@ -848,7 +852,7 @@ Orca does not use `wxConfig`/`wxFileConfig` (so the 3.3 change of the Unix defau
**Contract** (`interface/wx/secretstore.h`): on Unix it needs libsecret and a running secret service, so **Contract** (`interface/wx/secretstore.h`): on Unix it needs libsecret and a running secret service, so
always check `IsOk(&errmsg)` (`:193-210, 257`); libsecret is no longer required at run time always check `IsOk(&errmsg)` (`:193-210, 257`); libsecret is no longer required at run time
(`docs/changes.txt:533`), so a missing library or service shows up only as `IsOk()` false. (`docs/changes.txt:726`), so a missing library or service shows up only as `IsOk()` false.
`GetDefault()` "may show a dialog to the user under some platforms, so it can take an arbitrarily long `GetDefault()` "may show a dialog to the user under some platforms, so it can take an arbitrarily long
time to return" (`:243-246`). One username per service (`:260-268`). time to return" (`:243-246`). One username per service (`:260-268`).
@@ -7,7 +7,7 @@ yields and nested event loops, progress dialogs, startup, shutdown and exception
screen, and the access rules for `wxGetApp()` and `app_config`. Read it whenever code runs off the screen, and the access rules for `wxGetApp()` and `app_config`. Read it whenever code runs off the
main thread, defers work, starts a timer, yields, shows progress, or runs during startup or shutdown. main thread, defers work, starts a timer, yields, shows progress, or runs during startup or shutdown.
wx cites are relative to the pinned wx 3.3.2 tree (located as in `SKILL.md` §Ground truth). wx cites are relative to the pinned wx 3.3.4 tree (located as in `SKILL.md` §Ground truth).
Orca builds wx with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`, so `wxASSERT` Orca builds wx with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`, so `wxASSERT`
is compiled out and `wxCHECK*` returns silently: a timer started off the main thread never fires on macOS, is compiled out and `wxCHECK*` returns silently: a timer started off the main thread never fires on macOS,
`Exit()` on a loop that is not the active one is ignored, `Start(0)` on macOS fails — all without `Exit()` on a loop that is not the active one is ignored, `Start(0)` on macOS fails — all without
@@ -454,12 +454,12 @@ and aborts the whole app. Wrap the entire body; log and convert to a status the
`wxMessageQueue::Post(T&&)` accepts move-only types (`interface/wx/msgqueue.h:90-97`). `wxMessageQueue::Post(T&&)` accepts move-only types (`interface/wx/msgqueue.h:90-97`).
- `wxTHREAD_WAIT_DEFAULT` is now `wxTHREAD_WAIT_BLOCK`; `wxTHREAD_WAIT_YIELD` "is dangerous" and "is - `wxTHREAD_WAIT_DEFAULT` is now `wxTHREAD_WAIT_BLOCK`; `wxTHREAD_WAIT_YIELD` "is dangerous" and "is
only implemented in wxMSW and simply ignored under the other platforms" (`interface/wx/thread.h:648-675`), only implemented in wxMSW and simply ignored under the other platforms" (`interface/wx/thread.h:648-675`),
so the 3.3 default change (`docs/changes.txt:39-41`) only affects MSW code calling so the 3.3 default change (`docs/changes.txt:45-47`) only affects MSW code calling
`Wait()`/`Delete()` from the GUI thread. `Wait()`/`Delete()` from the GUI thread.
- `wxCRITICAL_SECTION(name)` declares a function-static critical section, which is initialised - `wxCRITICAL_SECTION(name)` declares a function-static critical section, which is initialised
safely only if the function is first called from the main thread before other threads call it; safely only if the function is first called from the main thread before other threads call it;
otherwise make it a global (`interface/wx/thread.h:1762-1779`). Prefer `std::mutex`. otherwise make it a global (`interface/wx/thread.h:1762-1779`). Prefer `std::mutex`.
- `wxSecretStore` documents no thread-affinity notes in 3.3.2 (`interface/wx/secretstore.h`). - `wxSecretStore` documents no thread-affinity notes in 3.3.4 (`interface/wx/secretstore.h`).
## The Jobs framework ## The Jobs framework
@@ -829,8 +829,8 @@ nothing) (`interface/wx/utils.h:1203-1212, 1243-1248`; see `references/strings-i
**Platforms.** On MSW `wxProgressDialog` is native: a TaskDialog run by a **Platforms.** On MSW `wxProgressDialog` is native: a TaskDialog run by a
`wxProgressDialogTaskRunner` **wxThread**, yielding `ALL & ~USER_INPUT` (TIMER and THREAD included) `wxProgressDialogTaskRunner` **wxThread**, yielding `ALL & ~USER_INPUT` (TIMER and THREAD included)
(`src/msw/progdlg.cpp` `DispatchEvents`) **[source]**; anything based on `TaskDialog()` has no dark (`src/msw/progdlg.cpp` `DispatchEvents`) **[source]**; the native `TaskDialog` follows wx dark mode
mode (`interface/wx/app.h:1436-1440`). On macOS and GTK it is `wxGenericProgressDialog`, which creates since 3.3.3 (`interface/wx/app.h:1442-1448`). On macOS and GTK it is `wxGenericProgressDialog`, which creates
a temporary event loop if none is active (`src/generic/progdlgg.cpp:360-366`). On MSW (native a temporary event loop if none is active (`src/generic/progdlgg.cpp:360-366`). On MSW (native
dialog or Orca's generic one) and macOS, `CallAfter` bodies run inside `Update()`/`Pulse()`; on GTK dialog or Orca's generic one) and macOS, `CallAfter` bodies run inside `Update()`/`Pulse()`; on GTK
the masked yield runs no queued event, so they wait until control returns to an event loop the masked yield runs no queued event, so they wait until control returns to an event loop
@@ -839,7 +839,7 @@ the masked yield runs no queued event, so they wait until control returns to an
**OrcaSlicer.** **OrcaSlicer.**
- `Slic3r::GUI::ProgressDialog` (`Widgets/ProgressDialog.hpp`) is a themed fork of - `Slic3r::GUI::ProgressDialog` (`Widgets/ProgressDialog.hpp`) is a themed fork of
`wxGenericProgressDialog`: same `YieldFor(UI | USER_INPUT)` semantics, temporary event loop when `wxGenericProgressDialog`: same `YieldFor(UI | USER_INPUT)` semantics, temporary event loop when
none is active, generic on every platform (so no TaskDialog dark-mode gap). none is active, generic on every platform (so it is themed by Orca, not the native TaskDialog).
- `detail::run_off_thread_with_progress` (`PluginsDialog.hpp`, wrapped by - `detail::run_off_thread_with_progress` (`PluginsDialog.hpp`, wrapped by
`PluginsDialog::run_with_dialog`/`run_with_dialog_wait`): a heap wx `wxProgressDialog` (the native `PluginsDialog::run_with_dialog`/`run_with_dialog_wait`): a heap wx `wxProgressDialog` (the native
TaskDialog on MSW, the generic dialog on macOS and GTK) pulsed by a TaskDialog on MSW, the generic dialog on macOS and GTK) pulsed by a
@@ -1,7 +1,7 @@
# WebView, OpenGL canvas, AUI docking and media # WebView, OpenGL canvas, AUI docking and media
How wxWebView, wxGLCanvas/wxGLContext, wxAuiManager/wxAuiToolBar and the camera view behave in the How wxWebView, wxGLCanvas/wxGLContext, wxAuiManager/wxAuiToolBar and the camera view behave in the
wx 3.3.2 tree Orca builds, and the Orca wrappers built on them: `WebView`, `WebViewHostDialog` and wx 3.3.4 tree Orca builds, and the Orca wrappers built on them: `WebView`, `WebViewHostDialog` and
the web dialogs/panels, `OpenGLManager`, `GLCanvas3D` and its ImGui layer, the Plater docking the web dialogs/panels, `OpenGLManager`, `GLCanvas3D` and its ImGui layer, the Plater docking
manager, `BBLTopbar`, `wxMediaCtrl3`. Read it before touching any browser view, GL canvas, docked manager, `BBLTopbar`, `wxMediaCtrl3`. Read it before touching any browser view, GL canvas, docked
pane, the top bar or the camera view, or when debugging a blank web page, a black or garbled 3D pane, the top bar or the camera view, or when debugging a blank web page, a black or garbled 3D
@@ -242,7 +242,7 @@ a single message handler and the Chromium and IE backends do not support script
| `Add…` return | `false` if *any* handler already exists, whatever its name (`src/msw/webview_edge.cpp:1635-1645`) | always `true` (`src/osx/webview_webkit.mm:620-629`); a duplicate name makes WebKit raise an NSException that cannot be caught and kills the app ([external]: Apple behaviour, recorded in the `WebView::CreateWebView` comment) | `false` on a duplicate or with no view, **but** `g_signal_connect` runs before registration, so a duplicate add leaves a second connection (`src/gtk/webview_webkit2.cpp:1638-1657`) | | `Add…` return | `false` if *any* handler already exists, whatever its name (`src/msw/webview_edge.cpp:1635-1645`) | always `true` (`src/osx/webview_webkit.mm:620-629`); a duplicate name makes WebKit raise an NSException that cannot be caught and kills the app ([external]: Apple behaviour, recorded in the `WebView::CreateWebView` comment) | `false` on a duplicate or with no view, **but** `g_signal_connect` runs before registration, so a duplicate add leaves a second connection (`src/gtk/webview_webkit2.cpp:1638-1657`) |
| `Remove…` | clears the single name (`1647-1652`) | removes the native handler (`632-636`) | unregisters but **does not disconnect** the signal (`1659-1664`): Remove + Add delivers every later message **twice** | | `Remove…` | clears the single name (`1647-1652`) | removes the native handler (`632-636`) | unregisters but **does not disconnect** the signal (`1659-1664`): Remove + Add delivers every later message **twice** |
| `window.<name>` alias | user script `window.<name> = window.chrome.webview` + `ExecuteScript` (`1030-1046`) | `AddUserScript` + **synchronous** `RunScript` (`626-628`) | `AddUserScript` + **synchronous** `RunScript` (`1650-1654`) | | `window.<name>` alias | user script `window.<name> = window.chrome.webview` + `ExecuteScript` (`1030-1046`) | `AddUserScript` + **synchronous** `RunScript` (`626-628`) | `AddUserScript` + **synchronous** `RunScript` (`1650-1654`) |
| Delivery | queued with `AddPendingEvent` (`785-813`); [documented] "Queue Edge wxWebView events" (`docs/changes.txt:525`) | `ProcessWindowEvent` **inside** the `WKScriptMessageHandler` delegate (`1324-1361`) | `HandleWindowEvent` **inside** the GTK signal (`397-409`) | | Delivery | queued with `AddPendingEvent` (`785-813`); [documented] "Queue Edge wxWebView events" (`docs/changes.txt:718`) | `ProcessWindowEvent` **inside** the `WKScriptMessageHandler` delegate (`1324-1361`) | `HandleWindowEvent` **inside** the GTK signal (`397-409`) |
| Event fields | handler name and event object set | name set, **no event object** | **empty `GetMessageHandler()`, no event object** | | Event fields | handler name and event object set | name set, **no event object** | **empty `GetMessageHandler()`, no event object** |
| Body | `get_WebMessageAsJson`, JSON-decoded when it is a string (`798-809`) | NSString as is; dict/array → JSON; NSNumber → `stringValue` (booleans arrive as `1`/`0`); NSNull → `"null"` | object → JSON string, otherwise `ToString` (`64-94`) | | Body | `get_WebMessageAsJson`, JSON-decoded when it is a string (`798-809`) | NSString as is; dict/array → JSON; NSNumber → `stringValue` (booleans arrive as `1`/`0`); NSNull → `"null"` | object → JSON string, otherwise `ToString` (`64-94`) |
@@ -710,8 +710,8 @@ the environment variable `wx_opengl_egl=0` does the same; it exists only when `w
returns true only when EGL is in use (false when `wxHAS_EGL` is undefined); `GetGLXVersion()` returns 0 returns true only when EGL is in use (false when `wxHAS_EGL` is undefined); `GetGLXVersion()` returns 0
when GLX is not in use; both exist only when `wxHAS_GLX` is defined (`interface/wx/glcanvas.h:999-1030`). when GLX is not in use; both exist only when `wxHAS_GLX` is defined (`interface/wx/glcanvas.h:999-1030`).
`wxGLCanvas::CreateSurface()` was removed "as exposing it doesn't make sense when wxGLCanvas may use `wxGLCanvas::CreateSurface()` was removed "as exposing it doesn't make sense when wxGLCanvas may use
either EGL or GLX" (`docs/changes.txt:250-252`); "Allow using GLX and EGL in same program (#26023)" is either EGL or GLX" (`docs/changes.txt:282-284`); "Allow using GLX and EGL in same program (#26023)" is
an upstream 3.3.2 wxGTK change (`docs/changes.txt:290-292`). an upstream 3.3.2 wxGTK change (`docs/changes.txt:485`).
**Source** [source]: **Source** [source]:
- When both backends are built, **EGL is the default even on X11** unless `PreferGLX()` or the - When both backends are built, **EGL is the default even on X11** unless `PreferGLX()` or the
@@ -727,7 +727,7 @@ an upstream 3.3.2 wxGTK change (`docs/changes.txt:290-292`).
(`src/unix/glegl.cpp:801-860`). (`src/unix/glegl.cpp:801-860`).
- The EGL-based `wxGLCanvas` for Wayland dates from 3.1.5 (`docs/changes_32.txt:497`), so it predates - The EGL-based `wxGLCanvas` for Wayland dates from 3.1.5 (`docs/changes_32.txt:497`), so it predates
Orca's upgrade; its Orca's upgrade; its
high-DPI scale under EGL/Wayland was fixed in 3.3.0 (`docs/changes.txt:538`). high-DPI scale under EGL/Wayland was fixed in 3.3.0 (`docs/changes.txt:731`).
**OrcaSlicer.** **OrcaSlicer.**
- `deps/wxWidgets/wxWidgets.cmake` passes `-DwxUSE_GLCANVAS_EGL=ON` (also in the Flatpak manifest). - `deps/wxWidgets/wxWidgets.cmake` passes `-DwxUSE_GLCANVAS_EGL=ON` (also in the Flatpak manifest).
@@ -956,13 +956,13 @@ widgets beside the canvas (a sibling, not a child over it), or in a popup.
`src/aui/framemanager.cpp:910-920`; `OnPaneButton`); `DestroyOnClose` panes are detached and `Destroy()`ed `src/aui/framemanager.cpp:910-920`; `OnPaneButton`); `DestroyOnClose` panes are detached and `Destroy()`ed
(`ClosePane`, `1431-1467`). With several handlers bound, each must `Skip()`. (`ClosePane`, `1431-1467`). With several handlers bound, each must `Skip()`.
- **3.3 changes.** `wxAUI_MGR_HINT_FADE` left the default flags (`interface/wx/aui/framemanager.h:43-50`; - **3.3 changes.** `wxAUI_MGR_HINT_FADE` left the default flags (`interface/wx/aui/framemanager.h:43-50`;
`docs/changes.txt:132`); `wxAUI_MGR_LIVE_RESIZE` joined them (`interface/wx/aui/framemanager.h:59-62`); `AlwaysUsesLiveResize()` "always `docs/changes.txt:138`); `wxAUI_MGR_LIVE_RESIZE` joined them (`interface/wx/aui/framemanager.h:59-62`); `AlwaysUsesLiveResize()` "always
returns false" as of 3.3.0 (`interface/wx/aui/framemanager.h:345`; `src/aui/framemanager.cpp:711-714`), non-live resize being returns false" as of 3.3.0 (`interface/wx/aui/framemanager.h:345`; `src/aui/framemanager.cpp:711-714`), non-live resize being
restored (`docs/changes.txt:490`) — the older "live resize is always used on wxOSX and GTK3/Wayland" restored (`docs/changes.txt:683`) — the older "live resize is always used on wxOSX and GTK3/Wayland"
statement (`interface/wx/aui/framemanager.h:336-340`) is obsolete. Docking hints for floating frames use statement (`interface/wx/aui/framemanager.h:336-340`) is obsolete. Docking hints for floating frames use
`::wxGetMousePosition()` (`src/aui/framemanager.cpp:4139-4148`, `4242-4251`), which Wayland cannot supply. `::wxGetMousePosition()` (`src/aui/framemanager.cpp:4139-4148`, `4242-4251`), which Wayland cannot supply.
- `wxAuiNotebook` (not used by Orca): page indices are logical; use `GetPagePosition()` for on-screen - `wxAuiNotebook` (not used by Orca): page indices are logical; use `GetPagePosition()` for on-screen
order (`docs/changes.txt:121-126`); the default tab art changed (`35-37`). order (`docs/changes.txt:128-132`); the default tab art changed (`41-43`).
**OrcaSlicer.** Orca's docks use `AuiMgr` (`AuiMgr.hpp`), a `wxAuiManager` whose `CreateFloatingFrame` **OrcaSlicer.** Orca's docks use `AuiMgr` (`AuiMgr.hpp`), a `wxAuiManager` whose `CreateFloatingFrame`
returns a `wxAuiFloatingFrame` that applies `UpdateFrameDarkUI`. `init(window)` calls returns a `wxAuiFloatingFrame` that applies `UpdateFrameDarkUI`. `init(window)` calls
@@ -1034,8 +1034,10 @@ Plater (Prepare and Preview); `DesignPanel::m_aui` manages the Design tab's body
``` ```
- **Rule:** Disable floating on Wayland (clear `wxAUI_MGR_ALLOW_FLOATING`, `Floatable(false)`, strip - **Rule:** Disable floating on Wayland (clear `wxAUI_MGR_ALLOW_FLOATING`, `Floatable(false)`, strip
floating state from saved layouts). floating state from saved layouts).
**Why:** AUI's floating and docking-hint logic needs global pointer positions and top-level window **Why:** AUI's docking-hint logic needs global pointer positions and top-level window moves
moves (`wxGetMousePosition`, `wxEVT_MOVE`), which Wayland does not provide. (`wxGetMousePosition`, `wxEVT_MOVE`), which Wayland does not provide. 3.3.4 added system drag sessions
so wx can move a pane's floating frame there anyway (`src/aui/framemanager.cpp` `StartDragSession`),
but the drop/docking hints still cannot work, so Orca keeps floating disabled.
## wxAuiToolBar and BBLTopbar ## wxAuiToolBar and BBLTopbar
@@ -6,7 +6,7 @@ port; what Orca's `DPIDialog`/`DPIFrame` add; the Orca dialog recipe; and the `M
Read it before writing or reviewing any dialog, frame, close handler, `Destroy()`/`delete`, or code Read it before writing or reviewing any dialog, frame, close handler, `Destroy()`/`delete`, or code
that keeps a pointer to a window across an event, a `CallAfter` or a modal loop. that keeps a pointer to a window across an event, a `CallAfter` or a modal loop.
wx cites are relative to the pinned wx 3.3.2 tree (located as in `SKILL.md` §Ground truth). wx is wx cites are relative to the pinned wx 3.3.4 tree (located as in `SKILL.md` §Ground truth). wx is
built with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`: every wx assert built with `wxBUILD_DEBUG_LEVEL=0` and `libslic3r_gui` with `wxDEBUG_LEVEL=0`: every wx assert
quoted below is compiled out, so misuse fails silently (dropped call, stuck loop, freed memory), never with an assert dialog. "GTK" below quoted below is compiled out, so misuse fails silently (dropped call, stuck loop, freed memory), never with an assert dialog. "GTK" below
means wxGTK as Orca builds it on Linux: GTK3 by default (X11 or Wayland); GTK2 is only an opt-out. means wxGTK as Orca builds it on Linux: GTK3 by default (X11 or Wayland); GTK2 is only an opt-out.
@@ -424,7 +424,7 @@ mapped (`src/gtk/toplevel.cpp:1141-1243`).
**Raise.** "only requests the window manager to raise this window… If the window is currently hidden, **Raise.** "only requests the window manager to raise this window… If the window is currently hidden,
this function does *not* show it", top-level windows only (`interface/wx/window.h:3013-3033`); true on all ports this function does *not* show it", top-level windows only (`interface/wx/window.h:3013-3033`); true on all ports
since 3.3 (`docs/changes.txt:144-146`). **[source]** MSW = `::SetForegroundWindow`, subject to the since 3.3 (`docs/changes.txt:145-147`). **[source]** MSW = `::SetForegroundWindow`, subject to the
foreground lock — Windows may only flash the taskbar button (`src/msw/toplevel.cpp:650-655`); GTK = foreground lock — Windows may only flash the taskbar button (`src/msw/toplevel.cpp:650-655`); GTK =
`gtk_window_present` only if shown (`src/gtk/toplevel.cpp:1301-1310`; during a deferred X11 first show it `gtk_window_present` only if shown (`src/gtk/toplevel.cpp:1301-1310`; during a deferred X11 first show it
already counts as shown); macOS = `makeKeyAndOrderFront` only if shown (`src/osx/nonownedwnd_osx.cpp:289-295`, `src/osx/cocoa/nonownedwnd.mm:897-899`), already counts as shown); macOS = `makeKeyAndOrderFront` only if shown (`src/osx/nonownedwnd_osx.cpp:289-295`, `src/osx/cocoa/nonownedwnd.mm:897-899`),
@@ -910,8 +910,9 @@ buttons are chosen — in numeric id order, so `{"Save", "OK"}` makes Save prima
**Rule.** Never `wxMessageBox`/`wxMessageDialog`/`wxRichMessageDialog` once the GUI exists; use the themed **Rule.** Never `wxMessageBox`/`wxMessageDialog`/`wxRichMessageDialog` once the GUI exists; use the themed
replacements in `src/slic3r/GUI/MsgDialog.hpp` (`Slic3r::GUI`), rooted in `MsgDialog : DPIDialog` (logo on the replacements in `src/slic3r/GUI/MsgDialog.hpp` (`Slic3r::GUI`), rooted in `MsgDialog : DPIDialog` (logo on the
left, content on the right, `Button` row underneath, dark-mode and DPI aware). Why: on MSW the TaskDialog-based left, content on the right, `Button` row underneath, dark-mode and DPI aware). Why: on MSW the TaskDialog-based
native boxes (`wxMessageBox`, `wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`) ignore dark mode native boxes (`wxMessageBox`, `wxMessageDialog`, `wxRichMessageDialog`, `wxProgressDialog`) now follow dark mode
(`interface/wx/app.h:1436-1446`), and native boxes cannot match Orca's look. `wxMessageBox` remains only for since 3.3.3, so only the date/time/calendar controls, `wxPrintDialog` on Windows 10 and MDI applications stay
light (`interface/wx/app.h:1442-1448`); native boxes cannot match Orca's look. `wxMessageBox` remains only for
failures before the GUI exists (e.g. `GUI_App::load_language`). Native message-box style limits: failures before the GUI exists (e.g. `GUI_App::load_language`). Native message-box style limits:
`references/strings-i18n-files.md`. Return-value trap when reading old code: `wxMessageBox()` returns `references/strings-i18n-files.md`. Return-value trap when reading old code: `wxMessageBox()` returns
`wxYES/wxNO/wxCANCEL/wxOK/wxHELP`, while `ShowModal()` returns `wxID_YES/…` (`interface/wx/msgdlg.h:269-276` vs `309-311`). `wxYES/wxNO/wxCANCEL/wxOK/wxHELP`, while `ShowModal()` returns `wxID_YES/…` (`interface/wx/msgdlg.h:269-276` vs `309-311`).
@@ -1,17 +1,19 @@
# wx 3.1.5 → 3.3.2: changes Orca code can trip on # wx 3.1.5 → 3.3.4: changes Orca code can trip on
OrcaSlicer moved from wxWidgets **3.1.5** to **3.3.2** (8248b06337, #12941). This file digests the OrcaSlicer moved from wxWidgets **3.1.5** to **3.3.2** (8248b06337, #12941) and the pin is now upstream
**3.3.4** (`deps/wxWidgets/wxWidgets.cmake`, tag `v3.3.4`). This file digests the
changes between those versions that matter to GUI code — the 3.1.6–3.2.0 incompatible changes, the changes between those versions that matter to GUI code — the 3.1.6–3.2.0 incompatible changes, the
3.3 incompatible changes, and the notable 3.3.0/3.3.1/3.3.2 changes — each with what it means for 3.3 incompatible changes, and the notable 3.3.0/3.3.1/3.3.2/3.3.3/3.3.4 changes — each with what it
Orca, plus the migration already done in Orca as rules for new code. Read it when code written means for Orca, plus the migration already done in Orca as rules for new code. Read it when code
from older wx knowledge behaves oddly, when a wx doc says "since 3.3", or when reviewing code near written from older wx knowledge behaves oddly, when a wx doc says "since 3.3", or when reviewing code
the workarounds in §8. Where this file and prior wx knowledge disagree, this file wins. near the workarounds in §10. Where this file and prior wx knowledge disagree, this file wins.
Contents: [Rules](#rules) · [1 Reading the change logs](#1-reading-the-change-logs) · Contents: [Rules](#rules) · [1 Reading the change logs](#1-reading-the-change-logs) ·
[2 3.1.6 → 3.2.0](#2-changes-from-316-to-320) · [3 3.3 behaviour changes](#3-33-behaviour-changes-that-compile) · [2 3.1.6 → 3.2.0](#2-changes-from-316-to-320) · [3 3.3 behaviour changes](#3-33-behaviour-changes-that-compile) ·
[4 3.3 build changes](#4-33-changes-that-break-the-build) · [5 3.3.0](#5-330-notable-changes) · [4 3.3 build changes](#4-33-changes-that-break-the-build) · [5 3.3.0](#5-330-notable-changes) ·
[6 3.3.1](#6-331-notable-fixes) · [7 3.3.2](#7-332-notable-changes) · [6 3.3.1](#6-331-notable-fixes) · [7 3.3.2](#7-332-notable-changes) ·
[8 Migration done in Orca](#8-migration-already-done-in-orca) [8 3.3.3](#8-333-notable-changes) · [9 3.3.4](#9-334-notable-changes) ·
[10 Migration done in Orca](#10-migration-already-done-in-orca)
All `docs/`, `interface/`, `include/`, `src/`, `build/` cites are relative to the pinned wx tree All `docs/`, `interface/`, `include/`, `src/`, `build/` cites are relative to the pinned wx tree
(located as in `SKILL.md` §Ground truth), except paths (located as in `SKILL.md` §Ground truth), except paths
@@ -21,8 +23,8 @@ explicitly called Orca's (`deps/…`, Orca's `src/CMakeLists.txt`) and bare Orca
1. Read every "now asserts" in the change logs as "now silently returns or does nothing" in Orca: 1. Read every "now asserts" in the change logs as "now silently returns or does nothing" in Orca:
wx asserts are compiled out. Validate arguments yourself. → [§1](#1-reading-the-change-logs) wx asserts are compiled out. Validate arguments yourself. → [§1](#1-reading-the-change-logs)
2. Target 3.3.2 only. Do not add `wxCHECK_VERSION` / `wxVERSION_NUMBER` / 2. Target 3.3.4 only. Do not add `wxCHECK_VERSION` / `wxVERSION_NUMBER` /
`wxVERSION_EQUAL_OR_GREATER_THAN` branches for older wx. → [§8](#8-migration-already-done-in-orca) `wxVERSION_EQUAL_OR_GREATER_THAN` branches for older wx. → [§10](#10-migration-already-done-in-orca)
3. Mark every override of a wx virtual `override`. 3.2/3.3 changed parameter types (`wxBitmapBundle`, 3. Mark every override of a wx virtual `override`. 3.2/3.3 changed parameter types (`wxBitmapBundle`,
`wxReadOnlyDC`, `wxWindowBase*`, `wxVersionContext`); a stale signature must fail to compile, not `wxReadOnlyDC`, `wxWindowBase*`, `wxVersionContext`); a stale signature must fail to compile, not
become a silent overload. → [§4](#4-33-changes-that-break-the-build) become a silent overload. → [§4](#4-33-changes-that-break-the-build)
@@ -39,33 +41,36 @@ explicitly called Orca's (`deps/…`, Orca's `src/CMakeLists.txt`) and bare Orca
`WX_GL_SAMPLES`); `wxGLAttributes::Defaults()` no longer includes it. → [§3](#3-33-behaviour-changes-that-compile) `WX_GL_SAMPLES`); `wxGLAttributes::Defaults()` no longer includes it. → [§3](#3-33-behaviour-changes-that-compile)
9. Size a `wxImageList` in physical pixels (the bitmaps' `GetSize()`), or use the `wxBitmapBundle` 9. Size a `wxImageList` in physical pixels (the bitmaps' `GetSize()`), or use the `wxBitmapBundle`
image APIs. → [§3](#3-33-behaviour-changes-that-compile) image APIs. → [§3](#3-33-behaviour-changes-that-compile)
10. Return translated strings as `wxString` by value. → [§3](#3-33-behaviour-changes-that-compile) 10. `wxGetTranslation()` returns `const wxString&` (3.3.2 made it by-value; 3.3.3 reverted that); a
wrapper that converts a translation returns by value. → [§3](#3-33-behaviour-changes-that-compile)
11. Escape `&` in user text used as a control label or book page title. → [§3](#3-33-behaviour-changes-that-compile) 11. Escape `&` in user text used as a control label or book page title. → [§3](#3-33-behaviour-changes-that-compile)
12. `wxDynamicCast` only on a pointer whose static type derives from `wxObject`; use `dynamic_cast` 12. `wxDynamicCast` only on a pointer whose static type derives from `wxObject`; use `dynamic_cast`
for mixin interfaces (`wxComboPopup`, `wxItemContainer`, `wxTextEntry`). → [§4](#4-33-changes-that-break-the-build) for mixin interfaces (`wxComboPopup`, `wxItemContainer`, `wxTextEntry`). → [§4](#4-33-changes-that-break-the-build)
13. Build a `wxArrayString` with `Add()` or an initializer list, walk wx lists with 13. Build a `wxArrayString` with `Add()` or an initializer list, walk wx lists with
`compatibility_iterator` or range-for, and make a `wxString` the first operand of a mixed `compatibility_iterator` or range-for, and make a `wxString` the first operand of a mixed
`+` chain. → [§4](#4-33-changes-that-break-the-build) `+` chain. → [§4](#4-33-changes-that-break-the-build)
14. MSW windows are not double-buffered by default in 3.3.2; a custom-painted control buffers itself. 14. MSW windows are not double-buffered by default in 3.3.4; a custom-painted control buffers itself.
→ [§5](#5-330-notable-changes) → [§5](#5-330-notable-changes)
15. `wxEVT_DPI_CHANGED` now fires on GTK3 too; such handlers must be correct on GTK, and every handler 15. `wxEVT_DPI_CHANGED` now fires on GTK3 too; such handlers must be correct on GTK, and every handler
you bind calls `Skip()` (`DPIAware`'s own is the one exception). → [§5](#5-330-notable-changes) you bind calls `Skip()` (`DPIAware`'s own is the one exception). → [§5](#5-330-notable-changes)
16. wx MSW dark mode cannot be switched at runtime; do not replace Orca's NppDarkMode with it without 16. wx MSW dark mode became runtime-switchable in 3.3.3/3.3.4 (`SetAppearance`/`MSWEnableDarkMode`
keeping live theme switching. → [§5](#5-330-notable-changes) restyle existing windows); Orca still keeps NppDarkMode for its own chrome.
→ [§5](#5-330-notable-changes), [§9](#9-334-notable-changes)
17. After `wxStaticText::SetLabel`, re-wrap with `Wrap(-1); Wrap(w);` (or use `Label`); `wxST_WRAP` 17. After `wxStaticText::SetLabel`, re-wrap with `Wrap(-1); Wrap(w);` (or use `Label`); `wxST_WRAP`
is opt-in and works only inside a sizer. → [§7](#7-332-notable-changes) is opt-in and works only inside a sizer. → [§7](#7-332-notable-changes)
18. On Linux/X11 call `wxGLCanvas::PreferGLX()` before any GL use; on Unix set a swap interval explicitly 18. On Linux/X11 call `wxGLCanvas::PreferGLX()` before any GL use; on Unix set a swap interval explicitly
if frame pacing matters (wx forces 0). → [§7](#7-332-notable-changes) if frame pacing matters (wx forces 0). → [§7](#7-332-notable-changes)
19. Compare `wxGrid::GetSelectedBlocks()` `begin()` with `end()` before dereferencing. 19. Compare `wxGrid::GetSelectedBlocks()` `begin()` with `end()` before dereferencing.
→ [§8](#8-migration-already-done-in-orca) → [§10](#10-migration-already-done-in-orca)
20. Keep the post-upgrade workarounds (MainFrame `WS_CAPTION` masking, macOS deep-link handler, 20. Keep the post-upgrade workarounds (MainFrame `WS_CAPTION` masking, macOS deep-link handler,
`MSWEnableDarkMode` ordering, `SidePopup` anchoring, MSW `GLCanvas3D::on_paint` render) when `MSWEnableDarkMode` ordering, `SidePopup` anchoring, MSW `GLCanvas3D::on_paint` render) when
touching that code. → [§8](#8-migration-already-done-in-orca) touching that code. → [§10](#10-migration-already-done-in-orca)
## 1 Reading the change logs ## 1 Reading the change logs
**Sources.** `docs/changes.txt` lists changes since 3.2: incompatible behaviour changes :11-146, **Sources.** `docs/changes.txt` lists changes since 3.2: incompatible behaviour changes :11-178,
build-breaking changes :149-252, 3.3.2 :255-330, 3.3.1 :333-377, 3.3.0 :380-622. build-breaking changes :181-292, 3.3.4 :295-385, 3.3.3 :388-445, 3.3.2 :448-523, 3.3.1 :526-570,
3.3.0 :573-815.
`docs/changes_32.txt` covers 3.x → 3.2.0: the cumulative "INCOMPATIBLE CHANGES SINCE 3.0.x" list `docs/changes_32.txt` covers 3.x → 3.2.0: the cumulative "INCOMPATIBLE CHANGES SINCE 3.0.x" list
:9-233, 3.2.0 :235-276, 3.1.7 :279-340, 3.1.6 :343-444. wxQt, wxiOS, wxUniv, wxMotif and wxGTK1 :9-233, 3.2.0 :235-276, 3.1.7 :279-340, 3.1.6 :343-444. wxQt, wxiOS, wxUniv, wxMotif and wxGTK1
items are left out here. items are left out here.
@@ -73,11 +78,14 @@ items are left out here.
**Coverage gaps.** **Coverage gaps.**
- The "since 3.0.x" list in `changes_32.txt` is cumulative over all of 3.1.x. Most of it was already - The "since 3.0.x" list in `changes_32.txt` is cumulative over all of 3.1.x. Most of it was already
in force in 3.1.5; §2.1 lists only what was added after 3.1.5, §2.3 the older items worth knowing. in force in 3.1.5; §2.1 lists only what was added after 3.1.5, §2.3 the older items worth knowing.
- `changes_32.txt` in this tree stops at 3.2.0. The 3.2.1–3.2.10 maintenance fixes are not listed - `changes_32.txt` in this tree stops at 3.2.0. The 3.2.1–3.2.12 maintenance fixes are not listed
anywhere in the tree. anywhere in the tree.
- 3.3.0's list is relative to 3.2.8 (`changes.txt:383`). 3.3.2's list is relative to 3.2.10, and the - 3.3.0's list is relative to 3.2.8 (`changes.txt:576`). 3.3.2's list is relative to 3.2.10, and the
full set of changes since 3.3.1 *also includes* the 3.2.9 and 3.2.10 fixes, which are **not** full set of changes since 3.3.1 *also includes* the 3.2.9 and 3.2.10 fixes, which are **not**
listed in this file (`changes.txt:258-259`). listed in this file (`changes.txt:451-452`). 3.3.3's list is relative to 3.2.11, and its changes
since 3.3.2 *also include* the 3.2.10–3.2.11 fixes (`changes.txt:391-392`); 3.3.4's list is
relative to 3.2.11 too, and its changes since 3.3.3 *also include* the 3.2.11–3.2.12 fixes
(`changes.txt:298-299`).
**"Asserts" mean silence in Orca.** wx is built with `-DwxBUILD_DEBUG_LEVEL=0` **"Asserts" mean silence in Orca.** wx is built with `-DwxBUILD_DEBUG_LEVEL=0`
(`deps/wxWidgets/wxWidgets.cmake` → `build/cmake/init.cmake:245-246`), and `libslic3r_gui` gets (`deps/wxWidgets/wxWidgets.cmake` → `build/cmake/init.cmake:245-246`), and `libslic3r_gui` gets
@@ -117,7 +125,7 @@ the 3.1.7-specific section.
| `wxSpinCtrl::SetValue(wxString)` sends no events on MSW (as documented) | :129-130 | do not rely on setter events (`controls-dataview.md`) | | `wxSpinCtrl::SetValue(wxString)` sends no events on MSW (as documented) | :129-130 | do not rely on setter events (`controls-dataview.md`) |
| `wxButton::GetBitmap{Current,Disabled,Focus,Pressed}()` return a valid bitmap on MSW only if set | :132-134 | check `IsOk()` | | `wxButton::GetBitmap{Current,Disabled,Focus,Pressed}()` return a valid bitmap on MSW only if set | :132-134 | check `IsOk()` |
| `wxFileName::GetVolume()` returns `\\share` for UNC paths and `\\?\Volume{GUID}` for GUID paths | :136-140 | path code comparing volumes | | `wxFileName::GetVolume()` returns `\\share` for UNC paths and `\\?\Volume{GUID}` for GUID paths | :136-140 | path code comparing volumes |
| `wxBitmapComboBoxBase::SetItemBitmap()` takes `wxBitmapBundle` | :152-153 | the bundle change also retyped `OnAddBitmap` (5f365b5c6b, §8) | | `wxBitmapComboBoxBase::SetItemBitmap()` takes `wxBitmapBundle` | :152-153 | the bundle change also retyped `OnAddBitmap` (5f365b5c6b, §10) |
| MSW also links `oleacc` (3.1.5 already needed `shlwapi`, `uxtheme`, `version`) | :158-163 | automatic with MSVC | | MSW also links `oleacc` (3.1.5 already needed `shlwapi`, `uxtheme`, `version`) | :158-163 | automatic with MSVC |
| Xcode projects drop i386, add arm64 | :205-207 | none (CMake build) | | Xcode projects drop i386, add arm64 | :205-207 | none (CMake build) |
| `wxImage` ctor from XPM data is `explicit` | :225-226 | write `wxImage(xpm)` | | `wxImage` ctor from XPM data is `explicit` | :225-226 | write `wxImage(xpm)` |
@@ -136,7 +144,7 @@ the 3.1.7-specific section.
| MSW: TLW resizing on DPI change improved and overridable — a handler that sizes the TLW itself does not `Skip()` (3.2.0) | `changes_32.txt:269`; `interface/wx/event.h` (`wxDPIChangedEvent`) | Orca's `DPIAware` handler does not `Skip()` (`dpi-bitmaps-fonts.md`) | | MSW: TLW resizing on DPI change improved and overridable — a handler that sizes the TLW itself does not `Skip()` (3.2.0) | `changes_32.txt:269`; `interface/wx/event.h` (`wxDPIChangedEvent`) | Orca's `DPIAware` handler does not `Skip()` (`dpi-bitmaps-fonts.md`) |
| `wxUILocale` (3.1.6); `wxLocale::IsAvailable` is now implemented through it | `changes_32.txt:348`; `src/common/intl.cpp:740-781` | see `wxUILocale::IsSupported` in §3 | | `wxUILocale` (3.1.6); `wxLocale::IsAvailable` is now implemented through it | `changes_32.txt:348`; `src/common/intl.cpp:740-781` | see `wxUILocale::IsSupported` in §3 |
| `wxWebView::RunScriptAsync()` (3.1.6) | `changes_32.txt:382` | `webview-gl-aui-media.md` | | `wxWebView::RunScriptAsync()` (3.1.6) | `changes_32.txt:382` | `webview-gl-aui-media.md` |
| wxOSX: "Allow user input in `wxPopupTransientWindow`" (3.1.7) — the popup's child holds mouse capture while the cursor is outside it and releases it inside, toggled from `OnIdle` [source] | `changes_32.txt:334`; `src/common/popupcmn.cpp:438-471` | how wxOSX transient popups track the mouse; the macOS gap-dismissal worked around in `SidePopup::Popup` is not traced to a specific wx change (§8; `popups-menus.md`) | | wxOSX: "Allow user input in `wxPopupTransientWindow`" (3.1.7) — the popup's child holds mouse capture while the cursor is outside it and releases it inside, toggled from `OnIdle` [source] | `changes_32.txt:334`; `src/common/popupcmn.cpp:438-471` | how wxOSX transient popups track the mouse; the macOS gap-dismissal worked around in `SidePopup::Popup` is not traced to a specific wx change (§10; `popups-menus.md`) |
| wxGTK: Wayland fixes (3.1.6), no GDK errors from `PopupMenu()` on Wayland (3.1.7), `wxCURSOR_SIZING` on Wayland (3.2.0) | `changes_32.txt:397, 317, 261` | `platforms.md` | | wxGTK: Wayland fixes (3.1.6), no GDK errors from `PopupMenu()` on Wayland (3.1.7), `wxCURSOR_SIZING` on Wayland (3.2.0) | `changes_32.txt:397, 317, 261` | `platforms.md` |
| MSW: all native modal dialogs are app-modal (3.1.6) | `changes_32.txt:409` | `windows-dialogs.md` | | MSW: all native modal dialogs are app-modal (3.1.6) | `changes_32.txt:409` | `windows-dialogs.md` |
| Also new: `wxKeyEvent::IsAutoRepeat()`, `wxSpinCtrl::GetTextValue()/SetIncrement()`, `wxTopLevelWindow::SetContentProtection()`, `wxEVT_SPLITTER_SASH_POS_RESIZE`, OSX full-screen view options, OSX `wxEVT_CHAR` from `wxDataViewCtrl` | `changes_32.txt:364-436` | available API | | Also new: `wxKeyEvent::IsAutoRepeat()`, `wxSpinCtrl::GetTextValue()/SetIncrement()`, `wxTopLevelWindow::SetContentProtection()`, `wxEVT_SPLITTER_SASH_POS_RESIZE`, OSX full-screen view options, OSX `wxEVT_CHAR` from `wxDataViewCtrl` | `changes_32.txt:364-436` | available API |
@@ -167,7 +175,7 @@ These were already in force in 3.1.5, so the upgrade did not change them, but co
## 3 3.3 behaviour changes that compile ## 3 3.3 behaviour changes that compile
`changes.txt` "Changes in behaviour not resulting in compilation errors" (:11-146). Each row: the `changes.txt` "Changes in behaviour not resulting in compilation errors" (:11-178). Each row: the
change, its line, and what it means for Orca. change, its line, and what it means for Orca.
| Change | Line | Orca relevance | | Change | Line | Orca relevance |
@@ -177,31 +185,30 @@ change, its line, and what it means for Orca.
| `wxGLCanvas` no longer multisamples by default | :21-23 | pitfall below | | `wxGLCanvas` no longer multisamples by default | :21-23 | pitfall below |
| `wxFileConfig` on Unix defaults to XDG `~/.config/appname.conf` (old file still used; `wxCONFIG_USE_XDG`/`wxCONFIG_USE_HOME`, `MigrateLocalFile()`) | :25-29 | none: Orca uses `AppConfig`, no `wxConfig` (`strings-i18n-files.md`) | | `wxFileConfig` on Unix defaults to XDG `~/.config/appname.conf` (old file still used; `wxCONFIG_USE_XDG`/`wxCONFIG_USE_HOME`, `MigrateLocalFile()`) | :25-29 | none: Orca uses `AppConfig`, no `wxConfig` (`strings-i18n-files.md`) |
| `wxColourDatabase` uses CSS values; `UseScheme()` restores the old ones (`interface/wx/gdicmn.h:845, 973-996`) | :31-33 | none: stock colours (`*wxGREEN`, …) are fixed RGB (`src/common/gdicmn.cpp:789-830`) and Orca builds colours from hex/RGB. Do not build colours from names | | `wxColourDatabase` uses CSS values; `UseScheme()` restores the old ones (`interface/wx/gdicmn.h:845, 973-996`) | :31-33 | none: stock colours (`*wxGREEN`, …) are fixed RGB (`src/common/gdicmn.cpp:789-830`) and Orca builds colours from hex/RGB. Do not build colours from names |
| `wxAuiNotebook` default art is the new flat art; `wxAuiNativeTabArt` (or `"native"` in XRC) keeps the old look | :35-37 | none: no `wxAuiNotebook` in Orca | | `wxAuiNotebook` default art is the new flat art; `wxAuiNativeTabArt` (or `"native"` in XRC) keeps the old look | :41-43 | none: no `wxAuiNotebook` in Orca |
| `wxTHREAD_WAIT_DEFAULT` is `wxTHREAD_WAIT_BLOCK`: `wxThread::Delete()/Wait()` no longer pump events | :39-41 | Orca uses std/boost threads (`wxThread` only for `IsMain()`); a new `wxThread` whose exit needs the main loop would deadlock | | `wxTHREAD_WAIT_DEFAULT` is `wxTHREAD_WAIT_BLOCK`: `wxThread::Delete()/Wait()` no longer pump events | :45-47 | Orca uses std/boost threads (`wxThread` only for `IsMain()`); a new `wxThread` whose exit needs the main loop would deadlock |
| `wxDocument::OnCloseDocument()` runs once, after the views are destroyed (it used to run twice when the document was closed from the menu); an override must not rely on any view existing | :43-46 | none: no doc/view | | `wxDocument::OnCloseDocument()` runs once, after the views are destroyed (it used to run twice when the document was closed from the menu); an override must not rely on any view existing | :49-52 | none: no doc/view |
| `wxGrid::FreezeTo()` asserts on out-of-range counts, and freezes even when the grid is too small | :48-51 | silent `false` in Orca; it also refuses reordered or drag-movable rows/columns [source] (`src/generic/grid.cpp:5742-5750`). Clamp arguments (`controls-dataview.md`) | | `wxGrid::FreezeTo()` asserts on out-of-range counts, and freezes even when the grid is too small | :54-57 | silent `false` in Orca; it also refuses reordered or drag-movable rows/columns [source] (`src/generic/grid.cpp:5742-5750`). Clamp arguments (`controls-dataview.md`) |
| Invalid `wxImageList` calls assert | :53-56 | silent in Orca; `wxCHECK` returns (generic `Add` → -1). Create the list with a valid size before use | | Invalid `wxImageList` calls assert | :59-62 | silent in Orca; `wxCHECK` returns (generic `Add` → -1). Create the list with a valid size before use |
| `wxTRANSPARENT_WINDOW` does nothing (`#define wxTRANSPARENT_WINDOW 0`, `include/wx/defs.h:1449`); MSW code that needs it can set `WS_EX_TRANSPARENT` | :58-60 | pitfall below; 026b105dcb | | `wxTRANSPARENT_WINDOW` does nothing (`#define wxTRANSPARENT_WINDOW 0`, `include/wx/defs.h:1449`); MSW code that needs it can set `WS_EX_TRANSPARENT` | :64-66 | pitfall below; 026b105dcb |
| MSW `wxTextDataObject::SetData()` size includes the 2-byte NUL (consistent with `GetDataSize()`); an old-style size chops the last character | :62-66 | none: Orca uses the `wxTextDataObject(text)` ctor; use `SetText()`, never `SetData()` | | MSW `wxTextDataObject::SetData()` size includes the 2-byte NUL (consistent with `GetDataSize()`); an old-style size chops the last character | :68-72 | none: Orca uses the `wxTextDataObject(text)` ctor; use `SetText()`, never `SetData()` |
| `wxListCtrl::EditLabel()` asserts without `wxLC_EDIT_LABELS` | :68-69 | silent no-op in Orca; add the style where editing is intended | | `wxListCtrl::EditLabel()` asserts without `wxLC_EDIT_LABELS` | :74-75 | silent no-op in Orca; add the style where editing is intended |
| MSW `wxSystemAppearance::IsDark()` reports the app's own mode; `AreAppsDark()`/`IsSystemDark()` report the OS | :71-73 | pitfall below | | MSW `wxSystemAppearance::IsDark()` reports the app's own mode; `AreAppsDark()`/`IsSystemDark()` report the OS | :77-79 | pitfall below |
| Unix `wxUILocale::IsSupported()` no longer falls back to another region of the same language; pass just `"fr"` to accept any `fr_XX` | :75-79 | `wxLocale::IsAvailable` builds the region-qualified tag (`GetCanonicalWithRegion()`) and calls `IsSupported()` [source] (`src/common/intl.cpp:740-781`); `GUI_App::load_language` relies on it, so on Linux a language whose canonical locale (e.g. `fr_FR`) is not installed reports unavailable. Keep the fallbacks in `load_language` | | Unix `wxUILocale::IsSupported()` no longer falls back to another region of the same language; pass just `"fr"` to accept any `fr_XX` | :81-85 | `wxLocale::IsAvailable` builds the region-qualified tag (`GetCanonicalWithRegion()`) and calls `IsSupported()` [source] (`src/common/intl.cpp:740-781`); `GUI_App::load_language` relies on it, so on Linux a language whose canonical locale (e.g. `fr_FR`) is not installed reports unavailable. Keep the fallbacks in `load_language` |
| Deprecated `wxPGCellRenderer::DrawCaptionSelectionRect()` overload not called; override the overload taking `wxWindow*`, or enable 3.0 compatibility | :81-83 | none: no propgrid in Orca's own code | | Deprecated `wxPGCellRenderer::DrawCaptionSelectionRect()` overload not called; override the overload taking `wxWindow*`, or enable 3.0 compatibility | :87-89 | none: no propgrid in Orca's own code |
| `wxImageList` size is in physical pixels | :85-88 | pitfall below | | `wxImageList` size is in physical pixels | :91-94 | pitfall below |
| Mac `wxWebRequest` no longer uses persistent storage. The entry names `wxWebRequest::EnablePersistentStorage()`; the real API is `wxWebSession::EnablePersistentStorage(bool)` (`interface/wx/webrequest.h:1612-1629`; also `wxWebSessionSync`, :1835), macOS-only, before the first request | :90-92 | none: Orca uses `wxWebRequest` only for image downloads (`wxWebSession::GetDefault().CreateRequest` in `StatusPanel`, `SliceInfoPanel`, `ReleaseNote`, `DeviceErrorDialog`); network and login agents use libcurl (`Slic3r::Http`) | | Mac `wxWebRequest` no longer uses persistent storage. The entry names `wxWebRequest::EnablePersistentStorage()`; the real API is `wxWebSession::EnablePersistentStorage(bool)` (`interface/wx/webrequest.h:1612-1629`; also `wxWebSessionSync`, :1835), macOS-only, before the first request | :96-98 | none: Orca uses `wxWebRequest` only for image downloads (`wxWebSession::GetDefault().CreateRequest` in `StatusPanel`, `SliceInfoPanel`, `ReleaseNote`, `DeviceErrorDialog`); network and login agents use libcurl (`Slic3r::Http`) |
| MSW `wxBitmap::Create(size, dc)` no longer multiplies by the DC's content scale; the size is physical | :94-96 | remove compensating scaling; use `CreateWithLogicalSize` for logical sizes | | MSW `wxBitmap::Create(size, dc)` no longer multiplies by the DC's content scale; the size is physical | :100-102 | remove compensating scaling; use `CreateWithLogicalSize` for logical sizes |
| `wxIMAGE_QUALITY_NEAREST` has a new value and is no longer `wxIMAGE_QUALITY_NORMAL`; `NORMAL` (the `Scale`/`Rescale` default) is bilinear + box average (`interface/wx/image.h:31-67`) | :98-99 | never store or compare the enum numerically; default-quality thumbnails and icons look smoother than under 3.1.5; pass `wxIMAGE_QUALITY_NEAREST` for pixel-exact scaling | | `wxIMAGE_QUALITY_NEAREST` has a new value and is no longer `wxIMAGE_QUALITY_NORMAL`; `NORMAL` (the `Scale`/`Rescale` default) is bilinear + box average (`interface/wx/image.h:31-67`) | :104-105 | never store or compare the enum numerically; default-quality thumbnails and icons look smoother than under 3.1.5; pass `wxIMAGE_QUALITY_NEAREST` for pixel-exact scaling |
| `wxTextCtrl::{Save,Load}File()` treat `.rtf` as RTF | :101-104 | pass `wxTEXT_TYPE_PLAIN` to keep plain text | | `wxTextCtrl::{Save,Load}File()` treat `.rtf` as RTF | :107-110 | pass `wxTEXT_TYPE_PLAIN` to keep plain text |
| `wxClientDC`/`wxPaintDC` offset their origin by a `wxFrame` toolbar on every port | :106-109 | none: Orca frames have no native toolbar (`BBLTopbar` is a child `wxAuiToolBar`) | | `wxClientDC`/`wxPaintDC` offset their origin by a `wxFrame` toolbar on every port | :112-115 | none: Orca frames have no native toolbar (`BBLTopbar` is a child `wxAuiToolBar`) |
| `wxTextCtrl::SetLabel()` does nothing and asserts on every port (MSW used to act as `SetValue`) | :111-113 | pitfall below | | `wxTextCtrl::SetLabel()` does nothing and asserts on every port (MSW used to act as `SetValue`) | :117-119 | pitfall below |
| `wxAuiGenericTabArt` subclasses (also via `wxAuiMSWTabArt`) override `DrawPageTab()`/`GetPageTabSize()` instead of `DrawTab()`/`GetTabSize()`; direct `wxAuiTabArt` subclasses still work | :115-120 | none: no Orca tab art | | `wxAuiGenericTabArt` subclasses (also via `wxAuiMSWTabArt`) override `DrawPageTab()`/`GetPageTabSize()` instead of `DrawTab()`/`GetTabSize()`; direct `wxAuiTabArt` subclasses still work | :121-126 | none: no Orca tab art |
| `wxAuiNotebook` page index is logical (reorder-independent); `GetPagePosition()` gives the screen position | :122-126 | none; index math under `wxAUI_NB_TAB_MOVE` is what breaks | | `wxAuiNotebook` page index is logical (reorder-independent); `GetPagePosition()` gives the screen position | :128-132 | none; index math under `wxAUI_NB_TAB_MOVE` is what breaks |
| `wxListbook`/`wxChoicebook` interpret mnemonics in page titles "just as the other wx*book classes already did" | :128-130 | Orca uses neither (`BedShapeDialog` uses `wxSimplebook` + a combo); every book interprets `&` (`interface/wx/bookctrl.h:141-147`) → rule 11 | | `wxListbook`/`wxChoicebook` interpret mnemonics in page titles "just as the other wx*book classes already did" | :134-136 | Orca uses neither (`BedShapeDialog` uses `wxSimplebook` + a combo); every book interprets `&` (`interface/wx/bookctrl.h:141-147`) → rule 11 |
| `wxAUI_MGR_HINT_FADE` is not in the default `wxAuiManager` style | :132-133 | Orca's `AuiMgr` keeps the default flags (minus `wxAUI_MGR_ALLOW_FLOATING` on Wayland, `AuiMgr::init`), so the docking hint no longer fades; add the flag if wanted | | `wxAUI_MGR_HINT_FADE` is not in the default `wxAuiManager` style | :138-139 | Orca's `AuiMgr` keeps the default flags (minus `wxAUI_MGR_ALLOW_FLOATING` on Wayland, `AuiMgr::init`), so the docking hint no longer fades; add the flag if wanted |
| `wxPrintDialogData::SetAllPages(false)`/`SetSelection(false)` changed meaning | :135-137 | none | | `wxPrintDialogData::SetAllPages(false)`/`SetSelection(false)` changed meaning | :141-143 | none |
| `wxGetTranslation()` returns `wxString` by value | :139-142 | pitfall below | | `wxWindow::Raise()` no longer shows a hidden window on any port | :145-147 | pitfall below; ba867cc534 |
| `wxWindow::Raise()` no longer shows a hidden window on any port | :144-146 | pitfall below; ba867cc534 |
**Pitfalls** **Pitfalls**
@@ -277,7 +284,7 @@ change, its line, and what it means for Orca.
// Wrong: m_input_ip->GetTextCtrl()->SetLabelText(m_obj->get_dev_ip()); // Wrong: m_input_ip->GetTextCtrl()->SetLabelText(m_obj->get_dev_ip());
// Right: m_input_ip->GetTextCtrl()->ChangeValue(m_obj->get_dev_ip()); // no wxEVT_TEXT // Right: m_input_ip->GetTextCtrl()->ChangeValue(m_obj->get_dev_ip()); // no wxEVT_TEXT
``` ```
Cite: `docs/changes.txt:111-113`; `controls-dataview.md`. Cite: `docs/changes.txt:117-119`; `controls-dataview.md`.
- **Rule:** Size a `wxImageList` from the bitmaps' physical size, or use - **Rule:** Size a `wxImageList` from the bitmaps' physical size, or use
`SetImages(std::vector<wxBitmapBundle>)`. `SetImages(std::vector<wxBitmapBundle>)`.
@@ -293,18 +300,23 @@ change, its line, and what it means for Orca.
// Right: wxBitmap bmp = create_scaled_bitmap("icon", this, 16); // Right: wxBitmap bmp = create_scaled_bitmap("icon", this, 16);
// m_images = new wxImageList(bmp.GetWidth(), bmp.GetHeight(), false); // m_images = new wxImageList(bmp.GetWidth(), bmp.GetHeight(), false);
``` ```
Cite: `docs/changes.txt:85-88`; `Tab` builds its list from `bmp().GetWidth()/GetHeight()`; Cite: `docs/changes.txt:91-94`; `Tab` builds its list from `bmp().GetWidth()/GetHeight()`;
`dpi-bitmaps-fonts.md`. `dpi-bitmaps-fonts.md`.
- **Rule:** A function that returns a translation returns `wxString` by value. - **Rule:** A wrapper that converts a translation returns by value; `wxGetTranslation()` itself
**Why:** `wxGetTranslation()` returns by value now (`include/wx/translation.h:278-321`); returning returns `const wxString&`.
it as `const wxString&` dangles. Orca's `I18N::translate` overloads and `_L` already return by **Why:** 3.3.2 changed `wxGetTranslation()` to return `wxString` by value, and **3.3.3 reverted it**
value. (`interface/wx/translation.h:615`, `include/wx/translation.h:277-309`), so the return type is the
3.2.x `const wxString&` again. That reference points at the catalog's own string or at
`wxTranslations::GetUntranslatedString()`, both of which outlive the call, so forwarding it as a
reference is safe. What still dangles is a temporary you construct: `wxString::FromUTF8`,
`ToUTF8()`, `format_wxstr`. Orca's `I18N::translate` overloads return `wxString` by value and
`translate_utf8`/`_u8L` return `std::string`.
```cpp ```cpp
// Wrong: const wxString& title() { return _L("Printer"); } // Wrong: const wxString& path() { return wxString::FromUTF8(raw); } // temporary
// Right: wxString title() { return _L("Printer"); } // Right: wxString path() { return wxString::FromUTF8(raw); }
``` ```
Cite: `docs/changes.txt:139-142`; `I18N.hpp`. Cite: §8 (the 3.3.3 revert); `I18N.hpp`.
- **Rule:** Escape `&` in user data (preset, filament, printer, file names) shown as a control label or - **Rule:** Escape `&` in user data (preset, filament, printer, file names) shown as a control label or
book page title. book page title.
@@ -314,37 +326,37 @@ change, its line, and what it means for Orca.
// Wrong: book->AddPage(page, preset_name); // Wrong: book->AddPage(page, preset_name);
// Right: book->AddPage(page, wxControl::EscapeMnemonics(preset_name)); // or label->SetLabelText(name) // Right: book->AddPage(page, wxControl::EscapeMnemonics(preset_name)); // or label->SetLabelText(name)
``` ```
Cite: `docs/changes.txt:128-130`; `interface/wx/bookctrl.h:141-147`; `controls-dataview.md`. Cite: `docs/changes.txt:134-136`; `interface/wx/bookctrl.h:141-147`; `controls-dataview.md`.
## 4 3.3 changes that break the build ## 4 3.3 changes that break the build
`changes.txt` "Changes in behaviour which may result in build errors" (:149-252). `changes.txt` "Changes in behaviour which may result in build errors" (:181-292).
| Change | Line | Orca relevance | | Change | Line | Orca relevance |
|---|---|---| |---|---|---|
| 3.0-deprecated symbols disabled by default (`WXWIN_COMPATIBILITY_3_0=1` at wx build time re-enables them), 2.8-deprecated removed | :152-154 | Orca builds `WXWIN_COMPATIBILITY_3_0 0`, `_3_2 1`: port off 3.0-deprecated API | | 3.0-deprecated symbols disabled by default (`WXWIN_COMPATIBILITY_3_0=1` at wx build time re-enables them), 2.8-deprecated removed | :184-186 | Orca builds `WXWIN_COMPATIBILITY_3_0 0`, `_3_2 1`: port off 3.0-deprecated API |
| `wxUSE_UNICODE=0` unsupported | :156 | none | | `wxUSE_UNICODE=0` unsupported | :188 | none |
| `wxUSE_STD_CONTAINERS=1` by default ("Container Classes" overview); building wx with 0 keeps the old containers | :158-161 | Orca builds with 1 → pitfall below | | `wxUSE_STD_CONTAINERS=1` by default ("Container Classes" overview); building wx with 0 keeps the old containers | :190-193 | Orca builds with 1 → pitfall below |
| `wxUSE_STL` gone; implicit `wxString` → `std::[w]string` only with `wxUSE_STD_STRING_CONV_IN_WXSTRING=1` at wx build time | :163-166 | Orca builds 0: convert explicitly (`into_u8`, `ToStdString`, `ToUTF8()`) | | `wxUSE_STL` gone; implicit `wxString` → `std::[w]string` only with `wxUSE_STD_STRING_CONV_IN_WXSTRING=1` at wx build time | :195-198 | Orca builds 0: convert explicitly (`into_u8`, `ToStdString`, `ToUTF8()`) |
| MSW links `gdiplus.lib`, `msimg32.lib` | :168-172 | automatic with MSVC/wx-config; only static non-MSVC builds add them | | MSW links `gdiplus.lib`, `msimg32.lib` | :200-204 | automatic with MSVC/wx-config; only static non-MSVC builds add them |
| wxMotif, wxGTK1 removed | :174-175 | none | | wxMotif, wxGTK1 removed | :206-207 | none |
| Private containers (e.g. `wxSimpleDataObjectList`) removed; object arrays (`wxImageArray`) compare values in `Index()` | :177-183 | use `std::vector`/`std::list` | | Private containers (e.g. `wxSimpleDataObjectList`) removed; object arrays (`wxImageArray`) compare values in `Index()` | :209-215 | use `std::vector`/`std::list` |
| Operators on wx types are hidden (not global) | :185-189 | pitfall below | | Operators on wx types are hidden (not global) | :217-221 | pitfall below |
| `wxString` from `std::string_view` makes `wxstr = {"Hello", 2}` ambiguous | :191-194 | write `wxString{"Hello", 2}` | | `wxString` from `std::string_view` makes `wxstr = {"Hello", 2}` ambiguous | :223-226 | write `wxString{"Hello", 2}` |
| Generic `wxSearchCtrl` lost multi-line-only methods | :196-197 | none | | Generic `wxSearchCtrl` lost multi-line-only methods | :228-229 | none |
| Wide-filename `wxOnAssert()` overload removed | :199-200 | none | | Wide-filename `wxOnAssert()` overload removed | :231-232 | none |
| 64-bit DLLs carry an `x64` suffix in all build systems | :202-204 | packaging scripts matching DLL names; Orca links wx statically (Flatpak builds it shared in its own manifest) | | 64-bit DLLs carry an `x64` suffix in all build systems | :234-236 | packaging scripts matching DLL names; Orca links wx statically (Flatpak builds it shared in its own manifest) |
| CMake config installs to `lib/cmake/wxWidgets-3.3`; plain `find_package(wxWidgets)` is unaffected, hard-coded paths break | :206-211 | Orca: `find_package(wxWidgets 3.3 CONFIG …)` on Windows/macOS, `wx-config --toolkit=gtk${SLIC3R_GTK}` on Linux (Orca's `src/CMakeLists.txt`) | | CMake config installs to `lib/cmake/wxWidgets-3.3`; plain `find_package(wxWidgets)` is unaffected, hard-coded paths break | :238-243 | Orca: `find_package(wxWidgets 3.3 CONFIG …)` on Windows/macOS, `wx-config --toolkit=gtk${SLIC3R_GTK}` on Linux (Orca's `src/CMakeLists.txt`) |
| Memory-tracing options removed | :213-216 | use ASan | | Memory-tracing options removed | :245-248 | use ASan |
| `wxTEST_DIALOG()` needs a trailing `;` | :218-219 | none | | `wxTEST_DIALOG()` needs a trailing `;` | :250-251 | none |
| `wxWindow::GetDefaultBorderForControl()` not virtual | :221-223 | do not override; use `wxBORDER_THEME` | | `wxWindow::GetDefaultBorderForControl()` not virtual | :253-255 | do not override; use `wxBORDER_THEME` |
| GTK `wxDirButton::Create()` lost `wildcard` | :225-226 | none | | GTK `wxDirButton::Create()` lost `wildcard` | :257-258 | none |
| Several virtuals take `wxReadOnlyDC` | :228-231 | pitfall below | | Several virtuals take `wxReadOnlyDC` | :260-263 | pitfall below |
| `wxSizer::Detach()` takes `wxWindowBase*` | :233-236 | only custom sizer subclasses | | `wxSizer::Detach()` takes `wxWindowBase*` | :265-268 | only custom sizer subclasses |
| `wx/cursor.h` no longer includes `wx/utils.h` | :238-240 | include `<wx/utils.h>` explicitly (8248b06337 added it to `GLCanvas3D.cpp`) | | `wx/cursor.h` no longer includes `wx/utils.h` | :270-272 | include `<wx/utils.h>` explicitly (8248b06337 added it to `GLCanvas3D.cpp`) |
| `wxStyledTextCtrl::AddSelection()` returns void | :242-244 | none: `wxUSE_STC=OFF` | | `wxStyledTextCtrl::AddSelection()` returns void | :274-276 | none: `wxUSE_STC=OFF` |
| `wxColour` from `bool` no longer compiles | :246-248 | use the RGB or string ctor explicitly | | `wxColour` from `bool` no longer compiles | :278-280 | use the RGB or string ctor explicitly |
| `wxGLCanvas::CreateSurface()` removed from EGL builds | :250-252 | none: wx chooses EGL or GLX itself (§7) | | `wxGLCanvas::CreateSurface()` removed from EGL builds | :282-284 | none: wx chooses EGL or GLX itself (§7) |
**Pitfalls** **Pitfalls**
@@ -366,7 +378,7 @@ change, its line, and what it means for Orca.
// Wrong: wxSize GetToolSize(wxDC& dc, wxWindow* w, const wxAuiToolBarItem& it); // never called // Wrong: wxSize GetToolSize(wxDC& dc, wxWindow* w, const wxAuiToolBarItem& it); // never called
// Right: wxSize GetToolSize(wxReadOnlyDC& dc, wxWindow* w, const wxAuiToolBarItem& it) override; // Right: wxSize GetToolSize(wxReadOnlyDC& dc, wxWindow* w, const wxAuiToolBarItem& it) override;
``` ```
Cite: `docs/changes.txt:228-231`; `painting-custom-widgets.md`. Cite: `docs/changes.txt:260-263`; `painting-custom-widgets.md`.
- **Rule:** With `wxUSE_STD_CONTAINERS=1`, build a `wxArrayString` with `Add()` or an initializer - **Rule:** With `wxUSE_STD_CONTAINERS=1`, build a `wxArrayString` with `Add()` or an initializer
list, and walk `WX_DECLARE_LIST` lists with `compatibility_iterator` or range-for. list, and walk `WX_DECLARE_LIST` lists with `compatibility_iterator` or range-for.
@@ -386,7 +398,7 @@ change, its line, and what it means for Orca.
`wchar_t`, `std::string` or `std::wstring`. `wchar_t`, `std::string` or `std::wstring`.
**Why:** wx operators are hidden friends now, found only by argument-dependent lookup on a wx type; **Why:** wx operators are hidden friends now, found only by argument-dependent lookup on a wx type;
"preventing them from implicitly being used with types convertible to wx types" "preventing them from implicitly being used with types convertible to wx types"
(`changes.txt:185-189`). `char + std::wstring + …` compiled under 3.1.5 through the global (`changes.txt:217-221`). `char + std::wstring + …` compiled under 3.1.5 through the global
`operator+(char, const wxString&)`, converting the `std::wstring` implicitly; under 3.3 that `operator+(char, const wxString&)`, converting the `std::wstring` implicitly; under 3.3 that
operator is a hidden friend (`include/wx/string.h:2150`) and no operand is a `wxString`, so it operator is a hidden friend (`include/wx/string.h:2150`) and no operand is a `wxString`, so it
does not. does not.
@@ -413,9 +425,9 @@ change, its line, and what it means for Orca.
## 5 3.3.0 notable changes ## 5 3.3.0 notable changes
`changes.txt:380-592` (relative to 3.2.8). `changes.txt:573-785` (relative to 3.2.8).
**Major changes** (:385-394) **Major changes** (:578-587)
| Change | Orca relevance | | Change | Orca relevance |
|---|---| |---|---|
@@ -429,7 +441,7 @@ change, its line, and what it means for Orca.
| Native GTK file dialogs when possible (#24486, #25104) | the portal dialog is used only with GTK ≥ 3.20 at runtime, without `wxFD_PREVIEW` and without an extra control [source] (`src/gtk/filedlg.cpp:265-273, 438-443`); Orca's `CheckboxFileDialog` (`SetExtraControlCreator`, `GUI_Utils.hpp`) therefore gets the non-native GTK dialog | | Native GTK file dialogs when possible (#24486, #25104) | the portal dialog is used only with GTK ≥ 3.20 at runtime, without `wxFD_PREVIEW` and without an extra control [source] (`src/gtk/filedlg.cpp:265-273, 438-443`); Orca's `CheckboxFileDialog` (`SetExtraControlCreator`, `GUI_Utils.hpp`) therefore gets the non-native GTK dialog |
| Native `wxTextCtrl` contents / RTF (#24626, #24912) | available (`GetRTFValue`, `SearchText`) | | Native `wxTextCtrl` contents / RTF (#24626, #24912) | available (`GetRTFValue`, `SearchText`) |
**All** (:398-442) **All** (:591-635)
| Change | Orca relevance | | Change | Orca relevance |
|---|---| |---|---|
@@ -439,7 +451,7 @@ change, its line, and what it means for Orca.
| Environment variables use UTF-8 (#25101) | check round-tripping of non-ASCII paths through `wxGetEnv`/`wxSetEnv` | | Environment variables use UTF-8 (#25101) | check round-tripping of non-ASCII paths through `wxGetEnv`/`wxSetEnv` |
| Improved locale matching (#24855); thread-safe `wxPlatformInfo::Get()` (#25459); `wxXmlParseError` from `wxXmlDocument::Load()` (#24215); customisable error exit code (#24770) | available | | Improved locale matching (#24855); thread-safe `wxPlatformInfo::Get()` (#25459); `wxXmlParseError` from `wxXmlDocument::Load()` (#24215); customisable error exit code (#24770) | available |
**All (GUI)** (:444-500) **All (GUI)** (:637-693)
| Change | Orca relevance | | Change | Orca relevance |
|---|---| |---|---|
@@ -452,17 +464,17 @@ change, its line, and what it means for Orca.
| Non-live resize restored in wxAUI and `wxSplitterWindow` (#24193) | `wxAUI_MGR_LIVE_RESIZE` is in `wxAUI_MGR_DEFAULT` since 3.3.0 (`interface/wx/aui/framemanager.h:59-66`). The style table's "always enabled in wxGTK3 and wxOSX ports as non-live resizing is not implemented in them" (:199-206) is as stale as the `AlwaysUsesLiveResize()` note: that function "always returns false" as of 3.3.0 (:345; `src/aui/framemanager.cpp:711-714`), and the flag decides on every port [source] (`HasLiveResize`, :716-719). See `webview-gl-aui-media.md` §AUI docking | | Non-live resize restored in wxAUI and `wxSplitterWindow` (#24193) | `wxAUI_MGR_LIVE_RESIZE` is in `wxAUI_MGR_DEFAULT` since 3.3.0 (`interface/wx/aui/framemanager.h:59-66`). The style table's "always enabled in wxGTK3 and wxOSX ports as non-live resizing is not implemented in them" (:199-206) is as stale as the `AlwaysUsesLiveResize()` note: that function "always returns false" as of 3.3.0 (:345; `src/aui/framemanager.cpp:711-714`), and the flag decides on every port [source] (`HasLiveResize`, :716-719). See `webview-gl-aui-media.md` §AUI docking |
| `wxInfoBar::ShowCheckBox()` (#25394); printing multiple page ranges (#25030); `wxGrid::CopySelection()` (#24124); new default flat AUI tab art (#25316); `wxApp::SetAppearance()` (#24461) | available | | `wxInfoBar::ShowCheckBox()` (#25394); printing multiple page ranges (#25030); `wxGrid::CopySelection()` (#24124); new default flat AUI tab art (#25316); `wxApp::SetAppearance()` (#24461) | available |
**All (WebView)** (:510-525) — `wxWebViewConfiguration` + `GetNativeConfiguration()`, `SetProxy()`, **All (WebView)** (:703-718) — `wxWebViewConfiguration` + `GetNativeConfiguration()`, `SetProxy()`,
`ShowDevTools()`, `EnablePersistentStorage()`, `EnableBrowserAcceleratorKeys()`, clearing browsing `ShowDevTools()`, `EnablePersistentStorage()`, `EnableBrowserAcceleratorKeys()`, clearing browsing
data, advanced requests, child-window handling, `IsTargetMainFrame()`, Edge user agent settable after data, advanced requests, child-window handling, `IsTargetMainFrame()`, Edge user agent settable after
creation, and **Edge events queued** (#22744, #19075): Edge handlers run later than on the other creation, and **Edge events queued** (#22744, #19075): Edge handlers run later than on the other
backends. Edge posts its events with `AddPendingEvent` (script messages: `src/msw/webview_edge.cpp:811`) backends. Edge posts its events with `AddPendingEvent` (script messages: `src/msw/webview_edge.cpp:872`)
except the vetoable ones, `wxEVT_WEBVIEW_NAVIGATING` (:599) and `wxEVT_WEBVIEW_NEWWINDOW` with its except the vetoable ones, `wxEVT_WEBVIEW_NAVIGATING` (:655-662) and `wxEVT_WEBVIEW_NEWWINDOW` with its
`NEWWINDOW_FEATURES` follow-up (:723, :737), which stay synchronous; WebKit and `NEWWINDOW_FEATURES` follow-up (:783-785, :796-798), which stay synchronous; WebKit and
WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:1360`, WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:1360`,
`src/gtk/webview_webkit2.cpp:408`) [source]. `webview-gl-aui-media.md` owns the details. `src/gtk/webview_webkit2.cpp:408`) [source]. `webview-gl-aui-media.md` owns the details.
**wxGTK** (:527-547) **wxGTK** (:720-740)
| Change | Orca relevance | | Change | Orca relevance |
|---|---| |---|---|
@@ -477,46 +489,53 @@ WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:136
| `wxDC::DrawRoundedRectangle()` radius limited to half the smaller side (#24327) | the clamp is in the GTK2 GDK DC (`src/gtk/dcclient.cpp:874-875`, built only in the GTK2 opt-out, `GTK2_LOWLEVEL_SRC` in `build/files`) and also in the common `wxGraphicsPathData::AddRoundedRectangle` (`src/common/graphcmn.cpp:439-440`, absent in 3.1.5) that `wxGraphicsContext::DrawRoundedRectangle` uses, so every `wxGCDC` clamps: GTK3 (Cairo) and macOS window DCs, and Orca's memory-DC + `wxGCDC` paint paths on all ports [source]. A radius larger than half the smaller side is now clamped instead of drawing overlapping arcs | | `wxDC::DrawRoundedRectangle()` radius limited to half the smaller side (#24327) | the clamp is in the GTK2 GDK DC (`src/gtk/dcclient.cpp:874-875`, built only in the GTK2 opt-out, `GTK2_LOWLEVEL_SRC` in `build/files`) and also in the common `wxGraphicsPathData::AddRoundedRectangle` (`src/common/graphcmn.cpp:439-440`, absent in 3.1.5) that `wxGraphicsContext::DrawRoundedRectangle` uses, so every `wxGCDC` clamps: GTK3 (Cairo) and macOS window DCs, and Orca's memory-DC + `wxGCDC` paint paths on all ports [source]. A radius larger than half the smaller side is now clamped instead of drawing overlapping arcs |
| Read-only `wxBitmapComboBox` height fixed (#25468) | `Slic3r::GUI::BitmapComboBox` on GTK | | Read-only `wxBitmapComboBox` height fixed (#25468) | `Slic3r::GUI::BitmapComboBox` on GTK |
**wxMSW** (:549-583) **wxMSW** (:742-776)
| Change | Orca relevance | | Change | Orca relevance |
|---|---| |---|---|
| "Enable double buffering for all windows" (#22851) | **reverted in 3.3.2** (#25808) → pitfall below | | "Enable double buffering for all windows" (#22851) | **reverted in 3.3.2** (#25808) → pitfall below |
| `wxOverlay` reimplemented with layered windows (#23261) | none: no `wxOverlay` | | `wxOverlay` reimplemented with layered windows (#23261) | none: no `wxOverlay` |
| `wxBG_STYLE_TRANSPARENT` implemented (#23412) | as `WS_EX_TRANSPARENT` on non-TLW children [source] (`src/msw/window.cpp:1581-1582`); set before `Create()` (`painting-custom-widgets.md`) | | `wxBG_STYLE_TRANSPARENT` implemented (#23412) | as `WS_EX_TRANSPARENT` on non-TLW children [source] (`src/msw/window.cpp:1581-1582`); set before `Create()` (`painting-custom-widgets.md`) |
| `wxCAPTION` turned on when min/max/close boxes are set (#23575) | `WS_CAPTION` is added to the style (`src/msw/toplevel.cpp:132-135`); origin of the MainFrame workaround (§8) | | `wxCAPTION` turned on when min/max/close boxes are set (#23575) | `WS_CAPTION` is added to the style (`src/msw/toplevel.cpp:132-135`); origin of the MainFrame workaround (§10) |
| `wxButton` default size larger in high DPI (#25297) | raw `wxButton` layouts may grow; Orca dialogs use `Button`/`DialogButtons` | | `wxButton` default size larger in high DPI (#25297) | raw `wxButton` layouts may grow; Orca dialogs use `Button`/`DialogButtons` |
| Markup in `wxStaticText` (#25000); `wxHyperlinkCtrl` colour changeable (#23549) | `SetLabelMarkup` now works on MSW (single line) | | Markup in `wxStaticText` (#25000); `wxHyperlinkCtrl` colour changeable (#23549) | `SetLabelMarkup` now works on MSW (single line) |
| Extended-length paths (#25033); `wxFileDialog` no unwanted extension (#24949); UTF-8 build fixes (#23313); non-BMP strings (#25128) | available | | Extended-length paths (#25033); `wxFileDialog` no unwanted extension (#24949); UTF-8 build fixes (#23313); non-BMP strings (#25128) | available |
| `wxDisplay` invalidated on display change (#25396); TLW with one child resized on DPI change (#22983); Aero-snapped geometry saved | multi-monitor geometry | | `wxDisplay` invalidated on display change (#25396); TLW with one child resized on DPI change (#22983); Aero-snapped geometry saved | multi-monitor geometry |
| Modern default `wxTreeCtrl` look (#23844); RTL fixes for `wxOverlay`/`wxScrolled` (#25413) and GDI+ (#25431); `wxBitmap::UseAlpha()` returns `bool` (#23919) | available | | Modern default `wxTreeCtrl` look (#23844); RTL fixes for `wxOverlay`/`wxScrolled` (#25413) and GDI+ (#25431); `wxBitmap::UseAlpha()` returns `bool` (#23919) | available |
**wxOSX** (:585-592) — `wxEventLoop::OnExit()` is always called (#25409); TLW cursor setting fixed **wxOSX** (:778-785) — `wxEventLoop::OnExit()` is always called (#25409); TLW cursor setting fixed
(#25131); Cmd-C no longer activates a "Close" button (#25346); `wxCursor` loadable from resources (#25131); Cmd-C no longer activates a "Close" button (#25346); `wxCursor` loadable from resources
(#24374); `wxUIActionSimulator` works (#23692), usable for GUI tests. (#24374); `wxUIActionSimulator` works (#23692), usable for GUI tests.
**Pitfalls** **Pitfalls**
- **Rule:** Do not replace Orca's MSW dark mode with wx's (`SetAppearance`/`MSWEnableDarkMode`) - **Rule:** Orca keeps its own Windows theming (`NppDarkMode`) and only informs wx with
unless live theme switching is kept. `MSWEnableDarkMode(DarkMode_Auto)`; do not replace it with wx's dark mode without accounting for the
**Why:** wx's MSW dark mode cannot change once any top-level window exists or a mode was chosen: chrome NppDarkMode themes itself.
`SetAppearance` returns `CannotChange` (`src/msw/darkmode.cpp:263-270`; **Why:** when 8248b06337 landed (3.3.2), wx's MSW dark mode could not be changed once a top-level
`interface/wx/app.h:1166-1173`). TaskDialog-based dialogs (`wxMessageDialog`, `wxProgressDialog`, window existed — `SetAppearance` returned `CannotChange` — so a live Preferences toggle would have
simple `wxAboutBox`), the common dialogs (colour, find/replace, font, page setup, print) and the been restart-only. That blocker is gone: 3.3.3 (#26516) and 3.3.4 (#26734) made the mode switchable
date/time/calendar controls stay light (`interface/wx/app.h:1434-1448`). Orca switches themes at at runtime. `MSWEnableDarkMode()` re-applies the mode to an existing window (sends it
runtime, which is why 8248b06337 kept NppDarkMode and only informs wx with `WM_SYSCOLORCHANGE`, `src/msw/darkmode.cpp:345-349`), controls restyle through
`MSWEnableDarkMode(DarkMode_Auto)` (§8). `wxMSWDarkMode::HasChanged()`/`NotifySysColorChange()` (`src/msw/window.cpp:5337, 5528-5534`), and
`SetAppearance()` returns only `Ok`/`Failure`; `AppearanceResult::CannotChange` is no longer
returned (`src/msw/darkmode.cpp:289-375`; `interface/wx/app.h:1151, 1179-1183`). The remaining
documented limits are the date/time/calendar controls, `wxPrintDialog` on Windows 10 and MDI
applications (`interface/wx/app.h:1442-1448`); `wxMessageDialog` (3.3.3, #26570) and the common
dialogs (3.3.4, #26780) now do support dark mode. Orca still keeps NppDarkMode because it themes
Orca's own chrome (title bars, explorer theme, scrollbars, list headers) and drives the live
theme-switch path (§10).
Cite: 8248b06337 (PR text); `colours-dark-mode.md`. Cite: 8248b06337 (PR text); `colours-dark-mode.md`.
- **Rule:** On MSW, a custom-painted control buffers its own drawing (`wxAutoBufferedPaintDC`/ - **Rule:** On MSW, a custom-painted control buffers its own drawing (`wxAutoBufferedPaintDC`/
`wxBufferedPaintDC` with `wxBG_STYLE_PAINT`, or the Orca memory-DC + `wxGCDC` path), or calls `wxBufferedPaintDC` with `wxBG_STYLE_PAINT`, or the Orca memory-DC + `wxGCDC` path), or calls
`SetDoubleBuffered(true)` after creation. `SetDoubleBuffered(true)` after creation.
**Why:** 3.3.0's global `WS_EX_COMPOSITED` was reverted in 3.3.2 (`changes.txt:308`). In 3.3.2 **Why:** 3.3.0's global `WS_EX_COMPOSITED` was reverted in 3.3.2 (`changes.txt:501`). In 3.3.4
nothing sets it except an explicit `SetDoubleBuffered(true)` [source] (`src/msw/window.cpp:4704-4721`; nothing sets it except an explicit `SetDoubleBuffered(true)` [source] (`src/msw/window.cpp:4704-4721`;
the only other use is `MSWDisableComposited`, :1643-1652), so MSW windows are not double-buffered by the only other use is `MSWDisableComposited`, :1643-1652), so MSW windows are not double-buffered by
default, exactly as in 3.1.5. `wxAutoBufferedPaintDC` is a `wxBufferedPaintDC` on MSW at compile default, exactly as in 3.1.5. `wxAutoBufferedPaintDC` is a `wxBufferedPaintDC` on MSW at compile
time (`include/wx/dcbuffer.h:18-23, 215-221`). Nothing tuned against 3.3.0/3.3.1 applies. time (`include/wx/dcbuffer.h:18-23, 215-221`). Nothing tuned against 3.3.0/3.3.1 applies.
Cite: `docs/changes.txt:308, 557`; `painting-custom-widgets.md`. Cite: `docs/changes.txt:501, 750`; `painting-custom-widgets.md`.
- **Rule:** A `wxEVT_DPI_CHANGED` handler must be correct on GTK3, and every handler you bind — on a - **Rule:** A `wxEVT_DPI_CHANGED` handler must be correct on GTK3, and every handler you bind — on a
child, a control or a `DPIDialog`/`DPIFrame` — calls `Skip()`. child, a control or a `DPIDialog`/`DPIFrame` — calls `Skip()`.
@@ -529,11 +548,11 @@ WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:136
ctor starts at 1 because `get_dpi_for_window` returns 96 on Linux). Double scaling when a window moves between monitors of ctor starts at 1 because `get_dpi_for_window` returns 96 on Linux). Double scaling when a window moves between monitors of
different scale is a risk that has not been verified at runtime; test DPI changes on GTK when different scale is a risk that has not been verified at runtime; test DPI changes on GTK when
touching `DPIAware::rescale` paths. touching `DPIAware::rescale` paths.
Cite: `docs/changes.txt:541`; `dpi-bitmaps-fonts.md` §wxEVT_DPI_CHANGED. Cite: `docs/changes.txt:734`; `dpi-bitmaps-fonts.md` §wxEVT_DPI_CHANGED.
## 6 3.3.1 notable fixes ## 6 3.3.1 notable fixes
`changes.txt:333-377`. `changes.txt:526-570`.
| Port | Change | Orca relevance | | Port | Change | Orca relevance |
|---|---|---| |---|---|---|
@@ -547,7 +566,7 @@ WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:136
## 7 3.3.2 notable changes ## 7 3.3.2 notable changes
`changes.txt:255-318`, relative to 3.2.10 (see §1 for the unlisted 3.2.9/3.2.10 fixes). `changes.txt:448-511`, relative to 3.2.10 (see §1 for the unlisted 3.2.9/3.2.10 fixes).
| Port | Change | Orca relevance | | Port | Change | Orca relevance |
|---|---|---| |---|---|---|
@@ -589,7 +608,7 @@ WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:136
// Wrong: m_static_valid->SetLabel(info_line); m_static_valid->Wrap(FromDIP(300)); // Wrong: m_static_valid->SetLabel(info_line); m_static_valid->Wrap(FromDIP(300));
// Right: m_static_valid->SetLabel(info_line); m_static_valid->Wrap(-1); m_static_valid->Wrap(FromDIP(300)); // Right: m_static_valid->SetLabel(info_line); m_static_valid->Wrap(-1); m_static_valid->Wrap(FromDIP(300));
``` ```
Cite: `docs/changes.txt:280`; `sizers-layout.md` §wxStaticText wrapping. Cite: `docs/changes.txt:473`; `sizers-layout.md` §wxStaticText wrapping.
- **Rule:** On Linux/X11, call `wxGLCanvas::PreferGLX()` before any GL use, attribute objects - **Rule:** On Linux/X11, call `wxGLCanvas::PreferGLX()` before any GL use, attribute objects
included; set a swap interval explicitly if the canvas needs VSync. included; set a swap interval explicitly if the canvas needs VSync.
@@ -605,7 +624,7 @@ WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:136
```cpp ```cpp
// Right (if frame pacing is wanted): canvas->SetSwapInterval(1); // before the first SwapBuffers // Right (if frame pacing is wanted): canvas->SetSwapInterval(1); // before the first SwapBuffers
``` ```
Cite: `docs/changes.txt:275-276, 292`; `webview-gl-aui-media.md` §EGL vs GLX. Cite: `docs/changes.txt:468-469, 485`; `webview-gl-aui-media.md` §EGL vs GLX.
- **Rule:** Do not count clicks from `wxEVT_LEFT_DCLICK` alone on macOS; handle `DOWN` and `DCLICK` - **Rule:** Do not count clicks from `wxEVT_LEFT_DCLICK` alone on macOS; handle `DOWN` and `DCLICK`
as on MSW. as on MSW.
@@ -613,13 +632,68 @@ WebKit2GTK deliver script messages synchronously (`src/osx/webview_webkit.mm:136
(left and right buttons), so a triple click gives `DOWN, DCLICK, DOWN` as on MSW; previously every (left and right buttons), so a triple click gives `DOWN, DCLICK, DOWN` as on MSW; previously every
click with `clickCount > 1` was a `DCLICK` [source] (`src/osx/cocoa/window.mm:4103-4150`). Per-platform click-count ifdefs click with `clickCount > 1` was a `DCLICK` [source] (`src/osx/cocoa/window.mm:4103-4150`). Per-platform click-count ifdefs
written for 3.1.5 need rechecking. written for 3.1.5 need rechecking.
Cite: `docs/changes.txt:316`; `mouse-keyboard-focus.md`. Cite: `docs/changes.txt:509`; `mouse-keyboard-focus.md`.
## 8 Migration already done in Orca ## 8 3.3.3 notable changes
The upgrade landed as 8248b06337 ("Updated wxWidgets to 3.3.2", #12941; build system 2d7e26292b). `changes.txt:388-445`, relative to 3.2.11 (see §1 for the unlisted 3.2.10/3.2.11 fixes).
Its PR kept Orca's own MSW dark mode to avoid broader changes and because wx's needs an app restart to
switch. Each row is a rule for new code; the owning file has the detail. | Port | Change | Orca relevance |
|---|---|---|
| All | `wxMoveToTrash()` (#26256); `wxSizer::DetachItem()` (#26512); truncated reads are errors in `wxDataInputStream` (#26600); `wxGetOsDescription()` (#26231); C++20 `<=>` for `wxString` (#26306) | available; Orca detaches windows and has its own file deletion |
| All | **`wxGetTranslation()` returns `const wxString&` again**, reverting 3.3.2's by-value change | the by-value rule is retired → §3 pitfall |
| GUI | `wxWebView::Print()` print settings (#26239) and `PrintToPDF()` (#26583); `wxWebViewConfiguration::DisableGPUAcceleration()` (#26626) | `webview-gl-aui-media.md` |
| GUI | `wxGrid::GetFrozen{Row,Col}LabelWindow()` (#26617); `wxSVGFileDC` accessibility (#26379) and `GetSVGDocument()` (#26344) | `controls-dataview.md`; `wxSVGFileDC` available |
| wxGTK | Fix regression when using `wxImageList` in high DPI (#26349) | the physical-pixel image-list rule is unchanged (§3) |
| wxGTK | Fix `wxStaticText` label wrapping | the base `Wrap()` cache is unchanged (§7); only the GTK label wrapping was fixed |
| wxGTK | Assert when the clipboard has non-ASCII targets fixed (#26263); GTK-without-Wayland build fixed (#26269); high-DPI bitmaps in `wxAboutBox` (#22192) | clipboard |
| wxMSW | **Light/dark mode switching implemented** (#26516) | see §5: this removes the old "cannot switch at runtime" blocker |
| wxMSW | `wxMessageDialog` dark mode (#26570); combo/listbox dark mode on Windows 11 (#26535); `wxCheckBox` label in screen readers (#26270); `wxPD_CAN_SKIP` regression (#26287); Direct2D text regression (#26259) | dark-mode and accessibility fixes |
| wxMSW | Stylus events (#26223); colour emoji via Direct2D (#26657) | available |
| wxOSX | Data-view icons under macOS 26 (#26374); `wxOverlay` phantoms in Mission Control (#26380); `wxEVT_DATAVIEW_ITEM_EDITING_DONE` value set (#26367); Xcode project for macOS 27 (#26578) | native look and data view |
## 9 3.3.4 notable changes
`changes.txt:295-385`, relative to 3.2.11 (see §1 for the unlisted 3.2.11/3.2.12 fixes).
| Port | Change | Orca relevance |
|---|---|---|
| All | `wxString` usable with `{fmt}`/`std::format()` (#27180); `wxPATH_RMDIR_PARENTS`; `fsync()` in `wxTempFile` (#27001); `wxDateTime::GetAsDOS()` after 2038 (#4393); TCP `wxIPC` fixes (#24858) | available |
| GUI | **Accelerators take priority over the focused window in all ports** (#22630), with the new `wxEVT_ACCELERATOR_KEY` event and the `wxWindow::ClaimsKeyBeforeAccelerator()` override that text controls use to reserve their editing keys (`interface/wx/event.h:1799`, `interface/wx/window.h:4580`) | pitfall below; `mouse-keyboard-focus.md` |
| GUI | wxGrid: `wxGridCellChoiceEditor` UI fixes (#12094), best size for auto-wrapped rows (#14072), `MakeCellVisible()` with variable row heights (#4371), editor-change crash (#21986) | `controls-dataview.md`; the choice-editor `Combo()` cast rule is unchanged |
| GUI | AUI: no spurious sash jump on click (#4547); an added pane's best size is respected (#4404) | Plater docking |
| GUI | `wxListCtrl` (#15411) and `wxStatusBar` (#24305) accessibility; `wxAuiNotebook` selection after a page removal (#9920); `wxPreviewCanvas` crash (#9822); generic `wxCalendarCtrl` background colour (#21885); LunaSVG with filters (#27176) | available; no `wxAuiNotebook` in Orca |
| wxMSW | **Dark mode can be enabled dynamically** (#26734); dark mode for `wxFontPickerCtrl` (#26667), `wxNotebook` (#26694, #26695), `wxSpinButton` (#26682, #26683) and the common dialogs (#26780) | §5 pitfall; `colours-dark-mode.md` |
| wxMSW | `wxRenameFile()` no longer copies file attributes (`changes.txt:345-347`, incompatible); Esc closes dialogs used by IME/auto-completion (#16059, #27145); IME handling in wxGrid improved (#24558); `wxPersistent` controls DPI-aware (#18752); non-BMP character input (#27016) | file dialogs, keyboard and IME |
| wxGTK | Wayland: crash on pointer/seat disconnect fixed (#27069); **AUI panes draggable via system drag sessions** (#26969); **window geometry restorable** via XDG session management (#26324); overlay-scrollbar client size (#26889) | the Wayland gaps are partly narrowed; `webview-gl-aui-media.md` §AUI |
| wxOSX | `wxEVT_CHAR` key codes fixed for events with Ctrl (#26810); context-menu accessibility (#13010); custom controls in sandboxed `wxFileDialog` (#26908) | `mouse-keyboard-focus.md`; macOS keys |
**Pitfalls**
- **Rule:** On every port an accelerator now runs before the focused window handles the key, unless
that window claims the key; a custom control that must keep a key over an accelerator overrides
`wxWindow::ClaimsKeyBeforeAccelerator()`, or handles `wxEVT_ACCELERATOR_KEY` and calls
`UseAccelerator()`.
**Why:** before 3.3.4 only wxGTK let the focused window handle the key first; the other ports
already gave accelerators priority. 3.3.4 made every port consistent and added the
`wxEVT_ACCELERATOR_KEY` event, sent after `wxEVT_CHAR_HOOK` (before it on macOS) to the focus
window and propagated to its parents (`interface/wx/event.h:1740-1801`;
`interface/wx/window.h:4554-4583`). Text controls, `wxComboBox` and `wxSpinCtrl` reserve their
editing keys by overriding `ClaimsKeyBeforeAccelerator()` and returning
`wxTextEntryBase::IsUsedForEditing()` (`src/common/textcmn.cpp:136-140`;
`src/common/textentrycmn.cpp:441-509`; `src/common/spinctrlcmn.cpp:160-167`;
`src/msw/combobox.cpp:389-395`, `src/gtk/combobox.cpp:205-211`), and the GTK accelerator walk now
consults it (`src/gtk/window.cpp:1524-1539`). Orca's topbar menus are popups whose accelerators are
display-only and Orca dispatches its own shortcuts, so few sites are affected; the macOS
`ObjectList` `wxAcceleratorTable` and the wxInspector table are the live ones.
Cite: `docs/changes.txt:321`; `mouse-keyboard-focus.md` §Accelerators.
## 10 Migration already done in Orca
The upgrade landed as 8248b06337 ("Updated wxWidgets to 3.3.2", #12941; build system 2d7e26292b) and
the pin later advanced to upstream 3.3.4. Its PR kept Orca's own MSW dark mode to avoid broader
changes; wx could then only switch at app start, so a live Orca toggle needed NppDarkMode. Each row is
a rule for new code; the owning file has the detail.
| Commit | Rule for new code | Where | Owner | | Commit | Rule for new code | Where | Owner |
|---|---|---|---| |---|---|---|---|
@@ -0,0 +1,38 @@
diff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in
index 2f3a735d920c..2593c045b89b 100644
--- a/build/cmake/wxWidgetsConfig.cmake.in
+++ b/build/cmake/wxWidgetsConfig.cmake.in
@@ -50,12 +50,28 @@ if(WIN32_MSVC_NAMING)
set(wxARCH_SUFFIX "_${wxPLATFORM_ARCH}")
endif()
- # use wxWidgets_USE_STATIC to force static libraries, otherwise shared is searched first
- if(NOT wxWidgets_USE_STATIC AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}_dll/@PROJECT_NAME@Targets.cmake")
- set(wxPLATFORM_LIB_DIR "/${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}_dll")
- elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}_lib/@PROJECT_NAME@Targets.cmake")
- set(wxPLATFORM_LIB_DIR "/${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}_lib")
+ # wxCOMPILER_PREFIX names the consuming compiler; the installed layout is named
+ # after the compiler that built wxWidgets. cl and clang-cl share an ABI, so
+ # either can consume either build.
+ set(wxCOMPILER_PREFIXES "${wxCOMPILER_PREFIX}")
+ if(wxCOMPILER_PREFIX STREQUAL "clang")
+ list(APPEND wxCOMPILER_PREFIXES "vc")
+ elseif(wxCOMPILER_PREFIX STREQUAL "vc")
+ list(APPEND wxCOMPILER_PREFIXES "clang")
endif()
+
+ # use wxWidgets_USE_STATIC to force static libraries, otherwise shared is searched first
+ foreach(wxPREFIX IN LISTS wxCOMPILER_PREFIXES)
+ if(NOT wxWidgets_USE_STATIC AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/${wxPREFIX}${wxARCH_SUFFIX}_dll/@PROJECT_NAME@Targets.cmake")
+ set(wxPLATFORM_LIB_DIR "/${wxPREFIX}${wxARCH_SUFFIX}_dll")
+ break()
+ elseif(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${wxPREFIX}${wxARCH_SUFFIX}_lib/@PROJECT_NAME@Targets.cmake")
+ set(wxPLATFORM_LIB_DIR "/${wxPREFIX}${wxARCH_SUFFIX}_lib")
+ break()
+ endif()
+ endforeach()
+ unset(wxPREFIX)
+ unset(wxCOMPILER_PREFIXES)
endif()
include("${CMAKE_CURRENT_LIST_DIR}${wxPLATFORM_LIB_DIR}/@PROJECT_NAME@Targets.cmake")
+8 -2
View File
@@ -28,12 +28,18 @@ if (APPLE)
COMMAND ${GIT_EXECUTABLE} apply --verbose COMMAND ${GIT_EXECUTABLE} apply --verbose
${CMAKE_CURRENT_LIST_DIR}/0001-macos-use-srgb-colour-components.patch ${CMAKE_CURRENT_LIST_DIR}/0001-macos-use-srgb-colour-components.patch
) )
elseif (WIN32)
set(_wx_patch_command
${GIT_EXECUTABLE} checkout -f -- build/cmake/wxWidgetsConfig.cmake.in
COMMAND ${GIT_EXECUTABLE} apply --verbose
${CMAKE_CURRENT_LIST_DIR}/0002-clang-cl-sibling-compiler-prefix.patch
)
endif () endif ()
orcaslicer_add_cmake_project( orcaslicer_add_cmake_project(
wxWidgets wxWidgets
GIT_REPOSITORY "https://github.com/SoftFever/Orca-deps-wxWidgets" GIT_REPOSITORY "https://github.com/wxWidgets/wxWidgets"
GIT_TAG v3.3.2 GIT_TAG v3.3.4
GIT_SHALLOW ON GIT_SHALLOW ON
GIT_SUBMODULES 3rdparty/catch 3rdparty/pcre 3rdparty/libwebp GIT_SUBMODULES 3rdparty/catch 3rdparty/pcre 3rdparty/libwebp
PATCH_COMMAND ${_wx_patch_command} PATCH_COMMAND ${_wx_patch_command}
File diff suppressed because it is too large Load Diff
@@ -118,9 +118,9 @@ modules:
# Use git instead of archive: wxWidgets 3.3 relies on multiple git # Use git instead of archive: wxWidgets 3.3 relies on multiple git
# submodules (PCRE2, etc.) that are not included in GitHub tarballs. # submodules (PCRE2, etc.) that are not included in GitHub tarballs.
- type: git - type: git
url: https://github.com/SoftFever/Orca-deps-wxWidgets.git url: https://github.com/wxWidgets/wxWidgets.git
tag: orca-3.3.2 tag: v3.3.4
commit: db1005db3dea2c37a46fb455a9a02e37aa360751 commit: 6a42a4b999b127cf28a8b5fe686da6b8ca93a9b8
# OrcaSlicer C++ dependencies (built offline with pre-downloaded archives) # OrcaSlicer C++ dependencies (built offline with pre-downloaded archives)
- name: orca_deps - name: orca_deps
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#include <string> #include <string>
namespace Slic3r { namespace Slic3r {
+2
View File
@@ -1,3 +1,5 @@
#pragma once
// paper: https://people.eecs.berkeley.edu/~jrs/meshpapers/GarlandHeckbert2.pdf // paper: https://people.eecs.berkeley.edu/~jrs/meshpapers/GarlandHeckbert2.pdf
// sum up: https://users.csc.calpoly.edu/~zwood/teaching/csc570/final06/jseeba/ // sum up: https://users.csc.calpoly.edu/~zwood/teaching/csc570/final06/jseeba/
// inspiration: https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification // inspiration: https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification
+15 -2
View File
@@ -379,14 +379,24 @@ void FilamentGroupPopup::OnTimer(wxTimerEvent &event)
// leaving event got triggered. So the timer is stopped first, then started // leaving event got triggered. So the timer is stopped first, then started
// again, causing the popup being dismissed immediately. // again, causing the popup being dismissed immediately.
// To fix this, we check if cursor is still inside the popup window before // To fix this, we check if cursor is still inside the popup window before
// dismissing. // dismissing, and keep checking while it is: a leave event is not guaranteed
// to follow, and a popup left open keeps grabbing the mouse capture.
wxPoint pos = this->ScreenToClient(wxGetMousePosition()); wxPoint pos = this->ScreenToClient(wxGetMousePosition());
if (this->GetClientRect().Contains(pos)) return; if (this->GetClientRect().Contains(pos)) {
StartTimer();
return;
}
#endif #endif
Dismiss(); Dismiss();
} }
FilamentGroupPopup::~FilamentGroupPopup()
{
m_timer->Stop();
delete m_timer;
}
void FilamentGroupPopup::Dismiss() { void FilamentGroupPopup::Dismiss() {
m_active = false; m_active = false;
PopupWindow::Dismiss(); PopupWindow::Dismiss();
@@ -405,7 +415,10 @@ void FilamentGroupPopup::OnEnterWindow(wxMouseEvent &)
// Ignore spurious ENTER synthesized by PopupWindow::OnMouseEvent2 on macOS. // Ignore spurious ENTER synthesized by PopupWindow::OnMouseEvent2 on macOS.
wxPoint pos = this->ScreenToClient(wxGetMousePosition()); wxPoint pos = this->ScreenToClient(wxGetMousePosition());
if (!this->GetClientRect().Contains(pos)) return; if (!this->GetClientRect().Contains(pos)) return;
// On macOS the timer keeps running instead, and OnTimer closes the popup once the cursor has left it.
#ifndef __APPLE__
ResetTimer(); ResetTimer();
#endif
} }
void FilamentGroupPopup::UpdateButtonStatus(int hover_idx) void FilamentGroupPopup::UpdateButtonStatus(int hover_idx)
+1
View File
@@ -27,6 +27,7 @@ class FilamentGroupPopup : public PopupWindow
{ {
public: public:
FilamentGroupPopup(wxWindow *parent); FilamentGroupPopup(wxWindow *parent);
~FilamentGroupPopup() override;
void tryPopup(Plater* plater,PartPlate* plate, bool slice_all); void tryPopup(Plater* plater,PartPlate* plate, bool slice_all);
void tryClose(); void tryClose();
void Dismiss() override; void Dismiss() override;
+9
View File
@@ -20,6 +20,8 @@
#include <wx/gdicmn.h> #include <wx/gdicmn.h>
#include <wx/dialog.h> #include <wx/dialog.h>
#include "slic3r/GUI/FilamentMapPanel.hpp" #include "slic3r/GUI/FilamentMapPanel.hpp"
#include "slic3r/GUI/FilamentGroupPopup.hpp"
#include "slic3r/GUI/MainFrame.hpp"
namespace Slic3r { namespace GUI { namespace Slic3r { namespace GUI {
@@ -377,6 +379,13 @@ FilamentMapMode FilamentMapDialog::get_mode()
int FilamentMapDialog::ShowModal() int FilamentMapDialog::ShowModal()
{ {
// The Slice-plate hover popup is a transient popup that keeps grabbing the mouse
// capture while shown. Left behind this modal dialog it would starve the dialog of
// mouse events, so close it synchronously first, whichever path opened the dialog.
if (MainFrame* frame = wxGetApp().mainframe;
frame && frame->m_filament_group_popup && frame->m_filament_group_popup->IsShown())
frame->m_filament_group_popup->Dismiss();
update_panel_status(m_page_type); update_panel_status(m_page_type);
return wxDialog::ShowModal(); return wxDialog::ShowModal();
} }
+2 -2
View File
@@ -235,7 +235,7 @@ void GridCellFilamentsEditor::SetSize(const wxRect& rect)
void GridCellFilamentsEditor::OnComboCloseUp(wxCommandEvent& evt) void GridCellFilamentsEditor::OnComboCloseUp(wxCommandEvent& evt)
{ {
wxGridCellChoiceEditor::OnComboCloseUp(evt); wxGridCellChoiceEditor::DismissEditor();
} }
void GridCellFilamentsEditor::BeginEdit(int row, int col, wxGrid* grid) void GridCellFilamentsEditor::BeginEdit(int row, int col, wxGrid* grid)
@@ -449,7 +449,7 @@ void GridCellChoiceEditor::SetSize(const wxRect &rect)
wxGridCellChoiceEditor::SetSize(rect); wxGridCellChoiceEditor::SetSize(rect);
} }
void GridCellChoiceEditor::OnComboCloseUp(wxCommandEvent &evt) { wxGridCellChoiceEditor::OnComboCloseUp(evt); } void GridCellChoiceEditor::OnComboCloseUp(wxCommandEvent &evt) { wxGridCellChoiceEditor::DismissEditor(); }
void GridCellChoiceEditor::BeginEdit(int row, int col, wxGrid *grid) void GridCellChoiceEditor::BeginEdit(int row, int col, wxGrid *grid)
{ {
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
@interface OtherInstanceMessageHandlerMac : NSObject @interface OtherInstanceMessageHandlerMac : NSObject
-6
View File
@@ -2309,12 +2309,6 @@ wxBoxSizer* MainFrame::create_side_tools()
bool slice = true; bool slice = true;
// The Slice-plate hover popup is a transient popup that keeps grabbing
// the mouse capture while shown. Left behind the modal grouping dialog it
// would starve that dialog of mouse events, so close it synchronously first.
if (m_filament_group_popup)
m_filament_group_popup->Dismiss();
auto curr_plate = m_plater->get_partplate_list().get_curr_plate(); auto curr_plate = m_plater->get_partplate_list().get_curr_plate();
#ifdef __linux__ #ifdef __linux__
PresetBundle* preset = wxGetApp().preset_bundle; PresetBundle* preset = wxGetApp().preset_bundle;
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#include "slic3r/GUI/wxExtensions.hpp" #include "slic3r/GUI/wxExtensions.hpp"
#include <map> #include <map>
#include <cstdint> #include <cstdint>
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
@interface RemovableDriveManagerMM : NSObject @interface RemovableDriveManagerMM : NSObject
+13 -2
View File
@@ -17,6 +17,7 @@
BEGIN_EVENT_TABLE(SideButton, wxWindow) BEGIN_EVENT_TABLE(SideButton, wxWindow)
EVT_LEFT_DOWN(SideButton::mouseDown) EVT_LEFT_DOWN(SideButton::mouseDown)
EVT_LEFT_UP(SideButton::mouseReleased) EVT_LEFT_UP(SideButton::mouseReleased)
EVT_MOUSE_CAPTURE_LOST(SideButton::mouseCaptureLost)
EVT_PAINT(SideButton::paintEvent) EVT_PAINT(SideButton::paintEvent)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -331,20 +332,30 @@ void SideButton::mouseDown(wxMouseEvent& event)
event.Skip(); event.Skip();
pressedDown = true; pressedDown = true;
SetFocus(); SetFocus();
CaptureMouse(); // Capturing twice pushes this button onto the capture stack twice, and the
// release would then hand the capture straight back to it.
if (!HasCapture())
CaptureMouse();
} }
void SideButton::mouseReleased(wxMouseEvent& event) void SideButton::mouseReleased(wxMouseEvent& event)
{ {
event.Skip(); event.Skip();
// A press whose release went elsewhere still holds the capture.
if (HasCapture())
ReleaseMouse();
if (pressedDown) { if (pressedDown) {
pressedDown = false; pressedDown = false;
ReleaseMouse();
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition())) if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
sendButtonEvent(); sendButtonEvent();
} }
} }
void SideButton::mouseCaptureLost(wxMouseCaptureLostEvent&)
{
pressedDown = false;
}
void SideButton::sendButtonEvent() void SideButton::sendButtonEvent()
{ {
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId()); wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
+1
View File
@@ -94,6 +94,7 @@ private:
void mouseDown(wxMouseEvent& event); void mouseDown(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event); void mouseReleased(wxMouseEvent& event);
void mouseCaptureLost(wxMouseCaptureLostEvent& event);
void sendButtonEvent(); void sendButtonEvent();
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/colour.h> #include <wx/colour.h>