Rerouting Events to other Gadgets ?

Linux specific forum
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Rerouting Events to other Gadgets ?

Post by grabiller »

Hi,

Is it possible to reroute an Event from one Gadget to another one ?

For instance let says I have a CanvasGadget and a StringGadget and I want to resend the '#PB_EventType_LeftButtonDown' recieved by the CanvasGadget to the StringGadget when I recieve it.

Is it possible directly in PureBasic ?

On Windows I workaround the problem by subclassing the control, but on linux, I'm not sure what to do.

Any idea ?

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

Never mind,

Got the solution:

PB_Gadget_SendGadgetCommand.l(Window.l, EventType.l)

(Internal PB command imported through Import "")

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

Hmm, in fact, it's for Windows only, it does not work for Linux..

So my question is still valid.

If someone has an idea ?

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
idle
Always Here
Always Here
Posts: 6026
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Rerouting Events to other Gadgets ?

Post by idle »

There are numerous ways to do it but the easiest is to add a signal callback to a gadget
on 32 bit linux you can use

g_signal_connect(gadgetID,Signal$,*function,*userdata)

for 64 bit you need to import it

ImportC "-gtk"
gsignal_connect(instance,signal.p-ascii,*fn,*vdata,destroy=0,flags=0) As "g_signal_connect_data"
EndImport

for details of the signals see http://developer.gnome.org/gtk/2.24/GtkWidget.html

Here's an example of a workaround fix for the calender gadget so it behaves like it does on windows

Code: Select all

ImportC  "-gtk"
  gsignal_connect(instance,signal.p-ascii,*fn,*vdata,destroy=0,flags=0) As "g_signal_connect_data"
  g_object_set_property(*widget,prop.p-ascii,*val.GValue); ;PB import not defined right for unicode  
  g_date_new()   ;pb import not defined right 
  g_date_valid(*date.GDate) ;pb import not defined right
EndImport 

Macro G_TYPE_MAKE_FUNDAMENTAL(x)
  ((x) << 2)
EndMacro
#G_TYPE_BOOLEAN = G_TYPE_MAKE_FUNDAMENTAL(5)

Prototype ProtoDateCB(date.s) 
Global iCurrentDate.s,idateinvalid.i,ikey

ProcedureC iDateGadgetClick(*editable.GtkEditable,*event.GdkEventButton,*usrdata)
  Protected startpos,*entry.GtkEntry,currentdate.s
  ;get the current date abd set the selection
  *entry = *editable 
  iCurrentdate = PeekS(*entry\text,*entry\text_length,#PB_UTF8) 
  startpos = gtk_editable_get_position_(*editable) 
  If (startpos <> 2 And startpos <> 5) 
    gtk_editable_select_region_(*editable,startpos,startpos+1);
  EndIf 
EndProcedure 

ProcedureC iDateGadgetKeyPress(*editable.GtkEditable,*event.GdkEventKey,*usrdata)
   Protected key,startpos,*entry.GtkEntry 
   Protected *date
   ;need to test if the key entry is going to result in a valid date 
   ;so check the current entry text and replace the charicter with the new one 
   key = *event\keyval & $FF  
   If key >= '0' And key <= '9'
     ikey=1
     *date = g_date_new()
     *entry = *editable 
     startpos = gtk_editable_get_position_(*editable) 
     tdate.s = PeekS(*entry\text,*entry\text_length,#PB_UTF8 )
     key = *event\keyval & $FF  
     tdate = Left(tdate,startpos-1) + Chr(key) + Right(tdate,10-startpos)
     g_date_set_parse_(*date,tdate)
     If g_date_valid(*date) 
        iCurrentDate = tdate 
     Else 
       idateinvalid =1
     EndIf  
     g_date_free_(*date) 
   EndIf  
 EndProcedure  
 
 ProcedureC iDateGadgetKeyRel(*editable.GtkEditable,*event.GdkEventKey,*usrdata)
  Protected key,startpos 
 ;handle arrow keys to move selection 
  startpos = gtk_editable_get_position_(*editable) 
  key = *event\keyval & $FF
  If startpos > 0
    If key = 81 
      If (startpos <> 3 And startpos <> 6)   
        startpos -1
      Else 
        startpos-2
      EndIf   
       gtk_editable_select_region_(*editable,startpos,startpos+1);
    ElseIf key = 83 
      If (startpos <> 1 And startpos <> 4)   
        startpos +1
      Else 
        startpos +2
      EndIf   
       gtk_editable_select_region_(*editable,startpos,startpos+1);
    EndIf   
  EndIf 
EndProcedure  

ProcedureC iDateChanged(*entry.GtkEntry,*usrdata)
  Protected sdate.s, cb.ProtoDateCB 
  Protected *date
  Static eat 
  cb = *usrdata
  If Not idateinvalid 
    If Not ikey 
       sdate = Trim(PeekS(*entry\text,*entry\text_length,#PB_UTF8 ))
      cb(sdate)
    Else 
      ikey=0
    EndIf
   Else   
     ;if the date is invalid reset it to the last entry   
     gtk_entry_set_text_(*entry,iCurrentDate)
    idateinvalid = 0
   EndIf   
 EndProcedure 

;user functions

Procedure DateGadgetEx(gadget,x,y,width,height,format.s,*cbDateChanged) 
  Protected *entry,gad
  Protected gval.GValue
  If gadget = #PB_Any 
      gad = DateGadget(gadget, x, y, width, height,format)
  Else 
     DateGadget(gadget, x, y, width, height,format)
     gad = gadget 
  EndIf   
  If *cbDateChanged  
      *entry = GadgetID(gad);gtk_widget_get_ancestor_(GadgetID(gad), gtk_entry_get_type_());
      If *entry
          g_value_init_(@gval,#G_TYPE_BOOLEAN) 
          g_value_set_boolean_(@gval, #True)
          g_object_set_property(*entry,"editable",@gval);
          gtk_entry_set_max_length_(*entry,10)
          gsignal_connect(*entry,"button-release-event",@iDateGadgetClick(),0)
          gsignal_connect(*entry,"key-release-event",@iDateGadgetKeyRel(),0)
          gsignal_connect(*entry,"key-press-event",@iDateGadgetKeyPress(),0)
          gsignal_connect(*entry,"changed",@iDateChanged(),*cbDateChanged)
          ProcedureReturn gad    
      EndIf 
 EndIf 
 ProcedureReturn gad 
 EndProcedure 

Procedure DateChanged(sdate.s)
  Debug sdate
EndProcedure 

If OpenWindow(0, 0, 0, 300, 300, "DateGadgetTest", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  DateGadgetEx(1, 8, 8, 120, 28, "%dd.%mm.%yyyy",@DateChanged())
          
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_Gadget
        Debug "In Linux no event at all"
      Case #PB_Event_CloseWindow
        Break
    EndSelect
  ForEver
EndIf
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

That's exactly what I was looking for.

A big thanks to you.

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

In fact I would need an additional information:

Once I'm in the iDateGadgetClick callback for instance, what should I do to 'pass-through' or 're-send' the same event I just recieve to another Widget ?

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
idle
Always Here
Always Here
Posts: 6026
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Rerouting Events to other Gadgets ?

Post by idle »

you can use

Code: Select all

gtk_signal_emit_by_name_(GadgetID,"signal",0);
and catch the event in the main loop
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

idle wrote:you can use

Code: Select all

gtk_signal_emit_by_name_(GadgetID,"signal",0);
and catch the event in the main loop
Ah, thanks a lot, it seems to be the solution yes, but strangely when I use it to send to the "other" GadgetID I get an "Invalid Memory Access" (yet the pointer is not null) while when I send it to itself it works ( I get multiple events ).

Yet the "other" GadgetID is used with other gtk api calls without triggering the error. It works.

I'm puzzled.. I'll investigate further..


Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

I've found the solution, I have to make room for the returned values:

gtk_signal_emit_by_name( GadgetID, "button-press-event", @event, @retval )

It does not crash anymore.

However the signal is not resent in the PB event main loop. Are you sure it should appear in the event main loop ?

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
User avatar
idle
Always Here
Always Here
Posts: 6026
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Rerouting Events to other Gadgets ?

Post by idle »

some but not all events will be caught in the main loop.
but I suppose you could connect a callback to handle the emitted signal.
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
grabiller
Enthusiast
Enthusiast
Posts: 309
Joined: Wed Jun 01, 2011 9:38 am
Location: France - 89220 Rogny-Les-Septs-Ecluses
Contact:

Re: Rerouting Events to other Gadgets ?

Post by grabiller »

That's what I'm doing but then I need to forward the signal to another widget wich does not recieve the user inputs.

Connecting callbacks to this other widget would be useless as it wont recieve events.

Anyway, I'm still investigating but I'm also reconsidering my linux approach.

Until now I was trying to 'port' my windows code wich works perfectly well (very fast, very easy to forward messages, to alter widgets programmaticaly and have immediate update of the layout before it gets painted, wich does not work on linux afaik).

But perhaps I should considere a different way more suitable to linux/gtk. The challenge beeing to achieve the exact same look and behavior of the widgets accross plateforms (and I did not touched Mac OS X yet.. ). This is the foundation of a heavy project and before I go any further I need to do this part absolutely right.

Someone on IRC suggested me to use only GTK on all tree platforms but I'm not convainced. From my experiments, native win32 UI is much faster (but perhaps someone will prove me wrong) and UI performance is also a big concern to me. Cocoa should be faster than gtk too on Mac ( but I did not use it yet so I can't really be sure). Plus, that would defeat the purpose of taking advantage of PureBasic and it's cross-plateform loop/events system (even though there is a need to use natives api calls here and there but this is far different from integrating a all new toolkit on all tree plateforms into PB).

This is not an easy problem, but I want to find the best approach. Perhaps I should forget all about native api calls and only use custom widgets entierly done in PB with the CanvasGadget. That's what I'll experiment next, I'm not sure about the performances of this approach yet but perhaps this is the solution.

Cheers,
Guy.
guy rabiller | radfac founder / ceo | raafal.org
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: Rerouting Events to other Gadgets ?

Post by BorisTheOld »

To avoid the complication of generating events, why not try doing a simple procedure call. We've been using this technique for many years with Visual Basic, Power Basic, and now PB.

If our program needs to create a non-standard or user event in order to process some gadget code, we just call the appropriate procedure and don't bother creating an actual event. This technique allows pseudo-events to be directed at any gadget code we choose. And if timing is an issue then we schedule the call after a known real event, or use a timer set to a short delay.

Another technique is to use standard events in a non-standard way. For example, set up an off-screen gadget that can be used to trap got-focus events, then code its event routine to perform the various functions you need. These events can be initiated from within code by setting focus to the off-screen gadget. You can use this gadget's data word to hold a user message number.

These techniques have the advantage of being cross-platform, because they don't require API code.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
Post Reply