Page 1 of 2

[RESOLVED] How to Trap a GTK Event?

Posted: Tue Oct 11, 2005 6:48 pm
by Straker
Hi all,

I am trying to trap a mouseover event on an ImageGadget in GTK/Linux, but have no idea how to do this. Specifically I am trying to emulate the Firefox Preferences toolbar which highlights graphics when a mouse moves over them, then changes to a darker color when selected. Its the mouseover that I am having trouble with.

Or better yet, can anyone describe how to trap any/all GTK events? (here's a similar windows thread: viewtopic.php?t=12352 )

Here is a screenshot showing the event in Linux:

Image

Thanks

Posted: Fri Oct 14, 2005 3:02 am
by Beach
I would like to know how to do this also. :)

Posted: Fri Oct 14, 2005 6:38 am
by Straker
Thanks Beach. I was getting kinda lonely here by myself.

Posted: Fri Oct 14, 2005 10:06 am
by Fred
I think you will have to connect a "enter-notify-event" signal and a "leave-notify-event" to the widget and handle you code in the associated callbacks : http://developer.gnome.org/doc/API/2.0/ ... tify-event
for a complete list of events for widgets (the ImageGadget() is a GtkPixmap).

Posted: Fri Oct 14, 2005 4:56 pm
by Beach
Fred wrote:I think you will have to connect a "enter-notify-event" signal and a "leave-notify-event" to the widget and handle you code in the associated callbacks
Nice, thanks Fred!

@Straker; let me know if you figure it out first. :)

Posted: Fri Oct 14, 2005 5:18 pm
by freak
This comes from the top of my head (no linux right now), so expect some mistakes :)

Code: Select all

; Wrapper to call the correct function for both Gtk Versions.
; #GTKVersion must be defined somewhere!
#GtkVersion = 1
;
Procedure GTKSignalConnect(*Widget, Signal$, Function, user_data)
  CompilerIf #GTKVersion = 1
    gtk_signal_connect_(*Widget, @Signal$, Function, user_data)
  CompilerElse
    g_signal_connect_data_(*Widget, @Signal$, Function, user_data, 0, 0)
  CompilerEndIf
EndProcedure


; This is a signal callback. Note the CDLL declaration. that is important.
; the user_data field helps to pass additional data.
;
ProcedureCDLL EventCallback(*Widget, *Event.GdkEventCrossing, user_data)
  If user_data = 1
    Debug "Enter Event"
  Else
    Debug "Leave Event"
  EndIf
EndProcedure


; connect the signals...
GTKSignalConnect(GadgetID(#MyGAdget), "enter-notify-event", @EventCallback(), 1)
GTKSignalConnect(GadgetID(#MyGAdget), "leave-notify-event", @EventCallback(), 2)
Something like that...

Posted: Fri Oct 14, 2005 6:31 pm
by Straker
Wow - thanks for the response guys. I will be testing this today. I have been browsing this area as well:

http://lidn.sourceforge.net

I am no C programmer, and am a n00b with regards to callbacks and pointers, but I'll try to cobble some code together and post it back here.

Thanks again.

Posted: Fri Oct 14, 2005 8:21 pm
by Straker
OK - This is not working, however, some things to note:

1) I added the gtk_init_() and gdk_init_() functions which I found in another thread. Don't know if these are required but they don't appear to be harmful.

2) the GtkVersion can be obtained directly with #GTK_MAJOR_VERSION (link).

3) replace "MyImage.s" var below with your own image to test.

4) I just confirmed in a bug report that the ImageGadget on Linux does not appear to be capturing any events. So, I don't know if the following code is not working because of that bug or if the code is wrong (but it compiles and runs without apparent error). More details here.

Code: Select all

gtk_init_(0,0)
gdk_init_(0,0)

Procedure GTKSignalConnect(*Widget, Signal$, Function, user_data)
  CompilerIf #GTK_MAJOR_VERSION = 1
    gtk_signal_connect_(*Widget, @Signal$, Function, user_data)
  CompilerElse
    g_signal_connect_data_(*Widget, @Signal$, Function, user_data, 0, 0)
  CompilerEndIf
EndProcedure


; This is a signal callback. Note the CDLL declaration. that is important.
; the user_data field helps to pass additional data.
;
ProcedureCDLL EventCallback(*Widget, *Event.GdkEventCrossing, user_data)
  If user_data = 1
    Debug "Enter Event"
  Else
    Debug "Leave Event"
  EndIf
EndProcedure

UseJPEGImageDecoder()
#MyGAdget = 0
MyImage.s = "r2d2.jpg"

  If OpenWindow(0,0,0,345,105,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"ImageGadget") And CreateGadgetList(WindowID(0))
    If LoadImage(0, MyImage.s)    ; change 2nd parameter to the path/filename of your image
      ImageGadget(#MyGAdget, 10,10,100,83,UseImage(0))                      ; imagegadget standard
      ;ImageGadget(1,130,10,100,83,UseImage(0),#PB_Image_Border)     ; imagegadget with border
      ButtonGadget(1, 200, 10, 100, 30, "Test")
      ; connect the signals...
      GTKSignalConnect(GadgetID(#MyGAdget), "enter-notify-event", @EventCallback(), 1)
      GTKSignalConnect(GadgetID(#MyGAdget), "leave-notify-event", @EventCallback(), 2) 


   Repeat
     EventID = WaitWindowEvent()
     
     Select EventID
     
       Case #PB_Event_Gadget
         Select EventGadgetID()
           Case 0 : Debug "Image 0 clicked!"
           Case 1 : Debug "Button 1 clicked!"
         EndSelect
     
     EndSelect
   Until EventID = #PB_Event_CloseWindow


    EndIf
    
  EndIf
Any comments are appreciated.

Thanks again.

Posted: Fri Oct 14, 2005 11:56 pm
by freak
Sorry, i did not read about the ImageGadget part...

The fact is that a GtkPixmap (ImageGadget) does not have an associated gdk window
like the other widgets have. (the contents seem to be directly drawn on the parent)
So you cannot receive such events from the ImageGadget.
Its not PB's fault.. its a Gtk thing.

What you have to do is put it on a ContainerGadget with the same size and
register the callback for that gadget.
I did the same for the IDE colorpicker and it works well.

About the gtk_init_(). It is called PB's initialisation functions once you use
any of the Gadget/Window commands afaik.

Posted: Sat Oct 15, 2005 9:06 pm
by Straker
Thanks freak. But I am not having any luck with the container gadget either. The button gadget works fine with your code however. Run the following test program to see the difference.

Code: Select all

Procedure GTKSignalConnect(*Widget, Signal$, Function, user_data)
  CompilerIf #GTK_MAJOR_VERSION = 1
    gtk_signal_connect_(*Widget, @Signal$, Function, user_data)
  CompilerElse
    g_signal_connect_data_(*Widget, @Signal$, Function, user_data, 0, 0)
  CompilerEndIf
EndProcedure

; This is a signal callback. Note the CDLL declaration. that is important.
; the user_data field helps to pass additional data.
;
ProcedureCDLL EventCallback(*Widget, *Event.GdkEventCrossing, user_data)
  Select user_data
   Case 1 : Debug "container enter event"
   Case 2 : Debug "container leave event"
   Case 3 : Debug "button enter event"
   Case 4 : Debug "button leave event"
  EndSelect
EndProcedure

#MyContainer = 10
#MyButton = 11

If OpenWindow(0,0,0,345,105,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"Event Test") And CreateGadgetList(WindowID(0))
  ButtonGadget(#MyButton, 200, 10, 100, 30, "Test")
  ContainerGadget(#MyContainer, 10,10,100,83,#PB_Container_Raised)
    
  ; connect the signals...
  GTKSignalConnect(*GadgetID(#MyContainer), "enter-notify-event", @EventCallback(), 1)
  GTKSignalConnect(*GadgetID(#MyContainer), "leave-notify-event", @EventCallback(), 2) 

  GTKSignalConnect(*GadgetID(#MyButton), "enter-notify-event", @EventCallback(), 3)
  GTKSignalConnect(*GadgetID(#MyButton), "leave-notify-event", @EventCallback(), 4) 

  Repeat
     EventID = WaitWindowEvent()
          
     Select EventID
     
       Case #PB_Event_Gadget
         Select EventGadgetID()
           Case #MyContainer : Debug "Container clicked!"
           Case #MyButton : Debug "Button clicked!"
         EndSelect
     
     EndSelect
   Until EventID = #PB_Event_CloseWindow
    
EndIf

End
I have also been experimenting with GtkEventBox but to no avail.

Thanks.

Posted: Thu Dec 01, 2005 8:09 am
by Shannara
Any news on this?

Posted: Thu Dec 01, 2005 11:39 pm
by Straker
Not as of yet. I did PM another member about it - but never got a response.

Maybe DarkDragon can shed some light on this, as I know he has been digging into the GTK/GDK interfaces.

If not - I was planning on converting this C code which does this, but so far, I have not been able to get it to work either. If anyone wants to take a shot at it here it is:

http://www.gtk.org/tutorial/c1247.html

If we can figure out how to bind GTK EventBoxes, then we should be able to map any event to any control.

Posted: Fri Dec 02, 2005 12:29 am
by KarLKoX
ATM, it is difficult to me to find enough spare time on coding :(
I ll let you know if i could dig a bit.

Posted: Fri Dec 02, 2005 3:00 am
by Straker
Thanks for the reply.
KarLKoX wrote:ATM, it is difficult to me to find enough spare time on coding :(
I am also in this situation right now.

Cheers.

Possible solution?

Posted: Fri Mar 03, 2006 4:52 am
by StanDan
I tried a couple different things. Including using an evenbox.

Code: Select all

Procedure GTKSignalConnect(*Widget, Signal$, Function, user_data)
  CompilerIf #GTK_MAJOR_VERSION = 1
    gtk_signal_connect_(*Widget, @Signal$, Function, user_data)
  CompilerElse
    g_signal_connect_data_(*Widget, @Signal$, Function, user_data, 0, 0)
  CompilerEndIf
EndProcedure

; This is a signal callback. Note the CDLL declaration. that is important.
; the user_data field helps to pass additional data.
;
ProcedureCDLL EventCallback(*Widget, *Event.GdkEventCrossing, user_data)
  Select user_data
   Case 1 : Debug "container enter event"
   Case 2 : Debug "container leave event"
   Case 3 : Debug "button enter event"
   Case 4 : Debug "button leave event"
  EndSelect
EndProcedure

#MyContainer = 10
#MyButton = 11

If OpenWindow(0,0,0,345,105,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"Event Test") And CreateGadgetList(WindowID(0))
  ButtonGadget(#MyButton, 200, 10, 100, 30, "Test")
  ContainerGadget(#MyContainer, 10,10,100,83,#PB_Container_Raised)
  *event_box.GtkWidget = gtk_event_box_new_()
  gtk_container_add_(*GadgetID(#MyContainer), *event_box)
  gtk_widget_show_(*event_box)
  ; connect the signals...
  
  gtk_widget_set_events_(*event_box, #GDK_ENTER_NOTIFY_MASK | #GDK_LEAVE_NOTIFY_MASK);
  GTKSignalConnect(*event_box, "enter-notify-event", @EventCallback(), 1)
  GTKSignalConnect(*event_box, "leave-notify-event", @EventCallback(), 2)

  GTKSignalConnect(*GadgetID(#MyButton), "enter-notify-event", @EventCallback(), 3)
  GTKSignalConnect(*GadgetID(#MyButton), "leave-notify-event", @EventCallback(), 4)
  gtk_widget_realize_(*event_box);
  Repeat
     EventID = WaitWindowEvent()
         
     Select EventID
     
       Case #PB_Event_Gadget
         Select EventGadgetID()
           Case #MyContainer : Debug "Container clicked!"
           Case #MyButton : Debug "Button clicked!"
         EndSelect
     
     EndSelect
   Until EventID = #PB_Event_CloseWindow
   
EndIf

End 
But this doesn't work. Very frusterating.

Anyway, did you try just using a button and packing the stuff into it? This actually does work.

Code: Select all

Procedure GTKSignalConnect(*Widget, Signal$, Function, user_data)
  CompilerIf #GTK_MAJOR_VERSION = 1
    gtk_signal_connect_(*Widget, @Signal$, Function, user_data)
  CompilerElse
    g_signal_connect_data_(*Widget, @Signal$, Function, user_data, 0, 0)
  CompilerEndIf
EndProcedure

; This is a signal callback. Note the CDLL declaration. that is important.
; the user_data field helps to pass additional data.
;
ProcedureCDLL EventCallback(*Widget, *Event.GdkEventCrossing, user_data)
  Select user_data
   Case 1 : Debug "container enter event"
   Case 2 : Debug "container leave event"
   Case 3 : Debug "button enter event"
   Case 4 : Debug "button leave event"
  EndSelect
EndProcedure

; from the GTK+ tutorial
Procedure.l xpm_label_box( xpm_filename$, label_text$ )
    *box.GtkWidget;
    *label.GtkWidget;
    *image.GtkWidget;

    ;/* Create box For image And label */
    *box = gtk_hbox_new_(#FALSE, 0);
    gtk_container_set_border_width_(*box, 2);

    ;/* Now on To the image stuff */
    *image = gtk_image_new_from_file_(xpm_filename$);

    ;/* Create a label For the button */
    *label = gtk_label_new_(label_text$);

    ;/* Pack the image And label into the box */
    gtk_box_pack_start_(*box, *image, #FALSE, #FALSE, 3);
    gtk_box_pack_start_(*box, *label, #FALSE, #FALSE, 3);

    gtk_widget_show_(*image);
    gtk_widget_show_(*label);

    ProcedureReturn *box
EndProcedure

#MyContainer = 10
#MyButton = 11

If OpenWindow(0,0,0,345,105,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"Event Test") And CreateGadgetList(WindowID(0))
  ButtonGadget(#MyButton, 200, 10, 100, 30, "Test")
  ContainerGadget(#MyContainer, 10,10,100,83,#PB_Container_Raised)
  *box.GtkWidget = xpm_label_box("/tmp/test.xpm", "Testing!")
  *button.GtkWidget = gtk_button_new_()
  ; /* Pack And show all our widgets */
  gtk_widget_show_(*box);
  gtk_container_add_(*button, *box);

  gtk_container_add_(*GadgetID(#MyContainer), *button)
  gtk_widget_show_(*button)
  ; connect the signals...
  
  GTKSignalConnect(*button, "enter-notify-event", @EventCallback(), 1)
  GTKSignalConnect(*button, "leave-notify-event", @EventCallback(), 2)

  GTKSignalConnect(*GadgetID(#MyButton), "enter-notify-event", @EventCallback(), 3)
  GTKSignalConnect(*GadgetID(#MyButton), "leave-notify-event", @EventCallback(), 4)
  gtk_widget_realize_(*event_box);
  Repeat
     EventID = WaitWindowEvent()
         
     Select EventID
     
       Case #PB_Event_Gadget
         Select EventGadgetID()
           Case #MyContainer : Debug "Container clicked!"
           Case #MyButton : Debug "Button clicked!"
         EndSelect
     
     EndSelect
   Until EventID = #PB_Event_CloseWindow
   
EndIf

End 
You could set the colors in the callback.