diff options
Diffstat (limited to 'kwin/manage.cpp')
-rw-r--r-- | kwin/manage.cpp | 600 |
1 files changed, 0 insertions, 600 deletions
diff --git a/kwin/manage.cpp b/kwin/manage.cpp deleted file mode 100644 index 85ba9adc9..000000000 --- a/kwin/manage.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/***************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org> -Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org> - -You can Freely distribute this program under the GNU General Public -License. See the file "COPYING" for the exact licensing terms. -******************************************************************/ - -/* - - This file contains things relevant to handling incoming events. - -*/ - -#include "client.h" - -#include <kstartupinfo.h> -#include <kglobal.h> -#include <X11/extensions/shape.h> - -#include "notifications.h" -#include "rules.h" -#include "group.h" - -namespace KWinInternal -{ - -/*! - Manages the clients. This means handling the very first maprequest: - reparenting, initial geometry, initial state, placement, etc. - Returns false if KWin is not going to manage this window. - */ -bool Client::manage( Window w, bool isMapped ) - { - XWindowAttributes attr; - if( !XGetWindowAttributes(qt_xdisplay(), 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 ); - - // SELI order all these things in some sane manner - - bool init_minimize = false; - XWMHints * hints = XGetWMHints(qt_xdisplay(), w ); - if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState) - init_minimize = true; - if (hints) - XFree(hints); - if( isMapped ) - init_minimize = false; // if it's already mapped, ignore hint - - unsigned long properties[ 2 ]; - properties[ WinInfo::PROTOCOLS ] = - NET::WMDesktop | - NET::WMState | - NET::WMWindowType | - NET::WMStrut | - NET::WMName | - NET::WMIconGeometry | - NET::WMIcon | - NET::WMPid | - NET::WMIconName | - 0; - properties[ WinInfo::PROTOCOLS2 ] = - NET::WM2UserTime | - NET::WM2StartupId | - NET::WM2ExtendedStrut | - 0; - - info = new WinInfo( this, qt_xdisplay(), client, qt_xrootwin(), properties, 2 ); - - cmap = attr.colormap; - - XClassHint classHint; - if ( XGetClassHint( qt_xdisplay(), 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 - resource_name = TQCString( classHint.res_name ).lower(); - resource_class = TQCString( classHint.res_class ).lower(); - XFree( classHint.res_name ); - XFree( classHint.res_class ); - } - ignore_focus_stealing = options->checkIgnoreFocusStealing( this ); // TODO change to rules - - window_role = staticWindowRole( w ); - getWmClientLeader(); - getWmClientMachine(); - // first only read the caption text, so that setupWindowRules() can use it for matching, - // and only then really set the caption using setCaption(), which checks for duplicates etc. - // and also relies on rules already existing - cap_normal = readName(); - setupWindowRules( false ); - 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 - readTransient(); - getIcons(); - getWindowProtocols(); - getWmNormalHints(); // get xSizeHint - getMotifHints(); - - // TODO try to obey all state information from info->state() - - original_skip_taskbar = skip_taskbar = ( info->state() & NET::SkipTaskbar) != 0; - skip_pager = ( info->state() & NET::SkipPager) != 0; - - KStartupInfoId asn_id; - KStartupInfoData asn_data; - bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data ); - - workspace()->updateClientLayer( this ); - - SessionInfo* session = workspace()->takeSessionInfo( this ); - - if ( session ) - { - if ( session->minimized ) - init_minimize = true; - if( session->userNoBorder ) - setUserNoBorder( true ); - } - - setShortcut( rules()->checkShortcut( session ? session->shortcut : TQString::null, true )); - - init_minimize = rules()->checkMinimize( init_minimize, !isMapped ); - if( rules()->checkNoBorder( false, !isMapped )) - setUserNoBorder( true ); - - checkAndSetInitialRuledOpacity(); - - // initial desktop placement - if ( session ) - { - desk = session->desktop; - if( session->onAllDesktops ) - desk = NET::OnAllDesktops; - } - else - { - // if this window is transient, ensure that it is opened on the - // same window as its parent. this is necessary when an application - // starts up on a different desktop than is currently displayed - if( isTransient()) - { - ClientList mainclients = mainClients(); - bool on_current = false; - Client* maincl = NULL; - // this is slightly duplicated from Placement::placeOnMainWindow() - for( ClientList::ConstIterator it = mainclients.begin(); - it != mainclients.end(); - ++it ) - { - if( mainclients.count() > 1 && (*it)->isSpecialWindow()) - continue; // don't consider toolbars etc when placing - maincl = *it; - if( (*it)->isOnCurrentDesktop()) - on_current = true; - } - if( on_current ) - desk = workspace()->currentDesktop(); - else if( maincl != NULL ) - desk = maincl->desktop(); - } - if ( info->desktop() ) - desk = info->desktop(); // window had the initial desktop property, force it - if( desktop() == 0 && asn_valid && asn_data.desktop() != 0 ) - desk = asn_data.desktop(); - } - if ( desk == 0 ) // assume window wants to be visible on the current desktop - desk = workspace()->currentDesktop(); - desk = rules()->checkDesktop( desk, !isMapped ); - if( desk != NET::OnAllDesktops ) // do range check - desk = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desk )); - info->setDesktop( desk ); - workspace()->updateOnAllDesktopsOfTransients( this ); // SELI -// onAllDesktopsChange(); decoration doesn't exist here yet - - TQRect geom( attr.x, attr.y, attr.width, attr.height ); - bool placementDone = FALSE; - - if ( session ) - geom = session->geometry; - - TQRect area; - bool partial_keep_in_area = isMapped || session; - if( isMapped || session ) - area = workspace()->clientArea( FullArea, geom.center(), desktop()); - else if( options->xineramaPlacementEnabled ) - { - int screen = options->xineramaPlacementScreen; - if( screen == -1 ) // active screen - screen = asn_data.xinerama() == -1 ? workspace()->activeScreen() : asn_data.xinerama(); - area = workspace()->clientArea( PlacementArea, workspace()->screenGeometry( screen ).center(), desktop()); - } - else - area = workspace()->clientArea( PlacementArea, TQCursor::pos(), desktop()); - - if( int type = checkFullScreenHack( geom )) - { - fullscreen_mode = FullScreenHack; - if( rules()->checkStrictGeometry( false )) - { - geom = type == 2 // 1 - it's xinerama-aware fullscreen hack, 2 - it's full area - ? workspace()->clientArea( FullArea, geom.center(), desktop()) - : workspace()->clientArea( ScreenArea, geom.center(), desktop()); - } - else - geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop()); - placementDone = true; - } - - if ( isDesktop() ) - { - // desktops are treated slightly special - geom = workspace()->clientArea( FullArea, geom.center(), desktop()); - placementDone = true; - } - - bool usePosition = false; - if ( isMapped || session || placementDone ) - placementDone = true; // use geometry - else if( isTransient() && !isUtility() && !isDialog() && !isSplash()) - usePosition = true; - else if( isTransient() && !hasNETSupport()) - usePosition = true; - else if( isDialog() && hasNETSupport()) - // if the dialog is actually non-NETWM transient window, don't try to apply placement to it, - // it breaks with too many things (xmms, display) - { - if( mainClients().count() >= 1 ) - { -#if 1 - // TODO #78082 - Ok, it seems there are after all some cases when an application has a good - // reason to specify a position for its dialog. Too bad other WMs have never bothered - // with placement for dialogs, so apps always specify positions for their dialogs, - // including such silly positions like always centered on the screen or under mouse. - // Using ignoring requested position in window-specific settings helps, but at least - // for Qt apps this should work better. - usePosition = true; -#else - ; // force using placement policy -#endif - } - else - usePosition = true; - } - else if( isSplash()) - ; // force using placement policy - else - usePosition = true; - if( !rules()->checkIgnoreGeometry( !usePosition )) - { - bool ignorePPosition = ( options->ignorePositionClasses.contains(TQString::tqfromLatin1(resourceClass()))); - - if ( ( (xSizeHint.flags & PPosition) && !ignorePPosition ) || - (xSizeHint.flags & USPosition) ) - { - placementDone = TRUE; - // disobey xinerama placement option for now (#70943) - area = workspace()->clientArea( PlacementArea, geom.center(), desktop()); - } - } - if( true ) // size is always obeyed for now, only with constraints applied - if ( (xSizeHint.flags & USSize) || (xSizeHint.flags & PSize) ) - { - // keep in mind that we now actually have a size :-) - } - - if (xSizeHint.flags & PMaxSize) - geom.setSize( geom.size().boundedTo( - rules()->checkMaxSize( TQSize(xSizeHint.max_width, xSizeHint.max_height ) ) ) ); - if (xSizeHint.flags & PMinSize) - geom.setSize( geom.size().expandedTo( - rules()->checkMinSize( TQSize(xSizeHint.min_width, xSizeHint.min_height ) ) ) ); - - if( isMovable()) - { - if( geom.x() > area.right() || geom.y() > area.bottom()) - placementDone = FALSE; // weird, do not trust. - } - - if ( placementDone ) - move( geom.x(), geom.y() ); // before gravitating - - updateDecoration( false ); // also gravitates - // TODO is CentralGravity right here, when resizing is done after gravitating? - plainResize( rules()->checkSize( sizeForClientSize( geom.size()), !isMapped )); - - TQPoint forced_pos = rules()->checkPosition( invalidPoint, !isMapped ); - if( forced_pos != invalidPoint ) - { - move( forced_pos ); - placementDone = true; - // don't keep inside workarea if the window has specially configured position - partial_keep_in_area = true; - area = workspace()->clientArea( FullArea, geom.center(), desktop()); - } - if( !placementDone ) - { // placement needs to be after setting size - workspace()->place( this, area ); - placementDone = TRUE; - } - - if(( !isSpecialWindow() || isToolbar()) && isMovable()) - keepInArea( area, partial_keep_in_area ); - - XShapeSelectInput( qt_xdisplay(), window(), ShapeNotifyMask ); - is_tqshape = 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 - // window that is not Iconic, set init_state to Normal - if( init_minimize && isTransient()) - { - ClientList mainclients = mainClients(); - for( ClientList::ConstIterator it = mainclients.begin(); - it != mainclients.end(); - ++it ) - if( (*it)->isShown( true )) - init_minimize = false; // SELI even e.g. for NET::Utility? - } - // if a dialog is shown for minimized window, minimize it too - if( !init_minimize && isTransient() && mainClients().count() > 0 ) - { - bool visible_parent = false; - ClientList mainclients = mainClients(); - for( ClientList::ConstIterator it = mainclients.begin(); - it != mainclients.end(); - ++it ) - if( (*it)->isShown( true )) - visible_parent = true; - if( !visible_parent ) - { - init_minimize = true; - demandAttention(); - } - } - - if( init_minimize ) - minimize( true ); // no animation - - // SELI this seems to be mainly for kstart and ksystraycmd - // probably should be replaced by something better - bool doNotShow = false; - if ( workspace()->isNotManaged( caption() ) ) - doNotShow = TRUE; - - // other settings from the previous session - if ( session ) - { - // session restored windows are not considered to be new windows WRT rules, - // i.e. obey only forcing rules - setKeepAbove( session->keepAbove ); - setKeepBelow( session->keepBelow ); - setSkipTaskbar( session->skipTaskbar, true ); - setSkipPager( session->skipPager ); - setShade( session->shaded ? ShadeNormal : ShadeNone ); - setShadowed( session->shadowed ); - if( session->maximized != MaximizeRestore ) - { - maximize( (MaximizeMode) session->maximized ); - geom_restore = session->restore; - } - if( session->fullscreen == FullScreenHack ) - ; // nothing, this should be already set again above - else if( session->fullscreen != FullScreenNone ) - { - setFullScreen( true, false ); - geom_fs_restore = session->fsrestore; - } - } - else - { - geom_restore = geometry(); // remember restore geometry - if ( isMaximizable() - && ( width() >= area.width() || height() >= area.height() ) ) - { - // window is too large for the screen, maximize in the - // directions necessary - if ( width() >= area.width() && height() >= area.height() ) - { - maximize( Client::MaximizeFull ); - geom_restore = TQRect(); // use placement when unmaximizing - } - else if ( width() >= area.width() ) - { - maximize( Client::MaximizeHorizontal ); - geom_restore = TQRect(); // use placement when unmaximizing - geom_restore.setY( y()); // but only for horizontal direction - geom_restore.setHeight( height()); - } - else if ( height() >= area.height() ) - { - maximize( Client::MaximizeVertical ); - geom_restore = TQRect(); // use placement when unmaximizing - geom_restore.setX( x()); // but only for vertical direction - geom_restore.setWidth( width()); - } - } - // window may want to be maximized - // done after checking that the window isn't larger than the workarea, so that - // the restore geometry from the checks above takes precedence, and window - // isn't restored larger than the workarea - MaximizeMode maxmode = static_cast< MaximizeMode > - ((( info->state() & NET::MaxVert ) ? MaximizeVertical : 0 ) - | (( info->state() & NET::MaxHoriz ) ? MaximizeHorizontal : 0 )); - MaximizeMode forced_maxmode = rules()->checkMaximize( maxmode, !isMapped ); - // either hints were set to maximize, or is forced to maximize, - // or is forced to non-maximize and hints were set to maximize - if( forced_maxmode != MaximizeRestore || maxmode != MaximizeRestore ) - maximize( forced_maxmode ); - - // read other initial states - setShade( rules()->checkShade( info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped )); - setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped )); - setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped )); - setSkipTaskbar( rules()->checkSkipTaskbar( info->state() & NET::SkipTaskbar, !isMapped ), true ); - setSkipPager( rules()->checkSkipPager( info->state() & NET::SkipPager, !isMapped )); - if( info->state() & NET::DemandsAttention ) - demandAttention(); - if( info->state() & NET::Modal ) - setModal( true ); - if( fullscreen_mode != FullScreenHack && isFullScreenable()) - setFullScreen( rules()->checkFullScreen( info->state() & NET::FullScreen, !isMapped ), false ); - } - - updateAllowedActions( true ); - - // TODO this should avoid flicker, because real restacking is done - // only after manage() finishes, but the window is shown sooner - // - keep it? - XLowerWindow( qt_xdisplay(), frameId()); - - // set initial user time directly - user_time = readUserTimeMapTimestamp( asn_valid ? &asn_id : NULL, asn_valid ? &asn_data : NULL, session ); - group()->updateUserTime( user_time ); // and do what Client::updateUserTime() does - - if( isTopMenu()) // they're shown in Workspace::addClient() if their mainwindow - hideClient( true ); // is the active one - - if( isShown( true ) && !doNotShow ) - { - if( isDialog()) - Notify::raise( Notify::TransNew ); - if( isNormalWindow()) - Notify::raise( Notify::New ); - - bool allow; - if( session ) - allow = session->active - && ( !workspace()->wasUserInteraction() - || workspace()->activeClient() == NULL || workspace()->activeClient()->isDesktop()); - else - allow = workspace()->allowClientActivation( this, userTime(), false ); - - // if session saving, force showing new windows (i.e. "save file?" dialogs etc.) - // also force if activation is allowed - if( !isOnCurrentDesktop() && !isMapped && !session && ( allow || workspace()->sessionSaving())) - workspace()->setCurrentDesktop( desktop()); - - bool belongs_to_desktop = false; - for( ClientList::ConstIterator it = group()->members().begin(); - it != group()->members().end(); - ++it ) - if( (*it)->isDesktop()) - { - belongs_to_desktop = true; - break; - } - if( !belongs_to_desktop && workspace()->showingDesktop()) - workspace()->resetShowingDesktop( options->showDesktopIsMinimizeAll ); - - if( isOnCurrentDesktop() && !isMapped && !allow ) - workspace()->restackClientUnderActive( this ); - else - workspace()->raiseClient( this ); - - updateVisibility(); - - if( !isMapped ) - { - if( allow && isOnCurrentDesktop()) - { - if( !isSpecialWindow()) - if ( options->focusPolicyIsReasonable() && wantsTabFocus() ) - workspace()->requestFocus( this ); - } - else - { - if( !session && !isSpecialWindow()) - demandAttention(); - } - } - } - else if( !doNotShow ) // if( !isShown( true ) && !doNotShow ) - { - updateVisibility(); - } - else // doNotShow - { // SELI HACK !!! - hideClient( true ); - setMappingState( IconicState ); - } - assert( mappingState() != WithdrawnState ); - - if( user_time == CurrentTime || user_time == -1U ) // no known user time, set something old - { - user_time = GET_QT_X_TIME() - 1000000; - if( user_time == CurrentTime || user_time == -1U ) // let's be paranoid - user_time = GET_QT_X_TIME() - 1000000 + 10; - } - - updateWorkareaDiffs(); - -// sendSyntheticConfigureNotify(); done when setting mapping state - - delete session; - - ungrabXServer(); - - client_rules.discardTemporary(); - applyWindowRules(); // just in case - workspace()->discardUsedWindowRules( this, false ); // remove ApplyNow rules - updateWindowRules(); // was blocked while !isManaged() - -// TODO there's a small problem here - isManaged() depends on the mapping state, -// but this client is not yet in Workspace's client list at this point, will -// be only done in addClient() - return true; - } - -// called only from manage() -void Client::embedClient( Window w, const XWindowAttributes &attr ) - { - assert( client == None ); - assert( frame == None ); - assert( wrapper == None ); - client = w; - // we don't want the window to be destroyed when we are destroyed - XAddToSaveSet( qt_xdisplay(), client ); - XSelectInput( qt_xdisplay(), client, NoEventMask ); - XUnmapWindow( qt_xdisplay(), 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( qt_xdisplay(), client, CWBorderWidth, &wc ); - - XSetWindowAttributes swa; - swa.colormap = attr.colormap; - swa.background_pixmap = None; - swa.border_pixel = 0; - - frame = XCreateWindow( qt_xdisplay(), qt_xrootwin(), 0, 0, 1, 1, 0, - attr.depth, InputOutput, attr.visual, - CWColormap | CWBackPixmap | CWBorderPixel, &swa ); - wrapper = XCreateWindow( qt_xdisplay(), frame, 0, 0, 1, 1, 0, - attr.depth, InputOutput, attr.visual, - CWColormap | CWBackPixmap | CWBorderPixel, &swa ); - - XDefineCursor( qt_xdisplay(), frame, tqarrowCursor.handle()); - // some apps are stupid and don't define their own cursor - set the arrow one for them - XDefineCursor( qt_xdisplay(), wrapper, tqarrowCursor.handle()); - XReparentWindow( qt_xdisplay(), client, wrapper, 0, 0 ); - XSelectInput( qt_xdisplay(), frame, - KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | - KeymapStateMask | - ButtonMotionMask | - PointerMotionMask | - EnterWindowMask | LeaveWindowMask | - FocusChangeMask | - ExposureMask | - PropertyChangeMask | - StructureNotifyMask | SubstructureRedirectMask ); - XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask ); - XSelectInput( qt_xdisplay(), client, - FocusChangeMask | - PropertyChangeMask | - ColormapChangeMask | - EnterWindowMask | LeaveWindowMask | - KeyPressMask | KeyReleaseMask - ); - updateMouseGrab(); - } - -} // namespace |