diff --git a/client.cpp b/client.cpp index 1bb7966bec..4cd5e2609e 100644 --- a/client.cpp +++ b/client.cpp @@ -28,7 +28,6 @@ License. See the file "COPYING" for the exact licensing terms. #include "atoms.h" #include "notifications.h" #include "rules.h" -#include "scene.h" #include #include @@ -64,10 +63,12 @@ namespace KWinInternal is done in manage(). */ Client::Client( Workspace *ws ) - : Toplevel( ws ), + : QObject( NULL ), client( None ), wrapper( None ), + frame( None ), decoration( NULL ), + wspace( ws ), bridge( new Bridge( this )), move_faked_activity( false ), move_resize_grab_window( None ), @@ -142,8 +143,11 @@ Client::Client( Workspace *ws ) cmap = None; - geom = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0) + frame_geometry = QRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0) client_size = QSize( 100, 100 ); + custom_opacity = false; + rule_opacity_active = 0;; //translucency rules + rule_opacity_inactive = 0; //dito. // SELI initialize xsizehints?? } @@ -155,8 +159,7 @@ Client::~Client() { assert(!moveResizeMode); assert( client == None ); - assert( wrapper == None ); -// assert( frameId() == None ); + assert( frame == None && wrapper == None ); assert( decoration == NULL ); assert( postpone_geometry_updates == 0 ); assert( !check_active_modal ); @@ -177,9 +180,9 @@ void Client::releaseWindow( bool on_shutdown ) { assert( !deleting ); deleting = true; - finishCompositing(); workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules StackingUpdatesBlocker blocker( workspace()); + if (!custom_opacity) setOpacity(false); if (moveResizeMode) leaveMoveResize(); finishWindowRules(); @@ -189,7 +192,7 @@ void Client::releaseWindow( bool on_shutdown ) hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags) if( !on_shutdown ) workspace()->clientHidden( this ); - XUnmapWindow( display(), frameId()); // destroying decoration would cause ugly visual effect + XUnmapWindow( QX11Info::display(), frameId()); // destroying decoration would cause ugly visual effect destroyDecoration(); cleanGrouping(); if( !on_shutdown ) @@ -201,28 +204,28 @@ void Client::releaseWindow( bool on_shutdown ) desk = 0; info->setState( 0, info->state()); // reset all state flags } - XDeleteProperty( display(), client, atoms->kde_net_wm_user_creation_time); - XDeleteProperty( display(), client, atoms->net_frame_extents ); - XDeleteProperty( display(), client, atoms->kde_net_wm_frame_strut ); - XReparentWindow( display(), client, workspace()->rootWin(), x(), y()); - XRemoveFromSaveSet( display(), client ); - XSelectInput( display(), client, NoEventMask ); + XDeleteProperty( QX11Info::display(), client, atoms->kde_net_wm_user_creation_time); + XDeleteProperty( QX11Info::display(), client, atoms->net_frame_extents ); + XDeleteProperty( QX11Info::display(), client, atoms->kde_net_wm_frame_strut ); + XReparentWindow( QX11Info::display(), client, workspace()->rootWin(), x(), y()); + XRemoveFromSaveSet( QX11Info::display(), client ); + XSelectInput( QX11Info::display(), client, NoEventMask ); if( on_shutdown ) { // map the window, so it can be found after another WM is started - XMapWindow( display(), client ); + XMapWindow( QX11Info::display(), client ); // TODO preserve minimized, shaded etc. state? } else { // Make sure it's not mapped if the app unmapped it (#65279). The app // may do map+unmap before we initially map the window by calling rawShow() from manage(). - XUnmapWindow( display(), client ); + XUnmapWindow( QX11Info::display(), client ); } client = None; - XDestroyWindow( display(), wrapper ); + XDestroyWindow( QX11Info::display(), wrapper ); wrapper = None; - XDestroyWindow( display(), frameId()); -// frame = None; + XDestroyWindow( QX11Info::display(), frame ); + frame = None; --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry deleteClient( this, Allowed ); } @@ -233,7 +236,6 @@ void Client::destroyClient() { assert( !deleting ); deleting = true; - finishCompositing(); workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules StackingUpdatesBlocker blocker( workspace()); if (moveResizeMode) @@ -247,10 +249,10 @@ void Client::destroyClient() cleanGrouping(); workspace()->removeClient( this, Allowed ); client = None; // invalidate - XDestroyWindow( display(), wrapper ); + XDestroyWindow( QX11Info::display(), wrapper ); wrapper = None; - XDestroyWindow( display(), frameId()); -// frame = None; + XDestroyWindow( QX11Info::display(), frame ); + frame = None; --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry deleteClient( this, Allowed ); } @@ -270,9 +272,12 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) // TODO check decoration's minimum size? decoration->init(); decoration->widget()->installEventFilter( this ); - XReparentWindow( display(), decoration->widget()->winId(), frameId(), 0, 0 ); + XReparentWindow( QX11Info::display(), decoration->widget()->winId(), frameId(), 0, 0 ); decoration->widget()->lower(); decoration->borders( border_left, border_right, border_top, border_bottom ); + options->onlyDecoTranslucent ? + setDecoHashProperty(border_top, border_right, border_bottom, border_left): + unsetDecoHashProperty(); int save_workarea_diff_x = workarea_diff_x; int save_workarea_diff_y = workarea_diff_y; move( calculateGravitation( false )); @@ -280,8 +285,6 @@ void Client::updateDecoration( bool check_workspace_pos, bool force ) workarea_diff_x = save_workarea_diff_x; workarea_diff_y = save_workarea_diff_y; do_show = true; - if( scene != NULL ) - scene->windowGeometryShapeChanged( this ); } else destroyDecoration(); @@ -308,8 +311,6 @@ void Client::destroyDecoration() move( grav ); workarea_diff_x = save_workarea_diff_x; workarea_diff_y = save_workarea_diff_y; - if( scene != NULL ) - scene->windowGeometryShapeChanged( this ); } } @@ -332,6 +333,9 @@ void Client::checkBorderSizes() border_right != new_right || border_top != new_top || border_bottom != new_bottom) + options->onlyDecoTranslucent ? + setDecoHashProperty(new_top, new_right, new_bottom, new_left): + unsetDecoHashProperty(); move( calculateGravitation( false )); plainResize( sizeForClientSize( clientSize()), ForceGeometrySet ); checkWorkspacePosition(); @@ -339,7 +343,7 @@ void Client::checkBorderSizes() void Client::detectNoBorder() { - if( hasShape( window())) + if( Shape::hasShape( window())) { noborder = true; return; @@ -370,6 +374,30 @@ void Client::detectNoBorder() noborder = true; } +void Client::detectShapable() + { + if( Shape::hasShape( window())) + return; + switch( windowType()) + { + case NET::Desktop : + case NET::Dock : + case NET::TopMenu : + case NET::Splash : + break; + case NET::Unknown : + case NET::Normal : + case NET::Toolbar : + case NET::Menu : + case NET::Dialog : + case NET::Utility : + setShapable(false); + break; + default: + assert( false ); + } + } + void Client::updateFrameExtents() { NETStrut strut; @@ -427,31 +455,46 @@ void Client::setUserNoBorder( bool set ) void Client::updateShape() { - if ( shape() ) - XShapeCombineShape(display(), frameId(), ShapeBounding, - clientPos().x(), clientPos().y(), - window(), ShapeBounding, ShapeSet); - else - XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0, - None, ShapeSet); - if( scene != NULL ) - scene->windowGeometryShapeChanged( this ); // workaround for #19644 - shaped windows shouldn't have decoration if( shape() && !noBorder()) { noborder = true; updateDecoration( true ); } + if( shape()) + { + XShapeCombineShape(QX11Info::display(), frameId(), ShapeBounding, + clientPos().x(), clientPos().y(), + window(), ShapeBounding, ShapeSet); + } + else + { + XShapeCombineMask( QX11Info::display(), frameId(), ShapeBounding, 0, 0, + None, ShapeSet); + } + if( Shape::major() > 1 || Shape::minor() >= 1 ) // has input shape support + { // there appears to be no way to find out if a window has input + // shape set or not, so always set propagate the input shape + // (it's the same like the bounding shape by default) + XShapeCombineMask( QX11Info::display(), frameId(), ShapeInput, 0, 0, + None, ShapeSet ); + XShapeCombineShape( QX11Info::display(), frameId(), ShapeInput, + clientPos().x(), clientPos().y(), + window(), ShapeBounding, ShapeSubtract ); + XShapeCombineShape( QX11Info::display(), frameId(), ShapeInput, + clientPos().x(), clientPos().y(), + window(), ShapeInput, ShapeUnion ); + } } void Client::setMask( const QRegion& reg, int mode ) { _mask = reg; if( reg.isEmpty()) - XShapeCombineMask( display(), frameId(), ShapeBounding, 0, 0, + XShapeCombineMask( QX11Info::display(), frameId(), ShapeBounding, 0, 0, None, ShapeSet ); else if( mode == X::Unsorted ) - XShapeCombineRegion( display(), frameId(), ShapeBounding, 0, 0, + XShapeCombineRegion( QX11Info::display(), frameId(), ShapeBounding, 0, 0, reg.handle(), ShapeSet ); else { @@ -466,12 +509,10 @@ void Client::setMask( const QRegion& reg, int mode ) xrects[ i ].width = rects[ i ].width(); xrects[ i ].height = rects[ i ].height(); } - XShapeCombineRectangles( display(), frameId(), ShapeBounding, 0, 0, + XShapeCombineRectangles( QX11Info::display(), frameId(), ShapeBounding, 0, 0, xrects, rects.count(), ShapeSet, mode ); delete[] xrects; } - if( scene != NULL ) - scene->windowGeometryShapeChanged( this ); } QRegion Client::mask() const @@ -481,6 +522,12 @@ QRegion Client::mask() const return _mask; } +void Client::setShapable(bool b) + { + long tmp = b?1:0; + XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L); + } + void Client::hideClient( bool hide ) { if( hidden == hide ) @@ -632,7 +679,7 @@ void Client::animateMinimizeOrUnminimize( bool minimize ) if (area2 != area) { pm = animationPixmap( area.width() ); - pm2 = QPixmap::grabWindow( rootWindow(), area.x(), area.y(), area.width(), area.height() ); + pm2 = QPixmap::grabWindow( QX11Info::appRootWindow(), area.x(), area.y(), area.width(), area.height() ); p.drawPixmap( area.x(), area.y(), pm ); if ( need_to_clear ) { @@ -641,8 +688,8 @@ void Client::animateMinimizeOrUnminimize( bool minimize ) } area2 = area; } - XFlush(display()); - XSync( display(), false ); + XFlush(QX11Info::display()); + XSync( QX11Info::display(), false ); diff = t.elapsed(); if (diff > step) diff = step; @@ -730,16 +777,16 @@ void Client::setShade( ShadeMode mode ) { // shade_mode == ShadeNormal // we're about to shade, texx xcompmgr to prepare long _shade = 1; - XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L); + XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L); // shade int h = height(); shade_geometry_change = true; QSize s( sizeForClientSize( QSize( clientSize()))); s.setHeight( border_top + border_bottom ); - XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify - XUnmapWindow( display(), wrapper ); - XUnmapWindow( display(), client ); - XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); + XSelectInput( QX11Info::display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify + XUnmapWindow( QX11Info::display(), wrapper ); + XUnmapWindow( QX11Info::display(), client ); + XSelectInput( QX11Info::display(), wrapper, ClientWinMask | SubstructureNotifyMask ); //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it //done xcompmgr workaround // FRAME repaint( false ); @@ -749,7 +796,7 @@ void Client::setShade( ShadeMode mode ) do { h -= step; - XResizeWindow( display(), frameId(), s.width(), h ); + XResizeWindow( QX11Info::display(), frameId(), s.width(), h ); resizeDecoration( QSize( s.width(), h )); QApplication::syncX(); } while ( h > s.height() + step ); @@ -766,7 +813,7 @@ void Client::setShade( ShadeMode mode ) } // tell xcompmgr shade's done _shade = 2; - XChangeProperty(display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L); + XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L); } else { @@ -779,7 +826,7 @@ void Client::setShade( ShadeMode mode ) do { h += step; - XResizeWindow( display(), frameId(), s.width(), h ); + XResizeWindow( QX11Info::display(), frameId(), s.width(), h ); resizeDecoration( QSize( s.width(), h )); // assume a border // we do not have time to wait for X to send us paint events @@ -792,9 +839,9 @@ void Client::setShade( ShadeMode mode ) plainResize( s ); if( shade_mode == ShadeHover || shade_mode == ShadeActivated ) setActive( true ); - XMapWindow( display(), wrapperId()); - XMapWindow( display(), window()); - XDeleteProperty (display(), client, atoms->net_wm_window_shade); + XMapWindow( QX11Info::display(), wrapperId()); + XMapWindow( QX11Info::display(), window()); + XDeleteProperty (QX11Info::display(), client, atoms->net_wm_window_shade); if ( isActive() ) workspace()->requestFocus( this ); } @@ -893,7 +940,7 @@ void Client::setMappingState(int s) mapping_state = s; if( mapping_state == WithdrawnState ) { - XDeleteProperty( display(), window(), atoms->wm_state ); + XDeleteProperty( QX11Info::display(), window(), atoms->wm_state ); return; } assert( s == NormalState || s == IconicState ); @@ -901,7 +948,7 @@ void Client::setMappingState(int s) unsigned long data[2]; data[0] = (unsigned long) s; data[1] = (unsigned long) None; - XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32, + XChangeProperty(QX11Info::display(), window(), atoms->wm_state, atoms->wm_state, 32, PropModeReplace, (unsigned char *)data, 2); if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry @@ -916,11 +963,11 @@ void Client::rawShow() { if( decoration != NULL ) decoration->widget()->show(); // not really necessary, but let it know the state - XMapWindow( display(), frameId()); + XMapWindow( QX11Info::display(), frame ); if( !isShade()) { - XMapWindow( display(), wrapper ); - XMapWindow( display(), client ); + XMapWindow( QX11Info::display(), wrapper ); + XMapWindow( QX11Info::display(), client ); } } @@ -937,11 +984,11 @@ void Client::rawHide() // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify // will be missed is also very minimal, so I don't think it's needed to grab the server // here. - XSelectInput( display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify - XUnmapWindow( display(), frameId()); - XUnmapWindow( display(), wrapper ); - XUnmapWindow( display(), client ); - XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); + XSelectInput( QX11Info::display(), wrapper, ClientWinMask ); // avoid getting UnmapNotify + XUnmapWindow( QX11Info::display(), frame ); + XUnmapWindow( QX11Info::display(), wrapper ); + XUnmapWindow( QX11Info::display(), client ); + XSelectInput( QX11Info::display(), wrapper, ClientWinMask | SubstructureNotifyMask ); if( decoration != NULL ) decoration->widget()->hide(); // not really necessary, but let it know the state workspace()->clientHidden( this ); @@ -958,14 +1005,14 @@ void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long ev.xclient.message_type = a; ev.xclient.format = 32; ev.xclient.data.l[0] = protocol; - ev.xclient.data.l[1] = xTime(); + ev.xclient.data.l[1] = QX11Info::appTime(); ev.xclient.data.l[2] = data1; ev.xclient.data.l[3] = data2; ev.xclient.data.l[4] = data3; mask = 0L; - if (w == rootWindow()) + if (w == QX11Info::appRootWindow()) mask = SubstructureRedirectMask; /* magic! */ - XSendEvent(display(), w, False, mask, &ev); + XSendEvent(QX11Info::display(), w, False, mask, &ev); } /* @@ -1017,7 +1064,7 @@ void Client::killWindow() Notify::raise( Notify::Delete ); killProcess( false ); // always kill this client at the server - XKillClient(display(), window() ); + XKillClient(QX11Info::display(), window() ); destroyClient(); } @@ -1036,7 +1083,7 @@ void Client::pingWindow() connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout())); ping_timer->setSingleShot( true ); ping_timer->start( options->killPingTimeout ); - ping_timestamp = xTime(); + ping_timestamp = QX11Info::appTime(); workspace()->sendPingToWindow( window(), ping_timestamp ); } @@ -1203,15 +1250,15 @@ void Client::takeActivity( int flags, bool handled, allowed_t ) #ifndef NDEBUG static Time previous_activity_timestamp; static Client* previous_client; - if( previous_activity_timestamp == xTime() && previous_client != this ) + if( previous_activity_timestamp == QX11Info::appTime() && previous_client != this ) { kDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl; kDebug( 1212 ) << kBacktrace() << endl; } - previous_activity_timestamp = xTime(); + previous_activity_timestamp = QX11Info::appTime(); previous_client = this; #endif - workspace()->sendTakeActivity( this, xTime(), flags ); + workspace()->sendTakeActivity( this, QX11Info::appTime(), flags ); } // performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS @@ -1220,17 +1267,17 @@ void Client::takeFocus( allowed_t ) #ifndef NDEBUG static Time previous_focus_timestamp; static Client* previous_client; - if( previous_focus_timestamp == xTime() && previous_client != this ) + if( previous_focus_timestamp == QX11Info::appTime() && previous_client != this ) { kDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl; kDebug( 1212 ) << kBacktrace() << endl; } - previous_focus_timestamp = xTime(); + previous_focus_timestamp = QX11Info::appTime(); previous_client = this; #endif if ( rules()->checkAcceptFocus( input )) { - XSetInputFocus( display(), window(), RevertToPointerRoot, xTime() ); + XSetInputFocus( QX11Info::display(), window(), RevertToPointerRoot, QX11Info::appTime() ); } if ( Ptakefocus ) sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus); @@ -1283,7 +1330,7 @@ QString Client::readName() const return KWin::readNameProperty( window(), XA_WM_NAME ); } -KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, Client, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption()); +KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption()); void Client::setCaption( const QString& _s, bool force ) { @@ -1363,7 +1410,7 @@ QString Client::caption( bool full ) const void Client::getWMHints() { - XWMHints *hints = XGetWMHints(display(), window() ); + XWMHints *hints = XGetWMHints(QX11Info::display(), window() ); input = true; window_group = None; urgency = false; @@ -1452,7 +1499,7 @@ void Client::getWindowProtocols() Pcontexthelp = 0; Pping = 0; - if (XGetWMProtocols(display(), window(), &p, &n)) + if (XGetWMProtocols(QX11Info::display(), window(), &p, &n)) { for (i = 0; i < n; i++) if (p[i] == atoms->wm_delete_window) @@ -1511,7 +1558,7 @@ Window Client::staticWmClientLeader(WId w) unsigned char *data = 0; Window result = w; XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler); - status = XGetWindowProperty( display(), w, atoms->wm_client_leader, 0, 10000, + status = XGetWindowProperty( QX11Info::display(), w, atoms->wm_client_leader, 0, 10000, false, XA_WINDOW, &type, &format, &nitems, &extra, &data ); XSetErrorHandler(oldHandler); @@ -1600,6 +1647,58 @@ bool Client::wantsInput() const return rules()->checkAcceptFocus( input || Ptakefocus ); } +bool Client::isDesktop() const + { + return windowType() == NET::Desktop; + } + +bool Client::isDock() const + { + return windowType() == NET::Dock; + } + +bool Client::isTopMenu() const + { + return windowType() == NET::TopMenu; + } + + +bool Client::isMenu() const + { + return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp. + } + +bool Client::isToolbar() const + { + return windowType() == NET::Toolbar; + } + +bool Client::isSplash() const + { + return windowType() == NET::Splash; + } + +bool Client::isUtility() const + { + return windowType() == NET::Utility; + } + +bool Client::isDialog() const + { + return windowType() == NET::Dialog; + } + +bool Client::isNormalWindow() const + { + return windowType() == NET::Normal; + } + +bool Client::isSpecialWindow() const + { + return isDesktop() || isDock() || isSplash() || isTopMenu() + || isToolbar(); // TODO + } + NET::WindowType Client::windowType( bool direct, int supported_types ) const { NET::WindowType wt = info->windowType( supported_types ); @@ -1631,12 +1730,6 @@ NET::WindowType Client::windowType( bool direct, int supported_types ) const return wt; } -bool Client::isSpecialWindow() const - { - return isDesktop() || isDock() || isSplash() || isTopMenu() - || isToolbar(); // TODO - } - /*! Sets an appropriate cursor shape for the logical mouse position \a m @@ -1682,7 +1775,7 @@ void Client::setCursor( const QCursor& c ) cursor = c; if( decoration != NULL ) decoration->widget()->setCursor( cursor ); - XDefineCursor( display(), frameId(), cursor.handle()); + XDefineCursor( QX11Info::display(), frameId(), cursor.handle()); } Client::Position Client::mousePosition( const QPoint& p ) const @@ -1733,38 +1826,312 @@ void Client::cancelAutoRaise() autoRaiseTimer = 0; } -// does the window w need a shape combine mask around it? -bool Client::hasShape( Window w ) +void Client::setOpacity(bool translucent, uint opacity) { - int xws, yws, xbs, ybs; - unsigned int wws, hws, wbs, hbs; - int boundingShaped = 0, clipShaped = 0; - if( !Extensions::shapeAvailable()) - return false; - XShapeQueryExtents(display(), w, - &boundingShaped, &xws, &yws, &wws, &hws, - &clipShaped, &xbs, &ybs, &wbs, &hbs); - return boundingShaped != 0; + if (isDesktop()) + return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling +// qWarning("setting opacity for %d",QX11Info::display()); + //rule out activated translulcency with 100% opacity + if (!translucent || opacity == 0xFFFFFFFF) + { + opacity_ = 0xFFFFFFFF; + XDeleteProperty (QX11Info::display(), frameId(), atoms->net_wm_window_opacity); + XDeleteProperty (QX11Info::display(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd + } + else{ + if(opacity == opacity_) + return; + opacity_ = opacity; + long data = opacity; // 32bit XChangeProperty needs long + XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L); + XChangeProperty(QX11Info::display(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L); + } + } + +void Client::setShadowSize(uint shadowSize) + { + // ignoring all individual settings - if we control a window, we control it's shadow + // TODO somehow handle individual settings for docks (besides custom sizes) + long data = shadowSize; + XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L); + } + +void Client::updateOpacity() +// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows) + { + if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity) + return; + if (isActive()) + { + if( ruleOpacityActive() ) + setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active); + else + setOpacity(options->translucentActiveWindows, options->activeWindowOpacity); + if (isBMP()) + // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P ) + { + ClientList tmpGroupMembers = group()->members(); + ClientList activeGroupMembers; + activeGroupMembers.append(this); + tmpGroupMembers.removeAll(this); + ClientList::Iterator it = tmpGroupMembers.begin(); + while (it != tmpGroupMembers.end()) + // search for next attached and not activated client and repeat if found + { + if ((*it) != this && (*it)->isBMP()) + // potential "to activate" client found + { +// qWarning("client found"); + if ((*it)->touches(this)) // first test, if the new client touches the just activated one + { +// qWarning("found client touches me"); + if( ruleOpacityActive() ) + (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active); + else + (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity); +// qWarning("activated, search restarted (1)"); + (*it)->setShadowSize(options->activeWindowShadowSize); + activeGroupMembers.append(*it); + tmpGroupMembers.erase(it); + it = tmpGroupMembers.begin(); // restart, search next client + continue; + } + else + { // pot. client does not touch c, so we have to search if it touches some other activated client + bool found = false; + for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ ) + { + if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2)) + { +// qWarning("found client touches other active client"); + if( ruleOpacityActive() ) + (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active); + else + (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity); + (*it)->setShadowSize(options->activeWindowShadowSize); + activeGroupMembers.append(*it); + tmpGroupMembers.erase(it); + it = tmpGroupMembers.begin(); // reset potential client search + found = true; +// qWarning("activated, search restarted (2)"); + break; // skip this loop + } + } + if (found) continue; + } + } + it++; + } + } + else if (isNormalWindow()) + // activate dependent minor windows as well + { + for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ ) + if ((*it)->isDialog() || (*it)->isUtility()) + if( (*it)->ruleOpacityActive() ) + (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive()); + else + (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity); + } + } + else + { + if( ruleOpacityInactive() ) + setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive); + else + setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive), + options->inactiveWindowOpacity); + // deactivate dependent minor windows as well + if (isBMP()) + // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P ) + { + ClientList tmpGroupMembers = group()->members(); + ClientList inactiveGroupMembers; + inactiveGroupMembers.append(this); + tmpGroupMembers.removeAll(this); + ClientList::Iterator it = tmpGroupMembers.begin(); + while ( it != tmpGroupMembers.end() ) + // search for next attached and not activated client and repeat if found + { + if ((*it) != this && (*it)->isBMP()) + // potential "to activate" client found + { +// qWarning("client found"); + if ((*it)->touches(this)) // first test, if the new client touches the just activated one + { +// qWarning("found client touches me"); + if( (*it)->ruleOpacityInactive() ) + (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive()); + else + (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity); + (*it)->setShadowSize(options->inactiveWindowShadowSize); +// qWarning("deactivated, search restarted (1)"); + inactiveGroupMembers.append(*it); + tmpGroupMembers.erase(it); + it = tmpGroupMembers.begin(); // restart, search next client + continue; + } + else // pot. client does not touch c, so we have to search if it touches some other activated client + { + bool found = false; + for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ ) + { + if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2)) + { +// qWarning("found client touches other inactive client"); + if( (*it)->ruleOpacityInactive() ) + (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive()); + else + (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity); + (*it)->setShadowSize(options->inactiveWindowShadowSize); +// qWarning("deactivated, search restarted (2)"); + inactiveGroupMembers.append(*it); + tmpGroupMembers.erase(it); + it = tmpGroupMembers.begin(); // reset potential client search + found = true; + break; // skip this loop + } + } + if (found) continue; + } + } + it++; + } + } + else if (isNormalWindow()) + { + for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ ) + if ((*it)->isUtility()) //don't deactivate dialogs... + if( (*it)->ruleOpacityInactive() ) + (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive()); + else + (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity); + } + } + } + +void Client::updateShadowSize() +// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows) + { + if (!(isNormalWindow() || isDialog() || isUtility() )) + return; + if (isActive()) + setShadowSize(options->activeWindowShadowSize); + else + setShadowSize(options->inactiveWindowShadowSize); } -double Client::opacity() const +uint Client::ruleOpacityInactive() { - if( info->opacity() == 0xffffffff ) - return 1.0; - return info->opacity() * 1.0 / 0xffffffff; + return rule_opacity_inactive;// != 0 ; } -void Client::setOpacity( double opacity ) +uint Client::ruleOpacityActive() { - opacity = qBound( 0.0, opacity, 1.0 ); - info->setOpacity( static_cast< unsigned long >( opacity * 0xffffffff )); - // we'll react on PropertyNotify + return rule_opacity_active;// != 0; + } + +bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set + { + unsigned char *data = 0; + Atom actual; + int format, result; + unsigned long n, left; + result = XGetWindowProperty(QX11Info::display(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data); + if (result == Success && data != None && format == 32 ) + { + opacity_ = *reinterpret_cast< long* >( data ); + custom_opacity = true; +// setOpacity(opacity_ < 0xFFFFFFFF, opacity_); + XFree ((char*)data); + return true; + } + return false; + } + +void Client::setCustomOpacityFlag(bool custom) + { + custom_opacity = custom; + } + +uint Client::opacity() + { + return opacity_; } -void Client::debug( kdbgstream& stream ) const +int Client::opacityPercentage() { - stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'"; + return int(100*((double)opacity_/0xffffffff)); } + +bool Client::touches(const Client* c) +// checks if this client borders c, needed to test beep media player window state + { + if (y() == c->y() + c->height()) // this bottom to c + return true; + if (y() + height() == c->y()) // this top to c + return true; + if (x() == c->x() + c->width()) // this right to c + return true; + if (x() + width() == c->x()) // this left to c + return true; + return false; + } + +void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth) +{ + long data = (topHeight < 255 ? topHeight : 255) << 24 | + (rightWidth < 255 ? rightWidth : 255) << 16 | + (bottomHeight < 255 ? bottomHeight : 255) << 8 | + (leftWidth < 255 ? leftWidth : 255); + XChangeProperty(QX11Info::display(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L); +} + +void Client::unsetDecoHashProperty() +{ + XDeleteProperty( QX11Info::display(), frameId(), atoms->net_wm_window_decohash); +} + +#ifndef NDEBUG +kdbgstream& operator<<( kdbgstream& stream, const Client* cl ) + { + if( cl == NULL ) + return stream << "\'NULL_CLIENT\'"; + return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'"; + } +kdbgstream& operator<<( kdbgstream& stream, const ClientList& list ) + { + stream << "LIST:("; + bool first = true; + for( ClientList::ConstIterator it = list.begin(); + it != list.end(); + ++it ) + { + if( !first ) + stream << ":"; + first = false; + stream << *it; + } + stream << ")"; + return stream; + } +kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list ) + { + stream << "LIST:("; + bool first = true; + for( ConstClientList::ConstIterator it = list.begin(); + it != list.end(); + ++it ) + { + if( !first ) + stream << ":"; + first = false; + stream << *it; + } + stream << ")"; + return stream; + } +#endif QPixmap * kwin_get_menu_pix_hack() { diff --git a/geometry.cpp b/geometry.cpp index 9fdc3f7c33..c42d988c9c 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -28,7 +28,6 @@ License. See the file "COPYING" for the exact licensing terms. #include "notifications.h" #include "geometrytip.h" #include "rules.h" -#include "effects.h" #include #include @@ -634,18 +633,18 @@ void Workspace::updateTopMenuGeometry( Client* c ) if( c != NULL ) { XEvent ev; - ev.xclient.display = display(); + ev.xclient.display = QX11Info::display(); ev.xclient.type = ClientMessage; ev.xclient.window = c->window(); - static Atom msg_type_atom = XInternAtom( display(), "_KDE_TOPMENU_MINSIZE", False ); + static Atom msg_type_atom = XInternAtom( QX11Info::display(), "_KDE_TOPMENU_MINSIZE", False ); ev.xclient.message_type = msg_type_atom; ev.xclient.format = 32; - ev.xclient.data.l[0] = xTime(); + ev.xclient.data.l[0] = QX11Info::appTime(); ev.xclient.data.l[1] = topmenu_space->width(); ev.xclient.data.l[2] = topmenu_space->height(); ev.xclient.data.l[3] = 0; ev.xclient.data.l[4] = 0; - XSendEvent( display(), c->window(), False, NoEventMask, &ev ); + XSendEvent( QX11Info::display(), c->window(), False, NoEventMask, &ev ); KWin::setStrut( c->window(), 0, 0, topmenu_height, 0 ); // so that kicker etc. know c->checkWorkspacePosition(); return; @@ -781,25 +780,25 @@ NETExtendedStrut Client::strut() const { ext.left_width = str.left; ext.left_start = 0; - ext.left_end = displayHeight(); + ext.left_end = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display())); } if( str.right != 0 ) { ext.right_width = str.right; ext.right_start = 0; - ext.right_end = displayHeight(); + ext.right_end = XDisplayHeight( QX11Info::display(), DefaultScreen( QX11Info::display())); } if( str.top != 0 ) { ext.top_width = str.top; ext.top_start = 0; - ext.top_end = displayWidth(); + ext.top_end = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display())); } if( str.bottom != 0 ) { ext.bottom_width = str.bottom; ext.bottom_start = 0; - ext.bottom_end = displayWidth(); + ext.bottom_end = XDisplayWidth( QX11Info::display(), DefaultScreen( QX11Info::display())); } } return ext; @@ -1197,7 +1196,7 @@ QSize Client::sizeForClientSize( const QSize& wsize, Sizemode mode, bool noframe void Client::getWmNormalHints() { long msize; - if (XGetWMNormalHints(display(), window(), &xSizeHint, &msize) == 0 ) + if (XGetWMNormalHints(QX11Info::display(), window(), &xSizeHint, &msize) == 0 ) xSizeHint.flags = 0; // set defined values for the fields, even if they're not in flags @@ -1299,7 +1298,7 @@ void Client::sendSyntheticConfigureNotify() c.border_width = 0; c.above = None; c.override_redirect = 0; - XSendEvent( display(), c.event, true, StructureNotifyMask, (XEvent*)&c ); + XSendEvent( QX11Info::display(), c.event, true, StructureNotifyMask, (XEvent*)&c ); } const QPoint Client::calculateGravitation( bool invert, int gravity ) const @@ -1658,11 +1657,9 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force ) { client_size = QSize( w - border_left - border_right, h - border_top - border_bottom ); } - if( force == NormalGeometrySet && geom == QRect( x, y, w, h )) + if( force == NormalGeometrySet && frame_geometry == QRect( x, y, w, h )) return; - // TODO add damage only if not obscured - workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry - geom = QRect( x, y, w, h ); + frame_geometry = QRect( x, y, w, h ); updateWorkareaDiffs(); if( postpone_geometry_updates != 0 ) { @@ -1670,24 +1667,21 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force ) return; } resizeDecoration( QSize( w, h )); - XMoveResizeWindow( display(), frameId(), x, y, w, h ); + XMoveResizeWindow( QX11Info::display(), frameId(), x, y, w, h ); // resizeDecoration( QSize( w, h )); if( !isShade()) { QSize cs = clientSize(); - XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(), + XMoveResizeWindow( QX11Info::display(), wrapperId(), clientPos().x(), clientPos().y(), cs.width(), cs.height()); - XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height()); + XMoveResizeWindow( QX11Info::display(), window(), 0, 0, cs.width(), cs.height()); } - if( shape()) - updateShape(); + updateShape(); // SELI TODO won't this be too expensive? updateWorkareaDiffs(); sendSyntheticConfigureNotify(); updateWindowRules(); checkMaximizeGeometry(); - resetWindowPixmap(); - workspace()->addDamage( this, geometry()); } void Client::plainResize( int w, int h, ForceGeometry_t force ) @@ -1717,10 +1711,9 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) kDebug() << "forced size fail:" << QSize( w,h ) << ":" << rules()->checkSize( QSize( w, h )) << endl; kDebug() << kBacktrace() << endl; } - if( force == NormalGeometrySet && geom.size() == QSize( w, h )) + if( force == NormalGeometrySet && frame_geometry.size() == QSize( w, h )) return; - workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry - geom.setSize( QSize( w, h )); + frame_geometry.setSize( QSize( w, h )); updateWorkareaDiffs(); if( postpone_geometry_updates != 0 ) { @@ -1728,23 +1721,20 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) return; } resizeDecoration( QSize( w, h )); - XResizeWindow( display(), frameId(), w, h ); + XResizeWindow( QX11Info::display(), frameId(), w, h ); // resizeDecoration( QSize( w, h )); if( !isShade()) { QSize cs = clientSize(); - XMoveResizeWindow( display(), wrapperId(), clientPos().x(), clientPos().y(), + XMoveResizeWindow( QX11Info::display(), wrapperId(), clientPos().x(), clientPos().y(), cs.width(), cs.height()); - XMoveResizeWindow( display(), window(), 0, 0, cs.width(), cs.height()); + XMoveResizeWindow( QX11Info::display(), window(), 0, 0, cs.width(), cs.height()); } - if( shape()) - updateShape(); + updateShape(); updateWorkareaDiffs(); sendSyntheticConfigureNotify(); updateWindowRules(); checkMaximizeGeometry(); - resetWindowPixmap(); - workspace()->addDamage( this, geometry()); } /*! @@ -1752,23 +1742,22 @@ void Client::plainResize( int w, int h, ForceGeometry_t force ) */ void Client::move( int x, int y, ForceGeometry_t force ) { - if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y )) + if( force == NormalGeometrySet && frame_geometry.topLeft() == QPoint( x, y )) return; - workspace()->addDamage( this, geometry()); // TODO cache the previous real geometry - geom.moveTopLeft( QPoint( x, y )); + frame_geometry.moveTopLeft( QPoint( x, y )); updateWorkareaDiffs(); if( postpone_geometry_updates != 0 ) { pending_geometry_update = true; return; } - XMoveWindow( display(), frameId(), x, y ); + XMoveWindow( QX11Info::display(), frameId(), x, y ); sendSyntheticConfigureNotify(); updateWindowRules(); checkMaximizeGeometry(); - workspace()->addDamage( this, geometry()); } + void Client::postponeGeometryUpdates( bool postpone ) { if( postpone ) @@ -2231,18 +2220,18 @@ bool Client::startMoveResize() // (http://lists.kde.org/?t=107302193400001&r=1&w=2) XSetWindowAttributes attrs; QRect r = workspace()->clientArea( FullArea, this ); - move_resize_grab_window = XCreateWindow( display(), workspace()->rootWin(), r.x(), r.y(), + move_resize_grab_window = XCreateWindow( QX11Info::display(), workspace()->rootWin(), r.x(), r.y(), r.width(), r.height(), 0, CopyFromParent, InputOnly, CopyFromParent, 0, &attrs ); - XMapRaised( display(), move_resize_grab_window ); - if( XGrabPointer( display(), move_resize_grab_window, False, + XMapRaised( QX11Info::display(), move_resize_grab_window ); + if( XGrabPointer( QX11Info::display(), move_resize_grab_window, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask, - GrabModeAsync, GrabModeAsync, None, cursor.handle(), xTime() ) == Success ) + GrabModeAsync, GrabModeAsync, None, cursor.handle(), QX11Info::appTime() ) == Success ) has_grab = true; - if( XGrabKeyboard( display(), frameId(), False, GrabModeAsync, GrabModeAsync, xTime() ) == Success ) + if( XGrabKeyboard( QX11Info::display(), frameId(), False, GrabModeAsync, GrabModeAsync, QX11Info::appTime() ) == Success ) has_grab = true; if( !has_grab ) // at least one grab is necessary in order to be able to finish move/resize { - XDestroyWindow( display(), move_resize_grab_window ); + XDestroyWindow( QX11Info::display(), move_resize_grab_window ); move_resize_grab_window = None; return false; } @@ -2252,6 +2241,13 @@ bool Client::startMoveResize() workspace()->setClientIsMoving(this); initialMoveResizeGeom = moveResizeGeom = geometry(); checkUnrestrictedMoveResize(); + // rule out non opaque windows from useless translucency settings, maybe resizes? + if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove)) + setShadowSize(0); + if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque){ + savedOpacity_ = opacity_; + setOpacity(options->translucentMovingWindows, options->movingWindowOpacity); + } if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque ) || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) ) { @@ -2266,8 +2262,6 @@ bool Client::startMoveResize() // not needed anymore? kapp->installEventFilter( eater ); } Notify::raise( isResize() ? Notify::ResizeStart : Notify::MoveStart ); - if( effects ) - effects->windowUserMovedResized( this, true, false ); return true; } @@ -2281,12 +2275,15 @@ void Client::finishMoveResize( bool cancel ) checkMaximizeGeometry(); // FRAME update(); Notify::raise( isResize() ? Notify::ResizeEnd : Notify::MoveEnd ); - if( effects ) - effects->windowUserMovedResized( this, false, true ); } void Client::leaveMoveResize() { + // rule out non opaque windows from useless translucency settings, maybe resizes? + if (rules()->checkMoveResizeMode( options->moveMode ) == Options::Opaque) + setOpacity(true, savedOpacity_); + if ((isResize() && options->removeShadowsOnResize) || (isMove() && options->removeShadowsOnMove)) + updateShadowSize(); clearbound(); if (geometryTip) { @@ -2297,9 +2294,9 @@ void Client::leaveMoveResize() if ( ( isMove() && rules()->checkMoveResizeMode( options->moveMode ) != Options::Opaque ) || ( isResize() && rules()->checkMoveResizeMode( options->resizeMode ) != Options::Opaque ) ) ungrabXServer(); - XUngrabKeyboard( display(), xTime() ); - XUngrabPointer( display(), xTime() ); - XDestroyWindow( display(), move_resize_grab_window ); + XUngrabKeyboard( QX11Info::display(), QX11Info::appTime() ); + XUngrabPointer( QX11Info::display(), QX11Info::appTime() ); + XDestroyWindow( QX11Info::display(), move_resize_grab_window ); move_resize_grab_window = None; workspace()->setClientIsMoving(0); if( move_faked_activity ) @@ -2545,9 +2542,8 @@ void Client::handleMoveResize( int x, int y, int x_root, int y_root ) } // so the geometry tip will be painted above the outline } if ( isMove() ) - workspace()->clientMoved(globalPos, xTime()); - if( effects ) - effects->windowUserMovedResized( this, false, false ); + workspace()->clientMoved(globalPos, QX11Info::appTime()); } + } // namespace diff --git a/manage.cpp b/manage.cpp index a62482fffc..4c6e0a76a4 100644 --- a/manage.cpp +++ b/manage.cpp @@ -38,29 +38,22 @@ bool Client::manage( Window w, bool isMapped ) { StackingUpdatesBlocker stacking_blocker( workspace()); - grabXServer(); - XWindowAttributes attr; - if( !XGetWindowAttributes(display(), w, &attr)) - { - ungrabXServer(); + if( !XGetWindowAttributes(QX11Info::display(), w, &attr)) return false; - } + + grabXServer(); // from this place on, manage() mustn't return false postpone_geometry_updates = 1; pending_geometry_update = true; // force update when finishing with geometry changes embedClient( w, attr ); - - vis = attr.visual; - - setupCompositing(); // SELI order all these things in some sane manner bool init_minimize = false; - XWMHints * hints = XGetWMHints(display(), w ); + XWMHints * hints = XGetWMHints(QX11Info::display(), w ); if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState) init_minimize = true; if (hints) @@ -84,15 +77,14 @@ bool Client::manage( Window w, bool isMapped ) NET::WM2UserTime | NET::WM2StartupId | NET::WM2ExtendedStrut | - NET::WM2Opacity | 0; - info = new WinInfo( this, display(), client, rootWindow(), properties, 2 ); + info = new WinInfo( this, QX11Info::display(), client, QX11Info::appRootWindow(), properties, 2 ); cmap = attr.colormap; XClassHint classHint; - if ( XGetClassHint( display(), client, &classHint ) ) + if ( XGetClassHint( QX11Info::display(), client, &classHint ) ) { // Qt3.2 and older had this all lowercase, Qt3.3 capitalized resource class // force lowercase, so that workarounds listing resource classes still work @@ -114,6 +106,7 @@ bool Client::manage( Window w, bool isMapped ) setCaption( cap_normal, true ); detectNoBorder(); + detectShapable(); fetchIconicName(); getWMHints(); // needs to be done before readTransient() because of reading the group modal = ( info->state() & NET::Modal ) != 0; // needs to be valid before handling groups @@ -150,6 +143,8 @@ bool Client::manage( Window w, bool isMapped ) if( rules()->checkNoBorder( false, !isMapped )) setUserNoBorder( true ); + checkAndSetInitialRuledOpacity(); + // initial desktop placement if ( session ) { @@ -321,10 +316,9 @@ bool Client::manage( Window w, bool isMapped ) if(( !isSpecialWindow() || isToolbar()) && isMovable()) keepInArea( area, partial_keep_in_area ); - if( Extensions::shapeAvailable()) - XShapeSelectInput( display(), window(), ShapeNotifyMask ); - if ( (is_shape = hasShape( window())) ) - updateShape(); + XShapeSelectInput( QX11Info::display(), window(), ShapeNotifyMask ); + is_shape = Shape::hasShape( window()); + updateShape(); //CT extra check for stupid jdk 1.3.1. But should make sense in general // if client has initial state set to Iconic and is transient with a parent @@ -437,7 +431,7 @@ bool Client::manage( Window w, bool isMapped ) // this should avoid flicker, because real restacking is done // only after manage() finishes because of blocking, but the window is shown sooner - XLowerWindow( display(), frameId()); + XLowerWindow( QX11Info::display(), frameId()); if( session && session->stackingOrder != -1 ) { sm_stacking_order = session->stackingOrder; @@ -509,9 +503,9 @@ bool Client::manage( Window w, bool isMapped ) if( user_time == CurrentTime || user_time == -1U ) // no known user time, set something old { - user_time = xTime() - 1000000; + user_time = QX11Info::appTime() - 1000000; if( user_time == CurrentTime || user_time == -1U ) // let's be paranoid - user_time = xTime() - 1000000 + 10; + user_time = QX11Info::appTime() - 1000000 + 10; } updateWorkareaDiffs(); @@ -519,7 +513,7 @@ bool Client::manage( Window w, bool isMapped ) // sendSyntheticConfigureNotify(); done when setting mapping state delete session; - + ungrabXServer(); client_rules.discardTemporary(); @@ -537,35 +531,34 @@ bool Client::manage( Window w, bool isMapped ) void Client::embedClient( Window w, const XWindowAttributes &attr ) { assert( client == None ); - assert( frameId() == None ); + assert( frame == None ); assert( wrapper == None ); client = w; // we don't want the window to be destroyed when we are destroyed - XAddToSaveSet( display(), client ); - XSelectInput( display(), client, NoEventMask ); - XUnmapWindow( display(), client ); + XAddToSaveSet( QX11Info::display(), client ); + XSelectInput( QX11Info::display(), client, NoEventMask ); + XUnmapWindow( QX11Info::display(), client ); XWindowChanges wc; // set the border width to 0 wc.border_width = 0; // TODO possibly save this, and also use it for initial configuring of the window - XConfigureWindow( display(), client, CWBorderWidth, &wc ); + XConfigureWindow( QX11Info::display(), client, CWBorderWidth, &wc ); XSetWindowAttributes swa; swa.colormap = attr.colormap; swa.background_pixmap = None; swa.border_pixel = 0; - Window frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0, + frame = XCreateWindow( QX11Info::display(), QX11Info::appRootWindow(), 0, 0, 1, 1, 0, attr.depth, InputOutput, attr.visual, CWColormap | CWBackPixmap | CWBorderPixel, &swa ); - setHandle( frame ); - wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0, + wrapper = XCreateWindow( QX11Info::display(), frame, 0, 0, 1, 1, 0, attr.depth, InputOutput, attr.visual, CWColormap | CWBackPixmap | CWBorderPixel, &swa ); - XDefineCursor( display(), frame, QCursor( Qt::ArrowCursor ).handle()); + XDefineCursor( QX11Info::display(), frame, QCursor( Qt::ArrowCursor ).handle()); // some apps are stupid and don't define their own cursor - set the arrow one for them - XDefineCursor( display(), wrapper, QCursor( Qt::ArrowCursor ).handle()); - XReparentWindow( display(), client, wrapper, 0, 0 ); - XSelectInput( display(), frame, + XDefineCursor( QX11Info::display(), wrapper, QCursor( Qt::ArrowCursor ).handle()); + XReparentWindow( QX11Info::display(), client, wrapper, 0, 0 ); + XSelectInput( QX11Info::display(), frame, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | KeymapStateMask | @@ -577,8 +570,8 @@ void Client::embedClient( Window w, const XWindowAttributes &attr ) PropertyChangeMask | StructureNotifyMask | SubstructureRedirectMask | VisibilityChangeMask ); - XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask ); - XSelectInput( display(), client, + XSelectInput( QX11Info::display(), wrapper, ClientWinMask | SubstructureNotifyMask ); + XSelectInput( QX11Info::display(), client, FocusChangeMask | PropertyChangeMask | ColormapChangeMask | diff --git a/utils.cpp b/utils.cpp index 6d42a6b1f6..4492a42013 100644 --- a/utils.cpp +++ b/utils.cpp @@ -30,7 +30,6 @@ License. See the file "COPYING" for the exact licensing terms. #include #include #include - #include #include "atoms.h" @@ -43,54 +42,41 @@ namespace KWinInternal #ifndef KCMRULES -bool Extensions::has_shape = 0; -int Extensions::shape_event_base = 0; -bool Extensions::has_damage = 0; -int Extensions::damage_event_base = 0; -bool Extensions::has_composite = 0; -bool Extensions::has_fixes = 0; +// used to store the return values of +// XShapeQueryExtension. +// Necessary since shaped window are an extension to X +int Shape::kwin_shape_version = 0; +int Shape::kwin_shape_event = 0; -void Extensions::init() +// does the window w need a shape combine mask around it? +bool Shape::hasShape( WId w) { + int xws, yws, xbs, ybs; + unsigned int wws, hws, wbs, hbs; + int boundingShaped = 0, clipShaped = 0; + if (!available()) + return false; + XShapeQueryExtents(QX11Info::display(), w, + &boundingShaped, &xws, &yws, &wws, &hws, + &clipShaped, &xbs, &ybs, &wbs, &hbs); + return boundingShaped != 0; + } + +int Shape::shapeEvent() + { + return kwin_shape_event; + } + +void Shape::init() + { + kwin_shape_version = 0; int dummy; - has_shape = XShapeQueryExtension( display(), &shape_event_base, &dummy); -#ifdef HAVE_XDAMAGE - has_damage = XDamageQueryExtension( display(), &damage_event_base, &dummy ); -#else - has_damage = false; -#endif -#ifdef HAVE_XCOMPOSITE - has_composite = XCompositeQueryExtension( display(), &dummy, &dummy ); - if( has_composite ) - { - int major = 0; - int minor = 2; - XCompositeQueryVersion( display(), &major, &minor ); - if( major == 0 && minor < 2 ) - has_composite = false; - } -#else - has_composite = false; -#endif -#ifdef HAVE_XFIXES - has_fixes = XFixesQueryExtension( display(), &dummy, &dummy ); -#else - has_fixes = false; -#endif - } - -int Extensions::shapeNotifyEvent() - { - return shape_event_base + ShapeNotify; - } - -int Extensions::damageNotifyEvent() - { -#ifdef HAVE_XDAMAGE - return damage_event_base + XDamageNotify; -#else - return 0; -#endif + if( !XShapeQueryExtension( QX11Info::display(), &kwin_shape_event, &dummy )) + return; + int major, minor; + if( !XShapeQueryVersion( QX11Info::display(), &major, &minor )) + return; + kwin_shape_version = major * 16 + minor; } void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move, @@ -101,7 +87,7 @@ void Motif::readFlags( WId w, bool& noborder, bool& resize, bool& move, unsigned long length, after; unsigned char* data; MwmHints* hints = 0; - if ( XGetWindowProperty( display(), w, atoms->motif_wm_hints, 0, 5, + if ( XGetWindowProperty( QX11Info::display(), w, atoms->motif_wm_hints, 0, 5, false, atoms->motif_wm_hints, &type, &format, &length, &after, &data ) == Success ) { @@ -154,10 +140,10 @@ KWinSelectionOwner::KWinSelectionOwner( int screen_P ) Atom KWinSelectionOwner::make_selection_atom( int screen_P ) { if( screen_P < 0 ) - screen_P = DefaultScreen( display()); + screen_P = DefaultScreen( QX11Info::display()); char tmp[ 30 ]; sprintf( tmp, "WM_S%d", screen_P ); - return XInternAtom( display(), tmp, False ); + return XInternAtom( QX11Info::display(), tmp, False ); } void KWinSelectionOwner::getAtoms() @@ -168,7 +154,7 @@ void KWinSelectionOwner::getAtoms() Atom atoms[ 1 ]; const char* const names[] = { "VERSION" }; - XInternAtoms( display(), const_cast< char** >( names ), 1, False, atoms ); + XInternAtoms( QX11Info::display(), const_cast< char** >( names ), 1, False, atoms ); xa_version = atoms[ 0 ]; } } @@ -178,7 +164,7 @@ void KWinSelectionOwner::replyTargets( Atom property_P, Window requestor_P ) KSelectionOwner::replyTargets( property_P, requestor_P ); Atom atoms[ 1 ] = { xa_version }; // PropModeAppend ! - XChangeProperty( display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend, + XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_ATOM, 32, PropModeAppend, reinterpret_cast< unsigned char* >( atoms ), 1 ); } @@ -187,7 +173,7 @@ bool KWinSelectionOwner::genericReply( Atom target_P, Atom property_P, Window re if( target_P == xa_version ) { long version[] = { 2, 0 }; - XChangeProperty( display(), requestor_P, property_P, XA_INTEGER, 32, + XChangeProperty( QX11Info::display(), requestor_P, property_P, XA_INTEGER, 32, PropModeReplace, reinterpret_cast< unsigned char* >( &version ), 2 ); } else @@ -207,7 +193,7 @@ QByteArray getStringProperty(WId w, Atom prop, char separator) unsigned char *data = 0; QByteArray result = ""; KXErrorHandler handler; // ignore errors - status = XGetWindowProperty( display(), w, prop, 0, 10000, + status = XGetWindowProperty( QX11Info::display(), w, prop, 0, 10000, false, XA_STRING, &type, &format, &nitems, &extra, &data ); if ( status == Success) @@ -262,8 +248,8 @@ static Bool update_x_time_predicate( Display*, XEvent* event, XPointer ) } /* - Updates xTime(). This used to simply fetch current timestamp from the server, - but that can cause xTime() to be newer than timestamp of events that are + Updates QX11Info::appTime(). This used to simply fetch current timestamp from the server, + but that can cause QX11Info::appTime() to be newer than timestamp of events that are still in our events queue, thus e.g. making XSetInputFocus() caused by such event to be ignored. Therefore events queue is searched for first event with timestamp, and extra PropertyNotify is generated in order to make @@ -275,20 +261,20 @@ void updateXTime() if ( !w ) w = new QWidget; long data = 1; - XChangeProperty(display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32, + XChangeProperty(QX11Info::display(), w->winId(), atoms->kwin_running, atoms->kwin_running, 32, PropModeAppend, (unsigned char*) &data, 1); next_x_time = CurrentTime; XEvent dummy; - XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL ); + XCheckIfEvent( QX11Info::display(), &dummy, update_x_time_predicate, NULL ); if( next_x_time == CurrentTime ) { - XSync( display(), False ); - XCheckIfEvent( display(), &dummy, update_x_time_predicate, NULL ); + XSync( QX11Info::display(), False ); + XCheckIfEvent( QX11Info::display(), &dummy, update_x_time_predicate, NULL ); } assert( next_x_time != CurrentTime ); QX11Info::setAppTime( next_x_time ); XEvent ev; // remove the PropertyNotify event from the events queue - XWindowEvent( display(), w->winId(), PropertyChangeMask, &ev ); + XWindowEvent( QX11Info::display(), w->winId(), PropertyChangeMask, &ev ); } static int server_grab_count = 0; @@ -296,7 +282,7 @@ static int server_grab_count = 0; void grabXServer() { if( ++server_grab_count == 1 ) - XGrabServer( display()); + XGrabServer( QX11Info::display()); } void ungrabXServer() @@ -304,8 +290,8 @@ void ungrabXServer() assert( server_grab_count > 0 ); if( --server_grab_count == 0 ) { - XUngrabServer( display()); - XFlush( display()); + XUngrabServer( QX11Info::display()); + XFlush( QX11Info::display()); Notify::sendPendingEvents(); } } @@ -315,20 +301,6 @@ bool grabbedXServer() return server_grab_count > 0; } -kdbgstream& operator<<( kdbgstream& stream, RegionDebug r ) - { - if( r.rr == None ) - return stream << "EMPTY"; - int num; - XRectangle* rects = XFixesFetchRegion( display(), r.rr, &num ); - if( rects == NULL || num == 0 ) - return stream << "EMPTY"; - for( int i = 0; - i < num; - ++i ) - stream << "[" << rects[ i ].x << "+" << rects[ i ].y << " " << rects[ i ].width << "x" << rects[ i ].height << "]"; - return stream; - } #endif bool isLocalMachine( const QByteArray& host ) @@ -360,7 +332,7 @@ ShortcutDialog::ShortcutDialog( const KShortcut& cut ) // make it a popup, so that it has the grab XSetWindowAttributes attrs; attrs.override_redirect = True; - XChangeWindowAttributes( display(), winId(), CWOverrideRedirect, &attrs ); + XChangeWindowAttributes( QX11Info::display(), winId(), CWOverrideRedirect, &attrs ); setWindowFlags( Qt::Popup ); } @@ -395,6 +367,8 @@ void ShortcutDialog::accept() KShortcutDialog::accept(); } #endif + + } // namespace #ifndef KCMRULES diff --git a/utils.h b/utils.h index 564f78ee06..2c58ee0d0e 100644 --- a/utils.h +++ b/utils.h @@ -12,43 +12,15 @@ License. See the file "COPYING" for the exact licensing terms. #ifndef KWIN_UTILS_H #define KWIN_UTILS_H -#include - -#include -#ifdef HAVE_XCOMPOSITE -#include -#endif -#ifdef HAVE_XDAMAGE -#include -#endif -#ifdef HAVE_XFIXES -#include -#endif - -#include - #include #include #include #include #include -#include namespace KWinInternal { -#ifndef HAVE_XDAMAGE -typedef long Damage; -struct XDamageNotifyEvent - { - }; -#endif -#ifndef HAVE_XFIXES -struct XserverRegion - { - }; -#endif - const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask; @@ -66,18 +38,12 @@ const long ClientWinMask = KeyPressMask | KeyReleaseMask | const QPoint invalidPoint( INT_MIN, INT_MIN ); -class Toplevel; class Client; -class Unmanaged; class Group; class Options; -typedef QList< Toplevel* > ToplevelList; -typedef QList< const Toplevel* > ConstToplevelList; typedef QList< Client* > ClientList; typedef QList< const Client* > ConstClientList; -typedef QList< Unmanaged* > UnmanagedList; -typedef QList< const Unmanaged* > ConstUnmanagedList; typedef QList< Group* > GroupList; typedef QList< const Group* > ConstGroupList; @@ -120,20 +86,6 @@ enum allowed_t { Allowed }; // some enums to have more readable code, instead of using bools enum ForceGeometry_t { NormalGeometrySet, ForceGeometrySet }; - -struct RegionDebug - { - RegionDebug( XserverRegion r ) : rr( r ) {} - XserverRegion rr; - }; - -#ifdef NDEBUG -inline -kndbgstream& operator<<( kndbgstream& stream, RegionDebug ) { return stream; } -#else -kdbgstream& operator<<( kdbgstream& stream, RegionDebug r ); -#endif - // Areas, mostly related to Xinerama enum clientAreaOption { @@ -156,23 +108,18 @@ enum ShadeMode ShadeActivated // "shaded", but visible due to alt+tab to the window }; -class Extensions +class Shape { public: + static bool available() { return kwin_shape_version > 0; } + static int major() { return kwin_shape_version / 16; } + static int minor() { return kwin_shape_version % 16; } + static bool hasShape( WId w); + static int shapeEvent(); static void init(); - static bool shapeAvailable() { return has_shape; } - static int shapeNotifyEvent(); - static bool damageAvailable() { return has_damage; } - static int damageNotifyEvent(); - static bool compositeAvailable() { return has_composite; } - static bool fixesAvailable() { return has_fixes; } private: - static bool has_shape; - static int shape_event_base; - static bool has_damage; - static int damage_event_base; - static bool has_composite; - static bool has_fixes; + static int kwin_shape_version; // as 16*major+minor + static int kwin_shape_event; }; class Motif @@ -244,68 +191,34 @@ void grabXServer(); void ungrabXServer(); bool grabbedXServer(); -inline -Display* display() - { - return QX11Info::display(); - } - -inline -Window rootWindow() - { - return QX11Info::appRootWindow(); - } - -inline -Window xTime() - { - return QX11Info::appTime(); - } - -inline -int displayWidth() - { - return XDisplayWidth( display(), DefaultScreen( display())); - } - -inline -int displayHeight() - { - return XDisplayHeight( display(), DefaultScreen( display())); - } - -class Scene; -extern Scene* scene; -inline bool compositing() { return scene != NULL; } - // the docs say it's UrgencyHint, but it's often #defined as XUrgencyHint #ifndef UrgencyHint #define UrgencyHint XUrgencyHint #endif // for STL-like algo's -#define KWIN_CHECK_PREDICATE( name, cls, check ) \ +#define KWIN_CHECK_PREDICATE( name, check ) \ struct name \ { \ - inline bool operator()( const cls* cl ) { return check; }; \ + inline bool operator()( const Client* cl ) { return check; }; \ } -#define KWIN_COMPARE_PREDICATE( name, cls, type, check ) \ +#define KWIN_COMPARE_PREDICATE( name, type, check ) \ struct name \ { \ typedef type type_helper; /* in order to work also with type being 'const Client*' etc. */ \ inline name( const type_helper& compare_value ) : value( compare_value ) {}; \ - inline bool operator()( const cls* cl ) { return check; }; \ + inline bool operator()( const Client* cl ) { return check; }; \ const type_helper& value; \ } -#define KWIN_PROCEDURE( name, cls, action ) \ +#define KWIN_PROCEDURE( name, action ) \ struct name \ { \ - inline void operator()( cls* cl ) { action; }; \ + inline void operator()( Client* cl ) { action; }; \ } -KWIN_CHECK_PREDICATE( TruePredicate, Client, cl == cl /*true, avoid warning about 'cl' */ ); +KWIN_CHECK_PREDICATE( TruePredicate, cl == cl /*true, avoid warning about 'cl' */ ); template< typename T > Client* findClientInList( const ClientList& list, T predicate ) @@ -318,17 +231,6 @@ Client* findClientInList( const ClientList& list, T predicate ) return NULL; } -template< typename T > -Unmanaged* findUnmanagedInList( const UnmanagedList& list, T predicate ) - { - for ( UnmanagedList::ConstIterator it = list.begin(); it != list.end(); ++it) - { - if ( predicate( const_cast< const Unmanaged* >( *it))) - return *it; - } - return NULL; - } - inline int timestampCompare( Time time1, Time time2 ) // like strcmp() {