root/lang/objective-cplusplus/i3/trunk/src/mil/include/mil/gui-cocoa/GuiModule.h @ 33764

Revision 33764, 4.4 kB (checked in by saturday06, 4 years ago)

samazama

Line 
1#pragma once
2#include "../Mil.h"
3#include "../Module.h"
4#include "../ModuleExecuteProxy.h"
5
6namespace mil
7{
8
9/**
10 * public members should be thread safe
11 */
12template <typename Child>
13class GuiModule : public Thread<GuiModule<Child> >
14{
15public:
16    Tls tls;
17private:
18    class EventBase : public boost::intrusive::slist_base_hook<>, public boost::noncopyable
19    {
20    public:
21        void (*execute)(void* event, void* target);
22        intptr_t owner_id;
23    };
24
25    class EventList : public boost::noncopyable
26    {
27        boost::intrusive::slist<EventBase, boost::intrusive::constant_time_size<false>, boost::intrusive::cache_last<true> > l;
28        boost::details::pool::default_mutex m;
29        typedef boost::details::pool::guard<boost::details::pool::default_mutex> guard;
30    public:
31        void push(EventBase& e)
32        {
33            guard g(m);
34            l.push_back(e);
35        }
36
37        void pop()
38        {
39            guard g(m);
40            l.pop_front();
41        }
42
43        EventBase* top()
44        {
45            guard g(m);
46            if (l.size() == 0)
47            {
48                return NULL;
49            }
50            return &l.front();
51        }
52    };
53
54    template <typename T>
55    class Event : public EventBase
56    {
57    public:
58        T data;
59    };
60
61    friend class Module_test;
62
63private:
64    EventList list;
65    Conditional c;
66    bool repost;
67    mil::atomic<bool> isWaiting;
68protected:
69    NSWindow *window;
70
71public:
72    GuiModule() : tls(this->thread_id), repost(false), isWaiting(false), window(NULL)
73    {
74    }
75
76    Child& getChild()
77    {
78        return *static_cast<Child*>(this);
79    }
80
81protected:
82    void repostEvent()
83    {
84        repost = true;
85    }
86
87
88    template <typename Data, typename Sender>
89    static void dispatcher(void* event_, void* target_)
90    {
91        typedef Child  Target;
92
93        if (!event_ || !target_)
94        {
95            return;
96        }
97
98        // XXX type safety??
99        Target& target = *static_cast<Target*>(target_);
100        Event<Data>& event = *static_cast<Event<Data>*>(event_);
101        target.list.pop();
102        target.repost = false;
103        ModuleExecuteProxy<Data, Target>::execute(event.data, target);
104        if (target.repost) {
105            target.list.push(event);
106            return;
107        }
108        if (event.owner_id == target.thread_id) {
109            mil::pool::ReturnMemoryProxy<Data>::free(&event, target.tls.producer, mil::pool::Blocks<Event<Data> >::value);
110            return;
111        }
112        void* mem = NULL;
113        pool::MemoryList* m = NULL;
114        boost::tie(mem, m) = target.tls.consumer.work(&event);
115        if (!m) {
116            return;
117        }
118        pool::ReturnMemoryEvent<pool::Blocks<Event<Data> >::value> e;
119        e.memory = m;
120        void* t = threads[event.owner_id].load();
121        if (!t) {
122            return;
123        }
124        (reinterpret_cast<Sender*>(t))->post(e, target, mem, event.owner_id);
125    }
126public:
127    template <typename T, typename Sender>
128    void post(const T& event, Sender& sender, void* memory = NULL, intptr_t owner_id = 0)
129    {
130        void* p = NULL;
131        if (memory) {
132            p = memory;
133        } else {
134            mil::pool::Producer& producer = sender.tls.producer;
135            p = producer.malloc<sizeof(Event<T>)>();
136        }
137
138        if (p == NULL)
139        {
140            // XXX
141            return;
142        }
143
144        Event<T>* e = new(p) Event<T>;
145        e->data = event;
146        e->execute = dispatcher<T, Sender>;
147        if (memory) {
148            e->owner_id = owner_id;
149        } else {
150            e->owner_id = sender.tls.thread_id;
151        }
152
153        list.push(*e);
154        if (isWaiting.load()) {
155            c.signal();
156        }
157    }
158public:
159    void destroy()
160    {
161        if (!window)
162        {
163            return;
164        }
165        [window dealloc];
166        window = NULL;
167    }
168
169    ~GuiModule() {
170        ExitEvent e;
171        post(e, *this);
172        //destroy();
173        this->join();
174    }
175
176    void execute_front()
177    {
178        EventBase* e = list.top();
179        if (!e)
180        {
181            return;
182        }
183        e->execute((void*)e, (void*)this);
184    }
185
186    void mouseDown(NSEvent*) {
187    }
188protected:
189    void loop()
190    {
191        [[NSRunLoop currentRunLoop] run];
192        destroy();
193    }
194};
195
196}
Note: See TracBrowser for help on using the browser.