00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "client.h"
00029
00030 #include <kstartupinfo.h>
00031 #include <kglobal.h>
00032 #include <X11/extensions/shape.h>
00033
00034 #include "notifications.h"
00035 #include <QX11Info>
00036 #include "rules.h"
00037 #include "group.h"
00038
00039 namespace KWin
00040 {
00041
00047 bool Client::manage( Window w, bool isMapped )
00048 {
00049 StackingUpdatesBlocker stacking_blocker( workspace());
00050
00051 grabXServer();
00052
00053 XWindowAttributes attr;
00054 if( !XGetWindowAttributes(display(), w, &attr))
00055 {
00056 ungrabXServer();
00057 return false;
00058 }
00059
00060
00061 block_geometry_updates = 1;
00062 pending_geometry_update = PendingGeometryForced;
00063
00064 embedClient( w, attr );
00065
00066 vis = attr.visual;
00067 bit_depth = attr.depth;
00068
00069 setupCompositing();
00070
00071
00072
00073 bool init_minimize = false;
00074 XWMHints * hints = XGetWMHints(display(), w );
00075 if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState)
00076 init_minimize = true;
00077 if (hints)
00078 XFree(hints);
00079 if( isMapped )
00080 init_minimize = false;
00081
00082 unsigned long properties[ 2 ];
00083 properties[ WinInfo::PROTOCOLS ] =
00084 NET::WMDesktop |
00085 NET::WMState |
00086 NET::WMWindowType |
00087 NET::WMStrut |
00088 NET::WMName |
00089 NET::WMIconGeometry |
00090 NET::WMIcon |
00091 NET::WMPid |
00092 NET::WMIconName |
00093 0;
00094 properties[ WinInfo::PROTOCOLS2 ] =
00095 NET::WM2UserTime |
00096 NET::WM2StartupId |
00097 NET::WM2ExtendedStrut |
00098 NET::WM2Opacity |
00099 0;
00100
00101 info = new WinInfo( this, display(), client, rootWindow(), properties, 2 );
00102
00103 cmap = attr.colormap;
00104
00105 getResourceClass();
00106 getWindowRole();
00107 getWmClientLeader();
00108 getWmClientMachine();
00109 getSyncCounter();
00110
00111
00112
00113 cap_normal = readName();
00114 setupWindowRules( false );
00115 ignore_focus_stealing = options->checkIgnoreFocusStealing( this );
00116 setCaption( cap_normal, true );
00117
00118 if( Extensions::shapeAvailable())
00119 XShapeSelectInput( display(), window(), ShapeNotifyMask );
00120 detectShape( window());
00121 detectNoBorder();
00122 fetchIconicName();
00123 getWMHints();
00124 modal = ( info->state() & NET::Modal ) != 0;
00125 readTransient();
00126 getIcons();
00127 getWindowProtocols();
00128 getWmNormalHints();
00129 getMotifHints();
00130
00131
00132
00133 original_skip_taskbar = skip_taskbar = ( info->state() & NET::SkipTaskbar) != 0;
00134 skip_pager = ( info->state() & NET::SkipPager) != 0;
00135
00136 KStartupInfoId asn_id;
00137 KStartupInfoData asn_data;
00138 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
00139
00140 workspace()->updateClientLayer( this );
00141
00142 SessionInfo* session = workspace()->takeSessionInfo( this );
00143 if( session )
00144 {
00145 init_minimize = session->minimized;
00146 noborder = session->noBorder;
00147 }
00148
00149 setShortcut( rules()->checkShortcut( session ? session->shortcut : QString(), true ));
00150
00151 init_minimize = rules()->checkMinimize( init_minimize, !isMapped );
00152 noborder = rules()->checkNoBorder( noborder, !isMapped );
00153
00154
00155 if ( session )
00156 {
00157 desk = session->desktop;
00158 if( session->onAllDesktops )
00159 desk = NET::OnAllDesktops;
00160 }
00161 else
00162 {
00163
00164
00165
00166 if( isTransient())
00167 {
00168 ClientList mainclients = mainClients();
00169 bool on_current = false;
00170 Client* maincl = NULL;
00171
00172 for( ClientList::ConstIterator it = mainclients.begin();
00173 it != mainclients.end();
00174 ++it )
00175 {
00176 if( mainclients.count() > 1 && (*it)->isSpecialWindow())
00177 continue;
00178 maincl = *it;
00179 if( (*it)->isOnCurrentDesktop())
00180 on_current = true;
00181 }
00182 if( on_current )
00183 desk = workspace()->currentDesktop();
00184 else if( maincl != NULL )
00185 desk = maincl->desktop();
00186 }
00187 if ( info->desktop() )
00188 desk = info->desktop();
00189 if( desktop() == 0 && asn_valid && asn_data.desktop() != 0 )
00190 desk = asn_data.desktop();
00191 }
00192 if ( desk == 0 )
00193 desk = workspace()->currentDesktop();
00194 desk = rules()->checkDesktop( desk, !isMapped );
00195 if( desk != NET::OnAllDesktops )
00196 desk = qMax( 1, qMin( workspace()->numberOfDesktops(), desk ));
00197 info->setDesktop( desk );
00198 workspace()->updateOnAllDesktopsOfTransients( this );
00199
00200
00201 QRect geom( attr.x, attr.y, attr.width, attr.height );
00202 bool placementDone = false;
00203
00204 if ( session )
00205 geom = session->geometry;
00206
00207 QRect area;
00208 bool partial_keep_in_area = isMapped || session;
00209 if( isMapped || session )
00210 area = workspace()->clientArea( FullArea, geom.center(), desktop());
00211 else if( options->xineramaPlacementEnabled )
00212 {
00213 int screen = options->xineramaPlacementScreen;
00214 if( screen == -1 )
00215 screen = asn_data.xinerama() == -1 ? workspace()->activeScreen() : asn_data.xinerama();
00216 area = workspace()->clientArea( PlacementArea, workspace()->screenGeometry( screen ).center(), desktop());
00217 }
00218 else
00219 area = workspace()->clientArea( PlacementArea, cursorPos(), desktop());
00220
00221 if( int type = checkFullScreenHack( geom ))
00222 {
00223 fullscreen_mode = FullScreenHack;
00224 if( rules()->checkStrictGeometry( false ))
00225 {
00226 geom = type == 2
00227 ? workspace()->clientArea( FullArea, geom.center(), desktop())
00228 : workspace()->clientArea( ScreenArea, geom.center(), desktop());
00229 }
00230 else
00231 geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop());
00232 placementDone = true;
00233 }
00234
00235 if ( isDesktop() )
00236 {
00237
00238 if (geom != workspace()->clientArea( ScreenArea, geom.center(), desktop()))
00239 {
00240 geom = workspace()->clientArea( FullArea, geom.center(), desktop());
00241 }
00242 placementDone = true;
00243 }
00244
00245 bool usePosition = false;
00246 if ( isMapped || session || placementDone )
00247 placementDone = true;
00248 else if( isTransient() && !isUtility() && !isDialog() && !isSplash())
00249 usePosition = true;
00250 else if( isTransient() && !hasNETSupport())
00251 usePosition = true;
00252 else if( isDialog() && hasNETSupport())
00253
00254
00255 {
00256 if( mainClients().count() >= 1 )
00257 {
00258 #if 1
00259
00260
00261
00262
00263
00264
00265 usePosition = true;
00266 #else
00267 ;
00268 #endif
00269 }
00270 else
00271 usePosition = true;
00272 }
00273 else if( isSplash())
00274 ;
00275 else
00276 usePosition = true;
00277 if( !rules()->checkIgnoreGeometry( !usePosition ))
00278 {
00279 bool ignorePPosition = ( options->ignorePositionClasses.contains(QString::fromLatin1(resourceClass())));
00280
00281 if ( ( (xSizeHint.flags & PPosition) && !ignorePPosition ) ||
00282 (xSizeHint.flags & USPosition) )
00283 {
00284 placementDone = true;
00285
00286 area = workspace()->clientArea( PlacementArea, geom.center(), desktop());
00287 }
00288 }
00289 if( true )
00290 if ( (xSizeHint.flags & USSize) || (xSizeHint.flags & PSize) )
00291 {
00292
00293 }
00294
00295 if (xSizeHint.flags & PMaxSize)
00296 geom.setSize( geom.size().boundedTo(
00297 rules()->checkMaxSize( QSize(xSizeHint.max_width, xSizeHint.max_height ) ) ) );
00298 if (xSizeHint.flags & PMinSize)
00299 geom.setSize( geom.size().expandedTo(
00300 rules()->checkMinSize( QSize(xSizeHint.min_width, xSizeHint.min_height ) ) ) );
00301
00302 if( isMovable())
00303 {
00304 if( geom.x() > area.right() || geom.y() > area.bottom())
00305 placementDone = false;
00306 }
00307
00308 if ( placementDone )
00309 move( geom.x(), geom.y() );
00310
00311 updateDecoration( false );
00312
00313 plainResize( rules()->checkSize( sizeForClientSize( geom.size()), !isMapped ));
00314
00315 QPoint forced_pos = rules()->checkPosition( invalidPoint, !isMapped );
00316 if( forced_pos != invalidPoint )
00317 {
00318 move( forced_pos );
00319 placementDone = true;
00320
00321 partial_keep_in_area = true;
00322 area = workspace()->clientArea( FullArea, geom.center(), desktop());
00323 }
00324 if( !placementDone )
00325 {
00326 workspace()->place( this, area );
00327 placementDone = true;
00328 }
00329
00330 if(( !isSpecialWindow() || isToolbar()) && isMovable())
00331 keepInArea( area, partial_keep_in_area );
00332
00333 updateShape();
00334
00335
00336
00337
00338 if( init_minimize && isTransient())
00339 {
00340 ClientList mainclients = mainClients();
00341 for( ClientList::ConstIterator it = mainclients.begin();
00342 it != mainclients.end();
00343 ++it )
00344 if( (*it)->isShown( true ))
00345 init_minimize = false;
00346 }
00347
00348 if( !init_minimize && isTransient() && mainClients().count() > 0 )
00349 {
00350 bool visible_parent = false;
00351
00352
00353 ClientList mainclients = allMainClients();
00354 for( ClientList::ConstIterator it = mainclients.begin();
00355 it != mainclients.end();
00356 ++it )
00357 if( (*it)->isShown( true ))
00358 visible_parent = true;
00359 if( !visible_parent )
00360 {
00361 init_minimize = true;
00362 demandAttention();
00363 }
00364 }
00365
00366 if( init_minimize )
00367 minimize( true );
00368
00369
00370
00371 bool doNotShow = false;
00372 if ( workspace()->isNotManaged( caption() ) )
00373 doNotShow = true;
00374
00375
00376 if ( session )
00377 {
00378
00379
00380 setKeepAbove( session->keepAbove );
00381 setKeepBelow( session->keepBelow );
00382 setSkipTaskbar( session->skipTaskbar, true );
00383 setSkipPager( session->skipPager );
00384 setShade( session->shaded ? ShadeNormal : ShadeNone );
00385 if( session->maximized != MaximizeRestore )
00386 {
00387 maximize( (MaximizeMode) session->maximized );
00388 geom_restore = session->restore;
00389 }
00390 if( session->fullscreen == FullScreenHack )
00391 ;
00392 else if( session->fullscreen != FullScreenNone )
00393 {
00394 setFullScreen( true, false );
00395 geom_fs_restore = session->fsrestore;
00396 }
00397 }
00398 else
00399 {
00400 geom_restore = geometry();
00401 if ( isMaximizable()
00402 && ( width() >= area.width() || height() >= area.height() ) )
00403 {
00404
00405
00406 if ( width() >= area.width() && height() >= area.height() )
00407 {
00408 maximize( Client::MaximizeFull );
00409 geom_restore = QRect();
00410 }
00411 else if ( width() >= area.width() )
00412 {
00413 maximize( Client::MaximizeHorizontal );
00414 geom_restore = QRect();
00415 geom_restore.setY( y());
00416 geom_restore.setHeight( height());
00417 }
00418 else if ( height() >= area.height() )
00419 {
00420 maximize( Client::MaximizeVertical );
00421 geom_restore = QRect();
00422 geom_restore.setX( x());
00423 geom_restore.setWidth( width());
00424 }
00425 }
00426
00427
00428
00429
00430 MaximizeMode maxmode = static_cast< MaximizeMode >
00431 ((( info->state() & NET::MaxVert ) ? MaximizeVertical : 0 )
00432 | (( info->state() & NET::MaxHoriz ) ? MaximizeHorizontal : 0 ));
00433 MaximizeMode forced_maxmode = rules()->checkMaximize( maxmode, !isMapped );
00434
00435
00436 if( forced_maxmode != MaximizeRestore || maxmode != MaximizeRestore )
00437 maximize( forced_maxmode );
00438
00439
00440 setShade( rules()->checkShade( info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped ));
00441 setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped ));
00442 setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped ));
00443 setSkipTaskbar( rules()->checkSkipTaskbar( info->state() & NET::SkipTaskbar, !isMapped ), true );
00444 setSkipPager( rules()->checkSkipPager( info->state() & NET::SkipPager, !isMapped ));
00445 if( info->state() & NET::DemandsAttention )
00446 demandAttention();
00447 if( info->state() & NET::Modal )
00448 setModal( true );
00449 if( fullscreen_mode != FullScreenHack && isFullScreenable())
00450 setFullScreen( rules()->checkFullScreen( info->state() & NET::FullScreen, !isMapped ), false );
00451 }
00452
00453 updateAllowedActions( true );
00454
00455
00456 user_time = readUserTimeMapTimestamp( asn_valid ? &asn_id : NULL, asn_valid ? &asn_data : NULL, session );
00457 group()->updateUserTime( user_time );
00458
00459 if( isTopMenu())
00460 hideClient( true );
00461
00462
00463
00464 XLowerWindow( display(), frameId());
00465 if( session && session->stackingOrder != -1 )
00466 {
00467 sm_stacking_order = session->stackingOrder;
00468 workspace()->restoreSessionStackingOrder( this );
00469 }
00470
00471 if( compositing())
00472 sendSyncRequest();
00473
00474 if( isShown( true ) && !doNotShow )
00475 {
00476 if( isDialog())
00477 Notify::raise( Notify::TransNew );
00478 if( isNormalWindow())
00479 Notify::raise( Notify::New );
00480
00481 bool allow;
00482 if( session )
00483 allow = session->active
00484 && ( !workspace()->wasUserInteraction()
00485 || workspace()->activeClient() == NULL || workspace()->activeClient()->isDesktop());
00486 else
00487 allow = workspace()->allowClientActivation( this, userTime(), false );
00488
00489
00490
00491 if( !isOnCurrentDesktop() && !isMapped && !session && ( allow || workspace()->sessionSaving()))
00492 workspace()->setCurrentDesktop( desktop());
00493
00494 bool belongs_to_desktop = false;
00495 for( ClientList::ConstIterator it = group()->members().begin();
00496 it != group()->members().end();
00497 ++it )
00498 if( (*it)->isDesktop())
00499 {
00500 belongs_to_desktop = true;
00501 break;
00502 }
00503 if( !belongs_to_desktop && workspace()->showingDesktop())
00504 workspace()->resetShowingDesktop( options->showDesktopIsMinimizeAll );
00505
00506 if( isOnCurrentDesktop() && !isMapped && !allow && (!session || session->stackingOrder < 0 ))
00507 workspace()->restackClientUnderActive( this );
00508
00509 updateVisibility();
00510
00511 if( !isMapped )
00512 {
00513 if( allow && isOnCurrentDesktop())
00514 {
00515 if( !isSpecialWindow())
00516 if ( options->focusPolicyIsReasonable() && wantsTabFocus() )
00517 workspace()->requestFocus( this );
00518 }
00519 else
00520 {
00521 if( !session && !isSpecialWindow())
00522 demandAttention();
00523 }
00524 }
00525 }
00526 else if( !doNotShow )
00527 {
00528 updateVisibility();
00529 }
00530 else
00531 {
00532 hideClient( true );
00533 setMappingState( IconicState );
00534 }
00535 assert( mappingState() != WithdrawnState );
00536
00537 if( user_time == CurrentTime || user_time == -1U )
00538 {
00539 user_time = xTime() - 1000000;
00540 if( user_time == CurrentTime || user_time == -1U )
00541 user_time = xTime() - 1000000 + 10;
00542 }
00543
00544 updateWorkareaDiffs();
00545
00546
00547
00548 delete session;
00549
00550 ungrabXServer();
00551
00552 client_rules.discardTemporary();
00553 applyWindowRules();
00554 workspace()->discardUsedWindowRules( this, false );
00555 updateWindowRules();
00556
00557
00558
00559
00560 return true;
00561 }
00562
00563
00564 void Client::embedClient( Window w, const XWindowAttributes &attr )
00565 {
00566 assert( client == None );
00567 assert( frameId() == None );
00568 assert( wrapper == None );
00569 client = w;
00570
00571 XAddToSaveSet( display(), client );
00572 XSelectInput( display(), client, NoEventMask );
00573 XUnmapWindow( display(), client );
00574 XWindowChanges wc;
00575 wc.border_width = 0;
00576 XConfigureWindow( display(), client, CWBorderWidth, &wc );
00577
00578 XSetWindowAttributes swa;
00579 swa.colormap = attr.colormap;
00580 swa.background_pixmap = None;
00581 swa.border_pixel = 0;
00582
00583 Window frame = XCreateWindow( display(), rootWindow(), 0, 0, 1, 1, 0,
00584 attr.depth, InputOutput, attr.visual,
00585 CWColormap | CWBackPixmap | CWBorderPixel, &swa );
00586 setWindowHandles( client, frame );
00587 wrapper = XCreateWindow( display(), frame, 0, 0, 1, 1, 0,
00588 attr.depth, InputOutput, attr.visual,
00589 CWColormap | CWBackPixmap | CWBorderPixel, &swa );
00590
00591 XDefineCursor( display(), frame, QCursor( Qt::ArrowCursor ).handle());
00592
00593 XDefineCursor( display(), wrapper, QCursor( Qt::ArrowCursor ).handle());
00594 XReparentWindow( display(), client, wrapper, 0, 0 );
00595 XSelectInput( display(), frame,
00596 KeyPressMask | KeyReleaseMask |
00597 ButtonPressMask | ButtonReleaseMask |
00598 KeymapStateMask |
00599 ButtonMotionMask |
00600 PointerMotionMask |
00601 EnterWindowMask | LeaveWindowMask |
00602 FocusChangeMask |
00603 ExposureMask |
00604 PropertyChangeMask |
00605 StructureNotifyMask | SubstructureRedirectMask );
00606 XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
00607 XSelectInput( display(), client,
00608 FocusChangeMask |
00609 PropertyChangeMask |
00610 ColormapChangeMask |
00611 EnterWindowMask | LeaveWindowMask |
00612 KeyPressMask | KeyReleaseMask
00613 );
00614 updateMouseGrab();
00615 }
00616
00617 }