FreeRDP
Loading...
Searching...
No Matches
SdlRailWindow Class Reference

#include <sdl_rail_window.hpp>

Data Structures

struct  LoopEndActions
 

Public Member Functions

 SdlRailWindow (uint64_t id, const SDL_Rect &rect)
 
 SdlRailWindow (SdlRailWindow &&)=delete
 
 SdlRailWindow (const SdlRailWindow &)=delete
 
SdlRailWindowoperator= (const SdlRailWindow &)=delete
 
SdlRailWindowoperator= (SdlRailWindow &&)=delete
 
uint64_t id () const
 
SDL_WindowID sdlId () const
 
SDL_Window * window () const
 
SDL_Renderer * renderer () const
 
void updateWindowRect (const SDL_Rect &rect)
 
SDL_Rect windowRect () const
 
void setLocalMoveActive (bool active)
 
bool localMoveActive () const
 
bool localMoveSizeChanged () const
 
SDL_Point localMoveServerPos () const
 
void adoptLocalGeometry (const SDL_Rect &rect)
 
void setResizeAnchor (bool right, bool bottom)
 
void markDeleted ()
 
bool isDeleted () const
 
bool geomApplyPending () const
 
void clearGeomApplyPending ()
 
void armLoopEnd ()
 
bool loopEndPending () const
 
void deferMaximize ()
 
void deferSnap (const SDL_Rect &serverRect)
 
void clearLoopEnd ()
 
LoopEndActions takeLoopEnd ()
 
bool takeWmOverride (SDL_Rect &outer)
 
void setVisibilityRects (std::vector< SDL_Rect > rects)
 
void setVisibleOffset (SDL_Point offset)
 
void setMinMaxSize (SDL_Point minSize, SDL_Point maxSize)
 
void setResizeMargins (int left, int top, int right, int bottom)
 
SDL_Rect resizeMargins () const
 
void setFrameMargins (const SDL_Rect &m)
 
SDL_Rect frameMargins () const
 
void setOwner (uint64_t ownerId)
 
uint64_t owner () const
 
bool isPopup () const
 
bool isFullscreen () const
 
bool isLayered () const
 
void setShadowAnchored (bool anchored)
 
void setFrame (bool frame)
 
bool isFrame () const
 
SDL_Rect insets () const
 
SDL_Rect outerRect () const
 
SDL_Point serverOrigin () const
 
SDL_Rect serverRect (const SDL_Rect &outer) const
 
void setStyle (uint32_t style, uint32_t exStyle)
 
void setTitle (const std::string &title)
 
void setVisible (bool visible)
 
void setIcon (const SdlRailIcon &icon)
 
bool takeSurfaceChange (uint32_t surfaceId)
 
void updateGfxSurface (const void *data, uint32_t stride, uint32_t width, uint32_t height, const RECTANGLE_16 *damage, uint32_t nbDamage, uint32_t format)
 
void invalidateAll ()
 
bool railMaximized () const
 
void setRailMaximized (bool m)
 
void setServerMaximized (bool m)
 
bool railMinimized () const
 
void setRailMinimized (bool m)
 
void setServerMinimized (bool m)
 
void markGeometryDirty ()
 
bool geometryFrozen () const
 
bool awaitingRestoreRect () const
 
bool effectivelyMaximized () const
 
bool stateTransitionPending () const
 
bool reconcile (SDL_Window *parent, const SDL_Rect &parentRect)
 
bool paint (SDL_Surface *primary, SDL_PixelFormat fallbackFormat, const std::vector< SDL_Rect > &damage, SDL_Window *parent, const SDL_Rect &parentRect)
 

Detailed Description

A single RemoteApp window, backed by a borderless SDL window.

Geometry is server-authoritative: _windowRect mirrors the server's WINDOW_ORDER offset/size and the local SDL window is moved/resized to follow it.

Definition at line 48 of file sdl_rail_window.hpp.


Data Structure Documentation

◆ SdlRailWindow::LoopEndActions

struct SdlRailWindow::LoopEndActions

Definition at line 95 of file sdl_rail_window.hpp.

Data Fields
bool maximize = false
bool snap = false
SDL_Rect snapRect = { 0, 0, 0, 0 }

Constructor & Destructor Documentation

◆ SdlRailWindow()

SdlRailWindow::SdlRailWindow ( uint64_t  id,
const SDL_Rect &  rect 
)

Definition at line 66 of file sdl_rail_window.cpp.

66 : _id(id), _windowRect(rect)
67{
68}

Member Function Documentation

◆ adoptLocalGeometry()

void SdlRailWindow::adoptLocalGeometry ( const SDL_Rect &  rect)

Definition at line 162 of file sdl_rail_window.cpp.

163{
164 /* Adopt local geometry so the server's echoing WINDOW_ORDER is a no-op (not a size snap). */
165 std::unique_lock lock(_gfxLock);
166 /* A completed local move settles geometry via the completion path, not the reporter. */
167 _geomApplyPending = false;
168 /* Translate visible offset by move delta. */
169 if (_visOffsetSet)
170 {
171 _visOffset.x += rect.x - _windowRect.x;
172 _visOffset.y += rect.y - _windowRect.y;
173 }
174 _windowRect = rect;
175 _geometryDirty = false;
176 /* A resize drag ends here; the server surface still has the pre-drag size. */
177 _awaitingFrameUntil =
178 (_localMoveActive && _localMoveIsResize) ? (SDL_GetTicks() + kAwaitServerFrameMs) : 0;
179 _localMoveActive = false;
180 _needsFullBlit = true;
181 /* Repaint real content (clear placeholder). */
182 if (_hasGfx)
183 _gfxDamage.assign(1, SDL_Rect{ 0, 0, static_cast<int>(_gfxW), static_cast<int>(_gfxH) });
184}

◆ armLoopEnd()

void SdlRailWindow::armLoopEnd ( )

Definition at line 216 of file sdl_rail_window.cpp.

217{
218 std::unique_lock lock(_gfxLock);
219 _loopEnd.pending = true;
220}

◆ awaitingRestoreRect()

bool SdlRailWindow::awaitingRestoreRect ( ) const
inline

Definition at line 192 of file sdl_rail_window.hpp.

193 {
194 std::unique_lock lock(_gfxLock);
195 return restoreRectPending();
196 }

◆ clearGeomApplyPending()

void SdlRailWindow::clearGeomApplyPending ( )

Definition at line 210 of file sdl_rail_window.cpp.

211{
212 std::unique_lock lock(_gfxLock);
213 _geomApplyPending = false;
214}

◆ clearLoopEnd()

void SdlRailWindow::clearLoopEnd ( )

Definition at line 241 of file sdl_rail_window.cpp.

242{
243 std::unique_lock lock(_gfxLock);
244 _loopEnd = {};
245}

◆ deferMaximize()

void SdlRailWindow::deferMaximize ( )

Definition at line 228 of file sdl_rail_window.cpp.

229{
230 std::unique_lock lock(_gfxLock);
231 _loopEnd.maximize = true;
232}

◆ deferSnap()

void SdlRailWindow::deferSnap ( const SDL_Rect &  serverRect)

Definition at line 234 of file sdl_rail_window.cpp.

235{
236 std::unique_lock lock(_gfxLock);
237 _loopEnd.snap = true;
238 _loopEnd.snapRect = serverRect;
239}

◆ effectivelyMaximized()

bool SdlRailWindow::effectivelyMaximized ( ) const

Definition at line 980 of file sdl_rail_window.cpp.

981{
982 return _maxState.rail ||
983 (_win && (SDL_GetWindowFlags(_win->window()) & SDL_WINDOW_MAXIMIZED) != 0);
984}

◆ frameMargins()

SDL_Rect SdlRailWindow::frameMargins ( ) const

Definition at line 319 of file sdl_rail_window.cpp.

320{
321 std::unique_lock lock(_gfxLock);
322 return _frameMargins;
323}

◆ geomApplyPending()

bool SdlRailWindow::geomApplyPending ( ) const

Definition at line 204 of file sdl_rail_window.cpp.

205{
206 std::unique_lock lock(_gfxLock);
207 return _geomApplyPending;
208}

◆ geometryFrozen()

bool SdlRailWindow::geometryFrozen ( ) const
inline

Definition at line 187 of file sdl_rail_window.hpp.

188 {
189 return _maxState.rail || _maxState.server || _minState.rail || _minState.server;
190 }

◆ id()

uint64_t SdlRailWindow::id ( ) const

Definition at line 73 of file sdl_rail_window.cpp.

74{
75 return _id;
76}

◆ insets()

SDL_Rect SdlRailWindow::insets ( ) const

Definition at line 430 of file sdl_rail_window.cpp.

431{
432 std::unique_lock lock(_gfxLock);
433 return _appliedInsets;
434}

◆ invalidateAll()

void SdlRailWindow::invalidateAll ( )

Definition at line 916 of file sdl_rail_window.cpp.

917{
918 std::unique_lock lock(_gfxLock);
919 _needsFullBlit = true;
920 if (_hasGfx)
921 _gfxDamage.assign(1, SDL_Rect{ 0, 0, static_cast<int>(_gfxW), static_cast<int>(_gfxH) });
922}

◆ isDeleted()

bool SdlRailWindow::isDeleted ( ) const

Definition at line 198 of file sdl_rail_window.cpp.

199{
200 std::unique_lock lock(_gfxLock);
201 return _deleted;
202}

◆ isFrame()

bool SdlRailWindow::isFrame ( ) const

Definition at line 367 of file sdl_rail_window.cpp.

368{
369 std::unique_lock lock(_gfxLock);
370 return _frame;
371}

◆ isFullscreen()

bool SdlRailWindow::isFullscreen ( ) const

Definition at line 343 of file sdl_rail_window.cpp.

344{
345 std::unique_lock lock(_gfxLock);
346 return _fullscreen;
347}

◆ isLayered()

bool SdlRailWindow::isLayered ( ) const

Definition at line 349 of file sdl_rail_window.cpp.

350{
351 std::unique_lock lock(_gfxLock);
352 return _layered;
353}

◆ isPopup()

bool SdlRailWindow::isPopup ( ) const

Definition at line 337 of file sdl_rail_window.cpp.

338{
339 std::unique_lock lock(_gfxLock);
340 return _isPopup;
341}

◆ localMoveActive()

bool SdlRailWindow::localMoveActive ( ) const

Definition at line 144 of file sdl_rail_window.cpp.

145{
146 std::unique_lock lock(_gfxLock);
147 return _localMoveActive;
148}

◆ localMoveServerPos()

SDL_Point SdlRailWindow::localMoveServerPos ( ) const

Definition at line 156 of file sdl_rail_window.cpp.

157{
158 std::unique_lock lock(_gfxLock);
159 return _localMoveServerPos;
160}

◆ localMoveSizeChanged()

bool SdlRailWindow::localMoveSizeChanged ( ) const

Definition at line 150 of file sdl_rail_window.cpp.

151{
152 std::unique_lock lock(_gfxLock);
153 return _localMoveSizeChanged;
154}

◆ loopEndPending()

bool SdlRailWindow::loopEndPending ( ) const

Definition at line 222 of file sdl_rail_window.cpp.

223{
224 std::unique_lock lock(_gfxLock);
225 return _loopEnd.pending;
226}

◆ markDeleted()

void SdlRailWindow::markDeleted ( )

Definition at line 192 of file sdl_rail_window.cpp.

193{
194 std::unique_lock lock(_gfxLock);
195 _deleted = true;
196}

◆ markGeometryDirty()

void SdlRailWindow::markGeometryDirty ( )
inline

Definition at line 181 of file sdl_rail_window.hpp.

182 {
183 std::unique_lock lock(_gfxLock);
184 _geometryDirty = true;
185 }

◆ outerRect()

SDL_Rect SdlRailWindow::outerRect ( ) const

Definition at line 437 of file sdl_rail_window.cpp.

438{
439 std::unique_lock lock(_gfxLock);
440 return addInsets(_windowRect, _appliedInsets);
441}

◆ owner()

uint64_t SdlRailWindow::owner ( ) const

Definition at line 331 of file sdl_rail_window.cpp.

332{
333 std::unique_lock lock(_gfxLock);
334 return _ownerId;
335}

◆ paint()

bool SdlRailWindow::paint ( SDL_Surface *  primary,
SDL_PixelFormat  fallbackFormat,
const std::vector< SDL_Rect > &  damage,
SDL_Window *  parent,
const SDL_Rect &  parentRect 
)

Definition at line 986 of file sdl_rail_window.cpp.

989{
990 if (!reconcile(parent, parentRect))
991 return false;
992
993 bool ok = false;
994 {
995 std::unique_lock lock(_gfxLock);
996 if (_hasGfx)
997 {
998 ok = paintGfx(fallbackFormat);
999 }
1000 else
1001 {
1002 lock.unlock();
1003 ok = paintLegacy(primary, damage);
1004 }
1005 }
1006
1007 /* Map in the same pass as the first frame, else the window defers a frame (menu lag). */
1008 if (_gfxPresented && !_mapped && !_minState.rail)
1009 {
1010 _mapped = true;
1011 WLog_DBG(TAG, "map id=0x%08" PRIx32 " %s", static_cast<uint32_t>(_id), role());
1012 SDL_ShowWindow(_win->window());
1013 /* Reassert target position after show to override stale events. */
1014 if (_isPopup && parent)
1015 {
1016 std::unique_lock lock(_gfxLock);
1017 const SDL_Rect vis = targetOuterRect();
1018 SDL_SetWindowPosition(_win->window(), vis.x - parentRect.x, vis.y - parentRect.y);
1019 if (!railPlatformCaps().positionsReadable)
1020 _needsFullBlit = true; /* Wayland applies move on next surface commit */
1021 }
1022 if ((!_isPopup && !_layered) || _fullscreen)
1023 _win->raise(); /* Bring app and fullscreen windows to front. */
1024 }
1025 return ok;
1026}

◆ railMaximized()

bool SdlRailWindow::railMaximized ( ) const
inline

Definition at line 159 of file sdl_rail_window.hpp.

160 {
161 return _maxState.rail;
162 }

◆ railMinimized()

bool SdlRailWindow::railMinimized ( ) const
inline

Definition at line 169 of file sdl_rail_window.hpp.

170 {
171 return _minState.rail;
172 }

◆ reconcile()

bool SdlRailWindow::reconcile ( SDL_Window *  parent,
const SDL_Rect &  parentRect 
)

Definition at line 600 of file sdl_rail_window.cpp.

601{
602 std::unique_lock lock(_gfxLock);
603
604 /* Hidden windows get no local SDL window. Layered windows (e.g. docks) need GFX content and
605 * vis-rects to show; this hides empty DWM snap overlays. */
606 const bool popupReady = !_isPopup || _hasGfx;
607 /* Suppress server shadow frames and unparented full-display overlays. */
608 const bool unplaceable =
609 _frame || (_overlay && !railPlatformCaps().positionsReadable && isFullDisplaySize());
610 /* Layered window is shown only when anchored to an adjoining visible popup or overlay. */
611 const bool drawable =
612 _visible && (_windowRect.w > 0) && (_windowRect.h > 0) && popupReady && !unplaceable &&
613 (!_layered || (_hasGfx && !_visRects.empty() && (_shadowAnchored || _overlay)));
614
615 if (!drawable)
616 {
617 /* Log standalone layered windows suppressed by popup shadow heuristic. */
618 if (_layered && _hasGfx && !_visRects.empty() && !_shadowAnchored && !_overlay &&
619 !_shadowSuppressLogged)
620 {
621 _shadowSuppressLogged = true;
622 WLog_DBG(TAG,
623 "shadow-rule suppressed id=0x%08" PRIx32 " %dx%d style=0x%08" PRIx32
624 " ex=0x%08" PRIx32,
625 static_cast<uint32_t>(_id), _windowRect.w, _windowRect.h, _style, _exStyle);
626 }
627 if (_win)
628 {
629 if ((SDL_GetWindowFlags(_win->window()) & SDL_WINDOW_HIDDEN) == 0)
630 {
631 WLog_DBG(TAG, "hide id=0x%08" PRIx32 " %s", static_cast<uint32_t>(_id), role());
632 SDL_HideWindow(_win->window());
633 }
634 _mapped = false;
635 }
636 if (_isPopup && !_visible)
637 {
638 _gfxPresented = false;
639 _hasGfx = false;
640 }
641 return false;
642 }
643
644 if (!_win)
645 {
646 if (!create(parent, parentRect))
647 return false;
648 _geometryDirty = false;
649 /* Shown + raised in paint() after the first frame (created hidden). */
650 }
651
652 /* create() returned false on failure, so _win is non-null from here down. */
653 if (_topmostDirty)
654 {
655 _topmostDirty = false;
656 /* X11 only; Wayland has no protocol for this, the call still returns true. */
657 if (!_isPopup && !_layered)
658 std::ignore = SDL_SetWindowAlwaysOnTop(_win->window(), _topmost);
659 }
660
661 /* Resizability first: SDL refuses to maximize a non-resizable window. */
662 if (_styleDirty)
663 {
664 _win->resizeable(styleResizable());
665 _styleDirty = false;
666 /* Insets refresh on geometry updates to avoid flicker. */
667 }
668
669 /* State first: maximized/minimized gates the geometry apply below. */
670 /* Hold geometry sync until server sends restored rect to prevent re-maximizing. */
671 if (applyServerState(_maxState, "maximize", SDL_MaximizeWindow))
672 _awaitRestoreUntil = SDL_GetTicks() + kAwaitRestoreRectMs;
673 std::ignore = applyServerState(_minState, "minimize", SDL_MinimizeWindow);
674 const bool restorePending = restoreRectPending();
675
676 /* Update insets across maximize transitions outside active drag grab. */
677 const bool maxed = effectivelyMaximized();
678 if ((maxed != _wasMaximized) && !_localMoveActive && !restorePending)
679 {
680 _appliedInsets = bandInsets();
681 if (!maxed)
682 _geometryDirty = true;
683 _wasMaximized = maxed;
684 }
685
686 /* _GTK_FRAME_EXTENTS: tell the WM the band ring is frame, not content (snap/tile geometry). */
687 const SDL_Rect ext = bandInsets();
688 if (!SDL_RectsEqual(&ext, &_extentsApplied) &&
689 sdl_x11_set_frame_extents(_win->window(), ext.x, ext.w, ext.y, ext.h))
690 _extentsApplied = ext;
691
692 /* Clamp min size hints to target bounds so stale hints do not block programmatic resize.
693 * Defer size hints and programmatic resize during active WM move/resize grab. */
694 const bool wmOwnsGeometry =
695 _localMoveActive || geometryFrozen() || _fullscreen || restorePending;
696 if ((_minMaxDirty || _geometryDirty) && !wmOwnsGeometry)
697 {
698 const SDL_Rect vis = targetOuterRect();
699 SDL_SetWindowMinimumSize(_win->window(), std::clamp(_minSize.x, 0, vis.w),
700 std::clamp(_minSize.y, 0, vis.h));
701 int maxW = (_maxSize.x > 0) ? std::max(1, _maxSize.x) : 0;
702 int maxH = (_maxSize.y > 0) ? std::max(1, _maxSize.y) : 0;
703 /* Wayland: cap to the usable area - an oversized window cannot be dragged into reach. */
704 SDL_Rect usable{};
705 if (!railPlatformCaps().positionsReadable &&
706 SDL_GetDisplayUsableBounds(SDL_GetPrimaryDisplay(), &usable))
707 {
708 /* The local window is the outer frame: cap to the usable area plus the insets. */
709 const SDL_Rect bi = bandInsets();
710 const int capW = usable.w + bi.x + bi.w;
711 const int capH = usable.h + bi.y + bi.h;
712 if ((maxW == 0) || (maxW > capW))
713 maxW = capW;
714 if ((maxH == 0) || (maxH > capH))
715 maxH = capH;
716 }
717 SDL_SetWindowMaximumSize(_win->window(), maxW, maxH);
718 _minMaxDirty = false;
719 }
720
721 /* Skip geometry apply when maximized, minimized or WM-dragged. */
722 if (_geometryDirty && !wmOwnsGeometry)
723 {
724 const SDL_Rect vis = targetOuterRect();
725 /* The window is (or becomes) vis = _windowRect + fresh insets: record those as the insets
726 * now baked in, so the round-trip back to server coords strips exactly this. */
727 _appliedInsets = bandInsets();
728 int cw = 0;
729 int ch = 0;
730 SDL_GetWindowSize(_win->window(), &cw, &ch);
731 bool applied = false;
732 /* Apply position and size if changed. */
733 if (_isPopup && parent)
734 {
735 if (!SDL_SetWindowPosition(_win->window(), vis.x - parentRect.x, vis.y - parentRect.y))
736 WLog_VRB(TAG, "popup reposition unsupported id=0x%08" PRIx32 ": %s",
737 static_cast<uint32_t>(_id), SDL_GetError());
738 else if (!railPlatformCaps().positionsReadable)
739 _needsFullBlit = true; /* Wayland applies move on next surface commit */
740 applied = true;
741 }
742 else if (railPlatformCaps().positionsReadable &&
743 !(_isPopup && SDL_GetWindowParent(_win->window())))
744 {
745 int cx = 0;
746 int cy = 0;
747 SDL_GetWindowPosition(_win->window(), &cx, &cy);
748 if ((cx != vis.x) || (cy != vis.y))
749 {
750 SDL_SetWindowPosition(_win->window(), vis.x, vis.y);
751 applied = true;
752 }
753 }
754 if ((cw != vis.w) || (ch != vis.h))
755 {
756 std::ignore = _win->resize({ vis.w, vis.h });
757 applied = true;
758 /* Settle window resize via SDL_SyncWindow before reading back geometry to avoid
759 * adopting transient dimensions while configure events are in flight. */
760 if (railPlatformCaps().positionsReadable && !_isPopup && !_localMoveActive &&
761 !_loopEnd.pending)
762 {
763 const bool settled = SDL_SyncWindow(_win->window());
764 int aw = 0;
765 int ah = 0;
766 SDL_GetWindowSize(_win->window(), &aw, &ah);
767 if (settled && ((aw != vis.w) || (ah != vis.h)))
768 {
769 /* Adopt WM size while preserving server origin. */
770 _wmRefusedOuter = { vis.x, vis.y, aw, ah };
771 _wmRefused = true;
772 applied = false; /* Geometry refused by WM; do not await echo. */
773 }
774 }
775 }
776 _geometryDirty = false;
777 /* Echo filtering is only tracked for top-level app windows. */
778 _geomApplyPending = applied && !_isPopup;
779 }
780 /* Make dialog transient for owner. */
781 if (!_isPopup && parent && !_parentApplied)
782 {
783 if (SDL_SetWindowParent(_win->window(), parent))
784 _parentApplied = true;
785 }
786 if (_titleDirty)
787 {
788 if (!_isPopup)
789 SDL_SetWindowTitle(_win->window(), _title.c_str());
790 _titleDirty = false;
791 }
792 if (_iconDirty)
793 {
794 if (!_isPopup && !_icon.bgra.empty())
795 {
796 SDL_Surface* s = SDL_CreateSurfaceFrom(
797 static_cast<int>(_icon.w), static_cast<int>(_icon.h), SDL_PIXELFORMAT_BGRA32,
798 _icon.bgra.data(), static_cast<int>(_icon.w * 4));
799 if (s)
800 {
801 if (!SDL_SetWindowIcon(_win->window(), s))
802 WLog_WARN(TAG, "SDL_SetWindowIcon failed for window 0x%08" PRIx32 ": %s",
803 static_cast<uint32_t>(_id), SDL_GetError());
804 SDL_DestroySurface(s);
805 }
806 }
807 _iconDirty = false;
808 }
809
810 /* Defer show until first frame; this runs every reconcile, so skip the call once visible. */
811 if (!_minState.rail && _gfxPresented &&
812 (SDL_GetWindowFlags(_win->window()) & SDL_WINDOW_HIDDEN))
813 {
814 /* If transient-for owner was closed or hidden, show dialog standalone. */
815 SDL_Window* owner = _isPopup ? nullptr : SDL_GetWindowParent(_win->window());
816 if (owner && ((SDL_GetWindowFlags(owner) & SDL_WINDOW_HIDDEN) != 0))
817 std::ignore = SDL_SetWindowParent(_win->window(), nullptr);
818 SDL_ShowWindow(_win->window());
819 }
820 return true;
821}

◆ renderer()

SDL_Renderer * SdlRailWindow::renderer ( ) const

Definition at line 88 of file sdl_rail_window.cpp.

89{
90 return _win ? _win->renderer() : nullptr;
91}

◆ resizeMargins()

SDL_Rect SdlRailWindow::resizeMargins ( ) const

Definition at line 307 of file sdl_rail_window.cpp.

308{
309 std::unique_lock lock(_gfxLock);
310 return _resizeMargins;
311}

◆ sdlId()

SDL_WindowID SdlRailWindow::sdlId ( ) const

Definition at line 78 of file sdl_rail_window.cpp.

79{
80 return _win ? _win->id() : 0;
81}

◆ serverOrigin()

SDL_Point SdlRailWindow::serverOrigin ( ) const

Definition at line 467 of file sdl_rail_window.cpp.

468{
469 std::unique_lock lock(_gfxLock);
470 /* Derive server coordinate from blit offset to match on-screen pixels. */
471 const SDL_Point dst = blitOffset();
472 return { _windowRect.x - dst.x, _windowRect.y - dst.y };
473}

◆ serverRect()

SDL_Rect SdlRailWindow::serverRect ( const SDL_Rect &  outer) const

Definition at line 443 of file sdl_rail_window.cpp.

444{
445 return stripInsets(outer, insets());
446}

◆ setFrame()

void SdlRailWindow::setFrame ( bool  frame)

Definition at line 361 of file sdl_rail_window.cpp.

362{
363 std::unique_lock lock(_gfxLock);
364 _frame = frame;
365}

◆ setFrameMargins()

void SdlRailWindow::setFrameMargins ( const SDL_Rect &  m)

Definition at line 313 of file sdl_rail_window.cpp.

314{
315 std::unique_lock lock(_gfxLock);
316 _frameMargins = m;
317}

◆ setIcon()

void SdlRailWindow::setIcon ( const SdlRailIcon icon)

Definition at line 529 of file sdl_rail_window.cpp.

530{
531 std::unique_lock lock(_gfxLock);
532 _icon = icon;
533 _iconDirty = true;
534}

◆ setLocalMoveActive()

void SdlRailWindow::setLocalMoveActive ( bool  active)

Definition at line 125 of file sdl_rail_window.cpp.

126{
127 std::unique_lock lock(_gfxLock);
128 _localMoveActive = active;
129 if (active)
130 {
131 _localMoveIsResize = false; /* default to move; setResizeAnchor marks a resize */
132 _localMoveSizeChanged = false;
133 }
134}

◆ setMinMaxSize()

void SdlRailWindow::setMinMaxSize ( SDL_Point  minSize,
SDL_Point  maxSize 
)

Definition at line 285 of file sdl_rail_window.cpp.

286{
287 std::unique_lock lock(_gfxLock);
288 _minSize = { std::max(0, minSize.x), std::max(0, minSize.y) };
289 _maxSize = { std::max(0, maxSize.x), std::max(0, maxSize.y) };
290 _minMaxDirty = true;
291 /* Re-apply geometry on min/max change. */
292 _geometryDirty = true;
293}

◆ setOwner()

void SdlRailWindow::setOwner ( uint64_t  ownerId)

Definition at line 325 of file sdl_rail_window.cpp.

326{
327 std::unique_lock lock(_gfxLock);
328 _ownerId = ownerId;
329}

◆ setRailMaximized()

void SdlRailWindow::setRailMaximized ( bool  m)
inline

Definition at line 163 of file sdl_rail_window.hpp.

164 {
165 std::unique_lock lock(_gfxLock);
166 _maxState.rail = m;
167 }

◆ setRailMinimized()

void SdlRailWindow::setRailMinimized ( bool  m)
inline

Definition at line 173 of file sdl_rail_window.hpp.

174 {
175 std::unique_lock lock(_gfxLock);
176 _minState.rail = m;
177 }

◆ setResizeAnchor()

void SdlRailWindow::setResizeAnchor ( bool  right,
bool  bottom 
)

Definition at line 136 of file sdl_rail_window.cpp.

137{
138 std::unique_lock lock(_gfxLock);
139 _resizeAnchorRight = right;
140 _resizeAnchorBottom = bottom;
141 _localMoveIsResize = true;
142}

◆ setResizeMargins()

void SdlRailWindow::setResizeMargins ( int  left,
int  top,
int  right,
int  bottom 
)

Definition at line 295 of file sdl_rail_window.cpp.

296{
297 std::unique_lock lock(_gfxLock);
298 const SDL_Rect m = { left, top, right, bottom };
299 if (SDL_RectsEqual(&m, &_resizeMargins))
300 return;
301 _resizeMargins = m;
302 /* Margins usually arrive after the first frame; the window must regrow to cover them. */
303 if (!railMaximized())
304 _geometryDirty = true;
305}

◆ setServerMaximized()

void SdlRailWindow::setServerMaximized ( bool  m)

Definition at line 934 of file sdl_rail_window.cpp.

935{
936 setServerState(_maxState, m);
937}

◆ setServerMinimized()

void SdlRailWindow::setServerMinimized ( bool  m)

Definition at line 939 of file sdl_rail_window.cpp.

940{
941 setServerState(_minState, m);
942}

◆ setShadowAnchored()

void SdlRailWindow::setShadowAnchored ( bool  anchored)

Definition at line 355 of file sdl_rail_window.cpp.

356{
357 std::unique_lock lock(_gfxLock);
358 _shadowAnchored = anchored;
359}

◆ setStyle()

void SdlRailWindow::setStyle ( uint32_t  style,
uint32_t  exStyle 
)

Definition at line 475 of file sdl_rail_window.cpp.

476{
477 std::unique_lock lock(_gfxLock);
478 const bool wasResizable = styleResizable();
479 const bool wasTopmost = _topmost;
480 _style = style;
481 _exStyle = exStyle;
482 _topmost = (exStyle & WS_EX_TOPMOST) != 0;
483 if (_topmost != wasTopmost)
484 _topmostDirty = true;
485 if ((style & (WS_THICKFRAME | WS_MAXIMIZEBOX)) != 0)
486 _everResizable = true;
487 /* Update resizability on style change. */
488 if (styleResizable() != wasResizable)
489 _styleDirty = true;
490 /* Classify popup and layered window types once on creation. */
491 if (!_popupClassified)
492 {
493 /* WS_CAPTION is WS_BORDER | WS_DLGFRAME; partial match is only a border. */
494 const bool captioned = (style & WS_CAPTION) == WS_CAPTION;
495 const bool isDialogOrApp =
496 captioned ||
497 ((style & (WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) != 0) ||
498 ((exStyle & WS_EX_APPWINDOW) != 0);
499 const bool isToolOrPopup =
500 ((exStyle & (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW)) != 0) || ((style & WS_POPUP) != 0);
501 /* Non-activating windows are popups regardless of app style bits. */
502 const bool noActivate =
503 ((exStyle & WS_EX_NOACTIVATE) != 0) && ((exStyle & WS_EX_APPWINDOW) == 0);
504 /* Route drag/feedback overlays through the popup path. */
505 constexpr uint32_t overlayEx = WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
506 const bool overlay = ((exStyle & overlayEx) == overlayEx) &&
507 ((exStyle & (WS_EX_NOACTIVATE | WS_EX_APPWINDOW)) == 0) && !captioned;
508 _overlay = overlay;
509 _isPopup = noActivate || overlay || (isToolOrPopup && !isDialogOrApp);
510 _layered = ((exStyle & WS_EX_LAYERED) != 0) && !isDialogOrApp;
511 _clickThrough = ((exStyle & WS_EX_TRANSPARENT) != 0);
512 _popupClassified = true;
513 }
514}

◆ setTitle()

void SdlRailWindow::setTitle ( const std::string &  title)

Definition at line 516 of file sdl_rail_window.cpp.

517{
518 std::unique_lock lock(_gfxLock);
519 _title = title;
520 _titleDirty = true;
521}

◆ setVisibilityRects()

void SdlRailWindow::setVisibilityRects ( std::vector< SDL_Rect >  rects)

Definition at line 265 of file sdl_rail_window.cpp.

266{
267 std::unique_lock lock(_gfxLock);
268 _visRects = std::move(rects);
269 _visDirty = true;
270}

◆ setVisible()

void SdlRailWindow::setVisible ( bool  visible)

Definition at line 523 of file sdl_rail_window.cpp.

524{
525 std::unique_lock lock(_gfxLock);
526 _visible = visible;
527}

◆ setVisibleOffset()

void SdlRailWindow::setVisibleOffset ( SDL_Point  offset)

Definition at line 272 of file sdl_rail_window.cpp.

273{
274 std::unique_lock lock(_gfxLock);
275 /* Freeze visible offset during local move. */
276 if (_localMoveActive)
277 return;
278 if (_visOffsetSet && (offset.x == _visOffset.x) && (offset.y == _visOffset.y))
279 return;
280 _visOffset = offset;
281 _visOffsetSet = true;
282 _visDirty = true;
283}

◆ stateTransitionPending()

bool SdlRailWindow::stateTransitionPending ( ) const
inline

Definition at line 200 of file sdl_rail_window.hpp.

201 {
202 /* _maxState/_minState are written under _gfxLock on the RDP thread. */
203 std::unique_lock lock(_gfxLock);
204 return _maxState.dirty || _minState.dirty || (_maxState.rail != _maxState.server) ||
205 (_minState.rail != _minState.server);
206 }

◆ takeLoopEnd()

SdlRailWindow::LoopEndActions SdlRailWindow::takeLoopEnd ( )

Definition at line 247 of file sdl_rail_window.cpp.

248{
249 std::unique_lock lock(_gfxLock);
250 const LoopEndActions actions{ _loopEnd.maximize, _loopEnd.snap, _loopEnd.snapRect };
251 _loopEnd = {};
252 return actions;
253}

◆ takeSurfaceChange()

bool SdlRailWindow::takeSurfaceChange ( uint32_t  surfaceId)

Definition at line 823 of file sdl_rail_window.cpp.

824{
825 std::unique_lock lock(_gfxLock);
826 if (_surfaceId == surfaceId)
827 return false;
828 _surfaceId = surfaceId;
829 return true;
830}

◆ takeWmOverride()

bool SdlRailWindow::takeWmOverride ( SDL_Rect &  outer)

Definition at line 255 of file sdl_rail_window.cpp.

256{
257 std::unique_lock lock(_gfxLock);
258 if (!_wmRefused)
259 return false;
260 outer = _wmRefusedOuter;
261 _wmRefused = false;
262 return true;
263}

◆ updateGfxSurface()

void SdlRailWindow::updateGfxSurface ( const void *  data,
uint32_t  stride,
uint32_t  width,
uint32_t  height,
const RECTANGLE_16 damage,
uint32_t  nbDamage,
uint32_t  format 
)

Definition at line 832 of file sdl_rail_window.cpp.

835{
836 std::unique_lock lock(_gfxLock);
837 /* The copies below are byte-for-byte; gdi_CreateSurface yields nothing else. */
838 WINPR_ASSERT((format == PIXEL_FORMAT_BGRA32) || (format == PIXEL_FORMAT_BGRX32));
839 /* Deep-copy GDI pixels to prevent UAF. */
840 const size_t bytes = static_cast<size_t>(stride) * height;
841 if (!data || (bytes == 0) || (width == 0) || (height == 0))
842 {
843 if (_hasGfx)
844 WLog_DBG(TAG, "gfx cleared id=0x%08" PRIx32 " (surface unmapped)",
845 static_cast<uint32_t>(_id));
846 _gfxBuffer.clear();
847 _hasGfx = false;
848 _gfxDamage.clear();
849 _gfxStride = stride;
850 _gfxW = width;
851 _gfxH = height;
852 _gfxVisOrigin = { 0, 0 };
853 return;
854 }
855
856 const auto* src = static_cast<const uint8_t*>(data);
857 /* Geometry/stride change, first frame, or no damage rects: full copy + repaint. */
858 const bool full = !_hasGfx || (_gfxBuffer.size() != bytes) || (_gfxStride != stride) ||
859 (_gfxW != width) || (_gfxH != height) || (nbDamage == 0);
860 if (full)
861 {
862 const SDL_Rect bounds{ 0, 0, static_cast<int>(width), static_cast<int>(height) };
863 /* Check _hasGfx first to avoid redundant full-surface blank checks once content exists. */
864 if (!_hasGfx && regionIsBlank(src, stride, bounds))
865 return;
866 _gfxBuffer.assign(src, src + bytes);
867 _gfxDamage.assign(1, SDL_Rect{ 0, 0, static_cast<int>(width), static_cast<int>(height) });
868 _needsFullBlit = true;
869 /* Blend real alpha, force opaque otherwise. */
870 _gfxHasAlpha = honorsAlpha() &&
871 regionHasAlpha(_gfxBuffer.data(), stride,
872 { 0, 0, static_cast<int>(width), static_cast<int>(height) });
873 }
874 else
875 {
876 const SDL_Rect bounds{ 0, 0, static_cast<int>(width), static_cast<int>(height) };
877 for (uint32_t i = 0; i < nbDamage; i++)
878 {
879 const SDL_Rect r{ damage[i].left, damage[i].top, damage[i].right - damage[i].left,
880 damage[i].bottom - damage[i].top };
881 SDL_Rect clip{};
882 if (!SDL_GetRectIntersection(&r, &bounds, &clip))
883 continue;
884 std::ignore = freerdp_image_copy_no_overlap(
885 _gfxBuffer.data(), PIXEL_FORMAT_BGRA32, stride, static_cast<UINT32>(clip.x),
886 static_cast<UINT32>(clip.y), static_cast<UINT32>(clip.w),
887 static_cast<UINT32>(clip.h), src, PIXEL_FORMAT_BGRA32, stride,
888 static_cast<UINT32>(clip.x), static_cast<UINT32>(clip.y), nullptr,
889 FREERDP_FLIP_NONE);
890 _gfxDamage.push_back(clip);
891 /* Alpha may first appear in a later incremental frame (e.g. a menu fading in). */
892 if (honorsAlpha() && !_gfxHasAlpha && regionHasAlpha(_gfxBuffer.data(), stride, clip))
893 _gfxHasAlpha = true;
894 }
895 /* A hidden window accumulates rects without ever painting; collapse to one full repaint. */
896 if (_gfxDamage.size() > 32)
897 _gfxDamage.assign(1,
898 SDL_Rect{ 0, 0, static_cast<int>(width), static_cast<int>(height) });
899 }
900 if ((_gfxW != width) || (_gfxH != height))
901 {
902 _resizeAnchorRight = false;
903 _resizeAnchorBottom = false;
904 _needsFullBlit = true;
905 /* Invalidate surface origin until visibility rect matching new dimensions arrives. */
906 _gfxVisOrigin = { 0, 0 };
907 }
908 _hasGfx = true;
909 _gfxStride = stride;
910 _gfxW = width;
911 _gfxH = height;
912 WLog_VRB(TAG, "gfx id=0x%08" PRIx32 " %ux%u full=%d nDamage=%u", static_cast<uint32_t>(_id),
913 width, height, full ? 1 : 0, nbDamage);
914}

◆ updateWindowRect()

void SdlRailWindow::updateWindowRect ( const SDL_Rect &  rect)

Definition at line 93 of file sdl_rail_window.cpp.

94{
95 std::unique_lock lock(_gfxLock);
96 _awaitRestoreUntil = 0; /* Server geometry received. */
97 if (_localMoveActive)
98 {
99 /* Adopt server size change during local move. */
100 if (!_localMoveIsResize && ((rect.w != _windowRect.w) || (rect.h != _windowRect.h)))
101 {
102 WLog_DBG(TAG, "size adopted mid-move id=0x%08" PRIx32 " %dx%d -> %dx%d at %d,%d",
103 static_cast<uint32_t>(_id), _windowRect.w, _windowRect.h, rect.w, rect.h,
104 rect.x, rect.y);
105 _windowRect.w = rect.w;
106 _windowRect.h = rect.h;
107 /* Record server re-anchor position. */
108 _localMoveServerPos = { rect.x, rect.y };
109 _localMoveSizeChanged = true;
110 _painted = false;
111 }
112 return;
113 }
114 /* Accept post-move geometry echoes. */
115 if (SDL_RectsEqual(&rect, &_windowRect))
116 return;
117 /* A resize recreates the render target, so the content needs a full re-copy. */
118 if ((rect.w != _windowRect.w) || (rect.h != _windowRect.h))
119 _painted = false;
120 _windowRect = rect;
121 /* Mark dirty even if frozen/maximized so pending restore rect applies upon unfreeze. */
122 _geometryDirty = true;
123}

◆ window()

SDL_Window * SdlRailWindow::window ( ) const

Definition at line 83 of file sdl_rail_window.cpp.

84{
85 return _win ? _win->window() : nullptr;
86}

◆ windowRect()

SDL_Rect SdlRailWindow::windowRect ( ) const

Definition at line 186 of file sdl_rail_window.cpp.

187{
188 std::unique_lock lock(_gfxLock);
189 return _windowRect;
190}

The documentation for this class was generated from the following files: