merge the C branch into HEAD
[dana/openbox.git] / python / historyplacement.py
1 ##############################################################################
2 ### The history window placement algorithm. ebind historyplacement.place   ###
3 ### to the ob.EventAction.PlaceWindow event to use it.                     ###
4 ##############################################################################
5
6 import windowplacement, config, hooks
7
8 def place(data):
9     """Place a window usingthe history placement algorithm."""
10     _place(data)
11
12 export_functions = place
13
14 ##############################################################################
15
16 config.add('historyplacement',
17            'ignore_requested_positions',
18            'Ignore Requested Positions',
19            "When true, the placement algorithm will attempt to place " + \
20            "windows even when they request a position (like XMMS can)." + \
21            "Note this only applies to 'normal' windows, not to special " + \
22            "cases like desktops and docks.",
23            'boolean',
24            0)
25 config.add('historyplacement',
26            'dont_duplicate',
27            "Don't Diplicate",
28            "When true, if 2 copies of the same match in history are to be " + \
29            "placed before one of them is closed (so it would be placed " + \
30            "over-top of the last one), this will cause the second window to "+\
31            "not be placed via history, and the 'Fallback Algorithm' will be "+\
32            "used instead.",
33            'boolean',
34            1)
35 config.add('historyplacement',
36            'filename',
37            'History Database Filename',
38            "The name of the file where history data will be stored. The " + \
39            "number of the screen is appended onto this name. The file will " +\
40            "be placed in ~/.openbox/.",
41            'string',
42            'historydb')
43 config.add('historyplacement',
44            'fallback',
45            'Fallback Algorithm',
46            "The window placement algorithm that will be used when history " + \
47            "placement does not have a place for the window.",
48            'enum',
49            windowplacement.random,
50            options = windowplacement.export_functions)
51
52 ###########################################################################
53
54 ###########################################################################
55 ###      Internal stuff, should not be accessed outside the module.     ###
56 ###########################################################################
57
58 import ob, os, string
59
60 _data = []
61
62 class _State:
63     def __init__(self, resname, resclass, role, x, y):
64         self.resname = resname
65         self.resclass = resclass
66         self.role = role
67         self.x = x
68         self.y = y
69         self.placed = 0
70     def __eq__(self, other):
71         if self.resname == other.resname and \
72            self.resclass == other.resclass and \
73            self.role == other.role:
74             return 1
75         return 0
76
77 def _load():
78     global _data
79     try:
80         file = open(os.environ['HOME'] + '/.openbox/' + \
81                     config.get('historyplacement', 'filename') + \
82                     "." + str(ob.Openbox.screenNumber()), 'r')
83         # read data
84         for line in file.readlines():
85             line = line[:-1] # drop the '\n'
86             try:
87                 s = string.split(line, '\0')
88                 state = _State(s[0], s[1], s[2],
89                                int(s[3]), int(s[4]))
90
91                 _data.append(state)
92                 
93             except ValueError: pass
94             except IndexError: pass
95         file.close()
96     except IOError: pass
97
98 def _save():
99     file = open(os.environ['HOME'] + '/.openbox/'+ \
100                 config.get('historyplacement', 'filename') + \
101                 "." + str(ob.Openbox.screenNumber()), 'w')
102     if file:
103         for i in _data:
104             file.write(i.resname + '\0' +
105                        i.resclass + '\0' +
106                        i.role + '\0' +
107                        str(i.x) + '\0' +
108                        str(i.y) + '\n')
109         file.close()
110
111 def _create_state(client):
112     area = client.area()
113     return _State(client.resName(), client.resClass(),
114                   client.role(), area[0], area[1])
115
116 def _place(client):
117     state = _create_state(client)
118     try:
119         print "looking for : " + state.resname +  " : " + \
120               state.resclass + " : " + state.role
121         try:
122             i = _data.index(state)
123         except ValueError:
124             print "No match in history"
125         else:
126             coords = _data[i] # get the equal element
127             print "Found in history ("+str(coords.x)+","+\
128                   str(coords.y)+")"
129             if not (config.get('historyplacement', 'dont_duplicate') \
130                     and coords.placed):
131                 coords.placed = 1
132                 if ob.Openbox.state() != ob.State.Starting:
133 #    if not (config.get('historyplacement', 'ignore_requested_positions') \
134 #            and data.client.normal()):
135 #        if data.client.positionRequested(): return
136                     ca = client.area()
137                     client.setArea((coords.x, coords.y, ca[2], ca[3]))
138                 return
139             else:
140                 print "Already placed another window there"
141     except TypeError:
142         pass
143     fallback = config.get('historyplacement', 'fallback')
144     if fallback: fallback(client)
145
146 def _save_window(client):
147     global _data
148     state = _create_state(client)
149     print "looking for : " + state.resname +  " : " + state.resclass + \
150           " : " + state.role
151
152     try:
153         print "replacing"
154         i = _data.index(state)
155         _data[i] = state # replace it
156     except ValueError:
157         print "appending"
158         _data.append(state)
159
160 hooks.startup.append(_load)
161 hooks.shutdown.append(_save)
162 hooks.closed.append(_save_window)
163
164 print "Loaded historyplacement.py"