Commit f0efb2e4 authored by Tim Clem's avatar Tim Clem Committed by Alexandre Julliard

winemac.drv: Hide app's dock icon when it wouldn't have a taskbar item on Windows.

Hide the icon when an app has no visible windows, or when all of its visible windows would have no taskbar entry (i.e., they are owned or have WS_EX_TOOLWINDOW or WS_EX_NOACTIVATE, but not WS_EX_APPWINDOW). The dock icon returns if those conditions are no longer satisfied. This behavior is behind a Mac Driver registry key, EagerDockIconHiding (defaulting to true), to allow toggling it on a per-app or global basis.
parent d6e39da9
......@@ -157,6 +157,7 @@ enum {
- (void) window:(WineWindow*)window isBeingDragged:(BOOL)dragged;
- (void) windowWillOrderOut:(WineWindow*)window;
- (void) maybeHideDockIconDueToWindowOrderingOut:(NSWindow *)window;
- (void) flipRect:(NSRect*)rect;
- (NSPoint) flippedMouseLocation:(NSPoint)point;
......
......@@ -1300,6 +1300,78 @@ static NSString* WineLocalizedString(unsigned int stringID)
[windowsBeingDragged removeObject:window];
}
/* Checks if, discounting the given window, there are any visible windows
that should make the app have a dock icon. window may be nil. anyVisible
will be set to reflect whether any window other than the given one is
visible. */
- (BOOL) shouldHaveDockIconAfterWindowOrdersOut:(NSWindow *)window
anyWindowIsVisible:(BOOL *)anyVisible
{
BOOL foundVisibleWindow = NO;
if (!eager_dock_icon_hiding)
return YES;
for (NSWindow *w in [NSApp windows])
{
if (w != window && (w.isVisible || w.isMiniaturized))
{
foundVisibleWindow = YES;
if ([w isKindOfClass:[WineWindow class]] && !((WineWindow *)w).needsDockIcon)
continue;
return YES;
}
}
if (anyVisible)
*anyVisible = foundVisibleWindow;
return NO;
}
/* If there are no visible windows that should make the app have a dock icon
(other than the provided one), hides the dock icon. window may be nil. */
- (void) maybeHideDockIconDueToWindowOrderingOut:(NSWindow *)window
{
BOOL anyVisibleWindows;
static int isMontereyOrLater = -1;
if (isMontereyOrLater == -1)
{
isMontereyOrLater = 0;
if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)])
{
NSOperatingSystemVersion requiredVersion = { 12, 0, 0 };
isMontereyOrLater = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:requiredVersion];
}
}
if (!eager_dock_icon_hiding)
return;
if (window &&
((!window.isVisible && !window.isMiniaturized) ||
([window isKindOfClass:[WineWindow class]] && !((WineWindow *)window).needsDockIcon)))
{
/* Nothing to do; that window couldn't have changed anything. */
return;
}
if ([NSApp activationPolicy] == NSApplicationActivationPolicyRegular &&
![self shouldHaveDockIconAfterWindowOrdersOut:window
anyWindowIsVisible:&anyVisibleWindows])
{
/* Before macOS 12 Monterey, hiding the dock icon while there are
visible windows makes those windows disappear until they are
programmatically ordered back in. So we don't do that transition
(which should be rather uncommon) on older OSes. */
if (isMontereyOrLater || !anyVisibleWindows)
NSApp.activationPolicy = NSApplicationActivationPolicyAccessory;
}
}
- (void) windowWillOrderOut:(WineWindow*)window
{
if ([windowsBeingDragged containsObject:window])
......@@ -1310,6 +1382,8 @@ static NSString* WineLocalizedString(unsigned int stringID)
[window.queue postEvent:event];
macdrv_release_event(event);
}
[self maybeHideDockIconDueToWindowOrderingOut:window];
}
- (BOOL) isAnyWineWindowVisible
......
......@@ -29,6 +29,7 @@
BOOL disabled;
BOOL noForeground;
BOOL preventsAppActivation;
BOOL needsDockIcon;
BOOL floating;
BOOL resizable;
BOOL maximized;
......@@ -93,6 +94,7 @@
@property (readonly, nonatomic) BOOL disabled;
@property (readonly, nonatomic) BOOL noForeground;
@property (readonly, nonatomic) BOOL preventsAppActivation;
@property (readonly, nonatomic) BOOL needsDockIcon;
@property (readonly, nonatomic) BOOL floating;
@property (readonly, getter=isFullscreen, nonatomic) BOOL fullscreen;
@property (readonly, getter=isFakingClose, nonatomic) BOOL fakingClose;
......
......@@ -1009,6 +1009,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
@synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue;
@synthesize usePerPixelAlpha;
@synthesize himc, commandDone;
@synthesize needsDockIcon;
+ (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
windowFrame:(NSRect)window_frame
......@@ -1048,6 +1049,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
window->savedContentMaxSize = NSMakeSize(FLT_MAX, FLT_MAX);
window->resizable = wf->resizable;
window->_lastDisplayTime = [[NSDate distantPast] timeIntervalSinceReferenceDate];
window->needsDockIcon = wf->dock_icon;
[window registerForDraggedTypes:@[(NSString*)kUTTypeData, (NSString*)kUTTypeContent]];
......@@ -1183,6 +1185,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
NSWindowStyleMaskNonactivatingPanel;
NSUInteger currentStyle = [self styleMask];
NSUInteger newStyle = style_mask_for_features(wf) | (currentStyle & ~usedStyles);
int neededDockIcon;
self.preventsAppActivation = wf->prevents_app_activation;
......@@ -1227,6 +1230,17 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
resizable = wf->resizable;
[self adjustFeaturesForState];
[self setHasShadow:wf->shadow];
// We may need to hide or show our dock icon in response to changes.
neededDockIcon = needsDockIcon;
needsDockIcon = wf->dock_icon; // Need to update this before calling maybeHideDockIcon
if ([self isOrderedIn])
{
if (neededDockIcon && !needsDockIcon)
[[WineApplicationController sharedController] maybeHideDockIconDueToWindowOrderingOut:nil];
else if(!neededDockIcon && needsDockIcon)
[[WineApplicationController sharedController] transformProcessToForeground:!self.preventsAppActivation];
}
}
// Indicates if the window would be visible if the app were not hidden.
......@@ -1739,7 +1753,9 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
WineWindow* parent;
WineWindow* child;
[controller transformProcessToForeground:!self.preventsAppActivation];
if (!eager_dock_icon_hiding || self.needsDockIcon)
[controller transformProcessToForeground:!self.preventsAppActivation];
if ([NSApp isHidden])
[NSApp unhide:nil];
wasVisible = [self isVisible];
......@@ -2110,7 +2126,10 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
if (activate)
{
WineApplicationController *controller = [WineApplicationController sharedController];
[controller transformProcessToForeground:YES];
if (!eager_dock_icon_hiding || self.needsDockIcon)
[controller transformProcessToForeground:YES];
[controller tryToActivateIgnoringOtherApps:YES];
}
......
......@@ -158,6 +158,7 @@ extern CFDictionaryRef localized_strings;
extern int retina_enabled; /* Whether Retina mode is enabled via registry setting. */
extern int retina_on; /* Whether Retina mode is currently active (enabled and display is in default mode). */
extern int enable_app_nap;
extern int eager_dock_icon_hiding;
static inline CGRect cgrect_mac_from_win(CGRect rect)
{
......@@ -521,6 +522,7 @@ struct macdrv_window_features {
unsigned int utility:1;
unsigned int shadow:1;
unsigned int prevents_app_activation:1;
unsigned int dock_icon:1;
};
struct macdrv_window_state {
......
......@@ -60,6 +60,7 @@ int use_precise_scrolling = TRUE;
int gl_surface_mode = GL_SURFACE_IN_FRONT_OPAQUE;
int retina_enabled = FALSE;
int enable_app_nap = FALSE;
int eager_dock_icon_hiding = TRUE;
CFDictionaryRef localized_strings;
......@@ -378,6 +379,9 @@ static void setup_options(void)
if (!get_config_key(hkey, appkey, "EnableAppNap", buffer, sizeof(buffer)))
enable_app_nap = IS_OPTION_TRUE(buffer[0]);
if (!get_config_key(hkey, appkey, "EagerDockIconHiding", buffer, sizeof(buffer)))
eager_dock_icon_hiding = IS_OPTION_TRUE(buffer[0]);
/* Don't use appkey. The DPI and monitor sizes should be consistent for all
processes in the prefix. */
if (!get_config_key(hkey, NULL, "RetinaMode", buffer, sizeof(buffer)))
......
......@@ -59,6 +59,14 @@ static void get_cocoa_window_features(struct macdrv_win_data *data,
if (ex_style & WS_EX_NOACTIVATE) wf->prevents_app_activation = TRUE;
/* The dock_icon flag is only relevant when the window is visible, so we
don't need to worry about any other styles or the window rect. */
if (NtUserGetWindowRelative(data->hwnd, GW_OWNER))
wf->dock_icon = FALSE;
else
wf->dock_icon = (ex_style & WS_EX_APPWINDOW) ||
((ex_style & (WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE)) == 0);
if (disable_window_decorations) return;
if (IsRectEmpty(window_rect)) return;
if (EqualRect(window_rect, client_rect)) return;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment