1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2/* vim:set ts=2 sw=2 sts=2 et cindent: */ 3/* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7#import <Cocoa/Cocoa.h> 8#include <stdio.h> 9#include <unistd.h> 10#include "mozilla/Sprintf.h" 11#include "progressui.h" 12#include "readstrings.h" 13#include "updatererrors.h" 14 15#define TIMER_INTERVAL 0.2 16 17static float sProgressVal; // between 0 and 100 18static BOOL sQuit = NO; 19static BOOL sIndeterminate = NO; 20static StringTable sLabels; 21static const char* sUpdatePath; 22 23@interface UpdaterUI : NSObject { 24 IBOutlet NSProgressIndicator* progressBar; 25 IBOutlet NSTextField* progressTextField; 26} 27@end 28 29@implementation UpdaterUI 30 31- (void)awakeFromNib { 32 NSWindow* w = [progressBar window]; 33 34 [w setTitle:[NSString stringWithUTF8String:sLabels.title.get()]]; 35 [progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info.get()]]; 36 37 NSRect origTextFrame = [progressTextField frame]; 38 [progressTextField sizeToFit]; 39 40 int widthAdjust = progressTextField.frame.size.width - origTextFrame.size.width; 41 42 if (widthAdjust > 0) { 43 NSRect f; 44 f.size.width = w.frame.size.width + widthAdjust; 45 f.size.height = w.frame.size.height; 46 [w setFrame:f display:YES]; 47 } 48 49 [w center]; 50 51 [progressBar setIndeterminate:sIndeterminate]; 52 [progressBar setDoubleValue:0.0]; 53 54 [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL 55 target:self 56 selector:@selector(updateProgressUI:) 57 userInfo:nil 58 repeats:YES] retain]; 59 60 // Make sure we are on top initially 61 [NSApp activateIgnoringOtherApps:YES]; 62} 63 64// called when the timer goes off 65- (void)updateProgressUI:(NSTimer*)aTimer { 66 if (sQuit) { 67 [aTimer invalidate]; 68 [aTimer release]; 69 70 // It seems to be necessary to activate and hide ourselves before we stop, 71 // otherwise the "run" method will not return until the user focuses some 72 // other app. The activate step is necessary if we are not the active app. 73 // This is a big hack, but it seems to do the trick. 74 [NSApp activateIgnoringOtherApps:YES]; 75 [NSApp hide:self]; 76 [NSApp stop:self]; 77 } 78 79 float progress = sProgressVal; 80 81 [progressBar setDoubleValue:(double)progress]; 82} 83 84// leave this as returning a BOOL instead of NSApplicationTerminateReply 85// for backward compatibility 86- (BOOL)applicationShouldTerminate:(NSApplication*)sender { 87 return sQuit; 88} 89 90@end 91 92int InitProgressUI(int* pargc, char*** pargv) { 93 sUpdatePath = (*pargv)[1]; 94 95 return 0; 96} 97 98int ShowProgressUI(bool indeterminate) { 99 if (!sUpdatePath) { 100 // InitProgressUI was never called. 101 return -1; 102 } 103 104 // Only show the Progress UI if the process is taking a significant amount of 105 // time where a significant amount of time is defined as .5 seconds after 106 // ShowProgressUI is called sProgress is less than 70. 107 usleep(500000); 108 109 if (sQuit || sProgressVal > 70.0f) { 110 return 0; 111 } 112 113 char path[PATH_MAX]; 114 SprintfLiteral(path, "%s/updater.ini", sUpdatePath); 115 if (ReadStrings(path, &sLabels) != OK) { 116 return -1; 117 } 118 119 sIndeterminate = indeterminate; 120 [NSApplication sharedApplication]; 121 [[NSBundle mainBundle] loadNibNamed:@"MainMenu" owner:NSApp topLevelObjects:nil]; 122 [NSApp run]; 123 124 return 0; 125} 126 127// Called on a background thread 128void QuitProgressUI() { sQuit = YES; } 129 130// Called on a background thread 131void UpdateProgressUI(float progress) { 132 sProgressVal = progress; // 32-bit writes are atomic 133} 134