Hi Andy,

On Jul 4, 2010, at 16:20, Andy Stewart wrote:
>>
>> pokeSerializedEventKey ptr (SerializedEvent
>> (SerializedEventKeyValue
>> {
>> [..]
>> ,sEventString = string_
>> }) window_) = do
>> str <- newCString string_
>> [..]
>> #{poke GdkEventKey, string} ptr str
>> Here, you leak the space of str. To fix this, you need to revamp the
>> whole code.
> Yes, it's a bug.
> I should ignore "string" field since it's has deprecated and should
> never be used.
>

No, you cannot omit any field of the event structure. You have to  
store everything, every field, with every pointer (to a string or  
other structure) that exists. Even though a field might be deprecated,  
it could still be used in a widget, esp in earlier versions of Gtk.  
Please make sure you store every field of the event structure.

>> Instead of using
>> with event $ \eventPtr -> runReaderT fun (castPtr eventPtr)
>> you need to write your own function that allocates space not only  
>> for the event structure but also
>> for the referenced structures, e.g. the  string. All of these  
>> structures must be freed
>> afterwards. Thus,  instead of 'with' you need to write your own  
>> function using 'alloca'.
>>
>> So I wonder if making you SerializedEvent an instance of Storable  
>> is really helpful as the 'sizeOf'
>> and the 'with' function that uses the  'poke' method need to be  
>> spacial.
> Yes, you're right! instance Storable is less help, i should use  
> allocaBytes.
>
> How about this?
>
> ------------------------------> new version start  
> <------------------------------
> deserializeEvent :: SerializedEventValue -> DrawWindow -> (EventM t  
> a) -> IO a
> deserializeEvent value drawWindow fun = do
>  -- We need use *client* value replace field of event.
>  let event = SerializedEvent value currentTime (Just drawWindow)
>  allocaBytes (sizeOfSerializedEvent event) $ \eventPtr -> do
>    pokeSerializedEvent eventPtr event

Well, you can't use pokeSerializedEvent since you need a function that  
also allocates bytes for the string (and other structures that the  
event points to). Something like:

deserializeEvent value drawWindow fun = do
   let execFun = case sEventType value of
     #{const GDK_KEY_PRESS}           -> withKeyEvent
     #{const GDK_KEY_RELEASE}         -> withKeyEvent
     #{const GDK_BUTTON_PRESS}        -> withButtonEvent
     #{const GDK_2BUTTON_PRESS}       -> withButtonEvent
     #{const GDK_3BUTTON_PRESS}       -> withButtonEvent
     #{const GDK_BUTTON_RELEASE}      -> withButtonEvent
    execFun drawWindow value $ runReaderT fun

withKeyEvent :: DrawWindow -> SerializedEvent -> (Ptr Event -> IO a) - 
 > IO a
withKeyEvent win SerializedEventKeyValue
                              {sEventType        = typ_
                              ,sEventSent        = sent_
                              ,sEventTime        = time_
                              ,sEventState       = state_
                              ,sEventKeyval      = keyval_
                              ,sEventLength      = length_
                              ,sEventString      = string_
                              ,sEventKeycode     = keycode_
                              ,sEventGroup       = group_
                              } act = do
   withCString string_ $ \str -> do
   allocaBytes #{size GtkKeyEvent} $ \ptr -> do
   #{poke GdkEventKey, type}             ptr ((fromIntegral  
typ_)        ::#gtk2hs_type GdkEventType)
   case (fromMaybe (DrawWindow nullForeignPtr) window_) of
     win_ -> withForeignPtr (unDrawWindow win_) $ \winPtr ->
                    #{poke GdkEventKey, window} ptr winPtr
   #{poke GdkEventKey, send_event}       ptr ((fromBool  
sent_)           ::#gtk2hs_type gint8)
   #{poke GdkEventKey, time}             ptr ((fromIntegral  
time_)       ::#gtk2hs_type guint32)
   #{poke GdkEventKey, state}            ptr ((fromIntegral  
state_)      ::#gtk2hs_type guint)
   #{poke GdkEventKey, keyval}           ptr  
(keyval_                    ::#gtk2hs_type guint)
   #{poke GdkEventKey, length}           ptr ((fromIntegral  
length_)     ::#gtk2hs_type gint)
   #{poke GdkEventKey, string}           ptr str
   #{poke GdkEventKey, hardware_keycode} ptr  
(keycode_                   ::#gtk2hs_type guint16)
   #{poke GdkEventKey, group}            ptr  
(group_                     ::#gtk2hs_type guint8)
   act ptr

>
> ------------------------------> new version start  
> <------------------------------
> data SerializedEvent =
>    SerializedEvent
>    {sEventValue       :: SerializedEventValue
>    ,sEventTime        :: Word32
>    ,sEventWindow      :: Maybe DrawWindow}
>

This data type is superfluous!
>
> BTW, do you want merge SerializedEvent.hsc into gtk2hs repo?
> Or i release it as individual package?
>

I'm happy to have it in Gtk2Hs.

I'm concerned that you're not transmitting all the data that there is  
in an event:

See:

http://library.gnome.org/devel/gdk/stable/gdk-Event-Structures.html#GdkEventKey

typedef struct { GdkEventType type; GdkWindow *window; gint8  
send_event; guint32 time; guint state; guint keyval;   gint length;  
gchar *string; guint16 hardware_keycode; guint8 group; guint  
is_modifier : 1; } GdkEventKey;

So there is the is_modifier field for which you need to write a C  
function to access it (neither hsc2hs nor c2hs can handle bit fields).  
Of course you can ignore it, but it could lead to unexpected bugs. At  
least you need to ensure that you know how to set a certain field. You  
cannot leave it randomly set!
Also:
typedef struct { GdkEventType type; GdkWindow *window; gint8  
send_event; guint32 time; gdouble x; gdouble y; gdouble *axes; guint  
state; guint button; GdkDevice *device; gdouble x_root, y_root; }  
GdkEventButton;

This structure contains a pointer to a GdkDevice. You could compare  
that if it's the mouse (say) and then only send it if it is the mouse.  
Then you need to re-insert the GdkDevice pointer to the standard mouse  
at the client side.
The accessor functions in EventM only give provide the most useful  
fields in the event structure. This is exactly because it is  
impossible to marshall all the fields to Haskell and then marshall  
them all back in case you want to re-use the whole event structure.  
(Well, it also has to do with memory management.)

Cheers,
Axel


> Cheers,
>
>  -- Andy
>
>>
>> Cheers,
>> Axel
>>
>> On Jul 3, 2010, at 20:06, Andy Stewart wrote:
>>
>>> Hi Axel,
>>>
>>> Axel Simon <axel.si...@in.tum.de> writes:
>>>
>>>> On 30.06.2010, at 17:34, Andy Stewart wrote:
>>>>>>>
>>>>>>> So my question is how to binding gtk_main_do_event ?
>>>>>>> Looks I should use Graphics.UI.Gtk.Gdk.Events.Event and not  
>>>>>>> EventM.
>>>>>>>
>>>>>>
>>>>>> Event is deprecated and will be removed soon. The problem with  
>>>>>> the C
>>>>>> Event structure is that it can contains pointers and varying  
>>>>>> fields.
>>>>>> Event did not mangage to translate all of them, also because new
>>>>>> event
>>>>>> are being added to Gtk+ occasionally. If you want to convert a C
>>>>>> Event
>>>>>> structure completely to Haskell, send it over the network and  
>>>>>> then
>>>>>> reemit the event inside a different application, I suggest that  
>>>>>> you
>>>>>> start with the Event module and create an opaque but serializable
>>>>>> data
>>>>>> type. This data type should contain some events of interest  
>>>>>> (keys,
>>>>>> mouse) but not all events. You would probably need to re-insert  
>>>>>> the
>>>>>> time stamp of the event when you reemit it in the other  
>>>>>> application.
>>>>>>
>>>>>> If you implement this, then the extraction of an event should  
>>>>>> be a
>>>>>> function
>>>>>>
>>>>>> serializeEvent :: EventM t SerializedEvent
>>>>>>
>>>>>> that runs in the EventM monad. It should throw an exception if  
>>>>>> it is
>>>>>> applied to an event that it can't handle.
>>>>>>
>>>>>> Then at the client side, we can implement gtk_main_do_event as
>>>>>>
>>>>>> mainDoEvent :: EventM t ()
>>>>>>
>>>>>> and have
>>>>>>
>>>>>> deserializeEvent :: SerializedEvent -> (EventM t a) -> IO a
>>>>>>
>>>>>> which executes any EventM function with the serialized event.
>>>>>>
>>>>>> Let me know if you need further help. The functions in Event.hs  
>>>>>> may
>>>>>> help you to get started with marshalling the events, but you  
>>>>>> should
>>>>>> use the EventM interface as described above.
>>>>> For make problem simpler, let us just think GdkEventKey.
>>>>>
>>>>> I have below SerializedEventKey for serialized the value of
>>>>> GdkEventKey
>>>>> on *Server* side.
>>>>>
>>>>> data SerializedEventKey =
>>>>>                  -- sEventType          :: Int               --
>>>>> get EventType when deserialize
>>>>
>>>> No, you need to get the event type from the event itself. You don't
>>>> know what the event type is at the deserialisation point.
>>>>
>>>>>                  -- ,sEventWindow       :: DrawWindow        --
>>>>> get DrawWindow when deserialize
>>>>>                  -- ,sEventTime         :: TimeStamp         --
>>>>> get TimeStamp when deserialize
>>>>>
>>>>>  SerializedEventKey {sEventSent         :: Bool
>>>>>                     ,sEventState        :: [Modifier]
>>>>>                     ,sEventKeyval       :: KeyVal
>>>>>                     ,sEventLength       :: Int
>>>>>                     ,sEventString       :: String
>>>>>                     ,sEventKeycode      :: Word16
>>>>>                     ,sEventGroup        :: Word8
>>>>>                     ,sEventIsModifier   :: Bool}
>>>>>
>>>>> I use below function to pick-up SerializeEventKey value from  
>>>>> EventM
>>>>> monad at *Server* side:
>>>>>
>>>>> serializedEventKey :: EventM EKey SerializedEventKey
>>>>> serializedEventKey = do
>>>>> sent       <- eventSent
>>>>> state      <- eventModifier
>>>>> keyval     <- eventKeyVal
>>>>> string     <- eventKeyName
>>>>> keycode    <- eventHardwareKeycode
>>>>> group      <- eventKeyboardGroup
>>>>> liftIO $ return $
>>>>>  SerializedEventKey sent
>>>>>                     state
>>>>>                     keyval
>>>>>                     (length string)
>>>>>                     string
>>>>>                     keycode
>>>>>                     group
>>>>>                     False
>>>>>
>>>>
>>>> Ok. I was suggesting a function that can deal with several,  
>>>> different
>>>> events. You could copy and paste code from the deprecated Event  
>>>> module.
>>>>
>>>>> Now we can send SerializedEventKey value to *client* side through
>>>>> DBus-system.
>>>>>
>>>>> When *client* receive the value of SerializedEventKey,
>>>>> We can use
>>>>>
>>>>> "deserializeEvent :: SerializedEventKey -> IO EventKey"
>>>>>
>>>>> add three new values:
>>>>>
>>>>>  sEventType          : GDK_KEY_RELEASE or GDK_KEY_PRESS
>>>>>  sEventWindow        : The DrawWindow of *client* that event focus
>>>>>  sEventTime          : The TimeStamp when *client* process re-emit
>>>>> key event
>>>>>
>>>>> to re-build EventKey.
>>>>>
>>>>> Because gtk_main_do_event need GdkEvent, so we transfer EventKey  
>>>>> to
>>>>> is okay.
>>>>>
>>>>
>>>> What is EventKey?
>>>>
>>>> What EventM is doing is to wrap a pointer to a C event struct. So  
>>>> your
>>>> EventKey could be a ForeignPtr to a C event struct and mainDoEvent
>>>> could take this ForeignPtr and call the main_do_event function  
>>>> with it.
>>>>
>>>> Or you could provide a function
>>>>
>>>>>> deserializeEvent :: SerializedEvent -> (EventM t a) -> IO a
>>>>
>>>> that executes the action with a pointer to a C event struct (and
>>>> destroys the memory associated with this pointer after the action  
>>>> has
>>>> finished). The mainDoEvent can send this event by reading this  
>>>> pointer.
>>>>
>>>> The advantages:
>>>>
>>>> - you can use mainDoEvent not only on deserialized events, but  
>>>> also on
>>>> local events in any event callback
>>>> - you can use other functions to query a deserialized event,  
>>>> e.g., you
>>>> could check if the deserialized event is a left-mouse-button  
>>>> click and
>>>> only call mainDoEvent on those
>>>>
>>>> It's more consistent with the rest of the interface.
>>> I success!
>>>
>>> Code at
>>>
>> https://patch-tag.com/r/AndyStewart/gtk-serialized-event/snapshot/current/content/pretty/Graphics/UI/Gtk/Gdk/SerializedEvent.hsc
>>>
>>> Can you help me review it?
>>>
>>> In EventM,
>>>
>>>  sEvent <- serializedEvent
>>>
>>> will got SerializedEventValue, you can pass SerializedEventValue  
>>> over the network.
>>>
>>> When client receive SerializedEventValue from network, client can  
>>> use
>>> below code propagate same event at child process:
>>>
>>>    drawWindow <- widgetGetDrawWindow targetWidget
>>>    postGUIAsync $ deserializeEvent event drawWindow (widgetEvent  
>>> targetWidget) >> return ()
>>>
>>> Demo at
>>>
>> https://patch-tag.com/r/AndyStewart/gtk-serialized-event/snapshot/current/content/pretty/demo/Main.hs
>>>
>>> To test demo program, you need install below packages:
>>>
>>>  dbus-core, dbus-client, webkit
>>>
>>> and apply the patch i send.
>>>
>>> Here is demo screenshot : 
>>> http://farm5.static.flickr.com/4080/4758242386_5230d3d54d_b.jpg
>>>
>>> Since Events.hsc has deprecated, i guess you don't like  
>>> SerializedEvent style.
>>> I need merge SerializedEvent.hsc into gtk2hs or release it as  
>>> individual package?
>>>
>>> Cheers,
>>>
>>> -- Andy
>>>
>>>
>>>
>>>
>>>
>>> ------------------------------------------------------------------------------
>>> This SF.net email is sponsored by Sprint
>>> What will you do first with EVO, the first 4G phone?
>>> Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
>>> _______________________________________________
>>> Gtk2hs-devel mailing list
>>> Gtk2hs-devel@lists.sourceforge.net
>>> https://lists.sourceforge.net/lists/listinfo/gtk2hs-devel


------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________
Gtk2hs-devel mailing list
Gtk2hs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gtk2hs-devel

Reply via email to