Hi Axel,

Axel Simon <axel.si...@in.tum.de> writes:

> H Andy,
>
> a few comment:
>
> - you make your SerializedEvent an instance of Storable. That could work, but 
> you really have to
> ensure that the size of the C structure  you allocated is big enough. At the 
> moment, you have
>
> instance Storable SerializedEvent where
> sizeOf _ = #{const sizeof (GdkEventKey)}
> This should be
> sizeOf _ = maximum [#{const sizeof (GdkEventKey)}, #{const sizeof 
> (GdkEventButton)}]
> i.e. the maximum of any event you event want to marshal.
I create Storable instance when i just have GdkEventKey.
And i think i need drop Storable instance, it's less help with SerializedEvent.

>
> The next problem I see is with pointers in the event structure. Data 
> structures that the event
> structure reference must be serialized as  well (which is not too hard and 
> which you've
> done). However, when you  deserialize these you need to re-create
> these structures. 
> At the  moment
> you have:
>
> 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.

> 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
    runReaderT fun eventPtr

sizeOfSerializedEvent event = do
  let eType = fromIntegral $ sEventType $ sEventValue event 
  (case eType of
     #{const GDK_KEY_PRESS}           -> #{const sizeof (GdkEventKey)}
     #{const GDK_KEY_RELEASE}         -> #{const sizeof (GdkEventKey)}
     #{const GDK_BUTTON_PRESS}        -> #{const sizeof (GdkEventButton)}
     #{const GDK_2BUTTON_PRESS}       -> #{const sizeof (GdkEventButton)}
     #{const GDK_3BUTTON_PRESS}       -> #{const sizeof (GdkEventButton)}
     #{const GDK_BUTTON_RELEASE}      -> #{const sizeof (GdkEventButton)}
     ty                               -> error ("sizeOfSerializedEvent: haven't 
support event type " ++ show ty)) 
------------------------------> new version end   
<------------------------------

allocaBytes will allocated enough space for different event type.

>
> Also, since you're not using the time field, why have it in SerializedEvent?
Yes, it's wrong.

Now i use below code fix this problem.

------------------------------> new version start 
<------------------------------
data SerializedEvent =     
    SerializedEvent
    {sEventValue       :: SerializedEventValue
    ,sEventTime        :: Word32
    ,sEventWindow      :: Maybe DrawWindow}
                     
data SerializedEventValue = 
    SerializedEventKeyValue 
    {sEventType      :: Int
    ,sEventSent      :: Bool
    ,sEventState     :: Int
    ,sEventKeyval    :: KeyVal
    ,sEventLength    :: Int
    ,sEventKeycode   :: Word16
    ,sEventGroup     :: Word8}
  | SerializedEventButtonValue
    {sEventType      :: Int
    ,sEventSent      :: Bool
    ,sEventX         :: Double
    ,sEventY         :: Double
    ,sEventState     :: Int
    ,sEventButton    :: Int
    ,sEventXRoot     :: Double
    ,sEventYRoot     :: Double}
    deriving (Show, Read, Eq, Ord)
------------------------------> new version end   
<------------------------------

Thank you for correcting my mistake!

You can find new version at 
https://patch-tag.com/r/AndyStewart/gtk-serialized-event/snapshot/current/content/pretty/Graphics/UI/Gtk/Gdk/SerializedEvent.hsc
Please let me know if you find any problem in my new code.

BTW, do you want merge SerializedEvent.hsc into gtk2hs repo?
Or i release it as individual package?

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