00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "client.h"
00023
00024 #include <QApplication>
00025 #include <QPainter>
00026 #include <QDateTime>
00027 #include <QProcess>
00028 #include <unistd.h>
00029 #include <kstandarddirs.h>
00030 #include <QWhatsThis>
00031 #include <kwindowsystem.h>
00032 #include <kiconloader.h>
00033 #include <stdlib.h>
00034 #include <signal.h>
00035
00036 #include "bridge.h"
00037 #include "group.h"
00038 #include "workspace.h"
00039 #include "atoms.h"
00040 #include "notifications.h"
00041 #include "rules.h"
00042 #include "scene.h"
00043 #include "effects.h"
00044 #include "deleted.h"
00045
00046 #include <X11/extensions/shape.h>
00047 #include <QX11Info>
00048
00049 #ifdef HAVE_XSYNC
00050 #include <X11/extensions/sync.h>
00051 #endif
00052
00053
00054
00055
00056 namespace KWin
00057 {
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00083 Client::Client( Workspace *ws )
00084 : Toplevel( ws ),
00085 client( None ),
00086 wrapper( None ),
00087 decoration( NULL ),
00088 bridge( new Bridge( this )),
00089 move_faked_activity( false ),
00090 move_resize_grab_window( None ),
00091 move_resize_has_keyboard_grab( false ),
00092 transient_for( NULL ),
00093 transient_for_id( None ),
00094 original_transient_for_id( None ),
00095 autoRaiseTimer( NULL ),
00096 shadeHoverTimer( NULL ),
00097 delayedMoveResizeTimer( NULL ),
00098 in_group( NULL ),
00099 window_group( None ),
00100 in_layer( UnknownLayer ),
00101 ping_timer( NULL ),
00102 process_killer( NULL ),
00103 user_time( CurrentTime ),
00104 allowed_actions( 0 ),
00105 block_geometry_updates( 0 ),
00106 pending_geometry_update( PendingGeometryNone ),
00107 shade_geometry_change( false ),
00108 #ifdef HAVE_XSYNC
00109 sync_counter( None ),
00110 sync_alarm( None ),
00111 #endif
00112 sync_timeout( NULL ),
00113 sync_resize_pending( false ),
00114 border_left( 0 ),
00115 border_right( 0 ),
00116 border_top( 0 ),
00117 border_bottom( 0 ),
00118 sm_stacking_order( -1 ),
00119 demandAttentionKNotifyTimer( NULL )
00120
00121 {
00122
00123
00124 mapping_state = WithdrawnState;
00125 desk = 0;
00126
00127 mode = PositionCenter;
00128 buttonDown = false;
00129 moveResizeMode = false;
00130
00131 info = NULL;
00132
00133 shade_mode = ShadeNone;
00134 active = false;
00135 deleting = false;
00136 keep_above = false;
00137 keep_below = false;
00138 motif_may_move = true;
00139 motif_may_resize = true;
00140 motif_may_close = true;
00141 fullscreen_mode = FullScreenNone;
00142 skip_taskbar = false;
00143 original_skip_taskbar = false;
00144 minimized = false;
00145 hidden = false;
00146 modal = false;
00147 noborder = false;
00148 app_noborder = false;
00149 urgency = false;
00150 ignore_focus_stealing = false;
00151 demands_attention = false;
00152 hidden_preview = false;
00153 raw_shown = false;
00154 check_active_modal = false;
00155
00156 Pdeletewindow = 0;
00157 Ptakefocus = 0;
00158 Ptakeactivity = 0;
00159 Pcontexthelp = 0;
00160 Pping = 0;
00161 input = false;
00162 skip_pager = false;
00163
00164 max_mode = MaximizeRestore;
00165 maxmode_restore = MaximizeRestore;
00166
00167 cmap = None;
00168
00169 geom = QRect( 0, 0, 100, 100 );
00170 client_size = QSize( 100, 100 );
00171 #if defined(HAVE_XSYNC) || defined(HAVE_XDAMAGE)
00172 ready_for_painting = false;
00173 #endif
00174
00175
00176 }
00177
00181 Client::~Client()
00182 {
00183 #ifdef HAVE_XSYNC
00184 if( sync_alarm != None )
00185 XSyncDestroyAlarm( display(), sync_alarm );
00186 #endif
00187 assert(!moveResizeMode);
00188 assert( client == None );
00189 assert( wrapper == None );
00190
00191 assert( decoration == NULL );
00192 assert( block_geometry_updates == 0 );
00193 assert( !check_active_modal );
00194 delete bridge;
00195 }
00196
00197
00198 void Client::deleteClient( Client* c, allowed_t )
00199 {
00200 delete c;
00201 }
00202
00206 void Client::releaseWindow( bool on_shutdown )
00207 {
00208 assert( !deleting );
00209 deleting = true;
00210 Deleted* del = Deleted::create( this );
00211 if( effects )
00212 {
00213 static_cast<EffectsHandlerImpl*>(effects)->windowClosed( effectWindow());
00214 scene->windowClosed( this, del );
00215 }
00216 finishCompositing();
00217 workspace()->discardUsedWindowRules( this, true );
00218 StackingUpdatesBlocker blocker( workspace());
00219 if (moveResizeMode)
00220 leaveMoveResize();
00221 finishWindowRules();
00222 ++block_geometry_updates;
00223 if( isOnCurrentDesktop() && isShown( true ))
00224 addWorkspaceRepaint( geometry());
00225
00226
00227 grabXServer();
00228 setMappingState( WithdrawnState );
00229 setModal( false );
00230 hidden = true;
00231 if( !on_shutdown )
00232 workspace()->clientHidden( this );
00233 XUnmapWindow( display(), frameId());
00234 destroyDecoration();
00235 cleanGrouping();
00236 if( !on_shutdown )
00237 {
00238 workspace()->removeClient( this, Allowed );
00239
00240
00241 info->setDesktop( 0 );
00242 desk = 0;
00243 info->setState( 0, info->state());
00244 }
00245 XDeleteProperty( display(), client, atoms->kde_net_wm_user_creation_time);
00246 XDeleteProperty( display(), client, atoms->net_frame_extents );
00247 XDeleteProperty( display(), client, atoms->kde_net_wm_frame_strut );
00248 XReparentWindow( display(), client, rootWindow(), x(), y());
00249 XRemoveFromSaveSet( display(), client );
00250 XSelectInput( display(), client, NoEventMask );
00251 if( on_shutdown )
00252 {
00253 XMapWindow( display(), client );
00254
00255 }
00256 else
00257 {
00258
00259
00260 XUnmapWindow( display(), client );
00261 }
00262 client = None;
00263 XDestroyWindow( display(), wrapper );
00264 wrapper = None;
00265 XDestroyWindow( display(), frameId());
00266
00267 --block_geometry_updates;
00268 disownDataPassedToDeleted();
00269 del->unrefWindow();
00270 checkNonExistentClients();
00271 deleteClient( this, Allowed );
00272 ungrabXServer();
00273 }
00274
00275
00276
00277 void Client::destroyClient()
00278 {
00279 assert( !deleting );
00280 deleting = true;
00281 Deleted* del = Deleted::create( this );
00282 if( effects )
00283 {
00284 static_cast<EffectsHandlerImpl*>(effects)->windowClosed( effectWindow());
00285 scene->windowClosed( this, del );
00286 }
00287 finishCompositing();
00288 workspace()->discardUsedWindowRules( this, true );
00289 StackingUpdatesBlocker blocker( workspace());
00290 if (moveResizeMode)
00291 leaveMoveResize();
00292 finishWindowRules();
00293 ++block_geometry_updates;
00294 if( isOnCurrentDesktop() && isShown( true ))
00295 addWorkspaceRepaint( geometry());
00296 setModal( false );
00297 hidden = true;
00298 workspace()->clientHidden( this );
00299 destroyDecoration();
00300 cleanGrouping();
00301 workspace()->removeClient( this, Allowed );
00302 client = None;
00303 XDestroyWindow( display(), wrapper );
00304 wrapper = None;
00305 XDestroyWindow( display(), frameId());
00306
00307 --block_geometry_updates;
00308 disownDataPassedToDeleted();
00309 del->unrefWindow();
00310 checkNonExistentClients();
00311 deleteClient( this, Allowed );
00312 }
00313
00314 void Client::updateDecoration( bool check_workspace_pos, bool force )
00315 {
00316 if( !force && (( decoration == NULL && noBorder())
00317 || ( decoration != NULL && !noBorder())))
00318 return;
00319 bool do_show = false;
00320 QRect oldgeom = geometry();
00321 blockGeometryUpdates( true );
00322 if( force )
00323 destroyDecoration();
00324 if( !noBorder())
00325 {
00326 setMask( QRegion());
00327 decoration = workspace()->createDecoration( bridge );
00328
00329 decoration->init();
00330 decoration->widget()->installEventFilter( this );
00331 XReparentWindow( display(), decoration->widget()->winId(), frameId(), 0, 0 );
00332 decoration->widget()->lower();
00333 decoration->borders( border_left, border_right, border_top, border_bottom );
00334 int save_workarea_diff_x = workarea_diff_x;
00335 int save_workarea_diff_y = workarea_diff_y;
00336 move( calculateGravitation( false ));
00337 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00338 workarea_diff_x = save_workarea_diff_x;
00339 workarea_diff_y = save_workarea_diff_y;
00340 do_show = true;
00341 if( compositing() )
00342 discardWindowPixmap();
00343 if( scene != NULL )
00344 scene->windowGeometryShapeChanged( this );
00345 if( effects != NULL )
00346 static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), oldgeom );
00347 }
00348 else
00349 destroyDecoration();
00350 if( check_workspace_pos )
00351 checkWorkspacePosition();
00352 blockGeometryUpdates( false );
00353 if( do_show )
00354 decoration->widget()->show();
00355 updateFrameExtents();
00356 }
00357
00358 void Client::destroyDecoration()
00359 {
00360 QRect oldgeom = geometry();
00361 if( decoration != NULL )
00362 {
00363 delete decoration;
00364 decoration = NULL;
00365 QPoint grav = calculateGravitation( true );
00366 border_left = border_right = border_top = border_bottom = 0;
00367 setMask( QRegion());
00368 int save_workarea_diff_x = workarea_diff_x;
00369 int save_workarea_diff_y = workarea_diff_y;
00370 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00371 move( grav );
00372 workarea_diff_x = save_workarea_diff_x;
00373 workarea_diff_y = save_workarea_diff_y;
00374 if( compositing() )
00375 discardWindowPixmap();
00376 if( scene != NULL && !deleting )
00377 scene->windowGeometryShapeChanged( this );
00378 if( effects != NULL && !deleting )
00379 static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), oldgeom );
00380 }
00381 }
00382
00383 bool Client::checkBorderSizes( bool also_resize )
00384 {
00385 if( decoration == NULL )
00386 return false;
00387 int new_left, new_right, new_top, new_bottom;
00388 decoration->borders( new_left, new_right, new_top, new_bottom );
00389 if( new_left == border_left && new_right == border_right
00390 && new_top == border_top && new_bottom == border_bottom )
00391 return false;
00392 if( !also_resize )
00393 {
00394 border_left = new_left;
00395 border_right = new_right;
00396 border_top = new_top;
00397 border_bottom = new_bottom;
00398 return true;
00399 }
00400 GeometryUpdatesBlocker blocker( this );
00401 move( calculateGravitation( true ));
00402 border_left = new_left;
00403 border_right = new_right;
00404 border_top = new_top;
00405 border_bottom = new_bottom;
00406 move( calculateGravitation( false ));
00407 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00408 checkWorkspacePosition();
00409 return true;
00410 }
00411
00412 void Client::repaintDecoration()
00413 {
00414 if( decoration != NULL )
00415 decoration->widget()->update();
00416 }
00417
00418 void Client::detectNoBorder()
00419 {
00420 if( shape())
00421 {
00422 noborder = true;
00423 app_noborder = true;
00424 return;
00425 }
00426 switch( windowType())
00427 {
00428 case NET::Desktop :
00429 case NET::Dock :
00430 case NET::TopMenu :
00431 case NET::Splash :
00432 noborder = true;
00433 app_noborder = true;
00434 break;
00435 case NET::Unknown :
00436 case NET::Normal :
00437 case NET::Toolbar :
00438 case NET::Menu :
00439 case NET::Dialog :
00440 case NET::Utility :
00441 noborder = false;
00442 break;
00443 default:
00444 assert( false );
00445 }
00446
00447
00448
00449 if( info->windowType( SUPPORTED_MANAGED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
00450 {
00451 noborder = true;
00452 app_noborder = true;
00453 }
00454 }
00455
00456 void Client::updateFrameExtents()
00457 {
00458 NETStrut strut;
00459 strut.left = border_left;
00460 strut.right = border_right;
00461 strut.top = border_top;
00462 strut.bottom = border_bottom;
00463 info->setFrameExtents( strut );
00464 }
00465
00466
00467
00468
00469
00470
00471 void Client::resizeDecoration( const QSize& s )
00472 {
00473 if( decoration == NULL )
00474 return;
00475 QSize oldsize = decoration->widget()->size();
00476 decoration->resize( s );
00477 if( oldsize == s )
00478 {
00479 QResizeEvent e( s, oldsize );
00480 QApplication::sendEvent( decoration->widget(), &e );
00481 }
00482 }
00483
00484 bool Client::noBorder() const
00485 {
00486 return noborder || isFullScreen();
00487 }
00488
00489 bool Client::userCanSetNoBorder() const
00490 {
00491 return !isFullScreen() && !isShade();
00492 }
00493
00494 void Client::setNoBorder( bool set )
00495 {
00496 if( !userCanSetNoBorder())
00497 return;
00498 set = rules()->checkNoBorder( set );
00499 if( noborder == set )
00500 return;
00501 noborder = set;
00502 updateDecoration( true, false );
00503 updateWindowRules();
00504 }
00505
00506 void Client::updateShape()
00507 {
00508
00509 if( shape())
00510 {
00511 if( !app_noborder )
00512 {
00513 app_noborder = true;
00514 noborder = true;
00515 updateDecoration( true );
00516 }
00517 }
00518 if( shape() && noBorder())
00519 XShapeCombineShape( display(), frameId(), ShapeBounding,
00520 clientPos().x(), clientPos().y(), window(), ShapeBounding, ShapeSet );
00521
00522
00523 updateInputShape();
00524 if( compositing())
00525 addDamageFull();
00526 if( scene != NULL )
00527 scene->windowGeometryShapeChanged( this );
00528 if( effects != NULL )
00529 static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
00530 }
00531
00532 static Window shape_helper_window = None;
00533
00534 void Client::updateInputShape()
00535 {
00536 if( hidden_preview )
00537 return;
00538 if( Extensions::shapeInputAvailable())
00539 {
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 if( shape_helper_window == None )
00550 shape_helper_window = XCreateSimpleWindow( display(), rootWindow(),
00551 0, 0, 1, 1, 0, 0, 0 );
00552 XResizeWindow( display(), shape_helper_window, width(), height());
00553 XShapeCombineShape( display(), shape_helper_window, ShapeInput, 0, 0,
00554 frameId(), ShapeBounding, ShapeSet );
00555 XShapeCombineShape( display(), shape_helper_window, ShapeInput,
00556 clientPos().x(), clientPos().y(),
00557 window(), ShapeBounding, ShapeSubtract );
00558 XShapeCombineShape( display(), shape_helper_window, ShapeInput,
00559 clientPos().x(), clientPos().y(),
00560 window(), ShapeInput, ShapeUnion );
00561 XShapeCombineShape( display(), frameId(), ShapeInput, 0, 0,
00562 shape_helper_window, ShapeInput, ShapeSet );
00563 }
00564 }
00565
00566 void Client::setMask( const QRegion& reg, int mode )
00567 {
00568 if( _mask == reg )
00569 return;
00570 _mask = reg;
00571 Window shape_window = frameId();
00572 if( shape())
00573 {
00574
00575 if( shape_helper_window == None )
00576 shape_helper_window = XCreateSimpleWindow( display(), rootWindow(),
00577 0, 0, 1, 1, 0, 0, 0 );
00578 shape_window = shape_helper_window;
00579 }
00580 if( reg.isEmpty())
00581 XShapeCombineMask( display(), shape_window, ShapeBounding, 0, 0,
00582 None, ShapeSet );
00583 else if( mode == X::Unsorted )
00584 XShapeCombineRegion( display(), shape_window, ShapeBounding, 0, 0,
00585 reg.handle(), ShapeSet );
00586 else
00587 {
00588 QVector< QRect > rects = reg.rects();
00589 XRectangle* xrects = new XRectangle[ rects.count() ];
00590 for( int i = 0;
00591 i < rects.count();
00592 ++i )
00593 {
00594 xrects[ i ].x = rects[ i ].x();
00595 xrects[ i ].y = rects[ i ].y();
00596 xrects[ i ].width = rects[ i ].width();
00597 xrects[ i ].height = rects[ i ].height();
00598 }
00599 XShapeCombineRectangles( display(), shape_window, ShapeBounding, 0, 0,
00600 xrects, rects.count(), ShapeSet, mode );
00601 delete[] xrects;
00602 }
00603 if( shape())
00604 {
00605 XRectangle rec = { 0, 0, clientSize().width(), clientSize().height() };
00606 XShapeCombineRectangles( display(), shape_helper_window, ShapeBounding,
00607 clientPos().x(), clientPos().y(), &rec, 1, ShapeSubtract, Unsorted );
00608 XShapeCombineShape( display(), shape_helper_window, ShapeBounding,
00609 clientPos().x(), clientPos().y(),
00610 window(), ShapeBounding, ShapeUnion );
00611 XShapeCombineShape( display(), frameId(), ShapeBounding, 0, 0,
00612 shape_helper_window, ShapeBounding, ShapeSet );
00613 }
00614 if( compositing())
00615 addDamageFull();
00616 if( scene != NULL )
00617 scene->windowGeometryShapeChanged( this );
00618 if( effects != NULL )
00619 static_cast<EffectsHandlerImpl*>(effects)->windowGeometryShapeChanged( effectWindow(), geometry());
00620 updateShape();
00621 }
00622
00623 QRegion Client::mask() const
00624 {
00625 if( _mask.isEmpty())
00626 return QRegion( 0, 0, width(), height());
00627 return _mask;
00628 }
00629
00630 void Client::hideClient( bool hide )
00631 {
00632 if( hidden == hide )
00633 return;
00634 hidden = hide;
00635 updateVisibility();
00636 }
00637
00638
00639
00640
00641 bool Client::isMinimizable() const
00642 {
00643 if( isSpecialWindow())
00644 return false;
00645 if( isTransient())
00646 {
00647 bool shown_mainwindow = false;
00648 ClientList mainclients = mainClients();
00649 for( ClientList::ConstIterator it = mainclients.begin();
00650 it != mainclients.end();
00651 ++it )
00652 {
00653 if( (*it)->isShown( true ))
00654 shown_mainwindow = true;
00655 }
00656 if( !shown_mainwindow )
00657 return true;
00658 }
00659
00660
00661
00662 if( transientFor() != NULL )
00663 return false;
00664 if( !wantsTabFocus())
00665 return false;
00666 return true;
00667 }
00668
00672 void Client::minimize( bool avoid_animation )
00673 {
00674 if ( !isMinimizable() || isMinimized())
00675 return;
00676
00677 Notify::raise( Notify::Minimize );
00678
00679 minimized = true;
00680
00681 updateVisibility();
00682 updateAllowedActions();
00683 workspace()->updateMinimizedOfTransients( this );
00684 updateWindowRules();
00685 workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
00686 if( effects && !avoid_animation )
00687 static_cast<EffectsHandlerImpl*>(effects)->windowMinimized( effectWindow());
00688 }
00689
00690 void Client::unminimize( bool avoid_animation )
00691 {
00692 if( !isMinimized())
00693 return;
00694
00695 Notify::raise( Notify::UnMinimize );
00696 minimized = false;
00697 updateVisibility();
00698 updateAllowedActions();
00699 workspace()->updateMinimizedOfTransients( this );
00700 updateWindowRules();
00701 if( effects && !avoid_animation )
00702 static_cast<EffectsHandlerImpl*>(effects)->windowUnminimized( effectWindow());
00703 }
00704
00705 QRect Client::iconGeometry() const
00706 {
00707 NETRect r = info->iconGeometry();
00708 QRect geom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00709 if( geom.isValid() )
00710 return geom;
00711 else
00712 {
00713
00714 foreach( Client* mainwin, mainClients() )
00715 {
00716 geom = mainwin->iconGeometry();
00717 if( geom.isValid() )
00718 return geom;
00719 }
00720
00721 return QRect();
00722 }
00723 }
00724
00725 bool Client::isShadeable() const
00726 {
00727 return !isSpecialWindow() && !noBorder();
00728 }
00729
00730 void Client::setShade( ShadeMode mode )
00731 {
00732 if( !isShadeable())
00733 return;
00734 mode = rules()->checkShade( mode );
00735 if( shade_mode == mode )
00736 return;
00737 bool was_shade = isShade();
00738 ShadeMode was_shade_mode = shade_mode;
00739 shade_mode = mode;
00740 if( was_shade == isShade())
00741 {
00742 if( decoration != NULL )
00743 decoration->shadeChange();
00744 return;
00745 }
00746
00747 if( shade_mode == ShadeNormal )
00748 {
00749 if ( isShown( true ) && isOnCurrentDesktop())
00750 Notify::raise( Notify::ShadeUp );
00751 }
00752 else if( shade_mode == ShadeNone )
00753 {
00754 if( isShown( true ) && isOnCurrentDesktop())
00755 Notify::raise( Notify::ShadeDown );
00756 }
00757
00758 assert( decoration != NULL );
00759 GeometryUpdatesBlocker blocker( this );
00760
00761 decoration->borders( border_left, border_right, border_top, border_bottom );
00762
00763
00764 if ( isShade())
00765 {
00766 addWorkspaceRepaint( geometry());
00767
00768 shade_geometry_change = true;
00769 QSize s( sizeForClientSize( QSize( clientSize())));
00770 s.setHeight( border_top + border_bottom );
00771 XSelectInput( display(), wrapper, ClientWinMask );
00772 XUnmapWindow( display(), wrapper );
00773 XUnmapWindow( display(), client );
00774 XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
00775 plainResize( s );
00776 shade_geometry_change = false;
00777 if( isActive())
00778 {
00779 if( was_shade_mode == ShadeHover )
00780 workspace()->activateNextClient( this );
00781 else
00782 workspace()->focusToNull();
00783 }
00784 }
00785 else
00786 {
00787 shade_geometry_change = true;
00788 QSize s( sizeForClientSize( clientSize()));
00789 shade_geometry_change = false;
00790 plainResize( s );
00791 if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00792 setActive( true );
00793 XMapWindow( display(), wrapperId());
00794 XMapWindow( display(), window());
00795 if ( isActive() )
00796 workspace()->requestFocus( this );
00797 }
00798 checkMaximizeGeometry();
00799 info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00800 info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00801 discardWindowPixmap();
00802 updateVisibility();
00803 updateAllowedActions();
00804 workspace()->updateMinimizedOfTransients( this );
00805 decoration->shadeChange();
00806 updateWindowRules();
00807 }
00808
00809 void Client::shadeHover()
00810 {
00811 setShade( ShadeHover );
00812 cancelShadeHover();
00813 }
00814
00815 void Client::cancelShadeHover()
00816 {
00817 delete shadeHoverTimer;
00818 shadeHoverTimer = 0;
00819 }
00820
00821 void Client::toggleShade()
00822 {
00823
00824 setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00825 }
00826
00827 void Client::updateVisibility()
00828 {
00829 if( deleting )
00830 return;
00831 bool show = true;
00832 if( hidden )
00833 {
00834 setMappingState( IconicState );
00835 info->setState( NET::Hidden, NET::Hidden );
00836 setSkipTaskbar( true, false );
00837 rawHide();
00838 show = false;
00839 }
00840 else
00841 {
00842 setSkipTaskbar( original_skip_taskbar, false );
00843 }
00844 if( minimized )
00845 {
00846 setMappingState( IconicState );
00847 info->setState( NET::Hidden, NET::Hidden );
00848 rawHide();
00849 show = false;
00850 }
00851 if( show )
00852 info->setState( 0, NET::Hidden );
00853 if( !isOnCurrentDesktop())
00854 {
00855 setMappingState( IconicState );
00856 rawHide();
00857 show = false;
00858 }
00859 if( show )
00860 {
00861 bool belongs_to_desktop = false;
00862 for( ClientList::ConstIterator it = group()->members().begin();
00863 it != group()->members().end();
00864 ++it )
00865 if( (*it)->isDesktop())
00866 {
00867 belongs_to_desktop = true;
00868 break;
00869 }
00870 if( !belongs_to_desktop && workspace()->showingDesktop())
00871 workspace()->resetShowingDesktop( true );
00872 if( isShade())
00873 setMappingState( IconicState );
00874 else
00875 setMappingState( NormalState );
00876 rawShow();
00877 }
00878 }
00879
00884 void Client::setMappingState(int s)
00885 {
00886 assert( client != None );
00887 assert( !deleting || s == WithdrawnState );
00888 if( mapping_state == s )
00889 return;
00890 bool was_unmanaged = ( mapping_state == WithdrawnState );
00891 mapping_state = s;
00892 if( mapping_state == WithdrawnState )
00893 {
00894 XDeleteProperty( display(), window(), atoms->wm_state );
00895 return;
00896 }
00897 assert( s == NormalState || s == IconicState );
00898
00899 unsigned long data[2];
00900 data[0] = (unsigned long) s;
00901 data[1] = (unsigned long) None;
00902 XChangeProperty(display(), window(), atoms->wm_state, atoms->wm_state, 32,
00903 PropModeReplace, (unsigned char *)data, 2);
00904
00905 if( was_unmanaged )
00906 blockGeometryUpdates( false );
00907 }
00908
00913 void Client::rawShow()
00914 {
00915 if( raw_shown )
00916 return;
00917 raw_shown = true;
00918 if( decoration != NULL )
00919 decoration->widget()->show();
00920 XMapWindow( display(), frameId());
00921 if( !isShade())
00922 {
00923 XMapWindow( display(), wrapper );
00924 XMapWindow( display(), client );
00925 }
00926 if( options->hiddenPreviews == HiddenPreviewsNever )
00927 {
00928
00929
00930
00931 if( compositing() )
00932 discardWindowPixmap();
00933 }
00934 else
00935 {
00936 if( hidden_preview )
00937 setHiddenPreview( false, Allowed );
00938 }
00939 }
00940
00946 void Client::rawHide()
00947 {
00948 if( !raw_shown )
00949 return;
00950 raw_shown = false;
00951 StackingUpdatesBlocker blocker( workspace());
00952 addWorkspaceRepaint( geometry());
00953 if( options->hiddenPreviews == HiddenPreviewsNever )
00954 {
00955
00956
00957
00958
00959
00960
00961 XSelectInput( display(), wrapper, ClientWinMask );
00962 XUnmapWindow( display(), frameId());
00963 XUnmapWindow( display(), wrapper );
00964 XUnmapWindow( display(), client );
00965 XSelectInput( display(), wrapper, ClientWinMask | SubstructureNotifyMask );
00966 if( decoration != NULL )
00967 decoration->widget()->hide();
00968 }
00969 else
00970 {
00971 if( !hidden_preview )
00972 {
00973 setHiddenPreview( true, Allowed );
00974
00975 if( decoration != NULL )
00976 decoration->widget()->show();
00977 XMapWindow( display(), frameId());
00978 if( !isShade())
00979 {
00980 XMapWindow( display(), wrapper );
00981 XMapWindow( display(), client );
00982 }
00983 }
00984 }
00985 workspace()->clientHidden( this );
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997 void Client::setHiddenPreview( bool set, allowed_t )
00998 {
00999 if( set && !hidden_preview )
01000 {
01001 hidden_preview = true;
01002 workspace()->forceRestacking();
01003 if( Extensions::shapeInputAvailable())
01004 XShapeCombineRectangles( display(), frameId(), ShapeInput, 0, 0, NULL, 0, ShapeSet, Unsorted );
01005 }
01006 else if( !set && hidden_preview )
01007 {
01008 hidden_preview = false;
01009 workspace()->forceRestacking();
01010 updateInputShape();
01011 }
01012 }
01013
01014 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
01015 {
01016 XEvent ev;
01017 long mask;
01018
01019 memset(&ev, 0, sizeof(ev));
01020 ev.xclient.type = ClientMessage;
01021 ev.xclient.window = w;
01022 ev.xclient.message_type = a;
01023 ev.xclient.format = 32;
01024 ev.xclient.data.l[0] = protocol;
01025 ev.xclient.data.l[1] = xTime();
01026 ev.xclient.data.l[2] = data1;
01027 ev.xclient.data.l[3] = data2;
01028 ev.xclient.data.l[4] = data3;
01029 mask = 0L;
01030 if (w == rootWindow())
01031 mask = SubstructureRedirectMask;
01032 XSendEvent(display(), w, False, mask, &ev);
01033 }
01034
01035
01036
01037
01038 bool Client::isCloseable() const
01039 {
01040 return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
01041 }
01042
01047 void Client::closeWindow()
01048 {
01049 if( !isCloseable())
01050 return;
01051
01052 updateUserTime();
01053 if ( Pdeletewindow )
01054 {
01055 Notify::raise( Notify::Close );
01056 sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
01057 pingWindow();
01058 }
01059 else
01060 {
01061
01062
01063 killWindow();
01064 }
01065 }
01066
01067
01071 void Client::killWindow()
01072 {
01073 kDebug( 1212 ) << "Client::killWindow():" << caption();
01074
01075
01076 Notify::raise( Notify::Close );
01077
01078 if( isDialog())
01079 Notify::raise( Notify::TransDelete );
01080 if( isNormalWindow())
01081 Notify::raise( Notify::Delete );
01082 killProcess( false );
01083
01084 XKillClient(display(), window() );
01085 destroyClient();
01086 }
01087
01088
01089
01090
01091 void Client::pingWindow()
01092 {
01093 if( !Pping )
01094 return;
01095 if( options->killPingTimeout == 0 )
01096 return;
01097 if( ping_timer != NULL )
01098 return;
01099 ping_timer = new QTimer( this );
01100 connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout()));
01101 ping_timer->setSingleShot( true );
01102 ping_timer->start( options->killPingTimeout );
01103 ping_timestamp = xTime();
01104 workspace()->sendPingToWindow( window(), ping_timestamp );
01105 }
01106
01107 void Client::gotPing( Time timestamp )
01108 {
01109
01110 if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
01111 return;
01112 delete ping_timer;
01113 ping_timer = NULL;
01114 if( process_killer != NULL )
01115 {
01116 process_killer->kill();
01117
01118
01119 connect(process_killer, SIGNAL(finished(int, QProcess::ExitStatus)), process_killer,
01120 SLOT(deleteLater()));
01121 process_killer = NULL;
01122 }
01123 }
01124
01125 void Client::pingTimeout()
01126 {
01127 kDebug( 1212 ) << "Ping timeout:" << caption();
01128 ping_timer->deleteLater();
01129 ping_timer = NULL;
01130 killProcess( true, ping_timestamp );
01131 }
01132
01133 void Client::killProcess( bool ask, Time timestamp )
01134 {
01135 if( process_killer != NULL )
01136 return;
01137 Q_ASSERT( !ask || timestamp != CurrentTime );
01138 QByteArray machine = wmClientMachine( true );
01139 pid_t pid = info->pid();
01140 if( pid <= 0 || machine.isEmpty())
01141 return;
01142 kDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")";
01143 if( !ask )
01144 {
01145 if( machine != "localhost" )
01146 {
01147 QStringList lst;
01148 lst << machine << "kill" << QString::number( pid );
01149 QProcess::startDetached("xon",lst);
01150 }
01151 else
01152 ::kill( pid, SIGTERM );
01153 }
01154 else
01155 {
01156 process_killer = new QProcess( this );
01157 connect( process_killer, SIGNAL( error( QProcess::ProcessError )), SLOT( processKillerExited()));
01158 connect( process_killer, SIGNAL( finished( int, QProcess::ExitStatus )), SLOT( processKillerExited()));
01159 process_killer->start( KStandardDirs::findExe( "kwin_killer_helper" ),
01160 QStringList() << "--pid" << QByteArray().setNum( (unsigned)pid ) << "--hostname" << machine
01161 << "--windowname" << caption()
01162 << "--applicationname" << resourceClass()
01163 << "--wid" << QString::number( window() )
01164 << "--timestamp" << QString::number( timestamp ));
01165 }
01166 }
01167
01168 void Client::processKillerExited()
01169 {
01170 kDebug( 1212 ) << "Killer exited";
01171 delete process_killer;
01172 process_killer = NULL;
01173 }
01174
01175 void Client::setSkipTaskbar( bool b, bool from_outside )
01176 {
01177 int was_wants_tab_focus = wantsTabFocus();
01178 if( from_outside )
01179 {
01180 b = rules()->checkSkipTaskbar( b );
01181 original_skip_taskbar = b;
01182 }
01183 if ( b == skipTaskbar() )
01184 return;
01185 skip_taskbar = b;
01186 info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01187 updateWindowRules();
01188 if( was_wants_tab_focus != wantsTabFocus())
01189 workspace()->updateFocusChains( this,
01190 isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
01191 }
01192
01193 void Client::setSkipPager( bool b )
01194 {
01195 b = rules()->checkSkipPager( b );
01196 if ( b == skipPager() )
01197 return;
01198 skip_pager = b;
01199 info->setState( b?NET::SkipPager:0, NET::SkipPager );
01200 updateWindowRules();
01201 }
01202
01203 void Client::setModal( bool m )
01204 {
01205 if( modal == m )
01206 return;
01207 modal = m;
01208 if( !modal )
01209 return;
01210
01211
01212 }
01213
01214 void Client::setDesktop( int desktop )
01215 {
01216 if( desktop != NET::OnAllDesktops )
01217 desktop = qMax( 1, qMin( workspace()->numberOfDesktops(), desktop ));
01218 desktop = rules()->checkDesktop( desktop );
01219 if( desk == desktop )
01220 return;
01221 int was_desk = desk;
01222 desk = desktop;
01223 info->setDesktop( desktop );
01224 if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01225 {
01226 if ( isShown( true ))
01227 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01228 workspace()->updateOnAllDesktopsOfTransients( this );
01229 }
01230 if( decoration != NULL )
01231 decoration->desktopChange();
01232 workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
01233 updateVisibility();
01234 updateWindowRules();
01235 }
01236
01243 int Client::desktop() const
01244 {
01245 return desk;
01246 }
01247
01248 void Client::setOnAllDesktops( bool b )
01249 {
01250 if(( b && isOnAllDesktops())
01251 || ( !b && !isOnAllDesktops()))
01252 return;
01253 if( b )
01254 setDesktop( NET::OnAllDesktops );
01255 else
01256 setDesktop( workspace()->currentDesktop());
01257 }
01258
01259
01260 void Client::takeActivity( int flags, bool handled, allowed_t )
01261 {
01262 if( !handled || !Ptakeactivity )
01263 {
01264 if( flags & ActivityFocus )
01265 takeFocus( Allowed );
01266 if( flags & ActivityRaise )
01267 workspace()->raiseClient( this );
01268 return;
01269 }
01270
01271 #ifndef NDEBUG
01272 static Time previous_activity_timestamp;
01273 static Client* previous_client;
01274 #if 0
01275 if( previous_activity_timestamp == xTime() && previous_client != this )
01276 {
01277 kDebug( 1212 ) << "Repeated use of the same X timestamp for activity";
01278 kDebug( 1212 ) << kBacktrace();
01279 }
01280 #endif
01281 previous_activity_timestamp = xTime();
01282 previous_client = this;
01283 #endif
01284 workspace()->sendTakeActivity( this, xTime(), flags );
01285 }
01286
01287
01288 void Client::takeFocus( allowed_t )
01289 {
01290 #ifndef NDEBUG
01291 static Time previous_focus_timestamp;
01292 static Client* previous_client;
01293 #if 0
01294 if( previous_focus_timestamp == xTime() && previous_client != this )
01295 {
01296 kDebug( 1212 ) << "Repeated use of the same X timestamp for focus";
01297 kDebug( 1212 ) << kBacktrace();
01298 }
01299 #endif
01300 previous_focus_timestamp = xTime();
01301 previous_client = this;
01302 #endif
01303 if ( rules()->checkAcceptFocus( input ))
01304 {
01305 XSetInputFocus( display(), window(), RevertToPointerRoot, xTime() );
01306 }
01307 if ( Ptakefocus )
01308 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01309 workspace()->setShouldGetFocus( this );
01310 }
01311
01319 bool Client::providesContextHelp() const
01320 {
01321 return Pcontexthelp;
01322 }
01323
01324
01331 void Client::showContextHelp()
01332 {
01333 if ( Pcontexthelp )
01334 {
01335 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01336 QWhatsThis::enterWhatsThisMode();
01337 }
01338 }
01339
01340
01345 void Client::fetchName()
01346 {
01347 setCaption( readName());
01348 }
01349
01350 QString Client::readName() const
01351 {
01352 if ( info->name() && info->name()[ 0 ] != '\0' )
01353 return QString::fromUtf8( info->name() );
01354 else
01355 return KWindowSystem::readNameProperty( window(), XA_WM_NAME );
01356 }
01357
01358 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, Client, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
01359
01360 void Client::setCaption( const QString& _s, bool force )
01361 {
01362 QString s = _s;
01363 if ( s != cap_normal || force )
01364 {
01365 bool reset_name = force;
01366 for( int i = 0;
01367 i < s.length();
01368 ++i )
01369 if( !s[ i ].isPrint())
01370 s[ i ] = QChar( ' ' );
01371 cap_normal = s;
01372 bool was_suffix = ( !cap_suffix.isEmpty());
01373 QString machine_suffix;
01374 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
01375 machine_suffix = " <@" + wmClientMachine( true ) + '>';
01376 QString shortcut_suffix = !shortcut().isEmpty() ? ( " {" + shortcut().toString() + '}' ) : QString();
01377 cap_suffix = machine_suffix + shortcut_suffix;
01378 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
01379 {
01380 int i = 2;
01381 do
01382 {
01383 cap_suffix = machine_suffix + " <" + QString::number(i) + '>' + shortcut_suffix;
01384 i++;
01385 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
01386 info->setVisibleName( caption().toUtf8() );
01387 reset_name = false;
01388 }
01389 if(( was_suffix && cap_suffix.isEmpty()
01390 || reset_name ))
01391 {
01392 info->setVisibleName( "" );
01393 info->setVisibleIconName( "" );
01394 }
01395 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
01396 info->setVisibleIconName( ( cap_iconic + cap_suffix ).toUtf8() );
01397
01398 if( isManaged() && decoration != NULL )
01399 decoration->captionChange();
01400 }
01401 }
01402
01403 void Client::updateCaption()
01404 {
01405 setCaption( cap_normal, true );
01406 }
01407
01408 void Client::fetchIconicName()
01409 {
01410 QString s;
01411 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
01412 s = QString::fromUtf8( info->iconName() );
01413 else
01414 s = KWindowSystem::readNameProperty( window(), XA_WM_ICON_NAME );
01415 if ( s != cap_iconic )
01416 {
01417 bool was_set = !cap_iconic.isEmpty();
01418 cap_iconic = s;
01419 if( !cap_suffix.isEmpty())
01420 {
01421 if( !cap_iconic.isEmpty())
01422 info->setVisibleIconName( ( s + cap_suffix ).toUtf8() );
01423 else if( was_set )
01424 info->setVisibleIconName( "" );
01425 }
01426 }
01427 }
01428
01431 QString Client::caption( bool full ) const
01432 {
01433 return full ? cap_normal + cap_suffix : cap_normal;
01434 }
01435
01436 void Client::getWMHints()
01437 {
01438 XWMHints *hints = XGetWMHints(display(), window() );
01439 input = true;
01440 window_group = None;
01441 urgency = false;
01442 if ( hints )
01443 {
01444 if( hints->flags & InputHint )
01445 input = hints->input;
01446 if( hints->flags & WindowGroupHint )
01447 window_group = hints->window_group;
01448 urgency = ( hints->flags & UrgencyHint ) ? true : false;
01449 XFree( (char*)hints );
01450 }
01451 checkGroup();
01452 updateUrgency();
01453 updateAllowedActions();
01454 }
01455
01456 void Client::getMotifHints()
01457 {
01458 bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
01459 Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
01460 if( mnoborder )
01461 {
01462 noborder = true;
01463 app_noborder = true;
01464 }
01465 if( !hasNETSupport())
01466 {
01467 motif_may_resize = mresize;
01468 motif_may_move = mmove;
01469 }
01470 else
01471 motif_may_resize = motif_may_move = true;
01472
01473
01474 motif_may_close = mclose;
01475 if( isManaged())
01476 updateDecoration( true );
01477 }
01478
01479 void Client::readIcons( Window win, QPixmap* icon, QPixmap* miniicon )
01480 {
01481
01482 if( icon != NULL )
01483 *icon = KWindowSystem::icon( win, 32, 32, true, KWindowSystem::NETWM | KWindowSystem::WMHints );
01484 if( miniicon != NULL )
01485 if( icon == NULL || !icon->isNull())
01486 *miniicon = KWindowSystem::icon( win, 16, 16, true, KWindowSystem::NETWM | KWindowSystem::WMHints );
01487 else
01488 *miniicon = QPixmap();
01489 }
01490
01491 void Client::getIcons()
01492 {
01493
01494 readIcons( window(), &icon_pix, &miniicon_pix );
01495 if( icon_pix.isNull())
01496 {
01497 icon_pix = group()->icon();
01498 miniicon_pix = group()->miniIcon();
01499 }
01500 if( icon_pix.isNull() && isTransient())
01501 {
01502 ClientList mainclients = mainClients();
01503 for( ClientList::ConstIterator it = mainclients.begin();
01504 it != mainclients.end() && icon_pix.isNull();
01505 ++it )
01506 {
01507 icon_pix = (*it)->icon();
01508 miniicon_pix = (*it)->miniIcon();
01509 }
01510 }
01511 if( icon_pix.isNull())
01512 {
01513 icon_pix = KWindowSystem::icon( window(), 32, 32, true, KWindowSystem::ClassHint | KWindowSystem::XApp );
01514 miniicon_pix = KWindowSystem::icon( window(), 16, 16, true, KWindowSystem::ClassHint | KWindowSystem::XApp );
01515 }
01516 if( isManaged() && decoration != NULL )
01517 decoration->iconChange();
01518 }
01519
01520 void Client::getWindowProtocols()
01521 {
01522 Atom *p;
01523 int i,n;
01524
01525 Pdeletewindow = 0;
01526 Ptakefocus = 0;
01527 Ptakeactivity = 0;
01528 Pcontexthelp = 0;
01529 Pping = 0;
01530
01531 if (XGetWMProtocols(display(), window(), &p, &n))
01532 {
01533 for (i = 0; i < n; i++)
01534 if (p[i] == atoms->wm_delete_window)
01535 Pdeletewindow = 1;
01536 else if (p[i] == atoms->wm_take_focus)
01537 Ptakefocus = 1;
01538 else if (p[i] == atoms->net_wm_take_activity)
01539 Ptakeactivity = 1;
01540 else if (p[i] == atoms->net_wm_context_help)
01541 Pcontexthelp = 1;
01542 else if (p[i] == atoms->net_wm_ping)
01543 Pping = 1;
01544 if (n>0)
01545 XFree(p);
01546 }
01547 }
01548
01549 void Client::getSyncCounter()
01550 {
01551 #ifdef HAVE_XSYNC
01552 if( !Extensions::syncAvailable())
01553 return;
01554
01555 Atom retType;
01556 unsigned long nItemRet;
01557 unsigned long byteRet;
01558 int formatRet;
01559 unsigned char* propRet;
01560 int ret = XGetWindowProperty( display(), window(), atoms->net_wm_sync_request_counter,
01561 0, 1, false, XA_CARDINAL, &retType, &formatRet, &nItemRet, &byteRet, &propRet );
01562
01563 if( ret == Success && formatRet == 32 )
01564 {
01565 sync_counter = *(long*)propRet;
01566 XSyncIntToValue( &sync_counter_value, 0 );
01567 XSyncValue zero;
01568 XSyncIntToValue( &zero, 0 );
01569 XSyncSetCounter( display(), sync_counter, zero );
01570 if( sync_alarm == None )
01571 {
01572 XSyncAlarmAttributes attrs;
01573 attrs.trigger.counter = sync_counter;
01574 attrs.trigger.value_type = XSyncRelative;
01575 attrs.trigger.test_type = XSyncPositiveTransition;
01576 XSyncIntToValue( &attrs.trigger.wait_value, 1 );
01577 XSyncIntToValue( &attrs.delta, 1 );
01578 sync_alarm = XSyncCreateAlarm( display(),
01579 XSyncCACounter | XSyncCAValueType | XSyncCATestType | XSyncCADelta | XSyncCAValue,
01580 &attrs );
01581 }
01582 }
01583 #endif
01584 }
01585
01586
01587 void Client::sendSyncRequest()
01588 {
01589 #ifdef HAVE_XSYNC
01590 if( sync_counter == None )
01591 return;
01592
01593
01594
01595
01596 int overflow;
01597 XSyncValue one;
01598 XSyncIntToValue( &one, 1 );
01599 #undef XSyncValueAdd // it causes a warning :-/
01600 XSyncValueAdd( &sync_counter_value, sync_counter_value, one, &overflow );
01601
01602
01603 XEvent ev;
01604 ev.xclient.type = ClientMessage;
01605 ev.xclient.window = window();
01606 ev.xclient.format = 32;
01607 ev.xclient.message_type = atoms->wm_protocols;
01608 ev.xclient.data.l[ 0 ] = atoms->net_wm_sync_request;
01609 ev.xclient.data.l[ 1 ] = xTime();
01610 ev.xclient.data.l[ 2 ] = XSyncValueLow32( sync_counter_value );
01611 ev.xclient.data.l[ 3 ] = XSyncValueHigh32( sync_counter_value );
01612 ev.xclient.data.l[ 4 ] = 0;
01613 XSendEvent( display(), window(), False, NoEventMask, &ev );
01614 XSync(display(),false);
01615 #endif
01616 }
01617
01618
01619 bool Client::wantsTabFocus() const
01620 {
01621 return ( isNormalWindow() || isDialog()) && wantsInput();
01622 }
01623
01624
01625 bool Client::wantsInput() const
01626 {
01627 return rules()->checkAcceptFocus( input || Ptakefocus );
01628 }
01629
01630 bool Client::isSpecialWindow() const
01631 {
01632 return isDesktop() || isDock() || isSplash() || isTopMenu()
01633 || isToolbar();
01634 }
01635
01640 void Client::updateCursor()
01641 {
01642 Position m = mode;
01643 if( !isResizable() || isShade())
01644 m = PositionCenter;
01645 QCursor c;
01646 switch( m )
01647 {
01648 case PositionTopLeft:
01649 case PositionBottomRight:
01650 c = Qt::SizeFDiagCursor;
01651 break;
01652 case PositionBottomLeft:
01653 case PositionTopRight:
01654 c = Qt::SizeBDiagCursor;
01655 break;
01656 case PositionTop:
01657 case PositionBottom:
01658 c = Qt::SizeVerCursor;
01659 break;
01660 case PositionLeft:
01661 case PositionRight:
01662 c = Qt::SizeHorCursor;
01663 break;
01664 default:
01665 if( moveResizeMode )
01666 c = Qt::SizeAllCursor;
01667 else
01668 c = Qt::ArrowCursor;
01669 break;
01670 }
01671 if( c.handle() == cursor.handle())
01672 return;
01673 cursor = c;
01674 if( decoration != NULL )
01675 decoration->widget()->setCursor( cursor );
01676 XDefineCursor( display(), frameId(), cursor.handle());
01677 if( moveResizeMode )
01678 XChangeActivePointerGrab( display(),
01679 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | LeaveWindowMask,
01680 cursor.handle(), xTime());
01681 }
01682
01683 Client::Position Client::mousePosition( const QPoint& p ) const
01684 {
01685 if( decoration != NULL )
01686 return decoration->mousePosition( p );
01687 return PositionCenter;
01688 }
01689
01690 void Client::updateAllowedActions( bool force )
01691 {
01692 if( !isManaged() && !force )
01693 return;
01694 unsigned long old_allowed_actions = allowed_actions;
01695 allowed_actions = 0;
01696 if( isMovable())
01697 allowed_actions |= NET::ActionMove;
01698 if( isResizable())
01699 allowed_actions |= NET::ActionResize;
01700 if( isMinimizable())
01701 allowed_actions |= NET::ActionMinimize;
01702 if( isShadeable())
01703 allowed_actions |= NET::ActionShade;
01704
01705 if( isMaximizable())
01706 allowed_actions |= NET::ActionMax;
01707 if( userCanSetFullScreen())
01708 allowed_actions |= NET::ActionFullScreen;
01709 allowed_actions |= NET::ActionChangeDesktop;
01710 if( isCloseable())
01711 allowed_actions |= NET::ActionClose;
01712 if( old_allowed_actions == allowed_actions )
01713 return;
01714
01715 info->setAllowedActions( allowed_actions );
01716
01717 }
01718
01719 void Client::autoRaise()
01720 {
01721 workspace()->raiseClient( this );
01722 cancelAutoRaise();
01723 }
01724
01725 void Client::cancelAutoRaise()
01726 {
01727 delete autoRaiseTimer;
01728 autoRaiseTimer = 0;
01729 }
01730
01731 void Client::debug( kdbgstream& stream ) const
01732 {
01733 stream << "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":" << resourceName() << ";Caption:" << caption() << "\'";
01734 }
01735
01736 QPixmap * kwin_get_menu_pix_hack()
01737 {
01738 static QPixmap p;
01739 if ( p.isNull() )
01740 p = SmallIcon( "bx2" );
01741 return &p;
01742 }
01743
01744 }
01745
01746 #include "client.moc"