ex11 - brain dump 1

Joe Armstrong joe@REDACTED
Wed Jan 14 11:06:15 CET 2004


Some more random thoughts:

I am now into "yet another" rewrite.

Here are some random design thoughts.

When an X event occurs you have to do something.
How should event processing be written:


-----------------
method 1)

The internal code in the display server did the following
To get an event to be processed I did the following:

	Display ! {onEvent, Win, Type, Fun/1}

The server remembers the fun. then when event Type with argument Args
occurs in Win the server did

	Fun(Args)

This is the good 'old "callback" style of programming

But what happens if Fun does not terminate or crashes - bad news

-----------------

method 2)

Same as above but I do

	spawn(fun() -> Fun() end)

when an event occurs

This *almost* worked but there are two problems

   a) What happens if the Fun is something like

	Fun(Event) ->
	    Pid !! op
	end.

      (answer possible deadlock - so funs must be carefully written)

   b) How can I synchronise execution of several callbacks

	annswer - you can't you must do it yourself

-----------------

method 3)

Junk the callbacks.

   I now send a

	{onevent, Win, Type, Pid, Tag}

   message to the server

   This means:

    If event Type occurs in Win then execute

	Pid ! {Tag, Event}

   This *cannot* fail for any reason

With this method a button widget looks like this

-module(swButton).

-export([make/8]).

-include("sw.hrl").

-import(ex11_lib, [ePolyText8/5, rpc/2, sleep/1, 
		   xClearArea/1,
		   xDo/2, xFlush/1,
		   xVar/2]).

make(Parent, X, Y, Width, Ht, Border, Color, Str) -> 
    Wargs = #win{x=X, y=Y, border=Border,width=Width,ht=Ht,color=Color, 
		 type=button, mask = ?EVENT_EXPOSURE bor 
		 ?EVENT_BUTTON_PRESS},
    sw:startWidget(Parent, Wargs, fun(D,W) -> init1(D,W,Str) end).

init1(Display, Wargs, Str) ->
    Win = Wargs#win.win,
    Bin =  ePolyText8(Win, xVar(Display, sysFontId), 10, 18, Str),


+------------------------------------------------------------+
|   Display ! {onEvent, Win, expose,      self(), expose1},  |
|   Display ! {onEvent, Win, buttonPress, self(), click},    |
|                                                            |
+------------------------------------------------------------+
 
   loop(Bin, Display, Wargs, fun(_) -> void end).

loop(B, Display, Wargs, Fun) ->
    receive
	{click, X} ->
	    flash(Display, Wargs),
	    Fun(X),
	    loop(B, Display, Wargs, Fun);
	{expose1, _} ->
	    xDo(Display, B),
	    xFlush(Display),
	    loop(B, Display, Wargs, Fun);
	{onClick, Fun1} ->
	    loop(B, Display, Wargs, Fun1);
	{set, Str} ->
	    Win = Wargs#win.win, 
	    xDo(Display, xClearArea(Win)),
	    Bin =  ePolyText8(Win, xVar(Display, sysFontId), 10, 18, Str),
	    loop(Bin, Display, Wargs, Fun);
	Any ->
	    io:format("Top loop got:~p~n", [Any]),
	    %% Now we call the generic operators
	    loop(B, Display, Wargs, Fun)
    end.

flash(Display, Wargs) ->
    S = self(),
    Win=Wargs#win.win,
    spawn(fun() ->
		  xDo(Display, xClearArea(Win)),
		  xFlush(Display),
		  sleep(200),
		  S ! {expose1, void}
	  end).


So far I can see no disadvanges with this.

I am re-writing all the widgets in this style.




On Wed, 14 Jan 2004, Vlad Dumitrescu wrote:

> Hi,
> 
> I thought I'd share some random and unsorted thoughts I had about a widget
> framework. Nothing revolutionary, but why let them go to waste? :-)
> 
> * widget users should see only generic events, not X ones. By that I mean there
> should be a generic protocol (as is sketched in ex11_widget_button) for example
> onClick, onDoubleClick, onEnter, onKeyPressed, onMouseMove, onMouseButtonDown,
> etc. Maybe even onCreate, onDestroy?
> 
> * the event handlers should get the widget pid as an argument, so that they can
> react according to the current state. For example draw_button() paints slightly
> different if the button is pressed.
> 
> * the !! operator is cool, but it should be used with care. Maybe the
> implementation of sysd:rpc should be refined to include timeouts and the
> possibility to get the reply later (à la gen_server). The reason is that if
> there are several widgets interacting (i.e. their states are interdependent)
> it's very easy to get a deadlock.
>     For example radio buttons work as a unit.
> 
> * there is some GUI functionality that isn't local to a widget (even if it may
> seem to be). For example tab order is known at parent window level, so the
> parent window should get the opportunity to see keypresses before the child,
> filtering tabs out (unless the child specifically wants to get them).
> 
> * there will be quite a bit of functionality common for many widgets. I think
> there should be a way to reuse it without resorting to cut-and-paste techniques
> ;-) I won't mention inheritance (oops, I just did!) because there are other
> ways - like for example providing plenty of hook points and functionality for
> adding/removing custom hooks (à la Emacs).
>     For example implementing a tri-state button would require very little
> changes to a regular button.
> 
> * It would be good if we could find an existing framework from which to map the
> functionality. There's no need to make all mistakes from scratch. Most
> frameworks are OO and make heavy use of inheritance, which is not a good
> starting point, but see above.
> 
> That's it for now. Cheers!
> /Vlad
> 




More information about the erlang-questions mailing list