Commit d0c3e28a authored by Hanspeter Portner's avatar Hanspeter Portner

simple_ui: reimplementation of external editor ui.

parent b54b8c6a
Pipeline #13056214 passed with stages
in 5 minutes and 18 seconds
......@@ -7,6 +7,7 @@ include_directories(${PROJECT_SOURCE_DIR}/tlsf-3.0)
include_directories(${PROJECT_SOURCE_DIR}/osc.lv2)
include_directories(${PROJECT_SOURCE_DIR}/timely.lv2)
include_directories(${PROJECT_SOURCE_DIR}/xpress.lv2)
include_directories(${PROJECT_SOURCE_DIR}/ext_ui.lv2)
include_directories(${PROJECT_SOURCE_DIR}/lua-5.3.4)
include_directories(${PROJECT_SOURCE_DIR}/tiny-AES128-C)
include_directories(${PROJECT_SOURCE_DIR}/laes128)
......@@ -74,10 +75,19 @@ option(BUILD_UI "Build UI" ON)
option(USE_MANUAL_GC "Use manual garbage collection" ON)
option(USE_CODE_COVERAGE "Use code coverage" OFF)
include(CMakeDependentOption)
cmake_dependent_option(ENABLE_EXTERNAL_EDITOR "Enable external editor" OFF "BUILD_UI" OFF)
if(USE_MANUAL_GC)
add_definitions("-DUSE_MANUAL_GC")
endif()
if(ENABLE_EXTERNAL_EDITOR)
# nothing
else()
set(UI_EXT "#")
endif()
if(BUILD_UI)
set(LIBS_UI ${LIBS_UI} m)
......@@ -142,8 +152,9 @@ if(BUILD_UI)
endif()
add_library(moony_ui MODULE
plugin/moony_nk.c
plugin/moony_ui.c
plugin/nk_ui.c
plugin/simple_ui.c
${TAR_UI}
$<TARGET_OBJECTS:lua>
$<TARGET_OBJECTS:lpeg>)
......
/*
LV2 External UI extension
This work is in public domain.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
If you have questions, contact Filipe Coelho (aka falkTX) <falktx@falktx.com>
or ask in #lad channel, FreeNode IRC network.
*/
/**
@file lv2_external_ui.h
C header for the LV2 External UI extension <http://kxstudio.sf.net/ns/lv2ext/external-ui>.
*/
#ifndef LV2_EXTERNAL_UI_H
#define LV2_EXTERNAL_UI_H
#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
#define LV2_EXTERNAL_UI_URI "http://kxstudio.sf.net/ns/lv2ext/external-ui"
#define LV2_EXTERNAL_UI_PREFIX LV2_EXTERNAL_UI_URI "#"
#define LV2_EXTERNAL_UI__Host LV2_EXTERNAL_UI_PREFIX "Host"
#define LV2_EXTERNAL_UI__Widget LV2_EXTERNAL_UI_PREFIX "Widget"
/** This extension used to be defined by a lv2plug.in URI */
#define LV2_EXTERNAL_UI_DEPRECATED_URI "http://lv2plug.in/ns/extensions/ui#external"
#ifdef __cplusplus
extern "C" {
#endif
/**
* When LV2_EXTERNAL_UI__Widget UI is instantiated, the returned
* LV2UI_Widget handle must be cast to pointer to LV2_External_UI_Widget.
* UI is created in invisible state.
*/
typedef struct _LV2_External_UI_Widget {
/**
* Host calls this function regulary. UI library implementing the
* callback may do IPC or redraw the UI.
*
* @param _this_ the UI context
*/
void (*run)(struct _LV2_External_UI_Widget * _this_);
/**
* Host calls this function to make the plugin UI visible.
*
* @param _this_ the UI context
*/
void (*show)(struct _LV2_External_UI_Widget * _this_);
/**
* Host calls this function to make the plugin UI invisible again.
*
* @param _this_ the UI context
*/
void (*hide)(struct _LV2_External_UI_Widget * _this_);
} LV2_External_UI_Widget;
#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr)
#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr)
#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr)
/**
* On UI instantiation, host must supply LV2_EXTERNAL_UI__Host feature.
* LV2_Feature::data must be pointer to LV2_External_UI_Host.
*/
typedef struct _LV2_External_UI_Host {
/**
* Callback that plugin UI will call when UI (GUI window) is closed by user.
* This callback will be called during execution of LV2_External_UI_Widget::run()
* (i.e. not from background thread).
*
* After this callback is called, UI is defunct. Host must call LV2UI_Descriptor::cleanup().
* If host wants to make the UI visible again, the UI must be reinstantiated.
*
* @note When using the depreated URI LV2_EXTERNAL_UI_DEPRECATED_URI,
* some hosts will not call LV2UI_Descriptor::cleanup() as they should,
* and may call show() again without re-initialization.
*
* @param controller Host context associated with plugin UI, as
* supplied to LV2UI_Descriptor::instantiate().
*/
void (*ui_closed)(LV2UI_Controller controller);
/**
* Optional (may be NULL) "user friendly" identifier which the UI
* may display to allow a user to easily associate this particular
* UI instance with the correct plugin instance as it is represented
* by the host (e.g. "track 1" or "channel 4").
*
* If supplied by host, the string will be referenced only during
* LV2UI_Descriptor::instantiate()
*/
const char * plugin_human_id;
} LV2_External_UI_Host;
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV2_EXTERNAL_UI_H */
......@@ -93,6 +93,8 @@
#define MOONY_PARAM_ROWS_URI MOONY_URI"#paramRows"
#define MOONY_NK_URI MOONY_URI"#moony_ui"
#define MOONY_SIMPLE_UI_URI MOONY_URI"#moony_zimple_ui"
#define MOONY_SIMPLE_KX_URI MOONY_URI"#moony_zimple_kx"
#define MOONY_C1XC1_URI MOONY_URI"#c1xc1"
#define MOONY_C2XC2_URI MOONY_URI"#c2xc2"
......@@ -121,6 +123,8 @@ extern const LV2_Descriptor c2a1xc2a1;
extern const LV2_Descriptor c4a1xc4a1;
extern const LV2UI_Descriptor nk_ui;
extern const LV2UI_Descriptor simple_ui;
extern const LV2UI_Descriptor simple_kx;
typedef enum _moony_udata_t {
MOONY_UDATA_ATOM,
......
......@@ -36,6 +36,8 @@ moony:c1xc1
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
moony:c2xc2
......@@ -44,6 +46,8 @@ moony:c2xc2
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
moony:c4xc4
......@@ -52,6 +56,8 @@ moony:c4xc4
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
# atom in, atom out
......@@ -61,6 +67,8 @@ moony:a1xa1
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
moony:a2xa2
......@@ -69,6 +77,8 @@ moony:a2xa2
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
moony:a4xa4
......@@ -77,6 +87,8 @@ moony:a4xa4
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
# control/atom in, control/atom out
......@@ -86,6 +98,8 @@ moony:c1a1xc1a1
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
moony:c2a1xc2a1
......@@ -94,6 +108,8 @@ moony:c2a1xc2a1
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
moony:c4a1xc4a1
......@@ -102,6 +118,8 @@ moony:c4a1xc4a1
lv2:microVersion @MOONY_MICRO_VERSION@ ;
lv2:binary <moony@CMAKE_SHARED_MODULE_SUFFIX@> ;
@UI_WRAP@ui:ui moony:moony_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_ui ;
@UI_WRAP@@UI_EXT@ui:ui moony:moony_zimple_kx ;
rdfs:seeAlso <moony.ttl> .
# UI
......@@ -109,6 +127,14 @@ moony:moony_ui
a ui:@MOONY_UI_TYPE@ ;
ui:binary <moony_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
rdfs:seeAlso <moony_ui.ttl> .
moony:moony_zimple_ui
a ui:UI ;
ui:binary <moony_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
rdfs:seeAlso <moony_ui.ttl> .
moony:moony_zimple_kx
a kx:Widget ;
ui:binary <moony_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
rdfs:seeAlso <moony_ui.ttl> .
# Banks
moony:bank-through
......
......@@ -29,6 +29,10 @@ lv2ui_descriptor(uint32_t index)
{
case 0:
return &nk_ui;
case 1:
return &simple_ui;
case 2:
return &simple_kx;
default:
return NULL;
}
......
......@@ -63,3 +63,84 @@ moony:moony_ui
lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map, urid:unmap ;
lv2:optionalFeature ui:resize ;
lv2:extensionData ui:idleInterface, ui:resize .
moony:moony_zimple_ui
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature ui:idleInterface, ui:portMap, urid:map, urid:unmap ;
lv2:extensionData ui:idleInterface, ui:showInterface .
moony:moony_zimple_kx
ui:portNotification [
ui:plugin moony:c1xc1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2xc2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4xc4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a1xa1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a2xa2 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:a4xa4 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c1a1xc1a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c2a1xc2a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] , [
ui:plugin moony:c4a1xc4a1 ;
lv2:symbol "notify" ;
ui:protocol atom:eventTransfer ;
] ;
lv2:requiredFeature kx:Host , ui:portMap, urid:map, urid:unmap .
/*
* Copyright (c) 2015-2017 Hanspeter Portner (dev@open-music-kontrollers.ch)
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the Artistic License 2.0 as published by
* The Perl Foundation.
*
* This source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Artistic License 2.0 for more details.
*
* You should have received a copy of the Artistic License 2.0
* along the source as a COPYING file. If not, obtain it from
* http://www.perlfoundation.org/artistic_license_2_0.
*/
#ifndef _MOONY_COMMON_UI_H
#define _MOONY_COMMON_UI_H
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#if !defined(_WIN32)
# include <sys/wait.h>
# include <signal.h>
#else
# include <fcntl.h>
# include <sys/stat.h>
# include <windows.h>
#endif
#include <lv2/lv2plug.in/ns/ext/log/logger.h>
typedef struct _spawn_t spawn_t;
struct _spawn_t {
#if defined(_WIN32)
PROCESS_INFORMATION pi;
#else
pid_t pid;
#endif
LV2_Log_Logger *logger;
};
static inline char **
_spawn_parse_env(char *env, char *path)
{
unsigned n = 0;
char **args = malloc((n+1) * sizeof(char *));
char **oldargs = NULL;
if(!args)
goto fail;
args[n] = NULL;
char *pch = strtok(env," \t");
while(pch)
{
args[n++] = pch;
oldargs = args;
args = realloc(args, (n+1) * sizeof(char *));
if(!args)
goto fail;
oldargs = NULL;
args[n] = NULL;
pch = strtok(NULL, " \t");
}
args[n++] = path;
oldargs = args;
args = realloc(args, (n+1) * sizeof(char *));
if(!args)
goto fail;
oldargs = NULL;
args[n] = NULL;
return args;
fail:
if(oldargs)
free(oldargs);
if(args)
free(args);
return 0;
}
#if defined(_WIN32)
static inline int
_spawn_spawn(spawn_t *spawn, char **args)
{
STARTUPINFO si;
memset(&si, 0x0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
size_t len = 0;
for(char **arg = args; *arg; arg++)
{
len += strlen(*arg) + 1; // + space
}
char *cmd = malloc(len + 1); // + zero byte
if(!cmd)
return -1;
cmd[0] = '\0';
for(char **arg = args; *arg; arg++)
{
cmd = strcat(cmd, *arg);
cmd = strcat(cmd, " ");
}
int ret = 0;
if(!CreateProcess(
NULL, // No module name (use command line)
cmd, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&spawn->pi ) // Pointer to PROCESS_INFORMATION structure
)
{
if(spawn->logger)
lv2_log_error(spawn->logger, "CreateProcess failed: %d\n", GetLastError());
ret = -1;
}
free(cmd);
return ret;
}
static inline int
_spawn_waitpid(spawn_t *spawn, bool blocking)
{
if(blocking)
{
WaitForSingleObject(spawn->pi.hProcess, INFINITE);
return 0;
}
// !blocking
const DWORD status = WaitForSingleObject(spawn->pi.hProcess, 0);
switch(WaitForSingleObject(spawn->pi.hProcess, 0))
{
case WAIT_TIMEOUT: // non-signaled, e.g. still running
return 0;
case WAIT_OBJECT_0: // signaled, e.g. not running anymore
return -1;
case WAIT_ABANDONED: // abandoned
if(spawn->logger)
lv2_log_note(spawn->logger, "WaitForSingleObject abandoned\n");
return -1;
case WAIT_FAILED: // failed, try later
if(spawn->logger)
lv2_log_note(spawn->logger, "WaitForSingleObject failed\n");
return 0;
}
return 0; // try later
}
static inline void
_spawn_kill(spawn_t *spawn)
{
CloseHandle(spawn->pi.hProcess);
CloseHandle(spawn->pi.hThread);
}
static inline bool
_spawn_has_child(spawn_t *spawn)
{
return (spawn->pi.hProcess != 0x0) && (spawn->pi.hThread != 0x0);
}
static inline void
_spawn_invalidate_child(spawn_t *spawn)
{
memset(&spawn->pi, 0x0, sizeof(PROCESS_INFORMATION));
}
#else // UNICES
static inline int
_spawn_spawn(spawn_t *spawn, char **args)
{
if(!args)
{
if(spawn->logger)
lv2_log_error(spawn->logger, "nil argument list\n");
return -1;
}
spawn->pid = fork();
if(spawn->pid == 0) // child
{
execvp(args[0], args); // p = search PATH for executable
if(spawn->logger)
lv2_log_error(spawn->logger, "execvp failed\n");
exit(-1);
}
else if(spawn->pid < 0)
{
if(spawn->logger)
lv2_log_error(spawn->logger, "fork failed\n");
return -1;
}
return 0; // fork succeeded
}
static inline int
_spawn_waitpid(spawn_t *spawn, bool blocking)
{
int status;
int res;
if(blocking)
{
waitpid(spawn->pid, &status, WUNTRACED); // blocking waitpid
return 0;
}
// !blocking
if( (res = waitpid(spawn->pid, &status, WUNTRACED | WNOHANG)) < 0)
{
if(errno == ECHILD) // child not existing
{
if(spawn->logger)
lv2_log_note(spawn->logger, "waitpid child not existing\n");
return -1;
}
}
else if(res == spawn->pid) // status change
{
if(!WIFSTOPPED(status) && !WIFCONTINUED(status)) // has actually exited, not only stopped
return -1;
}
return 0; // no status change, still running
}
static inline void
_spawn_kill(spawn_t *spawn)
{
kill(spawn->pid, SIGTERM);
}
static inline bool
_spawn_has_child(spawn_t *spawn)
{
return spawn->pid > 0;
}
static inline void
_spawn_invalidate_child(spawn_t *spawn)
{
spawn->pid = -1;
}
#endif
#if defined(_WIN32)
static int
_mkstemp_init(char *__template, char **suffix, size_t *length, DWORD *val,
size_t suffixlen)
{
*length = strlen(__template);
if ((*length < (6 + suffixlen))
|| (strncmp(__template + *length - 6 - suffixlen, "XXXXXX", 6) != 0))
{
errno = EINVAL;
return 0;
}
*suffix = __template + *length - 6 - suffixlen;
*val = GetTickCount();
*val += GetCurrentProcessId();
return 1;
}
static int
_mkstemp(char *suffix, int val)
{
const char lookup[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
DWORD v = val;
suffix[0] = lookup[v % 62];
v /= 62;
suffix[1] = lookup[v % 62];
v /= 62;
suffix[2] = lookup[v % 62];
v /= 62;
suffix[3] = lookup[v % 62];
v /= 62;
suffix[4] = lookup[v % 62];
v /= 62;
suffix[5] = lookup[v % 62];
v /= 62;
val += 7777;
return val;
}
static int
mkstemps(char *__template, int suffixlen)
{
char *suffix;
DWORD val;
size_t length;
int i;
if (!__template || (suffixlen < 0))
return 0;
if (!_mkstemp_init(__template, &suffix, &length, &val, (size_t) suffixlen))
return -1;
for (i = 0; i < 32768; i++)
{
int fd;
val = _mkstemp(suffix, val);
fd = open(__template, _O_RDWR | _O_BINARY | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
if (fd >= 0)
return fd;
}
errno = EEXIST;
return -1;
}
#endif
#endif
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment