#!/usr/bin/python # workspace switcher status # # display the workspaces of e.g. an xfce desktop during workspaces switches, # including a sketch of all windows # Copyright (c) 2012 Peter Palfrader # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. import pygtk, gtk, glib import wnck import datetime SCALE=50 BORDER=3 DELAY=500 class WSS: def cb_hide(self, data=None): print datetime.datetime.now(), "cb hide" print self.window.hide() return False def cb_update(self, widget, data=None): print datetime.datetime.now(), "cb update" workspace = self.screen.get_active_workspace() if self.previous is not None: self.label.set_markup("%s"%(workspace.get_name())) if not self.timerid is None: glib.source_remove(self.timerid) self.timerid = glib.timeout_add(DELAY, self.cb_hide) self.paint() self.window.queue_draw() print datetime.datetime.now(), 'show' self.window.show() self.previous = workspace def get_layout(self): wsposmap = {} wss = self.screen.get_workspaces() maxrow = 0 maxcol = 0 for ws in wss: r = ws.get_layout_row() c = ws.get_layout_column() if r > maxrow: maxrow = r if c > maxcol: maxcol = c wsposmap[ws.get_number()] = (r,c) w = self.screen.get_width() h = self.screen.get_height() layout = (w, h, maxrow+1, maxcol+1) self.wsposmap = wsposmap return layout def setup_table(self): width, height, rows, cols = self.get_layout() if self.table is not None: for area in self.areainfo: area.set_size_request(width/SCALE+2, height/SCALE+2) return table = gtk.Table(rows, cols, True) table.set_col_spacings(BORDER) table.set_row_spacings(BORDER) cells = [] areainfo = {} for r in xrange(0,rows): cells.append([]) for c in xrange(0,cols): area = gtk.DrawingArea() area.set_size_request(width/SCALE+2, height/SCALE+2) area.connect("expose-event", self.area_expose_cb) table.attach(area, c, c+1, r, r+1, xpadding=0, ypadding=0) i = {} i['w'] = [] cells[r].append(i) areainfo[area] = i table.show_all() self.box.add(table) self.table = table self.cells = cells self.areainfo = areainfo def area_expose_cb(self, area, event): width, height, rows, cols = self.get_layout() style = area.get_style() defgc = style.fg_gc[gtk.STATE_NORMAL] active_window = self.screen.get_active_window() i = self.areainfo[area] if 'gc' not in i: c = area.window.get_colormap().alloc_color(gtk.gdk.Color('#666666'), writeable=False, best_match=True) i['gc'] = area.window.new_gc(foreground=c) c = area.window.get_colormap().alloc_color(gtk.gdk.Color('#bbbbff'), writeable=False, best_match=True) i['gc-focus'] = area.window.new_gc(foreground=c) c = area.window.get_colormap().alloc_color(gtk.gdk.Color('#0000FF'), writeable=False, best_match=True) i['gc-border'] = area.window.new_gc(foreground=c, line_width=3) for w in i['w']: geom = w.get_geometry() if w == active_window: area.window.draw_rectangle(i['gc-focus'], True, geom[0]/SCALE+1, geom[1]/SCALE+1, geom[2]/SCALE, geom[3]/SCALE) area.window.draw_rectangle(defgc, False, geom[0]/SCALE+1, geom[1]/SCALE+1, geom[2]/SCALE, geom[3]/SCALE) else: area.window.draw_rectangle(i['gc'], True, geom[0]/SCALE+1, geom[1]/SCALE+1, geom[2]/SCALE, geom[3]/SCALE) area.window.draw_rectangle(defgc, False, geom[0]/SCALE+1, geom[1]/SCALE+1, geom[2]/SCALE, geom[3]/SCALE) if i['active']: area.window.draw_rectangle(i['gc-border'], False, 0, 0, width/SCALE+1, height/SCALE+1) else: area.window.draw_rectangle(defgc, False, 0, 0, width/SCALE+1, height/SCALE+1) return True def cell_info_from_workspace(self, ws): wsn = ws.get_number() wspos = self.wsposmap[wsn] row, col = wspos cell = self.cells[row][col] return cell def paint(self): width, height, mr, mc = self.get_layout() self.setup_table() window_list = self.screen.get_windows() for a in self.areainfo: del self.areainfo[a]['w'][:] self.areainfo[a]['active'] = False for w in window_list: ws = w.get_workspace() if ws is not None: cell = self.cell_info_from_workspace(ws) cell['w'].append(w) active = self.screen.get_active_workspace() cell = self.cell_info_from_workspace(active) cell['active'] = True def __init__(self): window = gtk.Window(gtk.WINDOW_POPUP) label = gtk.Label() box = gtk.VBox() box.set_border_width(20) box.add(label) window.add(box) window.set_position(gtk.WIN_POS_CENTER) box.show_all() screen = wnck.screen_get_default() screen.connect('active-workspace-changed', self.cb_update) self.window = window self.label = label self.box = box self.screen = screen self.previous = None self.table = None self.cells = None self.areainfo = None self.timerid = None def main(self): # All PyGTK applications must have a gtk.main(). Control ends here # and waits for an event to occur (like a key press or mouse event). gtk.main() if __name__ == "__main__": wss = WSS() wss.main() # vim:set et: # vim:set ts=4: # vim:set shiftwidth=4: