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