Merge pull request #111 - refactor test/demo.cxx
Simplify, clarify and fix bugs in test/demo.cxx As discussed and confirmed test/demo.cxx works now in all known and supported build systems.
This commit is contained in:
commit
b2ad5e4cfd
@ -15,8 +15,8 @@
|
|||||||
#
|
#
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
|
||||||
set (EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../bin/examples)
|
set (EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../bin)
|
||||||
set (TESTFILE_PATH ${EXECUTABLE_OUTPUT_PATH})
|
set (TESTFILE_PATH ${CMAKE_CURRENT_BINARY_DIR}/../data)
|
||||||
|
|
||||||
include (../CMake/FLTK-Functions.cmake)
|
include (../CMake/FLTK-Functions.cmake)
|
||||||
include (../CMake/fl_create_example.cmake)
|
include (../CMake/fl_create_example.cmake)
|
||||||
@ -204,13 +204,11 @@ endif (NOT ANDROID)
|
|||||||
|
|
||||||
# We need some support files for the demo programs:
|
# We need some support files for the demo programs:
|
||||||
|
|
||||||
# Note: this is incomplete as of 11 Feb 2015
|
# Note: this is incomplete as of July 2020
|
||||||
# Todo: currently all files are copied, but some of them need configuration:
|
# Todo: currently all files are copied, but some of them may need configuration:
|
||||||
# - demo.menu: fluid can't be started (wrong path)
|
|
||||||
# - demo.menu: help_dialog (help_dialog.html) can't find its images (not copied)
|
# - 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})
|
file (MAKE_DIRECTORY ${TESTFILE_PATH})
|
||||||
|
|
||||||
# copy the test files
|
# copy the test files
|
||||||
@ -221,13 +219,16 @@ file (COPY
|
|||||||
DESTINATION ${TESTFILE_PATH}
|
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
|
# Apple macOS creates bundles instead of executables and needs a little bit
|
||||||
# more help for demos to run correctly
|
# more help for demos to run correctly
|
||||||
|
|
||||||
if (APPLE AND (NOT OPTION_APPLE_X11) AND (NOT OPTION_APPLE_SDL))
|
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
|
# make the menu structure part of the app
|
||||||
target_sources (demo PRIVATE demo.menu)
|
target_sources (demo PRIVATE demo.menu)
|
||||||
set_target_properties (demo PROPERTIES MACOSX_BUNDLE TRUE RESOURCE demo.menu)
|
set_target_properties (demo PROPERTIES MACOSX_BUNDLE TRUE RESOURCE demo.menu)
|
||||||
|
519
test/demo.cxx
519
test/demo.cxx
@ -14,9 +14,56 @@
|
|||||||
// https://www.fltk.org/bugs.php
|
// 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) 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
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#if defined __APPLE__
|
#if defined __APPLE__
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
@ -26,24 +73,18 @@
|
|||||||
#include <FL/Fl_Double_Window.H>
|
#include <FL/Fl_Double_Window.H>
|
||||||
#include <FL/Fl_Box.H>
|
#include <FL/Fl_Box.H>
|
||||||
#include <FL/Fl_Button.H>
|
#include <FL/Fl_Button.H>
|
||||||
|
#include <FL/Fl_Menu_Button.H> // right click popup menu
|
||||||
#include <FL/Fl_Choice.H>
|
#include <FL/Fl_Choice.H>
|
||||||
|
#include <FL/Fl_Simple_Terminal.H> // tty
|
||||||
#include <FL/filename.H>
|
#include <FL/filename.H>
|
||||||
#include <FL/platform.H>
|
#include <FL/platform.H>
|
||||||
|
#include <FL/fl_ask.H> // fl_alert()
|
||||||
|
#include <FL/fl_utf8.h> // fl_getcwd()
|
||||||
|
|
||||||
/* Define a macro to decide whether a trailing 'd' needs to be removed
|
#define FORM_W 350
|
||||||
from the executable file name. Previous versions of Visual Studio
|
#define FORM_H 440
|
||||||
added a 'd' to the executable file name ('demod.exe') in Debug
|
#define TTY_W int(FORM_W*2.5)
|
||||||
configurations that needed to be removed.
|
#define TTY_H 200
|
||||||
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
|
|
||||||
|
|
||||||
/* The form description */
|
/* The form description */
|
||||||
|
|
||||||
@ -54,12 +95,81 @@ void doscheme(Fl_Choice *c, void *) {
|
|||||||
Fl::scheme(c->text(c->value()));
|
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];
|
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
|
||||||
|
void debug_var(const char *varname, const char *value) {
|
||||||
|
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() {
|
void create_the_forms() {
|
||||||
Fl_Widget *obj;
|
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 = new Fl_Box(FL_FRAME_BOX,10,15,330,40,"FLTK Demonstration");
|
||||||
obj->color(FL_GRAY-4);
|
obj->color(FL_GRAY-4);
|
||||||
obj->labelsize(24);
|
obj->labelsize(24);
|
||||||
@ -97,7 +207,16 @@ void create_the_forms() {
|
|||||||
but[i]->align(FL_ALIGN_WRAP);
|
but[i]->align(FL_ALIGN_WRAP);
|
||||||
but[i]->callback(dobut, i);
|
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->end();
|
||||||
|
form->resizable(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Maintaining and building up the menus. */
|
/* Maintaining and building up the menus. */
|
||||||
@ -214,190 +333,116 @@ void dobut(Fl_Widget *, long arg) {
|
|||||||
int men = find_menu(stack[stsize-1]);
|
int men = find_menu(stack[stsize-1]);
|
||||||
int n = menus[men].numb;
|
int n = menus[men].numb;
|
||||||
int bn = but2numb( (int) arg, n-1);
|
int bn = but2numb( (int) arg, n-1);
|
||||||
|
|
||||||
|
// menu ?
|
||||||
|
|
||||||
if (menus[men].icommand[bn][0] == '@') {
|
if (menus[men].icommand[bn][0] == '@') {
|
||||||
push_menu(menus[men].icommand[bn]);
|
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 {
|
} 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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
#ifdef _WIN32
|
||||||
|
|
||||||
STARTUPINFO suInfo; // Process startup information
|
STARTUPINFO suInfo; // Process startup information
|
||||||
PROCESS_INFORMATION prInfo; // Process 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));
|
memset(&suInfo, 0, sizeof(suInfo));
|
||||||
suInfo.cb = sizeof(suInfo);
|
suInfo.cb = sizeof(suInfo);
|
||||||
|
|
||||||
int icommand_length = strlen(menus[men].icommand[bn]);
|
debug_var("Command", command);
|
||||||
|
|
||||||
char* copy_of_icommand = new char[icommand_length+1];
|
BOOL stat = CreateProcess(NULL, command, NULL, NULL, FALSE,
|
||||||
strcpy(copy_of_icommand,menus[men].icommand[bn]);
|
NORMAL_PRIORITY_CLASS, NULL,
|
||||||
|
NULL, &suInfo, &prInfo);
|
||||||
// On Windows the .exe suffix needs to be appended to the command
|
if (!stat) {
|
||||||
// whilst leaving any additional parameters unchanged - this
|
DWORD err = GetLastError();
|
||||||
// is required to handle the correct conversion of cases such as :
|
fl_alert("Error starting process, error #%d\n'%s'", err, command);
|
||||||
// `../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;
|
|
||||||
|
|
||||||
#elif defined __APPLE__
|
#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
|
debug_var("Command", command);
|
||||||
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
|
|
||||||
|
|
||||||
'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, ' ');
|
|
||||||
|
|
||||||
/*
|
|
||||||
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;
|
|
||||||
|
|
||||||
/*
|
|
||||||
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);
|
system(command);
|
||||||
free(cmd);
|
|
||||||
|
#else // other platforms (Unix, Linux)
|
||||||
|
|
||||||
|
strcat(command, " &"); // run in background
|
||||||
|
|
||||||
|
debug_var("Command", command);
|
||||||
|
|
||||||
|
if (system(command) == -1) {
|
||||||
|
fl_alert("Could not start program, errno = %d\n'%s'", errno, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void doback(Fl_Widget *, void *) {pop_menu();}
|
void doback(Fl_Widget *, void *) {pop_menu();}
|
||||||
|
|
||||||
void doexit(Fl_Widget *, void *) {exit(0);}
|
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.
|
||||||
|
*/
|
||||||
|
int load_the_menu(char *menu) {
|
||||||
FILE *fin = 0;
|
FILE *fin = 0;
|
||||||
char line[256], mname[64],iname[64],cname[64];
|
char line[256], mname[64],iname[64],cname[64];
|
||||||
int i, j;
|
int i, j;
|
||||||
fin = fl_fopen(fname,"r");
|
|
||||||
#if defined ( __APPLE__ )
|
fin = fl_fopen(menu, "r");
|
||||||
if (fin == NULL) {
|
|
||||||
// mac os bundle menu detection:
|
if (fin == NULL)
|
||||||
char* pos = strrchr(fname,'/');
|
|
||||||
if (!pos) return 0;
|
|
||||||
*pos = '\0';
|
|
||||||
pos = strrchr(fname,'/');
|
|
||||||
if (!pos) return 0;
|
|
||||||
strcpy(pos,"/Resources/demo.menu");
|
|
||||||
fin = fl_fopen(fname,"r");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (fin == NULL) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (fgets(line,256,fin) == NULL) break;
|
if (fgets(line,256,fin) == NULL) break;
|
||||||
// remove all carriage returns that Cygwin may have inserted
|
// remove all carriage returns that Cygwin may have inserted
|
||||||
@ -436,32 +481,136 @@ int load_the_menu(char* fname) {
|
|||||||
return 1;
|
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) {
|
int main(int argc, char **argv) {
|
||||||
fl_putenv("FLTK_DOCDIR=../documentation/html");
|
|
||||||
char buf[FL_PATH_MAX];
|
fl_putenv("FLTK_DOCDIR=../documentation/html"); // not sure if this is needed
|
||||||
strcpy(buf, argv[0]);
|
|
||||||
#if DEBUG_EXE_WITH_D
|
char menu[FL_PATH_MAX];
|
||||||
// MS_Visual Studio appends a 'd' to debugging executables. Remove it.
|
|
||||||
fl_filename_setext( buf, "" );
|
// construct app_path for all executable files
|
||||||
buf[ strlen(buf)-1 ] = 0;
|
|
||||||
|
#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 app_path.
|
||||||
|
|
||||||
|
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
|
#endif
|
||||||
fl_filename_setext(buf,".menu");
|
fix_path(app_path);
|
||||||
char *fname = buf;
|
|
||||||
|
// 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 "/<exe-file-name>.menu"
|
||||||
|
strcat(menu, "/");
|
||||||
|
strcat(menu, fn);
|
||||||
|
fl_filename_setext(menu, sizeof(menu), ".menu");
|
||||||
|
|
||||||
|
// parse commandline
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
if (!Fl::args(argc,argv,i) || i < argc-1)
|
if (!Fl::args(argc,argv,i) || i < argc-1)
|
||||||
Fl::fatal("Usage: %s <switches> <menufile>\n%s", argv[0], Fl::help);
|
Fl::fatal("Usage: %s <switches> <menufile>\n%s", argv[0], Fl::help);
|
||||||
if (i < argc) fname = argv[i];
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
create_the_forms();
|
create_the_forms();
|
||||||
|
|
||||||
if (!load_the_menu(fname)) Fl::fatal("Can't open %s",fname);
|
{
|
||||||
if (buf != fname)
|
char cwd[1024];
|
||||||
strcpy(buf,fname);
|
debug_var("src_path", src_path);
|
||||||
const char *c = fl_filename_name(buf);
|
debug_var("app_path", app_path);
|
||||||
if (c > buf) {
|
debug_var("fluid_path", fluid_path);
|
||||||
buf[c-buf] = 0;
|
debug_var("data_path", data_path);
|
||||||
if (fl_chdir(buf) == -1) { /* ignore */ }
|
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);
|
||||||
|
|
||||||
push_menu("@main");
|
push_menu("@main");
|
||||||
form->show(argc,argv);
|
form->show(argc,argv);
|
||||||
Fl::run();
|
Fl::run();
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
@u:fast && slow widgets:fast_slow
|
@u:fast && slow widgets:fast_slow
|
||||||
@u:inactive:inactive
|
@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
|
@main:Cool\nDemos...:@e
|
||||||
@e:X Color\nBrowser:colbrowser
|
@e:X Color\nBrowser:colbrowser
|
||||||
|
Loading…
Reference in New Issue
Block a user