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

Revision 37777, 8.1 kB (checked in by saturday06, 3 years ago)

elaaaaaaaaa

Line 
1#pragma once
2
3#include "../Memory.h"
4#include "../ModuleCommon.h"
5#include "WindowProcedureRedirector.h"
6
7#ifdef _MSC_VER
8// XXX
9#pragma warning (disable: 4100)
10#endif
11
12namespace mil {
13
14/**
15* public should be thread safe
16*/
17template <typename Child>
18class GuiModule : public ModuleCommon<GuiModule<Child> > {
19public:
20    MIL_CRTP_CLASS_MEMBERS;
21
22private:
23    class EventBase : public boost::noncopyable {
24    public:
25        thread::id_t getThreadId() {
26            return pool::MemoryHeader::get((void*)this).getThreadId();
27        }
28        void (*execute)(void* event, void* target);
29        EventBase* next;
30    };
31
32    class EventList : public boost::noncopyable {
33        EventBase* head;
34        EventBase* tail;
35        Mutex mutex;
36    public:
37        EventList() {
38            head = NULL;
39            tail = NULL;
40        }
41
42        bool push(EventBase& e) {
43            synchronized (mutex) {
44                e.next = NULL;
45                if (head == NULL) { // tail == NULL
46                    head = &e;
47                    tail = &e;
48                    return true;
49                }
50                tail->next = &e;
51                tail = &e;
52            }
53            return false;
54        }
55
56        EventBase* pop() {
57            EventBase* result = NULL;
58            synchronized (mutex) {
59                if (!head) {
60                    return NULL;
61                }
62                result = head;
63                head = head->next;
64            }
65            return result;
66        }
67
68        void clear() {
69            synchronized (mutex) {
70                head = NULL;
71                tail = NULL;
72            }
73        }
74    };
75protected:
76    template <typename T>
77    class Event : public EventBase {
78    public:
79        typedef T DataType;
80        T data;
81    };
82
83private:
84    EventList list;
85    Semaphore semaphore;
86    bool repost;
87    bool handled;
88    LRESULT handled_result;
89protected:
90    bool break_loop_request;
91public:
92    atomic<HWND> window;
93    atomic<bool> break_loop_request_shared;
94protected:
95    HWND local_window;
96
97public:
98    GuiModule() :
99            window(NULL),
100            break_loop_request(false),
101            break_loop_request_shared(false),
102            repost(false),
103            handled(true),
104            handled_result(0),
105            local_window(NULL),
106            wndproc(getChild()) {
107    }
108
109    void requestExit(void* event_memory) {
110        list.clear();
111        break_loop_request_shared.store(true);
112        exitNotifier.tls.flush();
113        ExitEvent e;
114        post(e, exitNotifier, event_memory);
115    }
116
117    ~GuiModule() {
118        do_auto_join();
119        HWND w = getWindow();
120        if (IsWindow(w)) {
121            if (DestroyWindow(w) == 0) {
122                // error
123                //DebugBreak();
124            }
125        }
126        this->join();
127    }
128
129    template <typename Data, typename Sender>
130    static void dispatcher(void* event_, void* target_) {
131        typedef Child Target;
132
133        // XXX type safety??
134        Target& target = *static_cast<Target*>(target_);
135        Event<Data>& event = *static_cast<Event<Data>*>(event_);
136        //target.list.pop();
137        target.repost = false;
138        ModuleExecuteProxy::execute<Data, Target>(event.data, target);
139        if (target.repost) {
140            target.list.push(event);
141            return;
142        }
143
144        dispatcher_free_event<Event<Data>, Target, Sender>(event, target);
145    }
146
147    template <typename T, typename Sender>
148    void post(const T& event, Sender&, void* memory) {
149        Event<T>* e = new(memory) Event<T>;
150        e->data = event;
151        e->execute = dispatcher<T, Sender>;
152
153        if (list.push(*e)) {
154            semaphore.passeren();
155        }
156    }
157
158    template <typename T, typename Sender>
159    void post(const T& event, Sender& sender) {
160        pool::Producer& producer = sender.tls.producer;
161        void* memory = producer.allocate(sizeof(Event<T>));
162        if (unlikely(memory == NULL)) {
163            halt << "can't allocate event memory";
164            return;
165        }
166
167        post(event, sender, memory);
168    }
169
170protected:
171    void setWindow(HWND hWnd_) {
172        local_window = hWnd_;
173        window.store(hWnd_);
174        wndproc.set(hWnd_);
175    }
176
177public:
178    HWND getWindow() {
179        return window.load();
180    }
181
182    void destroy() { //XXX thread safe
183        //PostQuitMessage(0);
184        break_loop_request = true;
185        break_loop_request_shared.store(true);
186
187        // DestroyWindow -> dtor
188
189        //if (IsWindow(local_window))
190        //{
191        //    if (DestroyWindow(local_window) == 0)
192        //    {
193        //        // error
194        //        //DebugBreak();
195        //    }
196        //}
197        wndproc.inactivate();
198    }
199
200    void createUI() { // XXX UI or Gui
201    }
202
203    void run() {
204        MIL_MODULE_GET_SUPER_CHILD(*this).createGui();
205        MIL_MODULE_GET_SUPER_CHILD(*this).loop();
206    }
207
208    void loop() {
209        if (break_loop_request || break_loop_request_shared.load() || !IsWindow(this->local_window)) {
210            return;
211        }
212
213        assert(GetWindowThreadProcessId(this->local_window, NULL) == GetCurrentThreadId());
214
215        MSG msg = {};
216
217        for (;;) {
218            DWORD wakeup = MsgWaitForMultipleObjects(1, &(semaphore.handle), false, INFINITE, QS_ALLINPUT);
219            if (wakeup == WAIT_OBJECT_0) {
220                execute_front();
221            }
222
223            MSG msg;           
224            bool b = false;
225            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
226                // dirty if-condition is for most expected branch
227                if (msg.message != WM_QUIT) {
228                    TranslateMessage(&msg);
229                    DispatchMessage(&msg);
230                    if (likely(!break_loop_request)) {
231                        continue;
232                    } else {
233                        b = true;
234                        break;
235                    }
236                } else {
237                    return;     
238                }
239            }
240            if (likely(!b)) {
241                continue;
242            } else {
243                break;
244            }
245        }
246    }
247
248    template <typename Sender>
249    HWND getCachedWindow(Sender& sender, bool flush = false) {
250        // XXX must compare no cached
251        if (!flush) {
252            HWND window = sender.tls.getData(this->thread_id).window_cache;
253            if (window) {
254                return window;
255            }
256        }
257
258        HWND window = getWindow();
259        if (!IsWindow(window)) {
260            return NULL;
261        }
262        sender.tls.getData(this->thread_id).window_cache = window;
263        return window;
264    }
265
266    // Message Cracker Wizard for Win32 SDK Developers
267    // http://www.codeproject.com/KB/winsdk/msgcrackwizard.aspx
268#include "DummyMessageHandler-inl.h"
269
270protected:
271    void repostEvent() {
272        repost = true;
273    }
274    void SetMsgHandled(bool handled_, LRESULT handled_result_ = 0) {
275        handled = handled_;
276        handled_result = handled_result_;
277    }
278    LRESULT MessageMap(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
279        if (msg == WM_DESTROY || msg == WM_QUIT) {
280            destroy();
281        }
282
283        // XXX will be return
284        switch (msg) {
285#include "MessageCracker-inl.h"
286        default:
287            SetMsgHandled(false);
288            break;
289        }
290
291        return handled_result;
292    }
293public:
294    LRESULT WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
295        SetMsgHandled(true);
296        LRESULT result = MessageMap(hWnd, msg, wParam, lParam);
297        if (handled) {
298            return result;
299        }
300        return DefWindowProc(hWnd, msg, wParam, lParam);
301    }
302
303    bool execute_front() {
304        EventBase* e = list.pop();
305        if (!e) {
306            return false;
307        }
308        e->execute((void*)e, (void*)this);
309        return true;
310    }
311
312    mil::WindowProcedureRedirector<
313    GuiModule<Child>, &GuiModule<Child>::WindowProcedure> wndproc;
314};
315
316}
Note: See TracBrowser for help on using the browser.