1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
#pragma once
#include "EventLoop.h"
#include "Interface.h"
#include "Log.h"
#include "Sync.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <cassert>
#include <thread>
#include <mutex>
#include <atomic>
#include <list>
#include <unordered_map>
namespace vst {
namespace X11 {
class Window;
class EventLoop : public BaseEventLoop {
public:
static EventLoop& instance();
EventLoop();
~EventLoop();
bool available() const {
return display_ != nullptr;
}
void run();
void quit();
bool sync();
bool callSync(UIThread::Callback cb, void *user);
bool callAsync(UIThread::Callback cb, void *user);
Display *getDisplay() { return display_; }
::Window getRoot() { return root_; }
void registerWindow(Window* w);
void unregisterWindow(Window* w);
using EventHandlerCallback = void (*)(int fd, void *obj);
void registerEventHandler(int fd, EventHandlerCallback cb, void *obj);
void unregisterEventHandler(void *obj);
using TimerCallback = void (*)(void *obj);
void registerTimer(int64_t ms, TimerCallback cb, void *obj);
void unregisterTimer(void *obj);
private:
void startPolling() override;
void stopPolling() override;
void initUIThread();
void pushCommand(UIThread::Callback cb, void *obj);
void doRegisterTimer(int64_t ms, TimerCallback cb, void *obj);
void doUnregisterTimer(void *obj);
int updateTimers();
void pollFileDescriptors(int timeout);
void pollX11Events();
void handleCommands();
void notify();
Window* findWindow(::Window handle);
Display *display_ = nullptr;
::Window root_ = 0;
std::thread thread_;
int displayfd_ = -1;
int eventfd_ = -1;
std::atomic<bool> running_{false};
std::mutex syncMutex_;
SyncCondition event_;
std::vector<Window *> windows_;
struct Command {
UIThread::Callback cb;
void *obj;
};
std::vector<Command> commands_;
std::mutex commandMutex_;
struct EventHandler {
void *obj;
EventHandlerCallback cb;
};
std::unordered_map<int, EventHandler> eventHandlers_;
using Clock = std::chrono::high_resolution_clock;
using Milliseconds = std::chrono::milliseconds;
using TimePoint = std::chrono::time_point<Clock, Milliseconds>;
struct Timer {
struct Compare {
bool operator()(const Timer& a, const Timer& b) const {
if (a.deadline > b.deadline) {
return true;
} else if (a.deadline < b.deadline) {
return false;
} else {
return a.sequence > b.sequence;
}
}
};
TimerCallback cb = nullptr;
void *obj = nullptr;
int64_t interval;
uint64_t sequence; // keep insertion order
TimePoint deadline;
};
std::vector<Timer> timerQueue_;
uint64_t timerSequence_ = 0;
};
class Window : public IWindow {
public:
Window(Display &display, IPlugin& plugin);
~Window();
void open() override;
void close() override;
void setPos(int x, int y) override;
void setSize(int w, int h) override;
void resize(int w, int h) override;
void onClose();
void onConfigure(int x, int y, int width, int height);
void onUpdate();
void *getHandle() { return (void *)window_; }
private:
bool canResize() const;
Display *display_;
IPlugin *plugin_;
::Window window_ = 0;
Rect rect_{ 100, 100, 0, 0 }; // empty rect!
// helper methods
void doOpen();
void doClose();
void setFixedSize(int w, int h);
void savePosition();
struct Command {
Window *owner;
int x;
int y;
};
};
} // X11
} // vst
|