diff --git a/README.md b/README.md index f3173b62..65625673 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,20 @@ If you find any problem not mentioned there, please submit an issue. The primary development is done on OSX 10.10, but it should be running under OSX 10.7 as well. ## FAQ +##### How do I turn on/off windows cycling sizes with multiple hotkey presses? + +If this feature is on, snapping to the left side of the screen (and top, bottom, and right sides) will resize the window to half of the screen. If window is then snapped to the same side of the screen, it will resize to one third of the screen, and then two thirds of the screen. + +If the feature is off, additional snappings will have no effect and the window will remain at half of the screen. + +Currently, the only way to accomplish this is by running commands on the command line. To turn the feature on, run: +``` +defaults write org.shiftitapp.ShiftIt multipleActionsCycleWindowSizes YES +``` +To turn it off, run: +``` +defaults write org.shiftitapp.ShiftIt multipleActionsCycleWindowSizes NO +``` ##### I disabled the _Show Icon in Menu Bar_ in the preferences, how can I get it back? diff --git a/ShiftIt/DefaultShiftItActions.h b/ShiftIt/DefaultShiftItActions.h index 4229e413..7e973fa1 100644 --- a/ShiftIt/DefaultShiftItActions.h +++ b/ShiftIt/DefaultShiftItActions.h @@ -22,6 +22,8 @@ #import "ShiftIt.h" BOOL CloseTo(double a, double b); +BOOL rectCloseTo(NSRect a, NSRect b); + const extern SimpleWindowGeometryChangeBlock shiftItLeft; const extern SimpleWindowGeometryChangeBlock shiftItRight; const extern SimpleWindowGeometryChangeBlock shiftItTop; @@ -52,4 +54,4 @@ const extern SimpleWindowGeometryChangeBlock shiftItCenter; - (id) initWithMode:(BOOL)next; -@end \ No newline at end of file +@end diff --git a/ShiftIt/DefaultShiftItActions.m b/ShiftIt/DefaultShiftItActions.m index 81b6a518..11baa4fb 100644 --- a/ShiftIt/DefaultShiftItActions.m +++ b/ShiftIt/DefaultShiftItActions.m @@ -11,7 +11,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see . @@ -22,97 +22,139 @@ #import "ShiftItApp.h" BOOL CloseTo(double a, double b) { - return fabs(a - b) < 20; + return fabs(a - b) < 20; +} + +BOOL rectCloseTo(NSRect a, NSRect b) { + return CloseTo(a.origin.x, b.origin.x) && + CloseTo(a.origin.y, b.origin.y) && + CloseTo(a.size.height, b.size.height) && + CloseTo(a.size.width, b.size.width); } const SimpleWindowGeometryChangeBlock shiftItLeft = ^AnchoredRect(NSRect windowRect, NSSize screenSize) { - NSRect r = NSMakeRect(0, 0, 0, 0); + double screenWidth = screenSize.width; - r.origin.x = 0; - r.origin.y = 0; + NSRect leftHalf = NSMakeRect(0, 0, 0, 0); + leftHalf.origin.x = 0; + leftHalf.origin.y = 0; + leftHalf.size.width = screenSize.width / 2.0; + leftHalf.size.height = screenSize.height; - double w = windowRect.size.width; - double sw = screenSize.width; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL cycle = [defaults boolForKey: kMutipleActionsCycleWindowSizes]; + if(!cycle) { + return MakeAnchoredRect(leftHalf, kLeftDirection); + } - r.size.width = screenSize.width / 2.0; - r.size.height = screenSize.height; + NSRect leftThird = NSMakeRect(0, 0, 0, 0); + leftThird.origin.x = 0; + leftThird.origin.y = 0; + leftThird.size.width = floor(screenWidth * 1.0 / 3.0); + leftThird.size.height = screenSize.height; - if (CloseTo(w, sw / 2.0)) { - r.size.width = floor(sw * 1.0 / 3.0); - } else if (CloseTo(w, sw / 3.0)) { - r.size.width = floor(sw * 2.0 / 3.0); + if(rectCloseTo(windowRect, leftHalf)) { + return MakeAnchoredRect(leftThird, kLeftDirection); + } else if (rectCloseTo(windowRect, leftThird)) { + leftHalf.size.width = floor(screenWidth * 2.0 / 3.0); } - return MakeAnchoredRect(r, kLeftDirection); + + return MakeAnchoredRect(leftHalf, kLeftDirection); }; const SimpleWindowGeometryChangeBlock shiftItRight = ^AnchoredRect(NSRect windowRect, NSSize screenSize) { - NSRect r = NSMakeRect(0, 0, 0, 0); + double screenWidth = screenSize.width; - r.origin.x = screenSize.width / 2; - r.origin.y = 0; + NSRect rightHalf = NSMakeRect(0, 0, 0, 0); + rightHalf.origin.x = screenSize.width / 2; + rightHalf.origin.y = 0; + rightHalf.size.width = screenSize.width / 2.0; + rightHalf.size.height = screenSize.height; - r.size.width = screenSize.width / 2.0; - r.size.height = screenSize.height; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL cycle = [defaults boolForKey: kMutipleActionsCycleWindowSizes]; + if(!cycle) { + return MakeAnchoredRect(rightHalf, kRightDirection); + } - double w = windowRect.size.width; - double sw = screenSize.width; + NSRect rightThird = NSMakeRect(0, 0, 0, 0); + rightThird.origin.x = screenWidth - (screenWidth * 1.0 / 3.0); + rightThird.origin.y = 0; + rightThird.size.width = floor(screenWidth * 1.0 / 3.0); + rightThird.size.height = screenSize.height; - if (CloseTo(w, sw / 2.0)) { - r.size.width = floor(sw * 1.0 / 3.0); - r.origin.x = sw - (sw * 1.0 / 3.0); - } else if (CloseTo(w, sw / 3.0)) { - r.size.width = floor(sw * 2.0 / 3.0); - r.origin.x = sw - (sw * 2.0 / 3.0); + if(rectCloseTo(windowRect, rightHalf)) { + FMTLogDebug(@"Close to half!"); + return MakeAnchoredRect(rightThird, kRightDirection); + } else if (rectCloseTo(windowRect, rightThird)) { + FMTLogDebug(@"Close to third!"); + rightHalf.origin.x = screenWidth - (screenWidth * 2.0 / 3.0); + rightHalf.size.width = floor(screenWidth * 2.0 / 3.0); } - return MakeAnchoredRect(r, kRightDirection); + return MakeAnchoredRect(rightHalf, kRightDirection); }; const SimpleWindowGeometryChangeBlock shiftItTop = ^AnchoredRect(NSRect windowRect, NSSize screenSize) { - NSRect r = NSMakeRect(0, 0, 0, 0); + double screenHeight = screenSize.height; - r.origin.x = 0; - r.origin.y = 0; + NSRect topHalf = NSMakeRect(0, 0, 0, 0); + topHalf.origin.x = 0; + topHalf.origin.y = 0; + topHalf.size.width = screenSize.width; + topHalf.size.height = screenSize.height / 2; - r.size.width = screenSize.width; - r.size.height = screenSize.height / 2; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL cycle = [defaults boolForKey: kMutipleActionsCycleWindowSizes]; + if(!cycle) { + return MakeAnchoredRect(topHalf, kTopDirection); + } - double windowHeight = windowRect.size.height; - double screenHeight = screenSize.height; + NSRect topThird = NSMakeRect(0, 0, 0, 0); + topThird.origin.x = 0; + topThird.origin.y = 0; + topThird.size.width = screenSize.width; + topThird.size.height = floor(screenHeight * 1.0 / 3.0); - if (CloseTo(windowHeight, screenHeight / 2.0)) { - r.size.height = floor(screenHeight * 1.0 / 3.0); - r.origin.y = screenHeight * 1.0 / 3.0; - } else if (CloseTo(windowHeight, screenHeight / 3.0)) { - r.size.height = floor(screenHeight * 2.0 / 3.0); - r.origin.y = screenHeight * 2.0 / 3.0; + if(rectCloseTo(windowRect, topHalf)) { + return MakeAnchoredRect(topThird, kTopDirection); + } else if (rectCloseTo(windowRect, topThird)) { + topHalf.size.height = floor(screenHeight * 2.0 / 3.0); } - return MakeAnchoredRect(r, kTopDirection); + return MakeAnchoredRect(topHalf, kTopDirection); }; const SimpleWindowGeometryChangeBlock shiftItBottom = ^AnchoredRect(NSRect windowRect, NSSize screenSize) { - NSRect r = NSMakeRect(0, 0, 0, 0); + double screenHeight = screenSize.height; - r.origin.x = 0; - r.origin.y = screenSize.height / 2; + NSRect bottomHalf = NSMakeRect(0, 0, 0, 0); + bottomHalf.origin.x = 0; + bottomHalf.origin.y = screenSize.height / 2; + bottomHalf.size.width = screenSize.width; + bottomHalf.size.height = screenSize.height / 2; - r.size.width = screenSize.width; - r.size.height = screenSize.height / 2; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + BOOL cycle = [defaults boolForKey: kMutipleActionsCycleWindowSizes]; + if(!cycle) { + return MakeAnchoredRect(bottomHalf, kBottomDirection); + } - double windowHeight = windowRect.size.height; - double screenHeight = screenSize.height; + NSRect bottomThird = NSMakeRect(0, 0, 0, 0); + bottomThird.origin.x = 0; + bottomThird.origin.y = screenHeight - (screenHeight * 1.0 / 3.0); + bottomThird.size.width = screenSize.width; + bottomThird.size.height = floor(screenHeight * 1.0 / 3.0); - if (CloseTo(windowHeight, screenHeight / 2.0)) { - r.size.height = floor(screenHeight * 1.0 / 3.0); - r.origin.y = screenHeight - (screenHeight * 1.0 / 3.0); - } else if (CloseTo(windowHeight, screenHeight / 3.0)) { - r.size.height = floor(screenHeight * 2.0 / 3.0); - r.origin.y = screenHeight - (screenHeight * 2.0 / 3.0); + if(rectCloseTo(windowRect, bottomHalf)) { + return MakeAnchoredRect(bottomThird, kBottomDirection); + } else if (rectCloseTo(windowRect, bottomThird)) { + bottomHalf.size.height = floor(screenHeight * 2.0 / 3.0); + bottomHalf.origin.y = screenHeight - (screenHeight * 2.0 / 3.0); } - return MakeAnchoredRect(r, kBottomDirection); + return MakeAnchoredRect(bottomHalf, kBottomDirection); }; const SimpleWindowGeometryChangeBlock shiftItTopLeft = ^AnchoredRect(NSRect windowRect, NSSize screenSize) { @@ -189,13 +231,13 @@ BOOL CloseTo(double a, double b) { @implementation IncreaseReduceShiftItAction - (id)initWithMode:(BOOL)increase { - + if (![self init]) { return nil; } increase_ = increase; - + return self; } @@ -240,7 +282,7 @@ - (AnchoredRect)shiftWindowRect:(NSRect)windowRect screenSize:(NSSize)screenSize Margins margins; [windowContext getAnchorMargins:&margins]; - + // target window rect NSRect r = windowRect; // 1: increase, -1: reduce @@ -276,7 +318,7 @@ - (AnchoredRect)shiftWindowRect:(NSRect)windowRect screenSize:(NSSize)screenSize // directions at the same time we do half to each int khorz = (int) (inc * kw); if (directions & kLeftDirection - && directions & kRightDirection) { + && directions & kRightDirection) { khorz /= 2; } @@ -284,7 +326,7 @@ - (AnchoredRect)shiftWindowRect:(NSRect)windowRect screenSize:(NSSize)screenSize // directions at the same time we do half to each int kvert = (int) (inc * kh); if (directions & kTopDirection - && directions & kBottomDirection) { + && directions & kBottomDirection) { kvert /= 2; } @@ -335,16 +377,16 @@ - (BOOL)execute:(id )windowContext error:(NSError **)error { if (![windowContext getFocusedWindow:&window error:&cause]) { *error = SICreateErrorWithCause(kShiftItActionFailureErrorCode, - cause, - @"Unable to get active window"); + cause, + @"Unable to get active window"); return NO; } BOOL flag = NO; if (![window canZoom:&flag error:&cause]) { *error = SICreateErrorWithCause(kShiftItActionFailureErrorCode, - cause, - @"Unable to find out if window can zoom"); + cause, + @"Unable to find out if window can zoom"); } if (!flag) { *error = SICreateError(kShiftItActionFailureErrorCode, @"Window cannot zoom"); @@ -371,16 +413,16 @@ - (BOOL)execute:(id )windowContext error:(NSError **)error { if (![windowContext getFocusedWindow:&window error:&cause]) { *error = SICreateErrorWithCause(kShiftItActionFailureErrorCode, - cause, - @"Unable to get active window"); + cause, + @"Unable to get active window"); return NO; } BOOL flag = NO; if (![window canEnterFullScreen:&flag error:&cause]) { *error = SICreateErrorWithCause(kShiftItActionFailureErrorCode, - cause, - @"Unable to find out if window can enter fullscreen"); + cause, + @"Unable to find out if window can enter fullscreen"); } if (!flag) { *error = SICreateError(kShiftItActionFailureErrorCode, @"Window cannot enter fullscreen"); @@ -414,7 +456,7 @@ - (id)initWithMode:(BOOL)next { - (BOOL)execute:(id )windowContext error:(NSError **)error { FMTAssertNotNil(windowContext); FMTAssertNotNil(error); - + NSError *cause = nil; id window = nil; BOOL flag = NO; @@ -444,7 +486,7 @@ - (BOOL)execute:(id )windowContext error:(NSError **)error { *error = SICreateErrorWithCause(kShiftItActionFailureErrorCode, cause, @"Unable to get window geometry"); - return NO; + return NO; } FMTLogInfo(@"Current window geometry: %@ screen: %@", RECT_STR(currentGeometry), currentScreen); @@ -461,10 +503,10 @@ - (BOOL)execute:(id )windowContext error:(NSError **)error { CGFloat kw = screenSize.width / currentScreenSize.width; CGFloat kh = screenSize.height / currentScreenSize.height; - + NSRect geometry = { - { currentGeometry.origin.x * kw , currentGeometry.origin.y * kh }, - { currentGeometry.size.width * kw , currentGeometry.size.height * kh } + { currentGeometry.origin.x * kw , currentGeometry.origin.y * kh }, + { currentGeometry.size.width * kw , currentGeometry.size.height * kh } }; FMTLogInfo(@"New window geometry: %@ screen %@", RECT_STR(geometry), screen); @@ -482,10 +524,10 @@ - (BOOL)execute:(id )windowContext error:(NSError **)error { @"Unable to anchor window"); return NO; } - + // TODO: make sure window is always visible - + return YES; } -@end \ No newline at end of file +@end diff --git a/ShiftIt/ShiftIt-defaults.plist b/ShiftIt/ShiftIt-defaults.plist index 85b5e979..01662794 100644 --- a/ShiftIt/ShiftIt-defaults.plist +++ b/ShiftIt/ShiftIt-defaults.plist @@ -85,14 +85,16 @@ zoomKeyCode 6 zoomModifiers - 1835008 - nextscreenKeyCode - 45 - nextscreenModifiers + 1835008 + nextscreenKeyCode + 45 + nextscreenModifiers 1835008 previousscreenKeyCode 35 previousscreenModifiers 1835008 + mutipleActionsCycleWindowSizes + diff --git a/ShiftIt/ShiftItApp.h b/ShiftIt/ShiftItApp.h index d660d2b0..e5890dcf 100644 --- a/ShiftIt/ShiftItApp.h +++ b/ShiftIt/ShiftItApp.h @@ -40,6 +40,7 @@ extern NSString *const kWindowSizeDeltaPrefKey; extern NSString *const kScreenSizeDeltaPrefKey; extern NSString *const kAXIncludeDrawersPrefKey; extern NSString *const kAXDriverConvergePrefKey; +extern NSString *const kMutipleActionsCycleWindowSizes; typedef enum { kFixedSizeDeltaType = 3001, diff --git a/ShiftIt/ShiftItAppDelegate.m b/ShiftIt/ShiftItAppDelegate.m index e3502a1f..c5438836 100644 --- a/ShiftIt/ShiftItAppDelegate.m +++ b/ShiftIt/ShiftItAppDelegate.m @@ -48,6 +48,7 @@ NSString *const kFixedSizeHeightDeltaPrefKey = @"fixedSizeHeightDelta"; NSString *const kWindowSizeDeltaPrefKey = @"windowSizeDelta"; NSString *const kScreenSizeDeltaPrefKey = @"screenSizeDelta"; +NSString *const kMutipleActionsCycleWindowSizes = @"multipleActionsCycleWindowSizes"; // AX Driver Options // TODO: should be moved to AX driver @@ -738,4 +739,4 @@ - (NSArray *)feedParametersForUpdater:(SUUpdater *)updater } -@end \ No newline at end of file +@end