Skip to content

Feature/wayland support - #30

Open
pplupo wants to merge 41 commits into
Euro-Office:mainfrom
pplupo:feature/wayland-migration
Open

Feature/wayland support#30
pplupo wants to merge 41 commits into
Euro-Office:mainfrom
pplupo:feature/wayland-migration

Conversation

@pplupo

@pplupo pplupo commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Wayland support

@pplupo pplupo changed the title Feature/wayland supportt Feature/wayland support Jun 26, 2026
@pplupo
pplupo force-pushed the feature/wayland-migration branch 2 times, most recently from d71937d to fdbd784 Compare July 1, 2026 22:21
Comment thread win-linux/src/components/ctabpanel.cpp Outdated
Comment on lines +116 to +133
@@ -121,6 +126,11 @@ bool CTabPanel::openLocalFile(const std::wstring& path, const std::wstring& para
if ( _format == 0 )
return false;

QString qPath = QString::fromStdWString(path);
if (qPath.endsWith(".sqlite", Qt::CaseInsensitive) || qPath.endsWith(".sqlite3", Qt::CaseInsensitive) || qPath.endsWith(".db", Qt::CaseInsensitive) || qPath.endsWith(".db3", Qt::CaseInsensitive) || qPath.endsWith(".duckdb", Qt::CaseInsensitive) || qPath.endsWith(".parquet", Qt::CaseInsensitive) || qPath.endsWith(".pq", Qt::CaseInsensitive) || qPath.endsWith(".mdb", Qt::CaseInsensitive) || qPath.endsWith(".accdb", Qt::CaseInsensitive)) {
CMessage::warning(this, tr("Warning: Cannot recover constraints, procedures, etc. from database files. Saving won't be possible directly, you will be prompted to Save As."));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this belongs into the "data recovery" PR

Comment thread .docker/desktop-apps.bake.Dockerfile Outdated
libnss3-dev \
libnspr4-dev
libnspr4-dev \
mdbtools-dev

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another data recovery PR leftover

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
@pplupo
pplupo force-pushed the feature/wayland-migration branch from e8eaac0 to 05b92d9 Compare July 3, 2026 21:53
pplupo added 4 commits July 3, 2026 17:55
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Remove redundant QT_ROOT override.

Note: there is still a bug with characters with stress marks, such as ã é ü, etc.
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
qcefview.h now includes QOpenGLWidget for the Wayland OSR presenter, and
this target moc's that header directly, so it needs the OpenGLWidgets
component too or automoc fails with "QOpenGLWidget: No such file".

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
@pplupo
pplupo force-pushed the feature/wayland-migration branch from 6244f13 to 9d4dfe2 Compare July 7, 2026 19:46
pplupo and others added 7 commits July 10, 2026 11:12
mapToGlobal() relies on knowing the widget's absolute screen position,
which Wayland deliberately doesn't expose to clients -- it was
returning a bogus point, and QMenu fell back to centering itself.
QContextMenuEvent's own global position is computed correctly by Qt's
input pipeline at the time the event was generated, so use that
instead of mapping the local position after the fact.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
…on() in this Qt version

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
… position

CMenuWidget is a custom QWidget-based popup using Qt::Tool, which under
Wayland maps to a plain xdg_toplevel with set_parent() -- there's no
positioner data, so the compositor defaults to centering it over its
parent regardless of any move() call, explaining why it rendered dead
center of the main window rather than at the click position (a
previous attempt to fix the position passed to exec() had no effect,
confirming the problem isn't the position value itself).

Add Qt::Popup so this maps to the xdg_popup protocol instead, which
does support anchored positioning. Dismiss-on-outside-click/Escape is
already handled explicitly in this class's own eventFilter
(WindowDeactivate/MouseButtonPress/KeyRelease), so Qt::Popup's
implicit grab/dismiss behavior is redundant with that, not
conflicting.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Qt defines Tool = Popup | Dialog, so the previous "Qt::Tool | Qt::Popup"
change didn't actually change anything -- the Popup bit was already
part of Qt::Tool's value, so the resolved window type was still
exactly Tool (confirmed: menu still centered on the window after that
build). Use Qt::Popup alone so the widget's actual resolved window
type changes, which is what Qt's Wayland QPA plugin needs to map it to
the xdg_popup protocol instead of a plain xdg_toplevel.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Assisted-by: Claude Code:Opus 4.8
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Assisted-by: Claude Code:Opus 4.8
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
pplupo added 3 commits July 22, 2026 23:15
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
getScreenDpiRatio(), getScreenDpiRatioByHWND(), and
getScreenDpiRatioByWidget() each hardcoded a flat 1.0 on Wayland,
reasoning that Qt's automatic HiDPI backing-store scaling makes manual
scaling redundant there. That conflates two different things: Qt's
automatic scaling only controls how many physical pixels render a
given logical (DIP) size -- it doesn't retroactively enlarge a DIP
size an app explicitly computed from a hardcoded constant, e.g.
cplatformdecoration.cpp's CUSTOM_BORDER_WIDTH * dpi_ratio, which sizes
the native window decoration/caption region containing the tab strip.
That manual computation needs a real ratio on Wayland exactly like it
already does on X11, so let all three fall through to the same
QDpiChecker-based path X11 already uses (now Wayland-aware after the
desktop-sdk fix), instead of X11 || Wayland branching.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
CWindowBase's constructor, startRect(), and setScreenScalingFactor(),
plus the setScreenScalingFactor() overrides in CWindowPlatform,
CPresenterWindow, CEditorWindow, and CMainWindow all independently
hardcoded factor/dpi to 1.0 on Wayland before it ever reached
CPlatformDecoration's border sizing or m_boxTitleBtns (title bar/tab
button) sizing -- silently discarding whatever real scale
Utils::getScreenDpiRatio()/getScreenDpiRatioByWidget() computed
(already fixed to be Wayland-aware) and leaving the tab strip sized as
if unscaled regardless of the actual display scale. Same root pattern
as the earlier DPI-checker fix: each of these assumed Qt's own
automatic widget scaling made this redundant on Wayland, but that only
covers backing-store render resolution, not layout sizes computed
explicitly from a hardcoded base constant times a ratio.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
@pplupo
pplupo force-pushed the feature/wayland-migration branch from 62852d3 to b29381b Compare July 23, 2026 03:15
pplupo added 6 commits July 23, 2026 00:24
…gantic Wayland widgets

Native widgets (CWindowBase, CMessage, etc.) call this once at
construction time with no debounce, unlike CEF's UpdateUIScalePercentage()
which now guards against the known startup devicePixelRatio()
transient-misread race. Need to confirm whether choose_scaling() is
snapping such a misread to a too-high standard step for these widgets,
and whether it recurs for widgets constructed well after startup
(on-demand dialogs), which would rule out a pure startup-race
explanation. Remove once the underlying issue is found.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Extends the earlier debug logging to compare QWidget::devicePixelRatio()
against QScreen::devicePixelRatio() for the same widget, to confirm
they diverge on Wayland (screen-level appears stuck at the initial
integer-rounded buffer scale) before relying on that as the basis for
the desktop-sdk fix switching QDpiChecker::GetWidgetDpi() to the
widget-level value. Remove once confirmed.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Qt's Wayland platform plugin disables fractional-scale support and
permanently rounds devicePixelRatio() to the nearest integer for
ordinary widgets (e.g. a real 1.25 scale reads as 2) unless the app
explicitly opts into PassThrough -- confirmed as a known, documented
Qt/Wayland behavior, not a startup timing race as earlier commits in
this area assumed. This is the actual root cause of native widgets
(window decoration, title-bar buttons, dialogs) rendering oversized:
Utils::getScreenDpiRatioByWidget() was correctly reading
devicePixelRatio(), but Qt itself was permanently misreporting it.

Also removes the temporary debug logging added while investigating
this, now that the underlying cause is confirmed.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Even with HighDpiScaleFactorRoundingPolicy::PassThrough set, initial
sizing on Wayland can still be computed from a transiently-wrong
devicePixelRatio() reading -- the same startup compositor round-trip
race already proven for CEF's UI scale, just with no debounce here
since these widgets read the value once, synchronously, at
construction.

Add Utils::WatchForDpiChange(), a reusable helper installing an event
filter for QEvent::DevicePixelRatioChange (fired per-widget whenever
Qt's own notion of that widget's effective ratio changes, for any
reason -- the async correction arriving, or a real later change like
moving to a different-scaled monitor). Wire it into CWindowBase's
constructor to re-run updateScaling() when it fires, covering the main
window and its subclasses (title bar, buttons, tabs).

CMessage (dialogs) is not wired up yet -- its DPI-dependent sizing is
spread inline across its constructor rather than a separate,
re-callable method, so doing the same there needs a small refactor
first rather than being folded into this change.

Also re-adds (and extends, with a timestamp for correlating against
the CEF debug log) the temporary debug logging removed earlier, now
that PassThrough alone didn't fully resolve the issue.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Dead code with no remaining callers; had a stale Wayland hardcode
(return 1.0) inconsistent with the widget-level DPI fix applied
elsewhere.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Investigation is concluded; the underlying fix is confirmed working.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
pplupo added 10 commits July 24, 2026 20:49
QtMsg (CMessage's underlying dialog) read its own devicePixelRatio()
once at construction time, before Qt had received the Wayland
compositor's async fractional-scale answer for the dialog's surface --
the same startup race already fixed for CWindowBase, but this dialog
was never wired into the reactive correction.

Extracts the dpiRatio-dependent sizing into applyScaling(), called
once at construction and again via WatchForDpiChange whenever the
dialog's own devicePixelRatio() settles to its real value.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit 4273100)
QLayout::SetFixedSize locks the dialog's top-level size the first time
it activates. Shrinking a child's minimum width afterwards (the
WatchForDpiChange-triggered re-run, once the real ratio arrives)
doesn't automatically renegotiate an already-mapped Wayland surface
down to the smaller size, leaving the outer window oversized even
though its contents are now correctly scaled. Force the resize
explicitly via layout()->invalidate() + adjustSize().

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit 4dff132)
The app scales native Qt widgets manually (sizes/margins x dpiRatio,
plus a QSS 'scaling' property that bakes the factor into pixel
font-sizes) as a substitute for Qt's automatic HiDPI scaling, which is
deliberately disabled on X11 so devicePixelRatio() stays 1.

On Wayland, HighDpiScaleFactorRoundingPolicy::PassThrough makes Qt's
devicePixelRatio report the true fractional scale and Qt already scales
every widget by it. The manual scaling then applies on top, so a 1.25
display rendered native UI at ~1.56x. This was uniform across the whole
native UI (only visible by comparing a dialog side-by-side with X11,
since a uniform enlargement has no reference).

Make Qt's PassThrough devicePixelRatio the single source of scaling on
Wayland: getScreenDpiRatioByWidget/getScreenDpiRatioByHWND now return a
neutral 1.0 there, so the manual factor is 1.0 and Qt does the scaling
once, crisply, matching X11's physical result.

Since the Wayland factor no longer depends on the late-arriving
devicePixelRatio, the startup race it chased is gone: drop QtMsg's
WatchForDpiChange re-derivation and the forced-resize workaround.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit 3ed1c04)
This reverts commit 3ed1c04.

(cherry picked from commit 2e68c94)
Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Captures platform, widget class, size, widget/screen devicePixelRatio,
and the computed manual scaling factor for every native widget, so the
oversized dialog's numbers can be compared against the correctly-sized
main window on Wayland. To be reverted once diagnosed.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit d99f644)
The dialog computes its scaling factor once from its (stable) parent in
QtMsgPrivateIntf and applies it in the constructor -- which is already
correct (1.25) and matches how X11 styles the dialog exactly once.

The WatchForDpiChange re-derivation added earlier read the dialog's OWN
devicePixelRatio, which on Wayland races 2.0 -> 1.25 as the compositor
answers for the freshly-created surface. That fired applyScaling() with
a transient 2.0 (scaling="2x": double fonts/margins) and then 1.25,
leaving the dialog oversized, with the wrong icon, non-bold and
non-centered text, and a massive height. X11 never sees the race (its
devicePixelRatio never changes, so the watcher never fired) and looked
correct. Drop the watcher and the forced-resize workaround so Wayland
styles once from the parent ratio too.

Also removes the temporary per-widget DPI diagnostic logging.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit e155cbf)
Size (root cause): QtMsg computed its scale from getScreenDpiRatioByWidget
on the DIALOG itself. A freshly-created top-level surface reports the
rounded default devicePixelRatio (2.0) on Wayland until the compositor
answers with the real fractional scale, so the dialog was sized for 2.0
(scaling=2x, everything doubled) and never corrected -- hence 'enormous'.
Derive the ratio from the stable parent window instead (its dpr has long
since settled), via stableDpiRatioForDialog().

Styling: on Wayland the app uses this custom QtMsg (X11 uses the native
GTK dialog); QtMsg was a plain fallback that never matched GTK. Bring it
in line with the GTK message dialog: bold the primary (first) line and
keep following lines regular, centre the text, and recolour the warning
icon from yellow (#f1c40f) to GTK's warning orange (#f57900).

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit b7fab27)
- Enlarge the primary line (bold + ~1.2x the secondary font size), split
  cleanly from the secondary line which stays regular.
- Widen the gap between the primary and secondary lines.
- Enlarge the message icon (35 -> 44) closer to GTK's dialog icon size.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
(cherry picked from commit 768387d)
…lign text

setMinimumWidth was multiplied by dpiRatio (e.g. 1.25), making the dialog
25% wider than the X11/GTK equivalent and forcing text centering to leave a
large dead gap between the icon and the primary line.

Use unscaled logical-pixel values for the minimum width (Qt's layout engine
already handles DPI independently) and change label alignment to AlignLeft so
the text sits flush in its column, matching the GTK message dialog layout.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
Wrap the content row (icon + text) and the buttons row together in a
single bodyWidget. Add it to cLayout with AlignCenter so the whole block
uses its natural width and is centered symmetrically.

Previously the content row filled the entire available width while
m_boxButtons was AlignCenter — so the icon's left edge was at the far
left margin while the buttons started further in, creating an unbalanced
appearance. Now both rows share the same horizontal extent.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
@pplupo
pplupo force-pushed the feature/wayland-migration branch from be06089 to 40e6ede Compare July 31, 2026 03:45
pplupo added 3 commits August 5, 2026 10:07
The HoverLeave handler resetting m_boxTitleBtns to ArrowCursor ran on
every platform. On X11 and Windows it fought the cursor the editor
content had set, so the pointer stopped changing shape entirely --
no I-beam over text, no resize arrows over borders.

The reset exists for Wayland, where cursor inheritance across child
surfaces behaves differently; gate it to that platform.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
QGraphicsDropShadowEffect renders into an off-screen pixmap using its
own QPainter. On Wayland the compositor can trigger an independent
repaint flush while that painter is open, which is the 'paint device
can only be painted by one painter at a time' spew seen when closing an
editor, with QWidgetEffectSourcePrivate::pixmap in the trace.

Wayland compositors draw window shadows themselves, so the Qt software
shadow is redundant there as well as unsafe. isCompositingEnabled()
now reports false on Wayland in the three call sites that create one,
leaving X11 and Windows behaviour untouched.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
The app sizes its custom chrome by multiplying base constants by the
ratio these helpers return, and Qt then renders those logical sizes at
devicePixelRatio physical pixels. Both were being applied: on a
1.25-scaled display the chrome came out at 1.5625x, 25% above the
display scale, while the editor content -- scaled once, by CEF page
zoom off the same devicePixelRatio -- sat correctly at 1.25x. The gap
between the two is what reads as an oversized top bar beside the
document.

Return only the residual, the detected ratio divided by what Qt already
applies, clamped at 1.0. Where Qt's scaling covers the display scale
this is 1.0 and the chrome lands on the display scale; it rises above
1.0 only where the detected ratio genuinely exceeds it.

This is not Wayland-specific. Qt 6 scales on xcb too -- measured
devicePixelRatio 1.25 against Xft.dpi 120 -- because main.cpp disables
scaling through QT_ENABLE_HIGHDPI_SCALING, dropped in Qt 6, and
AA_DisableHighDpiScaling, compiled only for Qt 5. X11 carried the same
compounding, unnoticed because it erred in the same direction as
Wayland. On Windows the disabling does work, devicePixelRatio is 1, and
the division is by 1.

A further benefit is immunity to the Wayland startup race: numerator
and denominator move together, so the residual reads 1.0 both while the
surface reports the rounded 2.0 and after it corrects to 1.25, and the
chrome never needs re-laying-out.

The dpiApp < 0 fallback returned the widget's devicePixelRatio as the
manual factor, which would now compound; its residual is 1.0.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
@pplupo
pplupo force-pushed the feature/wayland-migration branch from 12e3e8b to c3366c6 Compare August 5, 2026 14:08
rikled and others added 7 commits August 6, 2026 14:01
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Assisted-by: Claude Code:Opus 4.8
Following the existing EditorJSVariables convention (same one used for
'os', 'lang', 'theme', etc). JS-side code that currently infers Wayland
OSR mode from the mere presence of window.AscDesktopEditor is wrong to
do so -- that object exists on every desktop platform (X11, Windows),
not just Wayland OSR -- and needs a real, definitive signal instead.
Feeds the upcoming clipboard-bridge and device-scale-correction fixes.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
…properties

The compounding fix (c3366c6) made getScreenDpiRatioByWidget() return
the residual left after Qt's own auto-scaling, correct for the widget
geometry math it was meant for (verified: button sizing matches
X11 exactly). But six call sites also feed that same residual into a
'zoom'/'scaling' widget property that several stylesheets
(editor_unix.qss's #mainPanel[zoom="1.25x"], message.qss's
#messageBody[scaling="1.25x"], etc.) use as a discrete lookup keyed by
the literal display-scale string, picking a pre-computed *physical*
font-size/padding for that exact factor -- not something Qt's
per-widget backing-store scaling touches at all.

Since the residual is typically 1.0 ("1x") once Qt's own scaling
already covers the display, and none of these stylesheets define a
'1x' rule, every match silently failed and fell through to the base,
unscaled styling. Confirmed by screenshot: both the title bar and the
Wayland QtMsg dialog rendered with visibly smaller-than-expected fonts,
identically on X11 and Wayland (both compute the same residual), while
the GTK dialog on X11 -- a completely separate code path this doesn't
touch -- was unaffected.

Add Utils::getDisplayScaleFactor(), returning what
getScreenDpiRatioByWidget() returned before the compounding fix (the
real, un-residual-corrected factor), and use it at all six zoom/scaling
property call sites. Leaves every other use of the residual (widget
geometry) untouched.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
…zoom/scaling QSS properties""

This reverts commit be54463.
The title bar tab labels and the Qt message dialog's body text sat one
pixel smaller than the editor's own text, which reads as the chrome
being undersized next to the ribbon directly below it. web-apps styles
the ribbon tabs with @font-size-medium (12px), so use the same value
for the corresponding chrome text.

This is the 1x/base value, so it scales with everything else: on a
1.25 display it renders at 15 physical px, the same as the ribbon's
12px CSS under CEF's 1.25 page zoom. The per-scale variant blocks are
left alone -- they are selected by the residual factor and already land
on the intended physical sizes.

Signed-off-by: Peter P. Lupo <pplupo@gmail.com>
@pplupo pplupo mentioned this pull request Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants