From b2c4e138f18f5c2ff98646add2c712ca74f20d81 Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Mon, 21 Mar 2016 15:48:42 -0700 Subject: [PATCH 1/3] Attempt for MunkiStatus to automagically stay in front of loginwindow PolicyBanner in 10.11+ --- .../MunkiStatus.xcodeproj/project.pbxproj | 2 + .../MunkiStatus/MSUStatusWindowController.py | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/code/apps/MunkiStatus/MunkiStatus.xcodeproj/project.pbxproj b/code/apps/MunkiStatus/MunkiStatus.xcodeproj/project.pbxproj index f98c5487..b1e37e41 100644 --- a/code/apps/MunkiStatus/MunkiStatus.xcodeproj/project.pbxproj +++ b/code/apps/MunkiStatus/MunkiStatus.xcodeproj/project.pbxproj @@ -57,6 +57,7 @@ C046261C1A00016200AF1E48 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; }; C046261D1A00019800AF1E48 /* it */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = it; path = it.lproj/MainMenu.xib; sourceTree = ""; }; C05C3CEE188391F200095E65 /* munki.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = munki.py; path = MunkiStatus/munki.py; sourceTree = SOURCE_ROOT; }; + C06137A51C9CB3BD00EC298E /* BorderlessWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderlessWindow.h; sourceTree = ""; }; C07E956C1913ECEF00B40B9A /* fr */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = fr; path = fr.lproj/MainMenu.xib; sourceTree = ""; }; C07E956D1913ECEF00B40B9A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; C07E956E1913ECF400B40B9A /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = de.lproj/MainMenu.xib; sourceTree = ""; }; @@ -157,6 +158,7 @@ C09004F916CDD84E00BE34CE /* MunkiStatus */ = { isa = PBXGroup; children = ( + C06137A51C9CB3BD00EC298E /* BorderlessWindow.h */, C094B6D31891826700E06897 /* BorderlessWindow.m */, C094B6D41891826700E06897 /* ScaledImageView.h */, C094B6D51891826700E06897 /* ScaledImageView.m */, diff --git a/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py b/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py index 0402fcb2..ee71ef15 100644 --- a/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py +++ b/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py @@ -22,6 +22,8 @@ from objc import YES, NO, IBAction, IBOutlet, nil from PyObjCTools import AppHelper import os +from platform import release + import munki import FoundationPlist @@ -86,6 +88,7 @@ class MSUStatusWindowController(NSObject): timeout_counter = 0 saw_process = False managedsoftwareupdate_pid = None + window_level = NSScreenSaverWindowLevel - 1 @IBAction def stopBtnClicked_(self, sender): @@ -131,6 +134,9 @@ class MSUStatusWindowController(NSObject): # set self.receiving_notifications to False so our process monitoring # thread will exit self.receiving_notifications = False + + def windowDidResignMain_(self, notification): + self.window.orderFrontRegardless() def managedsoftwareupdateStarted_(self, notification): '''Called when we get a @@ -145,9 +151,27 @@ class MSUStatusWindowController(NSObject): com.googlecode.munki.managedsoftwareupdate.ended notification''' NSLog('managedsoftwareupdate pid %s ended' % notification.userInfo().get('pid')) + + def setWindowLevel(self): + '''Sets our NSWindowLevel. Works around issues with the loginwindow + PolicyBanner in 10.11+ Some code based on earlier work by Pepijn + Bruienne''' + # Get our Darwin major version + clientOS = release().split('.')[0] + havePolicyBanner = False + for test_file in ['/Library/Security/PolicyBanner.txt', + '/Library/Security/PolicyBanner.rtf', + '/Library/Security/PolicyBanner.rtfd']: + if os.path.exists(test_file): + havePolicyBanner = True + break + # bump our NSWindowLevel if we have a PolicyBanner in ElCap+ + if havePolicyBanner and clientOS >= 15: + self.window_level = NSScreenSaverWindowLevel def initStatusSession(self): '''Initialize our status session''' + self.setWindowLevel() consoleuser = munki.getconsoleuser() if consoleuser == None or consoleuser == u"loginwindow": self.displayBackdropWindow() @@ -156,7 +180,7 @@ class MSUStatusWindowController(NSObject): if consoleuser == None or consoleuser == u"loginwindow": # needed so the window can show over the loginwindow self.window.setCanBecomeVisibleWithoutLogin_(True) - self.window.setLevel_(NSScreenSaverWindowLevel - 1) + self.window.setLevel_(self.window_level) self.window.center() self.messageFld.setStringValue_( NSLocalizedString(u"Starting…", None)) @@ -235,7 +259,7 @@ class MSUStatusWindowController(NSObject): '''Draw a window that covers the login UI''' if self.backdropWindow: self.backdropWindow.setCanBecomeVisibleWithoutLogin_(True) - self.backdropWindow.setLevel_(NSStatusWindowLevel) + self.backdropWindow.setLevel_(self.window_level) screenRect = NSScreen.mainScreen().frame() self.backdropWindow.setFrame_display_(screenRect, True) @@ -258,12 +282,24 @@ class MSUStatusWindowController(NSObject): self.backdropWindow.setAlphaValue_(0.0) self.backdropWindow.orderFrontRegardless() self.backdropWindow.animator().setAlphaValue_(1.0) + + # preserve the relative ordering of the backdrop window and the status window + # IOW, clicking the backdrop window will not bring it in front of the status window + self.backdropWindow.addChildWindow_ordered_(self.window, NSWindowAbove) + def updateStatus_(self, notification): '''Called when we get a com.googlecode.munki.managedsoftwareupdate.statusUpdate notification; update our status display with information from the notification''' + if self.window_level == NSScreenSaverWindowLevel: + # we're at the loginwindow, there is a PolicyBanner, and we're running + # under 10.11+. Make sure we're in the front. + if not NSApp.isActive(): + NSApp.activateIgnoringOtherApps_(YES) + self.window.orderFrontRegardless() + self.got_status_update = True info = notification.userInfo() # explictly get keys from info object; PyObjC in Mountain Lion @@ -288,6 +324,7 @@ class MSUStatusWindowController(NSObject): command = info.get('command') if command == 'activate': + NSApp.activateIgnoringOtherApps_(YES) self.window.orderFrontRegardless() elif command == 'showRestartAlert': # clean up timer From 495397ec1f3eeba18b7bfb6a91ef1e1f5e38282c Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Tue, 22 Mar 2016 11:44:40 -0700 Subject: [PATCH 2/3] reduce height of titled-box hr; thanks Erik Gomez --- .../Managed Software Center/WebResources/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css b/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css index 3e6b02f0..eabd5783 100644 --- a/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css +++ b/code/apps/Managed Software Center/Managed Software Center/WebResources/base.css @@ -474,7 +474,7 @@ div.titled-box h2, div.titled-box hr { } div.titled-box hr { - margin: 28px 0 + margin: 14px 0 } div.titled-box li.popup { From c69b744685b98de9096369a8de8012b32345a13e Mon Sep 17 00:00:00 2001 From: Greg Neagle Date: Wed, 23 Mar 2016 12:00:08 -0700 Subject: [PATCH 3/3] Create additional masking windows for all secondary displays. --- .../MunkiStatus/MSUStatusWindowController.py | 51 ++++++++++++------- .../MunkiStatus/en.lproj/MainMenu.xib | 17 +++++-- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py b/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py index ee71ef15..372e9967 100644 --- a/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py +++ b/code/apps/MunkiStatus/MunkiStatus/MSUStatusWindowController.py @@ -22,7 +22,6 @@ from objc import YES, NO, IBAction, IBOutlet, nil from PyObjCTools import AppHelper import os -from platform import release import munki import FoundationPlist @@ -157,16 +156,16 @@ class MSUStatusWindowController(NSObject): PolicyBanner in 10.11+ Some code based on earlier work by Pepijn Bruienne''' # Get our Darwin major version - clientOS = release().split('.')[0] - havePolicyBanner = False + darwin_vers = int(os.uname()[2].split('.')[0]) + have_policy_banner = False for test_file in ['/Library/Security/PolicyBanner.txt', '/Library/Security/PolicyBanner.rtf', '/Library/Security/PolicyBanner.rtfd']: if os.path.exists(test_file): - havePolicyBanner = True + have_policy_banner = True break # bump our NSWindowLevel if we have a PolicyBanner in ElCap+ - if havePolicyBanner and clientOS >= 15: + if have_policy_banner and darwin_vers > 14: self.window_level = NSScreenSaverWindowLevel def initStatusSession(self): @@ -255,6 +254,18 @@ class MSUStatusWindowController(NSObject): self.timer.invalidate() self.timer = None + def configureAndDisplayBackdropWindow_(self, window): + '''Sets all our configuration options for our masking windows''' + window.setCanBecomeVisibleWithoutLogin_(True) + window.setLevel_(self.window_level) + translucentColor = NSColor.blackColor().colorWithAlphaComponent_(0.35) + window.setBackgroundColor_(translucentColor) + window.setOpaque_(False) + window.setIgnoresMouseEvents_(False) + window.setAlphaValue_(0.0) + window.orderFrontRegardless() + window.animator().setAlphaValue_(1.0) + def displayBackdropWindow(self): '''Draw a window that covers the login UI''' if self.backdropWindow: @@ -271,18 +282,23 @@ class MSUStatusWindowController(NSObject): self.backdropWindow.orderFrontRegardless() else: # Lion+ - # draw a transparent/translucent window to prevent interaction + # draw transparent/translucent windows to prevent interaction # with the login UI self.backdropImageFld.setHidden_(True) - translucentColor = NSColor.blackColor( - ).colorWithAlphaComponent_(0.35) - self.backdropWindow.setBackgroundColor_(translucentColor) - self.backdropWindow.setOpaque_(False) - self.backdropWindow.setIgnoresMouseEvents_(False) - self.backdropWindow.setAlphaValue_(0.0) - self.backdropWindow.orderFrontRegardless() - self.backdropWindow.animator().setAlphaValue_(1.0) - + self.configureAndDisplayBackdropWindow_(self.backdropWindow) + # are there any other screens? + for screen in NSScreen.screens(): + if screen != NSScreen.mainScreen(): + # create another masking window for this secondary screen + window_rect = screen.frame() + window_rect.origin = NSPoint(0.0, 0.0) + child_window = NSWindow.alloc( + ).initWithContentRect_styleMask_backing_defer_screen_( + window_rect, + NSBorderlessWindowMask, NSBackingStoreBuffered, NO, screen) + self.configureAndDisplayBackdropWindow_(child_window) + self.backdropWindow.addChildWindow_ordered_(child_window, NSWindowAbove) + # preserve the relative ordering of the backdrop window and the status window # IOW, clicking the backdrop window will not bring it in front of the status window self.backdropWindow.addChildWindow_ordered_(self.window, NSWindowAbove) @@ -296,9 +312,8 @@ class MSUStatusWindowController(NSObject): if self.window_level == NSScreenSaverWindowLevel: # we're at the loginwindow, there is a PolicyBanner, and we're running # under 10.11+. Make sure we're in the front. - if not NSApp.isActive(): - NSApp.activateIgnoringOtherApps_(YES) - self.window.orderFrontRegardless() + NSApp.activateIgnoringOtherApps_(YES) + self.window.orderFrontRegardless() self.got_status_update = True info = notification.userInfo() diff --git a/code/apps/MunkiStatus/MunkiStatus/en.lproj/MainMenu.xib b/code/apps/MunkiStatus/MunkiStatus/en.lproj/MainMenu.xib index f098d821..b9ba6274 100644 --- a/code/apps/MunkiStatus/MunkiStatus/en.lproj/MainMenu.xib +++ b/code/apps/MunkiStatus/MunkiStatus/en.lproj/MainMenu.xib @@ -1,13 +1,13 @@ - + - - + + - + @@ -171,6 +171,7 @@