diff options
| -rw-r--r-- | fluid/fluid.cxx | 207 | ||||
| -rw-r--r-- | src/Fl_win32.cxx | 71 | ||||
| -rw-r--r-- | src/Fl_x.cxx | 1 |
3 files changed, 176 insertions, 103 deletions
diff --git a/fluid/fluid.cxx b/fluid/fluid.cxx index 54465015a..02ac4f9e2 100644 --- a/fluid/fluid.cxx +++ b/fluid/fluid.cxx @@ -57,6 +57,7 @@ # include <direct.h> # include <windows.h> # include <io.h> +# include <FCNTL.H> # include <commdlg.h> # include <FL/x.H> # ifndef __WATCOMC__ @@ -1847,63 +1848,176 @@ void update_history(const char *flname) { } } -// Shell command support... -#if (!defined(WIN32) || defined(__CYGWIN__)) && !defined(__MWERKS__) -// Support the full piped shell command... -static FILE *shell_pipe = 0; +// ********** portable process class definition ********** -void -shell_pipe_cb(int, void*) { - char line[1024]; // Line from command output... +class Fl_Process { +public: + // construction / destruction + Fl_Process() {_fpt= NULL;} + ~Fl_Process() {if (_fpt) close();} + + FILE * popen (const char *cmd, const char *mode="r"); + //not necessary here: FILE * fopen (const char *file, const char *mode="r"); + int close(); + + FILE * desc() const { return _fpt;} // non null if file is open + char * get_line(char * line, size_t s) const {return _fpt ? fgets(line, s, _fpt) : NULL;} + +#if defined(WIN32) && !defined(__CYGWIN__) +protected: + HANDLE pin[2], pout[2], perr[2]; + char ptmode; + PROCESS_INFORMATION pi; + STARTUPINFO si; + + static bool createPipe(HANDLE * h, BOOL bInheritHnd=TRUE); + +private: + FILE * freeHandles() { + clean_close(pin[0]); clean_close(pin[1]); + clean_close(pout[0]); clean_close(pout[1]); + clean_close(perr[0]); clean_close(perr[1]); + return NULL; // convenient for error management + } + static void clean_close(HANDLE& h); +#endif - if (fgets(line, sizeof(line), shell_pipe) != NULL) { - // Add the line to the output list... - shell_run_buffer->append(line); - } else { - // End of file; tell the parent... - Fl::remove_fd(fileno(shell_pipe)); +protected: + FILE * _fpt; +}; + +#if defined(WIN32) && !defined(__CYGWIN__) +bool Fl_Process::createPipe(HANDLE * h, BOOL bInheritHnd) { + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = bInheritHnd; + return CreatePipe (&h[0],&h[1],&sa,0) ? true : false; +} +#endif +// portable open process: +FILE * Fl_Process::popen(const char *cmd, const char *mode) { +#if defined(WIN32) && !defined(__CYGWIN__) + // PRECONDITIONS + if (!mode || !*mode || (*mode!='r' && *mode!='w') ) return NULL; + if (_fpt) close(); // close first before reuse + + ptmode = *mode; + pin[0] = pin[1] = pout[0] = pout[1] = perr[0] = perr[1] = INVALID_HANDLE_VALUE; + // stderr to stdout wanted ? + int fusion = (strstr(cmd,"2>&1") !=NULL); + + // Create windows pipes + if (!createPipe(pin) || !createPipe(pout) || (!fusion && !createPipe(perr) ) ) + return freeHandles(); // error + + // Initialize Startup Info + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = pin[0]; + si.hStdOutput = pout[1]; + si.hStdError = fusion ? pout[1] : perr [1]; + + if ( CreateProcess(NULL, (LPTSTR) cmd,NULL,NULL,TRUE, + DETACHED_PROCESS,NULL,NULL, &si, &pi)) { + // don't need theses handles inherited by child process: + clean_close(pin[0]); clean_close(pout[1]); clean_close(perr[1]); + HANDLE & h = *mode == 'r' ? pout[0] : pin[1]; + _fpt = _fdopen(_open_osfhandle((long) h,_O_BINARY),mode); + h= INVALID_HANDLE_VALUE; // reset the handle pointer that is shared + // with _fpt so we don't free it twice + } + + if (!_fpt) freeHandles(); + return _fpt; +#else + _fpt=::popen(cmd,mode); + return _fpt; +#endif +} - pclose(shell_pipe); - shell_pipe = NULL; - shell_run_buffer->append("... END SHELL COMMAND ...\n"); - } +int Fl_Process::close() { +#if defined(WIN32) && !defined(__CYGWIN__) + if (_fpt) { + fclose(_fpt); + clean_close(perr[0]); + clean_close(pin[1]); + clean_close(pout[0]); + _fpt = NULL; + return 0; + } + return -1; +#else + int ret = ::pclose(_fpt); + _fpt=NULL; + return ret; +#endif +} - shell_run_display->scroll(shell_run_display->count_lines(0, - shell_run_buffer->length(), 1), 0); +#if defined(WIN32) && !defined(__CYGWIN__) +void Fl_Process::clean_close(HANDLE& h) { + if (h!= INVALID_HANDLE_VALUE) CloseHandle(h); + h = INVALID_HANDLE_VALUE; } +#endif +// ********** Fl_Process class end ********** -void -do_shell_command(Fl_Return_Button*, void*) { - const char *command; // Command to run +static Fl_Process s_proc; +// Shell command support... +static bool prepare_shell_command(const char * &command) { // common pre-shell command code all platforms shell_window->hide(); - - if (shell_pipe) { + if (s_proc.desc()) { fl_alert("Previous shell command still running!"); - return; + return false; } - if ((command = shell_command_input->value()) == NULL || !*command) { fl_alert("No shell command entered!"); - return; + return false; } - if (shell_savefl_button->value()) { save_cb(0, 0); } - if (shell_writecode_button->value()) { compile_only = 1; write_cb(0, 0); compile_only = 0; } - if (shell_writemsgs_button->value()) { compile_only = 1; write_strings_cb(0, 0); compile_only = 0; } + return true; +} + +#if !defined(__MWERKS__) +// Support the full piped shell command... +void +shell_pipe_cb(int, void*) { + char line[1024]=""; // Line from command output... + + if (s_proc.get_line(line, sizeof(line)) != NULL) { + // Add the line to the output list... + shell_run_buffer->append(line); + } else { + // End of file; tell the parent... + Fl::remove_fd(fileno(s_proc.desc())); + s_proc.close(); + shell_run_buffer->append("... END SHELL COMMAND ...\n"); + } + + shell_run_display->scroll(shell_run_display->count_lines(0, + shell_run_buffer->length(), 1), 0); +} + +void +do_shell_command(Fl_Return_Button*, void*) { + const char *command=NULL; // Command to run + + if (!prepare_shell_command(command)) return; // Show the output window and clear things... shell_run_buffer->text(""); @@ -1911,7 +2025,7 @@ do_shell_command(Fl_Return_Button*, void*) { shell_run_buffer->append("\n"); shell_run_window->label("Shell Command Running..."); - if ((shell_pipe = popen((char *)command, "r")) == NULL) { + if (s_proc.popen((char *)command) == NULL) { fl_alert("Unable to run shell command: %s", strerror(errno)); return; } @@ -1920,9 +2034,9 @@ do_shell_command(Fl_Return_Button*, void*) { shell_run_window->hotspot(shell_run_display); shell_run_window->show(); - Fl::add_fd(fileno(shell_pipe), shell_pipe_cb); + Fl::add_fd(fileno(s_proc.desc()), shell_pipe_cb); - while (shell_pipe) Fl::wait(); + while (s_proc.desc()) Fl::wait(); shell_run_button->activate(); shell_run_window->label("Shell Command Complete"); @@ -1937,29 +2051,7 @@ do_shell_command(Fl_Return_Button*, void*) { const char *command; // Command to run int status; // Status from command... - - shell_window->hide(); - - if ((command = shell_command_input->value()) == NULL || !*command) { - fl_alert("No shell command entered!"); - return; - } - - if (shell_savefl_button->value()) { - save_cb(0, 0); - } - - if (shell_writecode_button->value()) { - compile_only = 1; - write_cb(0, 0); - compile_only = 0; - } - - if (shell_writemsgs_button->value()) { - compile_only = 1; - write_strings_cb(0, 0); - compile_only = 0; - } + if (!prepare_shell_command(command)) return; if ((status = system(command)) != 0) { fl_alert("Shell command returned status %d!", status); @@ -1967,8 +2059,7 @@ do_shell_command(Fl_Return_Button*, void*) { fl_message("Shell command completed successfully!"); } } -#endif // (!WIN32 || __CYGWIN__) && !__MWERKS__ - +#endif // !__MWERKS__ void show_shell_window() { diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index fc6ddffea..bf7402e29 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -64,11 +64,23 @@ // // USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... -// -// This currently doesn't appear to work; needs to be fixed! -// - -//#define USE_ASYNC_SELECT +// USE_ASYNC_SELECT is OBSOLETED in 1.3 for the following reasons: +/** + This feature was supposed to provide an efficient alternative to the current polling method, + but as it has been discussed (Thanks Albrecht!) : + - the async mode would imply to change the socket select mode to non blocking mode, + this can have unexpected side effects for 3rd party apps, especially if it is set on-the-fly when + socket service is really needed, as it is done today and on purpose, but still + the 3rd party developer wouldn't easily control the sequencing of socket operations. + - Finer granularity of events furthered by the async select is a plus only for socket 3rd party impl., + it is simply not needed for the 'light' fltk use we make of wsock, so here + it would also be a bad point, because of all the logic add-ons necessary for + using this functionality, without a clear benefit. + + So async mode select would not add benefits to fltk, worse, + it can slowdown fltk because of this finer granularity and instrumentation code + to be added for async mode proper operation, not mentioning the side effects... +*/ // dynamic wsock dll handling api: typedef int (WINAPI* fl_wsk_select_f)(int, fd_set*, fd_set*, fd_set*, const struct timeval*); @@ -81,14 +93,14 @@ static fl_wsk_fd_is_set_f fl_wsk_fd_is_set=0; static fl_wsk_async_select_f fl_wsk_async_select=0; static HMODULE get_wsock_mod() { - if (!s_wsock_mod) { - s_wsock_mod = LoadLibrary(WSCK_DLL_NAME); - if (s_wsock_mod==NULL) - Fl::fatal("FLTK Lib Error: %s file not found! Please check your winsock dll accessibility.\n",WSCK_DLL_NAME); - s_wsock_select = (fl_wsk_select_f) GetProcAddress(s_wsock_mod, "select"); - fl_wsk_fd_is_set = (fl_wsk_fd_is_set_f) GetProcAddress(s_wsock_mod, "__WSAFDIsSet"); - fl_wsk_async_select = (fl_wsk_async_select_f) GetProcAddress(s_wsock_mod, "WSAAsyncSelect"); - } + if (!s_wsock_mod) { + s_wsock_mod = LoadLibrary(WSCK_DLL_NAME); + if (s_wsock_mod==NULL) + Fl::fatal("FLTK Lib Error: %s file not found! Please check your winsock dll accessibility.\n",WSCK_DLL_NAME); + s_wsock_select = (fl_wsk_select_f) GetProcAddress(s_wsock_mod, "select"); + fl_wsk_fd_is_set = (fl_wsk_fd_is_set_f) GetProcAddress(s_wsock_mod, "__WSAFDIsSet"); + fl_wsk_async_select = (fl_wsk_async_select_f) GetProcAddress(s_wsock_mod, "WSAAsyncSelect"); + } return s_wsock_mod; } @@ -149,9 +161,7 @@ static HMODULE get_wsock_mod() { // select function that sends a WIN32 message when the select condition // exists... static int maxfd = 0; -#ifndef USE_ASYNC_SELECT static fd_set fdsets[3]; -#endif // !USE_ASYNC_SELECT #define POLLIN 1 #define POLLOUT 4 @@ -182,18 +192,10 @@ void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { fd[i].cb = cb; fd[i].arg = v; -#ifdef USE_ASYNC_SELECT - int mask = 0; - if (events & POLLIN) mask |= FD_READ; - if (events & POLLOUT) mask |= FD_WRITE; - if (events & POLLERR) mask |= FD_CLOSE; - if (get_wsock_mod()) fl_wsk_async_select(n, fl_window, WM_FLSELECT, mask); -#else if (events & POLLIN) FD_SET((unsigned)n, &fdsets[0]); if (events & POLLOUT) FD_SET((unsigned)n, &fdsets[1]); if (events & POLLERR) FD_SET((unsigned)n, &fdsets[2]); if (n > maxfd) maxfd = n; -#endif // USE_ASYNC_SELECT } void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { @@ -216,13 +218,9 @@ void Fl::remove_fd(int n, int events) { } nfds = j; -#ifdef USE_ASYNC_SELECT - if (get_wsock_mod()) fl_wsk_async_select(n, 0, 0, 0); -#else if (events & POLLIN) FD_CLR(unsigned(n), &fdsets[0]); if (events & POLLOUT) FD_CLR(unsigned(n), &fdsets[1]); if (events & POLLERR) FD_CLR(unsigned(n), &fdsets[2]); -#endif // USE_ASYNC_SELECT } void Fl::remove_fd(int n) { @@ -261,7 +259,6 @@ int fl_wait(double time_to_wait) { in_idle = 0; } -#ifndef USE_ASYNC_SELECT if (nfds) { // For WIN32 we need to poll for socket input FIRST, since // the event queue is not something we can select() on... @@ -287,7 +284,6 @@ int fl_wait(double time_to_wait) { if (time_to_wait > .001) time_to_wait = .001; } } -#endif // USE_ASYNC_SELECT if (Fl::idle || Fl::damage()) time_to_wait = 0.0; @@ -309,18 +305,6 @@ int fl_wait(double time_to_wait) { have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); if (have_message > 0) { while (have_message != 0 && have_message != -1) { -#ifdef USE_ASYNC_SELECT - if (fl_msg.message == WM_FLSELECT) { - // Got notification for socket - for (int i = 0; i < nfds; i ++) - if (fd[i].fd == (int)fl_msg.wParam) { - (fd[i].cb)(fd[i].fd, fd[i].arg); - break; - } - // looks like it is best to do the dispatch-message anyway: - } -#endif - if (fl_msg.message == fl_wake_msg) { // Used for awaking wait() from another thread thread_message_ = (void*)fl_msg.wParam; @@ -345,16 +329,13 @@ int fl_wait(double time_to_wait) { // fl_ready() is just like fl_wait(0.0) except no callbacks are done: int fl_ready() { if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; -#ifdef USE_ASYNC_SELECT - return 0; -#else + if (!nfds) return 0; timeval t; t.tv_sec = 0; t.tv_usec = 0; fd_set fdt[3]; memcpy(fdt, fdsets, sizeof fdt); return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0; -#endif // USE_ASYNC_SELECT } //////////////////////////////////////////////////////////////// diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 7121cc8d9..3a8242b3e 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -249,6 +249,7 @@ int fl_wait(double time_to_wait) { // fl_ready() is just like fl_wait(0.0) except no callbacks are done: int fl_ready() { if (XQLength(fl_display)) return 1; + if (!nfds) return 0; // nothing to select or poll # if USE_POLL return ::poll(pollfds, nfds, 0); # else |
