summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fluid/fluid.cxx207
-rw-r--r--src/Fl_win32.cxx71
-rw-r--r--src/Fl_x.cxx1
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