1 """Useful utility methods for GTK."""
3 # Copyright (C) 2009, Thomas Leonard
4 # See the README file for details, or visit http://0install.net.
7 from zeroinstall
.support
import tasks
10 """Wrapper for GtkBuilder widget tree that throws a sensible exception if the widget isn't found."""
11 def __init__(self
, builderfile
, root
):
13 @param builderfile: pathname of the .ui file to load
14 @param root: the name of the top-level widget inside the file"""
15 self
.builder
= gtk
.Builder()
16 self
.builder
.set_translation_domain('zero-install')
17 self
.builder
.add_from_file(builderfile
)
18 self
.builderfile
= builderfile
21 def get_widget(self
, name
= None):
22 """Look up a widget by name."""
25 widget
= self
.builder
.get_object(name
)
26 assert widget
, "Widget '%s' not found in GtkBuilder file '%s'" % (name
, self
.builderfile
)
29 def show_message_box(parent
, message
, type = gtk
.MESSAGE_ERROR
):
30 """Display a non-modal message box with an OK button.
31 @param parent: the parent window
32 @param message: the message to be displayed
33 @param type: the type of box (used for the icon)"""
34 box
= gtk
.MessageDialog(parent
, gtk
.DIALOG_DESTROY_WITH_PARENT
,
37 box
.set_position(gtk
.WIN_POS_CENTER
)
40 box
.connect('response', resp
)
44 def get_busy_pointer():
45 """Get a GDK background-activity cursor.
46 Use this when something is happening, but the GUI is still responsive.
47 @return: the busy cursor (a singleton)
51 if _busy_pointer
is not None:
54 # This is crazy. We build a cursor that looks like the old
55 # Netscape busy-with-a-pointer cursor and set that, then the
56 # X server replaces it with a decent-looking one!!
57 # See http://mail.gnome.org/archives/gtk-list/2007-May/msg00100.html
60 \x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\
61 \x0c\x00\x00\x00\x1c\x00\x00\x00\x3c\x00\x00\x00\
62 \x7c\x00\x00\x00\xfc\x00\x00\x00\xfc\x01\x00\x00\
63 \xfc\x3b\x00\x00\x7c\x38\x00\x00\x6c\x54\x00\x00\
64 \xc4\xdc\x00\x00\xc0\x44\x00\x00\x80\x39\x00\x00\
65 \x80\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
66 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
67 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
68 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
69 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
70 \x00\x00\x00\x00\x00\x00\x00\x00"
73 pix
= gtk
.gdk
.bitmap_create_from_data(None, bit_data
, 32, 32)
74 color
= gtk
.gdk
.Color()
75 _busy_pointer
= gtk
.gdk
.Cursor(pix
, pix
, color
, color
, 2, 2)
77 #old bug http://bugzilla.gnome.org/show_bug.cgi?id=103616
78 _busy_pointer
= gtk
.gdk
.Cursor(gtk
.gdk
.WATCH
)
81 class DialogResponse(tasks
.Blocker
):
82 """Triggers when the GtkDialog gets a response.
85 def __init__(self
, dialog
):
86 tasks
.Blocker
.__init
__(self
, dialog
.get_title())
88 def response(d
, resp
):
92 a
= dialog
.connect('response', response
)
94 class ButtonClickedBlocker(tasks
.Blocker
):
95 """Triggers when the GtkButton is activated.
97 def __init__(self
, button
):
98 tasks
.Blocker
.__init
__(self
, "Button click")
103 a
= button
.connect('clicked', lambda b
: self
.trigger())
105 def MixedButton(message
, stock
, x_align
= 0.5, button
= None):
106 """A GtkButton with a stock icon.
109 button
= gtk
.Button()
111 label
= gtk
.Label('')
112 label
.set_text_with_mnemonic(message
)
113 label
.set_mnemonic_widget(button
)
115 image
= gtk
.image_new_from_stock(stock
, gtk
.ICON_SIZE_BUTTON
)
116 box
= gtk
.HBox(False, 2)
117 align
= gtk
.Alignment(x_align
, 0.5, 0.0, 0.0)
119 box
.pack_start(image
, False, False, 0)
120 box
.pack_end(label
, False, False, 0)