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