boinc/client/mac/mac_main.cpp

960 lines
35 KiB
C++
Executable File

// The contents of this file are subject to the BOINC Public License
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://boinc.berkeley.edu/license_1.0.txt
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
//
// The Initial Developer of the Original Code is the SETI@home project.
// Portions created by the SETI@home project are Copyright (C) 2002
// University of California at Berkeley. All Rights Reserved.
//
// Contributor(s):
//
#include <math.h>
#include <stdio.h>
#include <string.h>
// project includes ---------------------------------------------------------
#include "mac_main.h"
#include "mac_join.h"
#include "mac_about.h"
#include "mac_prefs.h"
#include "account.h"
#include "client_state.h"
#include "log_flags.h"
#include "message.h"
#include "gui_titles.h"
#include "util.h"
// statics/globals (internal only) ------------------------------------------
WindowRef boincWindow;
EventLoopTimerRef boincTimer,boincIdleTimer;
EventLoopTimerUPP boincTimerUPP,boincIdleUPP;
EventHandlerUPP appCommandProcessor,winCommandProcessor;
WindowPtr boincAboutWindow;
Point oldMouse;
KeyMap oldKeys;
UInt32 user_idle_since,user_idle_length;
vector<MESSAGE*> msgs;
ControlRef tabControl;
int winXPos, winYPos, winWidth, winHeight;
int tabList[] = {5, 129, 130, 131, 132, 133}; // Tab UserPane IDs
int lastTabIndex = 1;
MenuRef dockMenu, fileMenu;
MenuItemIndex dockSuspendIndex, dockResumeIndex;
MenuItemIndex fileSuspendIndex, fileResumeIndex;
bool user_requested_exit = false;
ControlRef boincDataBrowsers[MAX_LIST_ID];
DataBrowserPropertyType column_types[MAX_LIST_ID][MAX_COLS] = {
{kDataBrowserTextType, kDataBrowserTextType, kDataBrowserTextType, kDataBrowserTextType, kDataBrowserProgressBarType, NULL, NULL},
{kDataBrowserTextType, kDataBrowserTextType, kDataBrowserTextType, kDataBrowserTextType, kDataBrowserProgressBarType, kDataBrowserTextType, kDataBrowserTextType},
{kDataBrowserTextType, kDataBrowserTextType, kDataBrowserProgressBarType, kDataBrowserTextType, kDataBrowserTextType, kDataBrowserTextType, NULL},
{kDataBrowserTextType, kDataBrowserDateTimeType, kDataBrowserTextType, NULL, NULL, NULL, NULL}
};
DataBrowserItemDataUPP carbonItemCallbacks[MAX_LIST_ID] =
{BOINCCarbonProjectCallback, BOINCCarbonWorkCallback, BOINCCarbonTransferCallback, BOINCCarbonMessageCallback};
void Syncronize(ControlRef prog, vector<void*>* vect);
// --------------------------------------------------------------------------
OSStatus InitMainWindow(void) {
OSStatus err;
Handle boincMenuBar;
ControlID ctrlID;
IBNibRef boincNibRef;
int i,n;
DataBrowserCallbacks callbacks;
InitCursor();
// Search for the "boinc" .nib file
err = CreateNibReference(CFSTR("boinc"), &boincNibRef);
if ( err != noErr ) {
fprintf(stderr, "Can't load boinc.nib. Err: %d\n", (int)err);
ExitToShell();
}
// Init Menus
err = CreateMenuBarFromNib(boincNibRef, CFSTR("MainMenu"), &boincMenuBar);
if ( err != noErr ) {
fprintf(stderr, "Can't load MenuBar. Err: %d\n", (int)err);
ExitToShell();
}
err = CreateWindowFromNib(boincNibRef, CFSTR("Client Window"), &boincWindow);
if (err != noErr) {
fprintf(stderr, "Can't load Window. Err: %d\n", (int)err);
ExitToShell();
}
ReadBOINCPreferences();
// Enable the preferences item
EnableMenuCommand(NULL, kHICommandPreferences);
// Add the columns to the data browsers
for (i=0;i<MAX_LIST_ID;i++) {
ctrlID.signature = kBOINCDataBrowserSig;
ctrlID.id = 128+i;
err = GetControlByID( boincWindow, &ctrlID, &boincDataBrowsers[i] ); // Projects DataBrowser
if (err != noErr) return err;
for (n=0;n<MAX_COLS;n++) {
if (strlen(g_szColumnTitles[i][n])) {
err = AddColumnToList( boincDataBrowsers[i], g_szColumnTitles[i][n], n, column_types[i][n] );
if (err != noErr) return err;
}
if (column_types[i][n] == kDataBrowserProgressBarType) {
err = SetDataBrowserItemDataMinimum( boincDataBrowsers[i], 0 );
err = SetDataBrowserItemDataMaximum( boincDataBrowsers[i], 100 );
}
}
callbacks.version = kDataBrowserLatestCallbacks;
err = InitDataBrowserCallbacks( &callbacks );
if (err != noErr) return err;
callbacks.u.v1.itemDataCallback = carbonItemCallbacks[i];
err = SetDataBrowserCallbacks( boincDataBrowsers[i], &callbacks );
if (err != noErr) return err;
}
InstallTabHandler(boincWindow);
SelectItemOfTabControl(tabControl);
//err = AddFileMenu();
if (err != noErr) return err;
SetMenuBar(boincMenuBar);
SizeWindow( boincWindow, winWidth, winHeight, true );
MoveWindow( boincWindow, winXPos, winYPos, false );
ShowWindow(boincWindow);
err = AddDockMenu();
if (err != noErr) return err;
SuspendBOINC(gstate.suspend_requested);
// Application-level event handler installer
appCommandProcessor = NewEventHandlerUPP(MainAppEventHandler);
err = InstallApplicationEventHandler(appCommandProcessor, GetEventTypeCount(appEventList), appEventList, 0, NULL);
if (err != noErr) return err;
err = InstallMenuEventHandler(dockMenu, appCommandProcessor, GetEventTypeCount(appEventList), appEventList, 0, NULL);
if (err != noErr) return err;
// Window-level event handler installer
winCommandProcessor = NewEventHandlerUPP(MainWinEventHandler);
err = InstallWindowEventHandler(boincWindow, winCommandProcessor, GetEventTypeCount(winEventList), winEventList, 0, NULL);
if (err != noErr) return err;
// BOINC Timed event handler installer
boincTimerUPP = NewEventLoopTimerUPP(BOINCPollLoopProcessor);
err = InstallEventLoopTimer(GetCurrentEventLoop(), 0, kEventDurationMillisecond*100, boincTimerUPP, NULL, &boincTimer);
if (err != noErr) return err;
// BOINC Timed event handler installer
boincIdleUPP = NewEventLoopTimerUPP(BOINCIdleDetect);
err = InstallEventLoopTimer(GetCurrentEventLoop(), 0, kEventDurationMillisecond*100, boincIdleUPP, NULL, &boincIdleTimer);
if (err != noErr) return err;
DisposeNibReference(boincNibRef);
return noErr;
}
OSStatus AddDockMenu( void ) {
OSStatus myErr;
myErr = CreateNewMenu( 140, 0, &dockMenu );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( dockMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "Suspend", kCFStringEncodingMacRoman),
0, kBOINCCommandSuspend, &dockSuspendIndex );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( dockMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "Resume", kCFStringEncodingMacRoman),
0, kBOINCCommandResume, &dockResumeIndex );
if (myErr != noErr) return myErr;
myErr = SetApplicationDockTileMenu(dockMenu);
if (myErr != noErr) return myErr;
return noErr;
}
OSStatus AddFileMenu( void ) {
OSStatus myErr;
myErr = CreateNewMenu( 129, 0, &fileMenu );
if (myErr != noErr) return myErr;
myErr = SetMenuTitleWithCFString( fileMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "File2", kCFStringEncodingMacRoman) );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( fileMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "Show Graphics", kCFStringEncodingMacRoman),
0, kBOINCShowGraphics, NULL );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( fileMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "Clear Messages", kCFStringEncodingMacRoman),
0, kBOINCClearMessages, NULL );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( fileMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "", kCFStringEncodingMacRoman),
kMenuItemAttrSeparator, 0, NULL );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( fileMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "Suspend", kCFStringEncodingMacRoman),
0, kBOINCCommandSuspend, &fileSuspendIndex );
if (myErr != noErr) return myErr;
myErr = AppendMenuItemTextWithCFString( fileMenu,
CFStringCreateWithCString(CFAllocatorGetDefault(), "Resume", kCFStringEncodingMacRoman),
0, kBOINCCommandResume, &fileResumeIndex );
if (myErr != noErr) return myErr;
InsertMenu( fileMenu, 0 );
return noErr;
}
OSStatus AddColumnToList( ControlRef theList, char *columnName, DataBrowserPropertyID propertyID, DataBrowserPropertyType propertyType ) {
DataBrowserListViewColumnDesc columnDesc;
columnDesc.headerBtnDesc.btnContentInfo.contentType = 0;
columnDesc.headerBtnDesc.btnContentInfo.u.resID = 0;
columnDesc.headerBtnDesc.btnFontStyle.flags = kControlUseThemeFontIDMask;
columnDesc.headerBtnDesc.btnFontStyle.font = kControlFontViewSystemFont;
columnDesc.propertyDesc.propertyID = propertyID;
columnDesc.propertyDesc.propertyType = propertyType;
columnDesc.propertyDesc.propertyFlags = kDataBrowserDefaultPropertyFlags;
columnDesc.headerBtnDesc.version = kDataBrowserListViewLatestHeaderDesc;
columnDesc.headerBtnDesc.minimumWidth = 0;
columnDesc.headerBtnDesc.maximumWidth = 230;
columnDesc.headerBtnDesc.initialOrder = kDataBrowserOrderIncreasing; // ?
columnDesc.headerBtnDesc.titleOffset = 0;
columnDesc.headerBtnDesc.titleString = CFStringCreateWithCString(
CFAllocatorGetDefault(), columnName, kCFStringEncodingMacRoman);
return AddDataBrowserListViewColumn( theList, &columnDesc, ULONG_MAX );
}
bool CheckIfIdle( void ) {
if (gstate.global_prefs.idle_time_to_run > 0) {
if (user_idle_length > 60 * gstate.global_prefs.idle_time_to_run) { // Is there a defined constant we can use instead of 60?
return true;
} else {
return false;
}
} else {
return true;
}
}
////////////////////////////////////////////////////////
// BOINCPollLoopProcessor //
////////////////////////////////////////////////////////
pascal void BOINCPollLoopProcessor(EventLoopTimerRef inTimer, void* timeData)
{
gstate.user_idle = CheckIfIdle();
// While we still have something to do we keep processing,
// otherwise, we go back to sleep
while (gstate.do_something()) {
if (gstate.time_to_exit()) {
break;
}
}
Syncronize( boincDataBrowsers[0], (vector<void*>*)(&gstate.projects) );
Syncronize( boincDataBrowsers[1], (vector<void*>*)(&gstate.results) );
Syncronize( boincDataBrowsers[2], (vector<void*>*)(&gstate.pers_xfers->pers_file_xfers) );
Syncronize( boincDataBrowsers[3], (vector<void*>*)(&msgs) );
GUIRedraw();
fflush(stdout);
}
/////////////////////////////////////////////////////
// BOINCIdleDetect //
/////////////////////////////////////////////////////
pascal void BOINCIdleDetect(EventLoopTimerRef inTimer, void* timeData)
{
Point curMouse;
KeyMap curKeys;
int i;
UInt32 curTime;
curTime = TickCount();
// See if the mouse has moved
GetMouse( &curMouse );
if (curMouse.h != oldMouse.h || curMouse.v != oldMouse.v) {
user_idle_since = curTime;
}
oldMouse.h = curMouse.h;
oldMouse.v = curMouse.v;
// See if user has pressed the mouse button
if (Button())
user_idle_since = curTime;
// See if any keys have been pressed
GetKeys( curKeys );
for (i=0;i<4;i++) {
if (oldKeys[i] != curKeys[i]) {
user_idle_since = curTime;
}
oldKeys[i] = curKeys[i];
}
user_idle_length = curTime - user_idle_since;
}
//////////////////////////////////////////////////////////////////////////////////
// SuspendBOINC //
//////////////////////////////////////////////////////////////////////////////////
void SuspendBOINC( bool suspend ) {
gstate.suspend_requested = suspend;
if (suspend) {
DisableMenuItem( dockMenu, dockSuspendIndex );
DisableMenuItem( fileMenu, fileSuspendIndex );
EnableMenuItem( dockMenu, dockResumeIndex );
EnableMenuItem( fileMenu, fileResumeIndex );
} else {
DisableMenuItem( dockMenu, dockResumeIndex );
DisableMenuItem( fileMenu, fileResumeIndex );
EnableMenuItem( dockMenu, dockSuspendIndex );
EnableMenuItem( fileMenu, fileSuspendIndex );
}
}
//////////////////////////////////////////////////////////////////////////////////
// MainAppEventHandler //
//////////////////////////////////////////////////////////////////////////////////
pascal OSStatus MainAppEventHandler(EventHandlerCallRef appHandler, EventRef theEvent, void* appData)
{
#pragma unused (appHandler, appData)
HICommand aCommand;
OSStatus result;
switch(GetEventClass(theEvent))
{
case kEventClassCommand:
result = GetEventParameter(theEvent, kEventParamDirectObject,
typeHICommand, NULL, sizeof(HICommand),
NULL, &aCommand);
switch (aCommand.commandID)
{
case kHICommandQuit:
QuitApplicationEventLoop();
result = noErr;
break;
case kHICommandPreferences: // 'pref'
// Open prefs dialog
//CreatePrefsDialog();
result = noErr;
break;
case kBOINCCommandJoin: // 'join'
char new_master_url[256], new_auth[256];
// Open join dialog
if (CreateJoinDialog( new_master_url, new_auth ) ) {
gstate.add_project( new_master_url, new_auth );
}
result = noErr;
break;
case kBOINCCommandSuspend: // 'susp'
// Suspend processing
SuspendBOINC(true);
result = noErr;
break;
case kBOINCCommandResume: // 'resm'
// Resume processing
SuspendBOINC(false);
result = noErr;
break;
case kHICommandAbout: // 'abou'
// Open About window
CreateAboutWindow();
result = noErr;
break;
default:
result = eventNotHandledErr;
break;
}
break;
default:
result = eventNotHandledErr;
break;
}
return result;
}
//////////////////////////////////////////////////////////////////////////////////
// MainWinEventHandler //
//////////////////////////////////////////////////////////////////////////////////
pascal OSStatus MainWinEventHandler(EventHandlerCallRef appHandler, EventRef theEvent, void* appData)
{
#pragma unused (appHandler, appData)
OSStatus result;
UInt32 attributes;
Rect winRect;
switch(GetEventClass(theEvent))
{
case kEventClassWindow:
GetEventParameter(theEvent, kEventParamAttributes, typeUInt32, NULL, sizeof(UInt32), NULL, &attributes);
switch(GetEventKind(theEvent)) {
case kEventWindowBoundsChanged:
GetEventParameter(theEvent, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &winRect);
winXPos = winRect.left;
winYPos = winRect.top;
winWidth = winRect.right - winRect.left;
winHeight = winRect.bottom - winRect.top;
if (attributes & kWindowBoundsChangeSizeChanged) {
SizeControl( tabControl, winWidth, winHeight-12 );
for (int i=0;i<4;i++ )
SizeControl( boincDataBrowsers[i], winWidth-30-9, winHeight-49-30 );
}
break;
default:
result = eventNotHandledErr;
break;
}
break;
default:
result = eventNotHandledErr;
break;
}
return result;
}
// --------------------------------------------------------------------------
OSStatus mac_setup (void)
{
OSStatus err;
err = InitMainWindow();
if (err != noErr) return err;
RunApplicationEventLoop();
return true;
}
// --------------------------------------------------------------------------
void mac_cleanup (void)
{
RemoveEventLoopTimer(boincTimer);
DisposeEventLoopTimerUPP(boincTimerUPP);
DisposeEventHandlerUPP(appCommandProcessor);
}
// --------------------------------------------------------------------------
int main(int argc, char** argv) {
read_log_flags();
gstate.parse_cmdline(argc, argv);
if (gstate.init()) return -1;
// mac_setup won't return until the main application loop has quit
if (!mac_setup()) return -1;
// Afterwards, we clean up and exit
gstate.cleanup_and_exit();
SaveBOINCPreferences();
mac_cleanup();
}
// Check if we're running OS 8/9 or OS X
/*pm_features = PMFeatures();
// If the we can get the battery info from this API, do it
if ((pm_features>>canGetBatteryTime)&0x01) {
err = BatteryStatus( &a, &b );
if (err != noErr); // do something
} else
fprintf( stderr, "%d %d", a, b );
exit(0);*/
// --------------------------------------------------------------------------
void show_message(PROJECT *p, char* message, int priority) {
MESSAGE *new_msg;
new_msg = (MESSAGE*)malloc(sizeof(MESSAGE));
GetDateTime( &new_msg->timestamp );
safe_strncpy( new_msg->msg, message, sizeof(new_msg->msg) );
if (p)
safe_strncpy( new_msg->project, p->get_project_name(), sizeof(new_msg->msg) );
else
safe_strncpy( new_msg->project, "BOINC", sizeof(new_msg->msg) );
msgs.push_back(new_msg);
}
//
int add_new_project() {
return 0;
}
// ----------------------------------------------------------------------
// Show the selected pane, hide the others.
void SelectItemOfTabControl(ControlRef myTabControl) {
ControlRef userPane;
ControlRef selectedPane = NULL;
ControlID controlID;
UInt16 i;
SInt16 index = GetControlValue(myTabControl);
lastTabIndex = index;
controlID.signature = TAB_SIGNATURE;
for (i = 1; i < tabList[0] + 1; i++) {
controlID.id = tabList[i];
GetControlByID(GetControlOwner(myTabControl), &controlID, &userPane);
if (i == index) {
selectedPane = userPane;
SetControlVisibility(boincDataBrowsers[i-1],true,true);
} else {
SetControlVisibility(userPane,false,false);
SetControlVisibility(boincDataBrowsers[i-1],false,false);
DisableControl(userPane);
}
}
if (selectedPane != NULL) {
EnableControl(selectedPane);
SetControlVisibility(selectedPane, true, true);
}
SizeControl( tabControl, winWidth, winHeight-12 );
Draw1Control(myTabControl);
for (int i=0;i<4;i++ )
SizeControl( boincDataBrowsers[i], winWidth-30-9, winHeight-49-30 );
}
// ----------------------------------------------------------------------
// Listen to events. Only switch if the tab value has changed.
pascal OSStatus TabEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *inUserData)
{
OSStatus result = eventNotHandledErr;
ControlRef theControl;
ControlID controlID;
GetEventParameter(inEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof( ControlRef ), NULL, &theControl );
GetControlID(theControl, &controlID);
// If this event didn't trigger a tab change, give somebody else a chance to handle it.
if (controlID.id == TAB_ID && GetControlValue(theControl) != lastTabIndex) {
result = noErr;
SelectItemOfTabControl(theControl);
}
return result;
}
// ----------------------------------------------------------------------
void InstallTabHandler(WindowRef window)
{
EventTypeSpec controlSpec = { kEventClassControl, kEventControlHit }; // event class, event kind
ControlID controlID;
// Find the tab control and install an event handler on it.
controlID.signature = TAB_SIGNATURE;
controlID.id = TAB_ID;
GetControlByID(window, &controlID, &tabControl);
InstallEventHandler(GetControlEventTarget(tabControl), NewEventHandlerUPP( TabEventHandler ),
1, &controlSpec, 0, NULL);
//Select the active tab to start with.
lastTabIndex = GetControlValue(tabControl);
SelectItemOfTabControl(tabControl);
}
// Force a redraw of the GUI elements
//
void GUIRedraw(void) {
DataBrowserItemID items;
items = kDataBrowserNoItem;
for (int i=0;i<MAX_LIST_ID;i++ ) {
UpdateDataBrowserItems( boincDataBrowsers[i], kDataBrowserNoItem, 1, &items, kDataBrowserItemNoProperty, kDataBrowserNoItem );
}
}
OSStatus BOINCCarbonProjectCallback( ControlRef browser, DataBrowserItemID itemID,
DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue) {
OSStatus err;
char buf[256];
unsigned int i;
PROJECT *p = (PROJECT*)itemID;
float totalres = 0;
if (!changeValue) {
sprintf( buf, " " );
switch (property) {
case 0: // Project name
safe_strncpy( buf, p->get_project_name(), sizeof(buf) );
break;
case 1: // Account name
safe_strncpy( buf, p->user_name, sizeof(buf) );
break;
case 2: // Total credit
sprintf( buf, "%0.2f", p->user_total_credit);
break;
case 3: // Average credit
sprintf( buf, "%0.2f", p->user_expavg_credit);
break;
case 4: // Resource share
for(i = 0; i < gstate.projects.size(); i ++) {
totalres += gstate.projects[i]->resource_share;
}
if (totalres <= 0)
SetDataBrowserItemDataValue( itemData, 100 );
else
SetDataBrowserItemDataValue( itemData, (int)((100 * p->resource_share)/totalres) );
break;
default:
break;
}
err = SetDataBrowserItemDataText( itemData, CFStringCreateWithCString(CFAllocatorGetDefault(), buf, kCFStringEncodingMacRoman));
}
return noErr;
}
OSStatus BOINCCarbonWorkCallback( ControlRef browser, DataBrowserItemID itemID,
DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue) {
OSStatus err;
char buf[256];
RESULT *re = (RESULT*)itemID;
ACTIVE_TASK* at;
int cpuhour, cpumin, cpusec;
if (!changeValue) {
sprintf( buf, " " );
switch (property) {
case 0: // Project name
safe_strncpy( buf, re->project->project_name, sizeof(buf) );
break;
case 1: // App name
safe_strncpy( buf, re->app->name, sizeof(buf) );
break;
case 2: // Workunit name
safe_strncpy( buf, re->name, sizeof(buf) );
break;
case 3: // CPU time
double cur_cpu;
at = gstate.lookup_active_task_by_result(re);
if (at) {
cur_cpu = at->current_cpu_time;
} else {
cur_cpu = 0;
}
cpuhour = (int)(cur_cpu / (60 * 60));
cpumin = (int)(cur_cpu / 60) % 60;
cpusec = (int)(cur_cpu) % 60;
sprintf( buf, "%02d:%02d:%02d", cpuhour, cpumin, cpusec);
break;
case 4: // Progress
at = gstate.lookup_active_task_by_result(re);
if(!at) {
SetDataBrowserItemDataValue(itemData, 0);
} else {
SetDataBrowserItemDataValue(itemData, (int)(at->fraction_done * 100));
}
break;
case 5: // Time to completion
double tocomp;
if(!at || at->fraction_done == 0) {
tocomp = gstate.estimate_cpu_time(*re->wup);
} else {
tocomp = at->est_time_to_completion();
}
cpuhour = (int)(tocomp / (60 * 60));
cpumin = (int)(tocomp / 60) % 60;
cpusec = (int)(tocomp) % 60;
sprintf( buf, "%02d:%02d:%02d", cpuhour, cpumin, cpusec);
break;
case 6: // Status
switch(re->state) {
case RESULT_NEW:
safe_strncpy(buf, g_szMiscItems[0], sizeof(buf));
break;
case RESULT_FILES_DOWNLOADING:
safe_strncpy(buf, g_szMiscItems[9], sizeof(buf));
break;
case RESULT_FILES_DOWNLOADED:
if (at) safe_strncpy(buf, g_szMiscItems[1], sizeof(buf));
else safe_strncpy(buf, g_szMiscItems[2], sizeof(buf));
break;
case RESULT_COMPUTE_DONE:
safe_strncpy(buf, g_szMiscItems[3], sizeof(buf));
break;
case RESULT_FILES_UPLOADING:
safe_strncpy(buf, g_szMiscItems[8], sizeof(buf));
break;
default:
if (re->server_ack) {
safe_strncpy(buf, g_szMiscItems[5], sizeof(buf)); break;
} else if (re->ready_to_ack) {
safe_strncpy(buf, g_szMiscItems[4], sizeof(buf)); break;
} else {
safe_strncpy(buf, g_szMiscItems[6], sizeof(buf)); break;
}
}
break;
}
err = SetDataBrowserItemDataText( itemData, CFStringCreateWithCString(CFAllocatorGetDefault(), buf, kCFStringEncodingMacRoman));
}
return noErr;
}
OSStatus BOINCCarbonTransferCallback( ControlRef browser, DataBrowserItemID itemID,
DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue) {
OSStatus err;
char buf[256];
PERS_FILE_XFER *fi = (PERS_FILE_XFER*)itemID;
double xSent,xtime;
int xhour, xmin, xsec;
if (!changeValue) {
xSent = 0;
if( fi->fip->generated_locally ) {
xSent = fi->fip->upload_offset;
} else {
char pathname[256];
get_pathname(fi->fip, pathname);
file_size(pathname, xSent);
}
sprintf( buf, " " );
switch (property) {
case 0: // Project name
safe_strncpy( buf, fi->fip->project->project_name, sizeof(buf) );
break;
case 1: // File name
safe_strncpy( buf, fi->fip->name, sizeof(buf) );
break;
case 2: // Transfer progress
SetDataBrowserItemDataValue(itemData, (int)(100.0 * xSent / fi->fip->nbytes));
break;
case 3: // Size
sprintf( buf,"%0.0f/%0.0fKB", xSent / 1024.0, fi->fip->nbytes / 1024.0);
break;
case 4: // Time
xtime = fi->time_so_far;
xhour = (int)(xtime / (60 * 60));
xmin = (int)(xtime / 60) % 60;
xsec = (int)(xtime) % 60;
sprintf(buf,"%02d:%02d:%02d", xhour, xmin, xsec);
break;
case 5: // Status
if (fi->next_request_time > time(0)) {
xtime = fi->next_request_time-time(0);
xhour = (int)(xtime / (60 * 60));
xmin = (int)(xtime / 60) % 60;
xsec = (int)(xtime) % 60;
sprintf(buf,"%s %02d:%02d:%02d", g_szMiscItems[10], xhour, xmin, xsec);
} else if (fi->fip->status == ERR_GIVEUP_DOWNLOAD) {
safe_strncpy( buf, g_szMiscItems[11], sizeof(buf) );
} else if (fi->fip->status == ERR_GIVEUP_UPLOAD) {
safe_strncpy( buf, g_szMiscItems[12], sizeof(buf) );
} else {
safe_strncpy( buf, fi->fip->generated_locally?g_szMiscItems[8]:g_szMiscItems[9], sizeof(buf) );
}
break;
}
err = SetDataBrowserItemDataText( itemData, CFStringCreateWithCString(CFAllocatorGetDefault(), buf, kCFStringEncodingMacRoman));
}
return noErr;
}
OSStatus BOINCCarbonMessageCallback( ControlRef browser, DataBrowserItemID itemID,
DataBrowserPropertyID property, DataBrowserItemDataRef itemData, Boolean changeValue) {
OSStatus err;
char buf[256];
MESSAGE *msg = (MESSAGE*)itemID;
if (!changeValue) {
switch (property) {
case 0: // Project
safe_strncpy( buf, msg->project, sizeof(buf) );
err = SetDataBrowserItemDataText( itemData, CFStringCreateWithCString(CFAllocatorGetDefault(), buf, kCFStringEncodingMacRoman));
break;
case 1: // Time
SetDataBrowserItemDataDateTime( itemData, msg->timestamp );
break;
case 2: // File name
safe_strncpy( buf, msg->msg, sizeof(buf) );
err = SetDataBrowserItemDataText( itemData, CFStringCreateWithCString(CFAllocatorGetDefault(), buf, kCFStringEncodingMacRoman));
break;
default:
safe_strncpy( buf, " ", sizeof(buf) );
err = SetDataBrowserItemDataText( itemData, CFStringCreateWithCString(CFAllocatorGetDefault(), buf, kCFStringEncodingMacRoman));
break;
}
}
return noErr;
}
//////////
// arguments: prog: pointer to a progress list control
// vect: pointer to a vector of pointers
// returns: void
// function: first, goes through the vector and adds items to the list
// control for any pointers it does not already contain, then
// goes through the list control and removes any pointers the
// vector does not contain.
void Syncronize(ControlRef prog, vector<void*>* vect) {
unsigned int i,j;
Handle items;
OSStatus err;
DataBrowserItemID duff[1];
items = NewHandle(0);
err = GetDataBrowserItems(prog, kDataBrowserNoItem, true, 0, items);
// add items to list that are not already in it
for(i = 0; i < vect->size(); i ++) {
void* item = (*vect)[i];
bool contained = false;
for(j = 0; j < (GetHandleSize(items) / sizeof(DataBrowserItemID)); j ++) {
if(item == items[j]) {
contained = true;
break;
}
}
if(!contained) {
duff[0] = (long unsigned int)item;
err = AddDataBrowserItems( prog, kDataBrowserNoItem, 1, duff, kDataBrowserItemNoProperty );
}
}
// remove items from list that are not in vector
// now just set the pointer to NULL but leave the item in the list
for(i = 0; i < (GetHandleSize(items) / sizeof(DataBrowserItemID)); i ++) {
void* item = items[i];
bool contained = false;
for(j = 0; j < vect->size(); j ++) {
if(item == (*vect)[j]) {
contained = true;
break;
}
}
if(!contained) {
duff[0] = (long unsigned int)item;
err = RemoveDataBrowserItems( prog, kDataBrowserNoItem, 1, duff, kDataBrowserItemNoProperty );
}
}
}
OSStatus SaveBOINCPreferences( void ) {
unsigned int i, n;
char buf[256];
UInt32 ncols;
// Set up the preferences
CFPreferencesSetAppValue(CFSTR("mainWindowXPos"), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &winXPos),
kCFPreferencesCurrentApplication);
CFPreferencesSetAppValue(CFSTR("mainWindowYPos"), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &winYPos),
kCFPreferencesCurrentApplication);
CFPreferencesSetAppValue(CFSTR("mainWindowWidth"), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &winWidth),
kCFPreferencesCurrentApplication);
CFPreferencesSetAppValue(CFSTR("mainWindowHeight"), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &winHeight),
kCFPreferencesCurrentApplication);
CFPreferencesSetAppValue(CFSTR("mainWindowCurTab"), CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &lastTabIndex),
kCFPreferencesCurrentApplication);
for (i=0;i<4;i++) {
GetDataBrowserTableViewColumnCount(boincDataBrowsers[i],&ncols);
for (n=0;n<ncols;n++) {
sprintf( buf, "table-%d-col-%d", i, n );
CFPreferencesSetAppValue(CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingMacRoman),
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i),
kCFPreferencesCurrentApplication);
}
}
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
return noErr;
}
OSStatus ReadBOINCPreferences( void ) {
Boolean validPref;
winXPos = CFPreferencesGetAppIntegerValue( CFSTR("mainWindowXPos"), kCFPreferencesCurrentApplication, &validPref );
if (!validPref) { // also check if xPos is out of bounds
winXPos = 100;
}
winYPos = CFPreferencesGetAppIntegerValue( CFSTR("mainWindowYPos"), kCFPreferencesCurrentApplication, &validPref );
if (!validPref) { // also check if yPos is out of bounds
winYPos = 100;
}
winWidth = CFPreferencesGetAppIntegerValue( CFSTR("mainWindowWidth"), kCFPreferencesCurrentApplication, &validPref );
if (!validPref) {
winWidth = 640;
}
winHeight = CFPreferencesGetAppIntegerValue( CFSTR("mainWindowHeight"), kCFPreferencesCurrentApplication, &validPref );
if (!validPref) {
winHeight = 480;
}
lastTabIndex = CFPreferencesGetAppIntegerValue( CFSTR("mainWindowCurTab"), kCFPreferencesCurrentApplication, &validPref );
if (!validPref) {
lastTabIndex = 1;
}
return 0;
}
void delete_curtain() {
}
void create_curtain() {
}
void project_add_failed(PROJECT* project) {
}