From c6b49e99d88a1cfcdae851a30bb970384cb0fa3d Mon Sep 17 00:00:00 2001 From: SweetPPro Date: Thu, 16 Jun 2022 19:55:33 +0200 Subject: [PATCH] macOS revert fullscreen changes (#3304) * macOS remove NSWindow subclass as discussed in #3297 --- Transmission.xcodeproj/project.pbxproj | 6 - macosx/AddMagnetWindowController.mm | 4 +- macosx/AddWindowController.mm | 4 +- macosx/CMakeLists.txt | 1 - macosx/Controller.h | 76 +---- macosx/Controller.mm | 446 +++++++++++++++++++++++-- macosx/ControllerWindowMethods.h | 26 -- macosx/ControllerWindowMethods.mm | 273 --------------- macosx/CreatorWindowController.mm | 4 +- macosx/MessageWindowController.mm | 4 +- macosx/PrefsController.mm | 4 +- macosx/StatsWindowController.mm | 4 +- 12 files changed, 443 insertions(+), 409 deletions(-) delete mode 100644 macosx/ControllerWindowMethods.h delete mode 100644 macosx/ControllerWindowMethods.mm diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 8937165fb..9d2133b8f 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -21,7 +21,6 @@ 3C7A11980D0B2EE300B5701F /* getgateway.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C7A11920D0B2EE300B5701F /* getgateway.h */; }; 3C7A11990D0B2EE300B5701F /* natpmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C7A11930D0B2EE300B5701F /* natpmp.c */; }; 3C7A119A0D0B2EE300B5701F /* natpmp.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C7A11940D0B2EE300B5701F /* natpmp.h */; }; - 456B90D02855332F000D4D80 /* ControllerWindowMethods.mm in Sources */ = {isa = PBXBuildFile; fileRef = 456B90CE2855332F000D4D80 /* ControllerWindowMethods.mm */; }; 45A7D3292843B54D00F0C32A /* GroupPopUpButtonCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45A7D3282843B54D00F0C32A /* GroupPopUpButtonCell.mm */; }; 45A7D32C2843B55F00F0C32A /* PriorityPopUpButtonCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 45A7D32B2843B55F00F0C32A /* PriorityPopUpButtonCell.mm */; }; 4D043A7F090AE979009FEDA8 /* TransmissionDocument.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4D043A7E090AE979009FEDA8 /* TransmissionDocument.icns */; }; @@ -614,8 +613,6 @@ 3C7A11920D0B2EE300B5701F /* getgateway.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = getgateway.h; sourceTree = ""; }; 3C7A11930D0B2EE300B5701F /* natpmp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = natpmp.c; sourceTree = ""; }; 3C7A11940D0B2EE300B5701F /* natpmp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = natpmp.h; sourceTree = ""; }; - 456B90CE2855332F000D4D80 /* ControllerWindowMethods.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ControllerWindowMethods.mm; sourceTree = ""; }; - 456B90CF2855332F000D4D80 /* ControllerWindowMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ControllerWindowMethods.h; sourceTree = ""; }; 45A7D3272843B54D00F0C32A /* GroupPopUpButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupPopUpButtonCell.h; sourceTree = ""; }; 45A7D3282843B54D00F0C32A /* GroupPopUpButtonCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GroupPopUpButtonCell.mm; sourceTree = ""; }; 45A7D32A2843B55F00F0C32A /* PriorityPopUpButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PriorityPopUpButtonCell.h; sourceTree = ""; }; @@ -1391,8 +1388,6 @@ C86BCD9828228A9600F45599 /* SparkleProxy.mm */, 4DF0C5AA0899190500DD8943 /* Controller.h */, 4DF0C5A90899190500DD8943 /* Controller.mm */, - 456B90CF2855332F000D4D80 /* ControllerWindowMethods.h */, - 456B90CE2855332F000D4D80 /* ControllerWindowMethods.mm */, 4DFBC2DD09C0970D00D5C571 /* Torrent.h */, 4DFBC2DE09C0970D00D5C571 /* Torrent.mm */, A27F0F310E19AD9800B2DB97 /* TorrentGroup.h */, @@ -3028,7 +3023,6 @@ 35F373030C2DA89000DAA8F2 /* FilePriorityCell.mm in Sources */, A2085DDC0C53BC74000BC3B7 /* AboutWindowController.mm in Sources */, A21282A80CA6C66800EAEE0F /* StatusBarView.mm in Sources */, - 456B90D02855332F000D4D80 /* ControllerWindowMethods.mm in Sources */, A257C1820CAD3003004E121C /* PeerTableView.mm in Sources */, A2A6321B0CD9751700E3DA60 /* BadgeView.mm in Sources */, A2ED7D8F0CEF431B00970975 /* FilterButton.mm in Sources */, diff --git a/macosx/AddMagnetWindowController.mm b/macosx/AddMagnetWindowController.mm index f8801dc1a..d8a389d58 100644 --- a/macosx/AddMagnetWindowController.mm +++ b/macosx/AddMagnetWindowController.mm @@ -74,8 +74,8 @@ self.fNameField.stringValue = name; self.fNameField.toolTip = name; - //make window an auxillary view in fullscreen - [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + //disable fullscreen support + [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; [self setGroupsMenu]; [self.fGroupPopUp selectItemWithTag:self.fGroupValue]; diff --git a/macosx/AddWindowController.mm b/macosx/AddWindowController.mm index 8ef519040..dcfbe5cb8 100644 --- a/macosx/AddWindowController.mm +++ b/macosx/AddWindowController.mm @@ -106,8 +106,8 @@ self.fNameField.stringValue = name; self.fNameField.toolTip = name; - //make window an auxillary view in fullscreen - [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + //disable fullscreen support + [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; self.fIconView.image = self.torrent.icon; diff --git a/macosx/CMakeLists.txt b/macosx/CMakeLists.txt index 67cd8d6af..0d18489b1 100644 --- a/macosx/CMakeLists.txt +++ b/macosx/CMakeLists.txt @@ -50,7 +50,6 @@ set(${PROJECT_NAME}_SOURCES ButtonToolbarItem.mm ColorTextField.mm Controller.mm - ControllerWindowMethods.mm CreatorWindowController.mm DragOverlayView.mm DragOverlayWindow.mm diff --git a/macosx/Controller.h b/macosx/Controller.h index 854024954..4e06cbedb 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -10,7 +10,6 @@ #include #import "VDKQueue.h" -#import "TorrentTableView.h" @class AddMagnetWindowController; @class AddWindowController; @@ -159,12 +158,20 @@ typedef NS_ENUM(unsigned int, addType) { // - (void)toggleAvailabilityBar:(id)sender; - (void)toggleStatusBar:(id)sender; +- (void)showStatusBar:(BOOL)show animate:(BOOL)animate; - (void)toggleFilterBar:(id)sender; +- (void)showFilterBar:(BOOL)show animate:(BOOL)animate; - (void)focusFilterField; - (void)allToolbarClicked:(id)sender; - (void)selectedToolbarClicked:(id)sender; +- (void)setWindowSizeToFit; +@property(nonatomic, readonly) NSRect sizedWindowFrame; +- (void)updateForAutoSize; +- (void)setWindowMinMaxToCurrent; +@property(nonatomic, readonly) CGFloat minWindowContentSizeAllowed; + - (void)updateForExpandCollapse; - (void)showMainWindow:(id)sender; @@ -184,71 +191,4 @@ typedef NS_ENUM(unsigned int, addType) { // - (void)rpcMovedTorrent:(Torrent*)torrent; - (void)rpcUpdateQueue; -@property(nonatomic) IBOutlet NSWindow* fWindow; -@property(nonatomic) IBOutlet TorrentTableView* fTableView; - -@property(nonatomic) IBOutlet NSMenuItem* fOpenIgnoreDownloadFolder; -@property(nonatomic) IBOutlet NSButton* fActionButton; -@property(nonatomic) IBOutlet NSButton* fSpeedLimitButton; -@property(nonatomic) IBOutlet NSButton* fClearCompletedButton; -@property(nonatomic) IBOutlet NSTextField* fTotalTorrentsField; -@property(nonatomic) IBOutlet NSMenuItem* fNextFilterItem; - -@property(nonatomic) IBOutlet NSMenuItem* fNextInfoTabItem; -@property(nonatomic) IBOutlet NSMenuItem* fPrevInfoTabItem; - -@property(nonatomic) IBOutlet NSMenu* fSortMenu; - -@property(nonatomic) IBOutlet NSMenu* fGroupsSetMenu; -@property(nonatomic) IBOutlet NSMenu* fGroupsSetContextMenu; - -@property(nonatomic) IBOutlet NSMenu* fShareMenu; -@property(nonatomic) IBOutlet NSMenu* fShareContextMenu; -@property(nonatomic) IBOutlet NSMenuItem* fShareMenuItem; // remove when dropping 10.6 -@property(nonatomic) IBOutlet NSMenuItem* fShareContextMenuItem; // remove when dropping 10.6 - -@property(nonatomic, readonly) tr_session* fLib; - -@property(nonatomic, readonly) NSMutableArray* fTorrents; -@property(nonatomic, readonly) NSMutableArray* fDisplayedTorrents; -@property(nonatomic, readonly) NSMutableDictionary* fTorrentHashes; - -@property(nonatomic, readonly) InfoWindowController* fInfoController; -@property(nonatomic) MessageWindowController* fMessageController; - -@property(nonatomic, readonly) NSUserDefaults* fDefaults; - -@property(nonatomic, readonly) NSString* fConfigDirectory; - -@property(nonatomic) DragOverlayWindow* fOverlayWindow; - -@property(nonatomic) io_connect_t fRootPort; -@property(nonatomic) NSTimer* fTimer; - -@property(nonatomic) StatusBarController* fStatusBar; - -@property(nonatomic) FilterBarController* fFilterBar; - -@property(nonatomic) QLPreviewPanel* fPreviewPanel; -@property(nonatomic) BOOL fQuitting; -@property(nonatomic) BOOL fQuitRequested; -@property(nonatomic, readonly) BOOL fPauseOnLaunch; - -@property(nonatomic) Badger* fBadger; - -@property(nonatomic) NSMutableArray* fAutoImportedNames; -@property(nonatomic) NSTimer* fAutoImportTimer; - -@property(nonatomic) NSMutableDictionary* fPendingTorrentDownloads; - -@property(nonatomic) NSMutableSet* fAddingTransfers; - -@property(nonatomic) NSMutableSet* fAddWindows; -@property(nonatomic) URLSheetWindowController* fUrlSheetController; - -@property(nonatomic) BOOL fGlobalPopoverShown; -@property(nonatomic) NSView* fPositioningView; -@property(nonatomic) BOOL fSoundPlaying; -@property(nonatomic) id fNoNapActivity; - @end diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 6920d2367..bacbe147b 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -22,9 +22,9 @@ #import "CocoaCompatibility.h" #import "Controller.h" -#import "ControllerWindowMethods.h" #import "Torrent.h" #import "TorrentGroup.h" +#import "TorrentTableView.h" #import "CreatorWindowController.h" #import "StatsWindowController.h" #import "InfoWindowController.h" @@ -42,6 +42,8 @@ #import "ShareTorrentFileHelper.h" #import "ToolbarSegmentedCell.h" #import "BlocklistDownloader.h" +#import "StatusBarController.h" +#import "FilterBarController.h" #import "FileRenameSheetController.h" #import "BonjourController.h" #import "Badger.h" @@ -101,6 +103,10 @@ typedef NS_ENUM(unsigned int, sortOrderTag) { // #define ROW_HEIGHT_REGULAR 62.0 #define ROW_HEIGHT_SMALL 22.0 +#define WINDOW_REGULAR_WIDTH 468.0 + +#define STATUS_BAR_HEIGHT 21.0 +#define FILTER_BAR_HEIGHT 23.0 #define UPDATE_UI_SECONDS 1.0 @@ -221,6 +227,77 @@ static void removeKeRangerRansomware() NSLog(@"OSX.KeRanger.A ransomware removal completed, proceeding to normal operation"); } +@interface Controller () + +@property(nonatomic) IBOutlet NSWindow* fWindow; +@property(nonatomic) IBOutlet TorrentTableView* fTableView; + +@property(nonatomic) IBOutlet NSMenuItem* fOpenIgnoreDownloadFolder; +@property(nonatomic) IBOutlet NSButton* fActionButton; +@property(nonatomic) IBOutlet NSButton* fSpeedLimitButton; +@property(nonatomic) IBOutlet NSButton* fClearCompletedButton; +@property(nonatomic) IBOutlet NSTextField* fTotalTorrentsField; +@property(nonatomic) IBOutlet NSMenuItem* fNextFilterItem; + +@property(nonatomic) IBOutlet NSMenuItem* fNextInfoTabItem; +@property(nonatomic) IBOutlet NSMenuItem* fPrevInfoTabItem; + +@property(nonatomic) IBOutlet NSMenu* fSortMenu; + +@property(nonatomic) IBOutlet NSMenu* fGroupsSetMenu; +@property(nonatomic) IBOutlet NSMenu* fGroupsSetContextMenu; + +@property(nonatomic) IBOutlet NSMenu* fShareMenu; +@property(nonatomic) IBOutlet NSMenu* fShareContextMenu; +@property(nonatomic) IBOutlet NSMenuItem* fShareMenuItem; // remove when dropping 10.6 +@property(nonatomic) IBOutlet NSMenuItem* fShareContextMenuItem; // remove when dropping 10.6 + +@property(nonatomic, readonly) tr_session* fLib; + +@property(nonatomic, readonly) NSMutableArray* fTorrents; +@property(nonatomic, readonly) NSMutableArray* fDisplayedTorrents; +@property(nonatomic, readonly) NSMutableDictionary* fTorrentHashes; + +@property(nonatomic, readonly) InfoWindowController* fInfoController; +@property(nonatomic) MessageWindowController* fMessageController; + +@property(nonatomic, readonly) NSUserDefaults* fDefaults; + +@property(nonatomic, readonly) NSString* fConfigDirectory; + +@property(nonatomic) DragOverlayWindow* fOverlayWindow; + +@property(nonatomic) io_connect_t fRootPort; +@property(nonatomic) NSTimer* fTimer; + +@property(nonatomic) StatusBarController* fStatusBar; + +@property(nonatomic) FilterBarController* fFilterBar; + +@property(nonatomic) QLPreviewPanel* fPreviewPanel; +@property(nonatomic) BOOL fQuitting; +@property(nonatomic) BOOL fQuitRequested; +@property(nonatomic, readonly) BOOL fPauseOnLaunch; + +@property(nonatomic) Badger* fBadger; + +@property(nonatomic) NSMutableArray* fAutoImportedNames; +@property(nonatomic) NSTimer* fAutoImportTimer; + +@property(nonatomic) NSMutableDictionary* fPendingTorrentDownloads; + +@property(nonatomic) NSMutableSet* fAddingTransfers; + +@property(nonatomic) NSMutableSet* fAddWindows; +@property(nonatomic) URLSheetWindowController* fUrlSheetController; + +@property(nonatomic) BOOL fGlobalPopoverShown; +@property(nonatomic) NSView* fPositioningView; +@property(nonatomic) BOOL fSoundPlaying; +@property(nonatomic) id fNoNapActivity; + +@end + @implementation Controller + (void)initialize @@ -485,12 +562,12 @@ static void removeKeRangerRansomware() self.fWindow.delegate = self; //do manually to avoid placement issue + //disable fullscreen support + [self.fWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; + [self.fWindow makeFirstResponder:self.fTableView]; self.fWindow.excludedFromWindowsMenu = YES; - //make window primary view in fullscreen - [self.fWindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; - //set table size BOOL const small = [self.fDefaults boolForKey:@"SmallView"]; if (small) @@ -504,6 +581,12 @@ static void removeKeRangerRansomware() self.fTotalTorrentsField.cell.backgroundStyle = NSBackgroundStyleRaised; + //set up filter bar + [self showFilterBar:[self.fDefaults boolForKey:@"FilterBar"] animate:NO]; + + //set up status bar + [self showStatusBar:[self.fDefaults boolForKey:@"StatusBar"] animate:NO]; + self.fActionButton.toolTip = NSLocalizedString(@"Shortcuts for changing global settings.", "Main window -> 1st bottom left button (action) tooltip"); self.fSpeedLimitButton.toolTip = NSLocalizedString( @"Speed Limit overrides the total bandwidth limits with its own limits.", @@ -547,6 +630,13 @@ static void removeKeRangerRansomware() [self.fSortMenu insertItem:item atIndex:sortMenuIndex++]; } + //you would think this would be called later in this method from updateUI, but it's not reached in awakeFromNib + //this must be called after showStatusBar: + [self.fStatusBar updateWithDownload:0.0 upload:0.0]; + + //this should also be after the rest of the setup + [self updateForAutoSize]; + //register for sleep notifications IONotificationPortRef notify; io_object_t iterator; @@ -658,7 +748,7 @@ static void removeKeRangerRansomware() #warning rename [nc addObserver:self selector:@selector(fullUpdateUI) name:@"UpdateQueue" object:nil]; - [nc addObserver:self selector:@selector(drawMainWindow) name:@"ApplyFilter" object:nil]; + [nc addObserver:self selector:@selector(applyFilter) name:@"ApplyFilter" object:nil]; //open newly created torrent file [nc addObserver:self selector:@selector(beginCreateFile:) name:@"BeginCreateTorrentFile" object:nil]; @@ -668,8 +758,6 @@ static void removeKeRangerRansomware() [nc addObserver:self selector:@selector(applyFilter) name:@"UpdateGroups" object:nil]; - [self drawMainWindow]; - //timer to update the interface every second [self updateUI]; self.fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_UI_SECONDS target:self selector:@selector(updateUI) @@ -678,6 +766,8 @@ static void removeKeRangerRansomware() [NSRunLoop.currentRunLoop addTimer:self.fTimer forMode:NSModalPanelRunLoopMode]; [NSRunLoop.currentRunLoop addTimer:self.fTimer forMode:NSEventTrackingRunLoopMode]; + [self applyFilter]; + [self.fWindow makeKeyAndOrderFront:nil]; if ([self.fDefaults boolForKey:@"InfoVisible"]) @@ -879,6 +969,9 @@ static void removeKeRangerRansomware() [window close]; } + [self showStatusBar:NO animate:NO]; + [self showFilterBar:NO animate:NO]; + //save history [self updateTorrentHistory]; [self.fTableView saveCollapsedGroups]; @@ -1114,7 +1207,7 @@ static void removeKeRangerRansomware() } } - [self drawMainWindow]; + [self fullUpdateUI]; } - (void)askOpenConfirmed:(AddWindowController*)addController add:(BOOL)add @@ -1134,7 +1227,7 @@ static void removeKeRangerRansomware() } [self.fAddingTransfers addObject:torrent]; - [self drawMainWindow]; + [self fullUpdateUI]; } else { @@ -1208,7 +1301,7 @@ static void removeKeRangerRansomware() [self.fAddingTransfers addObject:torrent]; } - [self drawMainWindow]; + [self fullUpdateUI]; } - (void)askOpenMagnetConfirmed:(AddMagnetWindowController*)addController add:(BOOL)add @@ -1228,7 +1321,7 @@ static void removeKeRangerRansomware() } [self.fAddingTransfers addObject:torrent]; - [self drawMainWindow]; + [self fullUpdateUI]; } else { @@ -1725,8 +1818,6 @@ static void removeKeRangerRansomware() { [torrent closeRemoveTorrent:deleteData]; } - - [self drawMainWindow]; }; [self.fTableView beginUpdates]; @@ -1768,9 +1859,9 @@ static void removeKeRangerRansomware() { [torrent closeRemoveTorrent:deleteData]; } - - [self drawMainWindow]; } + + [self fullUpdateUI]; } - (void)removeNoDelete:(id)sender @@ -3728,7 +3819,7 @@ static void removeKeRangerRansomware() [self.fTableView endUpdates]; //resize for larger min height if not set to auto size - if (![self.fDefaults boolForKey:@"AutoSize"] || self.isFullScreen) + if (![self.fDefaults boolForKey:@"AutoSize"]) { NSSize const contentSize = self.fWindow.contentView.frame.size; @@ -3751,8 +3842,6 @@ static void removeKeRangerRansomware() { [self setWindowSizeToFit]; } - - [self drawMainWindow]; } - (void)togglePiecesBar:(id)sender @@ -3767,29 +3856,266 @@ static void removeKeRangerRansomware() [self.fTableView display]; } +- (NSRect)windowFrameByAddingHeight:(CGFloat)height checkLimits:(BOOL)check +{ + NSScrollView* scrollView = self.fTableView.enclosingScrollView; + + //convert pixels to points + NSRect windowFrame = self.fWindow.frame; + NSSize windowSize = [scrollView convertSize:windowFrame.size fromView:nil]; + windowSize.height += height; + + if (check) + { + //we can't call minSize, since it might be set to the current size (auto size) + CGFloat const minHeight = self.minWindowContentSizeAllowed + + (NSHeight(self.fWindow.frame) - NSHeight(self.fWindow.contentView.frame)); //contentView to window + + if (windowSize.height <= minHeight) + { + windowSize.height = minHeight; + } + else + { + NSScreen* screen = self.fWindow.screen; + if (screen) + { + NSSize maxSize = [scrollView convertSize:screen.visibleFrame.size fromView:nil]; + if (!self.fStatusBar) + { + maxSize.height -= STATUS_BAR_HEIGHT; + } + if (!self.fFilterBar) + { + maxSize.height -= FILTER_BAR_HEIGHT; + } + if (windowSize.height > maxSize.height) + { + windowSize.height = maxSize.height; + } + } + } + } + + //convert points to pixels + windowSize = [scrollView convertSize:windowSize toView:nil]; + + windowFrame.origin.y -= (windowSize.height - windowFrame.size.height); + windowFrame.size.height = windowSize.height; + return windowFrame; +} + - (void)toggleStatusBar:(id)sender { BOOL const show = self.fStatusBar == nil; + [self showStatusBar:show animate:YES]; [self.fDefaults setBool:show forKey:@"StatusBar"]; - [self drawMainWindow]; +} + +//doesn't save shown state +- (void)showStatusBar:(BOOL)show animate:(BOOL)animate +{ + BOOL const prevShown = self.fStatusBar != nil; + if (show == prevShown) + { + return; + } + + if (show) + { + self.fStatusBar = [[StatusBarController alloc] initWithLib:self.fLib]; + + NSView* contentView = self.fWindow.contentView; + NSSize const windowSize = [contentView convertSize:self.fWindow.frame.size fromView:nil]; + + NSRect statusBarFrame = self.fStatusBar.view.frame; + statusBarFrame.size.width = windowSize.width; + self.fStatusBar.view.frame = statusBarFrame; + + [contentView addSubview:self.fStatusBar.view]; + [self.fStatusBar.view setFrameOrigin:NSMakePoint(0.0, NSMaxY(contentView.frame))]; + } + + CGFloat heightChange = self.fStatusBar.view.frame.size.height; + if (!show) + { + heightChange *= -1; + } + + //allow bar to show even if not enough room + if (show && ![self.fDefaults boolForKey:@"AutoSize"]) + { + NSRect frame = [self windowFrameByAddingHeight:heightChange checkLimits:NO]; + + NSScreen* screen = self.fWindow.screen; + if (screen) + { + CGFloat change = screen.visibleFrame.size.height - frame.size.height; + if (change < 0.0) + { + frame = self.fWindow.frame; + frame.size.height += change; + frame.origin.y -= change; + [self.fWindow setFrame:frame display:NO animate:NO]; + } + } + } + + [self updateUI]; + + NSScrollView* scrollView = self.fTableView.enclosingScrollView; + + //set views to not autoresize + NSUInteger const statsMask = self.fStatusBar.view.autoresizingMask; + self.fStatusBar.view.autoresizingMask = NSViewNotSizable; + NSUInteger filterMask; + if (self.fFilterBar) + { + filterMask = self.fFilterBar.view.autoresizingMask; + self.fFilterBar.view.autoresizingMask = NSViewNotSizable; + } + NSUInteger const scrollMask = scrollView.autoresizingMask; + scrollView.autoresizingMask = NSViewNotSizable; + + NSRect const frame = [self windowFrameByAddingHeight:heightChange checkLimits:NO]; + [self.fWindow setFrame:frame display:YES animate:animate]; + + //re-enable autoresize + self.fStatusBar.view.autoresizingMask = statsMask; + if (self.fFilterBar) + { + self.fFilterBar.view.autoresizingMask = filterMask; + } + scrollView.autoresizingMask = scrollMask; + + if (!show) + { + [self.fStatusBar.view removeFromSuperviewWithoutNeedingDisplay]; + self.fStatusBar = nil; + } + + if ([self.fDefaults boolForKey:@"AutoSize"]) + { + [self setWindowMinMaxToCurrent]; + } + else + { + //change min size + NSSize minSize = self.fWindow.contentMinSize; + minSize.height += heightChange; + self.fWindow.contentMinSize = minSize; + } } - (void)toggleFilterBar:(id)sender { BOOL const show = self.fFilterBar == nil; - //disable filtering when hiding (have to do before drawMainWindow:) + //disable filtering when hiding (have to do before showFilterBar:animate:) if (!show) { [self.fFilterBar reset:NO]; } + [self showFilterBar:show animate:YES]; [self.fDefaults setBool:show forKey:@"FilterBar"]; - [self drawMainWindow]; + [self.fWindow.toolbar validateVisibleItems]; + + [self applyFilter]; //do even if showing to ensure tooltips are updated +} + +//doesn't save shown state +- (void)showFilterBar:(BOOL)show animate:(BOOL)animate +{ + BOOL const prevShown = self.fFilterBar != nil; + if (show == prevShown) + { + return; + } if (show) { - [self focusFilterField]; + self.fFilterBar = [[FilterBarController alloc] init]; + + NSView* contentView = self.fWindow.contentView; + NSSize const windowSize = [contentView convertSize:self.fWindow.frame.size fromView:nil]; + + NSRect filterBarFrame = self.fFilterBar.view.frame; + filterBarFrame.size.width = windowSize.width; + self.fFilterBar.view.frame = filterBarFrame; + + if (self.fStatusBar) + { + [contentView addSubview:self.fFilterBar.view positioned:NSWindowBelow relativeTo:self.fStatusBar.view]; + } + else + { + [contentView addSubview:self.fFilterBar.view]; + } + CGFloat const originY = self.fStatusBar ? NSMinY(self.fStatusBar.view.frame) : NSMaxY(contentView.frame); + [self.fFilterBar.view setFrameOrigin:NSMakePoint(0.0, originY)]; + } + else + { + [self.fWindow makeFirstResponder:self.fTableView]; + } + + CGFloat heightChange = NSHeight(self.fFilterBar.view.frame); + if (!show) + { + heightChange *= -1; + } + + //allow bar to show even if not enough room + if (show && ![self.fDefaults boolForKey:@"AutoSize"]) + { + NSRect frame = [self windowFrameByAddingHeight:heightChange checkLimits:NO]; + + NSScreen* screen = self.fWindow.screen; + if (screen) + { + CGFloat change = screen.visibleFrame.size.height - frame.size.height; + if (change < 0.0) + { + frame = self.fWindow.frame; + frame.size.height += change; + frame.origin.y -= change; + [self.fWindow setFrame:frame display:NO animate:NO]; + } + } + } + + NSScrollView* scrollView = self.fTableView.enclosingScrollView; + + //set views to not autoresize + NSUInteger const filterMask = self.fFilterBar.view.autoresizingMask; + NSUInteger const scrollMask = scrollView.autoresizingMask; + self.fFilterBar.view.autoresizingMask = NSViewNotSizable; + scrollView.autoresizingMask = NSViewNotSizable; + + NSRect const frame = [self windowFrameByAddingHeight:heightChange checkLimits:NO]; + [self.fWindow setFrame:frame display:YES animate:animate]; + + //re-enable autoresize + self.fFilterBar.view.autoresizingMask = filterMask; + scrollView.autoresizingMask = scrollMask; + + if (!show) + { + [self.fFilterBar.view removeFromSuperviewWithoutNeedingDisplay]; + self.fFilterBar = nil; + } + + if ([self.fDefaults boolForKey:@"AutoSize"]) + { + [self setWindowMinMaxToCurrent]; + } + else + { + //change min size + NSSize minSize = self.fWindow.contentMinSize; + minSize.height += heightChange; + self.fWindow.contentMinSize = minSize; } } @@ -4850,6 +5176,80 @@ static void removeKeRangerRansomware() return menu; } +- (NSRect)windowWillUseStandardFrame:(NSWindow*)window defaultFrame:(NSRect)defaultFrame +{ + //if auto size is enabled, the current frame shouldn't need to change + NSRect frame = [self.fDefaults boolForKey:@"AutoSize"] ? window.frame : self.sizedWindowFrame; + + frame.size.width = [self.fDefaults boolForKey:@"SmallView"] ? self.fWindow.minSize.width : WINDOW_REGULAR_WIDTH; + return frame; +} + +- (void)setWindowSizeToFit +{ + if ([self.fDefaults boolForKey:@"AutoSize"]) + { + NSScrollView* scrollView = self.fTableView.enclosingScrollView; + + scrollView.hasVerticalScroller = NO; + [self.fWindow setFrame:self.sizedWindowFrame display:YES animate:YES]; + scrollView.hasVerticalScroller = YES; + + [self setWindowMinMaxToCurrent]; + } +} + +- (NSRect)sizedWindowFrame +{ + NSUInteger groups = (self.fDisplayedTorrents.count > 0 && ![self.fDisplayedTorrents[0] isKindOfClass:[Torrent class]]) ? + self.fDisplayedTorrents.count : + 0; + + CGFloat heightChange = (GROUP_SEPARATOR_HEIGHT + self.fTableView.intercellSpacing.height) * groups + + (self.fTableView.rowHeight + self.fTableView.intercellSpacing.height) * (self.fTableView.numberOfRows - groups) - + NSHeight(self.fTableView.enclosingScrollView.frame); + + return [self windowFrameByAddingHeight:heightChange checkLimits:YES]; +} + +- (void)updateForAutoSize +{ + if ([self.fDefaults boolForKey:@"AutoSize"]) + { + [self setWindowSizeToFit]; + } + else + { + NSSize contentMinSize = self.fWindow.contentMinSize; + contentMinSize.height = self.minWindowContentSizeAllowed; + + self.fWindow.contentMinSize = contentMinSize; + + NSSize contentMaxSize = self.fWindow.contentMaxSize; + contentMaxSize.height = FLT_MAX; + self.fWindow.contentMaxSize = contentMaxSize; + } +} + +- (void)setWindowMinMaxToCurrent +{ + CGFloat const height = NSHeight(self.fWindow.contentView.frame); + + NSSize minSize = self.fWindow.contentMinSize, maxSize = self.fWindow.contentMaxSize; + minSize.height = height; + maxSize.height = height; + + self.fWindow.contentMinSize = minSize; + self.fWindow.contentMaxSize = maxSize; +} + +- (CGFloat)minWindowContentSizeAllowed +{ + CGFloat contentMinHeight = NSHeight(self.fWindow.contentView.frame) - NSHeight(self.fTableView.enclosingScrollView.frame) + + self.fTableView.rowHeight + self.fTableView.intercellSpacing.height; + return contentMinHeight; +} + - (void)updateForExpandCollapse { [self setWindowSizeToFit]; @@ -5007,7 +5407,7 @@ static void removeKeRangerRansomware() } [self.fAddingTransfers addObject:torrent]; - [self drawMainWindow]; + [self fullUpdateUI]; } - (void)rpcRemoveTorrent:(Torrent*)torrent deleteData:(BOOL)deleteData diff --git a/macosx/ControllerWindowMethods.h b/macosx/ControllerWindowMethods.h deleted file mode 100644 index a43b464ed..000000000 --- a/macosx/ControllerWindowMethods.h +++ /dev/null @@ -1,26 +0,0 @@ -// This file Copyright © 2005-2022 Transmission authors and contributors. -// It may be used under the MIT (SPDX: MIT) license. -// License text can be found in the licenses/ folder. - -#import "Controller.h" -#import "StatusBarController.h" -#import "FilterBarController.h" -#import "Torrent.h" - -@interface Controller (ControllerWindowMethods) - -- (void)drawMainWindow; - -- (void)setWindowSizeToFit; -- (void)updateForAutoSize; -- (void)setWindowMinMaxToCurrent; - -@property(nonatomic, readonly) NSRect sizedWindowFrame; -@property(nonatomic, readonly) CGFloat titlebarHeight; -@property(nonatomic, readonly) CGFloat mainWindowComponentHeight; -@property(nonatomic, readonly) CGFloat scrollViewHeight; -@property(nonatomic, readonly) CGFloat fullScreenScrollViewHeight; -@property(nonatomic, readonly) CGFloat minWindowContentSizeAllowed; -@property(nonatomic, readonly) BOOL isFullScreen; - -@end diff --git a/macosx/ControllerWindowMethods.mm b/macosx/ControllerWindowMethods.mm deleted file mode 100644 index aea7a8401..000000000 --- a/macosx/ControllerWindowMethods.mm +++ /dev/null @@ -1,273 +0,0 @@ -// This file Copyright © 2005-2022 Transmission authors and contributors. -// It may be used under the MIT (SPDX: MIT) license. -// License text can be found in the licenses/ folder. - -#import "ControllerWindowMethods.h" - -#define WINDOW_REGULAR_WIDTH 468.0 - -#define STATUS_BAR_HEIGHT 21.0 -#define FILTER_BAR_HEIGHT 23.0 -#define BOTTOM_BAR_HEIGHT 24.0 - -@implementation Controller (ControllerWindowMethods) - -- (void)drawMainWindow -{ - dispatch_async(dispatch_get_main_queue(), ^{ - NSView* contentView = self.fWindow.contentView; - NSSize const windowSize = [contentView convertSize:self.fWindow.frame.size fromView:nil]; - CGFloat originY = NSMaxY(contentView.frame); - - //remove all subviews - for (id view in contentView.subviews.copy) - { - [view removeFromSuperviewWithoutNeedingDisplay]; - } - - self.fStatusBar = nil; - self.fFilterBar = nil; - - if ([self.fDefaults boolForKey:@"StatusBar"]) - { - self.fStatusBar = [[StatusBarController alloc] initWithLib:self.fLib]; - - NSRect statusBarFrame = self.fStatusBar.view.frame; - statusBarFrame.size.width = windowSize.width; - - originY -= STATUS_BAR_HEIGHT; - statusBarFrame.origin.y = originY; - self.fStatusBar.view.frame = statusBarFrame; - - [contentView addSubview:self.fStatusBar.view]; - } - - if ([self.fDefaults boolForKey:@"FilterBar"]) - { - self.fFilterBar = [[FilterBarController alloc] init]; - - NSRect filterBarFrame = self.fFilterBar.view.frame; - filterBarFrame.size.width = windowSize.width; - - originY -= FILTER_BAR_HEIGHT; - filterBarFrame.origin.y = originY; - self.fFilterBar.view.frame = filterBarFrame; - - [contentView addSubview:self.fFilterBar.view]; - } - - NSScrollView* scrollView = self.fTableView.enclosingScrollView; - [contentView addSubview:scrollView]; - - [contentView addSubview:self.fActionButton]; - [contentView addSubview:self.fSpeedLimitButton]; - [contentView addSubview:self.fClearCompletedButton]; - [contentView addSubview:self.fTotalTorrentsField]; - - //window is updated and animated in fullUpdateUI --> applyFilter --> setWindowSizeToFit - [self fullUpdateUI]; - [self updateForAutoSize]; - }); -} - -- (void)setWindowSizeToFit -{ - NSScrollView* scrollView = self.fTableView.enclosingScrollView; - - scrollView.hasVerticalScroller = NO; - [self.fWindow setFrame:self.sizedWindowFrame display:YES animate:YES]; - scrollView.hasVerticalScroller = YES; - - if ([self.fDefaults boolForKey:@"AutoSize"]) - { - if (!self.isFullScreen) - { - [self setWindowMinMaxToCurrent]; - } - } -} - -- (void)updateForAutoSize -{ - if ([self.fDefaults boolForKey:@"AutoSize"] && !self.isFullScreen) - { - [self setWindowSizeToFit]; - } - else - { - NSSize contentMinSize = self.fWindow.contentMinSize; - contentMinSize.height = self.minWindowContentSizeAllowed; - - self.fWindow.contentMinSize = contentMinSize; - - NSSize contentMaxSize = self.fWindow.contentMaxSize; - contentMaxSize.height = FLT_MAX; - self.fWindow.contentMaxSize = contentMaxSize; - } -} - -- (void)setWindowMinMaxToCurrent -{ - CGFloat const height = NSHeight(self.fWindow.contentView.frame); - - NSSize minSize = self.fWindow.contentMinSize, maxSize = self.fWindow.contentMaxSize; - minSize.height = height; - maxSize.height = height; - - self.fWindow.contentMinSize = minSize; - self.fWindow.contentMaxSize = maxSize; -} - -- (NSRect)sizedWindowFrame -{ - NSRect windowFrame = self.fWindow.frame; - NSScrollView* scrollView = self.fTableView.enclosingScrollView; - CGFloat titleBarHeight = self.titlebarHeight; - CGFloat scrollViewHeight = self.scrollViewHeight; - CGFloat componentHeight = [self mainWindowComponentHeight]; - - //update window frame - NSSize windowSize = [scrollView convertSize:windowFrame.size fromView:nil]; - windowSize.height = titleBarHeight + componentHeight + scrollViewHeight + BOTTOM_BAR_HEIGHT; - - //update scrollview - NSRect scrollViewFrame = scrollView.frame; - scrollViewFrame.size.height = scrollViewHeight; - - //we can't call minSize, since it might be set to the current size (auto size) - CGFloat const minHeight = self.minWindowContentSizeAllowed + - (NSHeight(self.fWindow.frame) - NSHeight(self.fWindow.contentView.frame)); //contentView to window - - if (windowSize.height <= minHeight) - { - windowSize.height = minHeight; - } - else - { - NSScreen* screen = self.fWindow.screen; - if (screen && !self.isFullScreen) - { - NSSize maxSize = screen.frame.size; - maxSize.height -= titleBarHeight; - maxSize.height -= BOTTOM_BAR_HEIGHT; - - if (self.fStatusBar) - { - maxSize.height -= STATUS_BAR_HEIGHT; - } - if (self.fFilterBar) - { - maxSize.height -= FILTER_BAR_HEIGHT; - } - if (windowSize.height > maxSize.height) - { - windowSize.height = maxSize.height; - - //recalculate scrollview height - scrollViewFrame.size.height = self.fullScreenScrollViewHeight; - } - } - } - - //commit scrollview changes - scrollViewFrame.origin.y = BOTTOM_BAR_HEIGHT; - [scrollView setFrame:scrollViewFrame]; - - windowFrame.origin.y -= (windowSize.height - windowFrame.size.height); - windowFrame.size.height = windowSize.height; - return windowFrame; -} - -- (CGFloat)titlebarHeight -{ - return self.fWindow.frame.size.height - [self.fWindow contentRectForFrameRect:self.fWindow.frame].size.height; -} - -- (CGFloat)mainWindowComponentHeight -{ - CGFloat height = 0; - if (self.fStatusBar) - { - height += STATUS_BAR_HEIGHT; - } - - if (self.fFilterBar) - { - height += FILTER_BAR_HEIGHT; - } - - return height; -} - -- (CGFloat)scrollViewHeight -{ - if (self.isFullScreen) - { - return self.fullScreenScrollViewHeight; - } - - if ([self.fDefaults boolForKey:@"AutoSize"]) - { - NSUInteger groups = (self.fDisplayedTorrents.count > 0 && ![self.fDisplayedTorrents[0] isKindOfClass:[Torrent class]]) ? - self.fDisplayedTorrents.count : - 0; - - CGFloat height = (GROUP_SEPARATOR_HEIGHT + self.fTableView.intercellSpacing.height) * groups + - (self.fTableView.rowHeight + self.fTableView.intercellSpacing.height) * (self.fTableView.numberOfRows - groups); - - return height; - } - - return NSHeight(self.fTableView.enclosingScrollView.frame); -} - -- (CGFloat)fullScreenScrollViewHeight -{ - return self.fWindow.frame.size.height - self.titlebarHeight - self.mainWindowComponentHeight - BOTTOM_BAR_HEIGHT; -} - -- (CGFloat)minWindowContentSizeAllowed -{ - CGFloat contentMinHeight = self.fTableView.rowHeight + self.fTableView.intercellSpacing.height + - self.mainWindowComponentHeight + BOTTOM_BAR_HEIGHT; - return contentMinHeight; -} - -- (BOOL)isFullScreen -{ - return (self.fWindow.styleMask & NSFullScreenWindowMask); -} - -- (void)windowWillEnterFullScreen:(NSNotification*)notification -{ - // temporarily disable AutoSize - NSSize contentMinSize = self.fWindow.contentMinSize; - contentMinSize.height = self.minWindowContentSizeAllowed; - - self.fWindow.contentMinSize = contentMinSize; - - NSSize contentMaxSize = self.fWindow.contentMaxSize; - contentMaxSize.height = FLT_MAX; - self.fWindow.contentMaxSize = contentMaxSize; -} - -- (void)windowDidEnterFullScreen:(NSNotification*)notification -{ - [self drawMainWindow]; -} - -- (void)windowWillExitFullScreen:(NSNotification*)notification -{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self drawMainWindow]; - }); -} - -- (void)windowDidExitFullScreen:(NSNotification*)notification -{ - dispatch_async(dispatch_get_main_queue(), ^{ - [self drawMainWindow]; - }); -} - -@end diff --git a/macosx/CreatorWindowController.mm b/macosx/CreatorWindowController.mm index ff841bfb8..081373466 100644 --- a/macosx/CreatorWindowController.mm +++ b/macosx/CreatorWindowController.mm @@ -160,8 +160,8 @@ NSMutableSet* creatorWindowControllerSet = nil; self.window.title = name; - //make window an auxillary view in fullscreen - [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + //disable fullscreen support + [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; self.fNameField.stringValue = name; self.fNameField.toolTip = self.fPath.path; diff --git a/macosx/MessageWindowController.mm b/macosx/MessageWindowController.mm index 7e0e3914a..4b078c4f9 100644 --- a/macosx/MessageWindowController.mm +++ b/macosx/MessageWindowController.mm @@ -66,8 +66,8 @@ self.window.title = NSLocalizedString(@"Message Log", "Message window -> title"); - //make window an auxillary view in fullscreen - [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + //disable fullscreen support + [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; //set images and text for popup button items [self.fLevelButton itemAtIndex:LEVEL_ERROR].title = NSLocalizedString(@"Error", "Message window -> level string"); diff --git a/macosx/PrefsController.mm b/macosx/PrefsController.mm index 8ee80cf89..31c0a070d 100644 --- a/macosx/PrefsController.mm +++ b/macosx/PrefsController.mm @@ -202,8 +202,8 @@ self.window.restorationClass = [self class]; - //make window an auxillary view in fullscreen - [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + //disable fullscreen support + [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; NSToolbar* toolbar = [[NSToolbar alloc] initWithIdentifier:@"Preferences Toolbar"]; toolbar.delegate = self; diff --git a/macosx/StatsWindowController.mm b/macosx/StatsWindowController.mm index e2ff04bc2..750d26e7b 100644 --- a/macosx/StatsWindowController.mm +++ b/macosx/StatsWindowController.mm @@ -69,8 +69,8 @@ tr_session* fLib = NULL; self.window.title = NSLocalizedString(@"Statistics", "Stats window -> title"); - //make window an auxillary view in fullscreen - [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + //disable fullscreen support + [self.window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenNone]; //set label text self.fUploadedLabelField.stringValue = [NSLocalizedString(@"Uploaded", "Stats window -> label") stringByAppendingString:@":"];