Gtk3 and subclassing

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Gtk3 and subclassing

Gtk+ - Perl mailing list
Whilst working up a smallest working example for another bug, I've
discovered that I cannot get subclassing working when the main package
is in the same file as the module.

Below is the Gtk2 subclassing example from Muppet which I have trivially
converted to Gtk3.

I get the following error messages:

Odd number of elements in anonymous hash at
/usr/lib/x86_64-linux-gnu/perl5/5.28/Glib/Object/Introspection.pm line 267.
*** unhandled exception in callback:
***   Can't locate object method "get_colormap" via package
"Gtk3::EventBox" at ../gtk3-subclass.pl line 93.
***  ignoring at
/usr/lib/x86_64-linux-gnu/perl5/5.28/Glib/Object/Introspection.pm line 67.

What is going on?

Regards

Jeff

#http://gtk2-perl.sourceforge.net/doc/subclassing_widgets_in_perl.html
#!/usr/bin/perl -w

use strict;

package Mup::ColorButton;

use Gtk3;

# this big hairy statement registers our Glib::Object-derived class
# and sets up all the signals and properties for it.
use Glib::Object::Subclass Gtk3::Button::, signals => {
        # with an empty hash for color_changed, we use all defaults,
        # which results in a signal which receives no extra parameters[2]
        # and returns no value.
        color_changed => {},
        # by supplying a subroutine reference for an existing signal,
        # we override the default handler for the class; this is how
        # you override virtual functions on Glib::Objects.
        show => \&on_show,
    },
    properties => [
        Glib::ParamSpec->int (
                'red', # name
                'Red', # nickname
                'The Red component of the RGB color', #blurb
                0, # min
                0xffff, # max
                0xffff, # default
                [qw/readable writable/] #flags
        ),
        Glib::ParamSpec->int (
                'green', 'Green', 'The Green component of the RGB color',
                0, 0xffff, 0xffff, [qw/readable writable/]
        ),
        Glib::ParamSpec->int (
                'blue', 'Blue', 'The Blue component of the RGB color',
                0, 0xffff, 0xffff, [qw/readable writable/]
        ),
    ];

# as part of creating the C object, Glib will call the INIT_INSTANCE
# method to, surprise, initialize the instance.  this is not an inherited
# method; it will be called with a fully-qualified package name.
# most of what we used to have in the constructor goes here.
# in fact, we just inherit new() from the base class, because it does
# everything we need it to.
sub INIT_INSTANCE {
        my $self = shift;
        $self->{red} = 0xffff;
        $self->{green} = 0xffff;
        $self->{blue} = 0xffff;
        my $frame = Gtk3::Frame->new;
        $frame->set_border_width (3);
        $frame->set_shadow_type ('etched-in');
        $self->add ($frame);
        $frame->show;
        my $event_box = Gtk3::EventBox->new;
        $event_box->set_size_request (14, 14);
        $frame->add ($event_box);
        $event_box->show;
        $self->{colorbox} = $event_box;
}

# in a more ambitious widget, we'd probably define GET_PROPERTY
# and SET_PROPERTY to do some custom stuff... for our purposes,
# however, the default implementation provided by Glib::Object::Subclass
# is sufficient.  (it sets the property values as hash members in the
# instance variable.)

# here we need to override the show method to set the color the
# first time we go onscreen, because we can't do that in the
# initializer (the GdkWindow does not exist yet).
sub on_show {
        my $self = shift;
        $self->set_color (red => $self->{red},
                          green => $self->{green},
                          blue => $self->{blue});
        # perl code that needs to call the parent class usually does
something
        # like  $self->SUPER::methodname ---- however, class_closures for
        # for Glib::Objects are not inheritable in that way; the code to
which
        # we need to chain may not even be perl code.  Glib provides this
        # method to provide that functionality, instead.
        $self->signal_chain_from_overridden;
}

sub set_color {
        my $self = shift;
        my %params = @_;
        my $color = Gtk3::Gdk::Color->new ($params{red},
                                           $params{green},
                                           $params{blue});
        $self->{colorbox}->get_colormap->alloc_color ($color, 0, 1);
        $self->{colorbox}->modify_bg ('normal', $color);
        $self->{colorbox}->modify_bg ('active', $color);
        $self->{colorbox}->modify_bg ('prelight', $color);
        $self->{red} = $params{red};
        $self->{green} = $params{green};
        $self->{blue} = $params{blue};
        # emit the color-changed signal.  note again that the signal
        # name treats - and _ as equivalent.
        $self->signal_emit ('color-changed');
}

package main;

use Gtk3 -init;

my $window = Gtk3::Window->new;
$window->set_title ('Color buttons');
$window->set_border_width (6);
$window->signal_connect (delete_event => sub { Gtk3->main_quit; 1 });

my $vbox = Gtk3::VBox->new;
$window->add ($vbox);
$vbox->show;

my $foo = Mup::ColorButton->new (red => 0xaaaa, green => 0x0, blue =>
0xffff);
$vbox->pack_start ($foo, 1, 1, 0);
$foo->show;

$foo->signal_connect (clicked => sub {
                my $self = shift;
                my $dialog = Gtk3::ColorSelectionDialog->new ('pick a
color');
                my $c = Gtk3::Gdk::Color->new ($self->{red},
                                               $self->{green},
                                               $self->{blue});
                $self->{colorbox}->get_colormap->alloc_color ($c, 0, 1);
                $dialog->colorsel->set_current_color ($c);
                if ('ok' eq $dialog->run) {
                        my $c = $dialog->colorsel->get_current_color;
                        $self->set_color (red => $c->red,
                                          green => $c->green,
                                          blue => $c->blue);
                }
                $dialog->destroy;
        });

$foo->signal_connect (color_changed => sub {
      warn "the color changed - now "
        . join (", ", $_[0]->get (qw/red green blue/))
        . ".  i should do something!";
     });

$window->show;
Gtk3->main;


_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Gtk3 and subclassing

Gtk+ - Perl mailing list
On Fri, 30 Nov 2018 at 19:09, Jeff via gtk-perl-list <[hidden email]> wrote:
Whilst working up a smallest working example for another bug, I've
discovered that I cannot get subclassing working when the main package
is in the same file as the module.

Below is the Gtk2 subclassing example from Muppet which I have trivially
converted to Gtk3.


Your GTK 3 port is wrong.
 
I get the following error messages:

Odd number of elements in anonymous hash at
/usr/lib/x86_64-linux-gnu/perl5/5.28/Glib/Object/Introspection.pm line 267.
*** unhandled exception in callback:
***   Can't locate object method "get_colormap" via package
"Gtk3::EventBox" at ../gtk3-subclass.pl line 93.
***  ignoring at
/usr/lib/x86_64-linux-gnu/perl5/5.28/Glib/Object/Introspection.pm line 67.

What is going on?

You're calling the "get_colormap()" method on a GtkEventBox, which does not have a "get_colormap()" method—and neither do all its parent classes.

In GTK 2.x, there is a `gtk_widget_get_colormap()` method, but it was deprecated during the GTK 2.x API series, and thus removed once GTK 3.0 was released.
 
sub set_color {
        my $self = shift;
        my %params = @_;
        my $color = Gtk3::Gdk::Color->new ($params{red},
                                           $params{green},
                                           $params{blue});
        $self->{colorbox}->get_colormap->alloc_color ($color, 0, 1);
        $self->{colorbox}->modify_bg ('normal', $color);
        $self->{colorbox}->modify_bg ('active', $color);
        $self->{colorbox}->modify_bg ('prelight', $color);
        $self->{red} = $params{red};
        $self->{green} = $params{green};
        $self->{blue} = $params{blue};
        # emit the color-changed signal.  note again that the signal
        # name treats - and _ as equivalent.
        $self->signal_emit ('color-changed');
}

Creating a colormap, allocating a color, and calling `modify_bg()` was something used in GTK 2.x (and even there, it was questionable, as it broke themes).

In GTK 3.x you're supposed load a CSS fragment, defining the background-color CSS property for a specific class, e.g.

    .foo { background-color: red; }
    .foo:active { background-color: green; }
    .foo:hover { background-color: blue; }

You load this using a GtkCSSProvider associated to the GdkScreen, and loaded when you create your application instance.

If you're trying to set the color programmatically, overriding all user theming, you can generate a CSS fragment programmatically and associate it to the widget itself, instead of the global GdkScreen; or you can override the GtkWidget::draw signal, and render the color yourself using Cairo. Doing either of those is less than great, but it respects the original example's intent.

Ciao,
 Emmanuele.

--

_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Gtk3 and subclassing

Gtk+ - Perl mailing list
On 01/12/2018 00:36, Emmanuele Bassi wrote:

> On Fri, 30 Nov 2018 at 19:09, Jeff via gtk-perl-list
> <[hidden email] <mailto:[hidden email]>> wrote:
>
>     Whilst working up a smallest working example for another bug, I've
>     discovered that I cannot get subclassing working when the main package
>     is in the same file as the module.
>
>     Below is the Gtk2 subclassing example from Muppet which I have trivially
>     converted to Gtk3.
>
>
> Your GTK 3 port is wrong.
Grrr. Thanks for the feedback. The example I originally had was that
below, which I replaced with the one from the previous email to
eliminate the GooCanvas2 dependency. As the error seemed to have the
same source, I thought it would be simpler. Sorry for wasting your time.

The code below is cut down from that in gscan2pdf, where in a separate
file, the subclass, and thus the add_events() call works fine. Here, I get:

Can't locate object method "add_events" via package "My::Canvas" at
gtk3-subclass2.pl line 15.

I still can't work out why and would appreciate some insight.

Regards

Jeff

#!/usr/bin/perl -w

use strict;

package My::Canvas;

use strict;
use warnings;
use GooCanvas2;

use Glib::Object::Subclass GooCanvas2::Canvas::;

sub INIT_INSTANCE {
    my $self = shift;
    $self->add_events(
            Glib::Object::Introspection->convert_sv_to_flags(
                'Gtk3::Gdk::EventMask', 'exposure-mask' ) |
              Glib::Object::Introspection->convert_sv_to_flags(
                'Gtk3::Gdk::EventMask', 'button-press-mask' ) |
              Glib::Object::Introspection->convert_sv_to_flags(
                'Gtk3::Gdk::EventMask', 'button-release-mask' ) |
              Glib::Object::Introspection->convert_sv_to_flags(
                'Gtk3::Gdk::EventMask', 'pointer-motion-mask' ) |
              Glib::Object::Introspection->convert_sv_to_flags(
                'Gtk3::Gdk::EventMask', 'scroll-mask'
              )
        );
    return $self;
}

package main;

use strict;
use warnings;

use Gtk3 -init;
use GooCanvas2;

my $window = Gtk3::Window->new();
$window->set_default_size(640, 600);
$window->signal_connect('destroy' => sub {Gtk3->main_quit()});
my $canvas = My::Canvas->new();
$window->add($canvas);
$window->show_all;
Gtk3->main();


_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Gtk3 and subclassing

Torsten Schoenfeld
On 01.12.18 17:00, Jeff via gtk-perl-list wrote:
> The code below is cut down from that in gscan2pdf, where in a separate
> file, the subclass, and thus the add_events() call works fine. Here, I get:
>
> Can't locate object method "add_events" via package "My::Canvas" at
> gtk3-subclass2.pl line 15.
>
> I still can't work out why and would appreciate some insight.

Looks like GooCanvas2.pm neglects to pull in Gtk3.pm, so either patch
GooCanvas2.pm or "use Gtk3" yourself before you "use GooCanvas2".

Also, as of Gtk3.pm version 0.032 you do not need to use
Glib::Object::Introspection->convert_sv_to_flags for the mask argument
of add_events() anymore but can instead simply use something like this:

         [qw/exposure-mask
             button-press-mask
             button-release-mask
             pointer-motion-mask
             scroll-mask/]

-Torsten
_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Gtk3 and subclassing

Gtk+ - Perl mailing list
On 01/12/2018 17:22, Torsten Schoenfeld wrote:
> Looks like GooCanvas2.pm neglects to pull in Gtk3.pm, so either patch
> GooCanvas2.pm or "use Gtk3" yourself before you "use GooCanvas2".

That was it. Thanks.

Regards

Jeff


_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list

signature.asc (849 bytes) Download Attachment