Skip to content

Commit f4a1987

Browse files
committed
Improve Windows maximize handling: track bounds and prevent concurrent operations
1 parent cbf131a commit f4a1987

File tree

1 file changed

+138
-46
lines changed

1 file changed

+138
-46
lines changed

lib/manager/window_manager.dart

Lines changed: 138 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,11 @@ class WindowHeader extends StatefulWidget {
148148
class _WindowHeaderState extends State<WindowHeader> {
149149
final isMaximizedNotifier = ValueNotifier<bool>(false);
150150
final isPinNotifier = ValueNotifier<bool>(false);
151-
bool _manualMaximized = false; // Track manual maximized state on Windows
151+
bool _windowsBoundsMaximized =
152+
false; // Track Windows-specific bounds-based maximize state
152153
Rect? _savedBounds; // Save window bounds before maximizing
154+
bool _isUpdatingMaximized =
155+
false; // Prevent concurrent maximize/unmaximize operations
153156

154157
@override
155158
void initState() {
@@ -170,53 +173,142 @@ class _WindowHeaderState extends State<WindowHeader> {
170173
}
171174

172175
Future<void> _updateMaximized() async {
173-
final isMaximized = system.isWindows
174-
? _manualMaximized
175-
: await windowManager.isMaximized();
176-
177-
if (isMaximized) {
178-
// Unmaximize and restore previous size
179-
if (system.isWindows && _savedBounds != null) {
180-
// Restore saved window bounds on Windows
181-
await windowManager.setBounds(_savedBounds!);
182-
_savedBounds = null;
183-
} else {
184-
await windowManager.unmaximize();
185-
}
186-
_manualMaximized = false;
187-
isMaximizedNotifier.value = false;
188-
} else {
189-
// Maximize window
190-
if (system.isWindows) {
191-
// Save current window bounds
192-
final currentPosition = await windowManager.getPosition();
193-
final currentSize = await windowManager.getSize();
194-
_savedBounds = Rect.fromLTWH(
195-
currentPosition.dx,
196-
currentPosition.dy,
197-
currentSize.width,
198-
currentSize.height,
199-
);
200-
201-
// On Windows, manually set to work area size (excluding taskbar)
202-
final display = await screenRetriever.getPrimaryDisplay();
203-
final visiblePosition = display.visiblePosition ?? Offset.zero;
204-
final visibleSize = display.visibleSize ?? display.size;
205-
206-
await windowManager.setBounds(
207-
Rect.fromLTWH(
208-
visiblePosition.dx,
209-
visiblePosition.dy,
210-
visibleSize.width,
211-
visibleSize.height,
212-
),
213-
);
214-
_manualMaximized = true;
215-
isMaximizedNotifier.value = true;
176+
// Prevent concurrent execution to avoid race conditions
177+
if (_isUpdatingMaximized) return;
178+
_isUpdatingMaximized = true;
179+
180+
try {
181+
final isMaximized = system.isWindows
182+
? _windowsBoundsMaximized
183+
: await windowManager.isMaximized();
184+
185+
if (isMaximized) {
186+
// Unmaximize and restore previous size
187+
if (system.isWindows) {
188+
if (_savedBounds != null) {
189+
// Restore saved window bounds if we have them
190+
try {
191+
await windowManager.setBounds(_savedBounds!);
192+
// Only clear saved bounds after successful restoration
193+
_savedBounds = null;
194+
} catch (e) {
195+
// If restoration fails, keep saved bounds and try unmaximize
196+
commonPrint.log('Failed to restore saved bounds: $e');
197+
await windowManager.unmaximize();
198+
}
199+
} else {
200+
// Window was maximized externally (e.g., Win+Up, drag to edge)
201+
// Use system unmaximize, then verify the actual state
202+
await windowManager.unmaximize();
203+
final actuallyMaximized = await windowManager.isMaximized();
204+
if (actuallyMaximized) {
205+
// If still maximized, window might be in snap state
206+
// Restore to a default reasonable size
207+
try {
208+
final display = await screenRetriever.getPrimaryDisplay();
209+
final visibleSize = display.visibleSize ?? display.size;
210+
211+
// Validate display size before using it
212+
if (visibleSize.width > 0 && visibleSize.height > 0) {
213+
await windowManager.setSize(
214+
Size(visibleSize.width * 0.8, visibleSize.height * 0.8),
215+
);
216+
await windowManager.center();
217+
} else {
218+
// Invalid display size, use hardcoded fallback
219+
commonPrint.log(
220+
'Invalid display size, using fallback dimensions',
221+
);
222+
await windowManager.setSize(const Size(1280, 720));
223+
await windowManager.center();
224+
}
225+
} catch (e) {
226+
// Failed to get display info, use fallback size
227+
commonPrint.log('Failed to get display info: $e');
228+
await windowManager.setSize(const Size(1280, 720));
229+
await windowManager.center();
230+
}
231+
}
232+
}
233+
_windowsBoundsMaximized = false;
234+
isMaximizedNotifier.value = false;
235+
} else {
236+
// Non-Windows platforms: use standard unmaximize
237+
await windowManager.unmaximize();
238+
_windowsBoundsMaximized = false;
239+
isMaximizedNotifier.value = false;
240+
}
216241
} else {
217-
await windowManager.maximize();
218-
isMaximizedNotifier.value = await windowManager.isMaximized();
242+
// Maximize window
243+
if (system.isWindows) {
244+
// Save current window bounds
245+
final currentPosition = await windowManager.getPosition();
246+
final currentSize = await windowManager.getSize();
247+
_savedBounds = Rect.fromLTWH(
248+
currentPosition.dx,
249+
currentPosition.dy,
250+
currentSize.width,
251+
currentSize.height,
252+
);
253+
254+
// Determine which display the window is currently on by finding
255+
// the display that contains the window's center point
256+
final windowCenter = Offset(
257+
currentPosition.dx + currentSize.width / 2,
258+
currentPosition.dy + currentSize.height / 2,
259+
);
260+
261+
final displays = await screenRetriever.getAllDisplays();
262+
Display? targetDisplay;
263+
264+
for (final display in displays) {
265+
final displayBounds = Rect.fromLTWH(
266+
display.visiblePosition?.dx ?? 0,
267+
display.visiblePosition?.dy ?? 0,
268+
display.visibleSize?.width ?? display.size.width,
269+
display.visibleSize?.height ?? display.size.height,
270+
);
271+
if (displayBounds.contains(windowCenter)) {
272+
targetDisplay = display;
273+
break;
274+
}
275+
}
276+
277+
// Fallback to primary display if window is not on any display
278+
targetDisplay ??= await screenRetriever.getPrimaryDisplay();
279+
280+
// Validate display information before using it
281+
final visiblePosition = targetDisplay.visiblePosition ?? Offset.zero;
282+
final visibleSize = targetDisplay.visibleSize ?? targetDisplay.size;
283+
284+
// Ensure we have valid dimensions
285+
if (visibleSize.width <= 0 || visibleSize.height <= 0) {
286+
// Display information is invalid, fallback to native maximize
287+
commonPrint.log(
288+
'Invalid display dimensions, using native maximize',
289+
);
290+
await windowManager.maximize();
291+
_windowsBoundsMaximized = false;
292+
isMaximizedNotifier.value = await windowManager.isMaximized();
293+
} else {
294+
await windowManager.setBounds(
295+
Rect.fromLTWH(
296+
visiblePosition.dx,
297+
visiblePosition.dy,
298+
visibleSize.width,
299+
visibleSize.height,
300+
),
301+
);
302+
_windowsBoundsMaximized = true;
303+
isMaximizedNotifier.value = true;
304+
}
305+
} else {
306+
await windowManager.maximize();
307+
isMaximizedNotifier.value = await windowManager.isMaximized();
308+
}
219309
}
310+
} finally {
311+
_isUpdatingMaximized = false;
220312
}
221313
}
222314

0 commit comments

Comments
 (0)