macOS revert fullscreen changes (#3304)

* macOS remove NSWindow subclass

as discussed in #3297
This commit is contained in:
SweetPPro
2022-06-16 19:55:33 +02:00
committed by GitHub
parent 037f1bf403
commit c6b49e99d8
12 changed files with 443 additions and 409 deletions

View File

@@ -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<Torrent*>* fTorrents;
@property(nonatomic, readonly) NSMutableArray* fDisplayedTorrents;
@property(nonatomic, readonly) NSMutableDictionary<NSString*, Torrent*>* 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<NSString*>* fAutoImportedNames;
@property(nonatomic) NSTimer* fAutoImportTimer;
@property(nonatomic) NSMutableDictionary<NSURL*, id>* fPendingTorrentDownloads;
@property(nonatomic) NSMutableSet<Torrent*>* fAddingTransfers;
@property(nonatomic) NSMutableSet<NSWindowController*>* 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