1#!/usr/local/bin/python3.8 2""" 3 Provide a window showing a list of an app's actions and allow the 4 user to select one 5 6 In addition to the actions defined in the app's .desktop file, a 7 Pin/Unpin action will also be added as appropriate 8 9 The window will function in a similar way to a tooltip i.e. 10 it will appear when the mouse hovers over a dock icon and 11 will disappear if the mouse moves away from the window or 12 the dock applet. 13""" 14 15# 16# Copyright (C) 1997-2003 Free Software Foundation, Inc. 17# 18# This program is free software; you can redistribute it and/or 19# modify it under the terms of the GNU General Public License as 20# published by the Free Software Foundation; either version 2 of the 21# License, or (at your option) any later version. 22# 23# This program is distributed in the hope that it will be useful, but 24# WITHOUT ANY WARRANTY; without even the implied warranty of 25# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 26# General Public License for more details. 27# 28# You should have received a copy of the GNU General Public License 29# along with this program; if not, write to the Free Software 30# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 31# 02110-1301, USA. 32# 33# Author: 34# Robin Thompson 35 36# do not change the value of this variable - it will be set during build 37# according to the value of the --with-gtk3 option used with .configure 38build_gtk2 = False 39 40import gi 41 42if build_gtk2: 43 gi.require_version("Gtk", "2.0") 44 gi.require_version("Wnck", "1.0") 45else: 46 gi.require_version("Gtk", "3.0") 47 gi.require_version("Wnck", "3.0") 48 49gi.require_version("MatePanelApplet", "4.0") 50 51from gi.repository import Gtk 52from gi.repository import Wnck 53from gi.repository import GdkPixbuf 54from gi.repository import Gio 55from gi.repository import Gdk 56from gi.repository import GObject 57from gi.repository import MatePanelApplet 58from gi.repository import Pango 59 60from dock_popup import DockPopup 61 62from log_it import log_it as log_it 63 64CONST_MAX_TITLE_WIDTH = 300 # Max width of the action text 65CONST_SEP = "--------------------" # text which denotes tree view item is a separator 66 67 68class DockActionList(DockPopup): 69 70 """ Descendent of Dockup to provide a list of a running app's 71 open windows 72 73 """ 74 75 def __init__(self, wnck_screen, panel_orient, scroll_adj): 76 """ 77 create the window and its contents 78 79 Args: 80 wnck_screen: the wnck_screen of the applet 81 panel_orient : the orientation of the panel 82 scroll_adj : an adjustment to be applied to the window position 83 because the dock has scrolling enabled 84 """ 85 86 # call the base classes constructor 87 DockPopup.__init__(self, wnck_screen, panel_orient, scroll_adj) 88 89 # we use a treeview to list each action, so initialise it and its 90 # liststore 91 self.__tree_view = Gtk.TreeView() 92 93 if not build_gtk2: 94 self.__tree_view.set_valign(Gtk.Align.START) 95 self.__tree_view.set_halign(Gtk.Align.START) 96 self.__tree_view.hexpand = True 97 self.__tree_view.vexpand = True 98 99 self.__tree_view.set_headers_visible(False) 100 101 # turn grid lines off, although they still seem to appear in some 102 # themes e.g. Menta 103 self.__tree_view.set_grid_lines(Gtk.TreeViewGridLines.NONE) 104 105 self.__tree_view.set_hover_selection(True) 106 107 # the liststore needs to contain an icon, the action text, and the 108 # action itself 109 self.__list_store = Gtk.ListStore(str, Gtk.Action, GdkPixbuf.Pixbuf) 110 111 self.__icon_renderer = Gtk.CellRendererPixbuf() 112 self.__title_renderer = Gtk.CellRendererText() 113 114 # set default cell colours and padding 115 self.__title_renderer.set_padding(2, 6) 116 self.set_bg_col(32, 32, 32) 117 118 # create columns for the treeview 119 self.__col_icon = Gtk.TreeViewColumn("", 120 self.__icon_renderer, 121 pixbuf=2) 122 123 self.__col_title = Gtk.TreeViewColumn("", 124 self.__title_renderer, 125 text=0) 126 127 self.__col_title.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY) 128 self.__col_title.set_expand(True) 129 130 self.__col_title.set_max_width(CONST_MAX_TITLE_WIDTH) 131 self.__col_title.set_sizing(Gtk.TreeViewColumnSizing.GROW_ONLY) 132 133 # add the columns 134 self.__tree_view.set_model(self.__list_store) 135 self.__tree_view.append_column(self.__col_icon) 136 self.__tree_view.append_column(self.__col_title) 137 self.__tree_view.set_row_separator_func(self.check_sep) 138 139 # add the treeview to the window 140 self.set_main_widget(self.__tree_view) 141 142 self.__tree_view.connect("button-release-event", self.button_release) 143 self.__tree_view.connect("size-allocate", self.treeview_allocate) 144 145 def treeview_allocate(self, widget, allocation): 146 """ Event handler for the tree view size-allocate event 147 148 If the title column has expanded to its maximum width, ellipsize the 149 title text... 150 """ 151 152 if self.__col_title.get_width() == CONST_MAX_TITLE_WIDTH: 153 self.__col_title.set_min_width(CONST_MAX_TITLE_WIDTH) 154 self.__title_renderer.set_property("ellipsize", 155 Pango.EllipsizeMode.END) 156 157 self.__tree_view.get_selection().unselect_all() 158 159 def set_colours(self, panel_colour): 160 """ Sets the treeview colours (background, foreground and 161 highlight) to match the window colours. 162 163 Note : set_colours must have been called first so that 164 the window colours are set correctly 165 """ 166 167 DockPopup.set_colours(self, panel_colour) 168 169 # set strings used to set widget colours - we can't change 170 # the highlight colour, only foreground and background 171 r, g, b = self.bg_col 172 bg_str = "#%.2x%.2x%.2x" % (r, g, b) 173 r, g, b = self.fg_col 174 fg_str = "#%.2x%.2x%.2x" % (r, g, b) 175 176 # now set the treeview colours 177 self.__title_renderer.set_property("cell-background", bg_str) 178 self.__title_renderer.set_property("foreground", fg_str) 179 180 self.__icon_renderer.set_property("cell-background", bg_str) 181 182 def get_num_rows(self): 183 """ Returns the number of rows of data in the list store 184 """ 185 186 return (self.__list_store.iter_n_children(None)) 187 188 def button_release(self, widget, event): 189 """ Handler for the button release event 190 191 If the middle or right mouse button was pressed, do nothing 192 193 Otherwise, activate the selected item's action 194 195 Hide the action list 196 197 Args: 198 199 widget : the widget the received the signal i.e. our treeview 200 event : the event parameters 201 202 Returns: 203 True: to stop any other handlers from being invoked 204 """ 205 206 if event.button != 1: 207 return False # let other handlers run 208 209 path, col, xrel, yrel = self.__tree_view.get_path_at_pos(event.x, event.y) 210 sel_iter = self.__list_store.get_iter(path) 211 212 action = self.__list_store.get_value(sel_iter, 1) 213 title = self.__list_store.get_value(sel_iter, 0) 214 if action is not None: 215 self.hide() 216 action.activate() 217 218 return True 219 220 def add_separator(self): 221 """ Convenience method to add a separator to the list 222 223 If there are no items currently in the list then the separator 224 won't be added 225 """ 226 227 if len(self.__list_store) > 0: 228 self.add_to_list(CONST_SEP, None, False) 229 230 def add_to_list(self, title, action, show_icon): 231 """ Add an item to the action list 232 233 Args: 234 title - the title of the window or the action 235 action - a GTK Action to be activated if the item is clicked 236 show_icon - if True the app's icon will be shown alongside the 237 item in the list 238 """ 239 240 if show_icon: 241 app_icon = self.app_pb 242 else: 243 app_icon = None 244 245 self.__list_store.append([title, action, app_icon]) 246 247 def clear_act_list(self): 248 """ Clear the list of open windows """ 249 250 self.__list_store.clear() 251 252 def win_button_press(self, widget, event): 253 """ this is for debug puposes only""" 254 Gtk.main_quit() 255 256 def check_sep(self, model, iter, data=None): 257 """ Check to see if the current row is to be displayed as a separator 258 259 Args : 260 model : the treeview model (will be self.__list_store) 261 iter : the row in the model we're interested in 262 data : user defined data 263 264 Returns: 265 Bool 266 """ 267 268 title = model.get_value(iter, 0) 269 return title == CONST_SEP 270 271 272def main(): 273 """ 274 main function - debugging code goes here 275 """ 276 277# thewin = DockWinList() 278# thewin.set_app_name("Testing....") 279# thewin.add_to_list(None, False, "Win 1") 280# thewin.add_to_list(None, True, "Win 2 is active") 281# thewin.add_to_list(None, False, "Win 3") 282# thewin.show_all() 283 284# thewin.move(100, 110) 285# pos = thewin.get_position() 286# size = thewin.get_size() 287# print("pos %d %d" %(pos[0], pos[1])) 288# print("size %d %d" %(size[0], size[1])) 289# thewin.add_mouse_area(Gdk.Rectangle(pos[0]-15, pos[1]-15, size[0]+30, size[1]+30)) 290# thewin.add_mouse_area(Gdk.Rectangle(0, 0, 48, 500)) 291# thewin.add_mouse_area(Gdk.Rectangle(48, 110, 100, size[1])) 292# Gtk.main() 293 return 294 295 296if __name__ == "__main__": 297 main() 298