Browse Source

Testing code for X11 transient windows

tags/1.9.4
falkTX 10 years ago
parent
commit
13da4fdc73
6 changed files with 228 additions and 127 deletions
  1. +118
    -0
      source/backend/plugin/DssiPlugin.cpp
  2. +85
    -126
      source/backend/plugin/Lv2Plugin.cpp
  3. +6
    -0
      source/carla
  4. +1
    -1
      source/carla_settings.py
  5. +2
    -0
      source/modules/dgl/Window.hpp
  6. +16
    -0
      source/modules/dgl/src/Window.cpp

+ 118
- 0
source/backend/plugin/DssiPlugin.cpp View File

@@ -24,6 +24,11 @@
#include "CarlaMathUtils.hpp"

#include <QtCore/QByteArray>
#include <QtCore/QString>

#ifdef CARLA_OS_LINUX
# include <X11/Xlib.h>
#endif

CARLA_BACKEND_START_NAMESPACE

@@ -31,6 +36,9 @@ CARLA_BACKEND_START_NAMESPACE
}
#endif

// TESTING
static bool uiStarted = false;

class DssiPlugin : public CarlaPlugin
{
public:
@@ -374,6 +382,7 @@ public:
{
pData->osc.data.free();
pData->osc.thread.start();
uiStarted = true;
}
else
{
@@ -388,6 +397,115 @@ public:
}
}

void idle() override
{
CarlaPlugin::idle();

#ifdef CARLA_OS_LINUX
if (! uiStarted)
return;

// TESTING
static int counter = 0;

if (++counter != 100)
return;

if (const char* const win = getenv("CARLA_TRANSIENT_WINDOW"))
{
const long winl = std::atol(win);
carla_stderr2("got transient, %s vs %li", win, winl);

QString targetName(QString("%1 (GUI)").arg(pData->name));

Display* display = XOpenDisplay(0);
//int screen = DefaultScreen(display);
Window lastWindow = 0;

#if 0
Window root, parent;
Window* children = nullptr;
uint num = 0;
int status = XQueryTree(display, DefaultRootWindow(display), &root, &parent, &children, &num);

carla_stdout("HERE001 %i, %i", status, num);

for (uint i = 0; i < num; i++)
{
Window w = children[i];

carla_stdout("Scanned client window: %lu", w);

char* name = nullptr;
status = XFetchName(display, w, &name);

if (name != nullptr)
{
XFree(name);
carla_stdout("Found: %ul %s", w, name);
}
}
#else
Atom a = XInternAtom(display, "_NET_CLIENT_LIST" , true);

Atom actualType;
int actualFormat;
unsigned long numItems, bytesAfter;
unsigned char* data = nullptr;

int status = XGetWindowProperty(display, DefaultRootWindow(display), a, 0L, (~0L), False, AnyPropertyType, &actualType, &actualFormat, &numItems, &bytesAfter, &data);
carla_stdout("FOUND %i WINDOWS", numItems);

if (status >= Success && numItems)
{
// success - we have data: Format should always be 32:
CARLA_SAFE_ASSERT_RETURN(actualFormat == 32,);

// cast to proper format, and iterate through values:
Window* array = (Window*)data;

for (uint32_t k = 0; k < numItems; k++)
{
// get window Id:
Window w = array[k];

carla_stdout("Found at %i: %li", k+1, w);

#if 1
if (w == 0)
continue;

Atom name = XInternAtom(display, "_NET_WM_NAME", False);
// Atom utf8 = XInternAtom(display, "UTF8_STRING", False);

unsigned long numNames;
unsigned char* namesData = nullptr;

status = XGetWindowProperty(display, w, name, 0L, (~0L), False, AnyPropertyType/*utf8*/, &actualType, &actualFormat, &numNames, &bytesAfter, &namesData);
//if (status >= Success)
{
carla_stdout("Found at %i: %ul %ul %s", k+1, w, numNames, (const char*)namesData);
}

lastWindow = w;

XFree(namesData);
#endif
}

XFree(data);
}

if (lastWindow != 0)
{
XSetTransientForHint(display, lastWindow, (Window)winl);
XFlush(display);
}
#endif
}
#endif
}

// -------------------------------------------------------------------
// Plugin state



+ 85
- 126
source/backend/plugin/Lv2Plugin.cpp View File

@@ -20,12 +20,10 @@

#ifdef WANT_LV2

#ifdef HAVE_JUCE
# include "juce_gui_basics.h"
#endif
// need this first for juce headers
#include "CarlaMathUtils.hpp"

#include "CarlaLv2Utils.hpp"
#include "CarlaMathUtils.hpp"
#include "Lv2AtomQueue.hpp"

#include "../engine/CarlaEngineOsc.hpp"
@@ -37,6 +35,11 @@ extern "C" {
#include <QtCore/QDir>
#include <QtCore/QUrl>

#ifdef HAVE_DGL
# include "dgl/App.hpp"
# include "dgl/Window.hpp"
#endif

// -----------------------------------------------------

CARLA_BACKEND_START_NAMESPACE
@@ -409,19 +412,18 @@ public:
delete (LV2UI_Resize*)fFeatures[kFeatureIdUiResize]->data;

if (fFeatures[kFeatureIdExternalUi] != nullptr && fFeatures[kFeatureIdExternalUi]->data != nullptr)
{
const LV2_External_UI_Host* const uiHost((const LV2_External_UI_Host*)fFeatures[kFeatureIdExternalUi]->data);

if (uiHost->plugin_human_id != nullptr)
delete[] uiHost->plugin_human_id;

delete uiHost;
}
delete (LV2_External_UI_Host*)fFeatures[kFeatureIdExternalUi]->data;

fUi.descriptor = nullptr;
pData->uiLibClose();
}

if (fUi.title != nullptr)
{
delete[] fUi.title;
fUi.title = nullptr;
}

fUi.rdfDescriptor = nullptr;
}

@@ -908,22 +910,18 @@ public:
{
CarlaPlugin::setName(newName);

QString guiTitle(QString("%1 (GUI)").arg(pData->name));
if (fUi.title == nullptr)
return;

#if 0
if (pData->gui != nullptr)
pData->gui->setWindowTitle(guiTitle);
#endif
QString guiTitle(QString("%1 (GL GUI)").arg(pData->name));

if (fFeatures[kFeatureIdExternalUi] != nullptr && fFeatures[kFeatureIdExternalUi]->data != nullptr)
{
LV2_External_UI_Host* const uiHost((LV2_External_UI_Host*)fFeatures[kFeatureIdExternalUi]->data);
delete[] fUi.title;
fUi.title = carla_strdup(guiTitle.toUtf8().constData());

if (uiHost->plugin_human_id != nullptr)
delete[] uiHost->plugin_human_id;
fUi.glWindow.setTitle(fUi.title);

uiHost->plugin_human_id = carla_strdup(guiTitle.toUtf8().constData());
}
if (fFeatures[kFeatureIdExternalUi] != nullptr && fFeatures[kFeatureIdExternalUi]->data != nullptr)
((LV2_External_UI_Host*)fFeatures[kFeatureIdExternalUi]->data)->plugin_human_id = fUi.title;
}

// -------------------------------------------------------------------
@@ -1107,37 +1105,44 @@ public:
return;
}

if (fUi.type == UI::TYPE_EXTERNAL)
if (yesNo)
{
if (yesNo)
if (fUi.handle == nullptr)
{
if (fUi.handle == nullptr)
{
fUi.widget = nullptr;
fUi.handle = fUi.descriptor->instantiate(fUi.descriptor, fRdfDescriptor->URI, fUi.rdfDescriptor->Bundle,
carla_lv2_ui_write_function, this, &fUi.widget, fFeatures);
}

CARLA_SAFE_ASSERT(fUi.handle != nullptr);
CARLA_SAFE_ASSERT(fUi.widget != nullptr);
fUi.widget = nullptr;
fUi.handle = fUi.descriptor->instantiate(fUi.descriptor, fRdfDescriptor->URI, fUi.rdfDescriptor->Bundle,
carla_lv2_ui_write_function, this, &fUi.widget, fFeatures);
}

if (fUi.handle == nullptr || fUi.widget == nullptr)
{
fUi.widget = nullptr;
CARLA_SAFE_ASSERT(fUi.handle != nullptr);
CARLA_SAFE_ASSERT(fUi.type != UI::TYPE_EXTERNAL || fUi.widget != nullptr);

if (fUi.handle != nullptr)
{
fUi.descriptor->cleanup(fUi.handle);
fUi.handle = nullptr;
}
if (fUi.handle == nullptr || (fUi.type == UI::TYPE_EXTERNAL && fUi.widget == nullptr))
{
fUi.widget = nullptr;

pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0.0f, "Plugin refused to open its own UI");
return;
if (fUi.handle != nullptr)
{
fUi.descriptor->cleanup(fUi.handle);
fUi.handle = nullptr;
}

updateUi();
pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0.0f, "Plugin refused to open its own UI");
return;
}

updateUi();

if (fUi.type == UI::TYPE_EMBED)
fUi.glWindow.show();
else
LV2_EXTERNAL_UI_SHOW((LV2_External_UI_Widget*)fUi.widget);
}
else
{
if (fUi.type == UI::TYPE_EMBED)
{
fUi.glWindow.hide();
}
else
{
@@ -1145,89 +1150,19 @@ public:

if (fUi.widget != nullptr)
LV2_EXTERNAL_UI_HIDE((LV2_External_UI_Widget*)fUi.widget);

fUi.descriptor->cleanup(fUi.handle);
fUi.handle = nullptr;
fUi.widget = nullptr;
}
}
else // means TYPE_EMBED
{
#if 0
if (yesNo)
{
if (pData->gui == nullptr)
{
// TODO
CarlaPluginGui::Options guiOptions;
guiOptions.parented = (fUi.type == PLUGIN_UI_PARENT);
guiOptions.resizable = isUiResizable();

pData->gui = new CarlaPluginGui(pData->engine, this, guiOptions, pData->guiGeometry);
}

if (fUi.type == PLUGIN_UI_PARENT)
{
fFeatures[kFeatureIdUiParent]->data = pData->gui->getContainerWinId();
fFeatures[kFeatureIdUiParent]->URI = LV2_UI__parent;
}

if (fUi.handle == nullptr)
{
fUi.widget = nullptr;
fUi.handle = fUi.descriptor->instantiate(fUi.descriptor, fRdfDescriptor->URI, fUi.rdfDescriptor->Bundle,
carla_lv2_ui_write_function, this, &fUi.widget, fFeatures);
}

CARLA_ASSERT(fUi.handle != nullptr);
CARLA_ASSERT(fUi.type == PLUGIN_UI_PARENT || fUi.widget != nullptr);

if (fUi.handle == nullptr || (fUi.type != PLUGIN_UI_PARENT && fUi.widget == nullptr))
{
fUi.handle = nullptr;
fUi.widget = nullptr;

pData->guiGeometry = pData->gui->saveGeometry();
pData->gui->close();
delete pData->gui;
pData->gui = nullptr;

pData->engine->callback(CALLBACK_ERROR, fId, 0, 0, 0.0f, "Plugin refused to open its own UI");
pData->engine->callback(CALLBACK_SHOW_GUI, fId, -1, 0, 0.0f, nullptr);
return;
}

if (fUi.type == PLUGIN_UI_QT)
pData->gui->setWidget((QWidget*)fUi.widget);

updateUi();

pData->gui->setWindowTitle(QString("%1 (GUI)").arg(pData->name));
pData->gui->show();
}
else
{
fUi.descriptor->cleanup(fUi.handle);
fUi.handle = nullptr;
fUi.widget = nullptr;
fUi.descriptor->cleanup(fUi.handle);
fUi.handle = nullptr;
fUi.widget = nullptr;

if (pData->gui != nullptr)
{
pData->guiGeometry = pData->gui->saveGeometry();
pData->gui->close();
delete pData->gui;
pData->gui = nullptr;
}
}
#endif
if (fUi.type == UI::TYPE_EMBED)
fUi.glWindow.close();
}
}

void idle() override
{
if (fUi.type == UI::TYPE_NULL)
return CarlaPlugin::idle();

if (! fAtomQueueOut.isEmpty())
{
char dumpBuf[fAtomQueueOut.getSize()];
@@ -4059,6 +3994,8 @@ public:
CARLA_SAFE_ASSERT_RETURN(height > 0, 1);
carla_debug("Lv2Plugin::handleUiResize(%i, %i)", width, height);

fUi.glWindow.setSize(static_cast<uint>(width), static_cast<uint>(height));

return 0;
}

@@ -4740,9 +4677,23 @@ public:
}

// ---------------------------------------------------------------
// initialize ui features (part 1)
// initialize ui data

QString guiTitle(QString("%1 (GUI)").arg(pData->name));
QString guiTitle(QString("%1 (GL GUI)").arg(pData->name));
fUi.title = carla_strdup(guiTitle.toUtf8().constData());

fUi.glWindow.setResizable(isUiResizable());
fUi.glWindow.setTitle(fUi.title);

if (const char* const win = getenv("CARLA_TRANSIENT_WINDOW"))
{
const long winl = std::atol(win);
carla_stderr2("got transient, %s vs %li", win, winl);
fUi.glWindow.setTransient(winl);
}

// ---------------------------------------------------------------
// initialize ui features (part 1)

LV2_Extension_Data_Feature* const uiDataFt = new LV2_Extension_Data_Feature;
uiDataFt->data_access = fDescriptor->extension_data;
@@ -4757,7 +4708,7 @@ public:

LV2_External_UI_Host* const uiExternalHostFt = new LV2_External_UI_Host;
uiExternalHostFt->ui_closed = carla_lv2_external_ui_closed;
uiExternalHostFt->plugin_human_id = carla_strdup(guiTitle.toUtf8().constData());
uiExternalHostFt->plugin_human_id = fUi.title;

// ---------------------------------------------------------------
// initialize ui features (part 2)
@@ -4784,7 +4735,7 @@ public:
fFeatures[kFeatureIdUiNoUserResize]->data = nullptr;

fFeatures[kFeatureIdUiParent]->URI = LV2_UI__parent;
fFeatures[kFeatureIdUiParent]->data = nullptr;
fFeatures[kFeatureIdUiParent]->data = (void*)fUi.glWindow.getWindowId();

fFeatures[kFeatureIdUiPortMap]->URI = LV2_UI__portMap;
fFeatures[kFeatureIdUiPortMap]->data = uiPortMapFt;
@@ -4887,12 +4838,19 @@ private:
const LV2UI_Descriptor* descriptor;
const LV2_RDF_UI* rdfDescriptor;

const char* title;
DGL::App glApp;
DGL::Window glWindow;

UI()
: type(TYPE_NULL),
handle(nullptr),
widget(nullptr),
descriptor(nullptr),
rdfDescriptor(nullptr) {}
rdfDescriptor(nullptr),
title(nullptr),
glApp(),
glWindow(glApp) {}

~UI()
{
@@ -4900,6 +4858,7 @@ private:
CARLA_ASSERT(widget == nullptr);
CARLA_ASSERT(descriptor == nullptr);
CARLA_ASSERT(rdfDescriptor == nullptr);
CARLA_ASSERT(title == nullptr);
}
} fUi;



+ 6
- 0
source/carla View File

@@ -303,6 +303,12 @@ if __name__ == '__main__':

Carla.gui = CarlaHostW()

# test
win = Carla.gui.winId()

if win:
os.environ["CARLA_TRANSIENT_WINDOW"] = str(win)

# -------------------------------------------------------------
# Load project file if set



+ 1
- 1
source/carla_settings.py View File

@@ -45,7 +45,7 @@ CANVAS_EYECANDY_SMALL = 1
CARLA_DEFAULT_MAIN_PROJECT_FOLDER = HOME
CARLA_DEFAULT_MAIN_USE_PRO_THEME = True
CARLA_DEFAULT_MAIN_PRO_THEME_COLOR = "Black"
CARLA_DEFAULT_MAIN_REFRESH_INTERVAL = 50
CARLA_DEFAULT_MAIN_REFRESH_INTERVAL = 20

# Canvas
CARLA_DEFAULT_CANVAS_THEME = "Modern Dark"


+ 2
- 0
source/modules/dgl/Window.hpp View File

@@ -40,6 +40,8 @@ public:
Window(App& app, intptr_t parentId);
virtual ~Window();

void setTransient(const intptr_t win);

void show();
void hide();
void close();


+ 16
- 0
source/modules/dgl/src/Window.cpp View File

@@ -210,6 +210,17 @@ public:
DBG("Success!\n");
}

// TESTING
void setTransient(const intptr_t win)
{
#if DGL_OS_LINUX
XSetTransientForHint(xDisplay, xWindow, (::Window)win);
XFlush(xDisplay);
#else
return; (void)win;
#endif
}

// -------------------------------------------------------------------

void close()
@@ -780,6 +791,11 @@ Window::~Window()
delete pData;
}

void Window::setTransient(const intptr_t win)
{
pData->setTransient(win);
}

void Window::show()
{
pData->setVisible(true);


Loading…
Cancel
Save