Gtk2-Ex-WidgetCursor
view release on metacpan or search on metacpan
lib/Gtk2/Ex/WidgetCursor.pm view on Meta::CPAN
#
sub _container_recursively {
my @pending = @_;
my @ret;
while (@pending) {
my $widget = pop @pending;
push @ret, $widget;
if (my $func = $widget->can('get_children')) {
push @pending, $widget->$func;
}
}
return @ret;
}
#------------------------------------------------------------------------------
# operative windows hacks
#
# $widget->Gtk2_Ex_WidgetCursor_windows() returns a list of windows in
# $widget to act on, with hacks to pickup multiple windows on core classes.
#
# $widget->Gtk2_Ex_WidgetCursor_hack_restore() returns ($win, $cursor).
# $cursor is a string cursor name to put back on $win when there's no more
# WidgetCursor objects. Or the return is an empty list or $win undef when
# nothing to hack (in which case all windows go back to "undef" cursor).
#
# default to operate on $widget->window alone
*Gtk2::Widget::Gtk2_Ex_WidgetCursor_windows = \&Gtk2::Widget::window;
sub Gtk2::Widget::Gtk2_Ex_WidgetCursor_hack_restore { return (); }
# GtkEventBox under a GtkComboBox popup window has a 'top-left-arrow'. It
# gets overridden by a special case in the recursive updates above, and
# hack_restore() here puts it back.
#
sub Gtk2::EventBox::Gtk2_Ex_WidgetCursor_hack_restore {
my ($widget) = @_;
return _widget_is_combo_eventbox($widget)
&& ($widget->window, 'top-left-arrow');
}
# GtkTextView operate on 'text' subwindow to override its insertion point
# cursor there, plus the main 'widget' window to cover the entire widget
# extent. The 'text' subwindow insertion point is supposed to be on when
# the widget is sensitive, so hack_restore() that.
#
sub Gtk2::TextView::Gtk2_Ex_WidgetCursor_windows {
my ($widget) = @_;
return ($widget->get_window ('widget'),
$widget->get_window ('text'));
}
sub Gtk2::TextView::Gtk2_Ex_WidgetCursor_hack_restore {
my ($widget) = @_;
return $widget->sensitive && ($widget->get_window('text'), 'xterm');
}
# GtkEntry's extra subwindow is included here. And when sensitive it should
# be put back to an insertion point. For a bit of safety use list context
# etc to allow for no subwindows, since it's undocumented.
#
# In Gtk 2.14 the SpinButton sub-class has the arrow panel as a subwindow
# too (instead of an overlay in Gtk 2.12 and earlier). So look for the
# smaller height one among multiple subwindows.
#
sub Gtk2::Entry::Gtk2_Ex_WidgetCursor_windows {
my ($widget) = @_;
my $win = $widget->window || return; # if unrealized
return ($win, $win->get_children);
}
sub Gtk2::Entry::Gtk2_Ex_WidgetCursor_hack_restore {
my ($widget) = @_;
$widget->sensitive or return;
my $win = $widget->window || return; # if unrealized
my @children = $win->get_children;
# by increasing height
@children = sort {($a->get_size)[1] <=> ($b->get_size)[1]} @children;
return ($children[0], 'xterm');
}
# GtkSpinButton's extra "panel" overlay window either as a "sibling" (which
# also finds the main window) for Gtk 2.12 or in the get_children() for Gtk
# 2.13; plus the GtkEntry subwindow as per GtkEntry above. hack_restore()
# inherited from GtkEntry above.
#
sub Gtk2::SpinButton::Gtk2_Ex_WidgetCursor_windows {
my ($widget) = @_;
my $win = $widget->window || return; # if unrealized
return (_widget_sibling_windows ($widget),
$win->get_children);
}
# GtkButton secret input-only "event_window" overlay found as a "sibling".
#
sub Gtk2::Button::Gtk2_Ex_WidgetCursor_windows {
my ($widget) = @_;
return _widget_sibling_windows ($widget);
}
# _widget_sibling_windows() returns a list of the "sibling" windows of
# $widget. This means all the windows which are under $widget's parent and
# have their events directed to $widget. If $widget is a windowed widget
# then this will include its main $widget->window (or should do).
#
# The search works by seeing where a dummy expose event is directed by
# gtk_get_event_widget(). It'd also be possible to inspect
# gdk_window_get_user_data(), but Gtk2-Perl only returns an "unsigned" for
# that so it'd need some nasty digging for the widget address.
#
# In the past the code here cached the result against the widget (what was
# then just GtkButton's "event_window" sibling), with weakening of course so
# unrealize would destroy the windows as normal. But don't bother with that
# now, on the basis that cursor changes hopefully aren't so frequent as to
# need too much trouble, and that it's less prone to mistakes if not cached
# :-).
#
sub _widget_sibling_windows {
my ($widget) = @_;
my $parent_win = ($widget->flags & 'no-window'
? $widget->window
: $widget->get_parent_window)
|| return; # if unrealized
my $event = Gtk2::Gdk::Event->new ('expose');
return grep { $event->window ($_);
($widget == (Gtk2->get_event_widget($event) || 0))
} $parent_win->get_children;
}
# Return true if $widget is the Gtk2::EventBox child of a Gtk2::Combo popup
# window (it's a child of the popup window, not of the Combo itself).
#
sub _widget_is_combo_eventbox {
my ($widget) = @_;
my $parent;
return ($widget->isa('Gtk2::EventBox')
&& ($parent = $widget->get_parent) # might not have a parent
&& $parent->get_name eq 'gtk-combo-popup-window');
}
#------------------------------------------------------------------------------
# Could think about documenting this idle level to the world, maybe like the
# following, but would it be any use?
#
# =item C<$Gtk2::Ex::WidgetCursor::busy_idle_priority>
#
# The priority level of the (C<< Glib::Idle->add >>) handler installed by
# C<busy>. This is C<G_PRIORITY_DEFAULT_IDLE - 10> by default, which is
# designed to stay busy through Gtk resizing and redrawing at around
# C<G_PRIORITY_HIGH_IDLE>, but end the busy before ordinary "default idle"
# tasks.
( run in 1.394 second using v1.01-cache-2.11-cpan-39bf76dae61 )