Skip to content

Commit

Permalink
Make the "screen with cursor" preference cause hotkey windows to appe…
Browse files Browse the repository at this point in the history
…ar on

the screen that currently has the cursor.

Revamps the logic for picking the screen to canonicalize the frame to.
Affects the screen used by fitWIndowToTabs. This probably has unintended
consequences but the code is more readable now and there should be fewer
cases where the window randomly moves to the main screen.
  • Loading branch information
George Nachman committed Sep 26, 2016
1 parent 00241e7 commit 943a062
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 102 deletions.
14 changes: 14 additions & 0 deletions sources/PseudoTerminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ extern NSString *const kCurrentSessionDidChange;
// This is useful when attaching to an orphaned server.
@property(nonatomic, assign) BOOL disablePromptForSubstitutions;

// If the window is "anchored" to a screen, this returns that screen. Otherwise, it returns the
// current screen. If the window doesn't have a current screen, it returns the
// preferred screen from the profile. If headless, this returns nil. Consider
// this the preferred screen.
@property(nonatomic, readonly) NSScreen *screen;

// Draws a mock-up of a window arrangement into the current graphics context.
// |frames| gives an array of NSValue's having NSRect values for each screen,
// giving the screens' coordinates in the model.
Expand Down Expand Up @@ -292,5 +298,13 @@ extern NSString *const kCurrentSessionDidChange;

- (NSColor *)accessoryTextColor;

// Update self.screen to reflect the currently preferred screen. In practice,
// this changes self.screen to the screen with the cursor if the window is
// configured to follow it.
- (void)moveToPreferredScreen;

// Returns the preferred frame for the window if it were on a given screen.
- (NSRect)canonicalFrameForScreen:(NSScreen *)screen;

@end

191 changes: 113 additions & 78 deletions sources/PseudoTerminal.m
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,16 @@ @implementation PseudoTerminal {
iTermWindowType windowType_;
// Window type before entering fullscreen. Only relevant if in/entering fullscreen.
iTermWindowType savedWindowType_;
BOOL haveScreenPreference_;
int screenNumber_;

// Indicates if _anchoredScreenNumber is to be used.
BOOL _isAnchoredToScreen;

// The initial screen used for the window. Always >= 0.
int _anchoredScreenNumber;

// // The KEY_SCREEN from the profile the window was created with.
// -2 = follow cursor, -1 = no preference, >= 0 screen number
int _screenNumberFromFirstProfile;

// Window number, used for keyboard shortcut to select a window.
// This value is 0-based while the UI is 1-based.
Expand Down Expand Up @@ -411,6 +419,7 @@ - (void)finishInitializationWithSmartLayout:(BOOL)smartLayout

// Force the nib to load
[self window];
_screenNumberFromFirstProfile = screenNumber;
if ((windowType == WINDOW_TYPE_TRADITIONAL_FULL_SCREEN ||
windowType == WINDOW_TYPE_LION_FULL_SCREEN) &&
screenNumber == -1) {
Expand Down Expand Up @@ -458,13 +467,13 @@ - (void)finishInitializationWithSmartLayout:(BOOL)smartLayout
screen = [[self window] screen];
DLog(@"Screen number %d is out of range [0,%d] so using 0",
screenNumber, (int)[[NSScreen screens] count]);
screenNumber_ = 0;
haveScreenPreference_ = NO;
_anchoredScreenNumber = 0;
_isAnchoredToScreen = NO;
} else if (screenNumber >= 0) {
DLog(@"Selecting screen number %d", screenNumber);
screen = [[NSScreen screens] objectAtIndex:screenNumber];
screenNumber_ = screenNumber;
haveScreenPreference_ = YES;
_anchoredScreenNumber = screenNumber;
_isAnchoredToScreen = YES;
}

desiredRows_ = desiredColumns_ = -1;
Expand Down Expand Up @@ -500,7 +509,7 @@ - (void)finishInitializationWithSmartLayout:(BOOL)smartLayout
// Use the system-supplied frame which has a reasonable origin. It may
// be overridden by smart window placement or a saved window location.
initialFrame = [[self window] frame];
if (haveScreenPreference_) {
if (_isAnchoredToScreen) {
// Move the frame to the desired screen
NSScreen* baseScreen = [[self window] screen];
NSPoint basePoint = [baseScreen visibleFrame].origin;
Expand Down Expand Up @@ -977,18 +986,26 @@ - (PTYTab *)tabWithUniqueId:(int)uniqueId {
return nil;
}

- (NSScreen*)screen {
NSArray* screens = [NSScreen screens];
if (!haveScreenPreference_) {
DLog(@"No screen preference so using the window's current screen");
- (NSScreen *)screen {
NSArray *screens = [NSScreen screens];
if (screens.count == 0) {
DLog(@"We are headless");
return nil;
} else if (_isAnchoredToScreen && _anchoredScreenNumber < screens.count) {
DLog(@"Anchor screen preference %d respected", _anchoredScreenNumber);
return screens[_anchoredScreenNumber];
} else if (self.window.screen) {
DLog(@"Not anchored, or anchored screen does not exist. Using current screen.");
return self.window.screen;
}
if ([screens count] > screenNumber_) {
DLog(@"Screen preference %d respected", screenNumber_);
return screens[screenNumber_];
} else if (_screenNumberFromFirstProfile >= 0 && _screenNumberFromFirstProfile < screens.count) {
DLog(@"Using screen number from first profile %d", _screenNumberFromFirstProfile);
return screens[_screenNumberFromFirstProfile];
} else {
DLog(@"Screen preference %d out of range so using main screen.", screenNumber_);
return [NSScreen mainScreen];
// _screenNumberFromFirstProfile must be no preference (-1), where
// cursor was at creation time (-2), or out of range. We'll use the
// first screen for lack of any better option.
DLog(@"Using first screen because screen number from first profile is %d", _screenNumberFromFirstProfile);
return screens.firstObject;
}
}

Expand Down Expand Up @@ -2530,35 +2547,63 @@ - (void)toolbeltDidFinishGrowing {

- (void)canonicalizeWindowFrame {
PtyLog(@"canonicalizeWindowFrame");
PTYSession* session = [self currentSession];
NSDictionary* abDict = [session profile];
// It's important that this method respect the current screen if possible because
// -windowDidChangeScreen calls it.
NSScreen* screen = [[self window] screen];
if (!screen) {
PtyLog(@"No window screen");
// Try to use the screen of the current session. Fall back to the main
// screen if that's not an option.
NSArray* screens = [NSScreen screens];
int screenNumber = [abDict objectForKey:KEY_SCREEN] ? [[abDict objectForKey:KEY_SCREEN] intValue] : 0;
if (screenNumber == -1) { // No pref
screenNumber = 0;
} else if (screenNumber == -2) { // Where cursor is; respect original preference
if ([screens count] > screenNumber_) {
screenNumber = screenNumber_;
} else {
screenNumber = 0;
}
}
if ([screens count] == 0) {
PtyLog(@"We are headless");
// Nothing we can do if we're headless.
screen = self.screen;
if (!screen) {
// Headless
return;
}
if ([screens count] <= screenNumber) {
PtyLog(@"Using screen 0 because the preferred screen isn't around any more");
screenNumber = 0;
}
switch (windowType_) {
case WINDOW_TYPE_NORMAL:
case WINDOW_TYPE_NO_TITLE_BAR:
case WINDOW_TYPE_LION_FULL_SCREEN:
if ([self updateSessionScrollbars]) {
PtyLog(@"Fitting tabs to window because scrollbars changed.");
[self fitTabsToWindow];
}

case WINDOW_TYPE_TOP:
case WINDOW_TYPE_LEFT:
case WINDOW_TYPE_RIGHT:
case WINDOW_TYPE_BOTTOM:
case WINDOW_TYPE_TOP_PARTIAL:
case WINDOW_TYPE_LEFT_PARTIAL:
case WINDOW_TYPE_RIGHT_PARTIAL:
case WINDOW_TYPE_BOTTOM_PARTIAL: {
NSRect desiredWindowFrame = [self canonicalFrameForScreen:screen];
if (desiredWindowFrame.size.width > 0 && desiredWindowFrame.size.height > 0) {
[[self window] setFrame:desiredWindowFrame display:YES];
}
break;
}

case WINDOW_TYPE_TRADITIONAL_FULL_SCREEN: {
if ([screen frame].size.width > 0) {
// This is necessary when restoring a traditional fullscreen window while scrollbars are
// forced on systemwide.
BOOL changedScrollBars = [self updateSessionScrollbars];
NSRect originalFrame = self.window.frame;
PtyLog(@"set window to screen's frame");

[[self window] setFrame:[self canonicalFrameForScreen:screen] display:YES];

if (changedScrollBars && NSEqualSizes(self.window.frame.size, originalFrame.size)) {
DLog(@"Fitting tabs to window when canonicalizing fullscreen window because of scrollbar change");
[self fitTabsToWindow];
}
}
}
screen = screens[screenNumber];
}

[_contentView updateToolbeltFrame];
}

- (NSRect)canonicalFrameForScreen:(NSScreen *)screen {
PTYSession* session = [self currentSession];
NSRect frame = [[self window] frame];
NSRect screenVisibleFrame = [screen visibleFrame];
NSRect screenVisibleFrameIgnoringHiddenDock = [screen visibleFrameIgnoringHiddenDock];
Expand All @@ -2574,6 +2619,7 @@ - (void)canonicalizeWindowFrame {
switch (windowType_) {
case WINDOW_TYPE_TOP_PARTIAL:
edgeSpanning = NO;
// Fall through
case WINDOW_TYPE_TOP:
PtyLog(@"Window type = TOP, desired rows=%d", desiredRows_);
// If the screen grew and the window was smaller than the desired number of rows, grow it.
Expand All @@ -2593,10 +2639,7 @@ - (void)canonicalizeWindowFrame {
frame.origin.x = screenVisibleFrameIgnoringHiddenDock.origin.x;
}
frame.origin.y = screenVisibleFrame.origin.y + screenVisibleFrame.size.height - frame.size.height;

if (frame.size.width > 0) {
[[self window] setFrame:frame display:YES];
}
return frame;
break;

case WINDOW_TYPE_BOTTOM_PARTIAL:
Expand Down Expand Up @@ -2628,6 +2671,7 @@ - (void)canonicalizeWindowFrame {

case WINDOW_TYPE_LEFT_PARTIAL:
edgeSpanning = NO;
// Fall through
case WINDOW_TYPE_LEFT:
PtyLog(@"Window type = LEFT, desired cols=%d", desiredColumns_);
// If the screen grew and the window was smaller than the desired number of columns, grow it.
Expand All @@ -2648,13 +2692,11 @@ - (void)canonicalizeWindowFrame {
}
frame.origin.x = screenVisibleFrameIgnoringHiddenDock.origin.x;

if (frame.size.width > 0) {
[[self window] setFrame:frame display:YES];
}
break;
return frame;

case WINDOW_TYPE_RIGHT_PARTIAL:
edgeSpanning = NO;
// Fall through
case WINDOW_TYPE_RIGHT:
PtyLog(@"Window type = RIGHT, desired cols=%d", desiredColumns_);
// If the screen grew and the window was smaller than the desired number of columns, grow it.
Expand All @@ -2675,46 +2717,24 @@ - (void)canonicalizeWindowFrame {
}
frame.origin.x = screenVisibleFrameIgnoringHiddenDock.origin.x + screenVisibleFrameIgnoringHiddenDock.size.width - frame.size.width;

if (frame.size.width > 0) {
[[self window] setFrame:frame display:YES];
}
return frame;
break;

case WINDOW_TYPE_NORMAL:
case WINDOW_TYPE_NO_TITLE_BAR:
case WINDOW_TYPE_LION_FULL_SCREEN:
PtyLog(@"Window type = NORMAL, NO_TITLE_BAR, or LION_FULL_SCREEN");
if ([self updateSessionScrollbars]) {
PtyLog(@"Fitting tabs to window because scrollbars changed.");
[self fitTabsToWindow];
}
break;
return self.window.frame;

case WINDOW_TYPE_TRADITIONAL_FULL_SCREEN:
PtyLog(@"Window type = FULL SCREEN");
if ([screen frame].size.width > 0) {
// This is necessary when restoring a traditional fullscreen window while scrollbars are
// forced on systemwide.
BOOL changedScrollBars = [self updateSessionScrollbars];
NSRect originalFrame = self.window.frame;
PtyLog(@"set window to screen's frame");
if (windowType_ == WINDOW_TYPE_TRADITIONAL_FULL_SCREEN) {
[[self window] setFrame:[self traditionalFullScreenFrameForScreen:screen] display:YES];
} else {
[[self window] setFrame:[screen frame] display:YES];
}
if (changedScrollBars && NSEqualSizes(self.window.frame.size, originalFrame.size)) {
DLog(@"Fitting tabs to window when canonicalizing fullscreen window because of scrollbar change");
[self fitTabsToWindow];
}
return [self traditionalFullScreenFrameForScreen:screen];
} else {
return NSZeroRect;
}
break;

default:
break;
}

[_contentView updateToolbeltFrame];
return NSZeroRect;
}

- (void)screenParametersDidChange
Expand Down Expand Up @@ -3621,7 +3641,7 @@ - (void)windowWillShowInitial {
PtyLog(@"windowWillShowInitial");
iTermTerminalWindow* window = [self ptyWindow];
// If it's a full or top-of-screen window with a screen number preference, always honor that.
if (haveScreenPreference_) {
if (_isAnchoredToScreen) {
PtyLog(@"have screen preference is set");
NSRect frame = [window frame];
frame.origin = preferredOrigin_;
Expand All @@ -3631,7 +3651,7 @@ - (void)windowWillShowInitial {
NSUInteger numberOfTerminalWindows = [[[iTermController sharedInstance] terminals] count];
if (numberOfTerminalWindows == 1 ||
![iTermPreferences boolForKey:kPreferenceKeySmartWindowPlacement]) {
if (!haveScreenPreference_ &&
if (!_isAnchoredToScreen &&
[iTermAdvancedSettingsModel rememberWindowPositions]) {
PtyLog(@"No smart layout");
NSRect frame = [window frame];
Expand Down Expand Up @@ -7344,6 +7364,21 @@ - (IBAction)openSelection:(id)sender {
[[self currentSession] openSelection];
}

- (void)moveToPreferredScreen {
if (_screenNumberFromFirstProfile == -2) {
// Return screen with cursor
NSPoint cursor = [NSEvent mouseLocation];
[[NSScreen screens] enumerateObjectsUsingBlock:^(NSScreen * _Nonnull screen, NSUInteger i, BOOL * _Nonnull stop) {
if (NSPointInRect(cursor, screen.frame)) {
_isAnchoredToScreen = YES;
_anchoredScreenNumber = i;
DLog(@"Move window to screen %d %@", (int)i, NSStringFromRect(screen.frame));
*stop = YES;
}
}];
}
}

#pragma mark - Find

- (IBAction)showFindPanel:(id)sender {
Expand Down
Loading

0 comments on commit 943a062

Please sign in to comment.