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 "progressui.h" 11#include "readstrings.h" 12#include "errors.h" 13 14#define TIMER_INTERVAL 0.2 15 16static float sProgressVal; // between 0 and 100 17static BOOL sQuit = FALSE; 18static StringTable sLabels; 19static const char *sUpdatePath; 20 21@interface UpdaterUI : NSObject 22{ 23 IBOutlet NSProgressIndicator *progressBar; 24 IBOutlet NSTextField *progressTextField; 25} 26@end 27 28@implementation UpdaterUI 29 30-(void)awakeFromNib 31{ 32 NSWindow *w = [progressBar window]; 33 34 [w setTitle:[NSString stringWithUTF8String:sLabels.title]]; 35 [progressTextField setStringValue:[NSString stringWithUTF8String:sLabels.info]]; 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:NO]; 52 [progressBar setDoubleValue:0.0]; 53 54 [[NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self 55 selector:@selector(updateProgressUI:) 56 userInfo:nil repeats:YES] retain]; 57 58 // Make sure we are on top initially 59 [NSApp activateIgnoringOtherApps:YES]; 60} 61 62// called when the timer goes off 63-(void)updateProgressUI:(NSTimer *)aTimer 64{ 65 if (sQuit) { 66 [aTimer invalidate]; 67 [aTimer release]; 68 69 // It seems to be necessary to activate and hide ourselves before we stop, 70 // otherwise the "run" method will not return until the user focuses some 71 // other app. The activate step is necessary if we are not the active app. 72 // This is a big hack, but it seems to do the trick. 73 [NSApp activateIgnoringOtherApps:YES]; 74 [NSApp hide:self]; 75 [NSApp stop:self]; 76 } 77 78 float progress = sProgressVal; 79 80 [progressBar setDoubleValue:(double)progress]; 81} 82 83// leave this as returning a BOOL instead of NSApplicationTerminateReply 84// for backward compatibility 85- (BOOL)applicationShouldTerminate:(NSApplication *)sender 86{ 87 return sQuit; 88} 89 90@end 91 92int 93InitProgressUI(int *pargc, char ***pargv) 94{ 95 sUpdatePath = (*pargv)[1]; 96 97 return 0; 98} 99 100int 101ShowProgressUI() 102{ 103 // Only show the Progress UI if the process is taking a significant amount of 104 // time where a significant amount of time is defined as .5 seconds after 105 // ShowProgressUI is called sProgress is less than 70. 106 usleep(500000); 107 108 if (sQuit || sProgressVal > 70.0f) 109 return 0; 110 111 char path[PATH_MAX]; 112 snprintf(path, sizeof(path), "%s/updater.ini", sUpdatePath); 113 if (ReadStrings(path, &sLabels) != OK) 114 return -1; 115 116 // Continue the update without showing the Progress UI if any of the supplied 117 // strings are larger than MAX_TEXT_LEN (Bug 628829). 118 if (!(strlen(sLabels.title) < MAX_TEXT_LEN - 1 && 119 strlen(sLabels.info) < MAX_TEXT_LEN - 1)) 120 return -1; 121 122 [NSApplication sharedApplication]; 123 [NSBundle loadNibNamed:@"MainMenu" owner:NSApp]; 124 [NSApp run]; 125 126 return 0; 127} 128 129// Called on a background thread 130void 131QuitProgressUI() 132{ 133 sQuit = TRUE; 134} 135 136// Called on a background thread 137void 138UpdateProgressUI(float progress) 139{ 140 sProgressVal = progress; // 32-bit writes are atomic 141} 142