[cells-gtk-devel] start-app and multithreading?

Peter Hildebrandt peter.hildebrandt at gmail.com
Sun Dec 9 15:19:34 UTC 2007


On Thu, 06 Dec 2007 16:38:11 +0100, Ken Tilton <kennytilton at optonline.net>  
wrote:
> Peter Hildebrandt wrote:
>> On Tue, 04 Dec 2007 23:48:07 +0100, Ken Tilton  
>> <kennytilton at optonline.net>  wrote:
>>
>>> I just glanced at the GTk doc and did not see anything that would   
>>> support such a safety net, so you are probably on the right track   
>>> rolling one into Cells-Gtk. One might check with the GTk mailing list  
>>> to  see if we are missing something. Basically the Prime Directive in  
>>> these  GUI wrapper deals is to use the C library wherever possible.
>>   Thanks for the hint.  Indeed there is a way to do this with GTK.    
>> Actually, there is two:  The good people at  
>> gtk-app-devel-list at gnome.org  pointed me to gtk_quit_add [1] and  
>> gtk_quit_add_destroy [2].
>
> Cool.

They are part of my patch to cells-gtk I just mailed out.

>>  The former  registers a callback which is called once gtk-main quits,  
>> while the latter  simply schedules a window for destruction upon  
>> quitting the main app (as I  learned, this was discussed on the GTK  
>> mailing list in February 1999 [3]).
>>  http://mail.gnome.org/archives/gtk-list/1999-February/msg00577.html
>> [1]  
>> http://library.gnome.org/devel/gtk/2.12/gtk-General.html#gtk-quit-add
>> [2]   
>> http://library.gnome.org/devel/gtk/2.12/gtk-General.html#gtk-quit-add-destroy  
>>  [3] http://mail.gnome.org/archives/gtk-list/1999-February/msg00577.html
>>  I assume what we want is the former, that is code it along these lines
>>  - upon creation of a window we register a callback to dispose of the   
>> window once the app is closed (either md-awaken :after or  
>> make-instance  :after -- which one is more appropriate?  I'd go with  
>> the former,  since  this is the point in time where the window actually  
>> shows up on the screen)
>
> I think we want to register the callback as soon as possible so we do  
> not miss any action the GTk side -- I am imagining a sequence where  
> something goes wrong during window instantiation and GTk snuffs a window  
> while we are still going about building it from the Lisp side. Of course  
>   Gtk would complain about continued attempts to build a snuffed window,  
> but things might go more neatly if we avoid that by getting the callback  
> set up ASAP.

Yep, it's part of make-instance ((self window)) now.

> In the latest Cells (not yet pulled into Cells-GTk) there is an  
> elaborate scheme for handling such matters -- wherever messages get  
> prepped for Gtk they would get enqueued, not actually sent. Then Cells  
> allows the application to specify a custom handler for this queue, which  
> handler can sort the messages so they happen in just the right order. In  
> this case we would tag the creation message with :win-make and tag the  
> callback registration with :win-quit-cb-register and sort them to run  
> back to back. And in case anyone is thinking ahead, I believe there is  
> enough state information on the Lisp side to handle gracefully "snuff"  
> notifications that come in during window creation.

Well, of course that'd be a great project.  That would put us in a  
position to handle threading properly by wrapping the execution of the  
command queue win with-gdk-threads and thus be truly thread-safe in gdk  
terms.

Right now we ignore this issue more or less since it does not seem to be a  
problem.  (At least I haven't seen anything bad happen despite of some  
rigorous testing on test-gtk).  Maybe after all lisp does not really  
process stuff from the repl while in a C callback?

>
>>  - in the callback we finally call not-to-be on self to properly  
>> dispose of  the window.
>>
>>>>>> Is there anything wrong with hooking into md-awaken/not-to-be?  I
>>>>>> put the following in my code:
>>>>>>
>>>>>> (let ((open-windows nil))
>>>>>>    (defmethod md-awaken :after ((self window))
>>>>>>      (pushnew self open-windows))
>>>>>>    (defmethod not-to-be :before ((self window))
>>>>>>      (setf open-windows (delete self open-windows )))
>>>>>>    (defun not-to-be-all ()
>>>>>>      (mapcar #'not-to-be open-windows)
>>>>>>      (setf open-windows nil)))
>>>>>>
>>>>>> where not-to-be-all is called when the user closes the main window.
>>>>>> Appears to be working perfectly.  Am I missing something?
>>>>>
>>>>>
>>>>> Anyone?
>>>>
>>>>   It'd like to hear some comments, too.
>>>
>>>
>>> It's a toss-up. The above has a slight "backdoor" feel to it, but  
>>> that  might be the right way to go.
>>   It is definitely a hack.
>
> :) I did not mean anything disparaging by "backdoor". Indeed, we are at  
> the very boundary between C and Lisp "Gtks" where we might very much  
> /want/ to step out of the Cells machinery (but so far it looks like we  
> can stay within, if only because Cells does allow one to play with  
> md-awaken and not-to-be and get a c little closer to the action when  
> needed).

Well, actually it turned out that this way I might be messing with cells  
too much.  The mapcar #'not-to-be appears to be somewhat radical compared  
to a modest (not-to-be self) in the gtk-quit callback.

>>  That's why I'm discussing this issue with you  guys before publishing  
>> a patch.
>>
>>> Some background: Cells is all about making sure everything gets done  
>>> and  in the right order when things change. But because the Cells  
>>> engine is  ordering operations, interesting code is almost compelled  
>>> to play within  the Cells framework, or it misses out on vital action  
>>> (does not learn  about change) or at best runs at the wrong time.
>>   I think I understand.
>>
>>> If you creat a class called gtk-application and hang windows off that  
>>> as  kids of an instance of that, then you can just not-to-be that  
>>> instance  and have all windows tended to. Use of this instance gets  
>>> enforced  simply by having the md-awaken method merely enforce that  
>>> with a helpful  error message telling the developer the right way to  
>>> make a window (push  a new instance onto the kids of a gtk-application  
>>> instance.
>>   Well, the problem is that gtk-app is derived from window, hence its  
>> kids  are the widgets to be displayed within it.  As I mentioned  
>> before, I'd  like to maintain compatibility, thus I'd rather leave this  
>> as it is.  My  suggestion:
>>  We introduce a new class, gtk-application, which so far does nothing  
>> but  keep track of all windows opened by the app in its kids slots.
>
> <g> That is what I meant by gtk-app, which I did not know existed. <g>

Now we have a global variable *system*, and every window pushes itself  
open creation into the kids of *system*.  There is a function called  
(open-windows) that returns those kids which currently have a gtk  
representation.  (It appears I am not capable of removing a window from  
the kids of *system* without causing some cells havoc).  Still a hack, but  
closer to the Right Thing.  And once I figure it out, I can change it all  
internally wihtout modifying the interface.

> Is this the Windows model where a window (or the prime window) is the  
> same as an application? I grew up developing on the mac where one could  
> close all the windows and still have the app and its menu bar available.

Thanks for pointing that out.  Indeed I had the windowsy idea of a main  
window being equivalent to the app in mind (which seems to match the gtk  
philosophy).  Of course there is no point why a GUI toolkit should dictate  
this view.  The version I mailed out earlier today allows you work either  
way.

- Have a main app thread that is independent of any specific window and  
close it down at its on discretion (maybe a menu command or the like)
- Have a main window, closing which will result in closing all the other  
windows.

My current version supports only one app per image in the later model,  
whereas you can run several applications of the former kind within the  
same lisp image.

>> Since  not-to-be will remove them properly (and will be called either  
>> by the user  or through the callback), we do not have to keep track of  
>> that.  All  that's left to do is register new instances -- which I'd do  
>> within the  md-awaken method, so that instances are registered with the  
>> application  object at the same time the callback is registered.
>
> That would work. I do not mean to confuse things -- I think registering  
> for quits is still The Right Way meaning that is how windows would get  
> managed, but I might /still/ have gtk-application to support things like  
> my imagined menu of windows, drag/drop between windows, etc etc.

Yep, this is how it is done now.  gtk-quit closes windows if you want  
that, and (open-windows) gives you a list of all open instances of window  
(or its subclass gtk-app).

> Anyway, sounds like you are doing pretty good sorting this out, just  
> throwing thoughts over the wall.

Thanks!

Regards,
Peter



> cheers, ken




More information about the cells-gtk-devel mailing list