// 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., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // graphics-related interaction with running apps #include "cpp.h" #ifdef _WIN32 #include "boinc_win.h" #else #include "config.h" #endif #include "diagnostics.h" #include "client_state.h" #include "client_msgs.h" #include "app.h" #include "util.h" void ACTIVE_TASK::request_graphics_mode(GRAPHICS_MSG& m) { char buf[MSG_CHANNEL_SIZE], buf2[256]; if (!app_client_shm.shm) return; graphics_msg = m; // save graphics_station, desktop, display strcpy(buf, xml_graphics_modes[m.mode]); if (strlen(m.window_station)) { sprintf(buf2, "%s", m.window_station); strcat(buf, buf2); } if (strlen(m.desktop)) { sprintf(buf2, "%s", m.desktop); strcat(buf, buf2); } if (strlen(m.display)) { sprintf(buf2, "%s", m.display); strcat(buf, buf2); } if (log_flags.scrsave_debug) { msg_printf(0, MSG_INFO, "[scrsave_debug] ACTIVE_TASK::request_graphics_mode(): requesting graphics mode %s for %s", xml_graphics_modes[m.mode], result->name ); } graphics_request_queue.msg_queue_send( buf, app_client_shm.shm->graphics_request ); } // handle messages on the "graphics_reply" channel // void ACTIVE_TASK::check_graphics_mode_ack() { GRAPHICS_MSG gm; char buf[MSG_CHANNEL_SIZE]; #if (defined(__APPLE__) && defined(__i386__)) // PowerPC apps emulated on i386 Macs crash if running graphics if (powerpc_emulated_on_i386) { graphics_mode_acked = MODE_UNSUPPORTED; return; } #endif if (!app_client_shm.shm) return; if (app_client_shm.shm->graphics_reply.get_msg(buf)) { app_client_shm.decode_graphics_msg(buf, gm); if (log_flags.scrsave_debug) { msg_printf(0, MSG_INFO, "[scrsave_debug] ACTIVE_TASK::check_graphics_mode_ack(): got graphics ack %s for %s, previous mode %s", buf, result->name, xml_graphics_modes[graphics_mode_acked] ); } // if we receive MODE_HIDE_GRAPHICS from an application acting as the // screensaver it can be for one of two reasons: // 1) application shut down because it was done processing. // 2) user input was detected. // // in the first case we should choose another application to be // screensaver in the SS_LOGIC::poll function. // In the second condition // we should inform the various screensaver components to shutdown. // if (is_ss_app && (graphics_mode_acked == MODE_FULLSCREEN) && (gm.mode != MODE_FULLSCREEN) && (gm.mode != MODE_REREAD_PREFS) && !gstate.host_info.users_idle(true, 0.5) ) { gstate.ss_logic.stop_ss(); if (log_flags.scrsave_debug) { msg_printf(0, MSG_INFO, "[scrsave_debug] ACTIVE_TASK::check_graphics_mode_ack(): shutting down the screensaver" ); } } if (gm.mode != MODE_REREAD_PREFS) { graphics_mode_acked = gm.mode; } } } // return the active task that's currently acting as screensaver // ACTIVE_TASK* ACTIVE_TASK_SET::get_ss_app() { unsigned int i; for (i=0; iis_ss_app) { return atp; } } return NULL; } // remember graphics state of apps. // Called when entering screensaver mode, // so that we can return to same state later // void ACTIVE_TASK_SET::save_app_modes() { unsigned int i; ACTIVE_TASK* atp; for (i=0; igraphics_mode_acked == MODE_FULLSCREEN) { atp->graphics_mode_acked = MODE_HIDE_GRAPHICS; } atp->graphics_mode_before_ss = atp->graphics_mode_acked; if (log_flags.scrsave_debug) { msg_printf(0, MSG_INFO, "[scrsave_debug] ACTIVE_TASK_SET::save_app_modes(): saved mode %d", atp->graphics_mode_acked ); } } } void ACTIVE_TASK_SET::hide_apps() { unsigned int i; ACTIVE_TASK* atp; for (i=0; igraphics_msg.mode = MODE_HIDE_GRAPHICS; atp->request_graphics_mode(atp->graphics_msg); } } // return apps to the mode they were in before screensaving started // void ACTIVE_TASK_SET::restore_apps() { unsigned int i; ACTIVE_TASK* atp; for (i=0; igraphics_mode_before_ss == MODE_WINDOW) { atp->graphics_msg.mode = MODE_WINDOW; atp->request_graphics_mode(atp->graphics_msg); } } } void ACTIVE_TASK_SET::graphics_poll() { unsigned int i; ACTIVE_TASK* atp; for (i=0; iprocess_exists()) continue; atp->graphics_request_queue.msg_queue_poll( atp->app_client_shm.shm->graphics_request ); atp->check_graphics_mode_ack(); // If screensaver application has not responded to our request to exit // MODE_FULLSCREEN after 2 seconds, // then assume it has hung and kill it, // so it doesn't block access to the computer. // First try an exit request. // If it has not exit after 2 more seconds, kill it. // if (atp->graphics_mode_ack_timeout) { if (log_flags.scrsave_debug) { msg_printf(NULL, MSG_INFO, "ack_timeout %f is_ss_app %d acked %d", gstate.now-atp->graphics_mode_acked, atp->is_ss_app, atp->graphics_mode_acked ); } if (atp->is_ss_app || (atp->graphics_mode_acked != MODE_FULLSCREEN)) { atp->exit_requested = false; atp->graphics_mode_ack_timeout = 0.0; } } if (atp->graphics_mode_ack_timeout) { if (gstate.now > atp->graphics_mode_ack_timeout + 3.0) { if (atp->has_task_exited()) { atp->exit_requested = false; atp->graphics_mode_ack_timeout = 0.0; } else { if (!atp->exit_requested) { atp->exit_requested = true; atp->request_exit(); // Wait 2 more seconds for app to exit // atp->graphics_mode_ack_timeout = gstate.now; msg_printf(atp->wup->project, MSG_INTERNAL_ERROR, "%s not responding to screensaver, requesting exit", atp->app_version->app_name ); } else { atp->exit_requested = false; atp->graphics_mode_ack_timeout = 0.0; msg_printf(atp->wup->project, MSG_INTERNAL_ERROR, "%s not responding to screensaver, killing it", atp->app_version->app_name ); atp->kill_task(true); } } } } } } bool ACTIVE_TASK::supports_graphics() { #if (defined(__APPLE__) && defined(__i386__)) // PowerPC apps emulated on i386 Macs crash if running graphics if (powerpc_emulated_on_i386) return false; #endif if (graphics_mode_acked == MODE_UNSUPPORTED) return false; if (scheduler_state != CPU_SCHED_SCHEDULED) return false; return true; } // Return the next graphics-capable running app. // Always try to choose a new project. // Preferences goes to apps with pre-ss mode WINDOW, // then apps with pre-ss mode HIDE // ACTIVE_TASK* CLIENT_STATE::get_next_graphics_capable_app() { static int project_index=0; unsigned int i, j; ACTIVE_TASK *atp, *best_atp; PROJECT *p; // check to see if the applications have changed the graphics mode; // this can happen if they fail to find the target desktop // for (i=0; icheck_graphics_mode_ack(); } // loop through all projects starting with the one at project_index // for (i=0; ischeduler_state != CPU_SCHED_SCHEDULED) continue; // don't choose an application that doesn't support graphics if (atp->graphics_mode_acked == MODE_UNSUPPORTED) continue; // don't choose an application that hasn't ack'ed the // hide graphics request if (atp->graphics_mode_acked != MODE_HIDE_GRAPHICS) continue; if (atp->result->project != p) continue; if (!best_atp && atp->graphics_mode_before_ss == MODE_WINDOW) { best_atp = atp; } if (!best_atp && atp->graphics_mode_before_ss == MODE_HIDE_GRAPHICS) { best_atp = atp; } if (!best_atp) { best_atp = atp; } if (best_atp) { if (log_flags.scrsave_debug) { msg_printf(0, MSG_INFO, "[scrsave_debug] CLIENT_STATE::get_next_graphics_capable_app(): get_next_app: %s", best_atp->result->name ); } return atp; } } } if (log_flags.scrsave_debug) { msg_printf(0, MSG_INFO, "[scrsave_debug] CLIENT_STATE::get_next_graphics_capable_app(): get_next_app: none" ); } return NULL; } const char *BOINC_RCSID_71e9cd9f4d = "$Id$";