Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2013-05

LCL + GTK2 + CustomControl : Help needed

3 messages · 1 person · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Unknown author

Hi,
as I can't describe my problem in 2 sentences, I first try to give an overview.

= information you might need =

System: Linux 64bit, fpc 2.6.2 / lazarus 1.0.8
Assumption: LCLGTK2

I have a C library, which creates a custom control. It takes a window handle as parent (in my case only gtk -> gtk handle) and adds its visual / control to it.
The "plain" way to use it (which works fine) is:

--- snip ---

  gtk_init(nil, nil);  // in my case gtk
  Window := gtk_window_new(GTK_WINDOW_TOPLEVEL); // Create a window
  { do some gtk stuff }
  // add a box to the window
  Box := gtk_vbox_new(False, 0);
  gtk_container_add(GTK_CONTAINER(window), Box);
  { do library init }
  { pass "Box" to library }
  { -> there's a window with the library's visual in it :) }

--- end ---
Passing "Window" to the library in the above example works, too.

= The actual problem =

Now I created a custom Control for Lazarus: TCVisual = class(TWinControl).

From what I saw, there are 2 different ways to implement this control in LCL:

1.
Override CreateWnd with *no* inherited and pass Parent.Handle to the library. Get the childs handle from the library and set my control's handle to it.

To me this seems to be the preferred way, as the hierarchy is as flat as possible:

LCL Parent
|
TCVisual with library's handle

--- Code : snip --

procedure TCVisual.CreateWnd;
begin
  { make sure parent handle exists, if not: Parent.NeedsHandle etc. }
 // library's parent = control's parent
  parent_widget := Pointer(Parent.Handle);
  { pass "parent_widget" to the library }
  { do library calls }
// getWidget is a replacement for getting the newly created child from the
library
  Handle := HWND( getWidget() );
  { maybe call inherited now, after handle is set (?) }
end;

-- end --

The problem:
Gtk: Attempting to add a widget with type GtkExpandedContainer to a GtkWindow, but as a GtkBin subclass a GtkWindow can only contain one widget at a time; it already contains a widget of type GtkVBox

2.
Let LCL create a Handle and pass it to the library as the parent. Hierarchy then (should) look like this:

LCL Parent
|
TCVisual : handle created by LCL (GTK2) via

  TWSWinControlClass(WidgetSetClass).CreateHandle(Self, Params);
      |
    Library

--- Code : snip --

procedure TCVisual.CreateWnd;
begin
  inherited;
  // library's parent = control's handle
  parent_widget := Pointer(Handle);
  { pass "parent_widget" to the library }
  { do library calls }
  // Handle := HWND( getWidget() );  // library's handle isn't needed
end;

-- end --

The problem:
Gtk: gtk_scrolled_window_add: assertion `bin->child == NULL' failed

Apparently LCL sets bin.child, but the library assumes it to be nil -> a small hack 'solved' this problem:

  PGtkWindow(Handle)^.bin.child := nil;

Result:
Gtk: gtk_scrolled_window_add(): cannot add non scrollable widget use gtk_scrolled_window_add_with_viewport() instead

--------

I also did some other 'tests', but I don't think they have any additional valuable infos.
[Apart from: abusing a GroupBox's handle did work after setting bin.child to nil, instead of the GroupBox the library's visual appeared, but LCL crashed on Form.Destroy :) ]

My question now is:
How does LCL add controls - the parent was the main form - ? Are there e.g. additional containers somewhere (maybe invisible for the user)? [I read the LCLGTK sources, but I didn't get too much info out of it... :( ]

How can I get a handle from LCL / create and add a handle which basically behaves the same way as a VBox / HBox / Window (= the ones I know to work)?

I tried to create a VBox myself in CreateWnd
- gtk gave a error similar to (1), so I assume there is something more I need to know on how LCLGTK2 internally handles all the gtk stuff - but I really would prefer to do as little direct gtk as possible...

As I actually never did anything with gtk before, any hints may be valuable to me.
If something similar was solved already, simply point to it.

Thanks for reading this long message and
Thanks in advance for any help

Regards,
d.l.i.w

Reply by email

Unknown author
to Unknown author

Hi,
sorry to be so insistent, but I can't imagine noone has an idea :( No LCLGTK2 maintainer on this list?

To put it in a nutshell:
I need to get / create a handle via LCL or GTK2 directly, which is a gtkcontainer, with no bin.child attached...
or - seeing that LCL creates a bigger hierarchy for one control - the handle, to which children can be attached
Just like a button can be attached to a form / panel / groupbox...

The result of GetFixedWidget with the Handle created by default TWinControl.CreateWnd seems to be ok, but anything added with gtk_pack (which is the way the library attaches itself AFAIK) simply isn't displayed...
Maybe *the* one call to inform LCL about the new child is missing...

Any ideas?
Would it help, if I uploaded everything I have so far to e.g. github? [ I plan to publish one of these components anyway...]

Somehow I have the feeling, I don't see any trees being in a forest... :D

=== Additional info ===

I spend a couple more hours with trial and error - leading nowhere...

I found
1. FinishCreateHandle, which seems to take a gtkwidget and add lcl specific info to it
2. GetFixedWidget and FixedPutControl
Unfortunately there's no documentation - and little to no comments in the sources

(2) seemed to work (no errors on startup and destroy), but nothing was visible

I already found out, how LCL internally uses GTKbin to save additonal infos for LCL (with gtk_object_get_data, which is marked depreciated btw.) and how things roughly work - but still no idea where to start...

Two more possible hints:
1. A groupbox's handle worked fine, after setting its bin.child to nil. This broke LCL when cleaning up things, but apart from that everything worked as expected: resize / update / no flicker etc.
2. I found out that TForm has a vbox by default for the menu (according to the comments in the source). Passing its handle to the library things worked, too
- but of course it was in the wrong place...

Regards,
d.l.i.w

Reply by email