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

Revision 34065, 8.3 kB (checked in by saturday06, 5 years ago)

ce layout

Line 
1#pragma once
2#include "../Mil.h"
3#include "../ModuleCommon.h"
4#include "../Module.h"
5#include "../ModuleExecuteProxy.h"
6#include "WindowProcedureRedirector.h"
7
8#ifdef _MSC_VER
9// XXX
10#pragma warning (disable: 4100)
11#endif
12
13namespace mil
14{
15
16const UINT WM_MIL_GUIMODULE = WM_APP+100;
17
18/**
19 * public should be thread safe
20 */
21template <typename Child>
22class GuiModule : public ModuleCommon<GuiModule<Child> >
23{
24    class EventBase : boost::noncopyable
25    {
26    public:
27        //void (*execute)(void* event, void* target);
28    };
29
30    template <typename T>
31    class Event : public EventBase
32    {
33    public:
34        typedef T DataType;
35        int owner_id;
36        T data;
37    };
38
39    atomic<HWND> hSharedWnd;
40
41    //LONG_PTR breakLoopRequest;
42    PVOID breakLoopRequest;
43    //DWORD_PTR destroyed;
44    atomic<PVOID> destroyed;
45
46    bool repost;
47    bool handled;
48    LRESULT handled_result;
49
50protected:
51    HWND hLocalWnd;
52
53public:
54    Tls tls;
55
56    GuiModule() :
57            hSharedWnd(NULL),
58            breakLoopRequest(false),
59            destroyed(0),
60            repost(false),
61            handled(true),
62            handled_result(0),
63            hLocalWnd(NULL),
64            tls(this->thread_id),
65            wndproc(getChild())
66    {
67        set_auto_join(this);
68    }
69
70    void requestExit(void* event_memory)
71    {
72        ExitEvent e;
73        post(e, exitNotifier, event_memory, exitNotifier.tls.thread_id);
74        //destroyed.store((PVOID)1);
75        //this->join();
76    }
77
78    ~GuiModule()
79    {
80        do_auto_join();
81        HWND w = getWindow();
82        if (IsWindow(w))
83        {
84            if (DestroyWindow(w) == 0)
85            {
86                // error
87                //DebugBreak();
88            }
89        }
90        this->join();
91    }
92
93    template <typename Data, typename Sender>
94    static void dispatch(void* event_, void* target_)
95    {
96        typedef Child Target;
97        Target& target = *static_cast<Target*>(target_);
98        target.repost = false;
99
100        if (sizeof(Data) <= sizeof(LPARAM))
101        {
102            Data data;
103            memcpy(&data, &event_, sizeof(data));
104            mil::ModuleExecuteProxy<Data, Target>::execute(data, target);
105            if (!target.repost)
106            {
107                return;
108            }
109            LPARAM l = 0;
110            memcpy(&l, &data, sizeof(l));
111            void (*func)(void*, void*) = dispatch<Data, Child>;
112            PostMessage(target.hLocalWnd /* write operation should be done */ , WM_MIL_GUIMODULE,
113                        reinterpret_cast<WPARAM>(func), l);
114            return;
115        }
116
117        Event<Data>& event = *static_cast<Event<Data>*>(event_);
118        mil::ModuleExecuteProxy<Data, Target>::execute(event.data, target);
119        if (target.repost)
120        {
121            void (*func)(void*, void*) = dispatch<Data, Child>;
122            PostMessage(target.hLocalWnd /* write operation should be done */ , WM_MIL_GUIMODULE,
123                        reinterpret_cast<WPARAM>(func) ,
124                        reinterpret_cast<LPARAM>(&event));
125            return;
126        }
127
128        freeEvent<Sender>(event, target);
129    }
130
131protected:
132    void setWindow(HWND hWnd_)
133    {
134        hLocalWnd = hWnd_;
135        hSharedWnd.store(hWnd_);
136    }
137
138public:
139    HWND getWindow()
140    {
141        return hSharedWnd.load();
142    }
143
144    Child& getChild()
145    {
146        return *static_cast<Child*>(this);
147    }
148
149    void destroy()   //XXX thread safe
150    {
151        //PostQuitMessage(0);
152        breakLoopRequest = (PVOID)1;
153        destroyed.store((PVOID)1);
154        if (IsWindow(hLocalWnd))
155        {
156            if (DestroyWindow(hLocalWnd) == 0)
157            {
158                // error
159                //DebugBreak();
160            }
161        }
162        wndproc.inactivate();
163    }
164
165    void loop()
166    {
167        if (breakLoopRequest || destroyed.load() || !IsWindow(this->hLocalWnd))
168        {
169            return;
170        }
171
172        MSG msg = {};
173        while (__builtin_expect(!breakLoopRequest, true))
174        {
175            BOOL result = GetMessage(&msg, NULL, 0, 0);
176            if (!result)
177            {
178                break;
179            }
180            else if (result == -1)
181            {
182                // error
183                halt << msg.message;
184                break;
185            }
186            TranslateMessage(&msg);
187            DispatchMessage(&msg);
188        }
189    }
190
191    template <typename Sender>
192    HWND getCachedHWnd(Sender& sender) {
193        HWND hWnd = sender.tls.thread[this->thread_id].hWnd;
194        if (__builtin_expect(!hWnd, false))
195        {
196            hWnd = getWindow();
197            if (!IsWindow(hWnd))
198            {
199                return NULL;
200            }
201            sender.tls.thread[this->thread_id].hWnd = hWnd;
202        }
203        return hWnd;
204    }
205
206    template <typename T, typename Sender>
207    void post(const T& event, Sender& sender, void* memory, intptr_t owner_id)
208    {
209        Event<T>* e = new(memory) Event<T>;
210        e->data = event;
211        e->owner_id = owner_id;
212        void (*func)(void*, void*) = dispatch<T, Sender>;
213        HWND hWnd = getCachedHWnd(sender);
214        if (PostMessage(hWnd, WM_MIL_GUIMODULE,
215                        reinterpret_cast<WPARAM>(func),
216                        reinterpret_cast<LPARAM>(e)) == 0)
217        {
218            // error
219            //std::cout << "e" << std::flush;
220            //debug << "foo";
221            return;
222        }
223    }
224
225
226    template <typename T, typename Sender>
227    void post(const T& event, Sender& sender)
228    {
229        if (sizeof(T) <= sizeof(LPARAM))
230        {
231            HWND hWnd = getCachedHWnd(sender);
232            LPARAM l = 0;
233            memcpy(&l, &event, sizeof(l));
234            void (*func)(void*, void*) = dispatch<T, Sender>;
235            if (PostMessage(hWnd, WM_MIL_GUIMODULE,
236                        reinterpret_cast<WPARAM>(func),l) == 0)
237            {
238               //debug << "bar";
239            }
240            return;
241        }
242
243        mil::pool::Producer& producer = sender.tls.producer;
244        void* memory = producer.malloc<sizeof(Event<T>)>();
245        if (memory == NULL)
246        {
247            // XXX
248            return;
249        }
250        post(event, sender, memory, sender.tls.thread_id);
251    }
252
253    // Message Cracker Wizard for Win32 SDK Developers
254    // http://www.codeproject.com/KB/winsdk/msgcrackwizard.aspx
255#include "DummyMessageHandler-inl.h"
256
257protected:
258    void repostEvent()
259    {
260        repost = true;
261    }
262    void SetMsgHandled(bool handled_, LRESULT handled_result_ = 0)
263    {
264        handled = handled_;
265        handled_result = handled_result_;
266    }
267    LRESULT MessageMap(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
268    {
269        if (msg == mil::WM_MIL_GUIMODULE)
270        {
271            BOOST_STATIC_ASSERT(sizeof(EventBase*) == sizeof(lParam));
272            EventBase* e = reinterpret_cast<EventBase*>(lParam);
273            void (*func)(void*, void*) = reinterpret_cast<void (*)(void*, void*)>(wParam);
274            func(e, &getChild());
275            return 0;
276        }
277        else if (msg == WM_DESTROY || msg == WM_QUIT)
278        {
279            destroy();
280        }
281
282        // XXX will be return
283        switch (msg)
284        {
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    {
296        SetMsgHandled(true);
297        LRESULT result = MessageMap(hWnd, msg, wParam, lParam);
298        if (handled)
299        {
300            return result;
301        }
302        return DefWindowProc(hWnd, msg, wParam, lParam);
303    }
304
305    void execute_front()
306    {
307        MSG msg = {};
308        unsigned int loop = 10000;
309        while (PeekMessage (&msg,NULL,0,0,PM_REMOVE) != 0)
310        {
311            TranslateMessage(&msg);
312            DispatchMessage(&msg);
313            if (msg.message == WM_MIL_GUIMODULE)
314            {
315                return;
316            }
317            if (loop-- == 0)
318            {
319                return;
320            }
321        }
322    }
323
324    mil::WindowProcedureRedirector<
325    GuiModule<Child>, &GuiModule<Child>::WindowProcedure> wndproc;
326};
327
328}
Note: See TracBrowser for help on using the browser.