NAME
Gtk2::Ex::WidgetCursor -- mouse pointer cursor management for widgets
SYNOPSIS
use Gtk2::Ex::WidgetCursor;
my $wc = Gtk2::Ex::WidgetCursor->new (widget => $mywidget,
cursor => 'fleur',
active => 1);
# show wristwatch everywhere while number crunching
Gtk2::Ex::WidgetCursor->busy;
# bonus invisible cursor creator
my $cursor = Gtk2::Ex::WidgetCursor->invisible_cursor;
DESCRIPTION
WidgetCursor manages the mouse pointer cursor shown in widget windows as set by Gtk2::Gdk::Window::set_cursor
. A "busy" mechanism can display a wristwatch in all windows when the whole application is blocked.
The plain set_cursor
lacks even a corresponding get_cursor
until Gtk 2.18, making it difficult for widget add-ons or independent parts of an application to cooperate with what cursor should be shown at different times or in different modes.
To help that a Gtk2::Ex::WidgetCursor
object represents a desired cursor in one or more widgets. When "active" and when the newest or highest priority then the specified cursor is set onto those widget window(s). If the WidgetCursor object is later made inactive or destroyed then the next highest WidgetCursor takes effect, etc.
The idea is to have say a base WidgetCursor for an overall mode, then something else temporarily while dragging, and perhaps a wristwatch "busy" indication trumping one or both (like the global "busy" mechanism below).
The examples subdirectory in the WidgetCursor sources has some variously contrived sample programs.
WIDGETCURSOR OBJECTS
$wc = Gtk2::Ex::WidgetCursor->new (key => value, ...)
-
Create and return a new
WidgetCursor
object. Parameters are taken in key/value style,widget single widget widgets array reference for multiple widgets cursor string or object active boolean priority default 0 include_children boolean
For example,
$wc = Gtk2::Ex::WidgetCursor->new (widget => $mywidget, cursor => 'fleur', active => 1);
cursor
can be any ofA string name of a cursor from the
Gtk2::Gdk::CursorType
enum, such as"hand1"
(see Gtk2::Gdk::Cursor for the full list).The special string name
"invisible"
to have no cursor at all. (You can also use"blank-cursor"
in Gtk 2.16 and up.)A
Gtk2::Gdk::Cursor
object. If your program uses multiple displays then remember the cursor object must be on the same display as the widget(s).undef
to inherit the parent window's cursor, which often means the default little pointing arrow of the root window.
active
can be set to make the new cursor take effect immediately, otherwise theactive()
function below turns it on when desired.include_children
means all the children of the given widgets are affected too. Normally the cursor in a child widget overrides its parents (asset_cursor
does at the window level). But withinclude_children
a setting in a parent applies to the children too, with priority+newest applied as usual.Optional
priority
is a number. The default is level 0 and higher values are higher priority. A low value (perhaps negative) can act as a fallback, or a high value can trump other added cursors. $bool = $wc->active ()
$wc->active ($newval)
-
Get or set the "active" state of
$wc
. $cursor = $wc->cursor ()
$wc->cursor ($cursor)
-
Get or set the cursor of
$wc
. Any cursor setting in the style ofnew
above can be given. Eg.$wc->cursor ('umbrella');
@widgets = $wc->widgets ()
-
Return a list of the widgets currently in
$wc
. Eg.my @array = $wc->widgets;
or if you know you're only acting on one widget then say
my ($widget) = $wc->widgets;
$wc->add_widgets ($widget, $widget, ...)
-
Add widgets to
$wc
. Any widgets given which are in fact already in$wc
are ignored.
WidgetCursor objects can operate on unrealized widgets. The cursor settings take effect if/when the widgets are realized.
A WidgetCursor object only keeps weak references to its widget(s), so the mere fact there's a desired cursor won't keep a widget alive forever. Garbage collected widgets drop out of the widgets list. In particular this means it's safe to hold a WidgetCursor within a widget's own hash without creating a circular reference. Eg.
my $widget = Gtk2::DrawingArea->new;
$widget->{'base_cursor'} = Gtk2::Ex::WidgetCursor->new
(widget => $widget,
cursor => 'hand1',
active => 1,
priority => -10);
APPLICATION BUSY
The busy
mechanism sets a "watch" cursor on all windows to tell the user the program is doing CPU-intensive work and might not run the main loop to draw or interact for a while.
If your busy state isn't CPU-intensive, but instead perhaps a Glib timer or an I/O watch on a socket, then this is not what you want, it'll turn off too soon. (Instead simply make a WidgetCursor
with a "watch"
and turn it on or off at your start and end points. See examples/timebusy.pl in the sources for an example of that sort of thing.)
Gtk2::Ex::WidgetCursor->busy ()
-
Show the
"watch"
cursor (a little wristwatch) in all the application's widget windows (toplevels, dialogs, popups, etc). An idle handler (Glib::Idle->add
) removes the watch automatically upon returning to the main loop.The X queue is flushed to set the cursor immediately, so the program can go straight into its work. For example
Gtk2::Ex::WidgetCursor->busy; foreach my $i (1 .. 1_000_000) { # do much number crunching }
If you create new windows within a
busy
then they too get the busy cursor. You can even go busy before creating any windows at all. But note WidgetCursor doesn't do any extra X flush for new creations; if you want them to show immediately then you'll have to flush in the usual way.busy
uses aWidgetCursor
object as described above and so cooperates with application uses of that. Priority level 1000 is set to trump other cursor settings. Gtk2::Ex::WidgetCursor->unbusy ()
-
Explicitly remove the watch cursor setup by
busy
above. The X request queue is flushed to ensure any cursor change appears immediately. Ifbusy
is not active then do nothing.It's unlikely you'll need
unbusy
, because if your program hasn't yet reached the idle handler in the main loop then it's probably still busy! But perhaps if most of your work is done then you could unbusy while the remainder is finishing up.
INVISIBLE CURSOR
This invisible cusor constructor is used by WidgetCursor above for the "invisible"
cursor and is made available for general use. Gtk has similar code in GtkEntry
and GtkTextView
, but as of Gtk 2.12 doesn't make it available to applications.
$cursor = Gtk2::Ex::WidgetCursor->invisible_cursor ()
$cursor = Gtk2::Ex::WidgetCursor->invisible_cursor ($target)
-
Return a
Gtk2::Gdk::Cursor
object which is invisible, ie. displays no cursor at all. This is theblank-cursor
in Gtk 2.16 and up, or for earlier versions a "no pixels set" cursor as described bygdk_cursor_new
.With no arguments (or
undef
) the cursor is for the default displayGtk2::Gdk::Display->get_default
. If your program only uses one display then that's all you need.my $cursor = Gtk2::Ex::WidgetCursor->invisible_cursor;
For multiple displays a cursor is a per-display resource so you must pass a
$target
. This can be aGtk2::Gdk::Display
, or anything with aget_display
method, includingGtk2::Widget
,Gtk2::Gdk::Window
,Gtk2::Gdk::Drawable
, anotherGtk2::Gdk::Cursor
, etc.my $cursor = Gtk2::Ex::WidgetCursor->invisible_cursor ($widget);
When passing a widget note the display comes from its toplevel
Gtk2::Window
parent and until added in as a child somewhere under a toplevel itsget_display
is the default display andinvisible_cursor
will give a cursor for that display.The invisible cursor is cached against the display, so repeated calls don't make a new one every time.
LIMITATIONS
WidgetCursor settings are applied to the widget windows without paying attention to which among them are "no-window" and thus using their parents' windows. If different no-window children have a common windowed parent then WidgetCursor won't notice and the result will probably come out wrong. For now it's suggested you either always give a windowed widget, or at least always the same no-window child.
An exception to the no-window rule is Gtk2::Button
. It has the no-window flag but in fact keeps a private input-only event window over its allocated space. WidgetCursor digs that out and uses it to put the cursor on the intended area. But an exception to the exception is Gtk2::LinkButton
where a setting on the button works fine, but any WidgetCursor on its parent is messed up.
In the future it might be possible to have cursors on no-window widgets by following motion-notify events within the container parent in order to update the cursor as it goes across different children. But windowed widgets are normally best, since they let the X server take care of the display as the mouse moves around.
Reparenting widgets subject to an include_children
probably doesn't quite work. If it involves a new realize it probably works, otherwise probably not. Moving widgets is unusual, so in practice this isn't too bad. (Doing the right thing in all cases might need a lot of add
or parent
signal connections.)
Widgets calling $window->set_cursor
themselves generally defeat the WidgetCursor mechanism. WidgetCursor has some special handling for Gtk2::Entry
and Gtk2::TextView
(their insertion point cursor), but a few other core widgets have problems. The worst currently is Gtk2::LinkButton
per above. Hopefully this can improve in the future, though ill effects can often be as modest as an include_children
merely not "including" children of offending types.
SEE ALSO
Gtk2::Gdk::Cursor, Gtk2::Widget, Gtk2::Gdk::Window, Gtk2::Gdk::Display
HOME PAGE
http://user42.tuxfamily.org/gtk2-ex-widgetcursor/index.html
LICENSE
Copyright 2007, 2008, 2009, 2010 Kevin Ryde
Gtk2-Ex-WidgetCursor 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.
Gtk2-Ex-WidgetCursor 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 Gtk2-Ex-WidgetCursor. If not, see http://www.gnu.org/licenses/.