From af7f485e0692dc2eff7da057b6ecd038032ce8ec Mon Sep 17 00:00:00 2001 From: Albrecht Schlosser Date: Sat, 18 Jul 2020 16:17:59 +0200 Subject: [PATCH 1/3] Consolidate test/demo for all build systems This is an attempt to unify the code for all build systems (CMake, autotools with make), platforms (operating systems) and toolchains (make + gcc/clang, Visual Studio IDE, Xcode ...) to avoid duplicate code and clarify the differences for future devs and to simplify maintenance. The goal is to minimize the platform specific code. Much of the new code are comments to describe the different situations. The main program does now all the "hard work" to construct the paths necessary to access the other applications and data files. Use macOS specific code to determine the application path (app_path) in main() instead of function dobut(), when test apps are activated. Remove obsolete comments and dead code. Tested on Windows and Linux with both autotools/configure/make and CMake with make (Linux + MinGW), Visual Studio. --- test/CMakeLists.txt | 19 +- test/demo.cxx | 494 +++++++++++++++++++++++++++----------------- test/demo.menu | 2 +- 3 files changed, 320 insertions(+), 195 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f1265978c..b477d6647 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -15,8 +15,8 @@ # ####################################################################### -set (EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../bin/examples) -set (TESTFILE_PATH ${EXECUTABLE_OUTPUT_PATH}) +set (EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../bin) +set (TESTFILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../data) include (../CMake/FLTK-Functions.cmake) include (../CMake/fl_create_example.cmake) @@ -204,13 +204,11 @@ endif (NOT ANDROID) # We need some support files for the demo programs: -# Note: this is incomplete as of 11 Feb 2015 -# Todo: currently all files are copied, but some of them need configuration: -# - demo.menu: fluid can't be started (wrong path) +# Note: this is incomplete as of July 2020 +# Todo: currently all files are copied, but some of them may need configuration: # - demo.menu: help_dialog (help_dialog.html) can't find its images (not copied) -# - maybe more ... -# create data directory for test and demo programs +# create data directory for test and demo programs if it doesn't exist file (MAKE_DIRECTORY ${TESTFILE_PATH}) # copy the test files @@ -221,13 +219,16 @@ file (COPY DESTINATION ${TESTFILE_PATH} ) +# the main test program 'demo' needs additional hints and configurations + +target_compile_definitions (demo PRIVATE GENERATED_BY_CMAKE) +target_compile_definitions (demo PRIVATE CMAKE_SOURCE_PATH="${CMAKE_CURRENT_SOURCE_DIR}") + # Apple macOS creates bundles instead of executables and needs a little bit # more help for demos to run correctly if (APPLE AND (NOT OPTION_APPLE_X11) AND (NOT OPTION_APPLE_SDL)) - target_compile_definitions (demo PUBLIC USING_XCODE) - # make the menu structure part of the app target_sources (demo PRIVATE demo.menu) set_target_properties (demo PROPERTIES MACOSX_BUNDLE TRUE RESOURCE demo.menu) diff --git a/test/demo.cxx b/test/demo.cxx index e7f9445e1..e02b81def 100644 --- a/test/demo.cxx +++ b/test/demo.cxx @@ -14,9 +14,58 @@ // https://www.fltk.org/bugs.php // +/* + General information on directory structure and file handling. + + The "classic" autotools/make system creates executables in their source + folders, i.e. fluid/fluid, test/demo and test/xyz, resp.. The menu file is + in folder test/, as is the main demo(.exe) program. In the following text + and directory lists all test and demo executables are represented by "demo" + and the fluid executable by "fluid", no matter what OS (under Windows: *.exe). + + The CMake build system generates all executables in the build tree and copies + the supporting test data files to the build tree as well. This structure is + different and needs to be handled separately in this program. + + Additionally, different OS platforms create different types of files, for + instance "app bundles" on macOS. All this needs to be considered. + + The overall structure, relative to the FLTK source dir (fltk) and the build + tree (build): + + (1) Autotools / Make: + + fltk/fluid fluid (../fluid/fluid) + fltk/test demo, demo.menu, working directory, data files + fltk/documentation/src images for help_dialog(.html) + + (2) CMake + make (e.g. Unix) + + build/bin fluid, demo + build/data demo.menu, working directory, data files + + (3) CMake + Visual Studio (TYPE == build type: Debug, Release, ...) + + build/bin/TYPE fluid, demo + build/data demo.menu, working directory, data files + + (4) CMake + macOS + Xcode + + *FIXME* special code to handle bundles: do we need this? + + The built executable 'demo' can also be executed with the menu filename + as commandline argument. In this case all the support (data) files are + expected to be in the same directory as the menu file or relative paths + as needed by the test programs, for instance help_dialog which needs + help_dialog.html and related image files. +*/ + +#define DEBUG_VARS (1) // 1 = output variables to stderr, 0 = no + #include #include #include +#include #if defined __APPLE__ #include @@ -29,21 +78,7 @@ #include #include #include - -/* Define a macro to decide whether a trailing 'd' needs to be removed - from the executable file name. Previous versions of Visual Studio - added a 'd' to the executable file name ('demod.exe') in Debug - configurations that needed to be removed. - This is no longer true with CMake-generated IDE's since FLTK 1.4. - Just in case we add it again: leave macro DEBUG_EXE_WITH_D defined - and leave the code using this macro as-is. -*/ - -// #if defined(_MSC_VER) && defined(_DEBUG) // Visual Studio in Debug mode -// # define DEBUG_EXE_WITH_D 1 -// #else -# define DEBUG_EXE_WITH_D 0 -// #endif +#include // fl_alert() /* The form description */ @@ -57,6 +92,40 @@ void doscheme(Fl_Choice *c, void *) { Fl_Double_Window *form; Fl_Button *but[9]; +// Allocate space to edit commands and arguments from demo.menu. +// We "trust demo.menu" that strings don't overflow + +char cmdbuf[256]; // commandline w/o arguments +char params[256]; // commandline arguments + +// Global path variables for all platforms and build systems +// to avoid duplication and dynamic allocation + +char src_path [FL_PATH_MAX]; // directory of this souce file +char app_path [FL_PATH_MAX]; // directory of all demo binaries +char fluid_path [FL_PATH_MAX]; // binary directory of fluid +char data_path [FL_PATH_MAX]; // working directory of all demos +char command [2 * FL_PATH_MAX + 40]; // command to be executed + +// platform specific suffix for executable files + +#ifdef _WIN32 +const char *suffix = ".exe"; +#elif defined __APPLE__ +const char *suffix = ".app"; +#else +const char *suffix = ""; +#endif + +// debug output function (to stderr or ...) + +void debug_var(const char *varname, const char *value) { +#if (DEBUG_VARS) + fprintf(stderr, "%-10s = '%s'\n", varname, value); + fflush(stderr); // Windows needs this +#endif // DEBUG_VARS +} + void create_the_forms() { Fl_Widget *obj; form = new Fl_Double_Window(350, 440); @@ -214,190 +283,145 @@ void dobut(Fl_Widget *, long arg) { int men = find_menu(stack[stsize-1]); int n = menus[men].numb; int bn = but2numb( (int) arg, n-1); + + // menu ? + if (menus[men].icommand[bn][0] == '@') { push_menu(menus[men].icommand[bn]); + return; + } + + // not a menu: run test/demo/fluid executable + // find and separate "command" and "params" + + // skip leading spaces in command + char *start_command = menus[men].icommand[bn]; + while (*start_command == ' ') ++start_command; + + strcpy(cmdbuf, start_command); // here still full command w/params + + // find the space between the command and parameters if one exists + char *start_params = strchr(cmdbuf, ' '); + if (start_params) { + *start_params = '\0'; // terminate command + start_params++; // skip space + strcpy(params, start_params); // copy parameters } else { + params[0] = '\0'; // empty string + } + + // select application path: either app_path or fluid_path + + const char *path = app_path; + if (!strncmp(cmdbuf, "fluid", 5)) + path = fluid_path; + + // format commandline with optional parameters + +#if defined(__APPLE__) // macOS + + if (params[0]) { + // we assume that we have only one argument (which is a filename) + sprintf(command, "open '%s/%s%s' --args '%s'", path, cmdbuf, suffix, params); + } else { + sprintf(command, "open '%s/%s%s'", path, cmdbuf, suffix); + } + +#else // other platforms + + if (params[0]) + sprintf(command, "%s/%s%s %s", path, cmdbuf, suffix, params); + else + sprintf(command, "%s/%s%s", path, cmdbuf, suffix); + +#endif + + // finally, execute program (the system specific part) #ifdef _WIN32 - STARTUPINFO suInfo; // Process startup information - PROCESS_INFORMATION prInfo; // Process information + STARTUPINFO suInfo; // Process startup information + PROCESS_INFORMATION prInfo; // Process information -# if DEBUG_EXE_WITH_D - const char *exe = "d.exe"; // exe name with trailing 'd' -# else - const char *exe = ".exe"; // exe name w/o trailing 'd' -# endif + memset(&suInfo, 0, sizeof(suInfo)); + suInfo.cb = sizeof(suInfo); - memset(&suInfo, 0, sizeof(suInfo)); - suInfo.cb = sizeof(suInfo); + debug_var("Command", command); - int icommand_length = strlen(menus[men].icommand[bn]); - - char* copy_of_icommand = new char[icommand_length+1]; - strcpy(copy_of_icommand,menus[men].icommand[bn]); - - // On Windows the .exe suffix needs to be appended to the command - // whilst leaving any additional parameters unchanged - this - // is required to handle the correct conversion of cases such as : - // `../fluid/fluid valuators.fl' to '../fluid/fluid.exe valuators.fl'. - - // skip leading spaces. - char* start_command = copy_of_icommand; - while (*start_command == ' ') ++start_command; - - // find the space between the command and parameters if one exists. - char* start_parameters = strchr(start_command,' '); - - char* command = new char[icommand_length+6]; // 6 for extra 'd.exe\0' - - if (start_parameters==NULL) { // no parameters required. - sprintf(command, "%s%s", start_command, exe); - } else { // parameters required. - // break the start_command at the intermediate space between - // start_command and start_parameters. - *start_parameters = 0; - // move start_paremeters to skip over the intermediate space. - ++start_parameters; - - sprintf(command, "%s%s %s", start_command, exe, start_parameters); - } - - CreateProcess(NULL, command, NULL, NULL, FALSE, - NORMAL_PRIORITY_CLASS, NULL, NULL, &suInfo, &prInfo); - - delete[] command; - delete[] copy_of_icommand; + BOOL stat = CreateProcess(NULL, command, NULL, NULL, FALSE, + NORMAL_PRIORITY_CLASS, NULL, + NULL, &suInfo, &prInfo); + if (!stat) { + DWORD err = GetLastError(); + fl_alert("Error starting process, error #%d\n'%s'", err, command); + } #elif defined __APPLE__ - /* - Starting with version 1.4.0, FLTK uses CMake as the only supported build - system. On macOS, the app developer is expected to run CMake in a - directory named './build/Xcode' or './build/Makefiles' to generate the - build environment. - When building FLTK in the next step, teh macOS app bundles are then - stored in either: - './build/Xcode/bin/examples/hello.app/' for Makefiles - './build/Xcode/bin/examples/Debug/hello.app/' for XCode Debug - or - './build/Xcode/bin/examples/Release/hello.app/' as a symbolic - into the Archive system of macOS + debug_var("Command", command); + system(command); - 'Demo' needs to find and run all of these app bundles, some requiring - an additional file name and path for resource files. - This is my attempt to find the bundles and resources so that Demo.app - and all its dependencies will run without any further configuration. - They will stop running however if any of the bundles or rresources - are moved. - */ - { - char src_path[PATH_MAX]; - char app_path[PATH_MAX]; - char app_name[PATH_MAX]; - char command[2*PATH_MAX+2]; - char *cmd = strdup(menus[men].icommand[bn]); - char *args = strchr(cmd, ' '); +#else // other platforms (Unix, Linux) - /* - Get the path to the source code at compile time. This is where the other - resources are located. - */ - strcpy(src_path, __FILE__); - char *src_path_end = (char*)fl_filename_name(src_path); - if (src_path_end) *src_path_end = 0; + strcat(command, " &"); // run in background + debug_var("Command", command); - /* - All example app bundles are in the same directory as 'Demo', so set the - current dir to the location of Demo.app . - - Starting with macOS 10.12, the actual location of the app has a randomized - path to fix a vulnerability. This still works in Debug mode which is - */ - { - app_path[0] = 0; - CFBundleRef app = CFBundleGetMainBundle(); - CFURLRef url = CFBundleCopyBundleURL(app); - CFStringRef cc_app_path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); - CFRelease(url); - CFStringGetCString(cc_app_path, app_path, 2048, kCFStringEncodingUTF8); - CFRelease(cc_app_path); - if (app_path[0]) { - char *app_path_end = (char*)fl_filename_name(app_path); - if (app_path_end) *app_path_end = 0; - fl_chdir(app_path); - } - } - - // extract the executable name from the command in the menu file - strcpy(app_name, cmd); - // remove any additioanl command line arguments - if (args) app_name[args-cmd] = 0; - // make the file name into a bundle name - strcat(app_name, ".app"); - - if (args) { - if (strcmp(app_name, "../fluid/fluid.app")==0) { - // CMake -G 'Unix Makefiles' ... : ./bin/fluid.app - // CMake -G 'Xcode' ... : ./bin/Debug/fluid.app or ./bin/Release/fluid.app - // so removing the '/example' path segment from the app_path should - // always work. - char *examples = strstr(app_path, "/examples"); - if (examples) { - memmove(examples, examples+9, strlen(examples+9)+1); - } - sprintf(command, "open '%sfluid.app' --args '%s%s'", app_path, src_path, args+1); - } else { - // we assume that we have only one argument which is a filename, so we add a path - sprintf(command, "open '%s%s' --args '%s%s'", app_path, app_name, src_path, args+1); - } - } else { - sprintf(command, "open '%s%s'", app_path, app_name); - } - system(command); - free(cmd); - } - -#else // Non Windows systems. - - int icommand_length = strlen(menus[men].icommand[bn]); - char* command = new char[icommand_length+5]; // 5 for extra './' and ' &\0' - - sprintf(command, "./%s &", menus[men].icommand[bn]); - if (system(command)==-1) { /* ignore */ } - - delete[] command; + if (system(command) == -1) { + fl_alert("Could not start program, errno = %d\n'%s'", errno, command); + } #endif // _WIN32 - } + } void doback(Fl_Widget *, void *) {pop_menu();} void doexit(Fl_Widget *, void *) {exit(0);} -/* Load the menu file. Returns whether successful. */ -int load_the_menu(char* fname) { +/* + Load the menu file. Returns whether successful. + + New strategy: the menu file *should* be usable as is! + + Old strategy was: + + We have different situations: + + (1) Visual Studio: see main(): nothing to do + (2) Standard (autotools/make): nothing to do + (3) CMake: see main(): nothing to do + + (4) macOS: ??? *FIXME* +*/ +int load_the_menu(char *menu) { FILE *fin = 0; char line[256], mname[64],iname[64],cname[64]; int i, j; - fin = fl_fopen(fname,"r"); -#if defined ( __APPLE__ ) + + fin = fl_fopen(menu, "r"); + +// // *FIXME* Albrecht: Do we need this? I don't think so! +#if (0) // *FIXME* disabled for testing + +#if defined (__APPLE__) if (fin == NULL) { - // mac os bundle menu detection: - char* pos = strrchr(fname,'/'); + // macOS bundle menu detection: + char *pos = strrchr(menu, '/'); if (!pos) return 0; *pos = '\0'; - pos = strrchr(fname,'/'); + pos = strrchr(menu, '/'); if (!pos) return 0; - strcpy(pos,"/Resources/demo.menu"); - fin = fl_fopen(fname,"r"); + strcpy(pos, "/Resources/demo.menu"); + fin = fl_fopen(menu, "r"); } -#endif - if (fin == NULL) { +#endif // __APPLE __ + +#endif // *FIXME* disabled for testing + + if (fin == NULL) return 0; - } + for (;;) { if (fgets(line,256,fin) == NULL) break; // remove all carriage returns that Cygwin may have inserted @@ -436,32 +460,132 @@ int load_the_menu(char* fname) { return 1; } +// Fix '\' in Windows paths (convert to '/') and cut off filename (optional, default) +void fix_path(char *path, int strip_filename = 1) { + if (!path[0]) + return; +#ifdef _WIN32 // convert '\' to '/' + char *p = path; + while (*p) { + if (*p == '\\') + *p = '/'; + p++; + } +#endif // _WIN32 + if (strip_filename) { + char *pos = strrchr(path, '/'); + if (pos) + *pos = 0; + } +} + int main(int argc, char **argv) { - fl_putenv("FLTK_DOCDIR=../documentation/html"); - char buf[FL_PATH_MAX]; - strcpy(buf, argv[0]); -#if DEBUG_EXE_WITH_D - // MS_Visual Studio appends a 'd' to debugging executables. Remove it. - fl_filename_setext( buf, "" ); - buf[ strlen(buf)-1 ] = 0; + fl_putenv("FLTK_DOCDIR=../documentation/html"); // *FIXME* + + char menu[FL_PATH_MAX]; + + // construct app_path for all executable files + +#ifdef __APPLE__ + { + // Starting with macOS 10.12, the actual location of the app has a randomized + // path to fix a vulnerability. + // We need some "Apple magic" ;-) to find the actual path. + // Albrecht: is this (still) true and necessary? + + app_path[0] = 0; + CFBundleRef app = CFBundleGetMainBundle(); + CFURLRef url = CFBundleCopyBundleURL(app); + CFStringRef cc_app_path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + CFRelease(url); + CFStringGetCString(cc_app_path, app_path, 2048, kCFStringEncodingUTF8); + CFRelease(cc_app_path); + } +#else + fl_filename_absolute(app_path, sizeof(app_path), argv[0]); #endif - fl_filename_setext(buf,".menu"); - char *fname = buf; + fix_path(app_path); + + // construct src_path in case we want to use it (macOS ?) + +#if defined(GENERATED_BY_CMAKE) + strcpy(src_path, CMAKE_SOURCE_PATH); +#else + strcpy(src_path, app_path); +#endif + fix_path(src_path, 0); + + // fluid's path is the same for CMake builds but not for autoconf/make + + strcpy(fluid_path, app_path); + +#if !defined(GENERATED_BY_CMAKE) + fix_path(fluid_path); // removes folder name (test) + strcat(fluid_path, "/fluid"); +#endif + + // construct data_path for the menu file and all resources (data files) + // CMake: replace "/bin/*"" with "/data" + // autotools: use app_path directly + + strcpy(data_path, app_path); + +#if defined(GENERATED_BY_CMAKE) + { + char *pos = strstr(data_path, "/bin"); + if (pos) + strcpy(pos, "/data"); + } +#endif + + // construct the menu file name, optionally overridden by command args + // CMake: use data_path instead of app_path + + const char *fn = fl_filename_name(argv[0]); + +#if defined(GENERATED_BY_CMAKE) + strcpy(menu, data_path); +#else + strcpy(menu, app_path); +#endif + + // append "/.menu" + strcat(menu, "/"); + strcat(menu, fn); + fl_filename_setext(menu, sizeof(menu), ".menu"); + + // parse commandline + int i = 0; if (!Fl::args(argc,argv,i) || i < argc-1) - Fl::fatal("Usage: %s \n%s",argv[0],Fl::help); - if (i < argc) fname = argv[i]; + Fl::fatal("Usage: %s \n%s", argv[0], Fl::help); + if (i < argc) { + // override menu file *and* data path ! + fl_filename_absolute(menu, sizeof(menu), (const char *)argv[i]); + strcpy(data_path, menu); + fix_path(data_path); + } + +#if (DEBUG_VARS) + fprintf(stderr, "\n"); + debug_var("src_path", src_path); + debug_var("app_path", app_path); + debug_var("fluid_path", fluid_path); + debug_var("data_path", data_path); + debug_var("Menu file", menu); + fprintf(stderr, "\n"); +#endif // DEBUG_VARS create_the_forms(); - if (!load_the_menu(fname)) Fl::fatal("Can't open %s",fname); - if (buf != fname) - strcpy(buf,fname); - const char *c = fl_filename_name(buf); - if (c > buf) { - buf[c-buf] = 0; - if (fl_chdir(buf) == -1) { /* ignore */ } - } + // note: load_the_menu() *may* change the `menu` buffer contents ! + if (!load_the_menu(menu)) + Fl::fatal("Can't open %s", menu); + + // set current work directory to 'app_path' + + if (fl_chdir(data_path) == -1) { /* ignore */ } + push_menu("@main"); form->show(argc,argv); Fl::run(); diff --git a/test/demo.menu b/test/demo.menu index 2eedfb772..8b325cca6 100644 --- a/test/demo.menu +++ b/test/demo.menu @@ -58,7 +58,7 @@ @u:fast && slow widgets:fast_slow @u:inactive:inactive -@main:Fluid\n(UI design tool):../fluid/fluid valuators.fl +@main:Fluid\n(UI design tool):fluid valuators.fl @main:Cool\nDemos...:@e @e:X Color\nBrowser:colbrowser From 889ab6496260ce7ac1277f4391c050d1e35c21ab Mon Sep 17 00:00:00 2001 From: Greg Ercolano Date: Mon, 20 Jul 2020 11:43:47 -0700 Subject: [PATCH 2/3] Add Fl_Simple_Terminal for cross platform debugging --- test/demo.cxx | 97 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 21 deletions(-) diff --git a/test/demo.cxx b/test/demo.cxx index e02b81def..aab372c5a 100644 --- a/test/demo.cxx +++ b/test/demo.cxx @@ -60,8 +60,6 @@ help_dialog.html and related image files. */ -#define DEBUG_VARS (1) // 1 = output variables to stderr, 0 = no - #include #include #include @@ -75,10 +73,18 @@ #include #include #include +#include // right click popup menu #include +#include // tty #include #include #include // fl_alert() +#include // fl_getcwd() + +#define FORM_W 350 +#define FORM_H 440 +#define TTY_W int(FORM_W*2.5) +#define TTY_H 200 /* The form description */ @@ -89,7 +95,9 @@ void doscheme(Fl_Choice *c, void *) { Fl::scheme(c->text(c->value())); } -Fl_Double_Window *form; +Fl_Double_Window *form = 0; +Fl_Group *demogrp = 0; +Fl_Simple_Terminal *tty = 0; Fl_Button *but[9]; // Allocate space to edit commands and arguments from demo.menu. @@ -117,18 +125,51 @@ const char *suffix = ".app"; const char *suffix = ""; #endif -// debug output function (to stderr or ...) - +// debug output function void debug_var(const char *varname, const char *value) { -#if (DEBUG_VARS) - fprintf(stderr, "%-10s = '%s'\n", varname, value); - fflush(stderr); // Windows needs this -#endif // DEBUG_VARS + tty->printf("%-10s = '%s'\n", varname, value); +} + +// Show or hide the tty window +void show_tty(int val) { + if ( val ) { + form->size_range(FORM_W,FORM_H+TTY_H,0,0); // allow resizing + form->size(TTY_W,FORM_H+TTY_H); // demo + height for tty + demogrp->size(FORM_W,FORM_H); + tty->show(); // show tty + tty->resize(0, FORM_H, TTY_W, TTY_H); // force tty position + } else { + form->size_range(FORM_W,FORM_H,FORM_W,FORM_H); // no resizing + tty->hide(); // hide tty + form->size(FORM_W, FORM_H); // normal demo size + } + demogrp->size(FORM_W, FORM_H); + form->init_sizes(); +} + +// Right click popup menu handler +void popup_menu_cb(Fl_Widget*, void *userdata) { + const char *cmd = (const char*)userdata; + if ( strcmp(cmd, "showtty")==0 ) { show_tty(1); } + if ( strcmp(cmd, "hidetty")==0 ) { show_tty(0); } } void create_the_forms() { Fl_Widget *obj; - form = new Fl_Double_Window(350, 440); + Fl_Menu_Button *popup; + form = new Fl_Double_Window(FORM_W,FORM_H); + form->size_range(FORM_W,FORM_H,FORM_W+1,FORM_H+1); // XXX: +1 needed or window can't be made resizable later + // Small terminal window parented to window, not demogrp + tty = new Fl_Simple_Terminal(0, form->h(), form->w(), form->h()); + tty->history_lines(50); + tty->ansi(true); + tty->hide(); + tty->textsize(10); + // Parent group for demo + demogrp = new Fl_Group(0,0,FORM_W,FORM_H); + demogrp->resizable(0); + demogrp->begin(); + // Demo obj = new Fl_Box(FL_FRAME_BOX,10,15,330,40,"FLTK Demonstration"); obj->color(FL_GRAY-4); obj->labelsize(24); @@ -166,7 +207,16 @@ void create_the_forms() { but[i]->align(FL_ALIGN_WRAP); but[i]->callback(dobut, i); } + demogrp->end(); + // Right click popup menu + popup = new Fl_Menu_Button(0,0,FORM_W,FORM_H); + popup->box(FL_NO_BOX); + popup->type(Fl_Menu_Button::POPUP3); // pop menu on right-click + popup->add("Show debug terminal", 0, popup_menu_cb, (void*)"showtty"); + popup->add("Hide debug terminal", 0, popup_menu_cb, (void*)"hidetty"); + // End window form->end(); + form->resizable(tty); } /* Maintaining and building up the menus. */ @@ -359,12 +409,13 @@ void dobut(Fl_Widget *, long arg) { #elif defined __APPLE__ debug_var("Command", command); - system(command); + system(command); #else // other platforms (Unix, Linux) strcat(command, " &"); // run in background + debug_var("Command", command); if (system(command) == -1) { @@ -566,18 +617,22 @@ int main(int argc, char **argv) { fix_path(data_path); } -#if (DEBUG_VARS) - fprintf(stderr, "\n"); - debug_var("src_path", src_path); - debug_var("app_path", app_path); - debug_var("fluid_path", fluid_path); - debug_var("data_path", data_path); - debug_var("Menu file", menu); - fprintf(stderr, "\n"); -#endif // DEBUG_VARS - + // Create forms first + // tty needs to exist before we can print debug msgs + // create_the_forms(); + { + char cwd[1024]; + debug_var("src_path", src_path); + debug_var("app_path", app_path); + debug_var("fluid_path", fluid_path); + debug_var("data_path", data_path); + debug_var("Menu file", menu); + debug_var("Cwd", fl_getcwd(cwd,sizeof(cwd))); + tty->printf("\n"); + } + // note: load_the_menu() *may* change the `menu` buffer contents ! if (!load_the_menu(menu)) Fl::fatal("Can't open %s", menu); From 4957dd48c209bf6b635db5b4e131c1dba76f5e81 Mon Sep 17 00:00:00 2001 From: Albrecht Schlosser Date: Tue, 21 Jul 2020 00:50:25 +0200 Subject: [PATCH 3/3] Fix macOS code + remove obsolete code Albrecht: - move fl_chdir(data_path) up before fl_getcwd() prints it - add statements to open the argument (i.e. file) with data_path - update comments, remove obsolete code Greg: - on Mac we need absolute path for child filename parameters --- test/demo.cxx | 58 +++++++++++++-------------------------------------- 1 file changed, 14 insertions(+), 44 deletions(-) diff --git a/test/demo.cxx b/test/demo.cxx index aab372c5a..fa2b04bf4 100644 --- a/test/demo.cxx +++ b/test/demo.cxx @@ -49,9 +49,9 @@ build/bin/TYPE fluid, demo build/data demo.menu, working directory, data files - (4) CMake + macOS + Xcode - - *FIXME* special code to handle bundles: do we need this? + (4) macOS The setup is similar to Windows and Linux: + Makefiles: like (1) or (2) + Xcode: like (3), i.e. similar to VS layout The built executable 'demo' can also be executed with the menu filename as commandline argument. In this case all the support (data) files are @@ -371,8 +371,8 @@ void dobut(Fl_Widget *, long arg) { #if defined(__APPLE__) // macOS if (params[0]) { - // we assume that we have only one argument (which is a filename) - sprintf(command, "open '%s/%s%s' --args '%s'", path, cmdbuf, suffix, params); + // we assume that we have only one argument which is a filename in 'data_path' + sprintf(command, "open '%s/%s%s' --args '%s/%s'", path, cmdbuf, suffix, data_path, params); } else { sprintf(command, "open '%s/%s%s'", path, cmdbuf, suffix); } @@ -432,18 +432,6 @@ void doexit(Fl_Widget *, void *) {exit(0);} /* Load the menu file. Returns whether successful. - - New strategy: the menu file *should* be usable as is! - - Old strategy was: - - We have different situations: - - (1) Visual Studio: see main(): nothing to do - (2) Standard (autotools/make): nothing to do - (3) CMake: see main(): nothing to do - - (4) macOS: ??? *FIXME* */ int load_the_menu(char *menu) { FILE *fin = 0; @@ -452,24 +440,6 @@ int load_the_menu(char *menu) { fin = fl_fopen(menu, "r"); -// // *FIXME* Albrecht: Do we need this? I don't think so! -#if (0) // *FIXME* disabled for testing - -#if defined (__APPLE__) - if (fin == NULL) { - // macOS bundle menu detection: - char *pos = strrchr(menu, '/'); - if (!pos) return 0; - *pos = '\0'; - pos = strrchr(menu, '/'); - if (!pos) return 0; - strcpy(pos, "/Resources/demo.menu"); - fin = fl_fopen(menu, "r"); - } -#endif // __APPLE __ - -#endif // *FIXME* disabled for testing - if (fin == NULL) return 0; @@ -531,7 +501,8 @@ void fix_path(char *path, int strip_filename = 1) { } int main(int argc, char **argv) { - fl_putenv("FLTK_DOCDIR=../documentation/html"); // *FIXME* + + fl_putenv("FLTK_DOCDIR=../documentation/html"); // not sure if this is needed char menu[FL_PATH_MAX]; @@ -539,10 +510,9 @@ int main(int argc, char **argv) { #ifdef __APPLE__ { - // Starting with macOS 10.12, the actual location of the app has a randomized - // path to fix a vulnerability. - // We need some "Apple magic" ;-) to find the actual path. - // Albrecht: is this (still) true and necessary? + // Starting with macOS 10.12, the actual location of the app has a + // randomized path to fix a vulnerability. + // We need some "Apple magic" ;-) to find the actual app_path. app_path[0] = 0; CFBundleRef app = CFBundleGetMainBundle(); @@ -617,6 +587,10 @@ int main(int argc, char **argv) { fix_path(data_path); } + // set current work directory to 'app_path' + + if (fl_chdir(data_path) == -1) { /* ignore */ } + // Create forms first // tty needs to exist before we can print debug msgs // @@ -637,10 +611,6 @@ int main(int argc, char **argv) { if (!load_the_menu(menu)) Fl::fatal("Can't open %s", menu); - // set current work directory to 'app_path' - - if (fl_chdir(data_path) == -1) { /* ignore */ } - push_menu("@main"); form->show(argc,argv); Fl::run();