• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.2 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • windowmanagement
kwindowsystem_x11.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the KDE libraries
3  Copyright (C) 1999 Matthias Ettrich (ettrich@kde.org)
4  Copyright (C) 2007 Lubos Lunak (l.lunak@kde.org)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "kwindowsystem.h"
23 
24 #include <kiconloader.h>
25 #include <klocale.h>
26 #include <kdebug.h>
27 #include <ksystemeventfilter.h>
28 #include <kxerrorhandler.h>
29 #include <kxutils.h>
30 #include <netwm.h>
31 #include <QtGui/QApplication>
32 #include <QtGui/QBitmap>
33 #include <QDesktopWidget>
34 #include <QtGui/QDialog>
35 #include <QtDBus/QtDBus>
36 #include <QtGui/QX11Info>
37 #include <X11/Xatom.h>
38 
39 #include <config.h>
40 
41 #ifdef HAVE_XFIXES
42 #include <X11/extensions/Xfixes.h>
43 #endif
44 
45 class KWindowSystemStaticContainer {
46 public:
47  KWindowSystemStaticContainer() : d(0) {}
48  KWindowSystem kwm;
49  KWindowSystemPrivate* d;
50 };
51 
52 
53 K_GLOBAL_STATIC(KWindowSystemStaticContainer, g_kwmInstanceContainer)
54 
55 static Atom net_wm_cm;
56 static void create_atoms( Display* dpy = QX11Info::display() );
57 
58 static unsigned long windows_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
59  NET::Supported |
60  NET::NumberOfDesktops |
61  NET::DesktopGeometry |
62  NET::DesktopViewport |
63  NET::CurrentDesktop |
64  NET::DesktopNames |
65  NET::ActiveWindow |
66  NET::WorkArea,
67  NET::WM2ShowingDesktop };
68 
69 // ClientList and ClientListStacking is not per-window information, but a desktop information,
70 // so track it even with only INFO_BASIC
71 static unsigned long desktop_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking |
72  NET::Supported |
73  NET::NumberOfDesktops |
74  NET::DesktopGeometry |
75  NET::DesktopViewport |
76  NET::CurrentDesktop |
77  NET::DesktopNames |
78  NET::ActiveWindow |
79  NET::WorkArea,
80  NET::WM2ShowingDesktop };
81 
82 class KWindowSystemPrivate
83  : public QWidget, public NETRootInfo
84 {
85 public:
86  KWindowSystemPrivate(int _what);
87  void activate();
88  QList<WId> windows;
89  QList<WId> stackingOrder;
90 
91  struct StrutData
92  {
93  StrutData( WId window_, const NETStrut& strut_, int desktop_ )
94  : window( window_ ), strut( strut_ ), desktop( desktop_ ) {}
95  StrutData() {} // for QValueList to be happy
96  WId window;
97  NETStrut strut;
98  int desktop;
99  };
100  QList<StrutData> strutWindows;
101  QList<WId> possibleStrutWindows;
102  bool strutSignalConnected;
103  bool compositingEnabled;
104  bool haveXfixes;
105  int what;
106  int xfixesEventBase;
107  bool mapViewport();
108 
109  void addClient(Window);
110  void removeClient(Window);
111 
112  bool x11Event( XEvent * ev );
113 
114  void updateStackingOrder();
115  bool removeStrutWindow( WId );
116 };
117 
118 KWindowSystemPrivate::KWindowSystemPrivate(int _what)
119  : QWidget(0),
120  NETRootInfo( QX11Info::display(),
121  _what >= KWindowSystem::INFO_WINDOWS ? windows_properties : desktop_properties,
122  2, -1, false ),
123  strutSignalConnected( false ),
124  haveXfixes( false ),
125  what( _what )
126 {
127  KSystemEventFilter::installEventFilter(this);
128  (void ) qApp->desktop(); //trigger desktop widget creation to select root window events
129 
130 #ifdef HAVE_XFIXES
131  int errorBase;
132  if ((haveXfixes = XFixesQueryExtension(QX11Info::display(), &xfixesEventBase, &errorBase))) {
133  create_atoms();
134  XFixesSelectSelectionInput(QX11Info::display(), winId(), net_wm_cm,
135  XFixesSetSelectionOwnerNotifyMask |
136  XFixesSelectionWindowDestroyNotifyMask |
137  XFixesSelectionClientCloseNotifyMask);
138  compositingEnabled = XGetSelectionOwner(QX11Info::display(), net_wm_cm) != None;
139  }
140 #endif
141 }
142 
143 // not virtual, but it's called directly only from init()
144 void KWindowSystemPrivate::activate()
145 {
146  NETRootInfo::activate();
147  updateStackingOrder();
148 }
149 
150 bool KWindowSystemPrivate::x11Event( XEvent * ev )
151 {
152  KWindowSystem* s_q = KWindowSystem::self();
153 
154 #ifdef HAVE_XFIXES
155  if ( ev->type == xfixesEventBase + XFixesSelectionNotify && ev->xany.window == winId() ) {
156  XFixesSelectionNotifyEvent *event = reinterpret_cast<XFixesSelectionNotifyEvent*>(ev);
157  bool haveOwner = event->owner != None;
158  if (compositingEnabled != haveOwner) {
159  compositingEnabled = haveOwner;
160  emit s_q->compositingChanged( compositingEnabled );
161  }
162  return true;
163  }
164 #endif
165 
166  if ( ev->xany.window == QX11Info::appRootWindow() ) {
167  int old_current_desktop = currentDesktop();
168  WId old_active_window = activeWindow();
169  int old_number_of_desktops = numberOfDesktops();
170  bool old_showing_desktop = showingDesktop();
171  unsigned long m[ 5 ];
172  NETRootInfo::event( ev, m, 5 );
173 
174  if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
175  emit s_q->currentDesktopChanged( currentDesktop() );
176  if (( m[ PROTOCOLS ] & DesktopViewport ) && mapViewport() && currentDesktop() != old_current_desktop )
177  emit s_q->currentDesktopChanged( currentDesktop() );
178  if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
179  emit s_q->activeWindowChanged( activeWindow() );
180  if ( m[ PROTOCOLS ] & DesktopNames )
181  emit s_q->desktopNamesChanged();
182  if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
183  emit s_q->numberOfDesktopsChanged( numberOfDesktops() );
184  if (( m[ PROTOCOLS ] & DesktopGeometry ) && mapViewport() && numberOfDesktops() != old_number_of_desktops )
185  emit s_q->numberOfDesktopsChanged( numberOfDesktops() );
186  if ( m[ PROTOCOLS ] & WorkArea )
187  emit s_q->workAreaChanged();
188  if ( m[ PROTOCOLS ] & ClientListStacking ) {
189  updateStackingOrder();
190  emit s_q->stackingOrderChanged();
191  }
192  if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
193  emit s_q->showingDesktopChanged( showingDesktop());
194  }
195  } else if ( windows.contains( ev->xany.window ) ){
196  NETWinInfo ni( QX11Info::display(), ev->xany.window, QX11Info::appRootWindow(), 0 );
197  unsigned long dirty[ 2 ];
198  ni.event( ev, dirty, 2 );
199  if ( ev->type ==PropertyNotify ) {
200  if( ev->xproperty.atom == XA_WM_HINTS )
201  dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIcon; // support for old icons
202  else if( ev->xproperty.atom == XA_WM_NAME )
203  dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMName; // support for old name
204  else if( ev->xproperty.atom == XA_WM_ICON_NAME )
205  dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMIconName; // support for old iconic name
206  }
207  if( mapViewport() && ( dirty[ NETWinInfo::PROTOCOLS ] & (NET::WMState | NET::WMGeometry) )) {
208  /* geometry change -> possible viewport change
209  * state change -> possible NET::Sticky change
210  */
211  dirty[ NETWinInfo::PROTOCOLS ] |= NET::WMDesktop;
212  }
213  if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 ) {
214  removeStrutWindow( ev->xany.window );
215  if ( !possibleStrutWindows.contains( ev->xany.window ) )
216  possibleStrutWindows.append( ev->xany.window );
217  }
218  if ( dirty[ NETWinInfo::PROTOCOLS ] || dirty[ NETWinInfo::PROTOCOLS2 ] ) {
219  emit s_q->windowChanged( ev->xany.window );
220  emit s_q->windowChanged( ev->xany.window, dirty );
221  emit s_q->windowChanged( ev->xany.window, dirty[ NETWinInfo::PROTOCOLS ] );
222  if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
223  emit s_q->strutChanged();
224  }
225  }
226 
227  return false;
228 }
229 
230 bool KWindowSystemPrivate::removeStrutWindow( WId w )
231 {
232  for( QList< StrutData >::Iterator it = strutWindows.begin();
233  it != strutWindows.end();
234  ++it )
235  if( (*it).window == w ) {
236  strutWindows.erase( it );
237  return true;
238  }
239  return false;
240 }
241 
242 void KWindowSystemPrivate::updateStackingOrder()
243 {
244  stackingOrder.clear();
245  for ( int i = 0; i < clientListStackingCount(); i++ )
246  stackingOrder.append( clientListStacking()[i] );
247 }
248 
249 void KWindowSystemPrivate::addClient(Window w)
250 {
251  KWindowSystem* s_q = KWindowSystem::self();
252 
253  if ( (what >= KWindowSystem::INFO_WINDOWS) && !QWidget::find( w ) )
254  XSelectInput( QX11Info::display(), w, PropertyChangeMask | StructureNotifyMask );
255 
256  bool emit_strutChanged = false;
257 
258  if( strutSignalConnected ) {
259  NETWinInfo info( QX11Info::display(), w, QX11Info::appRootWindow(), NET::WMStrut | NET::WMDesktop );
260  NETStrut strut = info.strut();
261  if ( strut.left || strut.top || strut.right || strut.bottom ) {
262  strutWindows.append( StrutData( w, strut, info.desktop()));
263  emit_strutChanged = true;
264  }
265  } else
266  possibleStrutWindows.append( w );
267 
268  windows.append( w );
269  emit s_q->windowAdded( w );
270  if ( emit_strutChanged )
271  emit s_q->strutChanged();
272 }
273 
274 void KWindowSystemPrivate::removeClient(Window w)
275 {
276  KWindowSystem* s_q = KWindowSystem::self();
277 
278  bool emit_strutChanged = removeStrutWindow( w );
279  if( strutSignalConnected && possibleStrutWindows.contains( w )) {
280  NETWinInfo info( QX11Info::display(), w, QX11Info::appRootWindow(), NET::WMStrut );
281  NETStrut strut = info.strut();
282  if ( strut.left || strut.top || strut.right || strut.bottom ) {
283  emit_strutChanged = true;
284  }
285  }
286 
287  possibleStrutWindows.removeAll( w );
288  windows.removeAll( w );
289  emit s_q->windowRemoved( w );
290  if ( emit_strutChanged )
291  emit s_q->strutChanged();
292 }
293 
294 bool KWindowSystemPrivate::mapViewport()
295 {
296 // compiz claims support even though it doesn't use virtual desktops :(
297 // if( isSupported( NET::DesktopViewport ) && !isSupported( NET::NumberOfDesktops ))
298 
299 // this test is duplicated in KWindowSystem::mapViewport()
300  if( isSupported( NET::DesktopViewport ) && numberOfDesktops( true ) <= 1
301  && ( desktopGeometry( currentDesktop( true )).width > QApplication::desktop()->width()
302  || desktopGeometry( currentDesktop( true )).height > QApplication::desktop()->height()))
303  return true;
304  return false;
305 }
306 
307 static bool atoms_created = false;
308 
309 static Atom kde_wm_change_state;
310 static Atom _wm_protocols;
311 static Atom kwm_utf8_string;
312 
313 static void create_atoms( Display* dpy ) {
314  if (!atoms_created){
315  const int max = 20;
316  Atom* atoms[max];
317  const char* names[max];
318  Atom atoms_return[max];
319  int n = 0;
320 
321  atoms[n] = &kde_wm_change_state;
322  names[n++] = "_KDE_WM_CHANGE_STATE";
323 
324  atoms[n] = &_wm_protocols;
325  names[n++] = "WM_PROTOCOLS";
326 
327  atoms[n] = &kwm_utf8_string;
328  names[n++] = "UTF8_STRING";
329 
330  char net_wm_cm_name[ 100 ];
331  sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( dpy ));
332  atoms[n] = &net_wm_cm;
333  names[n++] = net_wm_cm_name;
334 
335  // we need a const_cast for the shitty X API
336  XInternAtoms( dpy, const_cast<char**>(names), n, false, atoms_return );
337  for (int i = 0; i < n; i++ )
338  *atoms[i] = atoms_return[i];
339 
340  atoms_created = True;
341  }
342 }
343 
344 static void sendClientMessageToRoot(Window w, Atom a, long x, long y = 0, long z = 0 ){
345  XEvent ev;
346  long mask;
347 
348  memset(&ev, 0, sizeof(ev));
349  ev.xclient.type = ClientMessage;
350  ev.xclient.window = w;
351  ev.xclient.message_type = a;
352  ev.xclient.format = 32;
353  ev.xclient.data.l[0] = x;
354  ev.xclient.data.l[1] = y;
355  ev.xclient.data.l[2] = z;
356  mask = SubstructureRedirectMask;
357  XSendEvent(QX11Info::display(), QX11Info::appRootWindow(), False, mask, &ev);
358 }
359 
360 KWindowSystem* KWindowSystem::self()
361 {
362  return &(g_kwmInstanceContainer->kwm);
363 }
364 
365 
366 KWindowSystemPrivate* KWindowSystem::s_d_func()
367 {
368  return g_kwmInstanceContainer->d;
369 }
370 
371 
372 // optimalization - create KWindowSystemPrivate only when needed and only for what is needed
373 void KWindowSystem::connectNotify( const char* signal )
374 {
375  int what = INFO_BASIC;
376  if( QLatin1String( signal ) == SIGNAL(workAreaChanged()))
377  what = INFO_WINDOWS;
378  else if( QLatin1String( signal ) == SIGNAL(strutChanged()))
379  what = INFO_WINDOWS;
380  else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(windowChanged(WId,const ulong*))).constData())
381  what = INFO_WINDOWS;
382  else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(windowChanged(WId,uint))).constData())
383  what = INFO_WINDOWS;
384  else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(windowChanged(WId))).constData())
385  what = INFO_WINDOWS;
386 
387  init( what );
388  KWindowSystemPrivate* const s_d = s_d_func();
389  if( !s_d->strutSignalConnected && qstrcmp( signal, SIGNAL(strutChanged())) == 0 )
390  s_d->strutSignalConnected = true;
391 
392  QObject::connectNotify( signal );
393 }
394 
395 // WARNING
396 // you have to call s_d_func() again after calling this function if you want a valid pointer!
397 void KWindowSystem::init(int what)
398 {
399  KWindowSystemPrivate* const s_d = s_d_func();
400 
401  if (what >= INFO_WINDOWS)
402  what = INFO_WINDOWS;
403  else
404  what = INFO_BASIC;
405 
406  if ( !s_d )
407  {
408  g_kwmInstanceContainer->d = new KWindowSystemPrivate(what); // invalidates s_d
409  g_kwmInstanceContainer->d->activate();
410  }
411  else if (s_d->what < what)
412  {
413  delete s_d;
414  g_kwmInstanceContainer->d = new KWindowSystemPrivate(what); // invalidates s_d
415  g_kwmInstanceContainer->d->activate();
416  }
417 }
418 
419 const QList<WId>& KWindowSystem::windows()
420 {
421  init( INFO_BASIC );
422  return s_d_func()->windows;
423 }
424 
425 KWindowInfo KWindowSystem::windowInfo( WId win, unsigned long properties, unsigned long properties2 )
426 {
427  return KWindowInfo( win, properties, properties2 );
428 }
429 
430 bool KWindowSystem::hasWId(WId w)
431 {
432  init( INFO_BASIC );
433  return s_d_func()->windows.contains( w );
434 }
435 
436 QList<WId> KWindowSystem::stackingOrder()
437 {
438  init( INFO_BASIC );
439  return s_d_func()->stackingOrder;
440 }
441 
442 int KWindowSystem::currentDesktop()
443 {
444  if (!QX11Info::display())
445  return 1;
446 
447  if( mapViewport()) {
448  init( INFO_BASIC );
449  KWindowSystemPrivate* const s_d = s_d_func();
450  NETPoint p = s_d->desktopViewport( s_d->currentDesktop( true ));
451  return viewportToDesktop( QPoint( p.x, p.y ));
452  }
453 
454  KWindowSystemPrivate* const s_d = s_d_func();
455  if( s_d )
456  return s_d->currentDesktop( true );
457  NETRootInfo info( QX11Info::display(), NET::CurrentDesktop );
458  return info.currentDesktop( true );
459 }
460 
461 int KWindowSystem::numberOfDesktops()
462 {
463  if (!QX11Info::display())
464  return 1;
465 
466  if( mapViewport()) {
467  init( INFO_BASIC );
468  KWindowSystemPrivate* const s_d = s_d_func();
469  NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
470  return s.width / qApp->desktop()->width() * s.height / qApp->desktop()->height();
471  }
472 
473  KWindowSystemPrivate* const s_d = s_d_func();
474  if( s_d )
475  return s_d->numberOfDesktops( true );
476  NETRootInfo info( QX11Info::display(), NET::NumberOfDesktops );
477  return info.numberOfDesktops( true );
478 }
479 
480 void KWindowSystem::setCurrentDesktop( int desktop )
481 {
482  if( mapViewport()) {
483  init( INFO_BASIC );
484  KWindowSystemPrivate* const s_d = s_d_func();
485  NETRootInfo info( QX11Info::display(), 0 );
486  QPoint pos = desktopToViewport( desktop, true );
487  NETPoint p;
488  p.x = pos.x();
489  p.y = pos.y();
490  info.setDesktopViewport( s_d->currentDesktop( true ), p );
491  return;
492  }
493  NETRootInfo info( QX11Info::display(), 0 );
494  info.setCurrentDesktop( desktop, true );
495 }
496 
497 void KWindowSystem::setOnAllDesktops( WId win, bool b )
498 {
499  if( mapViewport()) {
500  if( b )
501  setState( win, NET::Sticky );
502  else
503  clearState( win, NET::Sticky );
504  return;
505  }
506  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMDesktop );
507  if ( b )
508  info.setDesktop( NETWinInfo::OnAllDesktops, true );
509  else if ( info.desktop( true ) == NETWinInfo::OnAllDesktops ) {
510  NETRootInfo rinfo( QX11Info::display(), NET::CurrentDesktop );
511  info.setDesktop( rinfo.currentDesktop( true ), true );
512  }
513 }
514 
515 void KWindowSystem::setOnDesktop( WId win, int desktop )
516 {
517  if( mapViewport()) {
518  if( desktop == NET::OnAllDesktops )
519  return setOnAllDesktops( win, true );
520  else
521  clearState( win, NET::Sticky );
522  init( INFO_BASIC );
523  QPoint p = desktopToViewport( desktop, false );
524  Window dummy;
525  int x, y;
526  unsigned int w, h, b, dp;
527  XGetGeometry( QX11Info::display(), win, &dummy, &x, &y, &w, &h, &b, &dp );
528  // get global position
529  XTranslateCoordinates( QX11Info::display(), win, QX11Info::appRootWindow(), 0, 0, &x, &y, &dummy );
530  x += w / 2; // center
531  y += h / 2;
532  // transform to coordinates on the current "desktop"
533  x = x % qApp->desktop()->width();
534  y = y % qApp->desktop()->height();
535  if( x < 0 )
536  x = x + qApp->desktop()->width();
537  if( y < 0 )
538  y = y + qApp->desktop()->height();
539  x += p.x(); // move to given "desktop"
540  y += p.y();
541  x -= w / 2; // from center back to topleft
542  y -= h / 2;
543  p = constrainViewportRelativePosition( QPoint( x, y ));
544  int flags = ( NET::FromTool << 12 ) | ( 0x03 << 8 ) | 10; // from tool(?), x/y, static gravity
545  KWindowSystemPrivate* const s_d = s_d_func();
546  s_d->moveResizeWindowRequest( win, flags, p.x(), p.y(), w, h );
547  return;
548  }
549  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMDesktop );
550  info.setDesktop( desktop, true );
551 }
552 
553 WId KWindowSystem::activeWindow()
554 {
555  KWindowSystemPrivate* const s_d = s_d_func();
556  if( s_d )
557  return s_d->activeWindow();
558  NETRootInfo info( QX11Info::display(), NET::ActiveWindow );
559  return info.activeWindow();
560 }
561 
562 void KWindowSystem::activateWindow( WId win, long time )
563 {
564  NETRootInfo info( QX11Info::display(), 0 );
565  if( time == 0 )
566  time = QX11Info::appUserTime();
567  info.setActiveWindow( win, NET::FromApplication, time,
568  qApp->activeWindow() ? qApp->activeWindow()->winId() : 0 );
569 }
570 
571 void KWindowSystem::forceActiveWindow( WId win, long time )
572 {
573  NETRootInfo info( QX11Info::display(), 0 );
574  if( time == 0 )
575  time = QX11Info::appTime();
576  info.setActiveWindow( win, NET::FromTool, time, 0 );
577 }
578 
579 void KWindowSystem::demandAttention( WId win, bool set )
580 {
581  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMState );
582  info.setState( set ? NET::DemandsAttention : 0, NET::DemandsAttention );
583 }
584 
585 WId KWindowSystem::transientFor( WId win )
586 {
587  KXErrorHandler handler; // ignore badwindow
588  Window transient_for = None;
589  if( XGetTransientForHint( QX11Info::display(), win, &transient_for ))
590  return transient_for;
591  // XGetTransientForHint() did sync
592  return None;
593 }
594 
595 void KWindowSystem::setMainWindow( QWidget* subwindow, WId mainwindow )
596 {
597  subwindow->setAttribute( Qt::WA_X11BypassTransientForHint );
598  if( mainwindow != 0 )
599  XSetTransientForHint( QX11Info::display(), subwindow->winId(), mainwindow );
600  else
601  XDeleteProperty( QX11Info::display(), subwindow->winId(), XA_WM_TRANSIENT_FOR );
602 }
603 
604 WId KWindowSystem::groupLeader( WId win )
605 {
606  KXErrorHandler handler; // ignore badwindow
607  XWMHints *hints = XGetWMHints( QX11Info::display(), win );
608  Window window_group = None;
609  if ( hints )
610  {
611  if( hints->flags & WindowGroupHint )
612  window_group = hints->window_group;
613  XFree( reinterpret_cast< char* >( hints ));
614  }
615  // XGetWMHints() did sync
616  return window_group;
617 }
618 
619 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale )
620 {
621  return icon( win, width, height, scale, NETWM | WMHints | ClassHint | XApp );
622 }
623 
624 
625 QPixmap KWindowSystem::icon( WId win, int width, int height, bool scale, int flags )
626 {
627  KXErrorHandler handler; // ignore badwindow
628  QPixmap result;
629  if( flags & NETWM ) {
630  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMIcon );
631  NETIcon ni = info.icon( width, height );
632  if ( ni.data && ni.size.width > 0 && ni.size.height > 0 ) {
633  QImage img( (uchar*) ni.data, (int) ni.size.width, (int) ni.size.height, QImage::Format_ARGB32 );
634  if ( scale && width > 0 && height > 0 &&img.size() != QSize( width, height ) && !img.isNull() )
635  img = img.scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
636  if ( !img.isNull() )
637  result = QPixmap::fromImage( img );
638  return result;
639  }
640  }
641 
642  if( flags & WMHints ) {
643  Pixmap p = None;
644  Pixmap p_mask = None;
645 
646  XWMHints *hints = XGetWMHints(QX11Info::display(), win );
647  if (hints && (hints->flags & IconPixmapHint)){
648  p = hints->icon_pixmap;
649  }
650  if (hints && (hints->flags & IconMaskHint)){
651  p_mask = hints->icon_mask;
652  }
653  if (hints)
654  XFree((char*)hints);
655 
656  if (p != None){
657  QPixmap pm = KXUtils::createPixmapFromHandle( p, p_mask );
658  if ( scale && width > 0 && height > 0 && !pm.isNull()
659  && ( pm.width() != width || pm.height() != height) ){
660  result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
661  } else {
662  result = pm;
663  }
664  }
665  }
666 
667  // Since width can be any arbitrary size, but the icons cannot,
668  // take the nearest value for best results (ignoring 22 pixel
669  // icons as they don't exist for apps):
670  int iconWidth;
671  if( width < 24 )
672  iconWidth = 16;
673  else if( width < 40 )
674  iconWidth = 32;
675  else
676  iconWidth = 48;
677 
678  if( flags & ClassHint ) {
679  // Try to load the icon from the classhint if the app didn't specify
680  // its own:
681  if( result.isNull() ) {
682 
683  XClassHint hint;
684  if( XGetClassHint( QX11Info::display(), win, &hint ) ) {
685  QString className = hint.res_class;
686 
687  QPixmap pm = KIconLoader::global()->loadIcon( className.toLower(), KIconLoader::Small, iconWidth,
688  KIconLoader::DefaultState, QStringList(), 0, true );
689  if( scale && !pm.isNull() )
690  result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
691  else
692  result = pm;
693 
694  XFree( hint.res_name );
695  XFree( hint.res_class );
696  }
697  }
698  }
699 
700  if( flags & XApp ) {
701  // If the icon is still a null pixmap, load the icon for X applications
702  // as a last resort:
703  if ( result.isNull() ) {
704  QPixmap pm = KIconLoader::global()->loadIcon( "xorg", KIconLoader::Small, iconWidth,
705  KIconLoader::DefaultState, QStringList(), 0, true );
706  if( scale && !pm.isNull() )
707  result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
708  else
709  result = pm;
710  }
711  }
712  return result;
713 }
714 
715 void KWindowSystem::setIcons( WId win, const QPixmap& icon, const QPixmap& miniIcon )
716 {
717  if ( icon.isNull() )
718  return;
719  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
720  QImage img = icon.toImage().convertToFormat( QImage::Format_ARGB32 );
721  NETIcon ni;
722  ni.size.width = img.size().width();
723  ni.size.height = img.size().height();
724  ni.data = (unsigned char *) img.bits();
725  info.setIcon( ni, true );
726  if ( miniIcon.isNull() )
727  return;
728  img = miniIcon.toImage().convertToFormat( QImage::Format_ARGB32 );
729  if ( img.isNull() )
730  return;
731  ni.size.width = img.size().width();
732  ni.size.height = img.size().height();
733  ni.data = (unsigned char *) img.bits();
734  info.setIcon( ni, false );
735 }
736 
737 void KWindowSystem::setType( WId win, NET::WindowType windowType )
738 {
739  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
740  info.setWindowType( windowType );
741 }
742 
743 void KWindowSystem::setState( WId win, unsigned long state )
744 {
745  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMState );
746  info.setState( state, state );
747 }
748 
749 void KWindowSystem::clearState( WId win, unsigned long state )
750 {
751  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), NET::WMState );
752  info.setState( 0, state );
753 }
754 
755 void KWindowSystem::minimizeWindow( WId win, bool animation)
756 {
757  if ( !animation )
758  {
759  create_atoms();
760  sendClientMessageToRoot( win, kde_wm_change_state, IconicState, 1 );
761  }
762  QX11Info inf;
763  XIconifyWindow( QX11Info::display(), win, inf.screen() );
764 }
765 
766 void KWindowSystem::unminimizeWindow( WId win, bool animation )
767 {
768  if ( !animation )
769  {
770  create_atoms();
771  sendClientMessageToRoot( win, kde_wm_change_state, NormalState, 1 );
772  }
773  XMapWindow( QX11Info::display(), win );
774 }
775 
776 void KWindowSystem::raiseWindow( WId win )
777 {
778  NETRootInfo info( QX11Info::display(), NET::Supported );
779  if( info.isSupported( NET::WM2RestackWindow ))
780  info.restackRequest( win, NET::FromTool, None, Above, QX11Info::appUserTime());
781  else
782  XRaiseWindow( QX11Info::display(), win );
783 }
784 
785 void KWindowSystem::lowerWindow( WId win )
786 {
787  NETRootInfo info( QX11Info::display(), NET::Supported );
788  if( info.isSupported( NET::WM2RestackWindow ))
789  info.restackRequest( win, NET::FromTool, None, Below, QX11Info::appUserTime());
790  else
791  XLowerWindow( QX11Info::display(), win );
792 }
793 
794 bool KWindowSystem::compositingActive()
795 {
796  if( QX11Info::display()) {
797  init( INFO_BASIC );
798  if (s_d_func()->haveXfixes) {
799  return s_d_func()->compositingEnabled;
800  } else {
801  create_atoms();
802  return XGetSelectionOwner( QX11Info::display(), net_wm_cm );
803  }
804  } else { // work even without QApplication instance
805  Display* dpy = XOpenDisplay( NULL );
806  create_atoms( dpy );
807  bool ret = XGetSelectionOwner( dpy, net_wm_cm ) != None;
808  XCloseDisplay( dpy );
809  return ret;
810  }
811 }
812 
813 QRect KWindowSystem::workArea( int desktop )
814 {
815  init( INFO_BASIC );
816  int desk = (desktop > 0 && desktop <= (int) s_d_func()->numberOfDesktops() ) ? desktop : currentDesktop();
817  if ( desk <= 0 )
818  return QApplication::desktop()->geometry();
819 
820  NETRect r = s_d_func()->workArea( desk );
821  if( r.size.width <= 0 || r.size.height <= 0 ) // not set
822  return QApplication::desktop()->geometry();
823 
824  return QRect( r.pos.x, r.pos.y, r.size.width, r.size.height );
825 }
826 
827 QRect KWindowSystem::workArea( const QList<WId>& exclude, int desktop )
828 {
829  init( INFO_WINDOWS ); // invalidates s_d_func's return value
830  KWindowSystemPrivate* const s_d = s_d_func();
831 
832  QRect all = QApplication::desktop()->geometry();
833  QRect a = all;
834 
835  if (desktop == -1)
836  desktop = s_d->currentDesktop();
837 
838  QList<WId>::ConstIterator it1;
839  for( it1 = s_d->windows.constBegin(); it1 != s_d->windows.constEnd(); ++it1 ) {
840 
841  if(exclude.contains(*it1))
842  continue;
843 
844 // Kicker (very) extensively calls this function, causing hundreds of roundtrips just
845 // to repeatedly find out struts of all windows. Therefore strut values for strut
846 // windows are cached here.
847  NETStrut strut;
848  QList< KWindowSystemPrivate::StrutData >::Iterator it2 = s_d->strutWindows.begin();
849  for( ; it2 != s_d->strutWindows.end(); ++it2 )
850  if( (*it2).window == *it1 )
851  break;
852 
853  if( it2 != s_d->strutWindows.end()) {
854  if(!((*it2).desktop == desktop || (*it2).desktop == NETWinInfo::OnAllDesktops ))
855  continue;
856 
857  strut = (*it2).strut;
858  } else if( s_d->possibleStrutWindows.contains( *it1 ) ) {
859 
860  NETWinInfo info( QX11Info::display(), (*it1), QX11Info::appRootWindow(), NET::WMStrut | NET::WMDesktop);
861  strut = info.strut();
862  s_d->possibleStrutWindows.removeAll( *it1 );
863  s_d->strutWindows.append( KWindowSystemPrivate::StrutData( *it1, info.strut(), info.desktop()));
864 
865  if( !(info.desktop() == desktop || info.desktop() == NETWinInfo::OnAllDesktops) )
866  continue;
867  } else
868  continue; // not a strut window
869 
870  QRect r = all;
871  if ( strut.left > 0 )
872  r.setLeft( r.left() + (int) strut.left );
873  if ( strut.top > 0 )
874  r.setTop( r.top() + (int) strut.top );
875  if ( strut.right > 0 )
876  r.setRight( r.right() - (int) strut.right );
877  if ( strut.bottom > 0 )
878  r.setBottom( r.bottom() - (int) strut.bottom );
879 
880  a = a.intersect(r);
881  }
882  return a;
883 }
884 
885 QString KWindowSystem::desktopName( int desktop )
886 {
887  init( INFO_BASIC );
888  KWindowSystemPrivate* const s_d = s_d_func();
889 
890  bool isDesktopSane = (desktop > 0 && desktop <= (int) s_d->numberOfDesktops());
891  const char* name = s_d->desktopName( isDesktopSane ? desktop : currentDesktop() );
892 
893  if ( name && name[0] )
894  return QString::fromUtf8( name );
895 
896  return i18n("Desktop %1", desktop );
897 }
898 
899 void KWindowSystem::setDesktopName( int desktop, const QString& name )
900 {
901  KWindowSystemPrivate* const s_d = s_d_func();
902 
903  if (desktop <= 0 || desktop > (int) numberOfDesktops() )
904  desktop = currentDesktop();
905 
906  if( s_d ) {
907  s_d->setDesktopName( desktop, name.toUtf8().constData() );
908  return;
909  }
910 
911  NETRootInfo info( QX11Info::display(), 0 );
912  info.setDesktopName( desktop, name.toUtf8().constData() );
913 }
914 
915 bool KWindowSystem::showingDesktop()
916 {
917  init( INFO_BASIC );
918  return s_d_func()->showingDesktop();
919 }
920 
921 void KWindowSystem::setUserTime( WId win, long time )
922 {
923  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
924  info.setUserTime( time );
925 }
926 
927 void KWindowSystem::setExtendedStrut( WId win, int left_width, int left_start, int left_end,
928  int right_width, int right_start, int right_end, int top_width, int top_start, int top_end,
929  int bottom_width, int bottom_start, int bottom_end )
930 {
931  NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
932  NETExtendedStrut strut;
933  strut.left_width = left_width;
934  strut.right_width = right_width;
935  strut.top_width = top_width;
936  strut.bottom_width = bottom_width;
937  strut.left_start = left_start;
938  strut.left_end = left_end;
939  strut.right_start = right_start;
940  strut.right_end = right_end;
941  strut.top_start = top_start;
942  strut.top_end = top_end;
943  strut.bottom_start = bottom_start;
944  strut.bottom_end = bottom_end;
945  info.setExtendedStrut( strut );
946  NETStrut oldstrut;
947  oldstrut.left = left_width;
948  oldstrut.right = right_width;
949  oldstrut.top = top_width;
950  oldstrut.bottom = bottom_width;
951  info.setStrut( oldstrut );
952 }
953 
954 void KWindowSystem::setStrut( WId win, int left, int right, int top, int bottom )
955 {
956  int w = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display()));
957  int h = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display()));
958  setExtendedStrut( win, left, 0, left != 0 ? w : 0, right, 0, right != 0 ? w : 0,
959  top, 0, top != 0 ? h : 0, bottom, 0, bottom != 0 ? h : 0 );
960 }
961 
962 bool KWindowSystem::icccmCompliantMappingState()
963 {
964  static enum { noidea, yes, no } wm_is_1_2_compliant = noidea;
965  if( wm_is_1_2_compliant == noidea ) {
966  NETRootInfo info( QX11Info::display(), NET::Supported );
967  wm_is_1_2_compliant = info.isSupported( NET::Hidden ) ? yes : no;
968  }
969  return wm_is_1_2_compliant == yes;
970 }
971 
972 bool KWindowSystem::allowedActionsSupported()
973 {
974  static enum { noidea, yes, no } wm_supports_allowed_actions = noidea;
975  if( wm_supports_allowed_actions == noidea ) {
976  NETRootInfo info( QX11Info::display(), NET::Supported );
977  wm_supports_allowed_actions = info.isSupported( NET::WM2AllowedActions ) ? yes : no;
978  }
979  return wm_supports_allowed_actions == yes;
980 }
981 
982 QString KWindowSystem::readNameProperty( WId win, unsigned long atom )
983 {
984  XTextProperty tp;
985  char **text = NULL;
986  int count;
987  QString result;
988  if ( XGetTextProperty( QX11Info::display(), win, &tp, atom ) != 0 && tp.value != NULL ) {
989  create_atoms();
990 
991  if ( tp.encoding == kwm_utf8_string ) {
992  result = QString::fromUtf8 ( (const char*) tp.value );
993  } else if ( XmbTextPropertyToTextList( QX11Info::display(), &tp, &text, &count) == Success &&
994  text != NULL && count > 0 ) {
995  result = QString::fromLocal8Bit( text[0] );
996  } else if ( tp.encoding == XA_STRING )
997  result = QString::fromLocal8Bit( (const char*) tp.value );
998  if( text != NULL )
999  XFreeStringList( text );
1000  XFree( tp.value );
1001  }
1002  return result;
1003 }
1004 
1005 void KWindowSystem::doNotManage( const QString& title )
1006 {
1007  QDBusInterface("org.kde.kwin", "/KWin", "org.kde.KWin", QDBusConnection::sessionBus())
1008  .call("doNotManage", title);
1009 }
1010 
1011 void KWindowSystem::allowExternalProcessWindowActivation( int pid )
1012 {
1013  // Normally supported by X11, but may depend on some window managers ?
1014  Q_UNUSED(pid)
1015 }
1016 
1017 void KWindowSystem::setBlockingCompositing( WId window, bool active )
1018 {
1019  NETWinInfo info( QX11Info::display(), window, QX11Info::appRootWindow(), 0 );
1020  info.setBlockingCompositing( active );
1021 }
1022 
1023 
1024 bool KWindowSystem::mapViewport()
1025 {
1026  KWindowSystemPrivate* const s_d = s_d_func();
1027  if( s_d )
1028  return s_d->mapViewport();
1029  // avoid creating KWindowSystemPrivate
1030  NETRootInfo infos( QX11Info::display(), NET::Supported );
1031  if( !infos.isSupported( NET::DesktopViewport ))
1032  return false;
1033  NETRootInfo info( QX11Info::display(), NET::NumberOfDesktops | NET::CurrentDesktop | NET::DesktopGeometry );
1034  if( info.numberOfDesktops( true ) <= 1
1035  && ( info.desktopGeometry( info.currentDesktop( true )).width > QApplication::desktop()->width()
1036  || info.desktopGeometry( info.currentDesktop( true )).height > QApplication::desktop()->height()))
1037  return true;
1038  return false;
1039 }
1040 
1041 int KWindowSystem::viewportToDesktop( const QPoint& p )
1042 {
1043  init( INFO_BASIC );
1044  KWindowSystemPrivate* const s_d = s_d_func();
1045  NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
1046  QSize vs = qApp->desktop()->size();
1047  int xs = s.width / vs.width();
1048  int x = p.x() < 0 ? 0 : p.x() >= s.width ? xs - 1 : p.x() / vs.width();
1049  int ys = s.height / vs.height();
1050  int y = p.y() < 0 ? 0 : p.y() >= s.height ? ys - 1 : p.y() / vs.height();
1051  return y * xs + x + 1;
1052 }
1053 
1054 int KWindowSystem::viewportWindowToDesktop( const QRect& r )
1055 {
1056  init( INFO_BASIC );
1057  KWindowSystemPrivate* const s_d = s_d_func();
1058  QPoint p = r.center();
1059  // make absolute
1060  p = QPoint( p.x() + s_d->desktopViewport( s_d->currentDesktop( true )).x,
1061  p.y() + s_d->desktopViewport( s_d->currentDesktop( true )).y );
1062  NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
1063  QSize vs = qApp->desktop()->size();
1064  int xs = s.width / vs.width();
1065  int x = p.x() < 0 ? 0 : p.x() >= s.width ? xs - 1 : p.x() / vs.width();
1066  int ys = s.height / vs.height();
1067  int y = p.y() < 0 ? 0 : p.y() >= s.height ? ys - 1 : p.y() / vs.height();
1068  return y * xs + x + 1;
1069 }
1070 
1071 QPoint KWindowSystem::desktopToViewport( int desktop, bool absolute )
1072 {
1073  init( INFO_BASIC );
1074  KWindowSystemPrivate* const s_d = s_d_func();
1075  NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
1076  QSize vs = qApp->desktop()->size();
1077  int xs = s.width / vs.width();
1078  int ys = s.height / vs.height();
1079  if( desktop <= 0 || desktop > xs * ys )
1080  return QPoint( 0, 0 );
1081  --desktop;
1082  QPoint ret( vs.width() * ( desktop % xs ), vs.height() * ( desktop / xs ));
1083  if( !absolute ) {
1084  ret = QPoint( ret.x() - s_d->desktopViewport( s_d->currentDesktop( true )).x,
1085  ret.y() - s_d->desktopViewport( s_d->currentDesktop( true )).y );
1086  if( ret.x() >= s.width )
1087  ret.setX( ret.x() - s.width );
1088  if( ret.x() < 0 )
1089  ret.setX( ret.x() + s.width );
1090  if( ret.y() >= s.height )
1091  ret.setY( ret.y() - s.height );
1092  if( ret.y() < 0 )
1093  ret.setY( ret.y() + s.height );
1094  }
1095  return ret;
1096 }
1097 
1098 QPoint KWindowSystem::constrainViewportRelativePosition( const QPoint& pos )
1099 {
1100  init( INFO_BASIC );
1101  KWindowSystemPrivate* const s_d = s_d_func();
1102  NETSize s = s_d->desktopGeometry( s_d->currentDesktop( true ));
1103  NETPoint c = s_d->desktopViewport( s_d->currentDesktop( true ));
1104  int x = ( pos.x() + c.x ) % s.width;
1105  int y = ( pos.y() + c.y ) % s.height;
1106  if( x < 0 )
1107  x += s.width;
1108  if( y < 0 )
1109  y += s.height;
1110  return QPoint( x - c.x, y - c.y );
1111 }
1112 
1113 #include "kwindowsystem.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Apr 20 2013 06:01:51 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.10.2 API Reference

Skip menu "kdelibs-4.10.2 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal