1// This file is part of BOINC. 2// http://boinc.berkeley.edu 3// Copyright (C) 2016 University of California 4// 5// BOINC is free software; you can redistribute it and/or modify it 6// under the terms of the GNU Lesser General Public License 7// as published by the Free Software Foundation, 8// either version 3 of the License, or (at your option) any later version. 9// 10// BOINC is distributed in the hope that it will be useful, 11// but WITHOUT ANY WARRANTY; without even the implied warranty of 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13// See the GNU Lesser General Public License for more details. 14// 15// You should have received a copy of the GNU Lesser General Public License 16// along with BOINC. If not, see <http://www.gnu.org/licenses/>. 17 18// BOINCGUIApp.mm 19 20#include "MacGUI.pch" 21#include "BOINCGUIApp.h" 22#include "BOINCBaseFrame.h" 23#import <Cocoa/Cocoa.h> 24 25#if !wxCHECK_VERSION(3,0,1) 26// This should be fixed after wxCocoa 3.0.0: 27// http://trac.wxwidgets.org/ticket/16156 28 29#ifndef NSEventTypeApplicationDefined 30#define NSEventTypeApplicationDefined NSApplicationDefined 31#endif 32 33// Cocoa routines which are part of CBOINCGUIApp 34// Override standard wxCocoa wxApp::CallOnInit() to allow Manager 35// to run properly when launched hidden on login via Login Item. 36bool CBOINCGUIApp::CallOnInit() { 37 NSAutoreleasePool *mypool = [[NSAutoreleasePool alloc] init]; 38 39 NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined 40 location:NSMakePoint(0.0, 0.0) 41 modifierFlags:0 42 timestamp:0 43 windowNumber:0 44 context:nil 45 subtype:0 data1:0 data2:0]; 46 [NSApp postEvent:event atStart:FALSE]; 47 48 bool retVal = wxApp::CallOnInit(); 49 50 [mypool release]; 51 return retVal; 52} 53#endif 54 55 56// Our application can get into a strange state 57// if our login item launched it hidden and the 58// first time the user "opens" it he either 59// double-clicks on our Finder icon or uses 60// command-tab. It becomes the frontmost 61// application (with its menu in the menubar) 62// but the windows remain hidden, and it does 63// not receive an activate event, so we must 64// handle this case by polling. 65// 66// We can stop the polling after the windows 67// have been shown once, since this state only 68// occurs if the windows have never appeared. 69// 70// TODO: Can we avoid polling by using notification 71// TODO: [NSApplicationDelegate applicationDidUnhide: ] ? 72// 73void CBOINCGUIApp::CheckPartialActivation() { 74 // This code is not needed and has bad effects on OS 10.5. 75 // Initializing wasHidden this way avoids the problem 76 // because we are briefly shown at login on OS 10.5. 77 static bool wasHidden = [ NSApp isHidden ]; 78 79 if (wasHidden) { 80 if (m_bAboutDialogIsOpen) return; 81 82 if (! [ NSApp isHidden ]) { 83 wasHidden = false; 84 ShowInterface(); 85 } 86 } 87} 88 89 90// Returns true if file was modified since system was booted, else false 91// 92bool CBOINCGUIApp::WasFileModifiedBeforeSystemBoot(char * filePath) { 93 NSTimeInterval upTime = [[NSProcessInfo processInfo] systemUptime]; 94 NSString *path = [NSString stringWithUTF8String:filePath]; 95 NSError *error = nil; 96 NSDictionary * attrs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:&error]; 97 if (attrs && !error) { // If file exists, then ... 98 NSDate *fileLastModifiedDate = [attrs fileModificationDate]; 99 NSTimeInterval ageOfFile = -[fileLastModifiedDate timeIntervalSinceNow]; 100 return (ageOfFile > upTime); 101 } 102 103 return false; 104} 105 106 107// HideThisApp() is called from CBOINCGUIApp::ShowApplication(bool) 108// and replaces a call of ShowHideProcess() which is deprecated 109// under OS 10.9. 110void CBOINCGUIApp::HideThisApp() { 111 [ NSApp hide:NSApp ]; 112} 113 114 115/// Determines if the current process is visible. 116/// 117/// @return 118/// true if the current process is visible, otherwise false. 119/// 120bool CBOINCGUIApp::IsApplicationVisible() { 121 return (! [ NSApp isHidden ]); 122} 123 124 125/// 126/// Shows or hides the current process. 127/// 128/// @param bShow 129/// true will show the process, false will hide the process. 130/// 131void CBOINCGUIApp::ShowApplication(bool bShow) { 132 if (bShow) { 133 [ NSApp activateIgnoringOtherApps:YES ]; 134 } else { 135 [ NSApp hide:NSApp ]; 136 } 137} 138 139 140extern bool s_bSkipExitConfirmation; 141 142// Set s_bSkipExitConfirmation to true if cancelled because of logging out or shutting down 143// 144OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) { 145 DescType senderType; 146 Size actualSize; 147 pid_t senderPid; 148 OSStatus anErr; 149 150 // Refuse to quit if a modal dialog is open. 151 // Unfortunately, I know of no way to disable the Quit item in our Dock menu 152 if (wxGetApp().IsModalDialogDisplayed()) { 153 NSBeep(); 154 return userCanceledErr; 155 } 156 157 anErr = AEGetAttributePtr(appleEvt, keySenderPIDAttr, typeSInt32, 158 &senderType, &senderPid, sizeof(senderPid), &actualSize); 159 if (anErr == noErr) { 160 NSString * bundleID = [[NSRunningApplication runningApplicationWithProcessIdentifier:senderPid] bundleIdentifier]; 161 // Consider a Quit command from our Dock menu as coming from this application 162 if (bundleID) { 163 if (([bundleID compare:@"com.apple.dock"] != NSOrderedSame) 164 && ([bundleID compare:@"edu.berkeley.boinc"] != NSOrderedSame)) { 165 s_bSkipExitConfirmation = true; // Not from our app, our dock icon or our taskbar icon 166 // The following may no longer be needed under wxCocoa-3.0.0 167 wxGetApp().ExitMainLoop(); // Prevents wxMac from issuing events to closed frames 168 } 169 } 170 } 171 172 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, wxID_EXIT); 173 wxGetApp().GetFrame()->GetEventHandler()->AddPendingEvent(evt); 174 return noErr; 175} 176