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

Revision 32286, 7.7 kB (checked in by saturday06, 5 years ago)

fu

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