Signed-off-by: falkTX <falktx@falktx.com>pull/272/head
@@ -265,7 +265,7 @@ endif | |||||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ||||
ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) | |||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | |||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | ||||
ifeq ($(HAVE_XCURSOR),true) | ifeq ($(HAVE_XCURSOR),true) | ||||
# TODO -DHAVE_XCURSOR | # TODO -DHAVE_XCURSOR | ||||
@@ -50,6 +50,60 @@ class TopLevelWidget; | |||||
class Window | class Window | ||||
{ | { | ||||
public: | public: | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
/** | |||||
File browser options. | |||||
@see Window::openFileBrowser | |||||
*/ | |||||
struct FileBrowserOptions { | |||||
/** | |||||
File browser button state. | |||||
This allows to customize the behaviour of the file browse dialog buttons. | |||||
*/ | |||||
enum ButtonState { | |||||
kButtonInvisible, | |||||
kButtonVisibleUnchecked, | |||||
kButtonVisibleChecked, | |||||
}; | |||||
/** Start directory, uses current working directory if null */ | |||||
const char* startDir; | |||||
/** File browser dialog window title, uses "FileBrowser" if null */ | |||||
const char* title; | |||||
/** File browser dialog window width */ | |||||
uint width; | |||||
/** File browser dialog window height */ | |||||
uint height; | |||||
// TODO file filter | |||||
/** | |||||
File browser buttons. | |||||
*/ | |||||
struct Buttons { | |||||
/** Whether to list all files vs only those with matching file extension */ | |||||
ButtonState listAllFiles; | |||||
/** Whether to show hidden files */ | |||||
ButtonState showHidden; | |||||
/** Whether to show list of places (bookmarks) */ | |||||
ButtonState showPlaces; | |||||
/** Constuctor for default values */ | |||||
Buttons() | |||||
: listAllFiles(kButtonVisibleChecked), | |||||
showHidden(kButtonVisibleUnchecked), | |||||
showPlaces(kButtonVisibleUnchecked) {} | |||||
} buttons; | |||||
/** Constuctor for default values */ | |||||
FileBrowserOptions() | |||||
: startDir(nullptr), | |||||
title(nullptr), | |||||
width(0), | |||||
height(0), | |||||
buttons() {} | |||||
}; | |||||
#endif // DGL_FILE_BROWSER_DISABLED | |||||
/** | /** | ||||
Constructor for a regular, standalone window. | Constructor for a regular, standalone window. | ||||
*/ | */ | ||||
@@ -130,7 +184,18 @@ public: | |||||
*/ | */ | ||||
void close(); | void close(); | ||||
/** | |||||
Check if this window is resizable. | |||||
@see setResizable | |||||
*/ | |||||
bool isResizable() const noexcept; | bool isResizable() const noexcept; | ||||
/** | |||||
Set window as resizable (by the user or window manager). | |||||
It is always possible to resize a window programmatically, which is not the same as the user being allowed to it. | |||||
@note This function does nothing for plugins, where the resizable state is set via macro. | |||||
@see DISTRHO_UI_USER_RESIZABLE | |||||
*/ | |||||
void setResizable(bool resizable); | void setResizable(bool resizable); | ||||
/** | /** | ||||
@@ -247,6 +312,17 @@ public: | |||||
*/ | */ | ||||
void focus(); | void focus(); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
/** | |||||
Open a file browser dialog with this window as parent. | |||||
A few options can be specified to setup the dialog. | |||||
This function does not block. | |||||
If a path is selected, onFileSelected() will be called with the user chosen path. | |||||
*/ | |||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
#endif | |||||
/** | /** | ||||
Request repaint of this window, for the entire area. | Request repaint of this window, for the entire area. | ||||
*/ | */ | ||||
@@ -272,16 +348,15 @@ public: | |||||
bool keepAspectRatio = false, | bool keepAspectRatio = false, | ||||
bool automaticallyScale = false); | bool automaticallyScale = false); | ||||
/* | |||||
void setTransientWinId(uintptr_t winId); | |||||
*/ | |||||
/** DEPRECATED Use isIgnoringKeyRepeat(). */ | |||||
DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | ||||
inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | ||||
/** DEPRECATED Use getScaleFactor(). */ | |||||
DISTRHO_DEPRECATED_BY("getScaleFactor()") | DISTRHO_DEPRECATED_BY("getScaleFactor()") | ||||
inline double getScaling() const noexcept { return getScaleFactor(); } | inline double getScaling() const noexcept { return getScaleFactor(); } | ||||
/** DEPRECATED Use runAsModal(bool). */ | |||||
DISTRHO_DEPRECATED_BY("runAsModal(bool)") | DISTRHO_DEPRECATED_BY("runAsModal(bool)") | ||||
inline void exec(bool blockWait = false) { runAsModal(blockWait); } | inline void exec(bool blockWait = false) { runAsModal(blockWait); } | ||||
@@ -302,9 +377,23 @@ protected: | |||||
/** | /** | ||||
A function called when the window is resized. | A function called when the window is resized. | ||||
If there is a top-level widget associated with this window, its size will be set right after this function. | If there is a top-level widget associated with this window, its size will be set right after this function. | ||||
The default implementation sets up drawing context where necessary. | |||||
*/ | */ | ||||
virtual void onReshape(uint width, uint height); | virtual void onReshape(uint width, uint height); | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
/** | |||||
A function called when a path is selected by the user, as triggered by openFileBrowser(). | |||||
This action happens after the user confirms the action, so the file browser dialog will be closed at this point. | |||||
The default implementation does nothing. | |||||
*/ | |||||
virtual void onFileSelected(const char* filename); | |||||
/** DEPRECATED Use onFileSelected(). */ | |||||
DISTRHO_DEPRECATED_BY("onFileSelected(const char*)") | |||||
inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); } | |||||
#endif | |||||
private: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
@@ -319,62 +408,10 @@ private: | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
/* TODO | /* TODO | ||||
* add focusEvent with CrossingMode arg | |||||
* add eventcrossing/enter-leave event | * add eventcrossing/enter-leave event | ||||
*/ | */ | ||||
#if 0 | #if 0 | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
/** | |||||
File browser options. | |||||
*/ | |||||
struct FileBrowserOptions { | |||||
const char* startDir; | |||||
const char* title; | |||||
uint width; | |||||
uint height; | |||||
/** | |||||
File browser buttons. | |||||
0 means hidden. | |||||
1 means visible and unchecked. | |||||
2 means visible and checked. | |||||
*/ | |||||
struct Buttons { | |||||
uint listAllFiles; | |||||
uint showHidden; | |||||
uint showPlaces; | |||||
/** Constuctor for default values */ | |||||
Buttons() | |||||
: listAllFiles(2), | |||||
showHidden(1), | |||||
showPlaces(1) {} | |||||
} buttons; | |||||
/** Constuctor for default values */ | |||||
FileBrowserOptions() | |||||
: startDir(nullptr), | |||||
title(nullptr), | |||||
width(0), | |||||
height(0), | |||||
buttons() {} | |||||
}; | |||||
#endif // DGL_FILE_BROWSER_DISABLED | |||||
void addIdleCallback(IdleCallback* const callback); | |||||
void removeIdleCallback(IdleCallback* const callback); | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
#endif | |||||
protected: | protected: | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
virtual void fileBrowserSelected(const char* filename); | |||||
#endif | |||||
bool handlePluginKeyboard(const bool press, const uint key); | bool handlePluginKeyboard(const bool press, const uint key); | ||||
bool handlePluginSpecial(const bool press, const Key key); | bool handlePluginSpecial(const bool press, const Key key); | ||||
#endif | #endif | ||||
@@ -201,6 +201,13 @@ void Window::focus() | |||||
pData->focus(); | pData->focus(); | ||||
} | } | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
bool Window::openFileBrowser(const FileBrowserOptions& options) | |||||
{ | |||||
return pData->openFileBrowser(options); | |||||
} | |||||
#endif | |||||
void Window::repaint() noexcept | void Window::repaint() noexcept | ||||
{ | { | ||||
puglPostRedisplay(pData->view); | puglPostRedisplay(pData->view); | ||||
@@ -271,51 +278,20 @@ void Window::onReshape(uint, uint) | |||||
puglFallbackOnResize(pData->view); | puglFallbackOnResize(pData->view); | ||||
} | } | ||||
#if 0 | |||||
void Window::setTransientWinId(const uintptr_t winId) | |||||
{ | |||||
puglSetTransientFor(pData->fView, winId); | |||||
} | |||||
void Window::_addWidget(Widget* const widget) | |||||
{ | |||||
pData->addWidget(widget); | |||||
} | |||||
void Window::_removeWidget(Widget* const widget) | |||||
{ | |||||
pData->removeWidget(widget); | |||||
} | |||||
void Window::_idle() | |||||
{ | |||||
pData->windowSpecificIdle(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void Window::addIdleCallback(IdleCallback* const callback) | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
void Window::onFileSelected(const char*) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||||
pData->fAppData->idleCallbacks.push_back(callback); | |||||
} | } | ||||
#endif | |||||
void Window::removeIdleCallback(IdleCallback* const callback) | |||||
#if 0 | |||||
void Window::setTransientWinId(const uintptr_t winId) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||||
pData->fAppData->idleCallbacks.remove(callback); | |||||
puglSetTransientFor(pData->view, winId); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
void Window::fileBrowserSelected(const char*) | |||||
{ | |||||
} | |||||
#endif | |||||
bool Window::handlePluginKeyboard(const bool press, const uint key) | bool Window::handlePluginKeyboard(const bool press, const uint key) | ||||
{ | { | ||||
// TODO | // TODO | ||||
@@ -19,6 +19,14 @@ | |||||
#include "pugl.hpp" | #include "pugl.hpp" | ||||
#include "../../distrho/extra/String.hpp" | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# include <direct.h> | |||||
#else | |||||
# include <unistd.h> | |||||
#endif | |||||
#define DGL_DEBUG_EVENTS | #define DGL_DEBUG_EVENTS | ||||
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | ||||
@@ -66,6 +74,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
win32SelectedFile(nullptr), | |||||
#endif | |||||
modal() | modal() | ||||
{ | { | ||||
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
@@ -85,6 +96,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
win32SelectedFile(nullptr), | |||||
#endif | |||||
modal(ppData) | modal(ppData) | ||||
{ | { | ||||
init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | init(DEFAULT_WIDTH, DEFAULT_HEIGHT, false); | ||||
@@ -108,6 +122,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
win32SelectedFile(nullptr), | |||||
#endif | |||||
modal() | modal() | ||||
{ | { | ||||
if (isEmbed) | if (isEmbed) | ||||
@@ -142,6 +159,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
minWidth(0), | minWidth(0), | ||||
minHeight(0), | minHeight(0), | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
win32SelectedFile(nullptr), | |||||
#endif | |||||
modal() | modal() | ||||
{ | { | ||||
if (isEmbed) | if (isEmbed) | ||||
@@ -163,6 +183,9 @@ Window::PrivateData::~PrivateData() | |||||
{ | { | ||||
if (isEmbed) | if (isEmbed) | ||||
{ | { | ||||
#ifdef HAVE_X11 | |||||
sofdFileDialogClose(view); | |||||
#endif | |||||
puglHide(view); | puglHide(view); | ||||
appData->oneWindowClosed(); | appData->oneWindowClosed(); | ||||
isClosed = true; | isClosed = true; | ||||
@@ -199,9 +222,6 @@ void Window::PrivateData::init(const uint width, const uint height, const bool r | |||||
puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | puglSetViewHint(view, PUGL_STENCIL_BITS, 8); | ||||
// PUGL_SAMPLES ?? | // PUGL_SAMPLES ?? | ||||
puglSetEventFunc(view, puglEventCallback); | puglSetEventFunc(view, puglEventCallback); | ||||
// #ifndef DGL_FILE_BROWSER_DISABLED | |||||
// puglSetFileSelectedFunc(fView, fileBrowserSelectedCallback); | |||||
// #endif | |||||
PuglRect rect = puglGetFrame(view); | PuglRect rect = puglGetFrame(view); | ||||
rect.width = width; | rect.width = width; | ||||
@@ -215,6 +235,21 @@ void Window::PrivateData::init(const uint width, const uint height, const bool r | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Window::PrivateData::close() | |||||
{ | |||||
DGL_DBG("Window close\n"); | |||||
// DGL_DBGp("Window close DBG %i %i %p\n", isEmbed, isClosed, appData); | |||||
if (isEmbed || isClosed) | |||||
return; | |||||
isClosed = true; | |||||
hide(); | |||||
appData->oneWindowClosed(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void Window::PrivateData::show() | void Window::PrivateData::show() | ||||
{ | { | ||||
if (isVisible) | if (isVisible) | ||||
@@ -293,6 +328,9 @@ void Window::PrivateData::hide() | |||||
if (modal.enabled) | if (modal.enabled) | ||||
stopModal(); | stopModal(); | ||||
#ifdef HAVE_X11 | |||||
sofdFileDialogClose(view); | |||||
#endif | |||||
puglHide(view); | puglHide(view); | ||||
isVisible = false; | isVisible = false; | ||||
@@ -300,21 +338,6 @@ void Window::PrivateData::hide() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Window::PrivateData::close() | |||||
{ | |||||
DGL_DBG("Window close\n"); | |||||
// DGL_DBGp("Window close DBG %i %i %p\n", isEmbed, isClosed, appData); | |||||
if (isEmbed || isClosed) | |||||
return; | |||||
isClosed = true; | |||||
hide(); | |||||
appData->oneWindowClosed(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void Window::PrivateData::focus() | void Window::PrivateData::focus() | ||||
{ | { | ||||
if (! isEmbed) | if (! isEmbed) | ||||
@@ -341,20 +364,29 @@ void Window::PrivateData::setResizable(const bool resizable) | |||||
void Window::PrivateData::idleCallback() | void Window::PrivateData::idleCallback() | ||||
{ | { | ||||
// #if defined(DISTRHO_OS_WINDOWS) && !defined(DGL_FILE_BROWSER_DISABLED) | |||||
// if (fSelectedFile.isNotEmpty()) | |||||
// { | |||||
// char* const buffer = fSelectedFile.getAndReleaseBuffer(); | |||||
// fView->fileSelectedFunc(fView, buffer); | |||||
// std::free(buffer); | |||||
// } | |||||
// #endif | |||||
// if (modal.enabled && modal.parent != nullptr) | |||||
// modal.parent->idleCallback(); | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
# ifdef DISTRHO_OS_WINDOWS | |||||
if (char* const path = win32SelectedFile) | |||||
{ | |||||
win32SelectedFile = nullptr; | |||||
self->onFileSelected(path); | |||||
std::free(path); | |||||
} | |||||
# endif | |||||
# ifdef HAVE_X11 | |||||
char* path; | |||||
if (sofdFileDialogGetPath(&path)) | |||||
{ | |||||
// TODO ignore null path?? | |||||
self->onFileSelected(path); | |||||
sofdFileDialogFree(path); | |||||
} | |||||
# endif | |||||
#endif | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// idle callback stuff | |||||
bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | bool Window::PrivateData::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | ||||
{ | { | ||||
@@ -379,6 +411,69 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | |||||
return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS; | return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS; | ||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// file handling | |||||
bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& options) | |||||
{ | |||||
using DISTRHO_NAMESPACE::String; | |||||
// -------------------------------------------------------------------------- | |||||
// configure start dir | |||||
// TODO: get abspath if needed | |||||
// TODO: cross-platform | |||||
String startDir(options.startDir); | |||||
if (startDir.isEmpty()) | |||||
{ | |||||
// TESTING verify this whole thing... | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
if (char* const cwd = _getcwd(nullptr, 0)) | |||||
{ | |||||
startDir = cwd; | |||||
std::free(cwd); | |||||
} | |||||
#else | |||||
if (char* const cwd = getcwd(nullptr, 0)) | |||||
{ | |||||
startDir = cwd; | |||||
std::free(cwd); | |||||
} | |||||
#endif | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | |||||
if (! startDir.endsWith(DISTRHO_OS_SEP)) | |||||
startDir += DISTRHO_OS_SEP_STR; | |||||
// -------------------------------------------------------------------------- | |||||
// configure title | |||||
String title(options.title); | |||||
if (title.isEmpty()) | |||||
{ | |||||
title = puglGetWindowTitle(view); | |||||
if (title.isEmpty()) | |||||
title = "FileBrowser"; | |||||
} | |||||
// -------------------------------------------------------------------------- | |||||
// show | |||||
#ifdef HAVE_X11 | |||||
uint flags = 0x0; | |||||
// TODO flags | |||||
return sofdFileDialogShow(view, startDir, title, flags, options.width, options.height); | |||||
#endif | |||||
return false; | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// modal handling | // modal handling | ||||
@@ -30,7 +30,7 @@ class TopLevelWidget; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
struct Window::PrivateData : IdleCallback { | struct Window::PrivateData : IdleCallback { | ||||
/* Reference to the DGL Application class this (private data) window associates with. */ | |||||
/** Reference to the DGL Application class this (private data) window associates with. */ | |||||
Application& app; | Application& app; | ||||
/** Direct access to the DGL Application private data where we registers ourselves in. */ | /** Direct access to the DGL Application private data where we registers ourselves in. */ | ||||
@@ -68,6 +68,11 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Pugl minWidth, minHeight access. */ | /** Pugl minWidth, minHeight access. */ | ||||
uint minWidth, minHeight; | uint minWidth, minHeight; | ||||
#ifdef DISTRHO_OS_WINDOWS | |||||
/** Selected file for openFileBrowser on windows, stored for fake async operation. */ | |||||
const char* win32SelectedFile; | |||||
#endif | |||||
/** Modal window setup. */ | /** Modal window setup. */ | ||||
struct Modal { | struct Modal { | ||||
PrivateData* parent; // parent of this window (so we can become modal) | PrivateData* parent; // parent of this window (so we can become modal) | ||||
@@ -102,9 +107,6 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Constructor for a modal window. */ | /** Constructor for a modal window. */ | ||||
explicit PrivateData(Application& app, Window* self, PrivateData* ppData); | explicit PrivateData(Application& app, Window* self, PrivateData* ppData); | ||||
/** Constructor for a regular, standalone window with a transient parent. */ | |||||
// explicit PrivateData(Application& app, Window* self, Window& transientWindow); | |||||
/** Constructor for an embed Window, with a few extra hints from the host side. */ | /** Constructor for an embed Window, with a few extra hints from the host side. */ | ||||
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable); | explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable); | ||||
@@ -118,9 +120,6 @@ struct Window::PrivateData : IdleCallback { | |||||
/** Helper initialization function called at the end of all this class constructors. */ | /** Helper initialization function called at the end of all this class constructors. */ | ||||
void init(uint width, uint height, bool resizable); | void init(uint width, uint height, bool resizable); | ||||
void show(); | |||||
void hide(); | |||||
/** Hide window and notify application of a window close event. | /** Hide window and notify application of a window close event. | ||||
* Does nothing if window is embed (that is, not standalone). | * Does nothing if window is embed (that is, not standalone). | ||||
* The application event-loop will stop when all windows have been closed. | * The application event-loop will stop when all windows have been closed. | ||||
@@ -130,17 +129,23 @@ struct Window::PrivateData : IdleCallback { | |||||
*/ | */ | ||||
void close(); | void close(); | ||||
void show(); | |||||
void hide(); | |||||
void focus(); | void focus(); | ||||
void setResizable(bool resizable); | void setResizable(bool resizable); | ||||
const GraphicsContext& getGraphicsContext() const noexcept; | const GraphicsContext& getGraphicsContext() const noexcept; | ||||
// idle callback stuff | |||||
void idleCallback() override; | void idleCallback() override; | ||||
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | ||||
bool removeIdleCallback(IdleCallback* callback); | bool removeIdleCallback(IdleCallback* callback); | ||||
// file handling | |||||
bool openFileBrowser(const Window::FileBrowserOptions& options); | |||||
// modal handling | // modal handling | ||||
void startModal(); | void startModal(); | ||||
void stopModal(); | void stopModal(); | ||||
@@ -1 +1 @@ | |||||
Subproject commit ecfa817136831ca2fe38561a68344f9e9076d3e7 | |||||
Subproject commit 83ccad73546576a5b439c0fe2415e16509f8f28a |
@@ -89,6 +89,12 @@ | |||||
# endif | # endif | ||||
#endif | #endif | ||||
#ifdef HAVE_X11 | |||||
# define 400 | |||||
# include "sofd/libsofd.h" | |||||
# include "sofd/libsofd.c" | |||||
#endif | |||||
#ifndef DISTRHO_OS_MAC | #ifndef DISTRHO_OS_MAC | ||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
#endif | #endif | ||||
@@ -355,6 +361,94 @@ void puglWin32SetWindowResizable(PuglView* const view, const bool resizable) | |||||
: GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; | : GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; | ||||
SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); | SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); | ||||
} | } | ||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif | |||||
#ifdef HAVE_X11 | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, setup event loop filter for sofd file dialog | |||||
static bool sofd_has_action; | |||||
static char* sofd_filename; | |||||
static bool sofd_event_filter(Display* const display, XEvent* const xevent) | |||||
{ | |||||
if (x_fib_handle_events(display, xevent) == 0) | |||||
return false; | |||||
if (sofd_filename != nullptr) | |||||
std::free(sofd_filename); | |||||
if (x_fib_status() > 0) | |||||
sofd_filename = x_fib_filename(); | |||||
else | |||||
sofd_filename = nullptr; | |||||
x_fib_close(display); | |||||
sofd_has_action = true; | |||||
return true; | |||||
} | |||||
void sofdFileDialogSetup(PuglWorld* const world) | |||||
{ | |||||
puglX11SetEventFilter(world, sofd_event_filter); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, show file dialog via sofd | |||||
bool sofdFileDialogShow(PuglView* const view, | |||||
const char* const startDir, const char* const title, | |||||
const uint flags, const uint width, const uint height) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | |||||
/* | |||||
x_fib_cfg_buttons(3, options.buttons.listAllFiles-1); | |||||
x_fib_cfg_buttons(1, options.buttons.showHidden-1); | |||||
x_fib_cfg_buttons(2, options.buttons.showPlaces-1); | |||||
*/ | |||||
PuglInternals* const impl = view->impl; | |||||
return (x_fib_show(impl->display, impl->win, width, height) == 0); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, close sofd file dialog | |||||
void sofdFileDialogClose(PuglView* const view) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
x_fib_close(impl->display); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, get path chosen via sofd file dialog | |||||
bool sofdFileDialogGetPath(char** path) | |||||
{ | |||||
if (! sofd_has_action) | |||||
return false; | |||||
sofd_has_action = false; | |||||
*path = sofd_filename; | |||||
return true; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, free path of sofd file dialog, no longer needed | |||||
void sofdFileDialogFree(char* const path) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(path == nullptr || path == sofd_filename,); | |||||
std::free(sofd_filename); | |||||
sofd_filename = nullptr; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif | #endif | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -88,6 +88,28 @@ PUGL_API void | |||||
puglWin32SetWindowResizable(PuglView* view, bool resizable); | puglWin32SetWindowResizable(PuglView* view, bool resizable); | ||||
#endif | #endif | ||||
#ifdef HAVE_X11 | |||||
// X11 specific, setup event loop filter for sofd file dialog | |||||
PUGL_API void | |||||
sofdFileDialogSetup(PuglWorld* world); | |||||
// X11 specific, show file dialog via sofd | |||||
PUGL_API bool | |||||
sofdFileDialogShow(PuglView* view, const char* startDir, const char* title, uint flags, uint width, uint height); | |||||
// X11 specific, close sofd file dialog | |||||
PUGL_API void | |||||
sofdFileDialogClose(PuglView* view); | |||||
// X11 specific, get path chosen via sofd file dialog | |||||
PUGL_API bool | |||||
sofdFileDialogGetPath(char** path); | |||||
// X11 specific, free path of sofd file dialog, no longer needed | |||||
PUGL_API void | |||||
sofdFileDialogFree(char* path); | |||||
#endif | |||||
PUGL_END_DECLS | PUGL_END_DECLS | ||||
// -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
@@ -32,7 +32,7 @@ | |||||
*/ | */ | ||||
#ifdef SOFD_TEST | #ifdef SOFD_TEST | ||||
#define SOFD_HAVE_X11 | |||||
#define HAVE_X11 | |||||
#include "libsofd.h" | #include "libsofd.h" | ||||
#endif | #endif | ||||
@@ -337,7 +337,7 @@ const char *x_fib_recent_file(const char *appname) { | |||||
return NULL; | return NULL; | ||||
} | } | ||||
#ifdef SOFD_HAVE_X11 | |||||
#ifdef HAVE_X11 | |||||
#include <mntent.h> | #include <mntent.h> | ||||
#include <dirent.h> | #include <dirent.h> | ||||
@@ -475,7 +475,10 @@ static int (*_fib_filter_function)(const char *filename); | |||||
#define FAREATEXTL (FAREAMRGL + TEXTSEP) //px; filename text-left FAREAMRGL + TEXTSEP | #define FAREATEXTL (FAREAMRGL + TEXTSEP) //px; filename text-left FAREAMRGL + TEXTSEP | ||||
#define SORTBTNOFF -10 //px; | #define SORTBTNOFF -10 //px; | ||||
#define DBLCLKTME 400 //msec; double click time | |||||
#ifndef DBLCLKTME | |||||
#define DBLCLKTME 200 //msec; double click time | |||||
#endif | |||||
#define DRAW_OUTLINE | #define DRAW_OUTLINE | ||||
#define DOUBLE_BUFFER | #define DOUBLE_BUFFER | ||||
@@ -1208,7 +1211,7 @@ static int fib_dirlistadd (Display *dpy, const int i, const char* path, const ch | |||||
static int fib_openrecent (Display *dpy, const char *sel) { | static int fib_openrecent (Display *dpy, const char *sel) { | ||||
int i; | int i; | ||||
unsigned int j; | |||||
unsigned int j; | |||||
assert (_recentcnt > 0); | assert (_recentcnt > 0); | ||||
fib_pre_opendir (dpy); | fib_pre_opendir (dpy); | ||||
query_font_geometry (dpy, _fib_gc, "Last Used", &_fib_font_time_width, NULL, NULL, NULL); | query_font_geometry (dpy, _fib_gc, "Last Used", &_fib_font_time_width, NULL, NULL, NULL); | ||||
@@ -1332,8 +1335,8 @@ static int fib_open (Display *dpy, int item) { | |||||
static void cb_cancel (Display *dpy) { | static void cb_cancel (Display *dpy) { | ||||
_status = -1; | _status = -1; | ||||
// unused | |||||
return; (void)dpy; | |||||
// unused | |||||
return; (void)dpy; | |||||
} | } | ||||
static void cb_open (Display *dpy) { | static void cb_open (Display *dpy) { | ||||
@@ -1478,8 +1481,8 @@ static int fib_widget_at_pos (Display *dpy, int x, int y, int *it) { | |||||
return 0; | return 0; | ||||
// unused | |||||
(void)dpy; | |||||
// unused | |||||
(void)dpy; | |||||
} | } | ||||
static void fib_update_hover (Display *dpy, int need_expose, const int type, const int item) { | static void fib_update_hover (Display *dpy, int need_expose, const int type, const int item) { | ||||
@@ -1592,9 +1595,11 @@ static void fib_mousedown (Display *dpy, int x, int y, int btn, unsigned long ti | |||||
fib_select (dpy, it); | fib_select (dpy, it); | ||||
_dblclk = time; | _dblclk = time; | ||||
} | } | ||||
/*if (_fsel >= 0) { | |||||
/* | |||||
if (_fsel >= 0) { | |||||
if (!(_dirlist[_fsel].flags & 4)); | if (!(_dirlist[_fsel].flags & 4)); | ||||
}*/ | |||||
} | |||||
*/ | |||||
} | } | ||||
break; | break; | ||||
case 1: // paths | case 1: // paths | ||||
@@ -1656,8 +1661,8 @@ static void fib_mousedown (Display *dpy, int x, int y, int btn, unsigned long ti | |||||
static void fib_mouseup (Display *dpy, int x, int y, int btn, unsigned long time) { | static void fib_mouseup (Display *dpy, int x, int y, int btn, unsigned long time) { | ||||
_scrl_my = -1; | _scrl_my = -1; | ||||
// unused | |||||
return; (void)dpy; (void)x; (void)y; (void)btn; (void)time; | |||||
// unused | |||||
return; (void)dpy; (void)x; (void)y; (void)btn; (void)time; | |||||
} | } | ||||
static void add_place_raw (Display *dpy, const char *name, const char *path) { | static void add_place_raw (Display *dpy, const char *name, const char *path) { | ||||
@@ -1885,8 +1890,8 @@ static int x_error_handler (Display *d, XErrorEvent *e) { | |||||
font_err = 1; | font_err = 1; | ||||
return 0; | return 0; | ||||
// unused | |||||
(void)d; (void)e; | |||||
// unused | |||||
(void)d; (void)e; | |||||
} | } | ||||
int x_fib_show (Display *dpy, Window parent, int x, int y) { | int x_fib_show (Display *dpy, Window parent, int x, int y) { | ||||
@@ -2340,7 +2345,7 @@ char *x_fib_filename () { | |||||
else | else | ||||
return NULL; | return NULL; | ||||
} | } | ||||
#endif // SOFD_HAVE_X11 | |||||
#endif // HAVE_X11 | |||||
#if defined(__clang__) | #if defined(__clang__) | ||||
# pragma clang diagnostic pop | # pragma clang diagnostic pop | ||||
@@ -22,10 +22,15 @@ | |||||
*/ | */ | ||||
#ifndef LIBSOFD_H | #ifndef LIBSOFD_H | ||||
#define LIBSOFD_H | |||||
#define LIBSOFD_H 1 | |||||
#ifdef HAVE_X11 | |||||
#include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
/* public API */ | /* public API */ | ||||
@@ -110,6 +115,16 @@ int x_fib_cfg_buttons (int k, int v); | |||||
*/ | */ | ||||
int x_fib_cfg_filter_callback (int (*cb)(const char*)); | int x_fib_cfg_filter_callback (int (*cb)(const char*)); | ||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* END X11 specific functions */ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/* 'recently used' API. x-platform | /* 'recently used' API. x-platform | ||||
* NOTE: all functions use a static cache and are not reentrant. | * NOTE: all functions use a static cache and are not reentrant. | ||||
* It is expected that none of these functions are called in | * It is expected that none of these functions are called in | ||||
@@ -172,4 +187,8 @@ unsigned int x_fib_recent_count (); | |||||
*/ | */ | ||||
const char *x_fib_recent_at (unsigned int i); | const char *x_fib_recent_at (unsigned int i); | ||||
#endif // LIBSOFD_H | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif // header guard |
@@ -246,7 +246,7 @@ protected: | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | # ifndef DGL_FILE_BROWSER_DISABLED | ||||
/** | /** | ||||
File browser selected function. | File browser selected function. | ||||
@see Window::fileBrowserSelected(const char*) | |||||
@see Window::onFileSelected(const char*) | |||||
*/ | */ | ||||
virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
# endif | # endif | ||||
@@ -185,6 +185,7 @@ void UI::uiFileBrowserSelected(const char*) | |||||
void UI::uiReshape(uint, uint) | void UI::uiReshape(uint, uint) | ||||
{ | { | ||||
// NOTE this must be the same as Window::onReshape | |||||
pData->fallbackOnResize(); | pData->fallbackOnResize(); | ||||
} | } | ||||
@@ -201,7 +202,9 @@ void UI::onResize(const ResizeEvent& ev) | |||||
const uint width = ev.size.getWidth(); | const uint width = ev.size.getWidth(); | ||||
const uint height = ev.size.getHeight(); | const uint height = ev.size.getHeight(); | ||||
/* | |||||
pData->window.setSize(width, height); | pData->window.setSize(width, height); | ||||
*/ | |||||
uiData->setSizeCallback(width, height); | uiData->setSizeCallback(width, height); | ||||
} | } | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
@@ -95,25 +95,25 @@ protected: | |||||
UI::PrivateData* const uiData = fUI->uiData; | UI::PrivateData* const uiData = fUI->uiData; | ||||
DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | ||||
/* | |||||
uiData->resizeInProgress = true; | uiData->resizeInProgress = true; | ||||
fUI->setSize(width, height); | fUI->setSize(width, height); | ||||
uiData->resizeInProgress = false; | uiData->resizeInProgress = false; | ||||
*/ | |||||
fUI->uiReshape(width, height); | fUI->uiReshape(width, height); | ||||
fIsReady = true; | fIsReady = true; | ||||
} | } | ||||
#if 0 /* TODO */ | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | # ifndef DGL_FILE_BROWSER_DISABLED | ||||
// custom file-browser selected | // custom file-browser selected | ||||
void fileBrowserSelected(const char* filename) override | |||||
void onFileSelected(const char* const filename) override | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
fUI->uiFileBrowserSelected(filename); | fUI->uiFileBrowserSelected(filename); | ||||
} | } | ||||
# endif | # endif | ||||
#endif | |||||
private: | private: | ||||
UI* const fUI; | UI* const fUI; | ||||