diff --git a/runtime/doc/gui_mac.txt b/runtime/doc/gui_mac.txt index 79552e4e1d..b8f8c9728f 100644 --- a/runtime/doc/gui_mac.txt +++ b/runtime/doc/gui_mac.txt @@ -446,13 +446,13 @@ that is the action that instructs them to paste something.) Menus are configured using the |:macmenu| command and the |:macaction| command can be used to send action messages. - *:maca* *:macaction* -:maca[ction] {action:} Send the message "action:" to the first responder. - The list of allowed actions can be seen by typing + *E9001-M* *:maca* *:macaction* +:maca[ction] {action:} Send the message "action:" to the first responder in + MacVim. The list of allowed actions can be seen by + typing > :maca - An attempt to send an action not listed here will - result in an error. This list is specified in a - property list file called |Actions.plist|. +< An attempt to send an action not listed here will + result in an error. See |macvim-actions| below. *:macm* *:macmenu* :macm[enu] {menu} {key}={arg} ... @@ -466,10 +466,10 @@ can be used to send action messages. For convenience, a menu with "action=name:" which is bound to will act as if bound to - ":maca name:". Thus, if "Menu.Item" is given by + ":maca name:". Thus, if "Menu.Item" is given by > :an Menu.Item :macm Menu.Item action=name: - then ":emenu Menu.Item" is equivalent to +< then ":emenu Menu.Item" is equivalent to ":maca name:". The key equivalent is specified with the @@ -513,18 +513,17 @@ file for more examples on how to set up menus. Note: When no window is open a minimal default menu is used. The default menu is set up in MainMenu.nib which resides in "Resources/English.lproj/" folder inside the app bundle. - *E9001-M* *Actions.plist* -Some action messages would not be suitable to call from within Vim, so there -is a dictionary called "Actions.plist" (in the Resources folder of the -application bundle) which contains all actions that may be called. The key in -this dictionary is the name of the action message (case sensitive), the value -is not used. + *Actions.plist* *macvim-actions* +Some actions (e.g. changing the font size) are not directly Vim related, and +are handled by MacVim on the application level for the GUI. MacVim allows +these actions to be invoked by either directly calling |:macaction| or binding +to a menu via |:macmenu|. The full list of actions can be found in the file +"Actions.plist" (under MacVim.app/Contents/Resources/), but below are the +common ones which might be useful. Hint: The |:macaction| command supports command-line completion so you can enter ":maca" to see a list of all available actions. -Here are some of the actions from Actions.plist which might be useful. - Action Description ~ fileOpen: Show "File Open" dialog findNext: Search forward using the "Find Pasteboard" @@ -543,8 +542,14 @@ performMiniaturize: Minimize window to the dock performZoom: Zoom window (same as clicking the green blob) terminate: Quit MacVim zoomAll: Zoom all windows +zoomLeft: Pin the window to the left of the screen +zoomRight: Pin the window to the right of the screen _cycleWindows: Select next window (similar to ) _cycleWindowsBackwards: Select previous window (similar to ) +_removeWindowFromStageManagerSet Remove window from a Stage Manager Set. Same + as the "Remove Window from Set" menu item. +joinAllStageManagerSets Window will float among all Stage Manager sets +unjoinAllStageManagerSets Window will only show up in its own set ============================================================================== 7. Toolbar *macvim-toolbar* diff --git a/runtime/doc/tags b/runtime/doc/tags index 35c3af79b0..79533dbe6c 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -8371,6 +8371,7 @@ macintosh os_mac.txt /*macintosh* macro map.txt /*macro* macvim gui_mac.txt /*macvim* macvim-PATH gui_mac.txt /*macvim-PATH* +macvim-actions gui_mac.txt /*macvim-actions* macvim-appearance gui_mac.txt /*macvim-appearance* macvim-appearance-mode gui_mac.txt /*macvim-appearance-mode* macvim-autocommands gui_mac.txt /*macvim-autocommands* diff --git a/runtime/menu.vim b/runtime/menu.vim index 9367e4f8c1..27197f51e8 100644 --- a/runtime/menu.vim +++ b/runtime/menu.vim @@ -81,15 +81,16 @@ if has("gui_macvim") an 9998.301 Window.Minimize\ All an 9998.310 Window.Zoom an 9998.311 Window.Zoom\ All + an 9998.318 Window.-SEP1- an 9998.320 Window.Toggle\ Full\ Screen\ Mode :set invfullscreen tln 9998.320 Window.Toggle\ Full\ Screen\ Mode :set invfullscreen - an 9998.330 Window.-SEP1- + an 9998.330 Window.-SEP2- " TODO! Grey out if no tabs are visible. an 9998.340 Window.Show\ Next\ Tab :tabnext tln 9998.340 Window.Show\ Next\ Tab :tabnext an 9998.350 Window.Show\ Previous\ Tab :tabprevious tln 9998.350 Window.Show\ Previous\ Tab :tabprevious - an 9998.360 Window.-SEP2- + an 9998.360 Window.-SEP3- an 9998.370 Window.Bring\ All\ To\ Front an 9998.380 Window.Stay\ in\ Front an 9998.390 Window.Stay\ in\ Back diff --git a/src/MacVim/Actions.plist b/src/MacVim/Actions.plist index 6db599bc62..2415e6b16f 100644 --- a/src/MacVim/Actions.plist +++ b/src/MacVim/Actions.plist @@ -74,11 +74,21 @@ zoomAll: + zoomLeft: + + zoomRight: + stayInFront: stayInBack: stayLevelNormal: + _removeWindowFromStageManagerSet: + + joinAllStageManagerSets: + + unjoinAllStageManagerSets: + diff --git a/src/MacVim/MMWindowController.h b/src/MacVim/MMWindowController.h index e1e83176e2..6bae3ff145 100644 --- a/src/MacVim/MMWindowController.h +++ b/src/MacVim/MMWindowController.h @@ -35,8 +35,8 @@ int updateToolbarFlag; BOOL keepOnScreen; NSString *windowAutosaveKey; - BOOL fullScreenEnabled; - MMFullScreenWindow *fullScreenWindow; + BOOL fullScreenEnabled; ///< Whether full screen is on (native or not) + MMFullScreenWindow *fullScreenWindow; ///< The window used for non-native full screen. Will only be non-nil when in non-native full screen. int fullScreenOptions; BOOL delayEnterFullScreen; NSRect preFullScreenFrame; @@ -127,5 +127,9 @@ - (IBAction)fontSizeDown:(id)sender; - (IBAction)findAndReplace:(id)sender; - (IBAction)zoom:(id)sender; +- (IBAction)zoomLeft:(id)sender; +- (IBAction)zoomRight:(id)sender; +- (IBAction)joinAllStageManagerSets:(id)sender; +- (IBAction)unjoinAllStageManagerSets:(id)sender; @end diff --git a/src/MacVim/MMWindowController.m b/src/MacVim/MMWindowController.m index 8496e8d522..000f057243 100644 --- a/src/MacVim/MMWindowController.m +++ b/src/MacVim/MMWindowController.m @@ -1351,7 +1351,64 @@ - (IBAction)zoom:(id)sender [vimController sendMessage:ZoomMsgID data:data]; } +/// Pin the window to the left of the screen. +/// +/// @note We expose this as a method instead of just having Actions.plist +/// expose NSWindow's private API `_zoomLeft` because it's a little nicer this +/// way instead of having to confuse the user with the underscore, and also so +/// that we can block this while full screen is active. +- (IBAction)zoomLeft:(id)sender +{ + if (fullScreenEnabled) + return; + + // macOS (as of 13.0) doesn't currently have an API to do "zoom left/right" + // aka Aero Snap in Windows, even though macOS 10.15 added UI to do so if + // you hover over the full screen button with Option key pressed. Because + // of that, we have to cheat a little bit and use private APIs + // (_zoomLeft/_zoomRight) which seems to work just fine. We also + // future-proof by detecting if this API gets graduated to public API + // (without the "_") and call that if that exists. + if ([decoratedWindow respondsToSelector:@selector(zoomLeft:)]) { + [decoratedWindow performSelector:@selector(zoomLeft:) withObject:sender]; + } else if ([decoratedWindow respondsToSelector:@selector(_zoomLeft:)]) { + [decoratedWindow performSelector:@selector(_zoomLeft:) withObject:sender]; + } +} + +/// Pin the window to the right of the screen. See zoomLeft: for comments. +- (IBAction)zoomRight:(id)sender +{ + if (fullScreenEnabled) + return; + if ([decoratedWindow respondsToSelector:@selector(zoomRight:)]) { + [decoratedWindow performSelector:@selector(zoomRight:) withObject:sender]; + } else if ([decoratedWindow respondsToSelector:@selector(_zoomRight:)]) { + [decoratedWindow performSelector:@selector(_zoomRight:) withObject:sender]; + } +} + +/// Make this window join all app sets +- (IBAction)joinAllStageManagerSets:(id)sender +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_0 + if (@available(macos 13.0, *)) { + [decoratedWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllApplications]; + } +#endif +} + +/// Make this window only show up in its own set. This is the default, so calling +/// this is only necessary if joinAllStageManagerSets: was previousaly called. +- (IBAction)unjoinAllStageManagerSets:(id)sender +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_13_0 + if (@available(macos 13.0, *)) { + [decoratedWindow setCollectionBehavior:NSWindowCollectionBehaviorPrimary]; + } +#endif +} // -- Services menu delegate -------------------------------------------------