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