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