#!/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("<span size='xx-large'>%s</span>"%(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: