From 1f1cc48a4c33be915e2dfb91508dbd75b3829a8f Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Wed, 29 Oct 2008 22:44:55 +0000 Subject: [PATCH] - client: include precompiled header in rr_sim.cpp so memory leak detection will work. - MGR: Have the BaseFrame call a function to determine if the selection list should be saved instead of traversing the application pointer. Each view just overrides the function returning a true/false value. We don't have to worry about null pointers and the like. - MGR: BOINCGUIApp should never need to know how either the views work or the document. Move the code that determines which RPCs should be fired into each of the views. Have the document look for it there. - MGR: Reduce duplicate code for hiding and showing an application - MGR: Move some Windows and Mac specific code into functions and streamline the application startup and shutdown rountines. - MGR: Move the event processing that was in BOINCGUIApp into the BaseFrame. - MGR: General cleanup. - MGR: Doxygen comments. - MGR: Cleanup some warnings. client/ rr_sim.cpp clientgui/ AdvancedFrame.cpp, .h AsyncRPC.cpp, .h BOINCBaseFrame.cpp, .h BOINCBaseView.cpp, .h BOINCClientManager.cpp BOINCGUIApp.cpp, .h BOINCTaskBar.cpp MainDocument.cpp, .h sg_BoincSimpleGUI.cpp, .h ViewProjects.cpp, .h ViewTransfers.cpp, .h ViewWork.cpp, .h WelcomePage.cpp win_build/installerv2/ BOINC.ism BOINCx64.ism win_build/ sim.vcproj svn path=/trunk/boinc/; revision=16357 --- checkin_notes | 45 +- client/rr_sim.cpp | 750 ++++++++++---------- clientgui/AdvancedFrame.cpp | 25 +- clientgui/AdvancedFrame.h | 27 +- clientgui/AsyncRPC.cpp | 135 ++-- clientgui/AsyncRPC.h | 27 +- clientgui/BOINCBaseFrame.cpp | 55 +- clientgui/BOINCBaseFrame.h | 18 +- clientgui/BOINCBaseView.cpp | 16 +- clientgui/BOINCBaseView.h | 4 + clientgui/BOINCClientManager.cpp | 2 +- clientgui/BOINCGUIApp.cpp | 1051 ++++++++++++++-------------- clientgui/BOINCGUIApp.h | 58 +- clientgui/BOINCTaskBar.cpp | 15 +- clientgui/MainDocument.cpp | 10 +- clientgui/MainDocument.h | 2 +- clientgui/ViewProjects.cpp | 4 + clientgui/ViewProjects.h | 2 + clientgui/ViewTransfers.cpp | 5 + clientgui/ViewTransfers.h | 2 + clientgui/ViewWork.cpp | 5 + clientgui/ViewWork.h | 3 + clientgui/WelcomePage.cpp | 2 +- clientgui/sg_BoincSimpleGUI.cpp | 10 + clientgui/sg_BoincSimpleGUI.h | 27 +- win_build/installerv2/BOINC.ism | Bin 211404 -> 211404 bytes win_build/installerv2/BOINCx64.ism | Bin 211404 -> 211404 bytes win_build/sim.vcproj | 2 + 28 files changed, 1208 insertions(+), 1094 deletions(-) diff --git a/checkin_notes b/checkin_notes index 8f401d2df5..f22e2e3838 100644 --- a/checkin_notes +++ b/checkin_notes @@ -8850,4 +8850,47 @@ David 29 Oct 2008 client/ client_state.h cpu_sched.cpp - sim.h \ No newline at end of file + sim.h + +Rom 29 Oct 2008 + - client: include precompiled header in rr_sim.cpp so memory + leak detection will work. + - MGR: Have the BaseFrame call a function to determine if the + selection list should be saved instead of traversing + the application pointer. Each view just overrides the function + returning a true/false value. We don't have to worry about null + pointers and the like. + - MGR: BOINCGUIApp should never need to know how either the views + work or the document. Move the code that determines which + RPCs should be fired into each of the views. Have the document + look for it there. + - MGR: Reduce duplicate code for hiding and showing an application + - MGR: Move some Windows and Mac specific code into functions + and streamline the application startup and shutdown rountines. + - MGR: Move the event processing that was in BOINCGUIApp into the + BaseFrame. + - MGR: General cleanup. + - MGR: Doxygen comments. + - MGR: Cleanup some warnings. + + client/ + rr_sim.cpp + clientgui/ + AdvancedFrame.cpp, .h + AsyncRPC.cpp, .h + BOINCBaseFrame.cpp, .h + BOINCBaseView.cpp, .h + BOINCClientManager.cpp + BOINCGUIApp.cpp, .h + BOINCTaskBar.cpp + MainDocument.cpp, .h + sg_BoincSimpleGUI.cpp, .h + ViewProjects.cpp, .h + ViewTransfers.cpp, .h + ViewWork.cpp, .h + WelcomePage.cpp + win_build/installerv2/ + BOINC.ism + BOINCx64.ism + win_build/ + sim.vcproj diff --git a/client/rr_sim.cpp b/client/rr_sim.cpp index 7d0d401370..f2c915fa14 100644 --- a/client/rr_sim.cpp +++ b/client/rr_sim.cpp @@ -1,377 +1,381 @@ -// This file is part of BOINC. -// http://boinc.berkeley.edu -// Copyright (C) 2008 University of California -// -// BOINC is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation, -// either version 3 of the License, or (at your option) any later version. -// -// BOINC is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// See the GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with BOINC. If not, see . - +// This file is part of BOINC. +// http://boinc.berkeley.edu +// Copyright (C) 2008 University of California +// +// BOINC is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// BOINC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with BOINC. If not, see . + +#ifdef _WIN32 +#include "boinc_win.h" +#endif + #ifdef SIM #include "sim.h" #else #include "client_state.h" -#endif -#include "client_msgs.h" - -struct RR_SIM_STATUS { - std::vector active; - COPROCS coprocs; - - inline bool can_run(RESULT* rp) { - return coprocs.sufficient_coprocs( - rp->avp->coprocs, log_flags.rr_simulation, "rr_simulation" - ); - } - inline void activate(RESULT* rp) { - coprocs.reserve_coprocs( - rp->avp->coprocs, rp, log_flags.rr_simulation, "rr_simulation" - ); - active.push_back(rp); - } - // remove *rpbest from active set, - // and adjust CPU time left for other results - // - inline void remove_active(RESULT* rpbest) { - coprocs.free_coprocs(rpbest->avp->coprocs, rpbest, log_flags.rr_simulation, "rr_simulation"); - vector::iterator it = active.begin(); - while (it != active.end()) { - RESULT* rp = *it; - if (rp == rpbest) { - it = active.erase(it); - } else { - rp->rrsim_cpu_left -= rp->project->rr_sim_status.proc_rate*rpbest->rrsim_finish_delay; - it++; - } - } - } - inline int nactive() { - return (int) active.size(); - } - ~RR_SIM_STATUS() { - coprocs.delete_coprocs(); - } -}; - -// Set the project's rrsim_proc_rate: -// the fraction of each CPU that it will get in round-robin mode. -// Precondition: the project's "active" array is populated -// -void PROJECT::set_rrsim_proc_rate(double rrs) { - int nactive = (int)rr_sim_status.active.size(); - if (nactive == 0) return; - double x; - - if (rrs) { - x = resource_share/rrs; - } else { - x = 1; // pathological case; maybe should be 1/# runnable projects - } - - // if this project has fewer active results than CPUs, - // scale up its share to reflect this - // - if (nactive < gstate.ncpus) { - x *= ((double)gstate.ncpus)/nactive; - } - - // But its rate on a given CPU can't exceed 1 - // - if (x>1) { - x = 1; - } - rr_sim_status.proc_rate = x*gstate.overall_cpu_frac(); - if (log_flags.rr_simulation) { - msg_printf(this, MSG_INFO, - "[rr_sim] set_rrsim_proc_rate: %f (rrs %f, rs %f, nactive %d, ocf %f", - rr_sim_status.proc_rate, rrs, resource_share, nactive, gstate.overall_cpu_frac() - ); - } -} - -void CLIENT_STATE::print_deadline_misses() { - unsigned int i; - RESULT* rp; - PROJECT* p; - for (i=0; irr_sim_misses_deadline && !rp->last_rr_sim_missed_deadline) { - msg_printf(rp->project, MSG_INFO, - "[cpu_sched_debug] Result %s projected to miss deadline.", rp->name - ); - } - else if (!rp->rr_sim_misses_deadline && rp->last_rr_sim_missed_deadline) { - msg_printf(rp->project, MSG_INFO, - "[cpu_sched_debug] Result %s projected to meet deadline.", rp->name - ); - } - } - for (i=0; irr_sim_status.deadlines_missed) { - msg_printf(p, MSG_INFO, - "[cpu_sched_debug] Project has %d projected deadline misses", - p->rr_sim_status.deadlines_missed - ); - } - } -} - -// Do a simulation of the current workload -// with weighted round-robin (WRR) scheduling. -// Include jobs that are downloading. -// -// For efficiency, we simulate a crude approximation of WRR. -// We don't model time-slicing. -// Instead we use a continuous model where, at a given point, -// each project has a set of running jobs that uses all CPUs -// (and obeys coprocessor limits). -// These jobs are assumed to run at a rate proportionate to their avg_ncpus, -// and each project gets CPU proportionate to its RRS. -// -// Outputs are changes to global state: -// For each project p: -// p->rr_sim_deadlines_missed -// p->cpu_shortfall -// For each result r: -// r->rr_sim_misses_deadline -// r->last_rr_sim_missed_deadline -// gstate.cpu_shortfall -// -// Deadline misses are not counted for tasks -// that are too large to run in RAM right now. -// -void CLIENT_STATE::rr_simulation() { - double rrs = nearly_runnable_resource_share(); - double trs = total_resource_share(); - PROJECT* p, *pbest; - RESULT* rp, *rpbest; - RR_SIM_STATUS sim_status; - unsigned int i; - - sim_status.coprocs.clone(coprocs, false); - double ar = available_ram(); - - if (log_flags.rr_simulation) { - msg_printf(0, MSG_INFO, - "[rr_sim] rr_sim start: work_buf_total %f rrs %f trs %f ncpus %d", - work_buf_total(), rrs, trs, ncpus - ); - } - - for (i=0; irr_sim_status.clear(); - } - - // Decide what jobs to include in the simulation, - // and pick the ones that are initially running - // - for (i=0; inearly_runnable()) continue; - if (rp->some_download_stalled()) continue; - if (rp->project->non_cpu_intensive) continue; - rp->rrsim_cpu_left = rp->estimated_cpu_time_remaining(false); - p = rp->project; - if (p->rr_sim_status.can_run(rp, gstate.ncpus) && sim_status.can_run(rp)) { - sim_status.activate(rp); - p->rr_sim_status.activate(rp); - } else { - p->rr_sim_status.add_pending(rp); - } - rp->last_rr_sim_missed_deadline = rp->rr_sim_misses_deadline; - rp->rr_sim_misses_deadline = false; - } - - for (i=0; iset_rrsim_proc_rate(rrs); - // if there are no results for a project, - // the shortfall is its entire share. - // - if (p->rr_sim_status.none_active()) { - double rsf = trs ? p->resource_share/trs : 1; - p->rr_sim_status.cpu_shortfall = work_buf_total() * overall_cpu_frac() * ncpus * rsf; - if (log_flags.rr_simulation) { - msg_printf(p, MSG_INFO, - "[rr_sim] no results; shortfall %f wbt %f ocf %f rsf %f", - p->rr_sim_status.cpu_shortfall, work_buf_total(), overall_cpu_frac(), rsf - ); - } - } - } - - double buf_end = now + work_buf_total(); - - // Simulation loop. Keep going until work done - // - double sim_now = now; - cpu_shortfall = 0; - while (sim_status.nactive()) { - - // compute finish times and see which result finishes first - // - rpbest = NULL; - for (i=0; iproject; - rp->rrsim_finish_delay = rp->rrsim_cpu_left/p->rr_sim_status.proc_rate; - if (!rpbest || rp->rrsim_finish_delay < rpbest->rrsim_finish_delay) { - rpbest = rp; - } - } - - pbest = rpbest->project; - - if (log_flags.rr_simulation) { - msg_printf(pbest, MSG_INFO, - "[rr_sim] result %s finishes after %f (%f/%f)", - rpbest->name, rpbest->rrsim_finish_delay, - rpbest->rrsim_cpu_left, pbest->rr_sim_status.proc_rate - ); - } - - // "rpbest" is first result to finish. Does it miss its deadline? - // - double diff = sim_now + rpbest->rrsim_finish_delay - ((rpbest->computation_deadline()-now)*CPU_PESSIMISM_FACTOR + now); - if (diff > 0) { - ACTIVE_TASK* atp = lookup_active_task_by_result(rpbest); - if (atp && atp->procinfo.working_set_size_smoothed > ar) { - if (log_flags.rr_simulation) { - msg_printf(pbest, MSG_INFO, - "[rr_sim] result %s misses deadline but too large to run", - rpbest->name - ); - } - } else { - rpbest->rr_sim_misses_deadline = true; - pbest->rr_sim_status.deadlines_missed++; - if (log_flags.rr_simulation) { - msg_printf(pbest, MSG_INFO, - "[rr_sim] result %s misses deadline by %f", - rpbest->name, diff - ); - } - } - } - - int last_active_size = sim_status.nactive(); - int last_proj_active_size = pbest->rr_sim_status.cpus_used(); - - sim_status.remove_active(rpbest); - - pbest->rr_sim_status.remove_active(rpbest); - - // If project has more results, add one or more to active set. - // - while (1) { - rp = pbest->rr_sim_status.get_pending(); - if (!rp) break; - if (pbest->rr_sim_status.can_run(rp, gstate.ncpus) && sim_status.can_run(rp)) { - sim_status.activate(rp); - pbest->rr_sim_status.activate(rp); - } else { - pbest->rr_sim_status.add_pending(rp); - break; - } - } - - // If all work done for a project, subtract that project's share - // and recompute processing rates - // - if (pbest->rr_sim_status.none_active()) { - rrs -= pbest->resource_share; - if (log_flags.rr_simulation) { - msg_printf(pbest, MSG_INFO, - "[rr_sim] decr rrs by %f, new value %f", - pbest->resource_share, rrs - ); - } - for (i=0; iset_rrsim_proc_rate(rrs); - } - } - - // increment CPU shortfalls if necessary - // - if (sim_now < buf_end) { - double end_time = sim_now + rpbest->rrsim_finish_delay; - if (end_time > buf_end) end_time = buf_end; - double d_time = end_time - sim_now; - int nidle_cpus = ncpus - last_active_size; - if (nidle_cpus<0) nidle_cpus = 0; - if (nidle_cpus > 0) cpu_shortfall += d_time*nidle_cpus; - - double rsf = trs?pbest->resource_share/trs:1; - double proj_cpu_share = ncpus*rsf; - - if (last_proj_active_size < proj_cpu_share) { - pbest->rr_sim_status.cpu_shortfall += d_time*(proj_cpu_share - last_proj_active_size); - if (log_flags.rr_simulation) { - msg_printf(pbest, MSG_INFO, - "[rr_sim] new shortfall %f d_time %f proj_cpu_share %f lpas %d", - pbest->rr_sim_status.cpu_shortfall, d_time, proj_cpu_share, last_proj_active_size - ); - } - } - - if (end_time < buf_end) { - d_time = buf_end - end_time; - // if this is the last result for this project, account for the tail - if (pbest->rr_sim_status.none_active()) { - pbest->rr_sim_status.cpu_shortfall += d_time * proj_cpu_share; - if (log_flags.rr_simulation) { - msg_printf(pbest, MSG_INFO, "[rr_sim] proj out of work; shortfall %f d %f pcs %f", - pbest->rr_sim_status.cpu_shortfall, d_time, proj_cpu_share - ); - } - } - } - if (log_flags.rr_simulation) { - msg_printf(0, MSG_INFO, - "[rr_sim] total: idle cpus %d, last active %d, active %d, shortfall %f", - nidle_cpus, last_active_size, sim_status.nactive(), - cpu_shortfall - - ); - msg_printf(0, MSG_INFO, - "[rr_sim] proj %s: last active %d, active %d, shortfall %f", - pbest->get_project_name(), last_proj_active_size, - pbest->rr_sim_status.cpus_used(), - pbest->rr_sim_status.cpu_shortfall - ); - } - } - - sim_now += rpbest->rrsim_finish_delay; - } - - if (sim_now < buf_end) { - cpu_shortfall += (buf_end - sim_now) * ncpus; - } - - if (log_flags.rr_simulation) { - for (i=0; irr_sim_status.cpu_shortfall) { - msg_printf(p, MSG_INFO, - "[rr_sim] shortfall %f\n", p->rr_sim_status.cpu_shortfall - ); - } - } - msg_printf(NULL, MSG_INFO, - "[rr_sim] done; total shortfall %f\n", - cpu_shortfall - ); - } -} +#endif +#include "client_msgs.h" + +struct RR_SIM_STATUS { + std::vector active; + COPROCS coprocs; + + inline bool can_run(RESULT* rp) { + return coprocs.sufficient_coprocs( + rp->avp->coprocs, log_flags.rr_simulation, "rr_simulation" + ); + } + inline void activate(RESULT* rp) { + coprocs.reserve_coprocs( + rp->avp->coprocs, rp, log_flags.rr_simulation, "rr_simulation" + ); + active.push_back(rp); + } + // remove *rpbest from active set, + // and adjust CPU time left for other results + // + inline void remove_active(RESULT* rpbest) { + coprocs.free_coprocs(rpbest->avp->coprocs, rpbest, log_flags.rr_simulation, "rr_simulation"); + vector::iterator it = active.begin(); + while (it != active.end()) { + RESULT* rp = *it; + if (rp == rpbest) { + it = active.erase(it); + } else { + rp->rrsim_cpu_left -= rp->project->rr_sim_status.proc_rate*rpbest->rrsim_finish_delay; + it++; + } + } + } + inline int nactive() { + return (int) active.size(); + } + ~RR_SIM_STATUS() { + coprocs.delete_coprocs(); + } +}; + +// Set the project's rrsim_proc_rate: +// the fraction of each CPU that it will get in round-robin mode. +// Precondition: the project's "active" array is populated +// +void PROJECT::set_rrsim_proc_rate(double rrs) { + int nactive = (int)rr_sim_status.active.size(); + if (nactive == 0) return; + double x; + + if (rrs) { + x = resource_share/rrs; + } else { + x = 1; // pathological case; maybe should be 1/# runnable projects + } + + // if this project has fewer active results than CPUs, + // scale up its share to reflect this + // + if (nactive < gstate.ncpus) { + x *= ((double)gstate.ncpus)/nactive; + } + + // But its rate on a given CPU can't exceed 1 + // + if (x>1) { + x = 1; + } + rr_sim_status.proc_rate = x*gstate.overall_cpu_frac(); + if (log_flags.rr_simulation) { + msg_printf(this, MSG_INFO, + "[rr_sim] set_rrsim_proc_rate: %f (rrs %f, rs %f, nactive %d, ocf %f", + rr_sim_status.proc_rate, rrs, resource_share, nactive, gstate.overall_cpu_frac() + ); + } +} + +void CLIENT_STATE::print_deadline_misses() { + unsigned int i; + RESULT* rp; + PROJECT* p; + for (i=0; irr_sim_misses_deadline && !rp->last_rr_sim_missed_deadline) { + msg_printf(rp->project, MSG_INFO, + "[cpu_sched_debug] Result %s projected to miss deadline.", rp->name + ); + } + else if (!rp->rr_sim_misses_deadline && rp->last_rr_sim_missed_deadline) { + msg_printf(rp->project, MSG_INFO, + "[cpu_sched_debug] Result %s projected to meet deadline.", rp->name + ); + } + } + for (i=0; irr_sim_status.deadlines_missed) { + msg_printf(p, MSG_INFO, + "[cpu_sched_debug] Project has %d projected deadline misses", + p->rr_sim_status.deadlines_missed + ); + } + } +} + +// Do a simulation of the current workload +// with weighted round-robin (WRR) scheduling. +// Include jobs that are downloading. +// +// For efficiency, we simulate a crude approximation of WRR. +// We don't model time-slicing. +// Instead we use a continuous model where, at a given point, +// each project has a set of running jobs that uses all CPUs +// (and obeys coprocessor limits). +// These jobs are assumed to run at a rate proportionate to their avg_ncpus, +// and each project gets CPU proportionate to its RRS. +// +// Outputs are changes to global state: +// For each project p: +// p->rr_sim_deadlines_missed +// p->cpu_shortfall +// For each result r: +// r->rr_sim_misses_deadline +// r->last_rr_sim_missed_deadline +// gstate.cpu_shortfall +// +// Deadline misses are not counted for tasks +// that are too large to run in RAM right now. +// +void CLIENT_STATE::rr_simulation() { + double rrs = nearly_runnable_resource_share(); + double trs = total_resource_share(); + PROJECT* p, *pbest; + RESULT* rp, *rpbest; + RR_SIM_STATUS sim_status; + unsigned int i; + + sim_status.coprocs.clone(coprocs, false); + double ar = available_ram(); + + if (log_flags.rr_simulation) { + msg_printf(0, MSG_INFO, + "[rr_sim] rr_sim start: work_buf_total %f rrs %f trs %f ncpus %d", + work_buf_total(), rrs, trs, ncpus + ); + } + + for (i=0; irr_sim_status.clear(); + } + + // Decide what jobs to include in the simulation, + // and pick the ones that are initially running + // + for (i=0; inearly_runnable()) continue; + if (rp->some_download_stalled()) continue; + if (rp->project->non_cpu_intensive) continue; + rp->rrsim_cpu_left = rp->estimated_cpu_time_remaining(false); + p = rp->project; + if (p->rr_sim_status.can_run(rp, gstate.ncpus) && sim_status.can_run(rp)) { + sim_status.activate(rp); + p->rr_sim_status.activate(rp); + } else { + p->rr_sim_status.add_pending(rp); + } + rp->last_rr_sim_missed_deadline = rp->rr_sim_misses_deadline; + rp->rr_sim_misses_deadline = false; + } + + for (i=0; iset_rrsim_proc_rate(rrs); + // if there are no results for a project, + // the shortfall is its entire share. + // + if (p->rr_sim_status.none_active()) { + double rsf = trs ? p->resource_share/trs : 1; + p->rr_sim_status.cpu_shortfall = work_buf_total() * overall_cpu_frac() * ncpus * rsf; + if (log_flags.rr_simulation) { + msg_printf(p, MSG_INFO, + "[rr_sim] no results; shortfall %f wbt %f ocf %f rsf %f", + p->rr_sim_status.cpu_shortfall, work_buf_total(), overall_cpu_frac(), rsf + ); + } + } + } + + double buf_end = now + work_buf_total(); + + // Simulation loop. Keep going until work done + // + double sim_now = now; + cpu_shortfall = 0; + while (sim_status.nactive()) { + + // compute finish times and see which result finishes first + // + rpbest = NULL; + for (i=0; iproject; + rp->rrsim_finish_delay = rp->rrsim_cpu_left/p->rr_sim_status.proc_rate; + if (!rpbest || rp->rrsim_finish_delay < rpbest->rrsim_finish_delay) { + rpbest = rp; + } + } + + pbest = rpbest->project; + + if (log_flags.rr_simulation) { + msg_printf(pbest, MSG_INFO, + "[rr_sim] result %s finishes after %f (%f/%f)", + rpbest->name, rpbest->rrsim_finish_delay, + rpbest->rrsim_cpu_left, pbest->rr_sim_status.proc_rate + ); + } + + // "rpbest" is first result to finish. Does it miss its deadline? + // + double diff = sim_now + rpbest->rrsim_finish_delay - ((rpbest->computation_deadline()-now)*CPU_PESSIMISM_FACTOR + now); + if (diff > 0) { + ACTIVE_TASK* atp = lookup_active_task_by_result(rpbest); + if (atp && atp->procinfo.working_set_size_smoothed > ar) { + if (log_flags.rr_simulation) { + msg_printf(pbest, MSG_INFO, + "[rr_sim] result %s misses deadline but too large to run", + rpbest->name + ); + } + } else { + rpbest->rr_sim_misses_deadline = true; + pbest->rr_sim_status.deadlines_missed++; + if (log_flags.rr_simulation) { + msg_printf(pbest, MSG_INFO, + "[rr_sim] result %s misses deadline by %f", + rpbest->name, diff + ); + } + } + } + + int last_active_size = sim_status.nactive(); + int last_proj_active_size = pbest->rr_sim_status.cpus_used(); + + sim_status.remove_active(rpbest); + + pbest->rr_sim_status.remove_active(rpbest); + + // If project has more results, add one or more to active set. + // + while (1) { + rp = pbest->rr_sim_status.get_pending(); + if (!rp) break; + if (pbest->rr_sim_status.can_run(rp, gstate.ncpus) && sim_status.can_run(rp)) { + sim_status.activate(rp); + pbest->rr_sim_status.activate(rp); + } else { + pbest->rr_sim_status.add_pending(rp); + break; + } + } + + // If all work done for a project, subtract that project's share + // and recompute processing rates + // + if (pbest->rr_sim_status.none_active()) { + rrs -= pbest->resource_share; + if (log_flags.rr_simulation) { + msg_printf(pbest, MSG_INFO, + "[rr_sim] decr rrs by %f, new value %f", + pbest->resource_share, rrs + ); + } + for (i=0; iset_rrsim_proc_rate(rrs); + } + } + + // increment CPU shortfalls if necessary + // + if (sim_now < buf_end) { + double end_time = sim_now + rpbest->rrsim_finish_delay; + if (end_time > buf_end) end_time = buf_end; + double d_time = end_time - sim_now; + int nidle_cpus = ncpus - last_active_size; + if (nidle_cpus<0) nidle_cpus = 0; + if (nidle_cpus > 0) cpu_shortfall += d_time*nidle_cpus; + + double rsf = trs?pbest->resource_share/trs:1; + double proj_cpu_share = ncpus*rsf; + + if (last_proj_active_size < proj_cpu_share) { + pbest->rr_sim_status.cpu_shortfall += d_time*(proj_cpu_share - last_proj_active_size); + if (log_flags.rr_simulation) { + msg_printf(pbest, MSG_INFO, + "[rr_sim] new shortfall %f d_time %f proj_cpu_share %f lpas %d", + pbest->rr_sim_status.cpu_shortfall, d_time, proj_cpu_share, last_proj_active_size + ); + } + } + + if (end_time < buf_end) { + d_time = buf_end - end_time; + // if this is the last result for this project, account for the tail + if (pbest->rr_sim_status.none_active()) { + pbest->rr_sim_status.cpu_shortfall += d_time * proj_cpu_share; + if (log_flags.rr_simulation) { + msg_printf(pbest, MSG_INFO, "[rr_sim] proj out of work; shortfall %f d %f pcs %f", + pbest->rr_sim_status.cpu_shortfall, d_time, proj_cpu_share + ); + } + } + } + if (log_flags.rr_simulation) { + msg_printf(0, MSG_INFO, + "[rr_sim] total: idle cpus %d, last active %d, active %d, shortfall %f", + nidle_cpus, last_active_size, sim_status.nactive(), + cpu_shortfall + + ); + msg_printf(0, MSG_INFO, + "[rr_sim] proj %s: last active %d, active %d, shortfall %f", + pbest->get_project_name(), last_proj_active_size, + pbest->rr_sim_status.cpus_used(), + pbest->rr_sim_status.cpu_shortfall + ); + } + } + + sim_now += rpbest->rrsim_finish_delay; + } + + if (sim_now < buf_end) { + cpu_shortfall += (buf_end - sim_now) * ncpus; + } + + if (log_flags.rr_simulation) { + for (i=0; irr_sim_status.cpu_shortfall) { + msg_printf(p, MSG_INFO, + "[rr_sim] shortfall %f\n", p->rr_sim_status.cpu_shortfall + ); + } + } + msg_printf(NULL, MSG_INFO, + "[rr_sim] done; total shortfall %f\n", + cpu_shortfall + ); + } +} diff --git a/clientgui/AdvancedFrame.cpp b/clientgui/AdvancedFrame.cpp index 75d7b1e2f7..33ebd58596 100644 --- a/clientgui/AdvancedFrame.cpp +++ b/clientgui/AdvancedFrame.cpp @@ -1034,6 +1034,25 @@ void CAdvancedFrame::RestoreWindowDimensions() { } +int CAdvancedFrame::_GetCurrentViewPage() { + switch (m_pNotebook->GetSelection()) { + case 0: + return VW_PROJ; + case 1: + return VW_TASK; + case 2: + return VW_XFER; + case 3: + return VW_MSGS; + case 4: + return VW_STAT; + case 5: + return VW_DISK; + } + return 0; // Should never happen. +} + + void CAdvancedFrame::OnActivitySelection(wxCommandEvent& event) { wxLogTrace(wxT("Function Start/End"), wxT("CAdvancedFrame::OnActivitySelection - Function Begin")); @@ -1135,11 +1154,11 @@ void CAdvancedFrame::OnSelectComputer(wxCommandEvent& WXUNUSED(event)) { // Connect to the remote machine wxString sHost = dlg.m_ComputerNameCtrl->GetValue(); long lPort = GUI_RPC_PORT; - int iPos = sHost.find(_(":")); + size_t iPos = sHost.find(_(":")); if (iPos != wxNOT_FOUND) { - wxString sPort = sHost.substr((size_t)iPos + 1); + wxString sPort = sHost.substr(iPos + 1); if (!sPort.ToLong(&lPort)) lPort = GUI_RPC_PORT; - sHost.erase((size_t)iPos); + sHost.erase(iPos); } lRetVal = pDoc->Connect( sHost, diff --git a/clientgui/AdvancedFrame.h b/clientgui/AdvancedFrame.h index e4e7ba5d67..7a21a5445d 100644 --- a/clientgui/AdvancedFrame.h +++ b/clientgui/AdvancedFrame.h @@ -23,6 +23,18 @@ #pragma interface "AdvancedFrame.cpp" #endif + +/// +/// Bitmask values for CMainDocument::RunPeriodicRPCs() +/// +#define VW_PROJ 1 +#define VW_TASK 2 +#define VW_XFER 4 +#define VW_MSGS 8 +#define VW_STAT 16 +#define VW_DISK 32 + + class CStatusBar : public wxStatusBar { DECLARE_DYNAMIC_CLASS(CStatusBar) @@ -83,7 +95,6 @@ public: void OnFrameRender( wxTimerEvent& event ); void OnNotebookSelectionChanged( wxNotebookEvent& event ); - int GetViewTabIndex() { return m_pNotebook->GetSelection(); } void OnRefreshView( CFrameEvent& event ); void OnConnect( CFrameEvent& event ); @@ -94,6 +105,13 @@ public: wxTimer* m_pRefreshStateTimer; wxTimer* m_pFrameRenderTimer; + +protected: + virtual int _GetCurrentViewPage(); + + wxAcceleratorEntry m_Shortcuts[1]; // For HELP keyboard shortcut + wxAcceleratorTable* m_pAccelTable; + private: wxMenuBar* m_pMenubar; @@ -131,13 +149,6 @@ private: void StartTimers(); void StopTimers(); -#ifdef __WXMAC__ -protected: - - wxAcceleratorEntry m_Shortcuts[1]; // For HELP keyboard shortcut - wxAcceleratorTable* m_pAccelTable; -#endif - DECLARE_EVENT_TABLE() }; diff --git a/clientgui/AsyncRPC.cpp b/clientgui/AsyncRPC.cpp index 9b638737d0..56269d8ac5 100755 --- a/clientgui/AsyncRPC.cpp +++ b/clientgui/AsyncRPC.cpp @@ -72,7 +72,7 @@ bool ASYNC_RPC_REQUEST::isSameAs(ASYNC_RPC_REQUEST& otherRequest) { AsyncRPC::AsyncRPC(CMainDocument *pDoc) { - m_Doc = pDoc; + m_pDoc = pDoc; } @@ -92,20 +92,19 @@ int AsyncRPC::RPC_Wait(RPC_SELECTOR which_rpc, void *arg1, void *arg2, request.arg4 = arg4; request.rpcType = RPC_TYPE_WAIT_FOR_COMPLETION; - retval = m_Doc->RequestRPC(request, hasPriority); + retval = m_pDoc->RequestRPC(request, hasPriority); return retval; } -RPCThread::RPCThread(CMainDocument *pDoc) - : wxThread() { - m_Doc = pDoc; +RPCThread::RPCThread(CMainDocument *pDoc) : wxThread() { + m_pDoc = pDoc; } void RPCThread::OnExit() { // Tell CMainDocument that thread has gracefully ended - m_Doc->m_RPCThread = NULL; + m_pDoc->m_RPCThread = NULL; } @@ -117,14 +116,13 @@ void RPCThread::OnExit() { void *RPCThread::Entry() { int retval; - CRPCFinishedEvent RPC_done_event( wxEVT_RPC_FINISHED ); while(true) { // check if we were asked to exit if ( TestDestroy() ) break; - if (! m_Doc->GetCurrentRPCRequest()->isActive) { + if (! m_pDoc->GetCurrentRPCRequest()->isActive) { // Wait until CMainDocument issues next RPC request #ifdef __WXMSW__ // Until we can suspend the thread without Deadlock on Windows Sleep(1); @@ -134,20 +132,24 @@ void *RPCThread::Entry() { continue; } - if (! m_Doc->IsConnected()) { + if (! m_pDoc->IsConnected()) { Yield(); } retval = ProcessRPCRequest(); - wxPostEvent( wxTheApp, RPC_done_event ); + + CBOINCBaseFrame* pFrame = wxGetApp().GetFrame(); + if (pFrame) { + pFrame->FireRPCFinished(); + } } #ifndef __WXMSW__ // Deadlocks on Windows // Use a critical section to prevent a crash during // manager shutdown due to a rare race condition - m_Doc->m_critsect.Enter(); - m_Doc->m_critsect.Leave(); + m_pDoc->m_critsect.Enter(); + m_pDoc->m_critsect.Leave(); #endif // !!__WXMSW__ // Deadlocks on Windows @@ -159,7 +161,7 @@ int RPCThread::ProcessRPCRequest() { int retval = 0; ASYNC_RPC_REQUEST *current_request; - current_request = m_Doc->GetCurrentRPCRequest(); + current_request = m_pDoc->GetCurrentRPCRequest(); switch (current_request->which_rpc) { // RPC_SELECTORS with no arguments case RPC_RUN_BENCHMARKS: @@ -179,45 +181,45 @@ int RPCThread::ProcessRPCRequest() { } switch (current_request->which_rpc) { case RPC_AUTHORIZE: - retval = (m_Doc->rpcClient).authorize((const char*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).authorize((const char*)(current_request->arg1)); break; case RPC_EXCHANGE_VERSIONS: - retval = (m_Doc->rpcClient).exchange_versions(*(VERSION_INFO*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).exchange_versions(*(VERSION_INFO*)(current_request->arg1)); break; case RPC_GET_STATE: - retval = (m_Doc->rpcClient).get_state(*(CC_STATE*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_state(*(CC_STATE*)(current_request->arg1)); break; case RPC_GET_RESULTS: - retval = (m_Doc->rpcClient).get_results(*(RESULTS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_results(*(RESULTS*)(current_request->arg1)); break; case RPC_GET_FILE_TRANSFERS: - retval = (m_Doc->rpcClient).get_file_transfers(*(FILE_TRANSFERS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_file_transfers(*(FILE_TRANSFERS*)(current_request->arg1)); break; case RPC_GET_SIMPLE_GUI_INFO1: - retval = (m_Doc->rpcClient).get_simple_gui_info(*(SIMPLE_GUI_INFO*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_simple_gui_info(*(SIMPLE_GUI_INFO*)(current_request->arg1)); break; case RPC_GET_SIMPLE_GUI_INFO2: // RPC_GET_SIMPLE_GUI_INFO2 is equivalent to doing both // RPC_GET_PROJECT_STATUS1 and RPC_GET_RESULTS - retval = (m_Doc->rpcClient).get_results(*(RESULTS*)(current_request->arg3)); + retval = (m_pDoc->rpcClient).get_results(*(RESULTS*)(current_request->arg3)); if (!retval) { - retval = (m_Doc->rpcClient).get_project_status(*(PROJECTS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_project_status(*(PROJECTS*)(current_request->arg1)); } break; case RPC_GET_PROJECT_STATUS1: - retval = (m_Doc->rpcClient).get_project_status(*(PROJECTS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_project_status(*(PROJECTS*)(current_request->arg1)); break; case RPC_GET_PROJECT_STATUS2: - retval = (m_Doc->rpcClient).get_project_status(*(PROJECTS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_project_status(*(PROJECTS*)(current_request->arg1)); break; case RPC_GET_ALL_PROJECTS_LIST: - retval = (m_Doc->rpcClient).get_all_projects_list(*(ALL_PROJECTS_LIST*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_all_projects_list(*(ALL_PROJECTS_LIST*)(current_request->arg1)); break; case RPC_GET_DISK_USAGE: - retval = (m_Doc->rpcClient).get_disk_usage(*(DISK_USAGE*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_disk_usage(*(DISK_USAGE*)(current_request->arg1)); break; case RPC_SHOW_GRAPHICS: - retval = (m_Doc->rpcClient).show_graphics( + retval = (m_pDoc->rpcClient).show_graphics( (const char*)(current_request->arg1), (const char*)(current_request->arg2), *(int*)(current_request->arg3), @@ -225,107 +227,107 @@ int RPCThread::ProcessRPCRequest() { ); break; case RPC_PROJECT_OP: - retval = (m_Doc->rpcClient).project_op( + retval = (m_pDoc->rpcClient).project_op( *(PROJECT*)(current_request->arg1), (const char*)(current_request->arg2) ); break; case RPC_SET_RUN_MODE: - retval = (m_Doc->rpcClient).set_run_mode( + retval = (m_pDoc->rpcClient).set_run_mode( *(int*)(current_request->arg1), *(double*)(current_request->arg2) ); break; case RPC_SET_NETWORK_MODE: - retval = (m_Doc->rpcClient).set_network_mode( + retval = (m_pDoc->rpcClient).set_network_mode( *(int*)(current_request->arg1), *(double*)(current_request->arg2) ); break; case RPC_GET_SCREENSAVER_TASKS: - retval = (m_Doc->rpcClient).get_screensaver_tasks( + retval = (m_pDoc->rpcClient).get_screensaver_tasks( *(int*)(current_request->arg1), *(RESULTS*)(current_request->arg2) ); break; case RPC_RUN_BENCHMARKS: - retval = (m_Doc->rpcClient).run_benchmarks(); + retval = (m_pDoc->rpcClient).run_benchmarks(); break; case RPC_SET_PROXY_SETTINGS: - retval = (m_Doc->rpcClient).set_proxy_settings(*(GR_PROXY_INFO*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).set_proxy_settings(*(GR_PROXY_INFO*)(current_request->arg1)); break; case RPC_GET_PROXY_SETTINGS: - retval = (m_Doc->rpcClient).get_proxy_settings(*(GR_PROXY_INFO*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_proxy_settings(*(GR_PROXY_INFO*)(current_request->arg1)); break; case RPC_GET_MESSAGES: - retval = (m_Doc->rpcClient).get_messages( + retval = (m_pDoc->rpcClient).get_messages( *(int*)(current_request->arg1), *(MESSAGES*)(current_request->arg2) ); break; case RPC_FILE_TRANSFER_OP: - retval = (m_Doc->rpcClient).file_transfer_op( + retval = (m_pDoc->rpcClient).file_transfer_op( *(FILE_TRANSFER*)(current_request->arg1), (const char*)(current_request->arg2) ); break; case RPC_RESULT_OP: - retval = (m_Doc->rpcClient).result_op( + retval = (m_pDoc->rpcClient).result_op( *(RESULT*)(current_request->arg1), (const char*)(current_request->arg2) ); break; case RPC_GET_HOST_INFO: - retval = (m_Doc->rpcClient).get_host_info(*(HOST_INFO*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_host_info(*(HOST_INFO*)(current_request->arg1)); break; case RPC_QUIT: - retval = (m_Doc->rpcClient).quit(); + retval = (m_pDoc->rpcClient).quit(); break; case RPC_ACCT_MGR_INFO: - retval = (m_Doc->rpcClient).acct_mgr_info(*(ACCT_MGR_INFO*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).acct_mgr_info(*(ACCT_MGR_INFO*)(current_request->arg1)); break; case RPC_GET_STATISTICS: - retval = (m_Doc->rpcClient).get_statistics(*(PROJECTS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_statistics(*(PROJECTS*)(current_request->arg1)); break; case RPC_NETWORK_AVAILABLE: - retval = (m_Doc->rpcClient).network_available(); + retval = (m_pDoc->rpcClient).network_available(); break; case RPC_GET_PROJECT_INIT_STATUS: - retval = (m_Doc->rpcClient).get_project_init_status(*(PROJECT_INIT_STATUS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_project_init_status(*(PROJECT_INIT_STATUS*)(current_request->arg1)); break; case RPC_GET_PROJECT_CONFIG: - retval = (m_Doc->rpcClient).get_project_config(*(std::string*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_project_config(*(std::string*)(current_request->arg1)); break; case RPC_GET_PROJECT_CONFIG_POLL: - retval = (m_Doc->rpcClient).get_project_config_poll(*(PROJECT_CONFIG*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_project_config_poll(*(PROJECT_CONFIG*)(current_request->arg1)); break; case RPC_LOOKUP_ACCOUNT: - retval = (m_Doc->rpcClient).lookup_account(*(ACCOUNT_IN*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).lookup_account(*(ACCOUNT_IN*)(current_request->arg1)); break; case RPC_LOOKUP_ACCOUNT_POLL: - retval = (m_Doc->rpcClient).lookup_account_poll(*(ACCOUNT_OUT*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).lookup_account_poll(*(ACCOUNT_OUT*)(current_request->arg1)); break; case RPC_CREATE_ACCOUNT: - retval = (m_Doc->rpcClient).create_account(*(ACCOUNT_IN*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).create_account(*(ACCOUNT_IN*)(current_request->arg1)); break; case RPC_CREATE_ACCOUNT_POLL: - retval = (m_Doc->rpcClient).create_account_poll(*(ACCOUNT_OUT*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).create_account_poll(*(ACCOUNT_OUT*)(current_request->arg1)); break; case RPC_PROJECT_ATTACH: - retval = (m_Doc->rpcClient).project_attach( + retval = (m_pDoc->rpcClient).project_attach( (const char*)(current_request->arg1), (const char*)(current_request->arg2), (const char*)(current_request->arg3) ); break; case RPC_PROJECT_ATTACH_FROM_FILE: - retval = (m_Doc->rpcClient).project_attach_from_file(); + retval = (m_pDoc->rpcClient).project_attach_from_file(); break; case RPC_PROJECT_ATTACH_POLL: - retval = (m_Doc->rpcClient).project_attach_poll(*(PROJECT_ATTACH_REPLY*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).project_attach_poll(*(PROJECT_ATTACH_REPLY*)(current_request->arg1)); break; case RPC_ACCT_MGR_RPC: - retval = (m_Doc->rpcClient).acct_mgr_rpc( + retval = (m_pDoc->rpcClient).acct_mgr_rpc( (const char*)(current_request->arg1), (const char*)(current_request->arg2), (const char*)(current_request->arg3), @@ -333,52 +335,52 @@ int RPCThread::ProcessRPCRequest() { ); break; case RPC_ACCT_MGR_RPC_POLL: - retval = (m_Doc->rpcClient).acct_mgr_rpc_poll(*(ACCT_MGR_RPC_REPLY*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).acct_mgr_rpc_poll(*(ACCT_MGR_RPC_REPLY*)(current_request->arg1)); break; case RPC_GET_NEWER_VERSION: - retval = (m_Doc->rpcClient).get_newer_version(*(std::string*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_newer_version(*(std::string*)(current_request->arg1)); break; case RPC_READ_GLOBAL_PREFS_OVERRIDE: - retval = (m_Doc->rpcClient).read_global_prefs_override(); + retval = (m_pDoc->rpcClient).read_global_prefs_override(); break; case RPC_READ_CC_CONFIG: - retval = (m_Doc->rpcClient).read_cc_config(); + retval = (m_pDoc->rpcClient).read_cc_config(); break; case RPC_GET_CC_STATUS: - retval = (m_Doc->rpcClient).get_cc_status(*(CC_STATUS*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_cc_status(*(CC_STATUS*)(current_request->arg1)); break; case RPC_GET_GLOBAL_PREFS_FILE: - retval = (m_Doc->rpcClient).get_global_prefs_file(*(std::string*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_global_prefs_file(*(std::string*)(current_request->arg1)); break; case RPC_GET_GLOBAL_PREFS_WORKING: - retval = (m_Doc->rpcClient).get_global_prefs_working(*(std::string*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_global_prefs_working(*(std::string*)(current_request->arg1)); break; case RPC_GET_GLOBAL_PREFS_WORKING_STRUCT: - retval = (m_Doc->rpcClient).get_global_prefs_working_struct( + retval = (m_pDoc->rpcClient).get_global_prefs_working_struct( *(GLOBAL_PREFS*)(current_request->arg1), *(GLOBAL_PREFS_MASK*)(current_request->arg2) ); break; case RPC_GET_GLOBAL_PREFS_OVERRIDE: - retval = (m_Doc->rpcClient).get_global_prefs_override(*(std::string*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).get_global_prefs_override(*(std::string*)(current_request->arg1)); break; case RPC_SET_GLOBAL_PREFS_OVERRIDE: - retval = (m_Doc->rpcClient).set_global_prefs_override(*(std::string*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).set_global_prefs_override(*(std::string*)(current_request->arg1)); break; case RPC_GET_GLOBAL_PREFS_OVERRIDE_STRUCT: - retval = (m_Doc->rpcClient).get_global_prefs_override_struct( + retval = (m_pDoc->rpcClient).get_global_prefs_override_struct( *(GLOBAL_PREFS*)(current_request->arg1), *(GLOBAL_PREFS_MASK*)(current_request->arg2) ); break; case RPC_SET_GLOBAL_PREFS_OVERRIDE_STRUCT: - retval = (m_Doc->rpcClient).set_global_prefs_override_struct( + retval = (m_pDoc->rpcClient).set_global_prefs_override_struct( *(GLOBAL_PREFS*)(current_request->arg1), *(GLOBAL_PREFS_MASK*)(current_request->arg2) ); break; case RPC_SET_DEBTS: - retval = (m_Doc->rpcClient).set_debts(*(std::vector*)(current_request->arg1)); + retval = (m_pDoc->rpcClient).set_debts(*(std::vector*)(current_request->arg1)); break; default: break; @@ -576,7 +578,7 @@ int CMainDocument::RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority) { } -void CMainDocument::OnRPCComplete(CRPCFinishedEvent&) { +void CMainDocument::OnRPCComplete() { HandleCompletedRPC(); } @@ -591,7 +593,6 @@ void CMainDocument::HandleCompletedRPC() { // called from RequestRPC, the CRPCFinishedEvent will still be // on the event queue, so we get called twice. Check for this here. if (current_rpc_request.which_rpc == 0) return; // already handled by a call from RequestRPC -// m_RPCThread->Pause(); // Find our completed request in the queue n = RPC_requests.size(); diff --git a/clientgui/AsyncRPC.h b/clientgui/AsyncRPC.h index 07abcb19d7..f4db84c207 100644 --- a/clientgui/AsyncRPC.h +++ b/clientgui/AsyncRPC.h @@ -23,10 +23,8 @@ #endif -class CBOINCGUIApp; // Forward declaration class CMainDocument; // Forward declaration - enum RPC_SELECTOR { RPC_AUTHORIZE = 1, RPC_EXCHANGE_VERSIONS, @@ -282,7 +280,7 @@ public: { return RPC_Wait(RPC_SET_DEBTS, (void*)&arg1); } private: - CMainDocument *m_Doc; + CMainDocument* m_pDoc; }; @@ -295,7 +293,7 @@ public: private: int ProcessRPCRequest(); - CMainDocument *m_Doc; + CMainDocument* m_pDoc; }; @@ -309,25 +307,4 @@ public: }; -class CRPCFinishedEvent : public wxEvent -{ -public: - CRPCFinishedEvent(wxEventType evtType) - : wxEvent(-1, evtType) - { - SetEventObject(wxTheApp); - } - - virtual wxEvent *Clone() const { return new CRPCFinishedEvent(*this); } -}; - -BEGIN_DECLARE_EVENT_TYPES() -DECLARE_EVENT_TYPE( wxEVT_RPC_FINISHED, -1 ) -END_DECLARE_EVENT_TYPES() - -#define EVT_RPC_FINISHED(fn) \ - DECLARE_EVENT_TABLE_ENTRY(wxEVT_RPC_FINISHED, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), - - - #endif // _ASYNCRPC_H_ diff --git a/clientgui/BOINCBaseFrame.cpp b/clientgui/BOINCBaseFrame.cpp index 07ae74f1c3..a829052dfa 100644 --- a/clientgui/BOINCBaseFrame.cpp +++ b/clientgui/BOINCBaseFrame.cpp @@ -43,6 +43,7 @@ DEFINE_EVENT_TYPE(wxEVT_FRAME_INITIALIZED) DEFINE_EVENT_TYPE(wxEVT_FRAME_REFRESHVIEW) DEFINE_EVENT_TYPE(wxEVT_FRAME_UPDATESTATUS) DEFINE_EVENT_TYPE(wxEVT_FRAME_RELOADSKIN) +DEFINE_EVENT_TYPE(wxEVT_FRAME_RPCFINISHED) IMPLEMENT_DYNAMIC_CLASS(CBOINCBaseFrame, wxFrame) @@ -54,6 +55,7 @@ BEGIN_EVENT_TABLE (CBOINCBaseFrame, wxFrame) EVT_FRAME_INITIALIZED(CBOINCBaseFrame::OnInitialized) EVT_FRAME_ALERT(CBOINCBaseFrame::OnAlert) EVT_FRAME_REFRESH(CBOINCBaseFrame::OnRefreshView) + EVT_FRAME_RPCFINISHED(CBOINCBaseFrame::OnRPCFinished) EVT_CLOSE(CBOINCBaseFrame::OnClose) EVT_MENU(ID_FILECLOSEWINDOW, CBOINCBaseFrame::OnCloseWindow) END_EVENT_TABLE () @@ -163,6 +165,16 @@ void CBOINCBaseFrame::OnPeriodicRPC(wxTimerEvent& WXUNUSED(event)) { } +void CBOINCBaseFrame::OnRPCFinished( CFrameEvent& /* event */ ) { + CMainDocument* pDoc = wxGetApp().GetDocument(); + + wxASSERT(pDoc); + wxASSERT(wxDynamicCast(pDoc, CMainDocument)); + + pDoc->OnRPCComplete(); +} + + void CBOINCBaseFrame::OnDocumentPoll(wxTimerEvent& WXUNUSED(event)) { static bool bAlreadyRunOnce = false; CMainDocument* pDoc = wxGetApp().GetDocument(); @@ -355,6 +367,11 @@ void CBOINCBaseFrame::OnExit(wxCommandEvent& WXUNUSED(event)) { } +int CBOINCBaseFrame::GetCurrentViewPage() { + return _GetCurrentViewPage(); +} + + void CBOINCBaseFrame::FireInitialize() { CFrameEvent event(wxEVT_FRAME_INITIALIZED, this); AddPendingEvent(event); @@ -369,9 +386,6 @@ void CBOINCBaseFrame::FireRefreshView() { pDoc->RefreshRPCs(); pDoc->RunPeriodicRPCs(); - -// CFrameEvent event(wxEVT_FRAME_REFRESHVIEW, this); -// AddPendingEvent(event); } @@ -387,6 +401,12 @@ void CBOINCBaseFrame::FireReloadSkin() { } +void CBOINCBaseFrame::FireRPCFinished() { + CFrameEvent event(wxEVT_FRAME_RPCFINISHED, this); + AddPendingEvent(event); +} + + void CBOINCBaseFrame::ShowConnectionBadPasswordAlert( bool bUsedDefaultPassword, int m_iReadGUIRPCAuthFailure ) { CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced(); wxString strDialogTitle = wxEmptyString; @@ -755,25 +775,26 @@ bool CBOINCBaseFrame::RestoreState() { return true; } - -#ifdef __WXMAC__ -bool CBOINCBaseFrame::Show(bool show) { - ProcessSerialNumber psn; - - GetCurrentProcess(&psn); - if (show) { - SetFrontProcess(&psn); // Shows process if hidden +/* +bool CBOINCBaseFrame::Show(bool bShow) { + if (bShow) { + wxGetApp().ShowApplication(true); } else { -// GetWindowDimensions(); - if (wxGetApp().GetCurrentGUISelection() == m_iWindowType) - if (IsProcessVisible(&psn)) - ShowHideProcess(&psn, false); + if ( this == wxGetApp().GetFrame() ) { + if (wxGetApp().IsApplicationVisible()) { + wxGetApp().ShowApplication(false); + } + } } - return wxFrame::Show(show); } +*/ -#endif // __WXMAC__ + +int CBOINCBaseFrame::_GetCurrentViewPage() { + wxASSERT(false); + return 0; +} void CFrameAlertEvent::ProcessResponse(const int response) const { diff --git a/clientgui/BOINCBaseFrame.h b/clientgui/BOINCBaseFrame.h index ac0034b1ad..8fc031c61f 100644 --- a/clientgui/BOINCBaseFrame.h +++ b/clientgui/BOINCBaseFrame.h @@ -51,6 +51,8 @@ public: ~CBOINCBaseFrame(); void OnPeriodicRPC( wxTimerEvent& event ); + void OnRPCFinished( CFrameEvent& event ); + void OnDocumentPoll( wxTimerEvent& event ); void OnAlertPoll( wxTimerEvent& event ); virtual void OnRefreshView( CFrameEvent& event ); @@ -61,7 +63,9 @@ public: virtual void OnClose( wxCloseEvent& event ); virtual void OnCloseWindow( wxCommandEvent& event ); virtual void OnExit( wxCommandEvent& event ); - + + int GetCurrentViewPage(); + int GetReminderFrequency() { return m_iReminderFrequency; } wxString GetDialupConnectionName() { return m_strNetworkDialupConnectionName; } @@ -69,6 +73,7 @@ public: void FireRefreshView(); void FireConnect(); void FireReloadSkin(); + void FireRPCFinished(); void ShowConnectionBadPasswordAlert( bool bUsedDefaultPassword, int m_iReadGUIRPCAuthFailure ); void ShowConnectionFailedAlert(); void ShowDaemonStartFailedAlert(); @@ -89,10 +94,7 @@ public: void ExecuteBrowserLink( const wxString& strLink ); -#ifdef __WXMAC__ - bool Show( bool show = true ); - int m_iWindowType; // BOINC_SIMPLEGUI or BOINC_ADVANCEDGUI -#endif + //bool Show( bool bShow = true ); protected: @@ -111,6 +113,8 @@ protected: bool m_bShowConnectionFailedAlert; + virtual int _GetCurrentViewPage(); + virtual bool SaveState(); virtual bool RestoreState(); @@ -183,7 +187,7 @@ DECLARE_EVENT_TYPE( wxEVT_FRAME_INITIALIZED, 10004 ) DECLARE_EVENT_TYPE( wxEVT_FRAME_REFRESHVIEW, 10005 ) DECLARE_EVENT_TYPE( wxEVT_FRAME_UPDATESTATUS, 10006 ) DECLARE_EVENT_TYPE( wxEVT_FRAME_RELOADSKIN, 10007 ) - +DECLARE_EVENT_TYPE( wxEVT_FRAME_RPCFINISHED, 10008 ) END_DECLARE_EVENT_TYPES() #define EVT_FRAME_ALERT(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_FRAME_ALERT, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), @@ -192,7 +196,7 @@ END_DECLARE_EVENT_TYPES() #define EVT_FRAME_REFRESH(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_FRAME_REFRESHVIEW, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), #define EVT_FRAME_UPDATESTATUS(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_FRAME_UPDATESTATUS, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), #define EVT_FRAME_RELOADSKIN(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_FRAME_RELOADSKIN, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), - +#define EVT_FRAME_RPCFINISHED(fn) DECLARE_EVENT_TABLE_ENTRY(wxEVT_FRAME_RPCFINISHED, -1, -1, (wxObjectEventFunction) (wxEventFunction) &fn, NULL), #endif diff --git a/clientgui/BOINCBaseView.cpp b/clientgui/BOINCBaseView.cpp index 8e4ed4a34d..821e234f0e 100644 --- a/clientgui/BOINCBaseView.cpp +++ b/clientgui/BOINCBaseView.cpp @@ -603,8 +603,7 @@ void CBOINCBaseView::ClearSavedSelections() { // Save the key values of the currently selected rows for later restore void CBOINCBaseView::SaveSelections() { - int currentTabView = wxGetApp().GetCurrentViewPage(); - if (! (currentTabView & (VW_PROJ | VW_TASK | VW_XFER))) { + if (!_ManageSelections()) { return; } @@ -630,8 +629,7 @@ void CBOINCBaseView::SaveSelections() { // previous selection and makes any adjustments to ensure that // the rows containing the originally selected data are selected. void CBOINCBaseView::RestoreSelections() { - int currentTabView = wxGetApp().GetCurrentViewPage(); - if (! (currentTabView & (VW_PROJ | VW_TASK | VW_XFER))) { + if (!_ManageSelections()) { return; } @@ -777,6 +775,16 @@ void CBOINCBaseView::UpdateWebsiteSelection(long lControlGroup, PROJECT* project } +bool CBOINCBaseView::_ManageSelections() { + return ManageSelections(); +} + + +bool CBOINCBaseView::ManageSelections() { + return false; +} + + bool CBOINCBaseView::_EnsureLastItemVisible() { return EnsureLastItemVisible(); } diff --git a/clientgui/BOINCBaseView.h b/clientgui/BOINCBaseView.h index 1b782afe99..3c51b22e7b 100644 --- a/clientgui/BOINCBaseView.h +++ b/clientgui/BOINCBaseView.h @@ -165,6 +165,10 @@ protected: virtual void UpdateWebsiteSelection(long lControlGroup, PROJECT* project); + + bool _ManageSelections(); + virtual bool ManageSelections(); + bool _EnsureLastItemVisible(); virtual bool EnsureLastItemVisible(); diff --git a/clientgui/BOINCClientManager.cpp b/clientgui/BOINCClientManager.cpp index f1e6aca4bd..cdacf2e99f 100644 --- a/clientgui/BOINCClientManager.cpp +++ b/clientgui/BOINCClientManager.cpp @@ -155,7 +155,7 @@ bool CBOINCClientManager::StartupBOINCCore() { LPTSTR szDataDirectory = NULL; if (IsBOINCConfiguredAsDaemon()) { - return (StartBOINCService()); + return StartBOINCService() == TRUE; } // Append boinc.exe to the end of the strExecute string and get ready to rock diff --git a/clientgui/BOINCGUIApp.cpp b/clientgui/BOINCGUIApp.cpp index 4f805c7c5c..f4d0cdd803 100644 --- a/clientgui/BOINCGUIApp.cpp +++ b/clientgui/BOINCGUIApp.cpp @@ -51,8 +51,6 @@ #include "sg_BoincSimpleGUI.h" #include "DlgGenericMessage.h" -static bool s_bSkipExitConfirmation = false; - #ifdef __WXMSW__ EXTERN_C BOOL ClientLibraryStartup(); EXTERN_C BOOL IdleTrackerAttach(); @@ -62,19 +60,75 @@ EXTERN_C DWORD BOINCGetIdleTickCount(); #endif -DEFINE_EVENT_TYPE(wxEVT_RPC_FINISHED) - IMPLEMENT_APP(CBOINCGUIApp) IMPLEMENT_DYNAMIC_CLASS(CBOINCGUIApp, wxApp) -BEGIN_EVENT_TABLE (CBOINCGUIApp, wxApp) - EVT_RPC_FINISHED(CBOINCGUIApp::OnRPCFinished) -END_EVENT_TABLE () +static bool s_bSkipExitConfirmation = false; + +#ifdef __WXMAC__ + +// Set s_bSkipExitConfirmation to true if cancelled because of logging out or shutting down +OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) { + DescType senderType; + Size actualSize; + ProcessSerialNumber SenderPSN, ourPSN; + Boolean isSame; + ProcessInfoRec pInfo; + FSSpec fileSpec; + OSStatus anErr; + + // Refuse to quit if a modal dialog is open. + // Unfortunately, I know of no way to disable the Quit item in our Dock menu + if (wxGetApp().IsModalDialogDisplayed()) { + SysBeep(4); + return userCanceledErr; + } + + anErr = AEGetAttributePtr(appleEvt, keyAddressAttr, typeProcessSerialNumber, + &senderType, &SenderPSN, sizeof(SenderPSN), &actualSize); + + if (anErr == noErr) { + + GetCurrentProcess(&ourPSN); + + anErr = SameProcess(&SenderPSN, &ourPSN, &isSame); + + if (anErr == noErr) { + if (!isSame) { + + pInfo.processInfoLength = sizeof( ProcessInfoRec ); + pInfo.processName = NULL; + pInfo.processAppSpec = &fileSpec; + + anErr = GetProcessInformation(&SenderPSN, &pInfo); + + // Consider a Quit command from our Dock menu as coming from this application + if (pInfo.processSignature != 'dock') { + s_bSkipExitConfirmation = true; // Not from our app, our dock icon or our taskbar icon + wxGetApp().ExitMainLoop(); // Prevents wxMac from issuing events to closed frames + } + } + } + } + + return wxGetApp().MacHandleAEQuit((AppleEvent*)appleEvt, reply); +} + +#endif bool CBOINCGUIApp::OnInit() { + // Initialize globals +#ifdef SANDBOX + g_use_sandbox = true; +#else + g_use_sandbox = false; +#endif - // Setup variables with default values + // Initialize statics + s_bSkipExitConfirmation = false; + + // Initialize class variables m_strBOINCArguments = wxEmptyString; m_strBOINCMGRRootDirectory = wxEmptyString; m_strBOINCMGRDataDirectory = wxEmptyString; @@ -85,7 +139,6 @@ bool CBOINCGUIApp::OnInit() { m_pTaskBarIcon = NULL; #ifdef __WXMAC__ m_pMacSystemMenu = NULL; - printf("Using %s.\n", wxVERSION_STRING); // For debugging #endif m_bGUIVisible = true; m_strDefaultWindowStation = wxEmptyString; @@ -97,31 +150,47 @@ bool CBOINCGUIApp::OnInit() { m_hClientLibraryDll = NULL; #endif -#if (defined(SANDBOX) || defined(__WXMAC__)) - int errCode = 0; -#endif + // Initialize local variables + int iErrorCode = 0; + wxString strDialogMessage = wxEmptyString; + + + // Dump useful debugging information + printf(wxT("BOINC Manager compiled with wxWidgets %s.\n"), wxVERSION_STRING); -#ifdef SANDBOX - g_use_sandbox = true; -#else - g_use_sandbox = false; -#endif // Commandline parsing is done in wxApp::OnInit() if (!wxApp::OnInit()) { return false; } - -#ifndef _WIN32 - if (g_use_sandbox) - umask (2); // Set file creation mask to be writable by both user and group - // Our umask will be inherited by all our child processes + +#ifdef __WXMAC__ + AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false ); + + // Cache the current process serial number + GetCurrentProcess(&m_psnCurrentProcess); + +#if wxCHECK_VERSION(2,8,0) + // In wxMac-2.8.7, default wxListCtrl::RefreshItem() does not work + // so use traditional generic implementation. + // This has been fixed in wxMac-2.8.8, but the Mac native implementation: + // - takes 3 times the CPU time as the Mac generic version. + // - seems to always redraw entire control even if asked to refresh only one row. + // - causes major flicker of progress bars, (probably due to full redraws.) + wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1); #endif +#endif + + if (g_use_sandbox) { + wxCHANGE_UMASK(2); // Set file creation mask to be writable by both user and group + // Our umask will be inherited by all our child processes + } // Setup application and company information SetAppName(wxT("BOINC Manager")); SetVendorName(wxT("Space Sciences Laboratory, U.C. Berkeley")); + // Initialize the configuration storage module m_pConfig = new wxConfig(GetAppName()); wxConfigBase::Set(m_pConfig); @@ -129,8 +198,376 @@ bool CBOINCGUIApp::OnInit() { m_pConfig->SetPath(wxT("/")); -#ifdef __WXMSW__ + // Detect where BOINC Manager was installed too. + DetectRootDirectory(); + + + // Detect where the BOINC Data files are. + DetectDataDirectory(); + + + // Switch the current directory to the BOINC Data directory + if (!GetDataDirectory().IsEmpty()) { + if (!wxSetWorkingDirectory(GetDataDirectory())) { + if (!g_use_sandbox) { + if (!wxDirExists(GetDataDirectory())) { + if (!wxMkdir(GetDataDirectory(), 0777)) { // Does nothing if dir exists + iErrorCode = -1016; + } + } + } + } + } + + +#ifdef SANDBOX + // Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox + if (!iErrorCode) { +#if (defined(__WXMAC__) && defined(_DEBUG)) // TODO: implement this for other platforms + // GDB can't attach to applications which are running as a different user + // or group, so fix up data with current user and group during debugging + if (check_security(g_use_sandbox, true)) { + CreateBOINCUsersAndGroups(); + SetBOINCDataOwnersGroupsAndPermissions(); + SetBOINCAppOwnersGroupsAndPermissions(NULL); + } +#endif + iErrorCode = check_security(g_use_sandbox, true); + } +#endif + + + if (iErrorCode) { + + ShowApplication(true); + + strDialogMessage.Printf( + wxT("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)\n"), + iErrorCode + ); + + wxMessageDialog* pDlg = new wxMessageDialog(NULL, strDialogMessage, wxT("BOINC Manager"), wxOK); + + pDlg->ShowModal(); + if (pDlg) + pDlg->Destroy(); + + return false; + } + + + // Initialize the BOINC Diagnostics Framework + int dwDiagnosticsFlags = + BOINC_DIAG_DUMPCALLSTACKENABLED | + BOINC_DIAG_HEAPCHECKENABLED | + BOINC_DIAG_MEMORYLEAKCHECKENABLED | +#if defined(__WXMSW__) || defined(__WXMAC__) + BOINC_DIAG_REDIRECTSTDERR | + BOINC_DIAG_REDIRECTSTDOUT | +#endif + BOINC_DIAG_TRACETOSTDOUT; + + diagnostics_init( + dwDiagnosticsFlags, + "stdoutgui", + "stderrgui" + ); + + + // Enable Logging and Trace Masks + m_pLog = new wxLogBOINC(); + wxLog::SetActiveTarget(m_pLog); + + m_pLog->AddTraceMask(wxT("Function Start/End")); + m_pLog->AddTraceMask(wxT("Function Status")); + + + // Enable known image types + wxImage::AddHandler(new wxXPMHandler); + wxImage::AddHandler(new wxPNGHandler); + wxImage::AddHandler(new wxGIFHandler); + wxImage::AddHandler(new wxICOHandler); + + + // Initialize the internationalization module + m_pLocale = new wxLocale(); + wxASSERT(m_pLocale); + + wxInt32 iSelectedLanguage = m_pConfig->Read(wxT("Language"), 0L); + + + // Look for the localization files by absolute and relative locations. + // preference given to the absolute location. + m_pLocale->Init(iSelectedLanguage); + if (!m_strBOINCMGRRootDirectory.IsEmpty()) { + m_pLocale->AddCatalogLookupPathPrefix( + wxString(m_strBOINCMGRRootDirectory + wxT("locale")) + ); + } + m_pLocale->AddCatalogLookupPathPrefix(wxT("locale")); + m_pLocale->AddCatalog(wxT("BOINC-Manager")); + + InitSupportedLanguages(); + + + // Note: JAWS for Windows will only speak the context-sensitive + // help if you use this help provider: + wxHelpProvider::Set(new wxHelpControllerHelpProvider()); + + + // Initialize the skin manager + m_pSkinManager = new CSkinManager(); + wxASSERT(m_pSkinManager); + + m_pSkinManager->ReloadSkin( + m_pLocale, + m_pConfig->Read(wxT("Skin"), m_pSkinManager->GetDefaultSkinName()) + ); + + +#ifdef __WXMSW__ + // Perform any last minute checks that should keep the manager + // from starting up. + wxString strRebootPendingFile = + GetRootDirectory() + wxFileName::GetPathSeparator() + wxT("RebootPending.txt"); + + wxFileInputStream fisRebootPending(strRebootPendingFile); + if (fisRebootPending.IsOk()) { + + wxMessageDialog dialog( + NULL, + _("A reboot is required in order for BOINC to run properly.\nPlease reboot your computer and try again."), + _("BOINC Manager"), + wxOK|wxICON_ERROR + ); + + dialog.ShowModal(); + return false; + } +#endif + + + // Initialize the main document + m_pDocument = new CMainDocument(); + wxASSERT(m_pDocument); + + m_pDocument->OnInit(); + + + // Which GUI should be displayed? + m_iGUISelected = m_pConfig->Read(wxT("GUISelection"), BOINC_SIMPLEGUI); + + + // Is there a condition in which the Simple GUI should not be used? + if (BOINC_SIMPLEGUI == m_iGUISelected) { + + // Screen too small? + if (wxGetDisplaySize().GetHeight() < 600) { + m_iGUISelected = BOINC_ADVANCEDGUI; + } + + // Screen reader in use? +#ifdef __WXMSW__ + BOOL bScreenReaderEnabled = false; + SystemParametersInfo(SPI_GETSCREENREADER, NULL, &bScreenReaderEnabled, NULL); + if (bScreenReaderEnabled) { + m_iGUISelected = BOINC_ADVANCEDGUI; + } +#endif + } + + + // Initialize the task bar icon +#if defined(__WXMSW__) || defined(__WXMAC__) + m_pTaskBarIcon = new CTaskBarIcon( + m_pSkinManager->GetAdvanced()->GetApplicationName(), + m_pSkinManager->GetAdvanced()->GetApplicationIcon(), + m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(), + m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon() + ); + wxASSERT(m_pTaskBarIcon); +#endif +#ifdef __WXMAC__ + m_pMacSystemMenu = new CMacSystemMenu( + m_pSkinManager->GetAdvanced()->GetApplicationName(), + m_pSkinManager->GetAdvanced()->GetApplicationIcon(), + m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(), + m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon() + ); + wxASSERT(m_pMacSystemMenu); +#endif + + + // Detect the display info and store for later use. + DetectDisplayInfo(); + + + // Startup the System Idle Detection code + ClientLibraryStartup(); + IdleTrackerAttach(); + +#ifdef __WXMAC__ + ProcessInfoRec pInfo; + OSStatus err; + + GetCurrentProcess(&psn); + memset(&pInfo, 0, sizeof(pInfo)); + pInfo.processInfoLength = sizeof( ProcessInfoRec ); + err = GetProcessInformation(&psn, &pInfo); + if (!err) { + psn = pInfo.processLauncher; + memset(&pInfo, 0, sizeof(pInfo)); + pInfo.processInfoLength = sizeof( ProcessInfoRec ); + err = GetProcessInformation(&psn, &pInfo); + } + // Don't open main window if we were started automatically at login + if (pInfo.processSignature == 'lgnw') { // Login Window app + m_bGUIVisible = false; + + // If the system was just started, we usually get a "Connection + // failed" error if we try to connect too soon, so delay a bit. + sleep(10); + } +#endif + + + // Show the UI + SetActiveGUI(m_iGUISelected, false); + if (m_bGUIVisible) { + SetActiveGUI(m_iGUISelected); + } else { + ShowApplication(false); + } + + return true; +} + + +int CBOINCGUIApp::OnExit() { + // Shutdown the System Idle Detection code + IdleTrackerDetach(); + ClientLibraryShutdown(); + + if (m_pDocument) { + m_pDocument->OnExit(); + delete m_pDocument; + m_pDocument = NULL; + } + + if (m_pSkinManager) { + m_pConfig->Write(wxT("Skin"), m_pSkinManager->GetSelectedSkin()); + delete m_pSkinManager; + } + + if (m_pLocale) { + delete m_pLocale; + } + + diagnostics_finish(); + + return wxApp::OnExit(); +} + + +/// +/// Pass the command line parameters and discriptions to wxWidgets for displaying. +/// +void CBOINCGUIApp::OnInitCmdLine(wxCmdLineParser &parser) { + wxApp::OnInitCmdLine(parser); + static const wxCmdLineEntryDesc cmdLineDesc[] = { + { wxCMD_LINE_SWITCH, wxT("s"), wxT("systray"), _("Startup BOINC so only the system tray icon is visible")}, + { wxCMD_LINE_SWITCH, wxT("b"), wxT("boincargs"), _("Startup BOINC with these optional arguments")}, + { wxCMD_LINE_SWITCH, wxT("i"), wxT("insecure"), _("disable BOINC security users and permissions")}, + { wxCMD_LINE_NONE} //DON'T forget this line!! + }; + parser.SetDesc(cmdLineDesc); +} + + +/// +/// Parse command line parameters. +/// +bool CBOINCGUIApp::OnCmdLineParsed(wxCmdLineParser &parser) { + // Give default processing (-?, --help and --verbose) the chance to do something. + wxApp::OnCmdLineParsed(parser); + + parser.Found(wxT("boincargs"), &m_strBOINCArguments); + if (parser.Found(wxT("systray"))) { + m_bGUIVisible = false; + } + if (parser.Found(wxT("insecure"))) { + g_use_sandbox = false; + } + + return true; +} + + +/// +/// Detect the desktop that BOINC Manager is running in. +/// +void CBOINCGUIApp::DetectDisplayInfo() { +#ifdef __WXMSW__ + wxChar szWindowStation[256]; + memset(szWindowStation, 0, sizeof(szWindowStation)/sizeof(wxChar)); + wxChar szDesktop[256]; + memset(szDesktop, 0, sizeof(szDesktop)/sizeof(wxChar)); + + if (wxWIN95 != wxGetOsVersion(NULL, NULL)) { + // Retrieve the current window station and desktop names + GetUserObjectInformation( + GetProcessWindowStation(), + UOI_NAME, + szWindowStation, + (sizeof(szWindowStation) / sizeof(wxChar)), + NULL + ); + GetUserObjectInformation( + GetThreadDesktop(GetCurrentThreadId()), + UOI_NAME, + szDesktop, + (sizeof(szDesktop) / sizeof(wxChar)), + NULL + ); + m_strDefaultWindowStation = szWindowStation; + m_strDefaultDesktop = szDesktop; + } + +#else + wxString p = wxString(getenv("DISPLAY"), wxConvUTF8); + if (p) m_strDefaultDisplay = p; +#endif + +} + + +/// +/// Determines where the BOINC Manager is executing from. +/// +void CBOINCGUIApp::DetectRootDirectory() { +#ifdef __WXMSW__ + TCHAR szPath[MAX_PATH-1]; + + // change the current directory to the boinc install directory + GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR))); + + TCHAR *pszProg = strrchr(szPath, '\\'); + if (pszProg) { + szPath[pszProg - szPath + 1] = 0; + } + + // Store the root directory for later use. + m_strBOINCMGRRootDirectory = szPath; +#endif +} + + +/// +/// Determines where the BOINC data directory is. +/// +void CBOINCGUIApp::DetectDataDirectory() { +#ifdef __WXMSW__ // // Determine BOINCMgr Data Directory // @@ -172,8 +609,6 @@ bool CBOINCGUIApp::OnInit() { &dwSize ); - SetCurrentDirectory(lpszRegistryValue); - // Store the root directory for later use. m_strBOINCMGRDataDirectory = lpszRegistryValue; } @@ -182,370 +617,10 @@ bool CBOINCGUIApp::OnInit() { // Cleanup if (hkSetupHive) RegCloseKey(hkSetupHive); if (lpszRegistryValue) free(lpszRegistryValue); - - - // - // Determine BOINCMgr Root Directory - // - TCHAR szPath[MAX_PATH-1]; - - // change the current directory to the boinc install directory - GetModuleFileName(NULL, szPath, (sizeof(szPath)/sizeof(TCHAR))); - - TCHAR *pszProg = strrchr(szPath, '\\'); - if (pszProg) { - szPath[pszProg - szPath + 1] = 0; - } - - // Store the root directory for later use. - m_strBOINCMGRRootDirectory = szPath; - #endif - #ifdef __WXMAC__ - -#if wxCHECK_VERSION(2,8,0) -// In wxMac-2.8.7, default wxListCtrl::RefreshItem() does not work -// so use traditional generic implementation. -// This has been fixed in wxMac-2.8.8, but the Mac native implementation: -// - takes 3 times the CPU time as the Mac generic version. -// - seems to always redraw entire control even if asked to refresh only one row. -// - causes major flicker of progress bars, (probably due to full redraws.) - wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1); + m_strBOINCMGRDataDirectory = wxT("/Library/Application Support/BOINC Data"); #endif - - wxString strDirectory = wxEmptyString; - bool success; - ProcessSerialNumber psn; - - // Set the current directory ahead of the application launch so the core - // client can find its files - - // The mac installer sets the "setuid & setgid" bits for the - // BOINC Manager and core client so any user can run them and - // they can operate on shared data. - strDirectory = wxT("/Library/Application Support/"); - - success = ::wxSetWorkingDirectory(strDirectory); - if (success) { - // If SetWD failed, don't create a directory in wrong place - strDirectory += wxT("BOINC Data"); // We don't customize BOINC Data directory name for branding - if (! g_use_sandbox) { - if (! wxDirExists(strDirectory)) - success = wxMkdir(strDirectory, 0777); // Does nothing if dir exists - } - success = ::wxSetWorkingDirectory(strDirectory); -// wxChar *wd = wxGetWorkingDirectory(buf, 1000); // For debugging - } - - if (!success) // wxSetWorkingDirectory("/Library/Application Support/BOINC Data") FAILED - errCode = -1016; -#endif // __WXMAC__ - -#ifdef SANDBOX - // Make sure owners, groups and permissions are correct for the current setting of g_use_sandbox - if (!errCode) { -#if (defined(__WXMAC__) && defined(_DEBUG)) // TODO: implement this for other platforms - // GDB can't attach to applications which are running as a different user - // or group, so fix up data with current user and group during debugging - if (check_security(g_use_sandbox, true)) { - CreateBOINCUsersAndGroups(); - SetBOINCDataOwnersGroupsAndPermissions(); - SetBOINCAppOwnersGroupsAndPermissions(NULL); - } -#endif // __WXMAC__ && _DEBUG - errCode = check_security(g_use_sandbox, true); - } - - if (errCode) { - wxString strDialogMessage = wxEmptyString; - strDialogMessage.Printf( - _("BOINC ownership or permissions are not set properly; please reinstall BOINC.\n(Error code %d)"), - errCode - ); - wxMessageDialog* pDlg = new wxMessageDialog(NULL, strDialogMessage, wxT(""), wxOK); - GetCurrentProcess(&psn); - SetFrontProcess(&psn); // Shows process if hidden - pDlg->ShowModal(); - if (pDlg) - pDlg->Destroy(); - return false; - } -#endif // SANDBOX - - // Initialize the BOINC Diagnostics Framework - int dwDiagnosticsFlags = - BOINC_DIAG_DUMPCALLSTACKENABLED | - BOINC_DIAG_HEAPCHECKENABLED | - BOINC_DIAG_MEMORYLEAKCHECKENABLED | -#if defined(__WXMSW__) || defined(__WXMAC__) - BOINC_DIAG_REDIRECTSTDERR | - BOINC_DIAG_REDIRECTSTDOUT | -#endif - BOINC_DIAG_TRACETOSTDOUT; - - diagnostics_init( - dwDiagnosticsFlags, - "stdoutgui", - "stderrgui" - ); - - // Enable Logging and Trace Masks - m_pLog = new wxLogBOINC(); - wxLog::SetActiveTarget(m_pLog); - - m_pLog->AddTraceMask(wxT("Function Start/End")); - m_pLog->AddTraceMask(wxT("Function Status")); - - // Enable known image types - wxImage::AddHandler(new wxXPMHandler); - wxImage::AddHandler(new wxPNGHandler); - wxImage::AddHandler(new wxGIFHandler); - wxImage::AddHandler(new wxICOHandler); - - // Initialize the internationalization module - m_pLocale = new wxLocale(); - wxASSERT(m_pLocale); - - wxInt32 iSelectedLanguage = m_pConfig->Read(wxT("Language"), 0L); - - // Look for the localization files by absolute and relative locations. - // preference given to the absolute location. - m_pLocale->Init(iSelectedLanguage); - if (!m_strBOINCMGRRootDirectory.IsEmpty()) { - m_pLocale->AddCatalogLookupPathPrefix( - wxString(m_strBOINCMGRRootDirectory + wxT("locale")) - ); - } - m_pLocale->AddCatalogLookupPathPrefix(wxT("locale")); - m_pLocale->AddCatalog(wxT("BOINC-Manager")); - - InitSupportedLanguages(); - - // Note: JAWS for Windows will only speak the context-sensitive - // help if you use this help provider: - wxHelpProvider::Set(new wxHelpControllerHelpProvider()); - - // Initialize the skin manager - m_pSkinManager = new CSkinManager(); - wxASSERT(m_pSkinManager); - - m_pSkinManager->ReloadSkin( - m_pLocale, - m_pConfig->Read(wxT("Skin"), m_pSkinManager->GetDefaultSkinName()) - ); - -#ifdef __WXMSW__ - // Perform any last minute checks that should keep the manager - // from starting up. - wxString strRebootPendingFile = - GetRootDirectory() + wxFileName::GetPathSeparator() + wxT("RebootPending.txt"); - - wxFileInputStream fisRebootPending(strRebootPendingFile); - if (fisRebootPending.IsOk()) { - - wxMessageDialog dialog( - NULL, - _("A reboot is required in order for BOINC to run properly.\nPlease reboot your computer and try again."), - _("BOINC Manager"), - wxOK|wxICON_ERROR - ); - - dialog.ShowModal(); - return false; - } -#endif - - // Initialize the main document - m_pDocument = new CMainDocument(); - wxASSERT(m_pDocument); - - m_pDocument->OnInit(); - - // Which GUI should be displayed? - m_iGUISelected = m_pConfig->Read(wxT("GUISelection"), BOINC_SIMPLEGUI); - - // Is there a condition in which the Simple GUI should not be used? - if (BOINC_SIMPLEGUI == m_iGUISelected) { - - // Screen too small? - if (wxGetDisplaySize().GetHeight() < 600) { - m_iGUISelected = BOINC_ADVANCEDGUI; - } - - // Screen reader in use? -#ifdef __WXMSW__ - BOOL bScreenReaderEnabled = false; - SystemParametersInfo(SPI_GETSCREENREADER, NULL, &bScreenReaderEnabled, NULL); - if (bScreenReaderEnabled) { - m_iGUISelected = BOINC_ADVANCEDGUI; - } -#endif - } - -#ifdef __WXMAC__ -#if 0 // We may still need this code; don't remove it yet -- CAF 1/30/08 - // When running BOINC Client as a daemon / service, the menubar icon is sometimes - // unresponsive to mouse clicks if we create it before connecting to the Client. - CBOINCClientManager* pcm = m_pDocument->m_pClientManager; - if (pcm->IsSystemBooting() && pcm->IsBOINCConfiguredAsDaemon()) { - pcm->StartupBOINCCore(); - } -#endif -#endif - - // Initialize the task bar icon -#if defined(__WXMSW__) || defined(__WXMAC__) - m_pTaskBarIcon = new CTaskBarIcon( - m_pSkinManager->GetAdvanced()->GetApplicationName(), - m_pSkinManager->GetAdvanced()->GetApplicationIcon(), - m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(), - m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon() - ); - wxASSERT(m_pTaskBarIcon); -#endif - - // Detect the display info and store for later use. - DetectDisplayInfo(); - - // Startup the System Idle Detection code - ClientLibraryStartup(); - IdleTrackerAttach(); - -#ifdef __WXMAC__ - s_bSkipExitConfirmation = false; - AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false ); - - m_pMacSystemMenu = new CMacSystemMenu( - m_pSkinManager->GetAdvanced()->GetApplicationName(), - m_pSkinManager->GetAdvanced()->GetApplicationIcon(), - m_pSkinManager->GetAdvanced()->GetApplicationDisconnectedIcon(), - m_pSkinManager->GetAdvanced()->GetApplicationSnoozeIcon() - ); - wxASSERT(m_pMacSystemMenu); - - ProcessInfoRec pInfo; - OSStatus err; - - GetCurrentProcess(&psn); - memset(&pInfo, 0, sizeof(pInfo)); - pInfo.processInfoLength = sizeof( ProcessInfoRec ); - err = GetProcessInformation(&psn, &pInfo); - if (!err) { - psn = pInfo.processLauncher; - memset(&pInfo, 0, sizeof(pInfo)); - pInfo.processInfoLength = sizeof( ProcessInfoRec ); - err = GetProcessInformation(&psn, &pInfo); - } - // Don't open main window if we were started automatically at login - if (pInfo.processSignature == 'lgnw') { // Login Window app - m_bGUIVisible = false; - - // If the system was just started, we usually get a "Connection - // failed" error if we try to connect too soon, so delay a bit. - sleep(10); - } -#endif - - // Show the UI - SetActiveGUI(m_iGUISelected, false); - if (m_bGUIVisible) { - SetActiveGUI(m_iGUISelected); - } else { -#ifdef __WXMAC__ - GetCurrentProcess(&psn); - ShowHideProcess(&psn, false); -#endif - } - - return true; -} - - -int CBOINCGUIApp::OnExit() { - // Shutdown the System Idle Detection code - IdleTrackerDetach(); - ClientLibraryShutdown(); - - if (m_pDocument) { - m_pDocument->OnExit(); - delete m_pDocument; - m_pDocument = NULL; - } - - if (m_pSkinManager) { - m_pConfig->Write(wxT("Skin"), m_pSkinManager->GetSelectedSkin()); - delete m_pSkinManager; - } - - if (m_pLocale) { - delete m_pLocale; - } - - diagnostics_finish(); - - return wxApp::OnExit(); -} - - -void CBOINCGUIApp::OnInitCmdLine(wxCmdLineParser &parser) { - wxApp::OnInitCmdLine(parser); - static const wxCmdLineEntryDesc cmdLineDesc[] = { - { wxCMD_LINE_SWITCH, wxT("s"), wxT("systray"), _("Startup BOINC so only the system tray icon is visible")}, - { wxCMD_LINE_SWITCH, wxT("b"), wxT("boincargs"), _("Startup BOINC with these optional arguments")}, - { wxCMD_LINE_SWITCH, wxT("i"), wxT("insecure"), _("disable BOINC security users and permissions")}, - { wxCMD_LINE_NONE} //DON'T forget this line!! - }; - parser.SetDesc(cmdLineDesc); -} - - -bool CBOINCGUIApp::OnCmdLineParsed(wxCmdLineParser &parser) { - // Give default processing (-?, --help and --verbose) the chance to do something. - wxApp::OnCmdLineParsed(parser); - parser.Found(wxT("boincargs"), &m_strBOINCArguments); - if (parser.Found(wxT("systray"))) { - m_bGUIVisible = false; - } - if (parser.Found(wxT("insecure"))) { - g_use_sandbox = false; - } - return true; -} - - -void CBOINCGUIApp::DetectDisplayInfo() { -#ifdef __WXMSW__ - wxChar szWindowStation[256]; - memset(szWindowStation, 0, sizeof(szWindowStation)/sizeof(wxChar)); - wxChar szDesktop[256]; - memset(szDesktop, 0, sizeof(szDesktop)/sizeof(wxChar)); - - if (wxWIN95 != wxGetOsVersion(NULL, NULL)) { - // Retrieve the current window station and desktop names - GetUserObjectInformation( - GetProcessWindowStation(), - UOI_NAME, - szWindowStation, - (sizeof(szWindowStation) / sizeof(wxChar)), - NULL - ); - GetUserObjectInformation( - GetThreadDesktop(GetCurrentThreadId()), - UOI_NAME, - szDesktop, - (sizeof(szDesktop) / sizeof(wxChar)), - NULL - ); - m_strDefaultWindowStation = szWindowStation; - m_strDefaultDesktop = szDesktop; - } - -#else - wxString p = wxString(getenv("DISPLAY"), wxConvUTF8); - if (p) m_strDefaultDisplay = p; -#endif - } @@ -570,58 +645,6 @@ void CBOINCGUIApp::InitSupportedLanguages() { } -#ifdef __WXMAC__ - -// Set s_bSkipExitConfirmation to true if cancelled because of logging out or shutting down -OSErr CBOINCGUIApp::QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) { - DescType senderType; - Size actualSize; - ProcessSerialNumber SenderPSN, ourPSN; - Boolean isSame; - ProcessInfoRec pInfo; - FSSpec fileSpec; - OSStatus anErr; - - // Refuse to quit if a modal dialog is open. - // Unfortunately, I know of no way to disable the Quit item in our Dock menu - if (wxGetApp().IsModalDialogDisplayed()) { - SysBeep(4); - return userCanceledErr; - } - - anErr = AEGetAttributePtr(appleEvt, keyAddressAttr, typeProcessSerialNumber, - &senderType, &SenderPSN, sizeof(SenderPSN), &actualSize); - - if (anErr == noErr) { - - GetCurrentProcess(&ourPSN); - - anErr = SameProcess(&SenderPSN, &ourPSN, &isSame); - - if (anErr == noErr) { - if (!isSame) { - - pInfo.processInfoLength = sizeof( ProcessInfoRec ); - pInfo.processName = NULL; - pInfo.processAppSpec = &fileSpec; - - anErr = GetProcessInformation(&SenderPSN, &pInfo); - - // Consider a Quit command from our Dock menu as coming from this application - if (pInfo.processSignature != 'dock') { - s_bSkipExitConfirmation = true; // Not from our app, our dock icon or our taskbar icon - wxGetApp().ExitMainLoop(); // Prevents wxMac from issuing events to closed frames - } - } - } - } - - return wxGetApp().MacHandleAEQuit((AppleEvent*)appleEvt, reply); -} - -#endif - - int CBOINCGUIApp::ClientLibraryStartup() { #ifdef __WXMSW__ ::ClientLibraryStartup(); @@ -654,16 +677,6 @@ int CBOINCGUIApp::ClientLibraryShutdown() { } -void CBOINCGUIApp::OnRPCFinished( CRPCFinishedEvent& event ) { - CMainDocument* pDoc = wxGetApp().GetDocument(); - - wxASSERT(pDoc); - wxASSERT(wxDynamicCast(pDoc, CMainDocument)); - - pDoc->OnRPCComplete(event); -} - - int CBOINCGUIApp::UpdateSystemIdleDetection() { #ifdef __WXMSW__ return BOINCGetIdleTickCount(); @@ -729,15 +742,19 @@ bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) { ); break; } + wxASSERT(pNewFrame); + if (pNewFrame) { SetTopWindow(pNewFrame); -#ifdef __WXMAC__ - // So closing old view doesn't hide application - pNewFrame->m_iWindowType = iGUISelection; - m_iGUISelected = iGUISelection; -#endif + // Hide the old one if it exists + if (m_pFrame) m_pFrame->Hide(); + + // Show the new frame if needed, and prevent Mac OSX from + // hiding the application + if (pNewFrame && bShowWindow) pNewFrame->Show(); + // Delete the old one if it exists if (m_pFrame) m_pFrame->Destroy(); @@ -747,7 +764,7 @@ bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) { } // Show the new frame if needed - if (m_pFrame && bShowWindow) m_pFrame->Show(); + if (m_pFrame && !m_pFrame->IsShown() && bShowWindow) m_pFrame->Show(); m_iGUISelected = iGUISelection; m_pConfig->Write(wxT("GUISelection"), iGUISelection); @@ -756,40 +773,11 @@ bool CBOINCGUIApp::SetActiveGUI(int iGUISelection, bool bShowWindow) { } -int CBOINCGUIApp::GetCurrentViewPage() { - if (!m_pFrame) return 0; - - if (m_iGUISelected == BOINC_SIMPLEGUI) { - if (((CSimpleFrame*)m_pFrame)->isMessagesDlgOpen()) { - return VW_SGUI | VW_SMSG; - } else { - return VW_SGUI; - } - } - - switch (((CAdvancedFrame*)m_pFrame)->GetViewTabIndex()) { - case 0: - return VW_PROJ; - case 1: - return VW_TASK; - case 2: - return VW_XFER; - case 3: - return VW_MSGS; - case 4: - return VW_STAT; - case 5: - return VW_DISK; - } - - return 0; // Should never happen. -} - - int CBOINCGUIApp::ConfirmExit() { - CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced(); - CMainDocument* pDoc = wxGetApp().GetDocument(); - wxString strTitle; + CSkinAdvanced* pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced(); + CMainDocument* pDoc = wxGetApp().GetDocument(); + wxString strTitle; + bool bWasVisible; wxASSERT(pDoc); wxASSERT(pSkinAdvanced); @@ -802,17 +790,12 @@ int CBOINCGUIApp::ConfirmExit() { if (!m_iDisplayExitWarning) return 1; -#ifdef __WXMAC__ // Don't run confirmation dialog if logging out or shutting down if (s_bSkipExitConfirmation) return 1; - ProcessSerialNumber psn; - - GetCurrentProcess(&psn); - bool wasVisible = IsProcessVisible(&psn); - SetFrontProcess(&psn); // Shows process if hidden -#endif + bWasVisible = IsApplicationVisible(); + ShowApplication(true); strTitle.Printf( _("%s - Exit Confirmation"), @@ -833,11 +816,11 @@ int CBOINCGUIApp::ConfirmExit() { s_bSkipExitConfirmation = true; // Don't ask twice (only affects Mac) return 1; } -#ifdef __WXMAC__ - if (!wasVisible) { - ShowHideProcess(&psn, false); + + if (!bWasVisible) { + ShowApplication(false); } -#endif + return 0; // User cancelled exit } @@ -859,6 +842,39 @@ int CBOINCGUIApp::SafeMessageBox(const wxString& message, const wxString& captio return retval; } +/// +/// Determines if the current process is visible. +/// +/// @return +/// true if the current process is visible, otherwise false. +/// +bool CBOINCGUIApp::IsApplicationVisible() { +#ifdef __WXMAC__ + if (IsProcessVisible(&m_psnCurrentProcess)) { + return true; + } +#endif + return false; +} + +/// +/// Shows or hides the current process. +/// +/// @param bShow +/// true will show the process, false will hide the process. +/// +void CBOINCGUIApp::ShowApplication(bool bShow) { +#ifndef __WXMAC__ + bool b = bShow; + b = true; +#else + if (bShow) { + SetFrontProcess(&m_psnCurrentProcess); + } else { + ShowHideProcess(&m_psnCurrentProcess, false); + } +#endif +} bool CBOINCGUIApp::IsModalDialogDisplayed() { if (m_bSafeMessageBoxDisplayed) return true; @@ -890,20 +906,18 @@ int CBOINCGUIApp::FilterEvent(wxEvent &event) { // - Open Manager menu item from system tray icon int theEventType = event.GetEventType(); - if ((theEventType == wxEVT_COMMAND_MENU_SELECTED) - && (event.GetId() == wxID_OPEN)) { + if ((theEventType == wxEVT_COMMAND_MENU_SELECTED) && (event.GetId() == wxID_OPEN)) { return -1; } wxDialog* theRPCWaitDialog = m_pDocument->GetRPCWaitDialog(); - wxObject * theObject = event.GetEventObject(); + wxObject* theObject = event.GetEventObject(); while (theObject) { - if (! theObject->IsKindOf(CLASSINFO(wxWindow))) break; + if (!theObject->IsKindOf(CLASSINFO(wxWindow))) break; if (theObject == theRPCWaitDialog) return -1; theObject = ((wxWindow*)theObject)->GetParent(); } -#if 1 // Allow all except Command, Timer and Mouse Moved events if (event.IsCommandEvent()) { return false; @@ -918,37 +932,6 @@ int CBOINCGUIApp::FilterEvent(wxEvent &event) { } return -1; -#else - // Reject all events except: - // - Taskbar Menu - // - Paint - // - Erase Background - if (theEventType == wxEVT_RPC_FINISHED) { - return -1; - } - -#ifdef __WXMSW__ - if (theEventType == wxEVT_TASKBAR_CONTEXT_MENU) { - return -1; - } - if (theEventType == wxEVT_TASKBAR_RIGHT_DOWN) { - return -1; - } - if (theEventType == wxEVT_TASKBAR_RIGHT_UP) { - return -1; - } -#endif - - if (theEventType == wxEVT_PAINT) { - return -1; - } - - if (theEventType == wxEVT_ERASE_BACKGROUND) { - return -1; - } - - return false; -#endif } const char *BOINC_RCSID_487cbf3018 = "$Id$"; diff --git a/clientgui/BOINCGUIApp.h b/clientgui/BOINCGUIApp.h index 747bcbc96a..aa74ff67f7 100644 --- a/clientgui/BOINCGUIApp.h +++ b/clientgui/BOINCGUIApp.h @@ -32,20 +32,12 @@ #include "mac/MacSysMenu.h" // Must be included before MainDocument.h #endif +/// +/// Which view is on display +/// #define BOINC_ADVANCEDGUI 1 #define BOINC_SIMPLEGUI 2 -// Bit values for CBOINCGUIApp::GetCurrentView() and -// CMainDocument::RunPeriodicRPCs() -#define VW_PROJ 1 -#define VW_TASK 2 -#define VW_XFER 4 -#define VW_MSGS 8 -#define VW_STAT 16 -#define VW_DISK 32 -#define VW_SGUI 1024 -#define VW_SMSG 2048 - class wxLogBOINC; class CBOINCBaseFrame; @@ -56,6 +48,7 @@ class CRPCFinishedEvent; class CBOINCGUIApp : public wxApp { + DECLARE_DYNAMIC_CLASS(CBOINCGUIApp) protected: @@ -65,13 +58,11 @@ protected: bool OnCmdLineParsed(wxCmdLineParser &parser); void DetectDisplayInfo(); + void DetectRootDirectory(); + void DetectDataDirectory(); void InitSupportedLanguages(); -#ifdef __WXMAC__ - static OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ); -#endif - int ClientLibraryStartup(); int IdleTrackerAttach(); int IdleTrackerDetach(); @@ -101,6 +92,10 @@ protected: #ifdef __WXMSW__ HINSTANCE m_hClientLibraryDll; #endif +#ifdef __WXMAC__ + ProcessSerialNumber m_psnCurrentProcess; +#endif + // The last value defined in the wxLanguage enum is wxLANGUAGE_USER_DEFINED. // defined in: wx/intl.h @@ -116,14 +111,9 @@ public: bool OnInit(); - int UpdateSystemIdleDetection(); - - int StartBOINCScreensaverTest(); - wxLocale* GetLocale() { return m_pLocale; } CSkinManager* GetSkinManager() { return m_pSkinManager; } CBOINCBaseFrame* GetFrame() { return m_pFrame; } - void FrameClosed() { m_pFrame = NULL; } CMainDocument* GetDocument() { return m_pDocument; } wxString GetArguments() { return m_strBOINCArguments; } wxString GetRootDirectory() { return m_strBOINCMGRRootDirectory; } @@ -133,33 +123,41 @@ public: #endif #ifdef __WXMAC__ CMacSystemMenu* GetMacSystemMenu() { return m_pMacSystemMenu; } - int GetCurrentGUISelection() { return m_iGUISelected; } #endif wxArrayString& GetSupportedLanguages() { return m_astrLanguages; } - int GetDisplayExitWarning() { return m_iDisplayExitWarning; } + int GetDisplayExitWarning() { return m_iDisplayExitWarning; } void SetDisplayExitWarning(int display) { m_iDisplayExitWarning = display; } void FireReloadSkin(); + void FrameClosed() { m_pFrame = NULL; } + + int StartBOINCScreensaverTest(); bool SetActiveGUI(int iGUISelection, bool bShowWindow = true); - int GetCurrentViewPage(); - virtual void OnRPCFinished( CRPCFinishedEvent& event ); + void OnRPCFinished( CRPCFinishedEvent& event ); int ConfirmExit(); - int SafeMessageBox(const wxString& message, - const wxString& caption = wxMessageBoxCaptionStr, - long style = wxOK | wxCENTRE, - wxWindow *parent = NULL, - int x = wxDefaultCoord, int y = wxDefaultCoord); + int SafeMessageBox( + const wxString& message, + const wxString& caption = wxMessageBoxCaptionStr, + long style = wxOK | wxCENTRE, + wxWindow *parent = NULL, + int x = wxDefaultCoord, + int y = wxDefaultCoord + ); + + bool IsApplicationVisible(); + void ShowApplication(bool bShow); bool IsModalDialogDisplayed(); + int FilterEvent(wxEvent &event); -DECLARE_EVENT_TABLE() + int UpdateSystemIdleDetection(); }; diff --git a/clientgui/BOINCTaskBar.cpp b/clientgui/BOINCTaskBar.cpp index aaae4566ff..9e82bda856 100644 --- a/clientgui/BOINCTaskBar.cpp +++ b/clientgui/BOINCTaskBar.cpp @@ -231,24 +231,19 @@ void CTaskBarIcon::OnSuspendResume(wxCommandEvent& WXUNUSED(event)) { void CTaskBarIcon::OnAbout(wxCommandEvent& WXUNUSED(event)) { -#ifdef __WXMAC__ - ProcessSerialNumber psn; + bool bWasVisible; - GetCurrentProcess(&psn); - bool wasVisible = IsProcessVisible(&psn); - SetFrontProcess(&psn); // Shows process if hidden -#endif + bWasVisible = wxGetApp().IsApplicationVisible(); + wxGetApp().ShowApplication(true); ResetTaskBar(); CDlgAbout dlg(NULL); dlg.ShowModal(); -#ifdef __WXMAC__ - if (!wasVisible) { - ShowHideProcess(&psn, false); + if (!bWasVisible) { + wxGetApp().ShowApplication(false); } -#endif } diff --git a/clientgui/MainDocument.cpp b/clientgui/MainDocument.cpp index 74c52969ba..a0b948b788 100644 --- a/clientgui/MainDocument.cpp +++ b/clientgui/MainDocument.cpp @@ -28,8 +28,10 @@ #endif #include "BOINCGUIApp.h" -#include "BOINCBaseFrame.h" #include "MainDocument.h" +#include "BOINCBaseFrame.h" +#include "AdvancedFrame.h" +#include "sg_BoincSimpleGUI.h" #include "BOINCClientManager.h" #include "BOINCTaskBar.h" #include "Events.h" @@ -769,6 +771,7 @@ void CMainDocument::RunPeriodicRPCs() { CBOINCBaseFrame* pFrame = wxGetApp().GetFrame(); if (!pFrame) return; + wxASSERT(wxDynamicCast(pFrame, CBOINCBaseFrame)); if (!IsConnected()) { @@ -782,10 +785,11 @@ void CMainDocument::RunPeriodicRPCs() { pTaskbar->AddPendingEvent(event); } #endif + return; } - int currentTabView = wxGetApp().GetCurrentViewPage(); + int currentTabView = pFrame->GetCurrentViewPage(); // Several functions (such as Abort, Reset, Detach) display an // "Are you sure?" dialog before passing a pointer to a result @@ -828,7 +832,7 @@ void CMainDocument::RunPeriodicRPCs() { request.arg2 = &messages; // request.arg2 = &async_messages_buf; // request.exchangeBuf = &messages; - request.rpcType = (currentTabView & VW_MSGS) ? + request.rpcType = (currentTabView & VW_MSGS) ? RPC_TYPE_ASYNC_WITH_REFRESH_AFTER : RPC_TYPE_ASYNC_WITH_UPDATE_MESSAGE_LIST_AFTER; request.completionTime = NULL; request.resultPtr = &m_iGet_messages_rpc_result; diff --git a/clientgui/MainDocument.h b/clientgui/MainDocument.h index 9d28b3d53c..52bf368ebf 100644 --- a/clientgui/MainDocument.h +++ b/clientgui/MainDocument.h @@ -176,7 +176,7 @@ public: // public: int RequestRPC(ASYNC_RPC_REQUEST& request, bool hasPriority = false); - void OnRPCComplete(CRPCFinishedEvent& event); + void OnRPCComplete(); void HandleCompletedRPC(); ASYNC_RPC_REQUEST* GetCurrentRPCRequest() { return ¤t_rpc_request; } bool WaitingForRPC() { return m_bWaitingForRPC; } diff --git a/clientgui/ViewProjects.cpp b/clientgui/ViewProjects.cpp index 3a7771ebff..b1fb853f29 100644 --- a/clientgui/ViewProjects.cpp +++ b/clientgui/ViewProjects.cpp @@ -643,6 +643,10 @@ wxInt32 CViewProjects::RemoveCacheElement() { } +bool CViewProjects::ManageSelections() { + return true; +} + void CViewProjects::UpdateSelection() { CTaskItemGroup* pGroup = NULL; PROJECT* project = NULL; diff --git a/clientgui/ViewProjects.h b/clientgui/ViewProjects.h index a797f51e51..d6a7d06ecc 100644 --- a/clientgui/ViewProjects.h +++ b/clientgui/ViewProjects.h @@ -84,6 +84,8 @@ protected: virtual wxInt32 RemoveCacheElement(); virtual bool SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex); + virtual bool ManageSelections(); + virtual void UpdateSelection(); void GetDocProjectName(wxInt32 item, wxString& strBuffer) const; diff --git a/clientgui/ViewTransfers.cpp b/clientgui/ViewTransfers.cpp index 1592de97eb..20c754a3f5 100644 --- a/clientgui/ViewTransfers.cpp +++ b/clientgui/ViewTransfers.cpp @@ -433,6 +433,11 @@ wxInt32 CViewTransfers::RemoveCacheElement() { } +bool CViewTransfers::ManageSelections() { + return true; +} + + void CViewTransfers::UpdateSelection() { CTaskItemGroup* pGroup = m_TaskGroups[0]; diff --git a/clientgui/ViewTransfers.h b/clientgui/ViewTransfers.h index 551e512639..82927b9481 100644 --- a/clientgui/ViewTransfers.h +++ b/clientgui/ViewTransfers.h @@ -79,6 +79,8 @@ protected: virtual wxInt32 RemoveCacheElement(); virtual bool SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex); + virtual bool ManageSelections(); + virtual void UpdateSelection(); void GetDocProjectName(wxInt32 item, wxString& strBuffer) const; diff --git a/clientgui/ViewWork.cpp b/clientgui/ViewWork.cpp index 3d23c9749a..8cf8289a14 100644 --- a/clientgui/ViewWork.cpp +++ b/clientgui/ViewWork.cpp @@ -580,6 +580,11 @@ wxInt32 CViewWork::RemoveCacheElement() { } +bool CViewWork::ManageSelections() { + return true; +} + + void CViewWork::UpdateSelection() { CTaskItemGroup* pGroup = NULL; RESULT* result = NULL; diff --git a/clientgui/ViewWork.h b/clientgui/ViewWork.h index 3a511c30c7..21f1a6d75a 100644 --- a/clientgui/ViewWork.h +++ b/clientgui/ViewWork.h @@ -85,6 +85,9 @@ protected: virtual wxInt32 GetCacheCount(); virtual wxInt32 RemoveCacheElement(); virtual bool SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex); + + virtual bool ManageSelections(); + virtual void UpdateSelection(); void GetDocProjectName(wxInt32 item, wxString& strBuffer) const; diff --git a/clientgui/WelcomePage.cpp b/clientgui/WelcomePage.cpp index dbdd7a286d..2e8823656f 100644 --- a/clientgui/WelcomePage.cpp +++ b/clientgui/WelcomePage.cpp @@ -521,7 +521,7 @@ void CWelcomePage::OnShow( wxShowEvent& event ) { * event handler for ID_WELCOMEPAGE */ -void CWelcomePage::OpenWCG( wxCommandEvent& event ) { +void CWelcomePage::OpenWCG( wxCommandEvent& /* event */ ) { wxLogTrace(wxT("Function Start/End"), wxT("CWelcomePage::OpenWCG - Function Begin")); wxString wcgUrl("http://www.worldcommunitygrid.org/ms/viewMyProjects.do", wxConvUTF8); wxHyperLink::ExecuteLink(wcgUrl); diff --git a/clientgui/sg_BoincSimpleGUI.cpp b/clientgui/sg_BoincSimpleGUI.cpp index b30f826140..8e472a0368 100644 --- a/clientgui/sg_BoincSimpleGUI.cpp +++ b/clientgui/sg_BoincSimpleGUI.cpp @@ -298,6 +298,16 @@ bool CSimpleFrame::SaveState() { } +int CSimpleFrame::_GetCurrentViewPage() { + if (isMessagesDlgOpen()) { + return VW_SGUI | VW_SMSG; + } else { + return VW_SGUI; + } + return 0; // Should never happen. +} + + void CSimpleFrame::OnHelp(wxHelpEvent& event) { wxLogTrace(wxT("Function Start/End"), wxT("CSimpleFrame::OnHelp - Function Begin")); diff --git a/clientgui/sg_BoincSimpleGUI.h b/clientgui/sg_BoincSimpleGUI.h index 48e49f0e5f..5463f319a0 100644 --- a/clientgui/sg_BoincSimpleGUI.h +++ b/clientgui/sg_BoincSimpleGUI.h @@ -23,6 +23,14 @@ #pragma interface "sg_BoincSimpleGUI.cpp" #endif + +/// +/// Bitmask values for CMainDocument::RunPeriodicRPCs() +/// +#define VW_SGUI 1024 +#define VW_SMSG 2048 + + class CViewTabPage; class StatImageLoader; class ImageLoader; @@ -113,21 +121,22 @@ public: void SetMsgsDlgOpen(CDlgMessages* newDlgPtr) { dlgMsgsPtr = newDlgPtr; } bool isMessagesDlgOpen() { return (dlgMsgsPtr != NULL); } -private: - bool SaveState(); - bool RestoreState(); - CDlgMessages* dlgMsgsPtr; - protected: + virtual int _GetCurrentViewPage(); + + wxAcceleratorEntry m_Shortcuts[1]; + wxAcceleratorTable* m_pAccelTable; + + CSimplePanel* m_pBackgroundPanel; #ifdef __WXMAC__ wxMenuBar* m_pMenubar; #endif - wxAcceleratorEntry m_Shortcuts[1]; - wxAcceleratorTable* m_pAccelTable; - - CSimplePanel* m_pBackgroundPanel; +private: + bool SaveState(); + bool RestoreState(); + CDlgMessages* dlgMsgsPtr; DECLARE_EVENT_TABLE() }; diff --git a/win_build/installerv2/BOINC.ism b/win_build/installerv2/BOINC.ism index f287373631f659e3064d295b00cf1501afbd1914..3ef1f2e0b947824018f418c183413900ab25d6bc 100644 GIT binary patch delta 456 zcmV;(0XP24^9;=M46tkj20%M`Djqqras)=H0|o#Av%9T$0R}cMGcGYXlm2!em+wXa z1+!PLqZ*>h1OsekbeGT^0Ufg%&fpuO>I9SA=^V2b?&Ke)4gmxPAZ=l8bz!y=0s0@N zG64hzWFU8GbZE9V0s0fRN&yOa3Z4xQ2oVSk2<`;86vF{X8v>~bw_e@>qAvzROD0Zb zc(x7#9|0X=Z)t90Up6i?E-^V@cWG{9Z+CNFX>N37Yw*y21{UZZ!bRec^0tA;_ zX9733I&1>QBLiq|X{L|@1ebc00wT91lmgo?188Y;ro;jSw*$xm_8caAF*i3hI5I{x zEjchaLM=2yGes>yG&DCYF+(ylG&4d*IW$BweYgMQ0^|m^>;iZK0VcP3?gEDa9b7_n zX>4R%S7~lDGF(z+Y-M3{Wm9QqZe?U-VrRDS0^mD_V{&v{ml_TO8@CM(17ZQUj1L2>B?ABe0Jl3e1Ca#Wrk8L4 delta 398 zcmV;90dfA!^9;=M46tkj24Jc4yi_%_as)=H0{{R3v%9T$0h9iAAG27ms2T=rWppke zAfn0yliD5|vmwsk8wO%#X>4UiqUr>*2JZSF1|V%=ZgpX%4gmxMY;1X#PzVDUw;>V% z-ya5KAa`kWXr?j&1h)n@0s0dLLrW%3Wq7tq0Sb8vsR<7V5eN+ko(;DY!vRPe0!|LM zUfuzsFSiB`0v`b;doV&VMnyD5LM<~wGczqTHbXfrK{Y}&Ek;E|H8wUyH#tQ{FnzZ| z4+6UgrWgVO18`wuwi*Kc0k#|hq$U9-x1~Y?TLA-dZ*8_j0{tVVXaWS6{$>I?w>NA8 z#v`VX0t5qSZfUlZ0{t(h!~z7Dk<9`Vw-Cqz<{Sn#E;BAMH@6(+0^|mk@B$sS>;iZK z0S32u?gEDaw;k{T;|G=q10AOL0uZ+y2m|8*lg)?^mk$mD4yFnN1h*Xy18)HxVsB|~ sV_!BdGcGYVUw3J4WN&wKUukZ1Wo&pjHn)rq1FR(j9RLBhJ2eB51dyJA;Q#;t diff --git a/win_build/installerv2/BOINCx64.ism b/win_build/installerv2/BOINCx64.ism index 63b1f9c6bbc6f2a745386e9bb523cc5fcc67c105..dc6a62a340d167d200ab75abf40ca8e8e1604b20 100644 GIT binary patch delta 632 zcmXAkOHUI~07iT79ZI2P%F9wH!OHAdN;bD(MfPYNNajG7#EuO2)YqnK%x^33q_3y8y7AdWAZJ|S$vDLv1i%Xv#gz? zsy=+V(!rIp)U{ScyUCO~G*mnoP_zR~X-vmcc10U!lpkxBvL(BTN`=){*Cj6O3vrPn zVXvPJ#k_&2Kj`J+Ju$B@!p6C9ZzvFE*`@O1>z%N4Yt9N>inNRsZGkBjwd&#{O3_xB z(yHbtzSi*-qpT;*W%Jwjj^a1nzcQtt+J2P=6xQkhQ)vXcvH#4kTM%eXmE)lHLhTl^ zni@=XrU*@%pMhfzxKcw-e+0#DtR(=0U)TUmXc~rrV@j4X(|oY2r_0ari&ADrUd-|5 zLqR?mAPZJlFsXJ3K_9+ngKfmv26sTE9X@aY2YDEQ6QE8g2vS;@N{h^_oW*}^&`#=O zaNDWQK?>hL16`yc4Y!=?4M^?d{VY4dPBPO%CL`w=DU-_!>B?=m+g*7M^@z`#uo1s` z2R(SQ4^)%xmvG&we%FsDlF4vtoR1BRL{o|3(ZtZ8)0wFJg1gn~Z&+^{$xU3I)Q9

XnjpS9s;8qFI2CzFdbIt$c#WOQ&R`vX4T zA!aDcxZPu7HYdrM!O{Msy*^*XhIXp(@>LMK>wy+B+>X|2u8^CB7KlP#(k~@s<)F7h)5OXgA6fzhL*vg?N Fe*w){(U$-K delta 491 zcmXAlKWGzi6vy*>@0wgB7J{T+Yn$sOagn5VMGB%r>7Z!9KhR)IC6(4H z4z3O=m-cRP>7fTYgxG`rrc$I1BE`ur4suJEMoOWJgM+`|_W8W`eLVQ?9L0Bz;;n~5 zSL#-6X2P!vuTnl82+*3P?m5k;vmEQxz0v2>I!BkTFE&$QeIz?Fmh*qSz5vz$UAN{E zB;2U1IX-oRh}ER-N5QAfKxw?aO5JaqzXytSK;3*?$e&2uVkkJWgiqP3gb#?FM8)gIFjJDa*X4Z9pyI5(AcmcRIJ@4D ztteB{xJPWh@XjMJC4-mAnLG29+THU1`pZj|+P(Ruh4PcUUe>kAqO+yqDYh_-t5FPv RLhRTC5&@MEaS{dG{0GrOoACeu diff --git a/win_build/sim.vcproj b/win_build/sim.vcproj index d08ea5e231..97475d423e 100644 --- a/win_build/sim.vcproj +++ b/win_build/sim.vcproj @@ -497,6 +497,8 @@ UsePrecompiledHeader="2" PrecompiledHeaderThrough="boinc_win.h" PrecompiledHeaderFile="$(IntDir)\$(TargetName).pch" + ExpandAttributedSource="true" + AssemblerOutput="2" AssemblerListingLocation="" ObjectFile="$(IntDir)\" ProgramDataBaseFileName="$(IntDir)\vc80.pdb"