diff --git a/api/boinc_api.C b/api/boinc_api.C index 2db8ec26c6..c2bda1672c 100644 --- a/api/boinc_api.C +++ b/api/boinc_api.C @@ -154,8 +154,7 @@ struct UPLOAD_FILE_STATUS { static bool have_new_upload_file; static std::vector upload_file_status; -static char graphics_app_path[1024]; -static void control_graphics_app(char* path, bool start, bool fullscreen); +void graphics_cleanup(); static int setup_shared_mem() { if (standalone) { @@ -431,9 +430,8 @@ int boinc_finish(int status) { // This is called from the worker, timer, and graphics threads. // void boinc_exit(int status) { - // kill the (separate) graphics app if running - if (options.backwards_compatible_graphics && graphics_app_path[0]) { - control_graphics_app(graphics_app_path, false, false); + if (options.backwards_compatible_graphics) { + graphics_cleanup(); } // Unlock the lock file @@ -714,16 +712,15 @@ static void handle_process_control_msg() { } } -// helper function for handle_graphics_messages() -// -static void control_graphics_app(char* path, bool start, bool fullscreen) { - static bool running = false; +struct GRAPHICS_APP { + bool fullscreen; #ifdef _WIN32 - static HANDLE pid=0; + HANDLE pid; #else - static int pid=0; + int pid; #endif - if (start) { + GRAPHICS_APP(bool f) {fullscreen=f;} + void run(char* path) { int argc; char* argv[4]; char abspath[1024]; @@ -743,29 +740,34 @@ static void control_graphics_app(char* path, bool start, bool fullscreen) { } int retval = run_program(0, abspath, argc, argv, 0, pid); if (retval) { - running = false; - pid = 0; - } else { - running = true; - } - } else { - if (running) { - kill_program(pid); - running = false; pid = 0; } } -} + bool is_running() { + if (pid && process_exists(pid)) return true; + pid = 0; + return false; + } + void kill() { + if (pid) { + kill_program(pid); + pid = 0; + } + } +}; + +static GRAPHICS_APP ga_win(false), ga_full(true); +static bool have_graphics_app; // The following is used by V6 apps so that graphics // will work with pre-V6 clients. // If we get a graphics message, run/kill the (separate) graphics app // static inline void handle_graphics_messages() { + static char graphics_app_path[1024]; char buf[MSG_CHANNEL_SIZE]; GRAPHICS_MSG m; static bool first=true; - static bool have_graphics_app; if (first) { first = false; boinc_resolve_filename( @@ -774,13 +776,12 @@ static inline void handle_graphics_messages() { ); if (!strcmp(graphics_app_path, GRAPHICS_APP_FILENAME)) { have_graphics_app = false; - graphics_app_path[0] = 0; } else { have_graphics_app = true; + app_client_shm->shm->graphics_reply.send_msg( + xml_graphics_modes[MODE_HIDE_GRAPHICS] + ); } - app_client_shm->shm->graphics_reply.send_msg( - xml_graphics_modes[MODE_HIDE_GRAPHICS] - ); } if (!have_graphics_app) return; @@ -789,18 +790,24 @@ static inline void handle_graphics_messages() { app_client_shm->decode_graphics_msg(buf, m); switch (m.mode) { case MODE_HIDE_GRAPHICS: - control_graphics_app(graphics_app_path, false, false); + if (ga_full.is_running()) { + ga_full.kill(); + } else if (ga_win.is_running()) { + ga_win.kill(); + } break; case MODE_WINDOW: - control_graphics_app(graphics_app_path, true, false); + if (!ga_win.is_running()) ga_win.run(graphics_app_path); break; case MODE_FULLSCREEN: - control_graphics_app(graphics_app_path, true, true); + if (!ga_full.is_running()) ga_full.run(graphics_app_path); break; case MODE_BLANKSCREEN: // we can't actually blank the screen; just kill the app // - control_graphics_app(graphics_app_path, false, false); + if (ga_full.is_running()) { + ga_full.kill(); + } break; } app_client_shm->shm->graphics_reply.send_msg( @@ -809,6 +816,12 @@ static inline void handle_graphics_messages() { } } +void graphics_cleanup() { + if (!have_graphics_app) return; + if (ga_full.is_running()) ga_full.kill(); + if (ga_win.is_running()) ga_win.kill(); +} + // once-a-second timer. // Runs in a separate thread (not the worker thread) // diff --git a/checkin_notes b/checkin_notes index 7757ee3b8f..dd490f4ea2 100755 --- a/checkin_notes +++ b/checkin_notes @@ -8906,3 +8906,15 @@ Charlie 27 Sep 2007 boinc.xcodeproj/ project.pbxproj +David 27 Sept 2007 + - graphics API: redo the code for backwards compatibility with V5 so that + at most one regular and one full-screen graphics window can be open, + and a "hide" message kills the full-screen window if one exists, + else a regular window. + Keep track of the PIDs separately for regular and full-screen. + Also, don't send a "hide" ack if we don't do graphics. + + api/ + boinc_api.C + lib/ + util.C,h diff --git a/lib/util.C b/lib/util.C index 97a4c0045d..fe847e85ea 100755 --- a/lib/util.C +++ b/lib/util.C @@ -398,12 +398,26 @@ int get_exit_status(HANDLE pid_handle) { } return (int) status; } +bool process_exists(HANDLE h) { + unsigned long status=1; + if (GetExitCodeProcess(h, &status)) { + if (status == STILL_ACTIVE) return true; + } + return false; +} + #else int get_exit_status(int pid) { int status; waitpid(pid, &status, 0); return status; } +bool process_exists(int pid) { + int p = waitpid(pid, 0, WNOHANG); + if (p == pid) return false; // process has exited + if (p == -1) return false; // PID doesn't exist + return true; +} #endif #ifdef _WIN32 diff --git a/lib/util.h b/lib/util.h index b7419a6849..fa3865d3c3 100755 --- a/lib/util.h +++ b/lib/util.h @@ -89,12 +89,14 @@ extern int run_program( ); extern void kill_program(HANDLE); extern int get_exit_status(HANDLE); +extern bool process_exists(HANDLE); #else extern int run_program( const char* path, const char* cdir, int argc, char *const argv[], double, int& ); extern void kill_program(int); extern int get_exit_status(int); +extern bool process_exists(int); #endif extern int wait_client_mutex(const char* dir, double timeout);