Audio/AudioControl: Allow muting mixer channels from config.py
[kwingrid.git] / kwingrid.cc
1 #include <iostream>
2
3 #include <kapplication.h>
4 #include <dcopclient.h>
5 #include <kwin.h>
6 #include <Xlib.h>
7 #include <Xutil.h>
8 #include <netwm_def.h>
9
10 #include "kwingrid.h"
11 #include "kwingrid.moc"
12
13 KWinGrid::KWinGrid(int hgap__, int vgap__, int hsplit__, int vsplit__, int split__)
14     : DCOPObject("grid"), split_(split__), 
15       hgap_(hgap__), vgap_(vgap__), hsplit_(hsplit__), vsplit_(vsplit__)
16 {
17     module_ = new KWinModule(KApplication::kApplication());
18     connect(module_,SIGNAL(activeWindowChanged(WId)),this,SLOT(activeWindowChanged(WId)));
19 }
20
21 void KWinGrid::move(int __xslot, int __yslot)
22 {
23     moveResize(__xslot, __yslot, -1, -1);
24 }
25
26 void KWinGrid::resize(int __xsize, int __ysize)
27 {
28     moveResize(-1,-1,__xsize,__ysize);
29 }
30
31 void KWinGrid::toDesk(int __desk)
32 {
33     int w = activeWindow();
34     if (w) 
35         KWin::setOnDesktop(w,__desk);
36 }
37
38 void KWinGrid::quit()
39 {
40     KApplication::kApplication()->quit();
41 }
42
43 int KWinGrid::activeWindow()
44 {
45     int av = module_->activeWindow();
46     KWin::WindowInfo info = KWin::windowInfo(av,NET::WMWindowType);
47     if (info.windowType(NET::AllTypesMask) == NET::Desktop) return 0;
48     return av;
49 }
50
51 void KWinGrid::updateTimestamp(void)
52 {
53     timestamp_ = QDateTime::currentDateTime();
54 }
55
56 void KWinGrid::activeWindowChanged(WId id)
57 {
58     if (!activeWindow_ || timestamp_.isNull())
59         return;
60
61     QDateTime tm = QDateTime::currentDateTime();
62
63     int deltaDays = timestamp_.date().daysTo(tm.date());
64     int deltaMSecs = timestamp_.time().msecsTo(tm.time());
65     
66     if (deltaDays>2 || deltaDays<0) {
67         activeWindow_ = 0;
68         return;
69     }
70     
71     deltaMSecs += deltaDays * 1000*(60*60*24);
72
73     if (deltaMSecs <= 300 && deltaMSecs > 0)
74         KWin::forceActiveWindow(activeWindow_);
75     else
76         activeWindow_ = 0;
77 }
78
79 void KWinGrid::moveResize(int __xslot, int __yslot,
80                           int __xsize, int __ysize)
81 {
82     initGeometry();
83     if (activeWindow_) {
84         QRect newGeometry = doMoveResize(__xslot,__yslot,__xsize,__ysize);
85         updateGeometry(newGeometry);
86         applyGeometry();
87     }
88 }
89
90 void KWinGrid::moveRelative(int __xdiff, int __ydiff)
91 {
92     initGeometry();
93     if (activeWindow_) {
94         int xSlot = (outer_.left()-region_.left()+hsize_/2)/hsize_;
95         int ySlot = (outer_.top()-region_.top()+vsize_/2)/vsize_;
96         xSlot += __xdiff;
97         ySlot += __ydiff;
98         if (xSlot<0) {
99             if (numScreens_ > 1 and screen_ > 0) {
100                 initGeometry(screen_-1);
101                 xSlot = hsplit_-1;
102                 ySlot = (outer_.top()-region_.top()+vsize_/2)/vsize_ + __ydiff;
103             } else 
104                 xSlot = 0;
105         } else if (xSlot >= hsplit_) {
106             if (numScreens_ > 1 and screen_ < numScreens_-1) {
107                 initGeometry(screen_+1);
108                 xSlot = 0;
109                 ySlot = (outer_.top()-region_.top()+vsize_/2)/vsize_ + __ydiff;
110             } else
111                 xSlot = hsplit_-1;
112         }
113         if (ySlot<0)
114             ySlot = 0;
115         else if (ySlot >= vsplit_)
116             ySlot = vsplit_-1;
117         QRect newGeometry = doMoveResize(xSlot,ySlot,-1,-1);
118         updateGeometry(newGeometry);
119         applyGeometry();
120     }
121 }
122
123 void KWinGrid::resizeRelative(int __xdiff, int __ydiff)
124 {
125     initGeometry();
126     if (activeWindow_) {
127         int xSize = (outer_.width()+hsize_/2)/hsize_;
128         int ySize = (outer_.height()+vsize_/2)/vsize_;
129         xSize += __xdiff;
130         ySize += __ydiff;
131         if (xSize<1)
132             xSize = 1;
133         if (xSize>hsplit_)
134             xSize = hsplit_;
135         if (ySize<1)
136             ySize = 1;
137         if (ySize>vsplit_)
138             ySize = vsplit_;
139         QRect newGeometry = doMoveResize(-1,-1,xSize,ySize);
140         updateGeometry(newGeometry);
141         applyGeometry();
142     }
143 }
144
145 QRect KWinGrid::doMoveResize(int __xslot, int __yslot,
146                              int __xsize, int __ysize)
147 {
148     QRect newGeometry(outer_);
149     
150     if (__xsize == -1) {
151         __xsize = (outer_.width()+hsize_/2)/hsize_;
152         if (__xsize<1) __xsize = 1;
153         if (__xsize>hsplit_) __xsize = hsplit_;
154     }
155     if (__ysize == -1) {
156         __ysize = (outer_.height()+vsize_/2)/vsize_;
157         if (__ysize<1) __ysize = 1;
158         if (__ysize>vsplit_) __ysize = vsplit_;
159     }
160     
161     newGeometry.setWidth(__xsize*hsize_-hgap_);
162     newGeometry.setHeight(__ysize*vsize_-vgap_);
163
164     if (__xslot == -1) {
165         __xslot = (outer_.left()-region_.left()+hsize_/2)/hsize_;
166         if (__xslot<0) __xslot = 0;
167         if (__xslot>=hsplit_) __xslot = hsplit_-1;
168     }
169     if (__yslot == -1) {
170         __yslot = (outer_.top()-region_.top()+vsize_/2)/vsize_;
171         if (__yslot<0) __yslot = 0;
172         if (__yslot>=vsplit_) __yslot = vsplit_-1;
173     }
174     newGeometry.moveTopLeft(QPoint(region_.left() + __xslot*hsize_ + hgap_/2,
175                                    region_.top() + __yslot*vsize_ + vgap_/2));
176     return newGeometry;
177 }
178
179 std::ostream& operator<<(std::ostream& os, QRect rect)
180 {
181     os << '(' << rect.width() << 'x' << rect.height() << '+' << rect.x() << '+' << rect.y() << ')';
182     return os;
183 }
184
185 std::ostream& operator<<(std::ostream& os, QPoint p)
186 {
187     os << '(' << p.x() << ',' << p.y() << ')';
188     return os;
189 }
190
191 std::ostream& operator<<(std::ostream& os, QSize s)
192 {
193     os << '(' << s.width() << 'x' << s.height() << ')';
194     return os;
195 }
196
197 void KWinGrid::initGeometry(int __forceScreen)
198 {
199     activeWindowChanged(0);
200     if (activeWindow_ == 0)
201         activeWindow_ = activeWindow();
202     if (activeWindow_) {
203         KWin::WindowInfo info(KWin::windowInfo(activeWindow_));
204         inner_ = info.geometry();
205         outer_ = info.frameGeometry();
206         orig_ = outer_;
207         if (split_) {
208             if (__forceScreen == -1)
209                 screen_ = outer_.left()>=split_ ? 1 : 0;
210             else
211                 screen_ = __forceScreen;
212             region_ = QApplication::desktop()->screenGeometry();
213             if (screen_ == 1)
214                 region_.setLeft(split_);
215             else
216                 region_.setRight(split_-1);
217             numScreens_ = 2;
218         } else {
219             if (__forceScreen == -1)
220                 screen_ = QApplication::desktop()->screenNumber(outer_.topLeft());
221             else
222                 screen_ = __forceScreen;
223             region_ = QApplication::desktop()->screenGeometry(screen_);
224             numScreens_ = QApplication::desktop()->numScreens();
225         }
226         QRect wa = module_->workArea();
227         region_ = region_ & wa;
228
229         hsize_ = (region_.width()-hgap_)/hsplit_;
230         vsize_ = (region_.height()-vgap_)/vsplit_;
231
232         int hdelta = region_.width()-hsize_*hsplit_;
233         int vdelta = region_.height()-vsize_*vsplit_;
234         QPoint topLeft(region_.topLeft());
235         topLeft+=QPoint(hdelta/2,vdelta/2);
236         region_.moveTopLeft(topLeft);
237         region_.setSize(QSize(hsize_*hsplit_,vsize_*vsplit_));
238     }
239 }
240
241 void KWinGrid::updateGeometry(QRect& __new)
242 {
243     QRect newInner(inner_);
244     newInner.moveTopLeft(QPoint(__new.left()+(inner_.left()-outer_.left()),
245                                 __new.top()+(inner_.top()-outer_.top())));
246     newInner.setSize(QSize(__new.width()-(outer_.width()-inner_.width()),
247                            __new.height()-(outer_.height()-inner_.height())));
248     inner_ = newInner;
249     outer_ = __new;
250
251     XSizeHints hints;
252     long supplied;
253     if (XGetWMNormalHints(KApplication::kApplication()->getDisplay(), 
254                           activeWindow_, &hints, &supplied)) {
255         hints.flags &= supplied;
256         if (hints.flags & PResizeInc && hints.width_inc != 0 && hints.height_inc != 0) {
257             QSize base(0,0);
258             if (hints.flags & PBaseSize) {
259                 base.setWidth(hints.base_width);
260                 base.setHeight(hints.base_height);
261             } else if (hints.flags & PMinSize) {
262                 base.setWidth(hints.min_width);
263                 base.setHeight(hints.min_height);
264             }
265             QSize newSize(((inner_.width()-base.width())/hints.width_inc)*hints.width_inc + base.width(),
266                           ((inner_.height()-base.height())/hints.height_inc)*hints.height_inc + base.height());
267             QSize delta(inner_.size() - newSize);
268             QPoint offset(delta.width()/2,delta.height()/2);
269             inner_.setSize(newSize);
270             outer_.setSize(outer_.size() - delta);
271             inner_.moveTopLeft(inner_.topLeft() + offset);
272             outer_.moveTopLeft(outer_.topLeft() + offset);
273         }
274     }
275 }
276
277 void KWinGrid::applyGeometry()
278 {
279     updateTimestamp();
280     if (orig_.topLeft() == outer_.topLeft())
281         // If the position of the window did not change,
282         // XMoveResizeWindow sometimes still moves the window a little
283         // bit. Seems to have something todo with window gravity
284         // ... we just leave the position allone in that case.
285         XResizeWindow(KApplication::kApplication()->getDisplay(),activeWindow_,
286                       inner_.width(),inner_.height());
287     else {
288         // I don't really know, whats all this stuff concerning window
289         // gravity. I only know, this works for my openoffice windows,
290         // which have StaticGravity. I have not found any window with
291         // a window_gravity of neither StaticGravity nor
292         // NorthWestGravity on my desktop so did not check other
293         // window gravities.
294         QPoint pos = outer_.topLeft();
295         XWindowAttributes winAttributes;
296         if (XGetWindowAttributes(KApplication::kApplication()->getDisplay(),activeWindow_, 
297                                  &winAttributes) && winAttributes.win_gravity == StaticGravity)
298             pos = inner_.topLeft();
299         XMoveResizeWindow(KApplication::kApplication()->getDisplay(),activeWindow_,
300                           pos.x(),pos.y(), inner_.width(),inner_.height());
301     }
302 }
303
304 // slots
305
306 void KWinGrid::move_TL()
307 {
308     move(0,0);
309 }
310
311 void KWinGrid::move_TR()
312 {
313     move(hsplit_/2,0);
314 }
315
316 void KWinGrid::move_BL()
317 {
318     move(0,vsplit_/2);
319 }
320
321 void KWinGrid::move_BR()
322 {
323     move(hsplit_/2,vsplit_/2);
324 }
325
326     
327 void KWinGrid::resize_Q()
328 {
329     resize(vsplit_/2,hsplit_/2);
330 }
331
332 void KWinGrid::resize_H()
333 {
334     resize(vsplit_,hsplit_/2);
335 }
336
337 void KWinGrid::resize_V()
338 {
339     resize(vsplit_/2,hsplit_);
340 }
341
342 void KWinGrid::resize_F()
343 {
344     resize(vsplit_,hsplit_);
345 }
346
347
348 void KWinGrid::move_L()
349 {
350     moveRelative(-1,0);
351 }
352
353 void KWinGrid::move_R()
354 {
355     moveRelative(1,0);
356 }
357
358 void KWinGrid::move_U()
359 {
360     moveRelative(0,-1);
361 }
362
363 void KWinGrid::move_D()
364 {
365     moveRelative(0,1);
366 }
367
368     
369 void KWinGrid::resize_IH()
370 {
371     resizeRelative(1,0);
372 }
373
374 void KWinGrid::resize_DH()
375 {
376     resizeRelative(-1,0);
377 }
378
379 void KWinGrid::resize_IV()
380 {
381     resizeRelative(0,1);
382 }
383
384 void KWinGrid::resize_DV()
385 {
386     resizeRelative(0,-1);
387 }
388