mirror of https://github.com/AxioDL/boo.git
working dbus instancing
This commit is contained in:
parent
6d8eb3039b
commit
35f2156de1
|
@ -15,7 +15,7 @@ struct IApplicationCallback
|
|||
{
|
||||
virtual void appLaunched(IApplication* app) {(void)app;}
|
||||
virtual void appQuitting(IApplication* app) {(void)app;}
|
||||
virtual bool appFileOpen(IApplication* app, const std::string& path) {(void)app;(void)path;return true;}
|
||||
virtual void appFilesOpen(IApplication* app, const std::vector<const std::string>& paths) {(void)app;(void)paths;}
|
||||
};
|
||||
|
||||
class IApplication
|
||||
|
@ -45,6 +45,8 @@ public:
|
|||
|
||||
virtual void run()=0;
|
||||
virtual void quit()=0;
|
||||
virtual const std::string& getUniqueName() const=0;
|
||||
virtual const std::string& getFriendlyName() const=0;
|
||||
virtual const std::string& getProcessName() const=0;
|
||||
virtual const std::vector<std::string>& getArgs() const=0;
|
||||
|
||||
|
@ -55,23 +57,27 @@ public:
|
|||
|
||||
IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
|
||||
IApplicationCallback& cb,
|
||||
const std::string& uniqueName,
|
||||
const std::string& friendlyName,
|
||||
const std::string& pname,
|
||||
const std::vector<std::string>& args);
|
||||
const std::vector<std::string>& args,
|
||||
bool singleInstance=true);
|
||||
extern IApplication* APP;
|
||||
#define IApplicationInstance() APP
|
||||
|
||||
static inline IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
|
||||
IApplicationCallback& cb,
|
||||
const std::string& uniqueName,
|
||||
const std::string& friendlyName,
|
||||
int argc, char** argv)
|
||||
int argc, char** argv,
|
||||
bool singleInstance=true)
|
||||
{
|
||||
if (APP)
|
||||
return APP;
|
||||
std::vector<std::string> args;
|
||||
for (int i=1 ; i<argc ; ++i)
|
||||
args.push_back(argv[i]);
|
||||
return IApplicationBootstrap(platform, cb, friendlyName, argv[0], args);
|
||||
return IApplicationBootstrap(platform, cb, uniqueName, friendlyName, argv[0], args, singleInstance);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
13
libBoo.pro
13
libBoo.pro
|
@ -1,18 +1,13 @@
|
|||
CONFIG -= Qt
|
||||
QT =
|
||||
LIBS -= -lQtGui -lQtCore
|
||||
#CONFIG += console
|
||||
#QMAKE_CXXFLAGS -= -std=c++0x
|
||||
#CONFIG += c++11
|
||||
|
||||
unix:QMAKE_CXXFLAGS += -std=c++11 -stdlib=libc++
|
||||
unix:LIBS += -std=c++11 -stdlib=libc++ -lc++abi -lxcb \
|
||||
-lxcb-glx -lxcb-xkb -lxcb-xinput -lxcb-keysyms \
|
||||
-lxkbcommon -lxkbcommon-x11
|
||||
unix:!macx:LIBS += -std=c++11 -stdlib=libc++ -lc++abi
|
||||
unix:!macx:CONFIG += link_pkgconfig
|
||||
unix:!macx:PKGCONFIG += xcb xcb-glx xcb-xinput xcb-xkb xcb-keysyms xkbcommon xkbcommon-x11 dbus-1
|
||||
|
||||
win32:LIBS += Setupapi.lib winusb.lib User32.lib /SUBSYSTEM:Windows
|
||||
|
||||
#unix:!macx:CONFIG += link_pkgconfig
|
||||
#unix:!macx:PKGCONFIG += x11
|
||||
|
||||
include(libBoo.pri)
|
||||
include(test/test.pri)
|
||||
|
|
|
@ -6,23 +6,62 @@
|
|||
#include "CApplicationXCB.hpp"
|
||||
#include "CApplicationWayland.hpp"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <stdio.h>
|
||||
|
||||
DBusConnection* registerDBus(const char* appName, bool& isFirst)
|
||||
{
|
||||
isFirst = true;
|
||||
DBusError err = {};
|
||||
dbus_error_init(&err);
|
||||
|
||||
/* connect to the bus and check for errors */
|
||||
DBusConnection* conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
|
||||
if (dbus_error_is_set(&err))
|
||||
{
|
||||
fprintf(stderr, "DBus Connection Error (%s)\n", err.message);
|
||||
dbus_error_free(&err);
|
||||
}
|
||||
if (NULL == conn)
|
||||
return NULL;
|
||||
|
||||
/* request our name on the bus and check for errors */
|
||||
char busName[256];
|
||||
snprintf(busName, 256, "boo.%s.unique", appName);
|
||||
int ret = dbus_bus_request_name(conn, busName, DBUS_NAME_FLAG_DO_NOT_QUEUE , &err);
|
||||
if (dbus_error_is_set(&err))
|
||||
{
|
||||
fprintf(stderr, "DBus Name Error (%s)\n", err.message);
|
||||
dbus_error_free(&err);
|
||||
dbus_connection_close(conn);
|
||||
return NULL;
|
||||
}
|
||||
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret)
|
||||
isFirst = false;
|
||||
|
||||
return conn;
|
||||
|
||||
}
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
IApplication* APP = NULL;
|
||||
IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
|
||||
IApplicationCallback& cb,
|
||||
const std::string& uniqueName,
|
||||
const std::string& friendlyName,
|
||||
const std::string& pname,
|
||||
const std::vector<std::string>& args)
|
||||
const std::vector<std::string>& args,
|
||||
bool singleInstance)
|
||||
{
|
||||
if (!APP)
|
||||
{
|
||||
if (platform == IApplication::PLAT_WAYLAND)
|
||||
APP = new CApplicationWayland(cb, friendlyName, pname, args);
|
||||
APP = new CApplicationWayland(cb, uniqueName, friendlyName, pname, args, singleInstance);
|
||||
else if (platform == IApplication::PLAT_XCB ||
|
||||
platform == IApplication::PLAT_AUTO)
|
||||
APP = new CApplicationXCB(cb, friendlyName, pname, args);
|
||||
APP = new CApplicationXCB(cb, uniqueName, friendlyName, pname, args, singleInstance);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include "IApplication.hpp"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
DBusConnection* registerDBus(const char* appName, bool& isFirst);
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
|
@ -12,10 +15,12 @@ IWindow* _CWindowWaylandNew(const std::string& title);
|
|||
class CApplicationWayland final : public IApplication
|
||||
{
|
||||
IApplicationCallback& m_callback;
|
||||
const std::string m_uniqueName;
|
||||
const std::string m_friendlyName;
|
||||
const std::string m_pname;
|
||||
const std::vector<std::string> m_args;
|
||||
|
||||
bool m_singleInstance;
|
||||
|
||||
void _deletedWindow(IWindow* window)
|
||||
{
|
||||
(void)window;
|
||||
|
@ -23,13 +28,17 @@ class CApplicationWayland final : public IApplication
|
|||
|
||||
public:
|
||||
CApplicationWayland(IApplicationCallback& callback,
|
||||
const std::string& uniqueName,
|
||||
const std::string& friendlyName,
|
||||
const std::string& pname,
|
||||
const std::vector<std::string>& args)
|
||||
const std::vector<std::string>& args,
|
||||
bool singleInstance)
|
||||
: m_callback(callback),
|
||||
m_uniqueName(uniqueName),
|
||||
m_friendlyName(friendlyName),
|
||||
m_pname(pname),
|
||||
m_args(args)
|
||||
m_args(args),
|
||||
m_singleInstance(singleInstance)
|
||||
{}
|
||||
|
||||
EPlatformType getPlatformType() const
|
||||
|
@ -46,6 +55,16 @@ public:
|
|||
{
|
||||
|
||||
}
|
||||
|
||||
const std::string& getUniqueName() const
|
||||
{
|
||||
return m_uniqueName;
|
||||
}
|
||||
|
||||
const std::string& getFriendlyName() const
|
||||
{
|
||||
return m_friendlyName;
|
||||
}
|
||||
|
||||
const std::string& getProcessName() const
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ class CApplicationWin32 final : public IApplication
|
|||
const std::string m_pname;
|
||||
const std::vector<std::string> m_args;
|
||||
std::unordered_map<HWND, IWindow*> m_allWindows;
|
||||
bool m_singleInstance;
|
||||
|
||||
void _deletedWindow(IWindow* window)
|
||||
{
|
||||
|
@ -32,11 +33,13 @@ public:
|
|||
CApplicationWin32(const IApplicationCallback& callback,
|
||||
const std::string& friendlyName,
|
||||
const std::string& pname,
|
||||
const std::vector<std::string>& args)
|
||||
const std::vector<std::string>& args,
|
||||
bool singleInstance)
|
||||
: m_callback(callback),
|
||||
m_friendlyName(friendlyName),
|
||||
m_pname(pname),
|
||||
m_args(args)
|
||||
m_args(args),
|
||||
m_singleInstance(singleInstance)
|
||||
{}
|
||||
|
||||
EPlatformType getPlatformType() const
|
||||
|
@ -95,14 +98,15 @@ IApplication* IApplicationBootstrap(IApplication::EPlatformType platform,
|
|||
IApplicationCallback& cb,
|
||||
const std::string& friendlyName,
|
||||
const std::string& pname,
|
||||
const std::vector<std::string>& args)
|
||||
const std::vector<std::string>& args,
|
||||
bool singleInstance)
|
||||
{
|
||||
if (!APP)
|
||||
{
|
||||
if (platform != IApplication::PLAT_WIN32 &&
|
||||
platform != IApplication::PLAT_AUTO)
|
||||
return NULL;
|
||||
APP = new CApplicationWin32(cb, friendlyName, pname, args);
|
||||
APP = new CApplicationWin32(cb, friendlyName, pname, args, singleInstance);
|
||||
}
|
||||
return APP;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
#include <xcb/xinput.h>
|
||||
#undef explicit
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
DBusConnection* registerDBus(const char* appName, bool& isFirst);
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
|
@ -113,14 +118,19 @@ IWindow* _CWindowXCBNew(const std::string& title, xcb_connection_t* conn);
|
|||
class CApplicationXCB final : public IApplication
|
||||
{
|
||||
IApplicationCallback& m_callback;
|
||||
const std::string m_uniqueName;
|
||||
const std::string m_friendlyName;
|
||||
const std::string m_pname;
|
||||
const std::vector<std::string> m_args;
|
||||
|
||||
/* DBus single-instance */
|
||||
bool m_singleInstance;
|
||||
DBusConnection* m_dbus = NULL;
|
||||
|
||||
/* All windows */
|
||||
std::unordered_map<xcb_window_t, IWindow*> m_windows;
|
||||
|
||||
xcb_connection_t* m_xcbConn;
|
||||
xcb_connection_t* m_xcbConn = NULL;
|
||||
bool m_running;
|
||||
|
||||
void _deletedWindow(IWindow* window)
|
||||
|
@ -130,14 +140,62 @@ class CApplicationXCB final : public IApplication
|
|||
|
||||
public:
|
||||
CApplicationXCB(IApplicationCallback& callback,
|
||||
const std::string& uniqueName,
|
||||
const std::string& friendlyName,
|
||||
const std::string& pname,
|
||||
const std::vector<std::string>& args)
|
||||
const std::vector<std::string>& args,
|
||||
bool singleInstance)
|
||||
: m_callback(callback),
|
||||
m_uniqueName(uniqueName),
|
||||
m_friendlyName(friendlyName),
|
||||
m_pname(pname),
|
||||
m_args(args)
|
||||
m_args(args),
|
||||
m_singleInstance(singleInstance)
|
||||
{
|
||||
/* DBus single instance registration */
|
||||
bool isFirst;
|
||||
m_dbus = registerDBus(uniqueName.c_str(), isFirst);
|
||||
if (m_singleInstance)
|
||||
{
|
||||
if (!isFirst)
|
||||
{
|
||||
/* This is a duplicate instance, send signal and return */
|
||||
if (args.size())
|
||||
{
|
||||
/* create a signal & check for errors */
|
||||
DBusMessage*
|
||||
msg = dbus_message_new_signal("/boo/signal/FileHandler",
|
||||
"boo.signal.FileHandling",
|
||||
"Open");
|
||||
|
||||
/* append arguments onto signal */
|
||||
DBusMessageIter argsIter;
|
||||
dbus_message_iter_init_append(msg, &argsIter);
|
||||
for (const std::string& arg : args)
|
||||
{
|
||||
const char* sigvalue = arg.c_str();
|
||||
dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &sigvalue);
|
||||
}
|
||||
|
||||
/* send the message and flush the connection */
|
||||
dbus_uint32_t serial;
|
||||
dbus_connection_send(m_dbus, msg, &serial);
|
||||
dbus_connection_flush(m_dbus);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is the first instance, register for signal */
|
||||
// add a rule for which messages we want to see
|
||||
DBusError err = {};
|
||||
dbus_bus_add_match(m_dbus, "type='signal',interface='boo.signal.FileHandling'", &err);
|
||||
dbus_connection_flush(m_dbus);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open X connection */
|
||||
m_xcbConn = xcb_connect(NULL, NULL);
|
||||
|
||||
/* The xkb extension requests that the X server does not
|
||||
|
@ -157,9 +215,6 @@ public:
|
|||
if (xiReply)
|
||||
XINPUT_OPCODE = xiReply->major_opcode;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
~CApplicationXCB()
|
||||
|
@ -174,24 +229,73 @@ public:
|
|||
|
||||
void run()
|
||||
{
|
||||
if (!m_xcbConn)
|
||||
return;
|
||||
|
||||
xcb_generic_event_t* event;
|
||||
m_running = true;
|
||||
m_callback.appLaunched(this);
|
||||
xcb_flush(m_xcbConn);
|
||||
|
||||
while (m_running && (event = xcb_wait_for_event(m_xcbConn)))
|
||||
int xcbFd = xcb_get_file_descriptor(m_xcbConn);
|
||||
int dbusFd;
|
||||
dbus_connection_get_unix_fd(m_dbus, &dbusFd);
|
||||
int maxFd = MAX(xcbFd, dbusFd);
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
bool windowEvent;
|
||||
xcb_window_t evWindow = getWindowOfEvent(event, windowEvent);
|
||||
//fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event));
|
||||
if (windowEvent)
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(xcbFd, &fds);
|
||||
FD_SET(dbusFd, &fds);
|
||||
select(maxFd+1, &fds, NULL, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(xcbFd, &fds))
|
||||
{
|
||||
auto window = m_windows.find(evWindow);
|
||||
if (window != m_windows.end())
|
||||
window->second->_incomingEvent(event);
|
||||
event = xcb_poll_for_event(m_xcbConn);
|
||||
if (!event)
|
||||
break;
|
||||
|
||||
bool windowEvent;
|
||||
xcb_window_t evWindow = getWindowOfEvent(event, windowEvent);
|
||||
//fprintf(stderr, "EVENT %d\n", XCB_EVENT_RESPONSE_TYPE(event));
|
||||
if (windowEvent)
|
||||
{
|
||||
auto window = m_windows.find(evWindow);
|
||||
if (window != m_windows.end())
|
||||
window->second->_incomingEvent(event);
|
||||
}
|
||||
free(event);
|
||||
}
|
||||
|
||||
if (FD_ISSET(dbusFd, &fds))
|
||||
{
|
||||
DBusMessage* msg;
|
||||
dbus_connection_read_write(m_dbus, 0);
|
||||
while ((msg = dbus_connection_pop_message(m_dbus)))
|
||||
{
|
||||
|
||||
/* check if the message is a signal from the correct interface and with the correct name */
|
||||
if (dbus_message_is_signal(msg, "boo.signal.FileHandling", "Open"))
|
||||
{
|
||||
/* read the parameters */
|
||||
std::vector<const std::string> paths;
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
while (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INVALID)
|
||||
{
|
||||
const char* argVal;
|
||||
dbus_message_iter_get_basic(&iter, &argVal);
|
||||
paths.push_back(argVal);
|
||||
dbus_message_iter_next(&iter);
|
||||
}
|
||||
m_callback.appFilesOpen(this, paths);
|
||||
}
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
}
|
||||
free(event);
|
||||
}
|
||||
|
||||
m_callback.appQuitting(this);
|
||||
}
|
||||
|
||||
|
@ -199,6 +303,16 @@ public:
|
|||
{
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
const std::string& getUniqueName() const
|
||||
{
|
||||
return m_uniqueName;
|
||||
}
|
||||
|
||||
const std::string& getFriendlyName() const
|
||||
{
|
||||
return m_friendlyName;
|
||||
}
|
||||
|
||||
const std::string& getProcessName() const
|
||||
{
|
||||
|
|
|
@ -123,10 +123,12 @@ struct CTestApplicationCallback : public IApplicationCallback
|
|||
{
|
||||
delete mainWindow;
|
||||
}
|
||||
bool appFileOpen(IApplication*, const std::string& path)
|
||||
void appFilesOpen(IApplication*, const std::vector<const std::string>& paths)
|
||||
{
|
||||
printf("OPENING: %s\n", path.c_str());
|
||||
return true;
|
||||
fprintf(stderr, "OPENING: ");
|
||||
for (const std::string& path : paths)
|
||||
fprintf(stderr, "%s ", path.c_str());
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,7 +137,8 @@ struct CTestApplicationCallback : public IApplicationCallback
|
|||
int main(int argc, char** argv)
|
||||
{
|
||||
boo::CTestApplicationCallback appCb;
|
||||
boo::IApplication* app = IApplicationBootstrap(boo::IApplication::PLAT_AUTO, appCb, "RWK", argc, argv);
|
||||
boo::IApplication* app = IApplicationBootstrap(boo::IApplication::PLAT_AUTO,
|
||||
appCb, "rwk", "RWK", argc, argv);
|
||||
app->run();
|
||||
delete app;
|
||||
printf("IM DYING!!\n");
|
||||
|
|
Loading…
Reference in New Issue