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>
42 #include <X11/extensions/Xfixes.h>
45 class KWindowSystemStaticContainer {
47 KWindowSystemStaticContainer() : d(0) {}
49 KWindowSystemPrivate* d;
56 static
void create_atoms( Display* dpy = QX11Info::display() );
82 class KWindowSystemPrivate
86 KWindowSystemPrivate(
int _what);
89 QList<WId> stackingOrder;
93 StrutData( WId window_,
const NETStrut& strut_,
int desktop_ )
94 : window( window_ ), strut( strut_ ), desktop( desktop_ ) {}
100 QList<StrutData> strutWindows;
101 QList<WId> possibleStrutWindows;
102 bool strutSignalConnected;
103 bool compositingEnabled;
112 bool x11Event( XEvent * ev );
114 void updateStackingOrder();
115 bool removeStrutWindow( WId );
118 KWindowSystemPrivate::KWindowSystemPrivate(
int _what)
123 strutSignalConnected( false ),
128 (void ) qApp->desktop();
132 if ((haveXfixes = XFixesQueryExtension(QX11Info::display(), &xfixesEventBase, &errorBase))) {
134 XFixesSelectSelectionInput(QX11Info::display(), winId(),
net_wm_cm,
135 XFixesSetSelectionOwnerNotifyMask |
136 XFixesSelectionWindowDestroyNotifyMask |
137 XFixesSelectionClientCloseNotifyMask);
138 compositingEnabled = XGetSelectionOwner(QX11Info::display(),
net_wm_cm) !=
None;
147 updateStackingOrder();
150 bool KWindowSystemPrivate::x11Event( XEvent * ev )
155 if ( ev->type == xfixesEventBase + XFixesSelectionNotify ) {
156 if ( ev->xany.window == winId() ) {
157 XFixesSelectionNotifyEvent *
event =
reinterpret_cast<XFixesSelectionNotifyEvent*
>(ev);
158 bool haveOwner =
event->owner !=
None;
159 if (compositingEnabled != haveOwner) {
160 compositingEnabled = haveOwner;
168 if ( ev->xany.window == QX11Info::appRootWindow() ) {
169 XFixesSelectionNotifyEvent *
event =
reinterpret_cast<XFixesSelectionNotifyEvent*
>(ev);
171 bool haveOwner =
event->owner !=
None;
172 if (compositingEnabled != haveOwner) {
173 compositingEnabled = haveOwner;
184 if ( ev->xany.window == QX11Info::appRootWindow() ) {
185 int old_current_desktop = currentDesktop();
186 WId old_active_window = activeWindow();
187 int old_number_of_desktops = numberOfDesktops();
188 bool old_showing_desktop = showingDesktop();
189 unsigned long m[ 5 ];
192 if (( m[ PROTOCOLS ] & CurrentDesktop ) && currentDesktop() != old_current_desktop )
194 if (( m[ PROTOCOLS ] & DesktopViewport ) && mapViewport() && currentDesktop() != old_current_desktop )
196 if (( m[ PROTOCOLS ] & ActiveWindow ) && activeWindow() != old_active_window )
198 if ( m[ PROTOCOLS ] & DesktopNames )
200 if (( m[ PROTOCOLS ] & NumberOfDesktops ) && numberOfDesktops() != old_number_of_desktops )
202 if (( m[ PROTOCOLS ] & DesktopGeometry ) && mapViewport() && numberOfDesktops() != old_number_of_desktops )
204 if ( m[ PROTOCOLS ] & WorkArea )
206 if ( m[ PROTOCOLS ] & ClientListStacking ) {
207 updateStackingOrder();
210 if(( m[ PROTOCOLS2 ] & WM2ShowingDesktop ) && showingDesktop() != old_showing_desktop ) {
213 }
else if ( windows.contains( ev->xany.window ) ){
214 NETWinInfo ni( QX11Info::display(), ev->xany.window, QX11Info::appRootWindow(), 0 );
215 unsigned long dirty[ 2 ];
216 ni.event( ev, dirty, 2 );
217 if ( ev->type ==PropertyNotify ) {
218 if( ev->xproperty.atom == XA_WM_HINTS )
220 else if( ev->xproperty.atom == XA_WM_NAME )
222 else if( ev->xproperty.atom == XA_WM_ICON_NAME )
232 removeStrutWindow( ev->xany.window );
233 if ( !possibleStrutWindows.contains( ev->xany.window ) )
234 possibleStrutWindows.append( ev->xany.window );
240 if ( (dirty[ NETWinInfo::PROTOCOLS ] & NET::WMStrut) != 0 )
248 bool KWindowSystemPrivate::removeStrutWindow( WId w )
250 for( QList< StrutData >::Iterator it = strutWindows.begin();
251 it != strutWindows.end();
253 if( (*it).window == w ) {
254 strutWindows.erase( it );
260 void KWindowSystemPrivate::updateStackingOrder()
262 stackingOrder.clear();
263 for (
int i = 0; i < clientListStackingCount(); i++ )
264 stackingOrder.append( clientListStacking()[i] );
271 if ( (what >= KWindowSystem::INFO_WINDOWS) && !
QWidget::find( w ) )
272 XSelectInput( QX11Info::display(), w, PropertyChangeMask | StructureNotifyMask );
274 bool emit_strutChanged =
false;
276 if( strutSignalConnected ) {
280 strutWindows.append( StrutData( w, strut, info.desktop()));
281 emit_strutChanged =
true;
284 possibleStrutWindows.append( w );
288 if ( emit_strutChanged )
296 bool emit_strutChanged = removeStrutWindow( w );
297 if( strutSignalConnected && possibleStrutWindows.contains( w )) {
298 NETWinInfo info( QX11Info::display(), w, QX11Info::appRootWindow(), NET::WMStrut );
301 emit_strutChanged =
true;
305 possibleStrutWindows.removeAll( w );
306 windows.removeAll( w );
308 if ( emit_strutChanged )
312 bool KWindowSystemPrivate::mapViewport()
319 && ( desktopGeometry( currentDesktop(
true )).width > QApplication::desktop()->width()
320 || desktopGeometry( currentDesktop(
true )).height > QApplication::desktop()->height()))
335 const char* names[max];
336 Atom atoms_return[max];
340 names[n++] =
"_KDE_WM_CHANGE_STATE";
343 names[n++] =
"WM_PROTOCOLS";
346 names[n++] =
"UTF8_STRING";
348 char net_wm_cm_name[ 100 ];
349 sprintf( net_wm_cm_name,
"_NET_WM_CM_S%d", DefaultScreen( dpy ));
351 names[n++] = net_wm_cm_name;
354 XInternAtoms( dpy, const_cast<char**>(names), n,
false, atoms_return );
355 for (
int i = 0; i < n; i++ )
356 *atoms[i] = atoms_return[i];
358 atoms_created = True;
366 memset(&ev, 0,
sizeof(ev));
367 ev.xclient.type = ClientMessage;
368 ev.xclient.window = w;
369 ev.xclient.message_type = a;
370 ev.xclient.format = 32;
371 ev.xclient.data.l[0] = x;
372 ev.xclient.data.l[1] = y;
373 ev.xclient.data.l[2] = z;
374 mask = SubstructureRedirectMask;
375 XSendEvent(QX11Info::display(), QX11Info::appRootWindow(), False, mask, &ev);
380 return &(g_kwmInstanceContainer->kwm);
384 KWindowSystemPrivate* KWindowSystem::s_d_func()
386 return g_kwmInstanceContainer->d;
393 int what = INFO_BASIC;
396 else if( QLatin1String( signal ) == SIGNAL(
strutChanged()))
398 else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(
windowChanged(WId,
const ulong*))).constData())
400 else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(
windowChanged(WId,uint))).constData())
402 else if( QLatin1String( signal ) == QMetaObject::normalizedSignature(SIGNAL(
windowChanged(WId))).constData())
407 if( !s_d->strutSignalConnected && qstrcmp( signal, SIGNAL(
strutChanged())) == 0 )
408 s_d->strutSignalConnected =
true;
415 void KWindowSystem::init(
int what)
419 if (what >= INFO_WINDOWS)
427 g_kwmInstanceContainer->d->activate();
429 else if (s_d->what < what)
433 g_kwmInstanceContainer->d->activate();
440 return s_d_func()->windows;
445 return KWindowInfo( win, properties, properties2 );
451 return s_d_func()->windows.contains( w );
457 return s_d_func()->stackingOrder;
462 if (!QX11Info::display())
468 NETPoint p = s_d->desktopViewport( s_d->currentDesktop(
true ));
474 return s_d->currentDesktop(
true );
476 return info.currentDesktop(
true );
481 if (!QX11Info::display())
487 NETSize s = s_d->desktopGeometry( s_d->currentDesktop(
true ));
488 return s.
width / qApp->desktop()->width() * s.
height / qApp->desktop()->height();
493 return s_d->numberOfDesktops(
true );
495 return info.numberOfDesktops(
true );
508 info.setDesktopViewport( s_d->currentDesktop(
true ), p );
512 info.setCurrentDesktop( desktop,
true );
529 info.setDesktop( rinfo.currentDesktop(
true ), true );
544 unsigned int w, h, b, dp;
545 XGetGeometry( QX11Info::display(), win, &dummy, &x, &y, &w, &h, &b, &dp );
547 XTranslateCoordinates( QX11Info::display(), win, QX11Info::appRootWindow(), 0, 0, &x, &y, &dummy );
551 x = x % qApp->desktop()->width();
552 y = y % qApp->desktop()->height();
554 x = x + qApp->desktop()->width();
556 y = y + qApp->desktop()->height();
564 s_d->moveResizeWindowRequest( win, flags, p.x(), p.y(), w, h );
568 info.setDesktop( desktop,
true );
575 return s_d->activeWindow();
577 return info.activeWindow();
584 time = QX11Info::appUserTime();
586 qApp->activeWindow() ? qApp->activeWindow()->winId() : 0 );
593 time = QX11Info::appTime();
607 if( XGetTransientForHint( QX11Info::display(), win, &transient_for ))
608 return transient_for;
615 subwindow->setAttribute( Qt::WA_X11BypassTransientForHint );
616 if( mainwindow != 0 )
617 XSetTransientForHint( QX11Info::display(), subwindow->winId(), mainwindow );
619 XDeleteProperty( QX11Info::display(), subwindow->winId(), XA_WM_TRANSIENT_FOR );
625 XWMHints *hints = XGetWMHints( QX11Info::display(), win );
629 if( hints->flags & WindowGroupHint )
630 window_group = hints->window_group;
631 XFree( reinterpret_cast< char* >( hints ));
647 if( flags &
NETWM ) {
649 NETIcon ni = info.icon( width, height );
652 if ( scale && width > 0 && height > 0 &&img.size() !=
QSize( width, height ) && !img.isNull() )
653 img = img.scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
655 result = QPixmap::fromImage( img );
662 Pixmap p_mask =
None;
664 XWMHints *hints = XGetWMHints(QX11Info::display(), win );
665 if (hints && (hints->flags & IconPixmapHint)){
666 p = hints->icon_pixmap;
668 if (hints && (hints->flags & IconMaskHint)){
669 p_mask = hints->icon_mask;
676 if ( scale && width > 0 && height > 0 && !pm.isNull()
677 && ( pm.width() != width || pm.height() != height) ){
678 result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
691 else if( width < 40 )
699 if( result.isNull() ) {
702 if( XGetClassHint( QX11Info::display(), win, &hint ) ) {
703 QString className = hint.res_class;
707 if( scale && !pm.isNull() )
708 result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
712 XFree( hint.res_name );
713 XFree( hint.res_class );
721 if ( result.isNull() ) {
723 KIconLoader::DefaultState,
QStringList(), 0,
true );
724 if( scale && !pm.isNull() )
725 result = QPixmap::fromImage( pm.toImage().scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
737 NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
738 QImage img = icon.toImage().convertToFormat( QImage::Format_ARGB32 );
742 ni.
data = (
unsigned char *) img.bits();
743 info.setIcon( ni,
true );
744 if ( miniIcon.isNull() )
746 img = miniIcon.toImage().convertToFormat( QImage::Format_ARGB32 );
751 ni.
data = (
unsigned char *) img.bits();
752 info.setIcon( ni,
false );
757 NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
758 info.setWindowType( windowType );
764 info.setState( state, state );
770 info.setState( 0, state );
781 XIconifyWindow( QX11Info::display(), win, inf.screen() );
791 XMapWindow( QX11Info::display(), win );
798 info.restackRequest( win,
NET::FromTool, None, Above, QX11Info::appUserTime());
800 XRaiseWindow( QX11Info::display(), win );
807 info.restackRequest( win,
NET::FromTool, None, Below, QX11Info::appUserTime());
809 XLowerWindow( QX11Info::display(), win );
814 if( QX11Info::display()) {
816 if (s_d_func()->haveXfixes) {
817 return s_d_func()->compositingEnabled;
820 return XGetSelectionOwner( QX11Info::display(),
net_wm_cm );
823 Display* dpy = XOpenDisplay( NULL );
826 XCloseDisplay( dpy );
834 int desk = (desktop > 0 && desktop <= (int) s_d_func()->numberOfDesktops() ) ? desktop :
currentDesktop();
836 return QApplication::desktop()->geometry();
838 NETRect r = s_d_func()->workArea( desk );
840 return QApplication::desktop()->geometry();
847 init( INFO_WINDOWS );
850 QRect all = QApplication::desktop()->geometry();
854 desktop = s_d->currentDesktop();
856 QList<WId>::ConstIterator it1;
857 for( it1 = s_d->windows.constBegin(); it1 != s_d->windows.constEnd(); ++it1 ) {
859 if(exclude.contains(*it1))
866 QList< KWindowSystemPrivate::StrutData >::Iterator it2 = s_d->strutWindows.begin();
867 for( ; it2 != s_d->strutWindows.end(); ++it2 )
868 if( (*it2).window == *it1 )
871 if( it2 != s_d->strutWindows.end()) {
875 strut = (*it2).strut;
876 }
else if( s_d->possibleStrutWindows.contains( *it1 ) ) {
879 strut = info.strut();
880 s_d->possibleStrutWindows.removeAll( *it1 );
881 s_d->strutWindows.append( KWindowSystemPrivate::StrutData( *it1, info.strut(), info.desktop()));
889 if ( strut.
left > 0 )
890 r.setLeft( r.left() + (int) strut.
left );
892 r.setTop( r.top() + (int) strut.
top );
893 if ( strut.
right > 0 )
894 r.setRight( r.right() - (int) strut.
right );
896 r.setBottom( r.bottom() - (int) strut.
bottom );
908 bool isDesktopSane = (desktop > 0 && desktop <= (int) s_d->numberOfDesktops());
911 if ( name && name[0] )
912 return QString::fromUtf8( name );
914 return i18n(
"Desktop %1", desktop );
925 s_d->setDesktopName( desktop, name.toUtf8().constData() );
930 info.setDesktopName( desktop, name.toUtf8().constData() );
936 return s_d_func()->showingDesktop();
941 NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
942 info.setUserTime( time );
946 int right_width,
int right_start,
int right_end,
int top_width,
int top_start,
int top_end,
947 int bottom_width,
int bottom_start,
int bottom_end )
949 NETWinInfo info( QX11Info::display(), win, QX11Info::appRootWindow(), 0 );
963 info.setExtendedStrut( strut );
965 oldstrut.
left = left_width;
966 oldstrut.
right = right_width;
967 oldstrut.
top = top_width;
968 oldstrut.
bottom = bottom_width;
969 info.setStrut( oldstrut );
974 int w = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display()));
975 int h = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display()));
976 setExtendedStrut( win, left, 0, left != 0 ? w : 0, right, 0, right != 0 ? w : 0,
977 top, 0, top != 0 ? h : 0, bottom, 0, bottom != 0 ? h : 0 );
982 static enum { noidea,
yes,
no } wm_is_1_2_compliant = noidea;
983 if( wm_is_1_2_compliant == noidea ) {
987 return wm_is_1_2_compliant ==
yes;
992 static enum { noidea,
yes,
no } wm_supports_allowed_actions = noidea;
993 if( wm_supports_allowed_actions == noidea ) {
997 return wm_supports_allowed_actions ==
yes;
1006 if ( XGetTextProperty( QX11Info::display(), win, &tp, atom ) != 0 && tp.value != NULL ) {
1009 if ( tp.encoding == kwm_utf8_string ) {
1010 result = QString::fromUtf8 ( (
const char*) tp.value );
1011 }
else if ( XmbTextPropertyToTextList( QX11Info::display(), &tp, &text, &count) == Success &&
1012 text != NULL && count > 0 ) {
1013 result = QString::fromLocal8Bit( text[0] );
1014 }
else if ( tp.encoding == XA_STRING )
1015 result = QString::fromLocal8Bit( (
const char*) tp.value );
1017 XFreeStringList( text );
1025 QDBusInterface(
"org.kde.kwin",
"/KWin",
"org.kde.KWin", QDBusConnection::sessionBus())
1026 .call(
"doNotManage", title);
1037 NETWinInfo info( QX11Info::display(), window, QX11Info::appRootWindow(), 0 );
1038 info.setBlockingCompositing( active );
1046 return s_d->mapViewport();
1063 NETSize s = s_d->desktopGeometry( s_d->currentDesktop(
true ));
1064 QSize vs = qApp->desktop()->size();
1065 int xs = s.
width / vs.width();
1066 int x = p.x() < 0 ? 0 : p.x() >= s.
width ? xs - 1 : p.x() / vs.width();
1067 int ys = s.
height / vs.height();
1068 int y = p.y() < 0 ? 0 : p.y() >= s.
height ? ys - 1 : p.y() / vs.height();
1069 return y * xs + x + 1;
1078 p =
QPoint( p.x() + s_d->desktopViewport( s_d->currentDesktop(
true )).x,
1079 p.y() + s_d->desktopViewport( s_d->currentDesktop(
true )).y );
1080 NETSize s = s_d->desktopGeometry( s_d->currentDesktop(
true ));
1081 QSize vs = qApp->desktop()->size();
1082 int xs = s.
width / vs.width();
1083 int x = p.x() < 0 ? 0 : p.x() >= s.
width ? xs - 1 : p.x() / vs.width();
1084 int ys = s.
height / vs.height();
1085 int y = p.y() < 0 ? 0 : p.y() >= s.
height ? ys - 1 : p.y() / vs.height();
1086 return y * xs + x + 1;
1093 NETSize s = s_d->desktopGeometry( s_d->currentDesktop(
true ));
1094 QSize vs = qApp->desktop()->size();
1095 int xs = s.
width / vs.width();
1096 int ys = s.
height / vs.height();
1097 if( desktop <= 0 || desktop > xs * ys )
1100 QPoint ret( vs.width() * ( desktop % xs ), vs.height() * ( desktop / xs ));
1102 ret =
QPoint( ret.x() - s_d->desktopViewport( s_d->currentDesktop(
true )).x,
1103 ret.y() - s_d->desktopViewport( s_d->currentDesktop(
true )).y );
1104 if( ret.x() >= s.
width )
1105 ret.setX( ret.x() - s.
width );
1107 ret.setX( ret.x() + s.
width );
1108 if( ret.y() >= s.
height )
1109 ret.setY( ret.y() - s.
height );
1111 ret.setY( ret.y() + s.
height );
1120 NETSize s = s_d->desktopGeometry( s_d->currentDesktop(
true ));
1121 NETPoint c = s_d->desktopViewport( s_d->currentDesktop(
true ));
1122 int x = ( pos.x() + c.
x ) % s.
width;
1123 int y = ( pos.y() + c.
y ) % s.
height;
1131 #include "kwindowsystem.moc"