]> icculus.org git repositories - dana/openbox.git/blob - scripts/historyplacement.py
merge the C branch into HEAD
[dana/openbox.git] / scripts / 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
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 otk
59 import ob
60 import os
61 import string
62
63 _data = []
64
65 class _state:
66     def __init__(self, appname, appclass, role, x, y):
67         self.appname = appname
68         self.appclass = appclass
69         self.role = role
70         self.x = x
71         self.y = y
72         self.placed = 0
73     def __eq__(self, other):
74         if self.appname == other.appname and \
75            self.appclass == other.appclass and \
76            self.role == other.role:
77             return 1
78         return 0
79
80 def _load(data):
81     global _data
82     try:
83         file = open(os.environ['HOME'] + '/.openbox/' + \
84                     config.get('historyplacement', 'filename') + \
85                     "." + str(data.screen), 'r')
86         # read data
87         for line in file.readlines():
88             line = line[:-1] # drop the '\n'
89             try:
90                 s = string.split(line, '\0')
91                 state = _state(s[0], s[1], s[2],
92                                string.atoi(s[3]), string.atoi(s[4]))
93
94                 while len(_data)-1 < data.screen:
95                     _data.append([])
96                 _data[data.screen].append(state)
97                 
98             except ValueError: pass
99             except IndexError: pass
100         file.close()
101     except IOError: pass
102
103 def _save(data):
104     global _data
105     file = open(os.environ['HOME']+'/.openbox/'+ \
106                 config.get('historyplacement', 'filename') + \
107                 "." + str(data.screen), 'w')
108     if file:
109         while len(_data)-1 < data.screen:
110             _data.append([])
111         for i in _data[data.screen]:
112             file.write(i.appname + '\0' +
113                        i.appclass + '\0' +
114                        i.role + '\0' +
115                        str(i.x) + '\0' +
116                        str(i.y) + '\n')
117         file.close()
118
119 def _create_state(data):
120     global _data
121     area = data.client.area()
122     return _state(data.client.appName(), data.client.appClass(),
123                   data.client.role(), area.x(), area.y())
124
125 def _find(screen, state):
126     global _data
127     try:
128         return _data[screen].index(state)
129     except ValueError:
130         return -1
131     except IndexError:
132         while len(_data)-1 < screen:
133             _data.append([])
134         return _find(screen, state) # try again
135
136 def _place(data):
137     global _data
138     if data.client:
139         if not (config.get('historyplacement', 'ignore_requested_positions') \
140                 and data.client.normal()):
141             if data.client.positionRequested(): return
142         state = _create_state(data)
143         try:
144             print "looking for : " + state.appname +  " : " + \
145                   state.appclass + " : " + state.role
146
147             i = _find(data.screen, state)
148             if i >= 0:
149                 coords = _data[data.screen][i]
150                 print "Found in history ("+str(coords.x)+","+\
151                       str(coords.y)+")"
152                 if not (config.get('historyplacement', 'dont_duplicate') \
153                         and coords.placed):
154                     data.client.move(coords.x, coords.y)
155                     coords.placed = 1
156                     return
157                 else:
158                     print "Already placed another window there"
159             else:
160                 print "No match in history"
161         except TypeError:
162             pass
163     fallback = config.get('historyplacement', 'fallback')
164     if fallback: fallback(data)
165
166 def _save_window(data):
167     global _data
168     if data.client:
169         state = _create_state(data)
170         print "looking for : " + state.appname +  " : " + state.appclass + \
171               " : " + state.role
172
173         i = _find(data.screen, state)
174         if i >= 0:
175             print "replacing"
176             _data[data.screen][i] = state # replace it
177         else:
178             print "appending"
179             _data[data.screen].append(state)
180
181 ob.ebind(ob.EventAction.CloseWindow, _save_window)
182 ob.ebind(ob.EventAction.Startup, _load)
183 ob.ebind(ob.EventAction.Shutdown, _save)
184
185 print "Loaded historyplacement.py"