Package traylib :: Module winmenu
[frames] | no frames]

Source Code for Module traylib.winmenu

  1  import rox, os, gobject, gtk, struct 
  2  from rox import processes 
  3   
  4  import traylib 
  5  from traylib import * 
  6  from pixbuf_helper import * 
  7   
  8  _ = rox.i18n.translation(os.path.join(os.path.dirname( 
  9                                                                                  os.path.dirname( 
 10                                                                                          os.path.dirname(traylib.__file__))), 
 11                                                                          'Messages')) 
 12   
13 -def _load_icons(icon_theme):
14 global dir_icon, home_icon 15 home_icon = None 16 dir_icon = None 17 for icon_name in ['mime-inode:directory', 'folder', 'gnome-fs-directory']: 18 try: 19 dir_icon = icon_theme.load_icon(icon_name, 32, 0) 20 break 21 except: 22 pass 23 for icon_name in ['user-home', 'gnome-fs-home']: 24 try: 25 home_icon = icon_theme.load_icon(icon_name, 32, 0) 26 break 27 except: 28 pass
29 30 home_icon = None 31 dir_icon = None 32 icon_theme.connect("changed", _load_icons) 33 _load_icons(icon_theme) 34
35 -def _kill(menu_item, pids, name):
36 if rox.confirm(_("Really force %s to quit?") % name, 37 gtk.STOCK_QUIT, _("Force quit")): 38 for pid in pids: 39 rox.processes.PipeThroughCommand(('kill', '-KILL', str(pid)), 40 None, None).wait()
41
42 -def _get_filer_window_path(window):
43 name = window.get_name() 44 if (window.get_class_group().get_name() != 'ROX-Filer' 45 or not (name.startswith('/') or name.startswith('~'))): 46 return '' 47 for i in range(1-len(name), 0): 48 if name[-i] == '(' or name[-i] == '+': 49 name = name[:-(i+1)] 50 break 51 return name
52
53 -class WindowActionMenu(gtk.Menu):
54 """ 55 A menu that shows actions for a C{wnck.Window}. 56 """ 57
58 - def __init__(self, 59 window, 60 has_kill = False, 61 path = None, 62 parent = None):
63 """ 64 Creates a new C{WindowActionMenu}. 65 66 @param has_kill: If C{True}, the menu contains an entry to kill the 67 process the window belongs to. 68 @param path: If not C{None}, indicates that the window is a filemanager 69 window showing the directory C{path}. 70 @param parent: The L{WindowMenu} showing all directories. 71 """ 72 assert isinstance(window, wnck.Window) 73 gtk.Menu.__init__(self) 74 75 self.__window = window 76 if path: 77 self.__path = os.path.expanduser(path) 78 else: 79 self.__path = None 80 self.__parent = parent 81 82 item = gtk.ImageMenuItem(_("Activate")) 83 item.get_image().set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_MENU) 84 item.connect("activate", self.__winaction2, wnck.Window.activate) 85 self.append(item) 86 87 self.append(gtk.SeparatorMenuItem()) 88 89 actions = window.get_actions() 90 91 if window.is_maximized(): 92 item = gtk.ImageMenuItem(_("Unmaximize")) 93 item.get_image().set_from_stock(gtk.STOCK_ZOOM_OUT, 94 gtk.ICON_SIZE_MENU) 95 item.connect("activate", self.__winaction, wnck.Window.unmaximize) 96 item.set_sensitive(wnck.WINDOW_ACTION_UNMAXIMIZE & actions) 97 else: 98 item = gtk.ImageMenuItem(_("Maximize")) 99 item.get_image().set_from_stock(gtk.STOCK_ZOOM_100, 100 gtk.ICON_SIZE_MENU) 101 item.connect("activate", self.__winaction, wnck.Window.maximize) 102 item.set_sensitive(wnck.WINDOW_ACTION_MAXIMIZE & actions) 103 self.append(item) 104 105 if window.is_minimized(): 106 item = gtk.ImageMenuItem(_("Show")) 107 item.get_image().set_from_stock(gtk.STOCK_REDO, gtk.ICON_SIZE_MENU) 108 item.connect("activate", self.__winaction2, wnck.Window.unminimize) 109 else: 110 item = gtk.ImageMenuItem(_("Hide")) 111 item.get_image().set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_MENU) 112 item.connect("activate", self.__minimize) 113 self.append(item) 114 115 if window.is_shaded(): 116 item = gtk.ImageMenuItem(_("Unshade")) 117 item.get_image().set_from_stock(gtk.STOCK_GOTO_BOTTOM, 118 gtk.ICON_SIZE_MENU) 119 item.connect("activate", self.__winaction, wnck.Window.unshade) 120 item.set_sensitive(wnck.WINDOW_ACTION_UNSHADE & actions) 121 else: 122 item = gtk.ImageMenuItem(_("Shade")) 123 item.get_image().set_from_stock(gtk.STOCK_GOTO_TOP, 124 gtk.ICON_SIZE_MENU) 125 item.connect("activate", self.__winaction, wnck.Window.shade) 126 item.set_sensitive(wnck.WINDOW_ACTION_SHADE & actions) 127 self.append(item) 128 129 self.append(gtk.SeparatorMenuItem()) 130 131 if window.is_pinned() or window.is_sticky(): 132 item = gtk.ImageMenuItem(_("Only on this workspace")) 133 item.get_image().set_from_stock(gtk.STOCK_REMOVE, 134 gtk.ICON_SIZE_MENU) 135 item.connect("activate", self.__winaction, wnck.Window.unstick) 136 item.connect("activate", self.__winaction, wnck.Window.unpin) 137 item.set_sensitive(wnck.WINDOW_ACTION_UNSTICK & actions) 138 else: 139 item = gtk.ImageMenuItem(_("Always on visible workspace")) 140 item.get_image().set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU) 141 item.connect("activate", self.__winaction, wnck.Window.stick) 142 item.connect("activate", self.__winaction, wnck.Window.pin) 143 item.set_sensitive(wnck.WINDOW_ACTION_STICK & actions) 144 self.append(item) 145 146 if screen.get_workspace_count() > 1: 147 item = gtk.ImageMenuItem(_("Move to workspace")) 148 item.get_image().set_from_stock(gtk.STOCK_JUMP_TO, 149 gtk.ICON_SIZE_MENU) 150 self.append(item) 151 submenu = gtk.Menu() 152 item.set_submenu(submenu) 153 for i in range(0, screen.get_workspace_count()): 154 workspace = screen.get_workspace(i) 155 item = gtk.MenuItem(workspace.get_name()) 156 if workspace != window.get_workspace(): 157 item.connect("activate", 158 self.__move_to_workspace, 159 workspace) 160 else: 161 item.set_sensitive(False) 162 submenu.append(item) 163 164 if has_kill: 165 self.append(gtk.SeparatorMenuItem()) 166 app = window.get_application() 167 pid = app.get_pid() 168 item = gtk.ImageMenuItem(_("Force quit")) 169 item.get_image().set_from_stock(gtk.STOCK_QUIT, gtk.ICON_SIZE_MENU) 170 self.append(item) 171 item.connect("activate", _kill, [pid], app.get_name()) 172 173 self.append(gtk.SeparatorMenuItem()) 174 175 if self.__parent and self.__path and os.path.isdir(self.__path): 176 item = gtk.ImageMenuItem(_("Close subdirectories")) 177 item.get_image().set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) 178 item.connect("activate", self.__close_subdirs) 179 self.append(item) 180 181 item = gtk.ImageMenuItem(gtk.STOCK_CLOSE) 182 item.connect("activate", self.__winaction2, wnck.Window.close) 183 self.append(item)
184
185 - def __close_subdirs(self, menu_item):
186 path = self.__path + os.sep 187 windows = [] 188 for window in self.__parent.get_windows(): 189 window_path = os.path.expanduser(_get_filer_window_path(window)) 190 if window_path and window_path.startswith(path): 191 windows.append(window) 192 if not windows: 193 rox.info(_("There are no windows showing subdirectories of %s") 194 % self.__path) 195 n_windows = len(windows) 196 if n_windows > 1: 197 if not rox.confirm(_("Close all %d subdirectories of %s?") 198 % (n_windows, self.__path), gtk.STOCK_CLOSE): 199 return 200 for window in windows: 201 window.close(gtk.get_current_event_time())
202
203 - def __winaction(self, menu_item, func):
204 func(self.__window)
205
206 - def __winaction2(self, menu_item, func):
207 func(self.__window, gtk.get_current_event_time())
208
209 - def __move_to_workspace(self, menu_item, workspace):
210 self.__window.move_to_workspace(workspace)
211
212 - def __minimize(self, menu_item):
213 self.__window.unshade() 214 self.__window.minimize()
215
216 -class WindowMenuItem(gtk.ImageMenuItem):
217 """ 218 A menu item representing a window. 219 """ 220
221 - def __init__(self, window, icon, root = None, root_icon = None):
222 """ 223 Creates a new WindowMenuItem. 224 225 @param window: The C{wnck.Window} the menu item represents. 226 """ 227 pixbuf = None 228 self.__window = window 229 self.__path = _get_filer_window_path(window) 230 if self.__path: 231 name = self.__path 232 if root: 233 root_dirname = os.path.dirname(root) 234 if root_dirname == '/': 235 l = 1 236 else: 237 l = len(root_dirname) + 1 238 if name != '/': 239 name = os.path.expanduser(name)[l:] 240 name = name.replace(os.path.expanduser('~'), '~') 241 else: 242 name = window.get_name() 243 size = 22 244 if window.is_minimized(): 245 name = "[ " + name + " ]" 246 if window.is_shaded(): 247 name = "= " + name + " =" 248 if window.needs_attention(): 249 name = "!! " + name + " !!" 250 if window == screen.get_active_window(): 251 size = 32 252 gtk.ImageMenuItem.__init__(self, name.replace('_', '__')) 253 if self.__path: 254 icon_path = os.path.expanduser(os.path.join(self.__path, 255 '.DirIcon')) 256 if os.access(icon_path, os.F_OK): 257 pixbuf = gtk.gdk.pixbuf_new_from_file(icon_path) 258 elif self.__path != root: 259 if os.path.expanduser(self.__path) == os.path.expanduser('~'): 260 pixbuf = home_icon 261 else: 262 pixbuf = dir_icon 263 elif self.__path == root and root_icon: 264 pixbuf = root_icon 265 if not pixbuf: 266 if icon: 267 pixbuf = icon 268 else: 269 pixbuf = window.get_icon() 270 pixbuf = scale_pixbuf_to_size(pixbuf, size) 271 self.get_image().set_from_pixbuf(pixbuf) 272 273 self.drag_source_set(gtk.gdk.BUTTON1_MASK, 274 [("application/x-wnck-window-id", 275 0, 276 TARGET_WNCK_WINDOW_ID)], 277 gtk.gdk.ACTION_MOVE) 278 self.connect("drag-begin", self.__drag_begin, pixbuf) 279 self.connect("drag-data-get", self.__drag_data_get)
280
281 - def __drag_begin(self, widget, context, pixbuf):
282 assert widget == self 283 context.set_icon_pixbuf(pixbuf, 0,0)
284
285 - def __drag_data_get(self, widget, context, data, info, time):
286 xid = self.__window.get_xid() 287 data.set(data.target, 8, apply(struct.pack, ['1i', xid]))
288
289 - def get_path(self):
290 return self.__path
291 292 # the type of a WindowMenu from which windows can be selected 293 TYPE_SELECT = 0 294 295 # the type of a WindowMenu which shows options for each window in a submenu 296 TYPE_OPTIONS = 1 297
298 -class WindowMenu(gtk.Menu):
299 """ 300 The menu for a list of windows. 301 """ 302
303 - def __init__(self, windows, type, icon, group_name, 304 root = None, root_icon = None, has_kill = False):
305 """ 306 Creates a new WindowMenu. 307 308 @param windows: A list of C{wnck.Window}s. 309 @param type: The type of the menu.\n 310 C{TYPE_SELECT}: A menu from which a window can be selected to be 311 activated.\n 312 C{TYPE_OPTIONS}: A menu which shows a submenu for each window, 313 "hide all" or "show all" and "close all" menu items. If 314 C{has_kill} is C{True}, it also contains a "force quit" menu 315 entry. 316 @param root: If not C{None}, indicates that the windows are filemanager 317 windows and the path prefix "root" should not be omitted. 318 @param root_icon: The icon to show for the root menu entry. This is the 319 menu entry showing C{root}. 320 @param has_kill: If C{True} and C{type==TYPE_OPTIONS}, the menu contains 321 a "kill" menu entry which kills the process the windows belong to. 322 If the windows belong to different processes, each submenu has its 323 own "kill" menu entry. 324 """ 325 assert type in (TYPE_SELECT, TYPE_OPTIONS) 326 gtk.Menu.__init__(self) 327 self.__group_name = group_name 328 self.__type = type 329 self.__windows = windows 330 windows.sort(key=wnck.Window.get_name) 331 time = gtk.get_current_event_time() 332 self.__active_window = screen.get_active_window() 333 has_minimized_windows = False 334 has_unminimized_windows = False 335 same_app = True 336 self.__pids = [] 337 for window in windows: 338 pid = window.get_application().get_pid() 339 if pid in self.__pids: 340 continue 341 self.__pids.append(pid) 342 for window in windows: 343 if window.is_minimized(): 344 has_minimized_windows = True 345 else: 346 has_unminimized_windows = True 347 item = WindowMenuItem(window, icon, root, root_icon) 348 if type == TYPE_OPTIONS: 349 item.set_submenu(WindowActionMenu(window, 350 has_kill and len(self.__pids) > 1, 351 item.get_path(), self)) 352 else: 353 item.connect("scroll-event", self.__scroll, window) 354 item.connect("activate", self.__window_selected, window, time) 355 self.append(item) 356 if self.__type == TYPE_OPTIONS: 357 self.append(gtk.SeparatorMenuItem()) 358 item = gtk.ImageMenuItem(_("Show all")) 359 item.get_image().set_from_stock(gtk.STOCK_REDO, gtk.ICON_SIZE_MENU) 360 item.connect("activate", self.__restore_all) 361 item.set_sensitive(has_minimized_windows) 362 self.append(item) 363 item = gtk.ImageMenuItem(_("Hide all")) 364 item.get_image().set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_MENU) 365 item.connect("activate", self.__minimize_all) 366 item.set_sensitive(has_unminimized_windows) 367 self.append(item) 368 if has_kill: 369 self.append(gtk.SeparatorMenuItem()) 370 item = gtk.ImageMenuItem(_("Force quit")) 371 item.get_image().set_from_stock(gtk.STOCK_QUIT, 372 gtk.ICON_SIZE_MENU) 373 item.connect("activate", _kill, self.__pids, group_name) 374 self.append(item) 375 self.append(gtk.SeparatorMenuItem()) 376 item = gtk.ImageMenuItem(_("Close all")) 377 item.get_image().set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) 378 item.connect("activate", self.__close_all) 379 self.append(item)
380
381 - def get_windows(self):
382 """ 383 @return: The windows belonging to the C{WindowMenu}. 384 """ 385 return self.__windows
386
387 - def __minimize_all(self, menu_item):
388 for window in self.__windows: 389 window.minimize()
390
391 - def __restore_all(self, menu_item):
392 for window in self.__windows: 393 if window.is_minimized(): 394 window.unminimize(gtk.get_current_event_time())
395
396 - def __close_all(self, menu_item):
397 n_windows = len(self.__windows) 398 if n_windows == 0: 399 rox.info(_("%s hasn't got any open windows anymore.") 400 % self.__group_name) 401 return 402 if not rox.confirm(_("Close all %d windows of %s?") 403 % (n_windows, self.__group_name), 404 gtk.STOCK_CLOSE, _("Close all")): 405 return 406 for window in self.__windows: 407 window.close(gtk.get_current_event_time())
408
409 - def __window_selected(self, menu_item, window, time):
410 window.activate(time)
411
412 - def __scroll(self, menu_item, event, window):
413 if event.direction == gtk.gdk.SCROLL_UP: 414 #if window == screen.get_active_window(): 415 # window.shade() 416 #else: 417 window.activate(event.time) 418 elif event.direction == gtk.gdk.SCROLL_DOWN: 419 #if window.is_shaded(): 420 # window.unshade() 421 # window.activate(event.time) 422 #else: 423 window.minimize()
424