root/trunk/gtk/old/application.d

Revision 8, 6.8 kB (checked in by Chris Miller, 5 years ago)

First steps of DFL GTK.

Line 
1 // See the included license.txt for copyright and license details.
2
3
4 ///
5 module dfl.application;
6
7 import dfl.base, dfl.event;
8 import dfl.form;
9 import dfl.internal.clib, dfl.internal.dlib, dfl.internal.gtk;
10
11
12 ///
13 class ApplicationContext // docmain
14 {
15     ///
16     this()
17     {
18     }
19    
20    
21     ///
22     // If onMainFormClose isn't overridden, the message
23     // loop terminates when the main form is destroyed.
24     this(Form mainForm)
25     {
26         mform = mainForm;
27         mainForm.closed ~= &onMainFormClosed;
28     }
29    
30    
31     ///
32     final void mainForm(Form mainForm) // setter
33     {
34         if(mform)
35             mform.closed.removeHandler(&onMainFormClosed);
36        
37         mform = mainForm;
38        
39         if(mainForm)
40             mainForm.closed ~= &onMainFormClosed;
41     }
42    
43     /// ditto
44     final Form mainForm() // getter
45     {
46         return mform;
47     }
48    
49    
50     ///
51     //EventHandler threadExit;
52     Event!() threadExit;
53    
54    
55     ///
56     final void exitThread()
57     {
58         exitThreadCore();
59     }
60    
61    
62     protected:
63    
64     ///
65     void exitThreadCore()
66     {
67         threadExit(this, EventArgs.empty);
68     }
69    
70    
71     ///
72     void onMainFormClosed(Object sender, EventArgs args)
73     {
74         exitThreadCore();
75     }
76    
77    
78     private:
79     Form mform; // The context form.
80     void delegate() _whileIdle;
81 }
82
83
84 private extern(C) gboolean _dflMainWhileIdle(gpointer data)
85 {
86     ApplicationContext appcon = cast(ApplicationContext)data;
87     appcon._whileIdle();
88     return true; // Continue.
89 }
90
91
92 ///
93 final class Application // docmain
94 {
95     private this() {}
96    
97    
98     static:
99    
100     void enableVisualStyles()
101     {
102     }
103    
104    
105     /+
106     /// Path of the executable including its file name.
107     char[] executablePath() // getter
108     {
109     }
110     
111     
112     /// Directory containing the executable.
113     char[] startupPath() // getter
114     {
115     }
116     +/
117    
118    
119     /+
120     ///
121     bool messageLoop() // getter
122     {
123         return (threadFlags & TF.RUNNING) != 0;
124     }
125     +/
126    
127    
128     /+
129     ///
130     void addMessageFilter(IMessageFilter mf)
131     {
132         //filters ~= mf;
133         
134         IMessageFilter[] fs = filters;
135         fs ~= mf;
136         filters = fs;
137     }
138     
139     /// ditto
140     void removeMessageFilter(IMessageFilter mf)
141     {
142         uint i;
143         for(i = 0; i != filters.length; i++)
144         {
145             if(mf is filters[i])
146             {
147                 if(!i)
148                     filters = filters[1 .. filters.length];
149                 else if(i == filters.length - 1)
150                     filters = filters[0 .. i];
151                 else
152                     filters = filters[0 .. i] ~ filters[i + 1 .. filters.length];
153                 break;
154             }
155         }
156     }
157     +/
158    
159    
160     /// Process all events in the mainloop. Returns false if the application should exit.
161     bool doEvents()
162     {
163         while(gtk_events_pending())
164         {
165             if(gtk_main_iteration())
166             {
167                 if(threadFlags & TF.QUIT)
168                     return false;
169             }
170         }
171         return true;
172     }
173    
174    
175     package void run2(ApplicationContext appcon)
176     {
177         if(threadFlags & TF.RUNNING)
178         {
179             //throw new DflException("Can only have one mainloop at a time");
180             assert(0, "Can only have one mainloop at a time");
181             return;
182         }
183        
184         if(threadFlags & TF.QUIT)
185         {
186             assert(0, "The application is shutting down");
187             return;
188         }
189        
190        
191         void threadJustExited(Object sender, EventArgs ea)
192         {
193             exitThread();
194         }
195        
196        
197         ctx = appcon;
198         ctx.threadExit ~= &threadJustExited;
199         try
200         {
201             threadFlags = threadFlags | TF.RUNNING;
202            
203             if(ctx.mainForm)
204             {
205                 //ctx.mainForm.createControl();
206                 ctx.mainForm.show();
207             }
208            
209             if(ctx._whileIdle)
210                 g_idle_add(&_dflMainWhileIdle, cast(gpointer)ctx);
211            
212             for(;;)
213             {
214                 try
215                 {
216                     gtk_main();
217                    
218                     // Stopped running.
219                     threadExit(Thread.getThis(), EventArgs.empty);
220                     threadFlags = threadFlags & ~(TF.RUNNING | TF.STOP_RUNNING);
221                     return;
222                 }
223                 catch(Object e)
224                 {
225                     onThreadException(e);
226                 }
227             }
228         }
229         finally
230         {
231             threadFlags = threadFlags & ~(TF.RUNNING | TF.STOP_RUNNING);
232            
233             if(ctx._whileIdle)
234                 g_idle_remove_by_data(cast(gpointer)ctx);
235            
236             ApplicationContext tctx;
237             tctx = ctx;
238             ctx = null;
239            
240             tctx.threadExit.removeHandler(&threadJustExited);
241         }
242     }
243    
244    
245     /// Run the application.
246     void run()
247     {
248         run2(new ApplicationContext);
249     }
250    
251     /// ditto
252     void run(void delegate() whileIdle)
253     {
254         run(new ApplicationContext, whileIdle);
255     }
256    
257     /// ditto
258     void run(ApplicationContext appcon)
259     {
260         run2(appcon);
261     }
262    
263     /// ditto
264     void run(ApplicationContext appcon, void delegate() whileIdle)
265     {
266         assert(whileIdle !is null);
267         appcon._whileIdle = whileIdle;
268         run2(appcon);
269     }
270    
271     /// ditto
272     void run(Form mainForm)
273     {
274         ApplicationContext appcon = new ApplicationContext(mainForm);
275         run2(appcon);
276     }
277    
278     /// ditto
279     void run(Form mainForm, void delegate() whileIdle)
280     {
281         ApplicationContext appcon = new ApplicationContext(mainForm);
282         run(appcon, whileIdle);
283     }
284    
285    
286     ///
287     void exit()
288     {
289         threadFlags = threadFlags | TF.QUIT;
290        
291         gtk_main_quit();
292     }
293    
294    
295     /// Exit the thread's mainloop and return from run.
296     // Actually only stops the current run() loop.
297     void exitThread()
298     {
299         threadFlags = threadFlags | TF.STOP_RUNNING;
300        
301         gtk_main_quit();
302     }
303    
304    
305     // Will be null if not in a successful Application.run.
306     package ApplicationContext context() // getter
307     {
308         return ctx;
309     }
310    
311    
312     /+
313     ///
314     HINSTANCE getInstance()
315     {
316         if(!hinst)
317             _initInstance();
318         return hinst;
319     }
320     
321     /// ditto
322     void setInstance(HINSTANCE inst)
323     {
324         if(hinst)
325         {
326             if(inst != hinst)
327                 throw new DflException("Instance is already set");
328             return;
329         }
330         
331         if(inst)
332         {
333             _initInstance(inst);
334         }
335         else
336         {
337             _initInstance(); // ?
338         }
339     }
340     +/
341    
342    
343     //private static class ErrForm: Form
344    
345    
346     /+
347     ///
348     bool showDefaultExceptionDialog(Object e)
349     {
350     }
351     +/
352    
353    
354     ///
355     void onThreadException(Object e)
356     {
357         // To-do: showDefaultExceptionDialog if no handlers.
358        
359         threadException(Thread.getThis(), new ThreadExceptionEventArgs(e));
360     }
361    
362    
363     ///
364     Event!(ThreadExceptionEventArgs) threadException;
365     ///
366     Event!() threadExit;
367    
368    
369     /+ // ?
370     ///
371     Resources resources() // getter
372     {
373     }
374     +/
375    
376    
377     ///
378     void autoCollect(bool byes) // setter
379     {
380         // To-do...
381         //assert(0, "Not implemented");
382     }
383    
384     /// ditto
385     bool autoCollect() // getter
386     {
387          // To-do...
388         return false;
389     }
390    
391    
392     /+
393     ///
394     // Because waiting for an event enters an idle state,
395     // this function fires the -idle- event.
396     void waitForEvent()
397     {
398         // Don't forget the autoCollect stuff.
399     }
400     +/
401    
402    
403     private:
404     //IMessageFilter[] filters;
405     ApplicationContext ctx = null;
406     uint threadFlags;
407    
408    
409     enum TF: uint
410     {
411         RUNNING = 1, // Application.run is in affect.
412         STOP_RUNNING = 2, // Application.exitThread was called.
413         QUIT = 4, // Application.exit was called.
414     }
415 }
416
417
418 package:
419
420 int dflargc = 0;
421 char*[1] _dflargva;
422 char** dflargv;
423
424 static this()
425 {
426     _dflargva[0] = null;
427     dflargv = _dflargva.ptr;
428    
429     if(!gtk_init_check(&dflargc, &dflargv))
430         throw new DflException("Unable to initialize GUI library");
431 }
Note: See TracBrowser for help on using the browser.