boinc/client/win/wingui_mainwindow.cpp

1648 lines
51 KiB
C++
Executable File

// The contents of this file are subject to the Mozilla 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://www.mozilla.org/MPL/
//
// 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 "wingui_mainwindow.h"
CMyApp g_myApp;
CMainWindow* g_myWnd = NULL;
/////////////////////////////////////////////////////////////////////////
// CMyApp member functions
//////////
// CMyApp::InitInstance
// arguments: void
// returns: true if initialization is successful, otherwise false
// function: creates and shows the main window if boinc is not running,
// otherwise shows the currently running window
BOOL CMyApp::InitInstance()
{
if(CreateMutex(NULL, false, RUN_MUTEX) == 0 || GetLastError() == ERROR_ALREADY_EXISTS) {
UINT nShowMsg = RegisterWindowMessage(SHOW_WIN_MSG);
PostMessage(HWND_BROADCAST, nShowMsg, 0, 0);
return FALSE;
}
m_pMainWnd = new CMainWindow();
if(gstate.projects.size() == 0) {
((CMainWindow*)m_pMainWnd)->SendMessage(WM_COMMAND, ID_SETTINGS_LOGIN);
}
if(gstate.start_saver) {
UINT nStartSaver = RegisterWindowMessage(START_SS_MSG);
((CMainWindow*)m_pMainWnd)->SendMessage(nStartSaver, 0);
}
return TRUE;
}
int CMyApp::ExitInstance()
{
if (m_pMainWnd)
m_pMainWnd->DestroyWindow();
gstate.free_mem();
return CWinApp::ExitInstance();
}
/////////////////////////////////////////////////////////////////////////
// CMainWindow message map and member functions
BEGIN_MESSAGE_MAP(CMainWindow, CWnd)
ON_WM_CLOSE()
ON_COMMAND(ID_FILE_CLEARINACTIVE, OnCommandFileClearInactive)
ON_COMMAND(ID_FILE_CLEARMESSAGES, OnCommandFileClearMessages)
ON_COMMAND(ID_FILE_HIDE, OnCommandHide)
ON_COMMAND(ID_FILE_SUSPEND, OnCommandSuspend)
ON_COMMAND(ID_FILE_RESUME, OnCommandResume)
ON_COMMAND(ID_FILE_EXIT, OnCommandExit)
ON_COMMAND(ID_CONNECTION_CONNECTNOW, OnCommandConnectionConnectNow)
ON_COMMAND(ID_SETTINGS_LOGIN, OnCommandSettingsLogin)
ON_COMMAND(ID_SETTINGS_QUIT, OnCommandSettingsQuit)
ON_COMMAND(ID_SETTINGS_PROXYSERVER, OnCommandSettingsProxyServer)
ON_COMMAND(ID_HELP_ABOUT, OnCommandHelpAbout)
ON_COMMAND(ID_PROJECT_RELOGIN, OnCommandProjectRelogin)
ON_COMMAND(ID_PROJECT_QUIT, OnCommandProjectQuit)
ON_COMMAND(ID_WORK_SHOWGRAPHICS, OnCommandWorkShowGraphics)
ON_COMMAND(ID_STATUSICON_HIDE, OnCommandHide)
ON_COMMAND(ID_STATUSICON_SUSPEND, OnCommandSuspend)
ON_COMMAND(ID_STATUSICON_RESUME, OnCommandResume)
ON_COMMAND(ID_STATUSICON_EXIT, OnCommandExit)
ON_WM_CREATE()
ON_WM_RBUTTONDOWN()
ON_WM_SIZE()
ON_WM_SETFOCUS()
ON_WM_TIMER()
ON_MESSAGE(STATUS_ICON_ID, OnStatusIcon)
END_MESSAGE_MAP()
//////////
// CMainWindow::CMainWindow
// arguments: void
// returns: void
// function: registers window class, creates and poisitions window.
CMainWindow::CMainWindow()
{
// register window class
CString strWndClass = AfxRegisterWndClass (0, g_myApp.LoadStandardCursor(IDC_ARROW),
(HBRUSH)(COLOR_3DFACE+1), g_myApp.LoadIcon(IDI_ICON));
// create and position window
CreateEx(0, strWndClass, WND_TITLE, WS_OVERLAPPEDWINDOW|WS_EX_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, NULL);
m_nShowMsg = RegisterWindowMessage(SHOW_WIN_MSG);
m_nNetActivityMsg = RegisterWindowMessage(NET_ACTIVITY_MSG);
}
//////////
// CMainWindow::GetPieColor
// arguments: nPiece: index of pie piece
// returns: the color that piece should be
// function: detemines colors for pie pieces in usage control
COLORREF CMainWindow::GetPieColor(int nPiece)
{
int nR = 0, nG = 0, nB = 0;
if(nPiece == 0) {
return RGB(255, 0, 255);
} else if(nPiece == 1) {
return RGB(192, 64, 192);
}
nPiece -= 2;
switch(nPiece % 4) {
case 0:
return RGB(0, 0, 255);
case 1:
return RGB(64, 0, 192);
case 2:
return RGB(128, 0, 128);
default:
return RGB(192, 0, 64);
}
return RGB(0, 0, 0);
}
//////////
// CMainWindow::UpdateGUI
// arguments: pcs: pointer to the client state for the gui to display
// returns: void
// function: syncronizes list controls with vectors in client state
// and displays them.
void CMainWindow::UpdateGUI(CLIENT_STATE* pcs)
{
CString strBuf;
int i;
// display projects
m_ProjectListCtrl.SetRedraw(FALSE);
float totalres = 0;
Syncronize(&m_ProjectListCtrl, (vector<void*>*)(&pcs->projects));
for(i = 0; i < pcs->projects.size(); i ++) {
totalres += pcs->projects[i]->resource_share;
}
for(i = 0; i < m_ProjectListCtrl.GetItemCount(); i ++) {
PROJECT* pr = (PROJECT*)m_ProjectListCtrl.GetItemData(i);
if(!pr) {
m_ProjectListCtrl.SetItemColor(i, RGB(128, 128, 128));
m_ProjectListCtrl.SetProjectURL(i, "");
m_ProjectListCtrl.SetItemProgress(i, 4, 0);
continue;
}
// project
if(!strcmp(pr->project_name, "")) {
m_ProjectListCtrl.SetItemText(i, 0, pr->master_url);
} else {
m_ProjectListCtrl.SetItemText(i, 0, pr->project_name);
}
m_ProjectListCtrl.SetProjectURL(i, pr->master_url);
// account
m_ProjectListCtrl.SetItemText(i, 1, pr->user_name);
// total credit
strBuf.Format("%0.2f", pr->user_total_credit);
m_ProjectListCtrl.SetItemText(i, 2, strBuf);
// avg credit
strBuf.Format("%0.2f", pr->user_expavg_credit);
m_ProjectListCtrl.SetItemText(i, 3, strBuf);
// resource share
if(totalres <= 0) {
m_ProjectListCtrl.SetItemProgress(i, 4, 100);
} else {
m_ProjectListCtrl.SetItemProgress(i, 4, (100 * pr->resource_share) / totalres);
}
}
m_ProjectListCtrl.SetRedraw(TRUE);
// update results
m_ResultListCtrl.SetRedraw(FALSE);
Syncronize(&m_ResultListCtrl, (vector<void*>*)(&pcs->results));
for(i = 0; i < m_ResultListCtrl.GetItemCount(); i ++) {
RESULT* re = (RESULT*)m_ResultListCtrl.GetItemData(i);
if(!re) {
m_ResultListCtrl.SetItemColor(i, RGB(128, 128, 128));
m_ResultListCtrl.SetItemProgress(i, 4, 100);
m_ResultListCtrl.SetItemText(i, 5, "00:00:00");
continue;
}
// project
m_ResultListCtrl.SetItemText(i, 0, re->project->project_name);
// application
m_ResultListCtrl.SetItemText(i, 1, re->app->name);
// name
m_ResultListCtrl.SetItemText(i, 2, re->name);
// cpu time
ACTIVE_TASK* at = gstate.lookup_active_task_by_result(re);
double cur_cpu;
if (at) {
cur_cpu = at->current_cpu_time;
} else {
if(re->state < RESULT_COMPUTE_DONE) cur_cpu = 0;
else cur_cpu = re->final_cpu_time;
}
int cpuhour = (int)(cur_cpu / (60 * 60));
int cpumin = (int)(cur_cpu / 60) % 60;
int cpusec = (int)(cur_cpu) % 60;
strBuf.Format("%0.2d:%0.2d:%0.2d", cpuhour, cpumin, cpusec);
m_ResultListCtrl.SetItemText(i, 3, strBuf);
// progress
if(!at) {
m_ResultListCtrl.SetItemProgress(i, 4, 0);
} else {
m_ResultListCtrl.SetItemProgress(i, 4, at->fraction_done * 100);
}
// to completion
double tocomp;
if(!at || at->fraction_done == 0) {
tocomp = re->wup->seconds_to_complete;
} else {
tocomp = at->est_time_to_completion();
}
cpuhour = (int)(tocomp / (60 * 60));
cpumin = (int)(tocomp / 60) % 60;
cpusec = (int)(tocomp) % 60;
strBuf.Format("%0.2d:%0.2d:%0.2d", cpuhour, cpumin, cpusec);
m_ResultListCtrl.SetItemText(i, 5, strBuf);
// status
switch(re->state) {
case RESULT_NEW:
strBuf.Format(g_szMiscItems[0]); break;
case RESULT_FILES_DOWNLOADED:
if (at)
strBuf.Format(g_szMiscItems[1]);
else
strBuf.Format(g_szMiscItems[2]);
break;
case RESULT_COMPUTE_DONE:
strBuf.Format(g_szMiscItems[3]); break;
default:
if (re->server_ack) {
strBuf.Format(g_szMiscItems[5]); break;
} else if (re->ready_to_ack) {
strBuf.Format(g_szMiscItems[4]); break;
} else {
strBuf.Format(g_szMiscItems[6]); break;
}
}
m_ResultListCtrl.SetItemText(i, 6, strBuf);
}
m_ResultListCtrl.SetRedraw(TRUE);
// update xfers
m_XferListCtrl.SetRedraw(FALSE);
Syncronize(&m_XferListCtrl, (vector<void*>*)(&pcs->pers_xfers->pers_file_xfers));
for(i = 0; i < m_XferListCtrl.GetItemCount(); i ++) {
PERS_FILE_XFER* fi = (PERS_FILE_XFER*)m_XferListCtrl.GetItemData(i);
if(!fi) {
m_XferListCtrl.SetItemColor(i, RGB(128, 128, 128));
m_XferListCtrl.SetItemProgress(i, 2, 100);
m_XferListCtrl.SetItemText(i, 3, g_szMiscItems[7]);
m_XferListCtrl.SetItemText(i, 5, "0.00 KBps");
m_XferListCtrl.SetItemText(i, 6, g_szMiscItems[7]);
continue;
}
// project
m_XferListCtrl.SetItemText(i, 0, fi->fip->project->project_name);
// file
m_XferListCtrl.SetItemText(i, 1, fi->fip->name);
// progress
double xSent = 0;
if (fi->fxp) {
xSent = fi->fxp->bytes_xferred;
}
m_XferListCtrl.SetItemProgress(i, 2, 100 * xSent / fi->fip->nbytes);
// size
strBuf.Format("%0.0f/%0.0fKB", xSent / 1024, fi->fip->nbytes / 1024);
m_XferListCtrl.SetItemText(i, 3, strBuf.GetBuffer(0));
// time
double xtime = 0;
xtime = fi->time_so_far;
int xhour = (int)(xtime / (60 * 60));
int xmin = (int)(xtime / 60) % 60;
int xsec = (int)(xtime) % 60;
strBuf.Format("%0.2d:%0.2d:%0.2d", xhour, xmin, xsec);
m_XferListCtrl.SetItemText(i, 4, strBuf.GetBuffer(0));
// speed
strBuf.Format("0.00 KBps");
if(fi->fxp) {
strBuf.Format("%0.2f KBps", fi->fxp->xfer_speed/1024);
}
m_XferListCtrl.SetItemText(i, 5, strBuf.GetBuffer(0));
// status
if (fi->next_request_time > time(0)) {
double xtime = fi->next_request_time-time(0);
int xhour = (int)(xtime / (60 * 60));
int xmin = (int)(xtime / 60) % 60;
int xsec = (int)(xtime) % 60;
strBuf.Format("%s %0.2d:%0.2d:%0.2d", g_szMiscItems[10], xhour, xmin, xsec);
m_XferListCtrl.SetItemText(i, 6, strBuf);
} else if (fi->fip->status == ERR_GIVEUP_DOWNLOAD) {
strBuf.Format(g_szMiscItems[11]);
m_XferListCtrl.SetItemText(i, 6, strBuf);
} else if (fi->fip->status == ERR_GIVEUP_UPLOAD) {
strBuf.Format(g_szMiscItems[12]);
m_XferListCtrl.SetItemText(i, 6, strBuf);
} else {
m_XferListCtrl.SetItemText(i, 6, fi->fip->generated_locally?g_szMiscItems[8]:g_szMiscItems[9]);
}
}
m_XferListCtrl.SetRedraw(TRUE);
// update usage
double xDiskTotal;
double xDiskFree; get_host_disk_info(xDiskTotal, xDiskFree);
double xDiskUsed = xDiskTotal - xDiskFree;
double xDiskAllow; gstate.allowed_disk_usage(xDiskAllow);
double xDiskUsage; gstate.current_disk_usage(xDiskUsage);
while(m_UsagePieCtrl.GetItemCount() - 4 < gstate.projects.size()) {
m_UsagePieCtrl.AddPiece("", GetPieColor(m_UsagePieCtrl.GetItemCount()), 0);
}
while(m_UsagePieCtrl.GetItemCount() - 4 > gstate.projects.size()) {
m_UsagePieCtrl.RemovePiece(m_UsagePieCtrl.GetItemCount() - 1);
}
m_UsagePieCtrl.SetTotal(xDiskTotal);
m_UsagePieCtrl.SetPiece(0, xDiskFree - (xDiskAllow - xDiskUsage)); // Free (non-BOINC)
m_UsagePieCtrl.SetPiece(1, xDiskAllow - xDiskUsage); // Free (BOINC)
m_UsagePieCtrl.SetPiece(2, xDiskUsed - xDiskUsage); // Used (non-BOINC)
for(i = 0; i < gstate.projects.size(); i ++) {
double xUsage;
CString strLabel;
strLabel.Format("%s %s", g_szUsageItems[4], gstate.projects[i]->project_name);
gstate.project_disk_usage(gstate.projects[i], xUsage);
m_UsagePieCtrl.SetPieceLabel(i + 4, strLabel.GetBuffer(0));
m_UsagePieCtrl.SetPiece(i + 4, xUsage);
xDiskUsage -= xUsage;
}
m_UsagePieCtrl.SetPiece(3, xDiskUsage); // Used (BOINC)
m_UsagePieCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_NOERASE|RDW_FRAME);
// make icon flash if needed
if(m_bMessage || m_bRequest) {
if(m_nIconState == ICON_NORMAL) {
SetStatusIcon(ICON_HIGHLIGHT);
} else if(m_nIconState == ICON_HIGHLIGHT) {
SetStatusIcon(ICON_NORMAL);
}
}
}
//////////
// CMainWindow::MessageUser
// arguments: message: message string to display
// priority: string with priority of message
// returns: void
// function: if message is MSG_ERROR priority, flashes the status icon,
// then adds to message edit control.
void CMainWindow::MessageUser(char* szProject, char* szMessage, int szPriority)
{
if(!m_MessageListCtrl.GetSafeHwnd()) return;
int nNewPos = m_MessageListCtrl.GetItemCount();
m_MessageListCtrl.InsertItem(nNewPos, szProject);
CTime curTime = CTime::GetCurrentTime();
CString strTime;
strTime = curTime.Format("%c");
m_MessageListCtrl.SetItemText(nNewPos, 1, strTime);
m_MessageListCtrl.SetItemText(nNewPos, 2, szMessage);
// set status icon to flash
if((szPriority == MSG_ERROR) && (m_TabCtrl.GetCurSel() != MESSAGE_ID || GetForegroundWindow() != this)) {
m_bMessage = true;
}
}
//////////
// CMainWindow::IsSuspended
// arguments: void
// returns: true if the window is suspended, false otherwise
// function: tells if the window is suspended
BOOL CMainWindow::IsSuspended()
{
return gstate.suspend_requested;
}
//////////
// CMainWindow::RequestNetConnect
// arguments: void
// returns: true if the user can connect, false otherwise
// function: asks the user for permission to connect to the network
BOOL CMainWindow::RequestNetConnect()
{
if(GetForegroundWindow() != this || !IsWindowVisible()) {
m_bRequest = true;
return FALSE;
}
CConnectDialog dlg(IDD_CONNECT);
int retval = dlg.DoModal();
m_bRequest = false;
if(retval == IDOK) {
return TRUE;
}
return FALSE;
}
//////////
// CMainWindow::ShowTab
// arguments: nTab: tab number to show
// returns: void
// function: handles everything necessary to switch to a new tab
void CMainWindow::ShowTab(int nTab)
{
m_TabCtrl.SetCurSel(nTab);
// make the selected control visible, all the rest invisible
if(nTab == PROJECT_ID) {
m_ProjectListCtrl.ModifyStyle(0, WS_VISIBLE);
m_ResultListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_XferListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_MessageListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_UsagePieCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ProjectListCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
} else if(nTab == RESULT_ID) {
m_ProjectListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ResultListCtrl.ModifyStyle(0, WS_VISIBLE);
m_XferListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_MessageListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_UsagePieCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ResultListCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
} else if(nTab == XFER_ID) {
m_ProjectListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ResultListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_XferListCtrl.ModifyStyle(0, WS_VISIBLE);
m_MessageListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_UsagePieCtrl.ModifyStyle(WS_VISIBLE, 0);
m_XferListCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
} else if(nTab == MESSAGE_ID) {
m_ProjectListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ResultListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_XferListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_MessageListCtrl.ModifyStyle(0, WS_VISIBLE);
m_UsagePieCtrl.ModifyStyle(WS_VISIBLE, 0);
if(m_bMessage) {
m_bMessage = false;
SetStatusIcon(ICON_NORMAL);
}
m_MessageListCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
} else if(nTab == USAGE_ID) {
m_ProjectListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ResultListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_XferListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_MessageListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_UsagePieCtrl.ModifyStyle(0, WS_VISIBLE);
m_UsagePieCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
m_TabCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
RedrawWindow();
}
//////////
// CMainWindow::SetStatusIcon
// arguments: dwMessage: hide or show the icon
// returns: void
// function: controls the status icon in the taskbar
void CMainWindow::SetStatusIcon(DWORD dwMessage)
{
if(dwMessage != ICON_OFF && dwMessage != ICON_NORMAL && dwMessage != ICON_HIGHLIGHT) {
return;
}
// if icon is in that state already, there is nothing to do
if(dwMessage == m_nIconState) return;
NOTIFYICONDATA icon_data;
memset( &icon_data, 0, sizeof(NOTIFYICONDATA) );
icon_data.cbSize = sizeof(NOTIFYICONDATA);
icon_data.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
icon_data.hWnd = GetSafeHwnd();
icon_data.uID = STATUS_ICON_ID;
safe_strncpy(icon_data.szTip, WND_TITLE, sizeof(icon_data.szTip));
icon_data.uCallbackMessage = STATUS_ICON_ID;
if(dwMessage == ICON_OFF) {
icon_data.hIcon = NULL;
Shell_NotifyIcon(NIM_DELETE, &icon_data);
} else if(dwMessage == ICON_NORMAL) {
icon_data.hIcon = g_myApp.LoadIcon(IDI_ICON);
if(m_nIconState == ICON_OFF) {
Shell_NotifyIcon(NIM_ADD, &icon_data);
} else {
Shell_NotifyIcon(NIM_MODIFY, &icon_data);
}
} else if(dwMessage == ICON_HIGHLIGHT) {
icon_data.hIcon = g_myApp.LoadIcon(IDI_ICONHIGHLIGHT);
if(m_nIconState == ICON_OFF) {
Shell_NotifyIcon(NIM_ADD, &icon_data);
} else {
Shell_NotifyIcon(NIM_MODIFY, &icon_data);
}
}
m_nIconState = dwMessage;
}
//////////
// CMainWindow::SaveListControls
// arguments: void
// returns: void
// function: saves relevant elements of list controls
void CMainWindow::SaveListControls()
{
char szPath[256];
CString strKey, strVal;
GetCurrentDirectory(256, szPath);
strcat(szPath, "\\");
strcat(szPath, LIST_STATE_FILE_NAME);
file_delete(szPath);
m_ProjectListCtrl.SaveInactive(szPath, "PROJECTS");
m_ResultListCtrl.SaveInactive(szPath, "WORK");
m_XferListCtrl.SaveInactive(szPath, "TRANSFERS");
m_MessageListCtrl.SaveInactive(szPath, "MESSAGES");
}
//////////
// CMainWindow::LoadListControls
// arguments: void
// returns: void
// function: loads relevant elements of list controls
void CMainWindow::LoadListControls()
{
char szPath[256];
CString strKey, strVal;
GetCurrentDirectory(256, szPath);
strcat(szPath, "\\");
strcat(szPath, LIST_STATE_FILE_NAME);
m_ProjectListCtrl.LoadInactive(szPath, "PROJECTS");
m_ResultListCtrl.LoadInactive(szPath, "WORK");
m_XferListCtrl.LoadInactive(szPath, "TRANSFERS");
m_MessageListCtrl.LoadInactive(szPath, "MESSAGES");
}
//////////
// CMainWindow::SaveUserSettings
// arguments: void
// returns: void
// function: saves relevant user settings to boinc ini file
void CMainWindow::SaveUserSettings()
{
char szPath[256];
CString strKey, strVal;
GetCurrentDirectory(256, szPath);
strcat(szPath, "\\");
strcat(szPath, INI_FILE_NAME);
int colorder[MAX_COLS];
int i;
// get rid of old lists
file_delete(szPath);
// save window size/position
CRect rt;
GetWindowRect(&rt);
strVal.Format("%d", rt.left);
WritePrivateProfileString("WINDOW", "xposition", strVal, szPath);
strVal.Format("%d", rt.top);
WritePrivateProfileString("WINDOW", "yposition", strVal, szPath);
strVal.Format("%d", rt.Width());
WritePrivateProfileString("WINDOW", "width", strVal, szPath);
strVal.Format("%d", rt.Height());
WritePrivateProfileString("WINDOW", "height", strVal, szPath);
// save selected tab
strVal.Format("%d", m_TabCtrl.GetCurSel());
WritePrivateProfileString("WINDOW", "selection", strVal, szPath);
// save project columns
m_ProjectListCtrl.GetColumnOrderArray(colorder, PROJECT_COLS);
WritePrivateProfileStruct("HEADERS", "projects-order", colorder, sizeof(colorder), szPath);
for(i = 0; i < m_ProjectListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("projects-%d", i);
strVal.Format("%d", m_ProjectListCtrl.GetColumnWidth(i));
WritePrivateProfileString("HEADERS", strKey, strVal, szPath);
}
// save result columns
m_ResultListCtrl.GetColumnOrderArray(colorder, RESULT_COLS);
WritePrivateProfileStruct("HEADERS", "results-order", colorder, sizeof(colorder), szPath);
for(i = 0; i < m_ResultListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("results-%d", i);
strVal.Format("%d", m_ResultListCtrl.GetColumnWidth(i));
WritePrivateProfileString("HEADERS", strKey, strVal, szPath);
}
// save xfer columns
m_XferListCtrl.GetColumnOrderArray(colorder, XFER_COLS);
WritePrivateProfileStruct("HEADERS", "xfers-order", colorder, sizeof(colorder), szPath);
for(i = 0; i < m_XferListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("xfers-%d", i);
strVal.Format("%d", m_XferListCtrl.GetColumnWidth(i));
WritePrivateProfileString("HEADERS", strKey, strVal, szPath);
}
// save xfer columns
m_MessageListCtrl.GetColumnOrderArray(colorder, MESSAGE_COLS);
WritePrivateProfileStruct("HEADERS", "messages-order", colorder, sizeof(colorder), szPath);
for(i = 0; i < m_MessageListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("messages-%d", i);
strVal.Format("%d", m_MessageListCtrl.GetColumnWidth(i));
WritePrivateProfileString("HEADERS", strKey, strVal, szPath);
}
}
//////////
// CMainWindow::LoadUserSettings
// arguments: void
// returns: void
// function: loads relevant user settings from boinc ini file
void CMainWindow::LoadUserSettings()
{
char szPath[256];
CString strKey;
GetCurrentDirectory(256, szPath);
strcat(szPath, "\\");
strcat(szPath, INI_FILE_NAME);
int i, nBuf;
int colorder[MAX_COLS];
// load window size/position
CRect rt;
nBuf = GetPrivateProfileInt("WINDOW", "xposition", 100, szPath);
rt.left = nBuf;
nBuf = GetPrivateProfileInt("WINDOW", "yposition", 100, szPath);
rt.top = nBuf;
nBuf = GetPrivateProfileInt("WINDOW", "width", 600, szPath);
rt.right = nBuf + rt.left;
nBuf = GetPrivateProfileInt("WINDOW", "height", 400, szPath);
rt.bottom = nBuf + rt.top;
CRect rtScreen, rtInt;
HDC screenDC=::GetDC(NULL);
rtScreen.left = rtScreen.top = 0;
rtScreen.right=GetDeviceCaps(screenDC, HORZRES);
rtScreen.bottom=GetDeviceCaps(screenDC, VERTRES);
::ReleaseDC(NULL, screenDC);
rtInt.IntersectRect(&rt, &rtScreen);
if(rtInt.IsRectEmpty()) {
rt.SetRect(100, 100, 600, 400);
}
SetWindowPos(&wndNoTopMost, rt.left, rt.top, rt.Width(), rt.Height(), 0);
// load selected tab
nBuf = GetPrivateProfileInt("WINDOW", "selection", 0, szPath);
ShowTab(nBuf);
// load project columns
if(GetPrivateProfileStruct("HEADERS", "projects-order", colorder, sizeof(colorder), szPath)) {
m_ProjectListCtrl.SetColumnOrderArray(PROJECT_COLS, colorder);
}
for(i = 0; i < m_ProjectListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("projects-%d", i);
nBuf = GetPrivateProfileInt("HEADERS", strKey.GetBuffer(0), DEF_COL_WIDTH, szPath);
m_ProjectListCtrl.SetColumnWidth(i, nBuf);
}
// load result columns
if(GetPrivateProfileStruct("HEADERS", "results-order", colorder, sizeof(colorder), szPath)) {
m_ResultListCtrl.SetColumnOrderArray(RESULT_COLS, colorder);
}
for(i = 0; i < m_ResultListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("results-%d", i);
nBuf = GetPrivateProfileInt("HEADERS", strKey.GetBuffer(0), DEF_COL_WIDTH, szPath);
m_ResultListCtrl.SetColumnWidth(i, nBuf);
}
// load xfer columns
if(GetPrivateProfileStruct("HEADERS", "xfers-order", colorder, sizeof(colorder), szPath)) {
m_XferListCtrl.SetColumnOrderArray(XFER_COLS, colorder);
}
for(i = 0; i < m_XferListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("xfers-%d", i);
nBuf = GetPrivateProfileInt("HEADERS", strKey.GetBuffer(0), DEF_COL_WIDTH, szPath);
m_XferListCtrl.SetColumnWidth(i, nBuf);
}
// load message columns
if(GetPrivateProfileStruct("HEADERS", "messages-order", colorder, sizeof(colorder), szPath)) {
m_MessageListCtrl.SetColumnOrderArray(MESSAGE_COLS, colorder);
}
for(i = 0; i < m_MessageListCtrl.GetHeaderCtrl()->GetItemCount(); i ++) {
strKey.Format("messages-%d", i);
int nWidth = DEF_COL_WIDTH;
if(i == 1) nWidth *= 1.5;
if(i == 2) nWidth *= 4;
nBuf = GetPrivateProfileInt("HEADERS", strKey.GetBuffer(0), nWidth, szPath);
m_MessageListCtrl.SetColumnWidth(i, nBuf);
}
}
//////////
// CMainWindow::LoadLanguage
// arguments: void
// returns: void
// function: loads new captions from language file
void CMainWindow::LoadLanguage()
{
char szPath[256];
int col;
CString strSection;
GetCurrentDirectory(256, szPath);
strcat(szPath, "\\");
strcat(szPath, LANGUAGE_FILE_NAME);
// load column headers
strSection.Format("HEADER-%s", g_szTabItems[PROJECT_ID]);
for(col = 0; col < PROJECT_COLS; col ++) {
GetPrivateProfileString(strSection, g_szColumnTitles[PROJECT_ID][col], g_szColumnTitles[PROJECT_ID][col], g_szColumnTitles[PROJECT_ID][col], 256, szPath);
}
GetPrivateProfileString(strSection, "Title", g_szTabItems[PROJECT_ID], g_szTabItems[PROJECT_ID], 16, szPath);
strSection.Format("HEADER-%s", g_szTabItems[RESULT_ID]);
for(col = 0; col < RESULT_COLS; col ++) {
GetPrivateProfileString(strSection, g_szColumnTitles[RESULT_ID][col], g_szColumnTitles[RESULT_ID][col], g_szColumnTitles[RESULT_ID][col], 256, szPath);
}
GetPrivateProfileString(strSection, "Title", g_szTabItems[RESULT_ID], g_szTabItems[RESULT_ID], 16, szPath);
strSection.Format("HEADER-%s", g_szTabItems[XFER_ID]);
for(col = 0; col < XFER_COLS; col ++) {
GetPrivateProfileString(strSection, g_szColumnTitles[XFER_ID][col], g_szColumnTitles[XFER_ID][col], g_szColumnTitles[XFER_ID][col], 256, szPath);
}
GetPrivateProfileString(strSection, "Title", g_szTabItems[XFER_ID], g_szTabItems[XFER_ID], 16, szPath);
strSection.Format("HEADER-%s", g_szTabItems[MESSAGE_ID]);
for(col = 0; col < MESSAGE_COLS; col ++) {
GetPrivateProfileString(strSection, g_szColumnTitles[MESSAGE_ID][col], g_szColumnTitles[MESSAGE_ID][col], g_szColumnTitles[MESSAGE_ID][col], 256, szPath);
}
GetPrivateProfileString(strSection, "Title", g_szTabItems[MESSAGE_ID], g_szTabItems[MESSAGE_ID], 16, szPath);
// load usage labels
strSection.Format("HEADER-%s", g_szTabItems[USAGE_ID]);
for(col = 0; col < MAX_USAGE_STR; col ++) {
GetPrivateProfileString(strSection, g_szUsageItems[col], g_szUsageItems[col], g_szUsageItems[col], 256, szPath);
}
GetPrivateProfileString(strSection, "Title", g_szTabItems[USAGE_ID], g_szTabItems[USAGE_ID], 16, szPath);
// load miscellaneous text
strSection.Format("HEADER-MISC");
for(col = 0; col < MAX_MISC_STR; col ++) {
GetPrivateProfileString(strSection, g_szMiscItems[col], g_szMiscItems[col], g_szMiscItems[col], 256, szPath);
}
// load menu items
CString strItem, strItemNoAmp;
char szItem[256];
int i, is;
for(i = 0; i < m_MainMenu.GetMenuItemCount(); i ++) {
m_MainMenu.GetMenuString(i, strItem, MF_BYPOSITION);
strItemNoAmp = strItem; strItemNoAmp.Remove('&');
strSection.Format("MENU-%s", strItemNoAmp);
GetPrivateProfileString(strSection, "Title", strItem, szItem, 256, szPath);
m_MainMenu.ModifyMenu(i, MF_BYPOSITION|MF_STRING, 0, szItem);
CMenu* pSubMenu = m_MainMenu.GetSubMenu(i);
if(!pSubMenu) continue;
for(is = 0; is < pSubMenu->GetMenuItemCount(); is ++) {
pSubMenu->GetMenuString(is, strItem, MF_BYPOSITION);
if(strItem.IsEmpty()) continue;
strItemNoAmp = strItem; strItemNoAmp.Remove('&');
GetPrivateProfileString(strSection, strItemNoAmp, strItem, szItem, 256, szPath);
pSubMenu->ModifyMenu(is, MF_BYPOSITION|MF_STRING, pSubMenu->GetMenuItemID(is), szItem);
}
}
for(i = 0; i < m_ContextMenu.GetMenuItemCount(); i ++) {
m_ContextMenu.GetMenuString(i, strItem, MF_BYPOSITION);
strItemNoAmp = strItem; strItemNoAmp.Remove('&');
strSection.Format("MENU-%s", strItemNoAmp);
GetPrivateProfileString(strSection, "Title", strItem, szItem, 256, szPath);
m_ContextMenu.ModifyMenu(i, MF_BYPOSITION|MF_STRING, 0, szItem);
CMenu* pSubMenu = m_ContextMenu.GetSubMenu(i);
if(!pSubMenu) continue;
for(is = 0; is < pSubMenu->GetMenuItemCount(); is ++) {
pSubMenu->GetMenuString(is, strItem, MF_BYPOSITION);
if(strItem.IsEmpty()) continue;
strItemNoAmp = strItem; strItemNoAmp.Remove('&');
GetPrivateProfileString(strSection, strItemNoAmp, strItem, szItem, 256, szPath);
pSubMenu->ModifyMenu(is, MF_BYPOSITION|MF_STRING, pSubMenu->GetMenuItemID(is), szItem);
}
}
}
//////////
// CMainWindow::GetUserIdleTime
// arguments: void
// returns: time the user has been idle in milliseconds
// function: calls a dll function to determine the the user's idle time
DWORD CMainWindow::GetUserIdleTime()
{
if(m_hIdleDll) {
typedef DWORD (CALLBACK* GetFn)();
GetFn fn;
fn = (GetFn)GetProcAddress(m_hIdleDll, "IdleTrackerGetLastTickCount");
if(fn) {
return GetTickCount() - fn();
} else {
typedef void (CALLBACK* TermFn)();
TermFn tfn;
tfn = (TermFn)GetProcAddress(m_hIdleDll, "IdleTrackerTerm");
if(tfn) {
tfn();
}
FreeLibrary(m_hIdleDll);
m_hIdleDll = NULL;
}
}
return 0;
}
//////////
// CMainWindow::Syncronize
// arguments: pProg: pointer to a progress list control
// pVect: 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 CMainWindow::Syncronize(CProgressListCtrl* pProg, vector<void*>* pVect)
{
int i, j;
// add items to list that are not already in it
for(i = 0; i < pVect->size(); i ++) {
void* item = (*pVect)[i];
BOOL contained = false;
for(j = 0; j < pProg->GetItemCount(); j ++) {
if((DWORD)item == pProg->GetItemData(j)) {
contained = true;
break;
}
}
if(!contained) {
pProg->InsertItem(i, "");
pProg->SetItemData(i, (DWORD)item);
}
}
// 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 < pProg->GetItemCount(); i ++) {
DWORD item = pProg->GetItemData(i);
BOOL contained = false;
for(j = 0; j < pVect->size(); j ++) {
if(item == (DWORD)(*pVect)[j]) {
contained = true;
break;
}
}
if(!contained) {
pProg->SetItemData(i, (DWORD)NULL);
}
}
}
//////////
// CMainWindow::PostNcDestroy
// arguments: void
// returns: void
// function: takes care of window being destroyed
void CMainWindow::PostNcDestroy()
{
delete this;
}
//////////
// CMainWindow::DefWindowProc
// arguments: message: message received
// wParam: message's wparam
// lParam: message's lparam
// returns: dependent on message
// function: handles any messages not handled by the window previously
LRESULT CMainWindow::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(m_nShowMsg == message) {
ShowWindow(SW_SHOW);
SetForegroundWindow();
return 0;
} else if(m_nNetActivityMsg == message) {
gstate.net_sleep(0);
return 0;
}
return CWnd::DefWindowProc(message, wParam, lParam);
}
//////////
// CMainWindow::OnClose
// arguments: void
// returns: void
// function: hides the window, keeps status icon
void CMainWindow::OnClose()
{
ShowWindow(SW_HIDE);
}
//////////
// CMainWindow::OnCommandSettingsQuit
// arguments: void
// returns: void
// function: shows the account quit dialog box
void CMainWindow::OnCommandSettingsQuit()
{
CQuitDialog dlg(IDD_QUIT);
int nResult = dlg.DoModal();
if(nResult == IDOK) {
CString str;
if(strcmp(gstate.projects[dlg.m_nSel]->project_name, "")) {
str.Format("Are you sure you want to quit the project %s?", gstate.projects[dlg.m_nSel]->project_name);
} else {
str.Format("Are you sure you want to quit the project %s?", gstate.projects[dlg.m_nSel]->master_url);
}
if(AfxMessageBox(str, MB_YESNO, 0) == IDYES) {
gstate.quit_project(dlg.m_nSel);
}
}
}
//////////
// CMainWindow::OnCommandSettingsLogin
// arguments: void
// returns: void
// function: shows the account login dialog box
void CMainWindow::OnCommandSettingsLogin()
{
if(GetForegroundWindow() != this || !IsWindowVisible()) {
return;
}
CLoginDialog dlg(IDD_LOGIN, "", "");
int nResult = dlg.DoModal();
if(nResult == IDOK) {
gstate.add_project(dlg.m_strUrl.GetBuffer(0), dlg.m_strAuth.GetBuffer(0));
}
}
//////////
// CMainWindow::OnCommandSettingsProxyServer
// arguments: void
// returns: void
// function: shows the proxy dialog box
void CMainWindow::OnCommandSettingsProxyServer()
{
CProxyDialog dlg(IDD_PROXY);
int nResult = dlg.DoModal();
}
//////////
// CMainWindow::OnCommandHelpAbout
// arguments: void
// returns: void
// function: shows the about dialog box
void CMainWindow::OnCommandHelpAbout()
{
CAboutDialog dlg(IDD_ABOUTBOX);
int nResult = dlg.DoModal();
}
//////////
// CMainWindow::OnCommandFileClearInactive
// arguments: void
// returns: void
// function: clears inactive items from lists
void CMainWindow::OnCommandFileClearInactive()
{
int i;
for(i = 0; i < m_ProjectListCtrl.GetItemCount();) {
if(!m_ProjectListCtrl.GetItemData(i)) {
m_ProjectListCtrl.DeleteItem(i);
} else {
i ++;
}
}
for(i = 0; i < m_ResultListCtrl.GetItemCount();) {
if(!m_ResultListCtrl.GetItemData(i)) {
m_ResultListCtrl.DeleteItem(i);
} else {
i ++;
}
}
for(i = 0; i < m_XferListCtrl.GetItemCount();) {
if(!m_XferListCtrl.GetItemData(i)) {
m_XferListCtrl.DeleteItem(i);
} else {
i ++;
}
}
}
//////////
// CMainWindow::OnCommandFileClearMessages
// arguments: void
// returns: void
// function: clears messages
void CMainWindow::OnCommandFileClearMessages()
{
m_MessageListCtrl.DeleteAllItems();
}
//////////
// CMainWindow::OnCommandConnectionConnectNow
// arguments: void
// returns: void
// function: causes the client to connect to the network
void CMainWindow::OnCommandConnectionConnectNow()
{
bool bOldConfirm = gstate.global_prefs.confirm_before_connecting;
gstate.global_prefs.confirm_before_connecting = false;
NetOpen();
gstate.global_prefs.confirm_before_connecting = bOldConfirm;
for(int ii = 0; ii < gstate.projects.size(); ii ++) {
gstate.projects[ii]->sched_rpc_pending = true;
}
NetClose();
}
//////////
// CMainWindow::OnCommandProjectRelogin
// arguments: void
// returns: void
// function: lets a user change the properties for an account
void CMainWindow::OnCommandProjectRelogin()
{
if(m_nContextItem < 0 || m_nContextItem > m_ProjectListCtrl.GetItemCount()) return;
PROJECT* pToRelogin = (PROJECT*)m_ProjectListCtrl.GetItemData(m_nContextItem);
m_nContextItem = -1;
if(!pToRelogin) return;
// find project index
int i;
for(i = 0; i < gstate.projects.size(); i ++) {
if(gstate.projects[i] == pToRelogin) break;
}
if(i == gstate.projects.size()) return;
// get info and relogin
CLoginDialog dlg(IDD_LOGIN, gstate.projects[i]->master_url, gstate.projects[i]->authenticator);
int retval = dlg.DoModal();
if(retval == IDOK) {
gstate.change_project(i, dlg.m_strUrl.GetBuffer(0), dlg.m_strAuth.GetBuffer(0));
}
}
//////////
// CMainWindow::OnCommandProjectQuit
// arguments: void
// returns: void
// function: lets the user quit a project
void CMainWindow::OnCommandProjectQuit()
{
if(m_nContextItem < 0 || m_nContextItem > m_ProjectListCtrl.GetItemCount()) return;
PROJECT* pToQuit = (PROJECT*)m_ProjectListCtrl.GetItemData(m_nContextItem);
m_nContextItem = -1;
if(!pToQuit) return;
// find project index
int i;
for(i = 0; i < gstate.projects.size(); i ++) {
if(gstate.projects[i] == pToQuit) break;
}
if(i == gstate.projects.size()) return;
// confirm and quit
CString strBuf;
if(strcmp(gstate.projects[i]->project_name, "")) {
strBuf.Format("Are you sure you want to quit the project %s?", gstate.projects[i]->project_name);
} else {
strBuf.Format("Are you sure you want to quit the project %s?", gstate.projects[i]->master_url);
}
if(AfxMessageBox(strBuf, MB_YESNO, 0) == IDYES) {
gstate.quit_project(i);
}
}
//////////
// CMainWindow::OnCommandWorkShowGraphics
// arguments: void
// returns: void
// function: brings up the graphics window for the selescted app
void CMainWindow::OnCommandWorkShowGraphics()
{
RESULT* resToShow = (RESULT*)m_ResultListCtrl.GetItemData(m_nContextItem);
if(resToShow) {
ACTIVE_TASK* at = gstate.lookup_active_task_by_result(resToShow);
if(at) {
CWnd* pAppWnd = GetWndFromProcId(at->pid);
if(pAppWnd && IsWindow(pAppWnd->m_hWnd)) {
pAppWnd->PostMessage(RegisterWindowMessage(APP_SET_MSG), MODE_WINDOW, MODE_DEFAULT);
}
}
}
}
//////////
// CMainWindow::OnCommandHide
// arguments: void
// returns: void
// function: hides or shows the window
void CMainWindow::OnCommandHide()
{
CMenu* pMainMenu;
CMenu* pFileMenu;
pMainMenu = GetMenu();
if(pMainMenu) {
pFileMenu = pMainMenu->GetSubMenu(0);
}
if(IsWindowVisible()) {
ShowWindow(SW_HIDE);
if(pFileMenu) {
pFileMenu->CheckMenuItem(ID_FILE_HIDE, MF_CHECKED);
}
} else {
ShowWindow(SW_SHOW);
if(pFileMenu) {
pFileMenu->CheckMenuItem(ID_FILE_HIDE, MF_UNCHECKED);
}
}
}
//////////
// CMainWindow::OnCommandSuspend
// arguments: void
// returns: void
// function: suspends client
void CMainWindow::OnCommandSuspend()
{
gstate.suspend_requested = true;
CMenu* pMainMenu;
CMenu* pFileMenu;
pMainMenu = GetMenu();
if(pMainMenu) {
pFileMenu = pMainMenu->GetSubMenu(0);
}
if(pFileMenu) {
pFileMenu->EnableMenuItem(ID_FILE_SUSPEND, MF_GRAYED);
pFileMenu->EnableMenuItem(ID_FILE_RESUME, MF_ENABLED);
}
}
//////////
// CMainWindow::OnCommandResume
// arguments: void
// returns: void
// function: resumes client
void CMainWindow::OnCommandResume()
{
gstate.suspend_requested = false;
CMenu* pMainMenu;
CMenu* pFileMenu;
pMainMenu = GetMenu();
if(pMainMenu) {
pFileMenu = pMainMenu->GetSubMenu(0);
}
if(pFileMenu) {
pFileMenu->EnableMenuItem(ID_FILE_SUSPEND, MF_ENABLED);
pFileMenu->EnableMenuItem(ID_FILE_RESUME, MF_GRAYED);
}
}
//////////
// CMainWindow::OnCommandExit
// arguments: void
// returns: void
// function: cleans up, closes and quits everything
void CMainWindow::OnCommandExit()
{
// quit
gstate.cleanup_and_exit();
PostQuitMessage(0);
KillTimer(m_nGuiTimerID);
// status icon in taskbar
SetStatusIcon(ICON_OFF);
// clean up and delete objects
m_Font.DeleteObject();
m_TabBMP[0].DeleteObject();
m_TabBMP[1].DeleteObject();
m_TabBMP[2].DeleteObject();
m_TabBMP[3].DeleteObject();
m_TabBMP[4].DeleteObject();
m_TabIL.DeleteImageList();
m_MainMenu.DestroyMenu();
m_ContextMenu.DestroyMenu();
// free dll and idle detection
if(m_hIdleDll) {
typedef void (CALLBACK* TermFn)();
TermFn fn;
fn = (TermFn)GetProcAddress(m_hIdleDll, "IdleTrackerTerm");
if(!fn) {
show_message(NULL, "Error in DLL \"boinc.dll\"", MSG_INFO);
} else {
fn();
}
FreeLibrary(m_hIdleDll);
m_hIdleDll = NULL;
}
SaveUserSettings();
SaveListControls();
delete m_pSSWnd;
CWnd::OnClose();
}
//////////
// CMainWindow::OnCreate
// arguments: lpcs: a pointer to the create structure
// returns: 0 if successful, otherwise -1
// function: sets window's global variable, loads resource, creates child
// windows, and initializes client state and timer
int CMainWindow::OnCreate(LPCREATESTRUCT lpcs)
{
char curDir[512];
char* szTitles[MAX_COLS];
int i;
if (CWnd::OnCreate(lpcs) == -1) {
return -1;
}
// Determine the OS version
UtilInitOSVersion();
g_myWnd = this;
m_nIconState = ICON_OFF;
m_bMessage = false;
m_bRequest = false;
m_nContextItem = -1;
m_pSSWnd = new CSSWindow();
// load menus
m_ContextMenu.LoadMenu(IDR_CONTEXT);
m_MainMenu.LoadMenu(IDR_MAINFRAME);
SetMenu(&m_MainMenu);
LoadLanguage();
// create project list control
m_ProjectListCtrl.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, PROJECT_ID);
m_ProjectListCtrl.SetExtendedStyle(m_ProjectListCtrl.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT);
for(i = 0; i < MAX_COLS; i ++) szTitles[i] = g_szColumnTitles[PROJECT_ID][i];
m_ProjectListCtrl.SetMenuItems(szTitles, PROJECT_COLS);
for(i = 0; i < PROJECT_COLS; i ++) {
m_ProjectListCtrl.InsertColumn(i, g_szColumnTitles[PROJECT_ID][i], LVCFMT_LEFT, DEF_COL_WIDTH, -1);
}
// create result list control
m_ResultListCtrl.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, RESULT_ID);
m_ResultListCtrl.SetExtendedStyle(m_ResultListCtrl.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT);
m_ResultListCtrl.ModifyStyle(WS_VISIBLE, 0);
for(i = 0; i < MAX_COLS; i ++) szTitles[i] = g_szColumnTitles[RESULT_ID][i];
m_ResultListCtrl.SetMenuItems(szTitles, RESULT_COLS);
for(i = 0; i < RESULT_COLS; i ++) {
m_ResultListCtrl.InsertColumn(i, g_szColumnTitles[RESULT_ID][i], LVCFMT_LEFT, DEF_COL_WIDTH, -1);
}
// create xfer list control
m_XferListCtrl.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, XFER_ID);
m_XferListCtrl.SetExtendedStyle(m_XferListCtrl.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT);
m_XferListCtrl.ModifyStyle(WS_VISIBLE, 0);
for(i = 0; i < MAX_COLS; i ++) szTitles[i] = g_szColumnTitles[XFER_ID][i];
m_XferListCtrl.SetMenuItems(szTitles, XFER_COLS);
for(i = 0; i < XFER_COLS; i ++) {
m_XferListCtrl.InsertColumn(i, g_szColumnTitles[XFER_ID][i], LVCFMT_LEFT, DEF_COL_WIDTH, -1);
}
// create message edit control
// create xfer list control
m_MessageListCtrl.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, MESSAGE_ID);
m_MessageListCtrl.SetExtendedStyle(m_MessageListCtrl.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT);
m_MessageListCtrl.ModifyStyle(WS_VISIBLE, 0);
for(i = 0; i < MAX_COLS; i ++) szTitles[i] = g_szColumnTitles[MESSAGE_ID][i];
m_MessageListCtrl.SetMenuItems(szTitles, MESSAGE_COLS);
for(i = 0; i < MESSAGE_COLS; i ++) {
int width = DEF_COL_WIDTH;
if(i == 1) width *= 1.5;
if(i == 2) width *= 4;
m_MessageListCtrl.InsertColumn(i, g_szColumnTitles[MESSAGE_ID][i], LVCFMT_LEFT, width, -1);
}
// create usage pie control
m_UsagePieCtrl.Create(WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, USAGE_ID);
m_UsagePieCtrl.ModifyStyle(WS_VISIBLE, 0);
m_UsagePieCtrl.AddPiece(g_szUsageItems[0], GetPieColor(0), 0);
m_UsagePieCtrl.AddPiece(g_szUsageItems[1], GetPieColor(1), 0);
m_UsagePieCtrl.AddPiece(g_szUsageItems[2], GetPieColor(2), 0);
m_UsagePieCtrl.AddPiece(g_szUsageItems[3], GetPieColor(3), 0);
// set up image list for tab control
m_TabIL.Create(16, 16, ILC_COLOR8|ILC_MASK, MAX_TABS, 1);
m_TabBMP[0].LoadBitmap(IDB_PROJ);
m_TabIL.Add(&m_TabBMP[0], RGB(255, 0, 255));
m_TabBMP[1].LoadBitmap(IDB_RESULT);
m_TabIL.Add(&m_TabBMP[1], RGB(255, 0, 255));
m_TabBMP[2].LoadBitmap(IDB_XFER);
m_TabIL.Add(&m_TabBMP[2], RGB(255, 0, 255));
m_TabBMP[3].LoadBitmap(IDB_MESS);
m_TabIL.Add(&m_TabBMP[3], RGB(255, 0, 255));
m_TabBMP[4].LoadBitmap(IDB_USAGE);
m_TabIL.Add(&m_TabBMP[4], RGB(255, 0, 255));
// create tab control
m_TabCtrl.Create(TCS_FIXEDWIDTH|TCS_BUTTONS|TCS_FLATBUTTONS|TCS_FOCUSNEVER|WS_CHILD|WS_VISIBLE, CRect(0,0,0,0), this, TAB_ID);
m_TabCtrl.SetImageList(&m_TabIL);
m_TabCtrl.InsertItem(1, g_szTabItems[0], 0);
m_TabCtrl.InsertItem(2, g_szTabItems[1], 1);
m_TabCtrl.InsertItem(3, g_szTabItems[2], 2);
m_TabCtrl.InsertItem(4, g_szTabItems[3], 3);
m_TabCtrl.InsertItem(5, g_szTabItems[4], 4);
// make all fonts the same nice font
CFont* pFont;
pFont = m_ProjectListCtrl.GetFont();
LOGFONT lf;
ZeroMemory(&lf, sizeof(LOGFONT));
pFont->GetLogFont(&lf);
m_Font.CreateFontIndirect(&lf);
m_TabCtrl.SetFont(&m_Font);
m_UsagePieCtrl.SetFont(&m_Font);
// Set the current directory to the default
UtilGetRegStr("ClientDir", curDir);
if (strlen(curDir))
SetCurrentDirectory(curDir);
// add status icon to taskbar
SetStatusIcon(ICON_NORMAL);
// take care of other things
//
// Redirect stdout and stderr to files
freopen(STDOUT_FILE_NAME, "w", stdout);
freopen(STDERR_FILE_NAME, "w", stderr);
// Check what (if any) activities should be logged
read_log_flags();
LoadUserSettings();
LoadListControls();
LPSTR command_line;
char* argv[100];
int argc;
command_line = GetCommandLine();
argc = parse_command_line( command_line, argv );
gstate.parse_cmdline(argc, argv);
int retval = gstate.init();
if (retval) {
OnCommandExit();
return 0;
}
m_nGuiTimerID = SetTimer(GUI_TIMER, GUI_WAIT, (TIMERPROC) NULL);
// load dll and start idle detection
m_hIdleDll = LoadLibrary("boinc.dll");
if(!m_hIdleDll) {
show_message(NULL,"Can't load \"boinc.dll\", will not be able to determine idle time", MSG_ERROR);
} else {
typedef BOOL (CALLBACK* InitFn)();
InitFn fn;
fn = (InitFn)GetProcAddress(m_hIdleDll, "IdleTrackerInit");
if(!fn) {
show_message(NULL,"Error in DLL \"boinc.dll\", will not be able to determine idle time", MSG_INFO);
FreeLibrary(m_hIdleDll);
m_hIdleDll = NULL;
} else {
if(!fn()) {
show_message(NULL,"Error in DLL \"boinc.dll\", will not be able to determine idle time", MSG_INFO);
FreeLibrary(m_hIdleDll);
m_hIdleDll = NULL;
}
}
}
UpdateGUI(&gstate);
// see if we need to add this to startup
if(gstate.global_prefs.run_on_startup) {
UtilGetRegStr("ClientPath", curDir);
if(strlen(curDir)) {
strcat(curDir, " -min");
UtilSetRegStartupStr("boincclient", curDir);
}
} else {
UtilSetRegStartupStr("boincclient", "");
}
// see if we need to hide the window
if(gstate.global_prefs.run_minimized || gstate.start_saver) {
ShowWindow(SW_HIDE);
} else {
ShowWindow(SW_SHOW);
}
if(gstate.suspend_requested) OnCommandSuspend();
else OnCommandResume();
return 0;
}
//////////
// CMainWindow::OnNotify
// arguments: wParam: notification's wparam
// lParam: notification's lparam
// pResult: pointer to result of notification
// returns: true if the notification is processed, otherwise false
// function: handles notifications from children, including:
// user selecting a new tab sets display to selected tab's control
BOOL CMainWindow::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
HD_NOTIFY* phdn = (HD_NOTIFY*)lParam;
// notification from tab control, user is changing the selection
if(phdn->hdr.code == TCN_SELCHANGE) {
int newTab = m_TabCtrl.GetCurSel();
ShowTab(newTab);
}
return CWnd::OnNotify(wParam, lParam, pResult);
}
//////////
// CMainWindow::OnRButtonDown
// arguments: nFlags: message flags (keys down)
// point: mouse's point
// returns: void
// function: shows context menu for list items
void CMainWindow::OnRButtonDown(UINT nFlags, CPoint point)
{
CMenu* pContextMenu = NULL;
GetCursorPos(&point);
CRect rt;
CListCtrl* pMenuCtrl = NULL;
int nMenuId = -1;
if(m_ProjectListCtrl.IsWindowVisible()) {
pMenuCtrl = &m_ProjectListCtrl;
nMenuId = PROJECT_MENU;
} else if(m_ResultListCtrl.IsWindowVisible()) {
pMenuCtrl = &m_ResultListCtrl;
nMenuId = RESULT_MENU;
} else if(m_XferListCtrl.IsWindowVisible()) {
pMenuCtrl = &m_XferListCtrl;
nMenuId = XFER_MENU;
}
if(pMenuCtrl) {
for(int i = 0; i < pMenuCtrl->GetItemCount(); i ++) {
pMenuCtrl->GetItemRect(i, &rt, LVIR_BOUNDS);
pMenuCtrl->ClientToScreen(&rt);
if(rt.PtInRect(point)) {
pContextMenu = m_ContextMenu.GetSubMenu(nMenuId);
if(pContextMenu) {
pContextMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
m_nContextItem = i;
}
break;
}
}
}
//CWnd::OnRButtonDown(nFlags, point);
}
//////////
// CMainWindow::OnFocus
// arguments: pOldWnd: pointer to previous window that had focus
// returns: void
// function: if there is a message for the user when this window
// gets the focus, selects the message tab
void CMainWindow::OnSetFocus(CWnd* pOldWnd)
{
if(m_TabCtrl.GetSafeHwnd() && m_bMessage) {
m_TabCtrl.SetCurSel(MESSAGE_ID);
m_ProjectListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_ResultListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_XferListCtrl.ModifyStyle(WS_VISIBLE, 0);
m_MessageListCtrl.ModifyStyle(0, WS_VISIBLE);
m_UsagePieCtrl.ModifyStyle(WS_VISIBLE, 0);
m_MessageListCtrl.RedrawWindow(NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
m_bMessage = false;
SetStatusIcon(ICON_NORMAL);
}
if(m_bRequest) {
m_bRequest = false;
if(RequestNetConnect()) OnCommandConnectionConnectNow();
}
}
//////////
// CMainWindow::OnSize
// arguments: nType: type of resizing
// cx: new width of window
// cy: new height of window
// returns: void
// function: calculates new rectangles for child windows and resizes
// them appropriately
void CMainWindow::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
// calculate the main rect for the tab control
RECT rt = {EDGE_BUFFER, TOP_BUFFER, cx-EDGE_BUFFER, cy-EDGE_BUFFER*2};
RECT irt = {0, 0, 0, 0};
if(m_TabCtrl.GetSafeHwnd()) {
m_TabCtrl.MoveWindow(&rt, false);
m_TabCtrl.GetItemRect(0, &irt);
// calculate the rects for other controls inside the tab control
RECT srt = {rt.left+EDGE_BUFFER, irt.bottom+EDGE_BUFFER*2+TOP_BUFFER, rt.right-EDGE_BUFFER, rt.bottom-EDGE_BUFFER};
if(m_ProjectListCtrl.GetSafeHwnd()) {
m_ProjectListCtrl.MoveWindow(&srt, false);
m_ProjectListCtrl.RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
if(m_ResultListCtrl.GetSafeHwnd()) {
m_ResultListCtrl.MoveWindow(&srt, false);
m_ResultListCtrl.RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
if(m_XferListCtrl.GetSafeHwnd()) {
m_XferListCtrl.MoveWindow(&srt, false);
m_XferListCtrl.RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
if(m_MessageListCtrl.GetSafeHwnd()) {
m_MessageListCtrl.MoveWindow(&srt, false);
m_MessageListCtrl.RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
if(m_UsagePieCtrl.GetSafeHwnd()) {
m_UsagePieCtrl.MoveWindow(&srt, false);
m_UsagePieCtrl.RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_NOERASE|RDW_FRAME);
}
m_TabCtrl.RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_NOERASE|RDW_FRAME);
RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ERASE|RDW_FRAME);
}
}
//////////
// CMainWindow::OnStatusIcon
// arguments: wParam: id of icon clicked
// lParam: message from icon
// returns: true if the menu is shown, false otherwise
// function: handles messages from status icon, including:
// right click: shows popup menu
// double click: alternates visibility of window
LRESULT CMainWindow::OnStatusIcon(WPARAM wParam, LPARAM lParam)
{
if(lParam == WM_RBUTTONDOWN) {
CPoint point;
SetForegroundWindow();
GetCursorPos(&point);
CMenu* pSubmenu;
pSubmenu = m_ContextMenu.GetSubMenu(STATUS_MENU);
if(IsSuspended()) {
pSubmenu->EnableMenuItem(ID_STATUSICON_SUSPEND, MF_GRAYED);
pSubmenu->EnableMenuItem(ID_STATUSICON_RESUME, MF_ENABLED);
} else {
pSubmenu->EnableMenuItem(ID_STATUSICON_SUSPEND, MF_ENABLED);
pSubmenu->EnableMenuItem(ID_STATUSICON_RESUME, MF_GRAYED);
}
pSubmenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
} else if(lParam == WM_LBUTTONDOWN) {
if(IsWindowVisible()) {
SetForegroundWindow();
}
} else if(lParam == WM_LBUTTONDBLCLK) {
if(IsWindowVisible()) {
ShowWindow(SW_HIDE);
} else {
ShowWindow(SW_SHOW);
}
}
return TRUE;
}
//////////
// CMainWindow::OnTimer
// arguments: uEventID: timer's id
// returns: void
// function: checks idle time, updates client state, flushed output streams,
// and updates gui display.
void CMainWindow::OnTimer(UINT uEventID)
{
if(uEventID == m_nGuiTimerID) {
// stop the timer while we do processing
KillTimer(m_nGuiTimerID);
// update state and gui
while(gstate.do_something());
NetCheck(); // need to check if network connection can be terminated
fflush(stdout);
fflush(stderr);
if(!IsSuspended()) {
// check user's idle time for suspension of apps
if (gstate.global_prefs.idle_time_to_run > 0) {
if (GetUserIdleTime() > 1000 * gstate.global_prefs.idle_time_to_run) {
gstate.user_idle = true;
} else {
gstate.user_idle = false;
}
} else {
gstate.user_idle = true;
}
UpdateGUI(&gstate);
}
// Start the timer again
m_nGuiTimerID = SetTimer(GUI_TIMER, GUI_WAIT, (TIMERPROC) NULL);
}
}