From 440ae7d73dcc878065e28136f8a512a19f8c2803 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Mon, 18 Aug 2008 22:09:22 +0000 Subject: [PATCH] Additional screensaver bug fix svn path=/trunk/boinc/; revision=15877 --- checkin_notes | 4 +- clientscr/screensaver.cpp | 1096 +++++++++++++++++++------------------ 2 files changed, 554 insertions(+), 546 deletions(-) diff --git a/checkin_notes b/checkin_notes index 555e182b5e..de6194bd9a 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6773,8 +6773,8 @@ Rom 18 Aug 2008 client/ hostinfo_win.C -Rom 18 Aug 2008 - - SCR: Fix my checkin that causes the CPU util to spike on Macs and +Rom & Charlie 18 Aug 2008 + - SCR: Fix 8/14 checkin that causes the CPU util to spike on Macs and possibly Windows. clientscr/ diff --git a/clientscr/screensaver.cpp b/clientscr/screensaver.cpp index 676ffdafcc..8e44f44445 100644 --- a/clientscr/screensaver.cpp +++ b/clientscr/screensaver.cpp @@ -1,544 +1,552 @@ -// 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" - -#include -#include -#include -#include - -#include "boinc_ss.h" - -#endif - -#include "diagnostics.h" -#include "common_defs.h" -#include "util.h" - -#ifdef _WIN32 -#include "gui_rpc_client.h" -#include "screensaver_win.h" -#endif - -#ifdef __APPLE__ -#include -#include -#include "gui_rpc_client.h" -#include "Mac_Saver_Module.h" -#endif -#include "screensaver.h" - -// Flags for testing & debugging -#define SIMULATE_NO_GRAPHICS 0 - - -bool CScreensaver::is_same_task(RESULT* taska, RESULT* taskb) { - if ((taska == NULL) || (taskb == NULL)) return false; - if (taska->name != taskb->name) return false; - if (taska->project_url != taskb->project_url) return false; - return true; -} - -int CScreensaver::count_active_graphic_apps(RESULTS& results, RESULT* exclude) { - unsigned int i = 0; - unsigned int graphics_app_count = 0; - m_bV5_GFX_app_is_running = false; - - // Count the number of active graphics-capable apps excluding the specified result. - // If exclude is NULL, don't exclude any results. - for (i = 0; i < results.results.size(); i++) { - BOINCTRACE(_T("get_random_graphics_app -- active task detected\n")); - BOINCTRACE( - _T("get_random_graphics_app -- name = '%s', path = '%s'\n"), - results.results[i]->name.c_str(), results.results[i]->graphics_exec_path.c_str() - ); - if (results.results[i]->supports_graphics) m_bV5_GFX_app_is_running = true; - if ((results.results[i]->graphics_exec_path.size() == 0) - && (state.executing_as_daemon || !(results.results[i]->supports_graphics))) continue; - BOINCTRACE(_T("get_random_graphics_app -- active task detected w/graphics\n")); - - if (is_same_task(results.results[i], exclude)) continue; - graphics_app_count++; - } - return graphics_app_count; -} - - -// Choose a random graphics application out of the vector. -// Exclude the specified result unless it is the only candidate. -// If exclude is NULL or an empty string, don't exclude any results. -// -RESULT* CScreensaver::get_random_graphics_app(RESULTS& results, RESULT* exclude) { - RESULT* rp = NULL; - unsigned int i = 0; - unsigned int graphics_app_count = 0; - unsigned int random_selection = 0; - unsigned int current_counter = 0; - RESULT *avoid = exclude; - - BOINCTRACE(_T("get_random_graphics_app -- Function Start\n")); - - graphics_app_count = count_active_graphic_apps(results, avoid); - BOINCTRACE(_T("get_random_graphics_app -- graphics_app_count = '%d'\n"), graphics_app_count); - - // If no graphics app found other than the one excluded, count again without excluding any - if ((0 == graphics_app_count) && (avoid != NULL)) { - avoid = NULL; - graphics_app_count = count_active_graphic_apps(results, avoid); - } - - // If no graphics app was found, return NULL - if (0 == graphics_app_count) { - goto CLEANUP; - } - - // Choose which application to display. - random_selection = (rand() % graphics_app_count) + 1; - BOINCTRACE(_T("get_random_graphics_app -- random_selection = '%d'\n"), random_selection); - - // Lets find the chosen graphics application. - for (i = 0; i < results.results.size(); i++) { - if ((results.results[i]->graphics_exec_path.size() == 0) - && (state.executing_as_daemon || !(results.results[i]->supports_graphics))) continue; - if (is_same_task(results.results[i], avoid)) continue; - - current_counter++; - if (current_counter == random_selection) { - rp = results.results[i]; - break; - } - } - -CLEANUP: - BOINCTRACE(_T("get_random_graphics_app -- Function End\n")); - - return rp; -} - - -// Launch the graphics application -// -#ifdef _WIN32 -int CScreensaver::launch_screensaver(RESULT* rp, HANDLE& graphics_application) -#else -int CScreensaver::launch_screensaver(RESULT* rp, int& graphics_application) -#endif -{ - int retval = 0; - if (!rp->graphics_exec_path.empty()) { - // V6 Graphics -#ifdef __APPLE__ - // For sandbox security, use gfx_switcher to launch gfx app - // as user boinc_project and group boinc_project. - // - // For unknown reasons, the graphics application exits with - // "RegisterProcess failed (error = -50)" unless we pass its - // full path twice in the argument list to execv. - char* argv[5]; - argv[0] = "gfx_Switcher"; - argv[1] = "-launch_gfx"; - argv[2] = strrchr(rp->slot_path.c_str(), '/'); - if (*argv[2]) argv[2]++; // Point to the slot number in ascii - - argv[3] = "--fullscreen"; - argv[4] = 0; - - retval = run_program( - rp->slot_path.c_str(), - m_gfx_Switcher_Path, - 4, - argv, - 0, - graphics_application - ); -#else - char* argv[3]; - argv[0] = "app_graphics"; // not used - argv[1] = "--fullscreen"; - argv[2] = 0; - retval = run_program( - rp->slot_path.c_str(), - rp->graphics_exec_path.c_str(), - 2, - argv, - 0, - graphics_application - ); -#endif - } else { - // V5 and Older - DISPLAY_INFO di; -#ifdef _WIN32 - graphics_application = NULL; - - memset(di.window_station, 0, sizeof(di.window_station)); - memset(di.desktop, 0, sizeof(di.desktop)); - memset(di.display, 0, sizeof(di.display)); - - if (!m_bIs9x) { - // Retrieve the current window station and desktop names - GetUserObjectInformation( - GetProcessWindowStation(), - UOI_NAME, - di.window_station, - (sizeof(di.window_station)), - NULL - ); - GetUserObjectInformation( - GetThreadDesktop(GetCurrentThreadId()), - UOI_NAME, - di.desktop, - sizeof(di.desktop), - NULL - ); - } -#else - char *p = getenv("DISPLAY"); - if (p) strcpy(di.display, p); - - graphics_application = 0; -#endif - retval = rpc->show_graphics( - rp->project_url.c_str(), - rp->name.c_str(), - MODE_FULLSCREEN, - di - ); - } - return retval; -} - - -// Terminate the graphics application -// -#ifdef _WIN32 -int CScreensaver::terminate_screensaver(HANDLE& graphics_application, RESULT *worker_app) -#else -int CScreensaver::terminate_screensaver(int& graphics_application, RESULT *worker_app) -#endif -{ - if (graphics_application) { - // V6 Graphics - kill_program(graphics_application); -#ifdef __APPLE__ - // For sandbox security, use gfx_switcher to launch gfx app - // as user boinc_project and group boinc_project. - int retval = 0; - char current_dir[MAXPATHLEN]; - char gfx_pid[16]; - pid_t thePID; - int i; - - sprintf(gfx_pid, "%d", graphics_application); - getcwd( current_dir, sizeof(current_dir)); - - char* argv[4]; - argv[0] = "gfx_switcher"; - argv[1] = "-kill_gfx"; - argv[2] = gfx_pid; - argv[3] = 0; - - retval = run_program( - current_dir, - m_gfx_Switcher_Path, - 3, - argv, - 0, - thePID - ); - if (retval) return retval; - - for (i=0; i<200; i++) { - boinc_sleep(0.01); // Wait 2 seconds max - // Prevent gfx_switcher from becoming a zombie - if (waitpid(thePID, 0, WNOHANG) == thePID) break; - } - return retval; -#endif - graphics_application = 0; - } else { - // V5 and Older - DISPLAY_INFO di; - - if (worker_app == NULL) return 0; - if (worker_app->name.empty()) return 0; - - memset(di.window_station, 0, sizeof(di.window_station)); - memset(di.desktop, 0, sizeof(di.desktop)); - memset(di.display, 0, sizeof(di.display)); - - rpc->show_graphics( - worker_app->project_url.c_str(), - worker_app->name.c_str(), - MODE_HIDE_GRAPHICS, - di - ); - } - return 0; -} - - -#ifdef _WIN32 -DWORD WINAPI CScreensaver::DataManagementProc() { -#else -void *CScreensaver::DataManagementProc() { -#endif - int retval = 0; - int suspend_reason = 0; - RESULT* theResult = NULL; - RESULT* graphics_app_result_ptr = NULL; - RESULT previous_result; - RESULT* previous_result_ptr = NULL; - int iResultCount = 0; - int iIndex = 0; - double launch_time = 0.0; - double last_change_time = 0.0; - double last_run_check_time = 0.0; - time_t long_poll_timer = 0; - -#ifdef _WIN32 - BOINCTRACE(_T("CScreensaver::DataManagementProc - Display screen saver loading message\n")); - SetError(TRUE, SCRAPPERR_BOINCSCREENSAVERLOADING); - m_tThreadCreateTime = time(0); - - // Set the starting point for iterating through the results - m_iLastResultShown = 0; - m_tLastResultChangeTime = 0; -#endif - - while (true) { - - // *** - // *** Things that should be run frequently. - // *** 4 times per second. - // *** - - // Are we supposed to exit the screensaver? - if (m_QuitDataManagementProc) { // If main thread has requested we exit - if (m_hGraphicsApplication || graphics_app_result_ptr) { - terminate_screensaver(m_hGraphicsApplication, graphics_app_result_ptr); - graphics_app_result_ptr = NULL; - previous_result_ptr = NULL; - m_hGraphicsApplication = 0; - } - return 0; // Exit the thread - } - -#ifdef _WIN32 - - // Check for keyboard and mouse activity just in case the - // user wants to blow out of the screensaver. - // - CheckKeyboardMouseActivity(); - - // Check to see if there are any notification windows from - // personal firewalls, virus scanners, or anything else that - // demands the users attention. If there is blow out of the - // screensaver - CheckForNotificationWindow(); - -#endif - - - // *** - // *** Things that should be run frequently. - // *** 1 time per second. - // *** - - if (time(0) > long_poll_timer) { - long_poll_timer = time(0); - - // Blank screen saver? - if ((m_dwBlankScreen) && (time(0) > m_dwBlankTime)) { - BOINCTRACE(_T("CScreensaver::DataManagementProc - Time to blank\n")); - SetError(FALSE, SCRAPPERR_SCREENSAVERBLANKED); - m_QuitDataManagementProc = true; - } - - // Do we need to get the core client state? - if (m_bResetCoreState) { - // Try and get the current state of the CC - retval = rpc->get_state(state); - if (retval) { - // CC may not yet be running - HandleRPCError(); - continue; - } - - m_bResetCoreState = false; - } - - BOINCTRACE(_T("CScreensaver::DataManagementProc - ErrorMode = '%d', ErrorCode = '%x'\n"), m_bErrorMode, m_hrError); - - // Update our task list - m_updating_results = true; - retval = rpc->get_screensaver_tasks(suspend_reason, results); - m_updating_results = false; - if (retval) { - // rpc call returned error - HandleRPCError(); - m_bResetCoreState = true; - continue; - } - - // Core client suspended? - if (suspend_reason && !(suspend_reason & SUSPEND_REASON_CPU_USAGE_LIMIT)) { - SetError(TRUE, SCRAPPERR_BOINCSUSPENDED); - if (m_hGraphicsApplication || previous_result_ptr) { - // use previous_result_ptr because graphics_app_result_ptr may no longer be valid - terminate_screensaver(m_hGraphicsApplication, previous_result_ptr); - if (m_hGraphicsApplication == 0) { - graphics_app_result_ptr = NULL; - } else { - // waitpid test will clear m_hGraphicsApplication and graphics_app_result_ptr - } - previous_result_ptr = NULL; - } - continue; - } - -#if SIMULATE_NO_GRAPHICS /* FOR TESTING */ - - SetError(TRUE, SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING); - -#else /* NORMAL OPERATION */ - - // Is the current graphics app's associated task still running? - if ((m_hGraphicsApplication) || (graphics_app_result_ptr)) { - - iResultCount = results.results.size(); - graphics_app_result_ptr = NULL; - - // Find the current task in the new results vector (if it still exists) - for (iIndex = 0; iIndex < iResultCount; iIndex++) { - theResult = results.results.at(iIndex); - - if (is_same_task(theResult, previous_result_ptr)) { - graphics_app_result_ptr = theResult; - previous_result = *theResult; - previous_result_ptr = &previous_result; - break; - } - } - - // V6 graphics only: if worker application has stopped running, terminate_screensaver - if ((graphics_app_result_ptr == NULL) && (m_hGraphicsApplication != 0)) { - if (previous_result_ptr) { - BOINCTRACE(_T("CScreensaver::DataManagementProc - %s finished\n"), previous_result.name.c_str()); - } - terminate_screensaver(m_hGraphicsApplication, previous_result_ptr); - previous_result_ptr = NULL; - // waitpid test will clear m_hGraphicsApplication - } - - if (last_change_time && ((dtime() - last_change_time) > GFX_CHANGE_PERIOD)) { - if (count_active_graphic_apps(results, previous_result_ptr) > 0) { - if (previous_result_ptr) { - BOINCTRACE(_T("CScreensaver::DataManagementProc - time to change: %s\n"), previous_result.name.c_str()); - } - terminate_screensaver(m_hGraphicsApplication, graphics_app_result_ptr); - if (m_hGraphicsApplication == 0) { - graphics_app_result_ptr = NULL; - // Save previous_result and previous_result_ptr for get_random_graphics_app() call - } else { - // waitpid test will clear m_hGraphicsApplication and graphics_app_result_ptr - } - } - last_change_time = dtime(); - } - } - - // If no current graphics app, pick an active task at random and launch its graphics app - if ((m_hGraphicsApplication == 0) && (graphics_app_result_ptr == NULL)) { - graphics_app_result_ptr = get_random_graphics_app(results, previous_result_ptr); - previous_result_ptr = NULL; - - if (graphics_app_result_ptr) { - retval = launch_screensaver(graphics_app_result_ptr, m_hGraphicsApplication); - if (retval) { - m_hGraphicsApplication = 0; - previous_result_ptr = NULL; - graphics_app_result_ptr = NULL; - } else { -#ifdef __APPLE__ - SetError(FALSE, SCRAPPERR_BOINCAPPFOUNDGRAPHICSLOADING); -#endif - SetError(FALSE, SCRAPPERR_SCREENSAVERRUNNING); - launch_time = dtime(); - last_change_time = launch_time; - last_run_check_time = launch_time; - // Make a local copy of current result, since original pointer - // may have been freed by the time we perform later tests - previous_result = *graphics_app_result_ptr; - previous_result_ptr = &previous_result; - if (previous_result_ptr) { - BOINCTRACE(_T("CScreensaver::DataManagementProc - launching %s\n"), previous_result.name.c_str()); - } - } - } else { - if (state.projects.size() == 0) { - // We are not attached to any projects - SetError(TRUE, SCRAPPERR_BOINCNOPROJECTSDETECTED); - } else if (results.results.size() == 0) { - // We currently do not have any applications to run - SetError(TRUE, SCRAPPERR_BOINCNOAPPSEXECUTING); - } else { - // We currently do not have any graphics capable application - SetError(TRUE, m_bV5_GFX_app_is_running ? - SCRAPPERR_DAEMONALLOWSNOGRAPHICS : SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING - ); - } - } - } else { // End if ((m_hGraphicsApplication == 0) && (graphics_app_result_ptr == NULL)) - - // Is the graphics app still running? - if (m_hGraphicsApplication) { -#ifdef _WIN32 - DWORD dwStatus = STILL_ACTIVE; - BOOL bRetVal = FALSE; - bRetVal = GetExitCodeProcess(m_hGraphicsApplication, &dwStatus); - BOINCTRACE(_T("CScreensaver::DataManagementProc - GetExitCodeProcess RetVal = '%d', Status = '%d'\n"), bRetVal, dwStatus); - if (bRetVal && (dwStatus != STILL_ACTIVE)) { - // Something has happened to the previously selected screensaver - // application. Start a different one. - m_hGraphicsApplication = 0; - graphics_app_result_ptr = NULL; - continue; - } else { - CheckForegroundWindow(); - } -#else - if (waitpid(m_hGraphicsApplication, 0, WNOHANG) == m_hGraphicsApplication) { - m_hGraphicsApplication = 0; - graphics_app_result_ptr = NULL; - continue; - } -#endif - } - } -#endif // ! SIMULATE_NO_GRAPHICS - } - - // Only loop through the data management proc 4 times a second. - // - boinc_sleep(0.25); - - } // end while(true) -} +// Berkeley Open Infrastructure for Network Computing +// http://boinc.berkeley.edu +// Copyright (C) 2005 University of California +// +// This 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 2.1 of the License, or (at your option) any later version. +// +// This software 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. +// +// To view the GNU Lesser General Public License visit +// http://www.gnu.org/copyleft/lesser.html +// or write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +#ifdef _WIN32 +#include "boinc_win.h" + +#include +#include +#include +#include + +#include "boinc_ss.h" + +#endif + +#include "diagnostics.h" +#include "common_defs.h" +#include "util.h" + +#ifdef _WIN32 +#include "gui_rpc_client.h" +#include "screensaver_win.h" +#endif + +#ifdef __APPLE__ +#include +#include +#include "gui_rpc_client.h" +#include "Mac_Saver_Module.h" +#endif +#include "screensaver.h" + +// Flags for testing & debugging +#define SIMULATE_NO_GRAPHICS 0 + + +bool CScreensaver::is_same_task(RESULT* taska, RESULT* taskb) { + if ((taska == NULL) || (taskb == NULL)) return false; + if (taska->name != taskb->name) return false; + if (taska->project_url != taskb->project_url) return false; + return true; +} + +int CScreensaver::count_active_graphic_apps(RESULTS& results, RESULT* exclude) { + unsigned int i = 0; + unsigned int graphics_app_count = 0; + m_bV5_GFX_app_is_running = false; + + // Count the number of active graphics-capable apps excluding the specified result. + // If exclude is NULL, don't exclude any results. + for (i = 0; i < results.results.size(); i++) { + BOINCTRACE(_T("get_random_graphics_app -- active task detected\n")); + BOINCTRACE( + _T("get_random_graphics_app -- name = '%s', path = '%s'\n"), + results.results[i]->name.c_str(), results.results[i]->graphics_exec_path.c_str() + ); + if (results.results[i]->supports_graphics) m_bV5_GFX_app_is_running = true; + if ((results.results[i]->graphics_exec_path.size() == 0) + && (state.executing_as_daemon || !(results.results[i]->supports_graphics))) continue; + BOINCTRACE(_T("get_random_graphics_app -- active task detected w/graphics\n")); + + if (is_same_task(results.results[i], exclude)) continue; + graphics_app_count++; + } + return graphics_app_count; +} + + +// Choose a random graphics application out of the vector. +// Exclude the specified result unless it is the only candidate. +// If exclude is NULL or an empty string, don't exclude any results. +// +RESULT* CScreensaver::get_random_graphics_app(RESULTS& results, RESULT* exclude) { + RESULT* rp = NULL; + unsigned int i = 0; + unsigned int graphics_app_count = 0; + unsigned int random_selection = 0; + unsigned int current_counter = 0; + RESULT *avoid = exclude; + + BOINCTRACE(_T("get_random_graphics_app -- Function Start\n")); + + graphics_app_count = count_active_graphic_apps(results, avoid); + BOINCTRACE(_T("get_random_graphics_app -- graphics_app_count = '%d'\n"), graphics_app_count); + + // If no graphics app found other than the one excluded, count again without excluding any + if ((0 == graphics_app_count) && (avoid != NULL)) { + avoid = NULL; + graphics_app_count = count_active_graphic_apps(results, avoid); + } + + // If no graphics app was found, return NULL + if (0 == graphics_app_count) { + goto CLEANUP; + } + + // Choose which application to display. + random_selection = (rand() % graphics_app_count) + 1; + BOINCTRACE(_T("get_random_graphics_app -- random_selection = '%d'\n"), random_selection); + + // Lets find the chosen graphics application. + for (i = 0; i < results.results.size(); i++) { + if ((results.results[i]->graphics_exec_path.size() == 0) + && (state.executing_as_daemon || !(results.results[i]->supports_graphics))) continue; + if (is_same_task(results.results[i], avoid)) continue; + + current_counter++; + if (current_counter == random_selection) { + rp = results.results[i]; + break; + } + } + +CLEANUP: + BOINCTRACE(_T("get_random_graphics_app -- Function End\n")); + + return rp; +} + + +// Launch the graphics application +// +#ifdef _WIN32 +int CScreensaver::launch_screensaver(RESULT* rp, HANDLE& graphics_application) +#else +int CScreensaver::launch_screensaver(RESULT* rp, int& graphics_application) +#endif +{ + int retval = 0; + if (!rp->graphics_exec_path.empty()) { + // V6 Graphics +#ifdef __APPLE__ + // For sandbox security, use gfx_switcher to launch gfx app + // as user boinc_project and group boinc_project. + // + // For unknown reasons, the graphics application exits with + // "RegisterProcess failed (error = -50)" unless we pass its + // full path twice in the argument list to execv. + char* argv[5]; + argv[0] = "gfx_Switcher"; + argv[1] = "-launch_gfx"; + argv[2] = strrchr(rp->slot_path.c_str(), '/'); + if (*argv[2]) argv[2]++; // Point to the slot number in ascii + + argv[3] = "--fullscreen"; + argv[4] = 0; + + retval = run_program( + rp->slot_path.c_str(), + m_gfx_Switcher_Path, + 4, + argv, + 0, + graphics_application + ); +#else + char* argv[3]; + argv[0] = "app_graphics"; // not used + argv[1] = "--fullscreen"; + argv[2] = 0; + retval = run_program( + rp->slot_path.c_str(), + rp->graphics_exec_path.c_str(), + 2, + argv, + 0, + graphics_application + ); +#endif + } else { + // V5 and Older + DISPLAY_INFO di; +#ifdef _WIN32 + graphics_application = NULL; + + memset(di.window_station, 0, sizeof(di.window_station)); + memset(di.desktop, 0, sizeof(di.desktop)); + memset(di.display, 0, sizeof(di.display)); + + if (!m_bIs9x) { + // Retrieve the current window station and desktop names + GetUserObjectInformation( + GetProcessWindowStation(), + UOI_NAME, + di.window_station, + (sizeof(di.window_station)), + NULL + ); + GetUserObjectInformation( + GetThreadDesktop(GetCurrentThreadId()), + UOI_NAME, + di.desktop, + sizeof(di.desktop), + NULL + ); + } +#else + char *p = getenv("DISPLAY"); + if (p) strcpy(di.display, p); + + graphics_application = 0; +#endif + retval = rpc->show_graphics( + rp->project_url.c_str(), + rp->name.c_str(), + MODE_FULLSCREEN, + di + ); + } + return retval; +} + + +// Terminate the graphics application +// +#ifdef _WIN32 +int CScreensaver::terminate_screensaver(HANDLE& graphics_application, RESULT *worker_app) +#else +int CScreensaver::terminate_screensaver(int& graphics_application, RESULT *worker_app) +#endif +{ + if (graphics_application) { + // V6 Graphics + kill_program(graphics_application); +#ifdef __APPLE__ + // For sandbox security, use gfx_switcher to launch gfx app + // as user boinc_project and group boinc_project. + int retval = 0; + char current_dir[MAXPATHLEN]; + char gfx_pid[16]; + pid_t thePID; + int i; + + sprintf(gfx_pid, "%d", graphics_application); + getcwd( current_dir, sizeof(current_dir)); + + char* argv[4]; + argv[0] = "gfx_switcher"; + argv[1] = "-kill_gfx"; + argv[2] = gfx_pid; + argv[3] = 0; + + retval = run_program( + current_dir, + m_gfx_Switcher_Path, + 3, + argv, + 0, + thePID + ); + if (retval) return retval; + + for (i=0; i<200; i++) { + boinc_sleep(0.01); // Wait 2 seconds max + // Prevent gfx_switcher from becoming a zombie + if (waitpid(thePID, 0, WNOHANG) == thePID) break; + } + return retval; +#endif + graphics_application = 0; + } else { + // V5 and Older + DISPLAY_INFO di; + + if (worker_app == NULL) return 0; + if (worker_app->name.empty()) return 0; + + memset(di.window_station, 0, sizeof(di.window_station)); + memset(di.desktop, 0, sizeof(di.desktop)); + memset(di.display, 0, sizeof(di.display)); + + rpc->show_graphics( + worker_app->project_url.c_str(), + worker_app->name.c_str(), + MODE_HIDE_GRAPHICS, + di + ); + } + return 0; +} + + +#ifdef _WIN32 +DWORD WINAPI CScreensaver::DataManagementProc() { +#else +void *CScreensaver::DataManagementProc() { +#endif + int retval = 0; + int suspend_reason = 0; + RESULT* theResult = NULL; + RESULT* graphics_app_result_ptr = NULL; + RESULT previous_result; + RESULT* previous_result_ptr = NULL; + int iResultCount = 0; + int iIndex = 0; + double launch_time = 0.0; + double last_change_time = 0.0; + double last_run_check_time = 0.0; + +#ifdef _WIN32 + BOINCTRACE(_T("CScreensaver::DataManagementProc - Display screen saver loading message\n")); + SetError(TRUE, SCRAPPERR_BOINCSCREENSAVERLOADING); + m_tThreadCreateTime = time(0); + + // Set the starting point for iterating through the results + m_iLastResultShown = 0; + m_tLastResultChangeTime = 0; +#endif + + while (true) { + for (int i = 0; i < 4; i++) { + // *** + // *** Things that should be run frequently. + // *** 4 times per second. + // *** + + // Are we supposed to exit the screensaver? + if (m_QuitDataManagementProc) { // If main thread has requested we exit + if (m_hGraphicsApplication || graphics_app_result_ptr) { + terminate_screensaver(m_hGraphicsApplication, graphics_app_result_ptr); + graphics_app_result_ptr = NULL; + previous_result_ptr = NULL; + m_hGraphicsApplication = 0; + } + return 0; // Exit the thread + } + +#ifdef _WIN32 + + // Check for keyboard and mouse activity just in case the + // user wants to blow out of the screensaver. + // + CheckKeyboardMouseActivity(); + + // Check to see if there are any notification windows from + // personal firewalls, virus scanners, or anything else that + // demands the users attention. If there is blow out of the + // screensaver + CheckForNotificationWindow(); + +#endif + + boinc_sleep(0.25); + } + + // *** + // *** Things that should be run frequently. + // *** 1 time per second. + // *** + + // Blank screen saver? + if ((m_dwBlankScreen) && (time(0) > m_dwBlankTime)) { + BOINCTRACE(_T("CScreensaver::DataManagementProc - Time to blank\n")); + SetError(FALSE, SCRAPPERR_SCREENSAVERBLANKED); + m_QuitDataManagementProc = true; + } + + // Do we need to get the core client state? + if (m_bResetCoreState) { + // Try and get the current state of the CC + retval = rpc->get_state(state); + if (retval) { + // CC may not yet be running + HandleRPCError(); + continue; + } + + m_bResetCoreState = false; + } + + BOINCTRACE(_T("CScreensaver::DataManagementProc - ErrorMode = '%d', ErrorCode = '%x'\n"), m_bErrorMode, m_hrError); + + // Update our task list + m_updating_results = true; + retval = rpc->get_screensaver_tasks(suspend_reason, results); + m_updating_results = false; + if (retval) { + // rpc call returned error + HandleRPCError(); + m_bResetCoreState = true; + continue; + } + + // Core client suspended? + if (suspend_reason && !(suspend_reason & SUSPEND_REASON_CPU_USAGE_LIMIT)) { + SetError(TRUE, SCRAPPERR_BOINCSUSPENDED); + if (m_hGraphicsApplication || previous_result_ptr) { + // use previous_result_ptr because graphics_app_result_ptr may no longer be valid + terminate_screensaver(m_hGraphicsApplication, previous_result_ptr); + if (m_hGraphicsApplication == 0) { + graphics_app_result_ptr = NULL; + } else { + // waitpid test will clear m_hGraphicsApplication and graphics_app_result_ptr + } + previous_result_ptr = NULL; + } + continue; + } + +#if SIMULATE_NO_GRAPHICS /* FOR TESTING */ + + SetError(TRUE, SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING); + +#else /* NORMAL OPERATION */ + + // Is the current graphics app's associated task still running? + if ((m_hGraphicsApplication) || (graphics_app_result_ptr)) { + + iResultCount = results.results.size(); + graphics_app_result_ptr = NULL; + + // Find the current task in the new results vector (if it still exists) + for (iIndex = 0; iIndex < iResultCount; iIndex++) { + theResult = results.results.at(iIndex); + + if (is_same_task(theResult, previous_result_ptr)) { + graphics_app_result_ptr = theResult; + previous_result = *theResult; + previous_result_ptr = &previous_result; + break; + } + } + + // V6 graphics only: if worker application has stopped running, terminate_screensaver + if ((graphics_app_result_ptr == NULL) && (m_hGraphicsApplication != 0)) { + if (previous_result_ptr) { + BOINCTRACE(_T("CScreensaver::DataManagementProc - %s finished\n"), previous_result.name.c_str()); + } + terminate_screensaver(m_hGraphicsApplication, previous_result_ptr); + previous_result_ptr = NULL; + // waitpid test will clear m_hGraphicsApplication + } +#if 0 + // Safety check that task is actually running + if (last_run_check_time && ((dtime() - last_run_check_time) > TASK_RUN_CHECK_PERIOD)) { + if (FindProcessPID(NULL, ? ? ?) == 0) { + terminate_screensaver(m_hGraphicsApplication, graphics_app_result_ptr); + if (m_hGraphicsApplication == 0) { + graphics_app_result_ptr = NULL; + // Save previous_result and previous_result_ptr for get_random_graphics_app() call + } else { + // waitpid test will clear m_hGraphicsApplication and graphics_app_result_ptr + } + previous_result_ptr = NULL; + } + } +#endif + if (last_change_time && ((dtime() - last_change_time) > GFX_CHANGE_PERIOD)) { + if (count_active_graphic_apps(results, previous_result_ptr) > 0) { + if (previous_result_ptr) { + BOINCTRACE(_T("CScreensaver::DataManagementProc - time to change: %s\n"), previous_result.name.c_str()); + } + terminate_screensaver(m_hGraphicsApplication, graphics_app_result_ptr); + if (m_hGraphicsApplication == 0) { + graphics_app_result_ptr = NULL; + // Save previous_result and previous_result_ptr for get_random_graphics_app() call + } else { + // waitpid test will clear m_hGraphicsApplication and graphics_app_result_ptr + } + } + last_change_time = dtime(); + } + } + + // If no current graphics app, pick an active task at random and launch its graphics app + if ((m_hGraphicsApplication == 0) && (graphics_app_result_ptr == NULL)) { + graphics_app_result_ptr = get_random_graphics_app(results, previous_result_ptr); + previous_result_ptr = NULL; + + if (graphics_app_result_ptr) { + retval = launch_screensaver(graphics_app_result_ptr, m_hGraphicsApplication); + if (retval) { + m_hGraphicsApplication = 0; + previous_result_ptr = NULL; + graphics_app_result_ptr = NULL; + } else { +#ifdef __APPLE__ + SetError(FALSE, SCRAPPERR_BOINCAPPFOUNDGRAPHICSLOADING); +#endif + SetError(FALSE, SCRAPPERR_SCREENSAVERRUNNING); + launch_time = dtime(); + last_change_time = launch_time; + last_run_check_time = launch_time; + // Make a local copy of current result, since original pointer + // may have been freed by the time we perform later tests + previous_result = *graphics_app_result_ptr; + previous_result_ptr = &previous_result; + if (previous_result_ptr) { + BOINCTRACE(_T("CScreensaver::DataManagementProc - launching %s\n"), previous_result.name.c_str()); + } + } + } else { + if (state.projects.size() == 0) { + // We are not attached to any projects + SetError(TRUE, SCRAPPERR_BOINCNOPROJECTSDETECTED); + } else if (results.results.size() == 0) { + // We currently do not have any applications to run + SetError(TRUE, SCRAPPERR_BOINCNOAPPSEXECUTING); + } else { + // We currently do not have any graphics capable application + SetError(TRUE, m_bV5_GFX_app_is_running ? + SCRAPPERR_DAEMONALLOWSNOGRAPHICS : SCRAPPERR_BOINCNOGRAPHICSAPPSEXECUTING + ); + } + } + } else { // End if ((m_hGraphicsApplication == 0) && (graphics_app_result_ptr == NULL)) + + // Is the graphics app still running? + if (m_hGraphicsApplication) { +#ifdef _WIN32 + DWORD dwStatus = STILL_ACTIVE; + BOOL bRetVal = FALSE; + bRetVal = GetExitCodeProcess(m_hGraphicsApplication, &dwStatus); + BOINCTRACE(_T("CScreensaver::DataManagementProc - GetExitCodeProcess RetVal = '%d', Status = '%d'\n"), bRetVal, dwStatus); + if (bRetVal && (dwStatus != STILL_ACTIVE)) { + // Something has happened to the previously selected screensaver + // application. Start a different one. + m_hGraphicsApplication = 0; + graphics_app_result_ptr = NULL; + continue; + } else { + CheckForegroundWindow(); + } +#else + if (waitpid(m_hGraphicsApplication, 0, WNOHANG) == m_hGraphicsApplication) { + m_hGraphicsApplication = 0; + graphics_app_result_ptr = NULL; + continue; + } +#endif + } + } +#endif // ! SIMULATE_NO_GRAPHICS + } // end while(true) +}