// includes #include "wingui.h" // globals CMainWindow* myWnd; CMyApp myApp; void show_message(char* message, char* priority) { if (!strcmp(priority, "high")) { fprintf(stderr, "BOINC core client: %s (priority: %s)\n", message, priority); } else { printf("BOINC core client: %s (priority: %s)\n", message, priority); } } int get_initial_project() { CLoginDialog dlg(IDD_LOGIN); int retval = dlg.DoModal(); if (retval != IDOK) return -1; write_account_file(dlg.m_url.GetBuffer(0), dlg.m_auth.GetBuffer(0)); return 0; } ///////////////////////////////////////////////////////////////////////// // CProgressHeaderCtrl message map and member functions BEGIN_MESSAGE_MAP (CProgressBarCtrl, CProgressCtrl) ON_WM_LBUTTONDOWN () ON_WM_LBUTTONUP () END_MESSAGE_MAP () CProgressBarCtrl::CProgressBarCtrl() { } void CProgressBarCtrl::OnLButtonDown(UINT nFlags, CPoint point) { CProgressCtrl::OnLButtonDown(nFlags, point); // if this control has a parent, repackage this message and forward it CWnd* parent = GetParent(); if(parent) { MapWindowPoints(parent,&point,1); WPARAM wParam = nFlags; LPARAM lParam = MAKELPARAM(point.x, point.y); parent->SendMessage(WM_LBUTTONDOWN, wParam, lParam); } } void CProgressBarCtrl::OnLButtonUp(UINT nFlags, CPoint point) { CProgressCtrl::OnLButtonUp(nFlags, point); // if this control has a parent, repackage this message and forward it CWnd* parent = GetParent(); if(parent) { MapWindowPoints(parent,&point,1); WPARAM wParam = nFlags; LPARAM lParam = MAKELPARAM(point.x, point.y); parent->SendMessage(WM_LBUTTONUP, wParam, lParam); } } ///////////////////////////////////////////////////////////////////////// // CProgressHeaderCtrl message map and member functions BEGIN_MESSAGE_MAP (CProgressHeaderCtrl, CHeaderCtrl) ON_WM_RBUTTONDOWN () END_MESSAGE_MAP () CProgressHeaderCtrl::CProgressHeaderCtrl() { } void CProgressHeaderCtrl::OnRButtonDown(UINT nFlags, CPoint point) { CHeaderCtrl::OnRButtonDown(nFlags, point); // if this control has a parent, repackage this message and forward it CWnd* parent = GetParent(); if(parent) { MapWindowPoints(parent,&point,1); WPARAM wParam = nFlags; LPARAM lParam = MAKELPARAM(point.x, point.y); parent->SendMessage(WM_RBUTTONDOWN, wParam, lParam); } } ///////////////////////////////////////////////////////////////////////// // CProgressListCtrl message map and member functions BEGIN_MESSAGE_MAP(CProgressListCtrl, CListCtrl) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_PAINT() ON_WM_RBUTTONDOWN() END_MESSAGE_MAP() CProgressListCtrl::CProgressListCtrl() { } int CProgressListCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1) { m_ColWidths.SetAtGrow(nCol, nWidth); return CListCtrl::InsertColumn(nCol, lpszColumnHeading, nFormat, nWidth, nSubItem); } BOOL CProgressListCtrl::SetColumnWidth(int nCol, int cx) { return CListCtrl::SetColumnWidth(nCol, cx); } void CProgressListCtrl::SetItemProgress(int item, int subitem, int prog) { CRect rt; CString str; CProgressCtrl* progCtrl = NULL; if(prog > 100) prog = 100; // lookup the position of the progress control str.Format("%d:%d", item, subitem); m_Progs.Lookup(str, (CObject*&)progCtrl); if(progCtrl) { // found, so just update it's progress progCtrl->SetPos(prog); } else { // not found, create one and put it in the map GetSubItemRect(item, subitem, LVIR_BOUNDS, rt); progCtrl = new CProgressBarCtrl(); progCtrl->Create(PBS_SMOOTH|WS_CHILD|WS_VISIBLE, rt, this, 0); progCtrl->SetPos(prog); m_Progs.SetAt(str, progCtrl); } } void CProgressListCtrl::RepositionProgress() { int item, subitem; CRect rt, hrt; CString str; CProgressCtrl* progCtrl = NULL; GetHeaderCtrl()->GetClientRect(hrt); // iterate through each progress control POSITION pos = m_Progs.GetStartPosition(); while (pos != NULL) { // look at the progress control and move it m_Progs.GetNextAssoc(pos, str, (CObject*&)progCtrl); sscanf(str.GetBuffer(0), "%d:%d", &item, &subitem); GetSubItemRect(item, subitem, LVIR_BOUNDS, rt); rt.top ++; rt.left ++; rt.bottom --; rt.right --; // if it's over the header, move it to where it can't be seen if(rt.top < hrt.bottom) { rt.top = -10; rt.bottom = 0; } progCtrl->MoveWindow(rt, false); } Invalidate(false); } void CProgressListCtrl::SwapItems(int i1, int i2) { int nCols = GetHeaderCtrl()->GetItemCount(); CProgressCtrl* progCtrl1 = NULL; CProgressCtrl* progCtrl2 = NULL; CString txt1, txt2; int si; // check item indicies if(i1 >= GetItemCount() || i2 >= GetItemCount()) { return; } for(si = 0; si < nCols; si ++) { // swap text txt1 = GetItemText(i1, si); txt2 = GetItemText(i2, si); SetItemText(i1, si, txt2); SetItemText(i2, si, txt1); // swap progress control if found txt1.Format("%d:%d", i1, si); txt2.Format("%d:%d", i2, si); m_Progs.Lookup(txt1, (CObject*&)progCtrl1); m_Progs.Lookup(txt2, (CObject*&)progCtrl2); if(progCtrl1) { m_Progs.RemoveKey(txt2); m_Progs.SetAt(txt2, (CObject*&)progCtrl1); } if(progCtrl2) { m_Progs.RemoveKey(txt1); m_Progs.SetAt(txt1, (CObject*&)progCtrl2); } } } void CProgressListCtrl::Sort(int si, int order) { int i, j, min, z; CString stri, strj; CProgressCtrl* progi = NULL; CProgressCtrl* progj = NULL; // check subitem is in bounds if(si >= GetHeaderCtrl()->GetItemCount()) { return; } // run selection sort for now int items = GetItemCount(); for(z = 0; z < GetItemCount(); z ++) { for(i = 0; i < items-1; i ++) { min = i; for(j = i+1; j < items; j ++) { // see if there is a progress control here, and set its // progress as the comparison string, otherwise, // just get the text stri.Format("%d:%d", i, si); strj.Format("%d:%d", j, si); m_Progs.Lookup(stri, (CObject*&)progi); m_Progs.Lookup(strj, (CObject*&)progj); if(progi) { stri.Format("%0.3d", progi->GetPos()); } else { stri = GetItemText(i, si); } if(progj) { strj.Format("%0.3d", progj->GetPos()); } else { strj = GetItemText(j, si); } if(order == SORT_ASCEND && strcmp(stri, strj) > 0) min = j; if(order == SORT_DESCEND && strcmp(stri, strj) < 0) min = j; } SwapItems(i, min); } } RepositionProgress(); } void CProgressListCtrl::SwapColumnVisibility(int col) { CHeaderCtrl* header = GetHeaderCtrl(); CMenu* menu = m_PopupMenu.GetSubMenu(GetDlgCtrlID()); if(header && col < header->GetItemCount()) { if(GetColumnWidth(col) == 0) { SetColumnWidth(col, m_ColWidths.GetAt(col)); if(menu) { menu->CheckMenuItem(PopupFromColumn(col), MF_CHECKED); } } else { SetColumnWidth(col, 0); if(menu) { menu->CheckMenuItem(PopupFromColumn(col), MF_UNCHECKED); } } } } int CProgressListCtrl::ColumnFromPopup(int p) { switch(p) { case ID_POPUP_0: return 0; case ID_POPUP_1: return 1; case ID_POPUP_2: return 2; case ID_POPUP_3: return 3; } return -1; } int CProgressListCtrl::PopupFromColumn(int c) { switch(c) { case 0: return ID_POPUP_0; case 1: return ID_POPUP_1; case 2: return ID_POPUP_2; case 3: return ID_POPUP_3; } return -1; } int CProgressListCtrl::OnCreate(LPCREATESTRUCT lpcs) { if(CListCtrl::OnCreate(lpcs) == -1) { return -1; } // load popup menu m_PopupMenu.LoadMenu(IDR_POPUP); // subclass header m_iSort = 0; CHeaderCtrl* header = GetHeaderCtrl(); if(header) { HWND hWnd = header->GetSafeHwnd(); if(hWnd) { m_Header.SubclassWindow(hWnd); } } return 0; } void CProgressListCtrl::OnDestroy() { CString str; CProgressCtrl* progCtrl = NULL; // iterate through each progress control POSITION pos = m_Progs.GetStartPosition(); while (pos != NULL) { // remove the control and delete it m_Progs.GetNextAssoc(pos, str, (CObject*&)progCtrl); m_Progs.RemoveKey(str); delete progCtrl; } } void CProgressListCtrl::OnRButtonDown(UINT nFlags, CPoint point) { ClientToScreen(&point); // see if user clicked on header and do its popup menu CHeaderCtrl* header = GetHeaderCtrl(); if(header) { CRect rt; header->GetWindowRect(&rt); if(rt.PtInRect(point)) { CMenu* menu = m_PopupMenu.GetSubMenu(GetDlgCtrlID()); if(menu) { menu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this); } } } //CListCtrl::OnRButtonDown(nFlags, point); } BOOL CProgressListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { HD_NOTIFY* phdn = (HD_NOTIFY*)lParam; // notification from header, user has clicked a header if(phdn->hdr.code == HDN_ITEMCLICKA || phdn->hdr.code == HDN_ITEMCLICKW) { int newSort = phdn->iItem + 1; // if this header was clicked before, alternate sorts, other wise just sort if(newSort == abs(m_iSort)) { m_iSort *= -1; if(m_iSort < 0) Sort(abs(m_iSort)-1, SORT_DESCEND); else Sort(abs(m_iSort)-1, SORT_ASCEND); } else { m_iSort = newSort; Sort(abs(m_iSort)-1, SORT_ASCEND); } } // notification from header, user has started tracking a header if(phdn->hdr.code == HDN_BEGINTRACKA || phdn->hdr.code == HDN_BEGINTRACKW) { // stop the header from tracking int col = phdn->iItem; if(GetColumnWidth(col) == 0) { *pResult = TRUE; return TRUE; } } // notification from header, user has finished tracking a header if(phdn->hdr.code == HDN_ENDTRACKA || phdn->hdr.code == HDN_ENDTRACKW) { // store the new width int col = phdn->iItem; m_ColWidths.SetAtGrow(col, GetColumnWidth(col)); } return CListCtrl::OnNotify(wParam, lParam, pResult); } void CProgressListCtrl::OnPaint() { RepositionProgress(); CListCtrl::OnPaint(); } BOOL CProgressListCtrl::OnCommand(WPARAM wParam, LPARAM lParam) { if(ColumnFromPopup(wParam) != -1) { SwapColumnVisibility(ColumnFromPopup(wParam)); } return CListCtrl::OnCommand(wParam, lParam); } ///////////////////////////////////////////////////////////////////////// // CMyApp member functions BOOL CMyApp::InitInstance() { m_pMainWnd = new CMainWindow(); m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } ///////////////////////////////////////////////////////////////////////// // CMainWindow message map and member functions BEGIN_MESSAGE_MAP(CMainWindow, CWnd) ON_WM_CREATE() ON_WM_PAINT() ON_WM_SIZE() ON_COMMAND(ID_FILE_CLOSE, OnCommandFileClose) ON_COMMAND(ID_ACCT_LOGIN, OnCommandAccountLogin) ON_COMMAND(ID_HELP_ABOUT, OnCommandHelpAbout) END_MESSAGE_MAP() CMainWindow::CMainWindow() { // clear pointers... m_bCreated = false; // register window class CString strWndClass = AfxRegisterWndClass (0, myApp.LoadStandardCursor(IDC_ARROW), (HBRUSH)(COLOR_3DFACE+1), myApp.LoadIcon(IDI_ICONSM)); // create and position window CreateEx(0, strWndClass, "BOINC", WS_OVERLAPPEDWINDOW|WS_EX_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL); CRect rect(0, 0, 420, 500); CalcWindowRect(&rect); SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_NOZORDER|SWP_NOMOVE|SWP_NOREDRAW); } void CALLBACK CMainWindow::TimerProc(HWND h, UINT x, UINT id, DWORD time) { while (gstate.do_something()); fflush(stdout); fflush(stderr); } void CMainWindow::MessageUser(char* s) { // put message in control if(m_bCreated) { CString text; m_CtrlMessages.GetWindowText(text); text += s; m_CtrlMessages.SetWindowText(text); m_CtrlMessages.RedrawWindow(); } } void CMainWindow::PostNcDestroy() { delete this; } void CMainWindow::OnCommandAccountLogin() { CLoginDialog dlg(IDD_LOGIN); int retval = dlg.DoModal(); } void CMainWindow::OnCommandFileClose() { SendMessage(WM_CLOSE, 0, 0); } void CMainWindow::OnCommandHelpAbout() { CDialog dlg(IDD_ABOUTBOX); int retval = dlg.DoModal(); /* // add some random info CString strText; for (int j=0;j < 5;j++) { int i = m_CtrlProjects.GetItemCount(); strText.Format("Project-%d", i); m_CtrlProjects.InsertItem(i, strText); strText.Format("http://%d", i); m_CtrlProjects.SetItemText(i, 1, strText); strText.Format("%d", rand()); m_CtrlProjects.SetItemText(i, 2, strText); strText.Format(""); m_CtrlProjects.SetItemText(i, 3, strText); m_CtrlProjects.SetItemProgress(i, 3, rand()%100); } */ } int CMainWindow::OnCreate(LPCREATESTRUCT lpcs) { if (CWnd::OnCreate(lpcs) == -1) { return -1; } CClientDC dc(this); myWnd = this; // load main menu m_MainMenu.LoadMenu(IDR_MAINFRAME); SetMenu(&m_MainMenu); // create controls and temporarily position them m_CtrlProjects.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, 0); m_CtrlProjects.SetExtendedStyle(m_CtrlProjects.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT); m_CtrlProjects.InsertColumn(0, "Name", LVCFMT_LEFT, 100); m_CtrlProjects.InsertColumn(1, "URL", LVCFMT_LEFT, 100); m_CtrlProjects.InsertColumn(2, "Total", LVCFMT_LEFT, 100); m_CtrlProjects.InsertColumn(3, "Share", LVCFMT_LEFT, 100); m_CtrlXfers.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, 1); m_CtrlXfers.SetExtendedStyle(m_CtrlXfers.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT); m_CtrlXfers.ModifyStyle(WS_VISIBLE, 0); m_CtrlXfers.InsertColumn(0, "Project", LVCFMT_LEFT, 100); m_CtrlXfers.InsertColumn(1, "Name", LVCFMT_LEFT, 100); m_CtrlXfers.InsertColumn(2, "Completion", LVCFMT_LEFT, 100); m_CtrlWorkunits.Create(LVS_REPORT|WS_CHILD|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, 2); m_CtrlWorkunits.SetExtendedStyle(m_CtrlWorkunits.GetExtendedStyle()|LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT); m_CtrlWorkunits.ModifyStyle(WS_VISIBLE, 0); m_CtrlWorkunits.InsertColumn(0, "Project", LVCFMT_LEFT, 100); m_CtrlWorkunits.InsertColumn(1, "Name", LVCFMT_LEFT, 100); m_CtrlWorkunits.InsertColumn(2, "Completion", LVCFMT_LEFT, 100); m_CtrlMessages.Create(ES_MULTILINE|ES_READONLY|WS_CHILD|WS_TABSTOP|WS_BORDER|WS_VISIBLE, CRect(0,0,0,0), this, 3); m_CtrlMessages.ModifyStyle(WS_VISIBLE, 0); m_Tabs.Create(TCS_BUTTONS|TCS_FIXEDWIDTH|WS_CHILD|WS_VISIBLE, CRect(0,0,0,0), this, 0); m_Tabs.InsertItem(0, "Projects"); m_Tabs.InsertItem(1, "Xfers"); m_Tabs.InsertItem(2, "Workunits"); m_Tabs.InsertItem(3, "Messages"); // load images m_Logo.LoadBitmap(IDB_LOGO); // take care of other things NetOpen(); freopen("stdout.txt", "w", stdout); freopen("stderr.txt", "w", stderr); read_log_flags(); int retval = gstate.init(); if (retval) exit(retval); SetTimer(ID_TIMER, 1000, TimerProc); m_bCreated = true; return 0; } 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_Tabs.GetCurSel(); // make the selected control visible, all the rest invisible if(newTab == 0) { m_CtrlProjects.ModifyStyle(0, WS_VISIBLE); m_CtrlXfers.ModifyStyle(WS_VISIBLE, 0); m_CtrlWorkunits.ModifyStyle(WS_VISIBLE, 0); m_CtrlMessages.ModifyStyle(WS_VISIBLE, 0); } else if(newTab == 1) { m_CtrlProjects.ModifyStyle(WS_VISIBLE, 0); m_CtrlXfers.ModifyStyle(0, WS_VISIBLE); m_CtrlWorkunits.ModifyStyle(WS_VISIBLE, 0); m_CtrlMessages.ModifyStyle(WS_VISIBLE, 0); } else if(newTab == 2) { m_CtrlProjects.ModifyStyle(WS_VISIBLE, 0); m_CtrlXfers.ModifyStyle(WS_VISIBLE, 0); m_CtrlWorkunits.ModifyStyle(0, WS_VISIBLE); m_CtrlMessages.ModifyStyle(WS_VISIBLE, 0); } else if(newTab == 3) { m_CtrlProjects.ModifyStyle(WS_VISIBLE, 0); m_CtrlXfers.ModifyStyle(WS_VISIBLE, 0); m_CtrlWorkunits.ModifyStyle(WS_VISIBLE, 0); m_CtrlMessages.ModifyStyle(0, WS_VISIBLE); } Invalidate(false); } return CWnd::OnNotify(wParam, lParam, pResult); } void CMainWindow::OnPaint() { CWnd::OnPaint(); /* CClientDC dc(this); CDC logoDC; logoDC.CreateCompatibleDC(&dc); logoDC.SelectObject(&m_Logo); dc.BitBlt(0,0,166,150,&logoDC,0,0,SRCCOPY); */ } 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, EDGE_BUFFER, cx-EDGE_BUFFER, cy-EDGE_BUFFER*2}; RECT irt = {0, 0, 0, 0}; float szDiv = (rt.bottom-rt.top)/100.0; if(m_bCreated) { m_Tabs.MoveWindow(&rt, false); m_Tabs.GetItemRect(0, &irt); // calculate the rects for other controls inside the tab control RECT srt = {rt.left+EDGE_BUFFER, irt.bottom+EDGE_BUFFER*2, rt.right-EDGE_BUFFER, rt.bottom-EDGE_BUFFER}; m_CtrlProjects.MoveWindow(&srt, false); m_CtrlXfers.MoveWindow(&srt, false); m_CtrlWorkunits.MoveWindow(&srt, false); m_CtrlMessages.MoveWindow(&srt, false); Invalidate(false); } } ///////////////////////////////////////////////////////////////////////// // CLoginDialog message map and member functions BEGIN_MESSAGE_MAP(CLoginDialog, CDialog) ON_BN_CLICKED(IDOK, OnOK) END_MESSAGE_MAP() CLoginDialog::CLoginDialog(UINT y) : CDialog(y) { } BOOL CLoginDialog::OnInitDialog() { CDialog::OnInitDialog(); CenterWindow(); return TRUE; } void CLoginDialog::OnOK() { GetDlgItemText(IDC_LOGIN_URL, m_url); GetDlgItemText(IDC_LOGIN_AUTH, m_auth); CDialog::OnOK(); }