Nicer borders
[switcha.git] / main.py
blobc3169ee80cc79273e39f98274bb20456f4028177
1 #!/usr/bin/env python
2 import os
3 import sys
4 import re
6 from PyQt4.QtCore import *
7 from PyQt4.QtGui import *
9 reSimplify = re.compile(" +")
10 def simplifySpaces(txt):
11 return reSimplify.sub(" ", txt)
14 def runWmCtrl(*args):
15 cmd = ["wmctrl"]
16 cmd.extend(args)
17 print cmd
18 sin, sout = os.popen2(cmd)
19 sin.close()
20 lines = [simplifySpaces(x.strip()) for x in sout.readlines()]
21 return lines
24 def getWindowList():
25 """0x032000e1 0 cpc6128 Qt Designer"""
26 lines = runWmCtrl("-l")
27 lst = []
28 for line in lines:
29 tokens = line.split(" ")
30 wid = tokens[0]
31 text = " ".join(tokens[3:])
32 lst.append( (text, wid) )
33 return lst
36 def switchToWindow(wid):
37 runWmCtrl("-ia", wid)
40 class ListView(QListView):
41 def sizeHint(self):
42 width = 0
43 height = 0
44 options = self.viewOptions()
45 for pos in range(self.model().rowCount()):
46 index = self.model().index(pos, 0)
47 hint = self.itemDelegate().sizeHint(options, index)
48 width = max(width, hint.width())
49 height += hint.height()
50 return QSize(width + 10, height + 10)
53 class Window(QDialog):
54 def __init__(self):
55 QDialog.__init__(self)
56 flags = self.windowFlags()
57 self.setWindowFlags(flags | Qt.FramelessWindowHint)
58 self.initModel()
59 self.initProxyModel()
60 self.initUi()
63 def initModel(self):
64 lst = getWindowList()
65 self._model = QStandardItemModel()
66 for text, wid in lst:
67 item = QStandardItem(unicode(text, "utf8"))
68 data = QVariant(QString(wid))
69 item.setData(data)
70 self._model.appendRow(item)
73 def initProxyModel(self):
74 self._proxyModel = QSortFilterProxyModel()
75 self._proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
76 self._proxyModel.setSourceModel(self._model)
79 def initUi(self):
80 frame = QFrame(self)
81 frame.setFrameStyle(QFrame.Box | QFrame.Plain)
82 layout = QVBoxLayout(self)
83 layout.setMargin(0)
84 layout.addWidget(frame)
86 # LineEdit
87 self._lineEdit = QLineEdit(frame)
88 QObject.connect(self._lineEdit, SIGNAL("textEdited(const QString&)"),
89 self.updateFilter)
90 QObject.connect(self._lineEdit, SIGNAL("returnPressed()"),
91 self.slotReturnPressed)
93 self._lineEdit.installEventFilter(self)
95 # View
96 self._view = ListView(frame)
97 self._view.setModel(self._proxyModel)
98 self._view.setEditTriggers(QAbstractItemView.NoEditTriggers)
99 QObject.connect(self._view, SIGNAL("activated(const QModelIndex&)"),
100 self.switchToWindow)
102 # Layout
103 layout = QVBoxLayout(frame)
104 layout.setMargin(6)
105 layout.addWidget(self._lineEdit)
106 layout.addWidget(self._view)
109 def updateFilter(self, text):
110 self._proxyModel.setFilterFixedString(text)
111 if not self._view.currentIndex().isValid():
112 firstIndex = self._proxyModel.index(0, 0)
113 if firstIndex.isValid():
114 self._view.setCurrentIndex(firstIndex)
117 def eventFilter(self, obj, event):
118 if event.type() != QEvent.KeyPress:
119 return False
121 if event.key() in (Qt.Key_Up, Qt.Key_Down):
122 newEvent = QKeyEvent(event.type(), event.key(), event.modifiers(), event.text())
123 QApplication.postEvent(self._view, newEvent)
124 return True
126 return False
129 def switchToWindow(self, index):
130 sourceIndex = self._proxyModel.mapToSource(index)
131 item = self._model.itemFromIndex(sourceIndex)
132 wid = item.data().toString()
133 switchToWindow(unicode(wid))
134 self.close()
137 def slotReturnPressed(self):
138 index = self._view.currentIndex()
139 if index.isValid():
140 self.switchToWindow(index)
141 else:
142 cmd = unicode(self._lineEdit.text())
143 os.spawnlp(os.P_NOWAIT, 'sh', 'sh', '-c', cmd)
144 self.close()
147 def main():
148 app = QApplication(sys.argv)
149 window = Window()
151 rect = QApplication.desktop().availableGeometry()
152 window.move( \
153 rect.left() + (rect.width() - window.sizeHint().width()) / 2, \
154 rect.top() + (rect.height() - window.sizeHint().height()) / 2 \
156 window.show()
157 app.exec_()
160 if __name__=="__main__":
161 main()