# Copyright 2009, 2010 Kevin Ryde # This file is part of Chart. # # Chart is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 3, or (at your option) any later # version. # # Chart is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with Chart. If not, see . # tracking window position in root coords, with watching for reparenting # package App::Chart::Gtk2::Ex::GdkWindowTracker; use 5.008; use strict; use warnings; use Gtk2; use Scalar::Util 1.18 'refaddr'; # 1.18 for pure-perl refaddr() fix # uncomment this to run the ### lines #use Smart::Comments; use Glib::Object::Subclass 'Glib::Object', properties => [Glib::ParamSpec->object ('window', 'window', 'Blurb.', 'Gtk2::Window', Glib::G_PARAM_READWRITE), ], signals => { moved => { param_types => [], return_type => undef }, }; my %realized_instances; my $configure_event_hook_id; # sub INIT_INSTANCE { # my ($self) = @_; # } sub FINALIZE_INSTANCE { my ($self) = @_; delete $realized_instances{refaddr($self)}; } sub SET_PROPERTY { my ($self, $pspec, $newval) = @_; my $pname = $pspec->get_name; if ($pname eq 'window') { FINALIZE_INSTANCE ($self); App::Chart::Glib::Ex::TieWeakNotify->set ($self, $pname, $newval); if ($newval) { Scalar::Util::weaken ($realized_instances{refaddr($self)} = $self); $configure_event_hook_id ||= Gtk2::Window->signal_add_emission_hook (configure_event => \&_do_configure_event); } } } sub _do_configure_event { my ($invocation_hint, $parameters) = @_; my $changed_window = $parameters->[0]; ### configure event: $changed_window foreach my $self (values %realized_instances) { if (my $window = $self->{'window'}) { if (_window_is_ancestor_or_self ($changed_window, $window)) { $self->signal_emit ('moved'); } } else { # window weakened away FINALIZE_INSTANCE ($self); } } if (%realized_instances) { return 1; # stay connected } else { ### disconnect hook undef $configure_event_hook_id; return 0; # disconnect } } sub _window_is_ancestor_or_self { my ($window, $child) = @_; for (;;) { if ($window == $child) { return 1; } $window = $window->get_parent || return 0; } } 1; __END__