File: WindowX11.h

package info (click to toggle)
pd-vstplugin 0.6.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,008 kB
  • sloc: cpp: 22,794; lisp: 2,860; makefile: 37; sh: 26
file content (158 lines) | stat: -rw-r--r-- 3,789 bytes parent folder | download
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