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