How to detect if OSX in dark or light mode in Auto Appearance Mode in Catalina - macos

My Mac app needs to change behaviour depending on light or dark mode.
Whats the best way to detect style when Appearance option is selected to auto in macOS Catalina?
NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
id style = [dict objectForKey:#"AppleInterfaceStyle"];
BOOL darkModeOn = ( style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:#"dark"] );
darkModeOn is still yes/dark even after switching from dark to auto appearance option.

you need to combine AppleInterfaceStyle with this new value introduced in macOS Catalina AppleInterfaceStyleSwitchesAutomatically.
Here is some pseudo-code explaining how to:
theme = light //default is light
if macOS_10.15
if UserDefaults(AppleInterfaceStyleSwitchesAutomatically) == TRUE
if UserDefaults(AppleInterfaceStyle) == NIL
theme = dark // is nil, means it's dark and will switch in future to light
else
theme = light //means it's light and will switch in future to dark
endif
else
if UserDefaults(AppleInterfaceStyle) == NIL
theme = light
else
theme = dark
endif
endif
else if macOS_10.14
if UserDefaults(AppleInterfaceStyle) == NIL
theme = light
else
theme = dark
endif
endif
You can check a macOS sample app here: https://github.com/ruiaureliano/macOS-Appearance.
Cheers 💪

In macOS, the best way to find the current effective appearance (what is actually being displayed) is to look at NSApplication.effectiveAppearance. This value is observable with KVO and can be accessed through the NSApp singleton. A good article regarding watching these changes Supporting Dark Mode: Responding to Change which covers observing this particular value.
General macOS note: Reading the configuration settings from the global user preferences will get you what was last stored, but it won't get you whatever interpretation the OS currently has of that value (which, as you've shown in this example, can shift over time). This is what you're running into here. As a general rule, if you find yourself reading NSUserDefaults for keys that are not defined in the API, you should look around for another approach.

Related

How to detect the "Accessibility Reduce Transparency" In macOS (Objective-C)?

By default, macOS11.0 Big Sur set the "reduce transparency" to true on Accessibility. That makes the light status menu almost the same as the dark one, thus make the setting of my app's status menubar icon becomes a challenge.
On iOS, a simple UIKit function could do the trick:
if (UIAccessibilityIsReduceTransparencyEnabled()){
//use the icon for dark mode although we are in light mode now
}
But there is no way to implement it on macOS although the Apple documentation indicated the Availability is iOS 8.0+ and macOS Catalyst 13.0+
Any ideas? Thank you!
You can use the defaults read com.apple.universalaccess reduceTransparency command. It's 1 if it's enabled, and 0 if it's not. In Objective-C that looks something like this:
- (BOOL)isTransparencyEnabled {
Boolean keyExists = false;
Boolean transparencyEnabled = CFPreferencesGetAppBooleanValue( CFSTR("reduceTransparency"), CFSTR("com.apple.universalaccess"), &keyExists);
return keyExists && transparencyEnabled;
}

Is there any way to completely remove the focus border of a wxTextCtrl object on OSX?

I am building a project in OSX (Yosemite) with wxWidgets 3.0.2.
I can remove a blue border around the wxTextCtrl window by using wxBORDER_NONE. But when I put it in a sizer, it has a 3 pixel grey border that I just can't get rid of. What's the point of having 2 borders, one of which cannot be removed? Surely people want to customise more than that?
Is there any possible way to remove it? I don't really want to hack at the wx source, but I will if I have to.
Or is there another way of controlling layout without using sizers, than might cause the border not to appear?
Update: It seems to be the focus highlight border. I don't want it.
Is there any way of disabling the border around the focused UI object? It's so frustrating because it is such a minor thing, but my program is useless if can't remove it.
In case someone else stumbles into this post, this answer is for the updated question:
Update: It seems to be the focus highlight border. I don't want it.
Is there any way of disabling the border around the focused UI object?
Using wxWidgets APIs, NO, there is no way to remove it, since it's a behavior of the native NSTextField class. I was only able to remove it by editing the wx source itself to set the focusRingType property of the underlying NSTextField object to NSFocusRingTypeNone:
File: core/textctrl.mm
Func: wxWidgetImpl::CreateTextControl
NSTextField* v = nil;
if ( style & wxTE_PASSWORD )
v = [[wxNSSecureTextField alloc] initWithFrame:r];
else
v = [[wxNSTextField alloc] initWithFrame:r];
...
// remove glow/border when textfield gets focused
[v setFocusRingType:NSFocusRingTypeNone];
I've also set BORDER_NONE on my wxTextCtrl.
Of course, this sort of changes the standard OS X look-and-feel, so maybe that's why this wasn't exposed as a wxTextCtrl API? Or it breaks something else? But so far it's working OK on my end. Plus, my app needs to have its own custom theme that doesn't go well with the glow border.
I'm using wxWidgets 3.1.0 (cloned from their repo) and OS X 10.12.
This worked for me -on Windows-:
First --> bind the EVT_SET_FOCUS to a styling method.
Second --> reset the fg and bg colours to your original design.
Python code:
button_1.Bind(wx.EVT_SET_FOCUS, focus_without_border)
def focus_without_border(evt=None):
element = evt.GetEventObject()
element.SetForegroundColour( wx.Colour( 241, 241, 241 ) )
element.SetBackgroundColour( wx.Colour( 40, 41, 42 ) )

Variables for colors in interface builder

I have a project that I need to change overall color themes in the app. A lot of my UI elements are built through Interface Builder in Xcode 6.1. I need to set colors as variables in interface builder, so if I set a preprocessor telling the app to use a certain scheme then the colors will change in interface builder. Is this even possible?
I'm not aware of any way to do this with interface builder, however there is a way that you can set appearance properties in code for many IOS UI elements that will then apply globally. As an example see the following snippet of code:
UIToolbar.appearance().tintColor = UIColor.whiteColor()
UIToolbar.appearance().barTintColor = UIColor.blackColor()
UITableView.appearance().separatorColor = UIColor.grayColor()
UITableView.appearance().sectionIndexColor = UIColor.grayColor();
UINavigationBar.appearance().tintColor = UIColor.blueColor()
UINavigationBar.appearance().barTintColor = UIColor.blackColor()
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.whiteColor()]
The code sets a the default tint and bar color for all the UIToolbars, separator and section index colors for all UITableViews, and appearance properties for all the UINavigation views in my app..
You could use #if to set the appearance differently depending on the environment variables set in the compiler.
If you want to find out more about how this works Id suggest reading Apples documentation on UIAppearance properties here:
UIAppearance Documentation
Color variables are awesome, I wish xcode had this too.
Turns out you can add a color variables feature.
This xcode plugin, called Suggested Colors, let's you build and use a palette of colors in Interface Builder. It uses a plist file, So I think you could read that in code and have a color palette shared between code and IB this way. Looks promising. Unfortunately, doesn't seem to work on xcode 6.3.2. Hope it gets fixed.

Highlighting the current line in TextMate 2

In TM 1.x, there was a preferences setting to enable the highlighting of the current line. This option seems to have disappeared in TM2. I assume there is some setting in tm_properties that can be set, but I cannot figure it out. I've tried setting lineHighlight to be a color, but this does not work. Has anyone figured this out?
It is not possible in TM2 yet, but there is an open ticket on github regarding this issue. The lead developer is assigned to it, however it doesn't seem to have that high priority.
Eventually you should be able to do like this:
settings = {
lineHighlight = '#FF483E';
};
This is from the Monokai Theme.
It's possible to set the colour for the current line in the line number and folding column on the left side of the window. Add the following after the first { in the beginning of the theme:
gutterSettings = {
foreground = '#BBBBBB';
background = '#333333';
divider = '#BBBBBB';
selectionBackground = '#FF8800';
selectionForeground = '#000000';
};

Setting printer-specific options on an NSPrintOperation without a panel

this question has bothered me on and off for about a year, and I thought perhaps someone else would have experience with a similar situation.
Goal: on Mac OS X 10.6-7, to print multiple NSViews to EPSON Stylus Pro 4880 printers using a defined resolution and 'high speed' setting, without showing a print panel.
Current situation: I can create successful NSPrintOperations for each NSView, but if I do not show a print panel, it appears the printer's default resolution is used, which is far too high, and slow, for my needs.
Best solution I have so far: I have tried showing the print panel and defining a Mac OS 'preset' which has the correct print resolution and high speed settings already enabled. The downside here is that the Mac preset overrides the number of copies I have set via NSCopies, which is a problem. The other difficulty of course is having someone always around to press the 'OK' button a few thousand times a day.
Where I'm up to
When the NSPrintOperation runs its panel, it has to set the EPSON-specific printer settings somewhere, but I cannot find where it is saved. They don't appear to be set in [NSPrintInfo printSettings].
I have looked at the PPD for the printer, but I can't find the high speed setting anywhere, and the default resolution defined in the PPD is not actually used as the default when printing. It appears EPSON has their own driver settings which are not taken from the PPD I have, and I am not sure how to set them manually.
Basically, running the NSPrintOperation with a print panel and preset overrides all the settings, including the ones I don't want to override. Running it without the print panel leaves all the settings as default, which is not what I want. Can anyone point me in the right direction to find a solution in between those two?
After the NSPrintOperation's runOperation runs with the dialog, look in PMPrintSettings, the printer-specific parameters may be there. I suppose you could persist PMPrintSettings for the future somehow and load the via updateFromPMPrintSettings.
This is unfortunately the best solution I have found so far though I hate to call it 'best', or even a 'solution'. It comes back to this: run an operation with a panel, and then programmatically 'click' the Print button.
[op runOperationModalForWindow: self.window delegate: self didRunSelector: nil contextInfo: nil];
NSPanel *panel = (NSPanel*)self.window.attachedSheet;
for (NSView *view in ((NSView*)panel.contentView).subviews)
{
if (view.class == [NSButton class])
{
NSButton *button = (NSButton*)view;
if ([button.title isEqualToString: #"Print"])
[button performClick: self];
}
}
or
op.runOperationModalForWindow(window, delegate: nil, didRunSelector: nil, contextInfo: nil)
(window.attachedSheet?.contentView.subviews.filter({ $0 is NSButton }) as [NSButton]).filter({ $0.title == "Print" }).first?.performClick(self)
The downside obviously is a window is needed, while I was hoping to run this as a headless server application. I have tried working with Core Printing and PMPrinter/PMPrintSettings and so forth to no avail. The only thing I have not yet tried is talking to CUPS directly. Maybe I'll save that for a rainy day!

Resources