Hi Andy, since the marshalling of bit-fields is difficult, it might be worthwhile trying to do things completely differently.
You could try to serialize an event using the following strategy: - query the size of the event - read each of the bytes in an event and serialize them (in hex or so) - for each pointer in each of the different events, store a set of functions to - read this pointer and to compare it with known objects, if no there is no "known" object, return Nothing which should stop the marshalling of the whole event - provide a function that re-inserts the corresponding object in the de-serialized event at the client Example: a button press event is received: you serialize all the bytes in this event 00 22 33 7f 28 etc the button press event has two pointers, the GdkWindow and the GdkDevice, so the list needs two function pairs: [(findWindow, replaceWindow), (findDevice, replaceDevice)] the findWindow :: Ptr Event -> Maybe () always returns Just () since replaceWindow will always replace the GdkWindow field with the local window the event is sent to the findDevice :: Ptr Event -> Maybe () returns Just () if the GdkDevice in the structure is the same as the default Device, if it is a different Device, it returns Nothing (it could return other values than () if it knows about several devices). At the client the function replaceDevice will update the Event structure by replacing the device pointer with the pointer to the standard device at the client. the key press event could then have the following functions: [(findWindow, replaceWindow), (findString, replaceString)] where findString always returns Just str where str is the pointed-to string. The type of the replace functions would have to be similar to the 'with' function to get the memory management right. Cheers, Axel On 05.07.2010, at 08:09, Andy Stewart wrote: > Hi Axel, > > Axel Simon <axel.si...@in.tum.de> writes: > >> 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. > I see. > I suppose i can omit field if this field is deprecated. > >> >>>> 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 > Thanks, has fix in darcs repo. >> >>> >>> ------------------------------> new version start >>> <------------------------------ >>> data SerializedEvent = >>> SerializedEvent >>> {sEventValue :: SerializedEventValue >>> ,sEventTime :: Word32 >>> ,sEventWindow :: Maybe DrawWindow} >>> >> >> This data type is superfluous! > Indeed, i have remove it. > >>> >>> 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! > Infact, i don't know how to write C function to access this > bitfield, then i > omit this field. > > Axel, can you help me write this C function? > Or have similar gtk2hs code that i can study? > >> 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. > Hmm, looks field "axes" and "device" is correlative. > I need research those two fields deeply. > > Cheers, > > -- Andy > >> 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