Internal
Public Access
The RDP session pipeline never accounted for display scale: it
requested a desktop canvas sized in Qt logical pixels (never
multiplied by devicePixelRatio()), and FreeRDP_DesktopScaleFactor/
DeviceScaleFactor were read but never actually set anywhere. On a
HiDPI monitor this meant the remote session rendered assuming a
96 DPI / 100% display, and the resulting canvas got stretched
locally — ClearType's subpixel hinting doesn't survive that kind of
resampling, producing distorted glyph shapes and color fringing
rather than plain blur.
RdpDisplayWidget now reports physical pixel dimensions and the real
devicePixelRatio (recomputed on resize and on screen changes, e.g.
dragging the window to a different-DPI monitor). RdpSessionBackend
maps that to the nearest FreeRDP-legal scale value ({100, 140, 180},
per MS-RDPEDISP and FreeRDP's own reference client) and sets it at
both connect time and on every dynamic resize, including the
FreeRDP_MonitorOverrideFlags required for the values to actually be
honored rather than silently ignored.
While testing this against real infrastructure, found and fixed two
related (pre-existing, not caused by this change) resize issues:
- A stale-frame race where the old frame could be drawn at the wrong
scale for a moment after a resize, before a correctly-sized one
arrives — now the frame is cleared during that transition instead.
- No debounce on outgoing resize requests — every single resize event
fired an immediate request to the server, which can visibly
contribute to host-side redraw glitches during rapid layout churn
(e.g. right after connecting). Coalesced into one request per burst,
plus an explicit refresh-rect request after each resize completes
as a best-effort nudge for hosts that don't fully repaint on their
own.
A separate, deeper issue was also found during testing (the remote
guest's actual resolution sometimes not changing despite the resize
channel reporting success) and is tracked separately, not fixed here.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
71 lines
1.9 KiB
C++
71 lines
1.9 KiB
C++
#ifndef ORBITHUB_RDP_DISPLAY_WIDGET_H
|
|
#define ORBITHUB_RDP_DISPLAY_WIDGET_H
|
|
|
|
#include <QImage>
|
|
#include <QWidget>
|
|
|
|
class QKeyEvent;
|
|
class QMouseEvent;
|
|
class QPaintEvent;
|
|
class QResizeEvent;
|
|
class QTimer;
|
|
class QWheelEvent;
|
|
|
|
class RdpDisplayWidget : public QWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit RdpDisplayWidget(QWidget* parent = nullptr);
|
|
|
|
void setFrame(const QImage& frame);
|
|
void setRemoteDesktopSize(int width, int height);
|
|
void clearFrame();
|
|
void setCursorImage(const QImage& image, const QPoint& hotspot);
|
|
void setCursorHidden();
|
|
void setCursorDefault();
|
|
|
|
signals:
|
|
void keyInput(int key, quint32 nativeScanCode, const QString& text, bool pressed, int modifiers);
|
|
void mouseMoveInput(int x, int y);
|
|
void mouseButtonInput(int x, int y, int button, bool pressed);
|
|
void mouseWheelInput(int x, int y, int deltaX, int deltaY);
|
|
void viewportSizeChanged(int width, int height);
|
|
void displayScaleChanged(qreal devicePixelRatio);
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent* event) override;
|
|
void resizeEvent(QResizeEvent* event) override;
|
|
bool event(QEvent* event) override;
|
|
void keyPressEvent(QKeyEvent* event) override;
|
|
void keyReleaseEvent(QKeyEvent* event) override;
|
|
void mousePressEvent(QMouseEvent* event) override;
|
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
|
void mouseMoveEvent(QMouseEvent* event) override;
|
|
void wheelEvent(QWheelEvent* event) override;
|
|
bool focusNextPrevChild(bool next) override;
|
|
|
|
private:
|
|
enum class CursorMode {
|
|
Default,
|
|
Custom,
|
|
Hidden,
|
|
};
|
|
|
|
QImage m_frame;
|
|
QSize m_remoteSize;
|
|
QImage m_cursorImage;
|
|
QPoint m_cursorHotspot;
|
|
CursorMode m_cursorMode;
|
|
QTimer* m_resizeDebounceTimer;
|
|
|
|
QRectF renderRect() const;
|
|
QPoint mapToRemote(const QPointF& pos) const;
|
|
QSize effectiveRemoteSize() const;
|
|
void applyCursor();
|
|
void emitViewportGeometry();
|
|
void scheduleViewportGeometryEmit();
|
|
};
|
|
|
|
#endif
|