Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | # |
| 2 | # BitBake Graphical GTK User Interface |
| 3 | # |
| 4 | # Copyright (C) 2012 Intel Corporation |
| 5 | # |
| 6 | # Authored by Joshua Lock <josh@linux.intel.com> |
| 7 | # |
| 8 | # This program is free software; you can redistribute it and/or modify |
| 9 | # it under the terms of the GNU General Public License version 2 as |
| 10 | # published by the Free Software Foundation. |
| 11 | # |
| 12 | # This program is distributed in the hope that it will be useful, |
| 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | # GNU General Public License for more details. |
| 16 | # |
| 17 | # You should have received a copy of the GNU General Public License along |
| 18 | # with this program; if not, write to the Free Software Foundation, Inc., |
| 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| 20 | |
| 21 | import gobject |
| 22 | import gtk |
| 23 | try: |
| 24 | import gconf |
| 25 | except: |
| 26 | pass |
| 27 | |
| 28 | class PersistentTooltip(gtk.Window): |
| 29 | """ |
| 30 | A tooltip which persists once shown until the user dismisses it with the Esc |
| 31 | key or by clicking the close button. |
| 32 | |
| 33 | # FIXME: the PersistentTooltip should be disabled when the user clicks anywhere off |
| 34 | # it. We can't do this with focus-out-event becuase modal ensures we have focus? |
| 35 | |
| 36 | markup: some Pango text markup to display in the tooltip |
| 37 | """ |
| 38 | def __init__(self, markup, parent_win=None): |
| 39 | gtk.Window.__init__(self, gtk.WINDOW_POPUP) |
| 40 | |
| 41 | # Inherit the system theme for a tooltip |
| 42 | style = gtk.rc_get_style_by_paths(gtk.settings_get_default(), |
| 43 | 'gtk-tooltip', 'gtk-tooltip', gobject.TYPE_NONE) |
| 44 | self.set_style(style) |
| 45 | |
| 46 | # The placement of the close button on the tip should reflect how the |
| 47 | # window manager of the users system places close buttons. Try to read |
| 48 | # the metacity gconf key to determine whether the close button is on the |
| 49 | # left or the right. |
| 50 | # In the case that we can't determine the users configuration we default |
| 51 | # to close buttons being on the right. |
| 52 | __button_right = True |
| 53 | try: |
| 54 | client = gconf.client_get_default() |
| 55 | order = client.get_string("/apps/metacity/general/button_layout") |
| 56 | if order and order.endswith(":"): |
| 57 | __button_right = False |
| 58 | except NameError: |
| 59 | pass |
| 60 | |
| 61 | # We need to ensure we're only shown once |
| 62 | self.shown = False |
| 63 | |
| 64 | # We don't want any WM decorations |
| 65 | self.set_decorated(False) |
| 66 | # We don't want to show in the taskbar or window switcher |
| 67 | self.set_skip_pager_hint(True) |
| 68 | self.set_skip_taskbar_hint(True) |
| 69 | # We must be modal to ensure we grab focus when presented from a gtk.Dialog |
| 70 | self.set_modal(True) |
| 71 | |
| 72 | self.set_border_width(0) |
| 73 | self.set_position(gtk.WIN_POS_MOUSE) |
| 74 | self.set_opacity(0.95) |
| 75 | |
| 76 | # Ensure a reasonable minimum size |
| 77 | self.set_geometry_hints(self, 100, 50) |
| 78 | |
| 79 | # Set this window as a transient window for parent(main window) |
| 80 | if parent_win: |
| 81 | self.set_transient_for(parent_win) |
| 82 | self.set_destroy_with_parent(True) |
| 83 | # Draw our label and close buttons |
| 84 | hbox = gtk.HBox(False, 0) |
| 85 | hbox.show() |
| 86 | self.add(hbox) |
| 87 | |
| 88 | img = gtk.Image() |
| 89 | img.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_BUTTON) |
| 90 | |
| 91 | self.button = gtk.Button() |
| 92 | self.button.set_image(img) |
| 93 | self.button.connect("clicked", self._dismiss_cb) |
| 94 | self.button.set_flags(gtk.CAN_DEFAULT) |
| 95 | self.button.grab_focus() |
| 96 | self.button.show() |
| 97 | vbox = gtk.VBox(False, 0) |
| 98 | vbox.show() |
| 99 | vbox.pack_start(self.button, False, False, 0) |
| 100 | if __button_right: |
| 101 | hbox.pack_end(vbox, True, True, 0) |
| 102 | else: |
| 103 | hbox.pack_start(vbox, True, True, 0) |
| 104 | |
| 105 | self.set_default(self.button) |
| 106 | |
| 107 | bin = gtk.HBox(True, 6) |
| 108 | bin.set_border_width(6) |
| 109 | bin.show() |
| 110 | self.label = gtk.Label() |
| 111 | self.label.set_line_wrap(True) |
| 112 | # We want to match the colours of the normal tooltips, as dictated by |
| 113 | # the users gtk+-2.0 theme, wherever possible - on some systems this |
| 114 | # requires explicitly setting a fg_color for the label which matches the |
| 115 | # tooltip_fg_color |
| 116 | settings = gtk.settings_get_default() |
| 117 | colours = settings.get_property('gtk-color-scheme').split('\n') |
| 118 | # remove any empty lines, there's likely to be a trailing one after |
| 119 | # calling split on a dictionary-like string |
| 120 | colours = filter(None, colours) |
| 121 | for col in colours: |
| 122 | item, val = col.split(': ') |
| 123 | if item == 'tooltip_fg_color': |
| 124 | style = self.label.get_style() |
| 125 | style.fg[gtk.STATE_NORMAL] = gtk.gdk.color_parse(val) |
| 126 | self.label.set_style(style) |
| 127 | break # we only care for the tooltip_fg_color |
| 128 | |
| 129 | self.label.set_markup(markup) |
| 130 | self.label.show() |
| 131 | bin.add(self.label) |
| 132 | hbox.pack_end(bin, True, True, 6) |
| 133 | |
| 134 | # add the original URL display for user reference |
| 135 | if 'a href' in markup: |
| 136 | hbox.set_tooltip_text(self.get_markup_url(markup)) |
| 137 | hbox.show() |
| 138 | |
| 139 | self.connect("key-press-event", self._catch_esc_cb) |
| 140 | |
| 141 | """ |
| 142 | Callback when the PersistentTooltip's close button is clicked. |
| 143 | Hides the PersistentTooltip. |
| 144 | """ |
| 145 | def _dismiss_cb(self, button): |
| 146 | self.hide() |
| 147 | return True |
| 148 | |
| 149 | """ |
| 150 | Callback when the Esc key is detected. Hides the PersistentTooltip. |
| 151 | """ |
| 152 | def _catch_esc_cb(self, widget, event): |
| 153 | keyname = gtk.gdk.keyval_name(event.keyval) |
| 154 | if keyname == "Escape": |
| 155 | self.hide() |
| 156 | return True |
| 157 | |
| 158 | """ |
| 159 | Called to present the PersistentTooltip. |
| 160 | Overrides the superclasses show() method to include state tracking. |
| 161 | """ |
| 162 | def show(self): |
| 163 | if not self.shown: |
| 164 | self.shown = True |
| 165 | gtk.Window.show(self) |
| 166 | |
| 167 | """ |
| 168 | Called to hide the PersistentTooltip. |
| 169 | Overrides the superclasses hide() method to include state tracking. |
| 170 | """ |
| 171 | def hide(self): |
| 172 | self.shown = False |
| 173 | gtk.Window.hide(self) |
| 174 | |
| 175 | """ |
| 176 | Called to get the hyperlink URL from markup text. |
| 177 | """ |
| 178 | def get_markup_url(self, markup): |
| 179 | url = "http:" |
| 180 | if markup and type(markup) == str: |
| 181 | s = markup |
| 182 | if 'http:' in s: |
| 183 | import re |
| 184 | url = re.search('(http:[^,\\ "]+)', s).group(0) |
| 185 | |
| 186 | return url |