summaryrefslogtreecommitdiff
path: root/fluid/ExternalCodeEditor_WIN32.cxx
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2025-03-07 16:34:35 +0100
committerMatthias Melcher <github@matthiasm.com>2025-03-07 16:34:48 +0100
commit1985aefc0e502048f92b91beef87c0dfbe669fed (patch)
treeaf62874def4590e437a47784b4428d975ceb262f /fluid/ExternalCodeEditor_WIN32.cxx
parent42a04c064d4b31c3a85210311f3ada163c406a25 (diff)
Restructuring Fluid source files.
Diffstat (limited to 'fluid/ExternalCodeEditor_WIN32.cxx')
-rw-r--r--fluid/ExternalCodeEditor_WIN32.cxx632
1 files changed, 0 insertions, 632 deletions
diff --git a/fluid/ExternalCodeEditor_WIN32.cxx b/fluid/ExternalCodeEditor_WIN32.cxx
deleted file mode 100644
index bb7d5791a..000000000
--- a/fluid/ExternalCodeEditor_WIN32.cxx
+++ /dev/null
@@ -1,632 +0,0 @@
-//
-// External code editor management class for Windows
-//
-// Copyright 1998-2023 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// https://www.fltk.org/COPYING.php
-//
-// Please see the following page on how to report bugs and issues:
-//
-// https://www.fltk.org/bugs.php
-//
-
-// Note: This entire file Windows only.
-
-#include <FL/Fl.H> // Fl_Timeout_Handler..
-#include <FL/fl_ask.H> // fl_alert()
-#include <FL/fl_utf8.h> // fl_utf8fromwc()
-#include <FL/fl_string_functions.h> // fl_strdup()
-
-#include "ExternalCodeEditor_WIN32.h"
-#include "fluid.h"
-
-#include <stdio.h> // snprintf()
-#include <stdlib.h>
-
-extern int G_debug; // defined in fluid.cxx
-
-// Static local data
-static int L_editors_open = 0; // keep track of #editors open
-static Fl_Timeout_Handler L_update_timer_cb = 0; // app's update timer callback
-static wchar_t *wbuf = NULL;
-static char *abuf = NULL;
-
-static wchar_t *utf8_to_wchar(const char *utf8, wchar_t *&wbuf, int lg = -1) {
- unsigned len = (lg >= 0) ? (unsigned)lg : (unsigned)strlen(utf8);
- unsigned wn = fl_utf8toUtf16(utf8, len, NULL, 0) + 1; // Query length
- wbuf = (wchar_t *)realloc(wbuf, sizeof(wchar_t) * wn);
- wn = fl_utf8toUtf16(utf8, len, (unsigned short *)wbuf, wn); // Convert string
- wbuf[wn] = 0;
- return wbuf;
-}
-
-static char *wchar_to_utf8(const wchar_t *wstr, char *&utf8) {
- unsigned len = (unsigned)wcslen(wstr);
- unsigned wn = fl_utf8fromwc(NULL, 0, wstr, len) + 1; // query length
- utf8 = (char *)realloc(utf8, wn);
- wn = fl_utf8fromwc(utf8, wn, wstr, len); // convert string
- utf8[wn] = 0;
- return utf8;
-}
-
-// [Static/Local] Get error message string for last failed WIN32 function.
-// Returns a string pointing to static memory.
-//
-static const char *get_ms_errmsg() {
- static char emsg[1024];
- DWORD lastErr = GetLastError();
- DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_FROM_SYSTEM;
- DWORD langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
- LPWSTR mbuf = 0;
- DWORD msize = 0;
-
- // Get error message from Windows
- msize = FormatMessageW(flags, 0, lastErr, langid, (LPWSTR)&mbuf, 0, NULL);
- if ( msize == 0 ) {
- _snprintf(emsg, sizeof(emsg), "Error #%ld", (unsigned long)lastErr);
- } else {
- // Convert message to UTF-8
- fl_utf8fromwc(emsg, sizeof(emsg), mbuf, msize);
- // Remove '\r's -- they screw up fl_alert()
- char *src = emsg, *dst = emsg;
- for ( ; 1; src++ ) {
- if ( *src == '\0' ) { *dst = '\0'; break; }
- if ( *src != '\r' ) { *dst++ = *src; }
- }
- LocalFree(mbuf); // Free the buffer allocated by the system
- }
- return emsg;
-}
-
-// [Static/Local] See if file exists
-static int is_file(const char *filename) {
- utf8_to_wchar(filename, wbuf);
- DWORD att = GetFileAttributesW(wbuf);
- if (att == INVALID_FILE_ATTRIBUTES)
- return 0;
- if ( (att & FILE_ATTRIBUTE_DIRECTORY) == 0 ) return 1; // not a dir == file
- return 0;
-}
-
-// [Static/Local] See if dir exists
-static int is_dir(const char *dirname) {
- utf8_to_wchar(dirname, wbuf);
- DWORD att = GetFileAttributesW(wbuf);
- if (att == INVALID_FILE_ATTRIBUTES) return 0;
- if (att & FILE_ATTRIBUTE_DIRECTORY) return 1;
- return 0;
-}
-
-// CTOR
-ExternalCodeEditor::ExternalCodeEditor() {
- memset(&pinfo_, 0, sizeof(pinfo_));
- memset(&file_mtime_, 0, sizeof(file_mtime_));
- memset(&file_size_, 0, sizeof(file_size_));
- filename_ = 0;
-}
-
-// DTOR
-ExternalCodeEditor::~ExternalCodeEditor() {
- close_editor(); // close editor, delete tmp file
- set_filename(0); // free()s filename
-}
-
-// [Protected] Set the filename. Handles memory allocation/free
-// If set to NULL, frees memory.
-//
-void ExternalCodeEditor::set_filename(const char *val) {
- if ( filename_ ) free((void*)filename_);
- filename_ = val ? fl_strdup(val) : 0;
-}
-
-// [Public] Is editor running?
-int ExternalCodeEditor::is_editing() {
- return( (pinfo_.dwProcessId != 0) ? 1 : 0 );
-}
-
-// [Static/Local] Terminate_app()'s callback to send WM_CLOSE to a single window.
-static BOOL CALLBACK terminate_app_enum(HWND hwnd, LPARAM lParam) {
- DWORD dwID;
- GetWindowThreadProcessId(hwnd, &dwID);
- if (dwID == (DWORD)lParam) {
- PostMessage(hwnd, WM_CLOSE, 0, 0);
- if ( G_debug )
- printf("terminate_app_enum() sends WIN_CLOSE to hwnd=%p\n", (void*)hwnd);
- }
- return TRUE;
-}
-
-// [Static/Local] Handle sending WIN_CLOSE to /all/ windows matching specified pid.
-// Wait up to msecTimeout for process to close, and if it doesn't, use TerminateProcess().
-//
-static int terminate_app(DWORD pid, DWORD msecTimeout) {
- HANDLE hProc = OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, pid);
- if ( !hProc ) return -1;
- // terminate_app_enum() posts WM_CLOSE to all windows matching pid
- EnumWindows((WNDENUMPROC)terminate_app_enum, (LPARAM) pid);
- // Wait on handle. If it closes, great. If it times out, use TerminateProcess()
- int ret = 0;
- if ( WaitForSingleObject(hProc, msecTimeout) != WAIT_OBJECT_0 ) {
- if ( G_debug ) {
- printf("WARNING: sent WIN_CLOSE, but timeout after %ld msecs.."
- "trying TerminateProcess\n", msecTimeout);
- }
- if ( TerminateProcess(hProc, 0) == 0 ) {
- if ( G_debug ) {
- printf("ERROR: TerminateProcess() for pid=%ld failed: %s\n",
- long(pid), get_ms_errmsg());
- }
- ret = -1;
- } else {
- ret = 0; // TerminateProcess succeeded
- }
- } else {
- ret = 0; // WaitForSingleObject() confirmed WIN_CLOSE succeeded
- }
- CloseHandle(hProc);
- return ret;
-}
-
-// [Protected] Wait for editor to close
-void ExternalCodeEditor::close_editor() {
- if ( G_debug ) printf("close_editor() called: pid=%ld\n", long(pinfo_.dwProcessId));
- // Wait until editor is closed + reaped
- while ( is_editing() ) {
- switch ( reap_editor() ) {
- case -2: // no editor running (unlikely to happen)
- return;
- case -1: // error
- fl_alert("Error reaping external editor\npid=%ld file=%s\nOS error message=%s",
- long(pinfo_.dwProcessId), filename(), get_ms_errmsg());
- break;
- case 0: // process still running
- switch ( fl_choice("Please close external editor\npid=%ld file=%s",
- "Force Close", // button 0
- "Closed", // button 1
- 0, // button 2
- long(pinfo_.dwProcessId), filename() ) ) {
- case 0: // Force Close
- kill_editor();
- continue;
- case 1: // Closed? try to reap
- continue;
- }
- break;
- case 1: // process reaped
- return;
- }
- }
-}
-
-// [Protected] Kill the running editor (if any) and cleanup
-// Kills the editor, reaps the process, and removes the tmp file.
-// The dtor calls this to ensure no editors remain running when fluid exits.
-//
-void ExternalCodeEditor::kill_editor() {
- if ( G_debug )
- printf("kill_editor() called: pid=%ld\n", (long)pinfo_.dwProcessId);
- if ( !is_editing() ) return;
- switch ( terminate_app(pinfo_.dwProcessId, 500) ) { // kill editor, wait up to 1/2 sec to die
- case -1: { // error
- fl_alert("Can't seem to close editor of file: %s\n"
- "Please close editor and hit OK", filename());
- break;
- }
- case 0: { // success -- process reaped
- DWORD pid = pinfo_.dwProcessId; // save pid
- reap_cleanup(); // clears pinfo_
- if ( G_debug )
- printf("*** kill_editor() REAP pid=%ld #open=%ld\n",
- long(pid), long(L_editors_open));
- break;
- }
- }
- return;
-}
-
-// [Public] Handle if file changed since last check, and update records if so.
-// Load new data into 'code', which caller must free().
-// If 'force' set, forces reload even if file size/time didn't change.
-//
-// Returns:
-// 0 -- file unchanged or not editing
-// 1 -- file changed, internal records updated, 'code' has new content
-// -1 -- error getting file info (get_ms_errmsg() has reason)
-//
-// OPTIONAL TODO:
-// Ignore changes made within the last 2 seconds,
-// to give editor time to fully write out the file.
-//
-int ExternalCodeEditor::handle_changes(const char **code, int force) {
- code[0] = 0;
- if ( !is_editing() ) return 0;
- // Sigh, have to open file to get file time/size :/
- utf8_to_wchar(filename(), wbuf);
- HANDLE fh = CreateFileW(wbuf, // file to read
- GENERIC_READ, // reading only
- FILE_SHARE_READ, // sharing -- allow read share; just getting file size
- NULL, // security
- OPEN_EXISTING, // create flags -- must exist
- 0, // misc flags
- NULL); // templates
- if ( fh == INVALID_HANDLE_VALUE ) return -1;
- LARGE_INTEGER fsize;
- // Get file size
- if ( GetFileSizeEx(fh, &fsize) == 0 ) {
- DWORD err = GetLastError();
- CloseHandle(fh);
- SetLastError(err); // return error from GetFileSizeEx(), not CloseHandle()
- return -1;
- }
- // Get file time
- FILETIME ftCreate, ftAccess, ftWrite;
- if ( GetFileTime(fh, &ftCreate, &ftAccess, &ftWrite) == 0 ) {
- DWORD err = GetLastError();
- CloseHandle(fh);
- SetLastError(err); // return error from GetFileTime(), not CloseHandle()
- return -1;
- }
- // OK, now see if file changed; update records if so
- int changed = 0;
- if ( fsize.QuadPart != file_size_.QuadPart )
- { changed = 1; file_size_ = fsize; }
- if ( CompareFileTime(&ftWrite, &file_mtime_) != 0 )
- { changed = 1; file_mtime_ = ftWrite; }
- // Changes? Load file. Be sure to fallthru to CloseHandle()
- int ret = 0;
- if ( changed || force ) {
- DWORD buflen = (DWORD)fsize.QuadPart;
- char *buf = (char*)malloc((size_t)buflen + 1);
- DWORD count;
- if ( ReadFile(fh, buf, buflen, &count, 0) == 0 ) {
- fl_alert("ERROR: ReadFile() failed for %s: %s",
- filename(), get_ms_errmsg());
- free((void*)buf); buf = 0;
- ret = -1; // fallthru to CloseHandle()
- } else if ( count != buflen ) {
- fl_alert("ERROR: ReadFile() failed for %s:\n"
- "expected %ld bytes, got %ld",
- filename(), long(buflen), long(count));
- free((void*)buf); buf = 0;
- ret = -1; // fallthru to CloseHandle()
- } else {
- // Successfully read changed file
- buf[count] = '\0';
- code[0] = buf; // return pointer to allocated buffer
- ret = 1; // fallthru to CloseHandle()
- }
- }
- CloseHandle(fh);
- return ret;
-}
-
-// [Public] Remove the tmp file (if it exists), and zero out filename/mtime/size
-// Returns:
-// -1 -- on error (dialog is posted as to why)
-// 0 -- no file to remove
-// 1 -- file was removed
-//
-int ExternalCodeEditor::remove_tmpfile() {
- const char *tmpfile = filename();
- if ( G_debug ) printf("remove_tmpfile() '%s'\n", tmpfile ? tmpfile : "(empty)");
- if ( !tmpfile ) return 0;
- // Filename set? remove (if exists) and zero filename/mtime/size
- if ( is_file(tmpfile) ) {
- if ( G_debug ) printf("Removing tmpfile '%s'\n", tmpfile);
- utf8_to_wchar(tmpfile, wbuf);
- if (DeleteFileW(wbuf) == 0) {
- fl_alert("WARNING: Can't DeleteFile() '%s': %s", tmpfile, get_ms_errmsg());
- return -1;
- }
- } else {
- if ( G_debug ) printf("remove_tmpfile(): is_file(%s) failed\n", tmpfile);
- }
- set_filename(0);
- memset(&file_mtime_, 0, sizeof(file_mtime_));
- memset(&file_size_, 0, sizeof(file_size_));
- return 1;
-}
-
-// [Static/Public] Return tmpdir name for this fluid instance.
-// Returns pointer to static memory.
-//
-const char* ExternalCodeEditor::tmpdir_name() {
- wchar_t tempdirW[FL_PATH_MAX+1];
- char tempdir[FL_PATH_MAX+1];
- if (GetTempPathW(FL_PATH_MAX, tempdirW) == 0) {
- strcpy(tempdir, "c:\\windows\\temp"); // fallback
- } else {
- strcpy(tempdir, wchar_to_utf8(tempdirW, abuf));
- }
- static char dirname[100];
- _snprintf(dirname, sizeof(dirname), "%s.fluid-%ld",
- tempdir, (long)GetCurrentProcessId());
- if ( G_debug ) printf("tmpdir_name(): '%s'\n", dirname);
- return dirname;
-}
-
-// [Static/Public] Clear the external editor's tempdir
-// Static so that the main program can call it on exit to clean up.
-//
-void ExternalCodeEditor::tmpdir_clear() {
- const char *tmpdir = tmpdir_name();
- if ( is_dir(tmpdir) ) {
- if ( G_debug ) printf("Removing tmpdir '%s'\n", tmpdir);
- utf8_to_wchar(tmpdir, wbuf);
- if ( RemoveDirectoryW(wbuf) == 0 ) {
- fl_alert("WARNING: Can't RemoveDirectory() '%s': %s",
- tmpdir, get_ms_errmsg());
- }
- }
-}
-
-// [Protected] Creates temp dir (if doesn't exist) and returns the dirname
-// as a static string. Returns NULL on error, dialog shows reason.
-//
-const char* ExternalCodeEditor::create_tmpdir() {
- const char *dirname = tmpdir_name();
- if ( ! is_dir(dirname) ) {
- utf8_to_wchar(dirname, wbuf);
- if (CreateDirectoryW(wbuf, 0) == 0) {
- fl_alert("can't create directory '%s': %s",
- dirname, get_ms_errmsg());
- return NULL;
- }
- }
- return dirname;
-}
-
-// [Protected] Returns temp filename in static buffer.
-// Returns NULL if can't, posts dialog explaining why.
-//
-const char* ExternalCodeEditor::tmp_filename() {
- static char path[512];
- const char *tmpdir = create_tmpdir();
- if ( !tmpdir ) return 0;
- const char *ext = g_project.code_file_name.c_str(); // e.g. ".cxx"
- _snprintf(path, sizeof(path), "%s\\%p%s", tmpdir, (void*)this, ext);
- path[sizeof(path)-1] = 0;
- return path;
-}
-
-// [Static/Local] Save string 'code' to 'filename', returning file's mtime/size
-// 'code' can be NULL -- writes an empty file if so.
-// Returns:
-// 0 on success
-// -1 on error (posts dialog with reason)
-//
-static int save_file(const char *filename,
- const char *code,
- FILETIME &file_mtime, // return these since in win32 it's..
- LARGE_INTEGER &file_size) { // ..efficient to get while file open
- if ( code == 0 ) code = ""; // NULL? write an empty file
- memset(&file_mtime, 0, sizeof(file_mtime));
- memset(&file_size, 0, sizeof(file_size));
- utf8_to_wchar(filename, wbuf);
- HANDLE fh = CreateFileW(wbuf, // filename
- GENERIC_WRITE, // write only
- 0, // sharing -- no share during write
- NULL, // security
- CREATE_ALWAYS, // create flags -- recreate
- FILE_ATTRIBUTE_NORMAL, // misc flags
- NULL); // templates
- if ( fh == INVALID_HANDLE_VALUE ) {
- fl_alert("ERROR: couldn't create file '%s': %s",
- filename, get_ms_errmsg());
- return(-1);
- }
- // Write the file, being careful to CloseHandle() even on errs
- DWORD clen = (DWORD)strlen(code);
- DWORD count = 0;
- int ret = 0;
- if ( WriteFile(fh, code, clen, &count, NULL) == 0 ) {
- fl_alert("ERROR: WriteFile() '%s': %s", filename, get_ms_errmsg());
- ret = -1; // fallthru to CloseHandle()
- } else if ( count != clen ) {
- fl_alert("ERROR: WriteFile() '%s': wrote only %lu bytes, expected %lu",
- filename, (unsigned long)count, (unsigned long)clen);
- ret = -1; // fallthru to CloseHandle()
- }
- // Get mtime/size before closing
- {
- FILETIME ftCreate, ftAccess, ftWrite;
- if ( GetFileSizeEx(fh, &file_size) == 0 ) {
- fl_alert("ERROR: save_file(%s): GetFileSizeEx() failed: %s\n",
- filename, get_ms_errmsg());
- }
- if ( GetFileTime(fh, &ftCreate, &ftAccess, &ftWrite) == 0 ) {
- fl_alert("ERROR: save_file(%s): GetFileTime() failed: %s\n",
- filename, get_ms_errmsg());
- }
- file_mtime = ftWrite;
- }
- // Close, done
- CloseHandle(fh);
- return(ret);
-}
-
-// [Protected] Start editor
-// Returns:
-// > 0 on success, leaves editor child process running as 'pinfo_'
-// > -1 on error, posts dialog with reason (child exits)
-//
-int ExternalCodeEditor::start_editor(const char *editor_cmd,
- const char *filename) {
- if ( G_debug ) printf("start_editor() cmd='%s', filename='%s'\n",
- editor_cmd, filename);
- // Startup info
- STARTUPINFOW sinfo;
- memset(&sinfo, 0, sizeof(sinfo));
- sinfo.cb = sizeof(sinfo);
- sinfo.dwFlags = 0;
- sinfo.wShowWindow = 0;
- // Process info
- memset(&pinfo_, 0, sizeof(pinfo_));
- // Command
- char cmd[1024];
- _snprintf(cmd, sizeof(cmd), "%s %s", editor_cmd, filename);
- utf8_to_wchar(cmd, wbuf);
- // Start editor process
- if (CreateProcessW(NULL, // app name
- wbuf, // command to exec
- NULL, // secure attribs
- NULL, // thread secure attribs
- FALSE, // handle inheritance
- 0, // creation flags
- NULL, // environ block
- NULL, // current dir
- &sinfo, // startup info
- &pinfo_) == 0 ) { // process info
- fl_alert("CreateProcess() failed to start '%s': %s",
- cmd, get_ms_errmsg());
- return(-1);
- }
- if ( L_editors_open++ == 0 ) // first editor? start timers
- { start_update_timer(); }
- if ( G_debug )
- printf("--- EDITOR STARTED: pid_=%ld #open=%d\n",
- (long)pinfo_.dwProcessId, L_editors_open);
- return 0;
-}
-
-// [Protected] Cleanup after editor reaped:
-// > Remove tmpfile, zeroes mtime/size/filename
-// > Close process handles
-// > Zeroes out pinfo_
-// > Decrease editor count
-//
-void ExternalCodeEditor::reap_cleanup() {
- remove_tmpfile(); // also zeroes mtime/size/filename
- CloseHandle(pinfo_.hProcess); // close process handle
- CloseHandle(pinfo_.hThread); // close thread handle
- memset(&pinfo_, 0, sizeof(pinfo_)); // clear pinfo_
- if ( --L_editors_open <= 0 )
- { stop_update_timer(); }
-}
-
-// [Public] Try to reap external editor process
-// If 'pid_reaped' not NULL, returns PID of reaped editor.
-// Returns:
-// -2 -- editor not open
-// -1 -- WaitForSingleObject() failed (get_ms_errmsg() has reason)
-// 0 -- process still running
-// 1 -- process finished + reaped ('pid_reaped' has pid), pinfo_ set to 0.
-// Handles removing tmpfile/zeroing file_mtime/file_size/filename
-//
-// If return value <=0, 'pid_reaped' is set to zero.
-//
-int ExternalCodeEditor::reap_editor(DWORD *pid_reaped) {
- if ( pid_reaped ) *pid_reaped = 0;
- if ( !is_editing() ) return -2;
- DWORD msecs_wait = 50; // .05 sec
- switch ( WaitForSingleObject(pinfo_.hProcess, msecs_wait) ) {
- case WAIT_TIMEOUT: { // process didn't reap, still running
- return 0;
- }
- case WAIT_OBJECT_0: { // reaped
- DWORD wpid = pinfo_.dwProcessId; // save pid
- reap_cleanup(); // clears pinfo_
- if ( pid_reaped ) *pid_reaped = wpid; // return pid to caller
- if ( G_debug ) printf("*** EDITOR REAPED: pid=%ld #open=%d\n",
- long(wpid), L_editors_open);
- return 1;
- }
- case WAIT_FAILED: { // failed
- return -1;
- }
- }
- return -1; // any other return unexpected
-}
-
-// [Public] Open external editor using 'editor_cmd' to edit 'code'.
-//
-// 'code' contains multiline code to be edited as a temp file.
-// 'code' can be NULL -- edits an empty file if so.
-//
-// Returns:
-// 0 if succeeds
-// -1 if can't open editor (already open, etc),
-// errors were shown to user in a dialog
-//
-int ExternalCodeEditor::open_editor(const char *editor_cmd,
- const char *code) {
- // Make sure a temp filename exists
- if ( !filename() ) {
- set_filename(tmp_filename());
- if ( !filename() ) return -1;
- }
- // See if tmpfile already exists or editor already open
- if ( is_file(filename()) ) {
- if ( is_editing() ) {
- // See if editor recently closed but not reaped; try to reap
- DWORD wpid;
- switch ( reap_editor(&wpid) ) {
- case -2: // no editor running (unlikely to happen)
- break;
- case -1: // wait failed
- fl_alert("ERROR: WaitForSingleObject() failed: %s\nfile='%s', pid=%ld",
- get_ms_errmsg(), filename(), long(pinfo_.dwProcessId));
- return -1;
- case 0: // process still running
- fl_alert("Editor Already Open\n file='%s'\n pid=%ld",
- filename(), long(pinfo_.dwProcessId));
- return 0;
- case 1: // process reaped, wpid is pid reaped
- if ( G_debug )
- printf("*** REAPED EXTERNAL EDITOR: PID %ld\n", long(wpid));
- break; // fall thru to open new editor instance
- }
- // Reinstate tmp filename (reap_editor() clears it)
- set_filename(tmp_filename());
- }
- }
- // Save code to tmpfile, getting mtime/size
- if ( save_file(filename(), code, file_mtime_, file_size_) < 0 ) {
- return -1; // errors were shown in dialog
- }
- if ( start_editor(editor_cmd, filename()) < 0 ) { // open file in external editor
- if ( G_debug ) printf("Editor failed to start\n");
- return -1; // errors were shown in dialog
- }
- // New editor opened -- start update timer (if not already)
- if ( L_update_timer_cb && !Fl::has_timeout(L_update_timer_cb) ) {
- if ( G_debug ) printf("--- Editor opened: STARTING UPDATE TIMER\n");
- Fl::add_timeout(2.0, L_update_timer_cb);
- }
- return 0;
-}
-
-// [Public/Static] Start update timer
-void ExternalCodeEditor::start_update_timer() {
- if ( !L_update_timer_cb ) return;
- if ( G_debug ) printf("--- TIMER: STARTING UPDATES\n");
- Fl::add_timeout(2.0, L_update_timer_cb);
-}
-
-// [Public/Static] Stop update timer
-void ExternalCodeEditor::stop_update_timer() {
- if ( !L_update_timer_cb ) return;
- if ( G_debug ) printf("--- TIMER: STOPPING UPDATES\n");
- Fl::remove_timeout(L_update_timer_cb);
-}
-
-// [Public/Static] Set app's external editor update timer callback
-// This is the app's callback callback we start while editors are open,
-// and stop when all editors are closed.
-//
-void ExternalCodeEditor::set_update_timer_callback(Fl_Timeout_Handler cb) {
- L_update_timer_cb = cb;
-}
-
-// [Static/Public] See if any external editors are open.
-// App's timer cb can see if any editors need checking..
-//
-int ExternalCodeEditor::editors_open() {
- return L_editors_open;
-}