Creating a GTK3 control from scratch in code

In this specific case I am targeting a Raspi, but should be a common thing for GTK based UIs:
I can create controls from scratch using declares. Some where I am adding features to those that the IDE created, some that do not have a visible control representation, like alerts.

But I fail when I try to insert a visible control I created into the view hierarchy. I tried with a Canvas as a container, adding the fully instantiated declared control as a child, or directly addressing the windows’ widget, but nothing. Parent of the declared widget will still be nil.

Are there any examples on how to do this? Would any of the 3rd party developers share his knowledge?
Thanks a lot!

I cannot Add on Plugin control for example because their panel type is in such way that I cannot embed on it, might be something like that your battling.

This has been longstanding issue for years and has held back things.

  1. You cannot embed on plugin control.
  2. If you let the control return its own GDK handle then that works but your still screwed since you cannot create Graphics then to expose to Xojo.

So its a no win cycle no matter which way one goes.

Now back to your issue…I would start trying to just embed on the Window that should work sort of…you might need to poke around a bit and grab the Windows first container as in might have some sort of Box container.

For canvas it might not actually embed the controls as in it might be just embedded on the Window. Or the Canvas might contain some sort of box which you would need to poke around to find, like VBox.

You can save your some work while testing and poking around by using the Linux Bridge Plugin (its free). Then you dont have to worry about getting the declares right at least while your poking around.

A first test in poking around:

It shows that the Canvas is GtkContainer of some sort…but not GtkBox, I did not have other containers currently in the Linux bridge to test others but I could add the other types to aid the poking around more.

using EinhugurLinuxBridgeGtk

Var ctrl as GtkWidget = GtkWidget.FromIntegerPtr(Integer(me.Handle))

if ctrl <> nil then
  MessageBox "Got GtkWidget"   // I Get this
  
  var container as GtkContainer = GtkContainer.Cast(ctrl)
  
  if container <> nil then
    MessageBox "Got container"  // And this
    
    var box as GtkBox = GtkBox.Cast(container)
    
    if box <> nil then
      MessageBox "Got Box"  // Not this
    end if
  end if
end if

Same test on plugin control shows its just GtkWidget and not even GtkContainer. Which is why plugin ListBox cannot even embed a scrollbar or anything on Linux.

Thanks a lot, Björn. So, doesn’t look good right now, if I understood you correctly? Shouldn’t one be able to add a declared widget to the container of a window?

Somehow Xojo must be doing all this too … Would be too good to have a ViewControl that just opens an embeddable rectangle you can feed with your declare controls. A feature request somewhere down in past.

I tried this with window and Canvas where this was the open event. But nothing visible:

Sub Open() Handles Open
  Me.Bar = New GTKLevelBar
  bar.realize
  var parent As New GTKWidget(Self)
  bar.SetSizeRequest Self.Width, Self.Height
  bar.AllocateSize(0, 10, Self.Width, Self.Height)
  GTKContainer(window1.ApplicationWindow).AddChild bar
End Sub

I think it would depend on what kind of container it is.

Like if its GtkFixed then you add it with gtk_fixed_put

but I added a bit more to the plugin to test more after last post.

But it does not respond to Fixed either… so hmmmm guess I need to add something more maybe I just dont know what.

using EinhugurLinuxBridgeGtk

Var ctrl as GtkWidget = GtkWidget.FromIntegerPtr(Integer(Canvas1.Handle))

if ctrl <> nil then
  MessageBox "Got GtkWidget"
  
  var container as GtkContainer = GtkContainer.Cast(ctrl)
  
  if container <> nil then
    MessageBox "Got container"
    
    var box as GtkBox = GtkBox.Cast(container)
    
    if box <> nil then
      MessageBox "Got Box"
    end if
  end if
  
  var fixed as GtkFixed = GtkFixed.Cast(container)
  
  if fixed <> nil then
    MessageBox "Got fixed"
  end if
end if

GtkLayout maybe ?

More testing shows its not GtkLayout either

but…as for your code then I think your missing gtk_widget_showfor your widget.

Some more info for you.

Canvas
Is of type XojoEventBox (custom GtkWidget container)
If you grab the first child from the XojoEventBox then you get GtkFixed which is probably where you should embed to.

Window
First child of the Window is GtkFixed. Which is probably what you should embed to, and not to the Window it self.

Remember to use gtk_widget_show which was missing from your code.

Thank you again, Björn. I had widget.show implemented at some stage too, will re-add it fur further tests.
Sadly gtk.org is currently down for me so I cannot find the docs to add missing parts (I took an old library I once started and started adding things).-

I still cannot get it to work though even if knowing where to get to the GtkFixed.

Maybe I am missing somehing

No it works !!!

It was just my reference counter that was making the button always go out of scope and get disposed.

The “Test” button is the one I embedded, and its embedded on Canvas.

image

using EinhugurLinuxBridgeGtk

Var ctrl as GtkWidget = GtkWidget.FromIntegerPtr(Integer(Canvas1.Handle))

MessageBox ctrl.Name


if ctrl <> nil then
  MessageBox "Got GtkWidget"
  
  var container as GtkContainer = GtkContainer.Cast(ctrl)
  
  
  if container <> nil then
    MessageBox "Got container"
    
    var fixed as GtkFixed = GtkFixed.Cast(container.FirstChild())
    
    if fixed = nil then
      MessageBox "Fixed is bad"
    end if
    
    var button as GtkButton = new GtkButton("Test")
    btn = button
    
    button.SizeAllocate(10,10, 80, 30)  // Not sure if I needed this one, probably not
    button.SetSizeRequest(80,30)  // Not sure if I needed this one, probably not
    
    fixed.Put(button, 10, 10)
    
    button.Show()
  end if
  
  
end if

Thanks a lot once again, Björn!
Are GTKFixed and Container.FirstChild extensions not yet published?
I tried with my own resurrected library (inside Opening event of a Canvas):

var container As GTKContainer = GTKContainer.FromPtr(Ptr(Me.Handle))
If container = Nil Then Break
var fixed As GTKFixed = GTKFixed(container.FirstChild)
If fixed = Nil Then Break

This is how far I get because fixed will always be nil. What I do in FirstChild is

#If TargetLinux
  Var initialList As GList = gtk_container_get_children(Mid)
  Var result As GTKContainer = GTKContainer.FromPtr(initialList.FirstItem)
  initialList.Free
  Return result
#EndIf

But InitialList, a 0 aligned structure of 3 ptrs, will always be zero.
Any ideas where my fault is?

FirstChild was because I am lazy bastard, i did not want to have to deal with figuring out how to return collection to get this test done.

But the implementation of it is:

static REALobject FirstChild(REALobject instance)
{
   #if X_WINDOW
       ClassData(GObjectXojoClass, instance, GObjectData, me);

       GList* children = gtk_container_get_children(GTK_CONTAINER(me->Object));
   
       if(children == NULL)
       {
           return NULL;
       }
   
       REALobject widgetInstance = REALnewInstanceOfClass(&GtkWidgetXojoClass);

       ClassData(GObjectXojoClass, widgetInstance, GObjectData, widgetData);

       widgetData->Object = G_OBJECT(children->data);

       g_object_ref(widgetData->Object);

       return widgetInstance;
   #else
       return NULL;
   #endif
}

I will compile 2 missing Linux targets also in the Plugin and Post it even if all the new routines have not been documented yet, so you have something you can test.

(will post again in few min)

Here is Linux Bridge 2.2 Pre-Release so you can test:

https://1drv.ms/u/s!AmeKIsBCQHA5gdRC2X2E-d0AZX731w?e=ORDt6t

The new additions have not been documented but I had the tool auto generate the documentation so you see syntax for everything. (Tool gives me 53 warnings on things where documentation needs revisiting)

Posted Official version now that has documentation and some fixes, so better for you to grab that one if you want to test.

1 Like

Excellent, Björn, thanks a lot!
I have to switch a bit between classes because my library is currently not based on yours, which I guess I will change – no reason to build everything from scratch if your foundation is also free –, but it’s working. Second control is a GTKLevelBar declared from my library, brought onto screen with your Linux Bridge.

No problem at all my friend.

This plugin is not a lot used so I mostly add to it when I know there is some need so by all means if you are missing something then let me know.

1 Like

Thank you, Björn. Think I’ll update my repository soon so we can have a Linux declare library to share. I was surprised to see such a thing does not exist. It was built in Xojo Core API times, so I still find quite some things to change.
I ran into a different question but will rather open a new thread on it.