00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "client.h"
00013
00014 #include <qapplication.h>
00015 #include <qpainter.h>
00016 #include <qdatetime.h>
00017 #include <kprocess.h>
00018 #include <unistd.h>
00019 #include <kstandarddirs.h>
00020 #include <qwhatsthis.h>
00021 #include <kwin.h>
00022 #include <kiconloader.h>
00023 #include <stdlib.h>
00024
00025 #include "bridge.h"
00026 #include "group.h"
00027 #include "workspace.h"
00028 #include "atoms.h"
00029 #include "notifications.h"
00030 #include "rules.h"
00031
00032 #include <X11/extensions/shape.h>
00033
00034
00035
00036
00037 extern Atom qt_wm_state;
00038 extern Time qt_x_time;
00039 extern Atom qt_window_role;
00040 extern Atom qt_sm_client_id;
00041
00042 namespace KWinInternal
00043 {
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00069 Client::Client( Workspace *ws )
00070 : QObject( NULL ),
00071 client( None ),
00072 wrapper( None ),
00073 frame( None ),
00074 decoration( NULL ),
00075 wspace( ws ),
00076 bridge( new Bridge( this )),
00077 move_faked_activity( false ),
00078 move_resize_grab_window( None ),
00079 transient_for( NULL ),
00080 transient_for_id( None ),
00081 original_transient_for_id( None ),
00082 in_group( NULL ),
00083 window_group( None ),
00084 in_layer( UnknownLayer ),
00085 ping_timer( NULL ),
00086 process_killer( NULL ),
00087 user_time( CurrentTime ),
00088 allowed_actions( 0 ),
00089 postpone_geometry_updates( 0 ),
00090 pending_geometry_update( false ),
00091 shade_geometry_change( false ),
00092 border_left( 0 ),
00093 border_right( 0 ),
00094 border_top( 0 ),
00095 border_bottom( 0 ),
00096 opacity_( 0 ),
00097 demandAttentionKNotifyTimer( NULL )
00098
00099 {
00100 autoRaiseTimer = 0;
00101 shadeHoverTimer = 0;
00102
00103
00104 mapping_state = WithdrawnState;
00105 desk = 0;
00106
00107 mode = PositionCenter;
00108 buttonDown = FALSE;
00109 moveResizeMode = FALSE;
00110
00111 info = NULL;
00112
00113 shade_mode = ShadeNone;
00114 active = FALSE;
00115 deleting = false;
00116 keep_above = FALSE;
00117 keep_below = FALSE;
00118 is_shape = FALSE;
00119 motif_noborder = false;
00120 motif_may_move = TRUE;
00121 motif_may_resize = TRUE;
00122 motif_may_close = TRUE;
00123 fullscreen_mode = FullScreenNone;
00124 skip_taskbar = FALSE;
00125 original_skip_taskbar = false;
00126 minimized = false;
00127 hidden = false;
00128 modal = false;
00129 noborder = false;
00130 user_noborder = false;
00131 urgency = false;
00132 ignore_focus_stealing = false;
00133 demands_attention = false;
00134 check_active_modal = false;
00135
00136 Pdeletewindow = 0;
00137 Ptakefocus = 0;
00138 Ptakeactivity = 0;
00139 Pcontexthelp = 0;
00140 Pping = 0;
00141 input = FALSE;
00142 skip_pager = FALSE;
00143
00144 max_mode = MaximizeRestore;
00145 maxmode_restore = MaximizeRestore;
00146
00147 cmap = None;
00148
00149 frame_geometry = QRect( 0, 0, 100, 100 );
00150 client_size = QSize( 100, 100 );
00151 custom_opacity = false;
00152 rule_opacity_active = 0;;
00153 rule_opacity_inactive = 0;
00154
00155
00156 }
00157
00161 Client::~Client()
00162 {
00163 assert(!moveResizeMode);
00164 assert( client == None );
00165 assert( frame == None && wrapper == None );
00166 assert( decoration == NULL );
00167 assert( postpone_geometry_updates == 0 );
00168 assert( !check_active_modal );
00169 delete info;
00170 delete bridge;
00171 }
00172
00173
00174 void Client::deleteClient( Client* c, allowed_t )
00175 {
00176 delete c;
00177 }
00178
00182 void Client::releaseWindow( bool on_shutdown )
00183 {
00184 assert( !deleting );
00185 deleting = true;
00186 workspace()->discardUsedWindowRules( this, true );
00187 StackingUpdatesBlocker blocker( workspace());
00188 if (!custom_opacity) setOpacity(FALSE);
00189 if (moveResizeMode)
00190 leaveMoveResize();
00191 finishWindowRules();
00192 ++postpone_geometry_updates;
00193 setMappingState( WithdrawnState );
00194 setModal( false );
00195 hidden = true;
00196 if( !on_shutdown )
00197 workspace()->clientHidden( this );
00198 XUnmapWindow( qt_xdisplay(), frameId());
00199 destroyDecoration();
00200 cleanGrouping();
00201 if( !on_shutdown )
00202 {
00203 workspace()->removeClient( this, Allowed );
00204
00205
00206 info->setDesktop( 0 );
00207 desk = 0;
00208 info->setState( 0, info->state());
00209 }
00210 XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
00211 XDeleteProperty( qt_xdisplay(), client, atoms->net_frame_extents );
00212 XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
00213 XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
00214 XRemoveFromSaveSet( qt_xdisplay(), client );
00215 XSelectInput( qt_xdisplay(), client, NoEventMask );
00216 if( on_shutdown )
00217 {
00218 XMapWindow( qt_xdisplay(), client );
00219
00220 }
00221 else
00222 {
00223
00224
00225 XUnmapWindow( qt_xdisplay(), client );
00226 }
00227 client = None;
00228 XDestroyWindow( qt_xdisplay(), wrapper );
00229 wrapper = None;
00230 XDestroyWindow( qt_xdisplay(), frame );
00231 frame = None;
00232 --postpone_geometry_updates;
00233 deleteClient( this, Allowed );
00234 }
00235
00236
00237
00238 void Client::destroyClient()
00239 {
00240 assert( !deleting );
00241 deleting = true;
00242 workspace()->discardUsedWindowRules( this, true );
00243 StackingUpdatesBlocker blocker( workspace());
00244 if (moveResizeMode)
00245 leaveMoveResize();
00246 finishWindowRules();
00247 ++postpone_geometry_updates;
00248 setModal( false );
00249 hidden = true;
00250 workspace()->clientHidden( this );
00251 destroyDecoration();
00252 cleanGrouping();
00253 workspace()->removeClient( this, Allowed );
00254 client = None;
00255 XDestroyWindow( qt_xdisplay(), wrapper );
00256 wrapper = None;
00257 XDestroyWindow( qt_xdisplay(), frame );
00258 frame = None;
00259 --postpone_geometry_updates;
00260 deleteClient( this, Allowed );
00261 }
00262
00263 void Client::updateDecoration( bool check_workspace_pos, bool force )
00264 {
00265 if( !force && (( decoration == NULL && noBorder())
00266 || ( decoration != NULL && !noBorder())))
00267 return;
00268 bool do_show = false;
00269 postponeGeometryUpdates( true );
00270 if( force )
00271 destroyDecoration();
00272 if( !noBorder())
00273 {
00274 setMask( QRegion());
00275 decoration = workspace()->createDecoration( bridge );
00276
00277 decoration->init();
00278 decoration->widget()->installEventFilter( this );
00279 XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
00280 decoration->widget()->lower();
00281 decoration->borders( border_left, border_right, border_top, border_bottom );
00282 options->onlyDecoTranslucent ?
00283 setDecoHashProperty(border_top, border_right, border_bottom, border_left):
00284 unsetDecoHashProperty();
00285 int save_workarea_diff_x = workarea_diff_x;
00286 int save_workarea_diff_y = workarea_diff_y;
00287 move( calculateGravitation( false ));
00288 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00289 workarea_diff_x = save_workarea_diff_x;
00290 workarea_diff_y = save_workarea_diff_y;
00291 do_show = true;
00292 }
00293 else
00294 destroyDecoration();
00295 if( check_workspace_pos )
00296 checkWorkspacePosition();
00297 postponeGeometryUpdates( false );
00298 if( do_show )
00299 decoration->widget()->show();
00300 updateFrameExtents();
00301 }
00302
00303 void Client::destroyDecoration()
00304 {
00305 if( decoration != NULL )
00306 {
00307 delete decoration;
00308 decoration = NULL;
00309 QPoint grav = calculateGravitation( true );
00310 border_left = border_right = border_top = border_bottom = 0;
00311 setMask( QRegion());
00312 int save_workarea_diff_x = workarea_diff_x;
00313 int save_workarea_diff_y = workarea_diff_y;
00314 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00315 move( grav );
00316 workarea_diff_x = save_workarea_diff_x;
00317 workarea_diff_y = save_workarea_diff_y;
00318 }
00319 }
00320
00321 void Client::checkBorderSizes()
00322 {
00323 if( decoration == NULL )
00324 return;
00325 int new_left, new_right, new_top, new_bottom;
00326 decoration->borders( new_left, new_right, new_top, new_bottom );
00327 if( new_left == border_left && new_right == border_right
00328 && new_top == border_top && new_bottom == border_bottom )
00329 return;
00330 GeometryUpdatesPostponer blocker( this );
00331 move( calculateGravitation( true ));
00332 border_left = new_left;
00333 border_right = new_right;
00334 border_top = new_top;
00335 border_bottom = new_bottom;
00336 if (border_left != new_left ||
00337 border_right != new_right ||
00338 border_top != new_top ||
00339 border_bottom != new_bottom)
00340 options->onlyDecoTranslucent ?
00341 setDecoHashProperty(new_top, new_right, new_bottom, new_left):
00342 unsetDecoHashProperty();
00343 move( calculateGravitation( false ));
00344 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00345 checkWorkspacePosition();
00346 }
00347
00348 void Client::detectNoBorder()
00349 {
00350 if( Shape::hasShape( window()))
00351 {
00352 noborder = true;
00353 return;
00354 }
00355 switch( windowType())
00356 {
00357 case NET::Desktop :
00358 case NET::Dock :
00359 case NET::TopMenu :
00360 case NET::Splash :
00361 noborder = true;
00362 break;
00363 case NET::Unknown :
00364 case NET::Normal :
00365 case NET::Toolbar :
00366 case NET::Menu :
00367 case NET::Dialog :
00368 case NET::Utility :
00369 noborder = false;
00370 break;
00371 default:
00372 assert( false );
00373 }
00374
00375
00376
00377 if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
00378 noborder = true;
00379 }
00380
00381 void Client::detectShapable()
00382 {
00383 if( Shape::hasShape( window()))
00384 return;
00385 switch( windowType())
00386 {
00387 case NET::Desktop :
00388 case NET::Dock :
00389 case NET::TopMenu :
00390 case NET::Splash :
00391 break;
00392 case NET::Unknown :
00393 case NET::Normal :
00394 case NET::Toolbar :
00395 case NET::Menu :
00396 case NET::Dialog :
00397 case NET::Utility :
00398 setShapable(FALSE);
00399 break;
00400 default:
00401 assert( false );
00402 }
00403 }
00404
00405 void Client::updateFrameExtents()
00406 {
00407 NETStrut strut;
00408 strut.left = border_left;
00409 strut.right = border_right;
00410 strut.top = border_top;
00411 strut.bottom = border_bottom;
00412 info->setFrameExtents( strut );
00413 }
00414
00415
00416
00417
00418
00419
00420 void Client::resizeDecoration( const QSize& s )
00421 {
00422 if( decoration == NULL )
00423 return;
00424 QSize oldsize = decoration->widget()->size();
00425 decoration->resize( s );
00426 if( oldsize == s )
00427 {
00428 QResizeEvent e( s, oldsize );
00429 QApplication::sendEvent( decoration->widget(), &e );
00430 }
00431 }
00432
00433 bool Client::noBorder() const
00434 {
00435 return noborder || isFullScreen() || user_noborder || motif_noborder;
00436 }
00437
00438 bool Client::userCanSetNoBorder() const
00439 {
00440 return !noborder && !isFullScreen() && !isShade();
00441 }
00442
00443 bool Client::isUserNoBorder() const
00444 {
00445 return user_noborder;
00446 }
00447
00448 void Client::setUserNoBorder( bool set )
00449 {
00450 if( !userCanSetNoBorder())
00451 return;
00452 set = rules()->checkNoBorder( set );
00453 if( user_noborder == set )
00454 return;
00455 user_noborder = set;
00456 updateDecoration( true, false );
00457 updateWindowRules();
00458 }
00459
00460 void Client::updateShape()
00461 {
00462
00463 if( shape() && !noBorder())
00464 {
00465 noborder = true;
00466 updateDecoration( true );
00467 }
00468 if ( shape() )
00469 {
00470 XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
00471 clientPos().x(), clientPos().y(),
00472 window(), ShapeBounding, ShapeSet);
00473 setShapable(TRUE);
00474 }
00475
00476
00477
00478 if( Shape::version() >= 0x11 )
00479 {
00480
00481
00482
00483
00484
00485
00486
00487
00488 static Window helper_window = None;
00489 if( helper_window == None )
00490 helper_window = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(),
00491 0, 0, 1, 1, 0, 0, 0 );
00492 XResizeWindow( qt_xdisplay(), helper_window, width(), height());
00493 XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput, 0, 0,
00494 frameId(), ShapeBounding, ShapeSet );
00495 XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
00496 clientPos().x(), clientPos().y(),
00497 window(), ShapeBounding, ShapeSubtract );
00498 XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
00499 clientPos().x(), clientPos().y(),
00500 window(), ShapeInput, ShapeUnion );
00501 XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput, 0, 0,
00502 helper_window, ShapeInput, ShapeSet );
00503 }
00504 }
00505
00506 void Client::setMask( const QRegion& reg, int mode )
00507 {
00508 _mask = reg;
00509 if( reg.isNull())
00510 XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00511 None, ShapeSet );
00512 else if( mode == X::Unsorted )
00513 XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00514 reg.handle(), ShapeSet );
00515 else
00516 {
00517 QMemArray< QRect > rects = reg.rects();
00518 XRectangle* xrects = new XRectangle[ rects.count() ];
00519 for( unsigned int i = 0;
00520 i < rects.count();
00521 ++i )
00522 {
00523 xrects[ i ].x = rects[ i ].x();
00524 xrects[ i ].y = rects[ i ].y();
00525 xrects[ i ].width = rects[ i ].width();
00526 xrects[ i ].height = rects[ i ].height();
00527 }
00528 XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00529 xrects, rects.count(), ShapeSet, mode );
00530 delete[] xrects;
00531 }
00532 updateShape();
00533 }
00534
00535 QRegion Client::mask() const
00536 {
00537 if( _mask.isEmpty())
00538 return QRegion( 0, 0, width(), height());
00539 return _mask;
00540 }
00541
00542 void Client::setShapable(bool b)
00543 {
00544 long tmp = b?1:0;
00545 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
00546 }
00547
00548 void Client::hideClient( bool hide )
00549 {
00550 if( hidden == hide )
00551 return;
00552 hidden = hide;
00553 updateVisibility();
00554 }
00555
00556
00557
00558
00559 bool Client::isMinimizable() const
00560 {
00561 if( isSpecialWindow())
00562 return false;
00563 if( isTransient())
00564 {
00565 bool shown_mainwindow = false;
00566 ClientList mainclients = mainClients();
00567 for( ClientList::ConstIterator it = mainclients.begin();
00568 it != mainclients.end();
00569 ++it )
00570 {
00571 if( (*it)->isShown( true ))
00572 shown_mainwindow = true;
00573 }
00574 if( !shown_mainwindow )
00575 return true;
00576 }
00577
00578
00579
00580 if( transientFor() != NULL )
00581 return false;
00582 if( !wantsTabFocus())
00583 return false;
00584 return true;
00585 }
00586
00590 void Client::minimize( bool avoid_animation )
00591 {
00592 if ( !isMinimizable() || isMinimized())
00593 return;
00594
00595 Notify::raise( Notify::Minimize );
00596
00597
00598 if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
00599 animateMinimizeOrUnminimize( true );
00600
00601 minimized = true;
00602
00603 updateVisibility();
00604 updateAllowedActions();
00605 workspace()->updateMinimizedOfTransients( this );
00606 updateWindowRules();
00607 workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
00608 }
00609
00610 void Client::unminimize( bool avoid_animation )
00611 {
00612 if( !isMinimized())
00613 return;
00614
00615 Notify::raise( Notify::UnMinimize );
00616 minimized = false;
00617 if( isOnCurrentDesktop() && isShown( true ))
00618 {
00619 if( mainClients().isEmpty() && !avoid_animation )
00620 animateMinimizeOrUnminimize( FALSE );
00621 }
00622 updateVisibility();
00623 updateAllowedActions();
00624 workspace()->updateMinimizedOfTransients( this );
00625 updateWindowRules();
00626 }
00627
00628 extern bool blockAnimation;
00629
00630 void Client::animateMinimizeOrUnminimize( bool minimize )
00631 {
00632 if ( blockAnimation )
00633 return;
00634 if ( !options->animateMinimize )
00635 return;
00636
00637 if( decoration != NULL && decoration->animateMinimize( minimize ))
00638 return;
00639
00640
00641
00642
00643
00644 float lf,rf,tf,bf,step;
00645
00646 int speed = options->animateMinimizeSpeed;
00647 if ( speed > 10 )
00648 speed = 10;
00649 if ( speed < 0 )
00650 speed = 0;
00651
00652 step = 40. * (11 - speed );
00653
00654 NETRect r = info->iconGeometry();
00655 QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00656 if ( !icongeom.isValid() )
00657 return;
00658
00659 QPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
00660
00661 QRect before, after;
00662 if ( minimize )
00663 {
00664 before = QRect( x(), y(), width(), pm.height() );
00665 after = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00666 }
00667 else
00668 {
00669 before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00670 after = QRect( x(), y(), width(), pm.height() );
00671 }
00672
00673 lf = (after.left() - before.left())/step;
00674 rf = (after.right() - before.right())/step;
00675 tf = (after.top() - before.top())/step;
00676 bf = (after.bottom() - before.bottom())/step;
00677
00678 grabXServer();
00679
00680 QRect area = before;
00681 QRect area2;
00682 QPixmap pm2;
00683
00684 QTime t;
00685 t.start();
00686 float diff;
00687
00688 QPainter p ( workspace()->desktopWidget() );
00689 bool need_to_clear = FALSE;
00690 QPixmap pm3;
00691 do
00692 {
00693 if (area2 != area)
00694 {
00695 pm = animationPixmap( area.width() );
00696 pm2 = QPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
00697 p.drawPixmap( area.x(), area.y(), pm );
00698 if ( need_to_clear )
00699 {
00700 p.drawPixmap( area2.x(), area2.y(), pm3 );
00701 need_to_clear = FALSE;
00702 }
00703 area2 = area;
00704 }
00705 XFlush(qt_xdisplay());
00706 XSync( qt_xdisplay(), FALSE );
00707 diff = t.elapsed();
00708 if (diff > step)
00709 diff = step;
00710 area.setLeft(before.left() + int(diff*lf));
00711 area.setRight(before.right() + int(diff*rf));
00712 area.setTop(before.top() + int(diff*tf));
00713 area.setBottom(before.bottom() + int(diff*bf));
00714 if (area2 != area )
00715 {
00716 if ( area2.intersects( area ) )
00717 p.drawPixmap( area2.x(), area2.y(), pm2 );
00718 else
00719 {
00720 pm3 = pm2;
00721 need_to_clear = TRUE;
00722 }
00723 }
00724 } while ( t.elapsed() < step);
00725 if (area2 == area || need_to_clear )
00726 p.drawPixmap( area2.x(), area2.y(), pm2 );
00727
00728 p.end();
00729 ungrabXServer();
00730 }
00731
00732
00736 QPixmap Client::animationPixmap( int w )
00737 {
00738 QFont font = options->font(isActive());
00739 QFontMetrics fm( font );
00740 QPixmap pm( w, fm.lineSpacing() );
00741 pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
00742 QPainter p( &pm );
00743 p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
00744 p.setFont(options->font(isActive()));
00745 p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
00746 return pm;
00747 }
00748
00749
00750 bool Client::isShadeable() const
00751 {
00752 return !isSpecialWindow() && !noBorder();
00753 }
00754
00755 void Client::setShade( ShadeMode mode )
00756 {
00757 if( !isShadeable())
00758 return;
00759 mode = rules()->checkShade( mode );
00760 if( shade_mode == mode )
00761 return;
00762 bool was_shade = isShade();
00763 ShadeMode was_shade_mode = shade_mode;
00764 shade_mode = mode;
00765 if( was_shade == isShade())
00766 {
00767 if( decoration != NULL )
00768 decoration->shadeChange();
00769 return;
00770 }
00771
00772 if( shade_mode == ShadeNormal )
00773 {
00774 if ( isShown( true ) && isOnCurrentDesktop())
00775 Notify::raise( Notify::ShadeUp );
00776 }
00777 else if( shade_mode == ShadeNone )
00778 {
00779 if( isShown( true ) && isOnCurrentDesktop())
00780 Notify::raise( Notify::ShadeDown );
00781 }
00782
00783 assert( decoration != NULL );
00784 GeometryUpdatesPostponer blocker( this );
00785
00786 decoration->borders( border_left, border_right, border_top, border_bottom );
00787
00788 int as = options->animateShade? 10 : 1;
00789
00790 if ( isShade())
00791 {
00792
00793 long _shade = 1;
00794 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00795
00796 int h = height();
00797 shade_geometry_change = true;
00798 QSize s( sizeForClientSize( QSize( clientSize())));
00799 s.setHeight( border_top + border_bottom );
00800 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
00801 XUnmapWindow( qt_xdisplay(), wrapper );
00802 XUnmapWindow( qt_xdisplay(), client );
00803 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00804
00805
00806
00807
00808
00809 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00810 do
00811 {
00812 h -= step;
00813 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00814 resizeDecoration( QSize( s.width(), h ));
00815 QApplication::syncX();
00816 } while ( h > s.height() + step );
00817
00818
00819 plainResize( s );
00820 shade_geometry_change = false;
00821 if( isActive())
00822 {
00823 if( was_shade_mode == ShadeHover )
00824 workspace()->activateNextClient( this );
00825 else
00826 workspace()->focusToNull();
00827 }
00828
00829 _shade = 2;
00830 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00831 }
00832 else
00833 {
00834 int h = height();
00835 shade_geometry_change = true;
00836 QSize s( sizeForClientSize( clientSize()));
00837
00838
00839 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00840 do
00841 {
00842 h += step;
00843 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00844 resizeDecoration( QSize( s.width(), h ));
00845
00846
00847
00848 QApplication::syncX();
00849 } while ( h < s.height() - step );
00850
00851
00852 shade_geometry_change = false;
00853 plainResize( s );
00854 if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00855 setActive( TRUE );
00856 XMapWindow( qt_xdisplay(), wrapperId());
00857 XMapWindow( qt_xdisplay(), window());
00858 XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
00859 if ( isActive() )
00860 workspace()->requestFocus( this );
00861 }
00862 checkMaximizeGeometry();
00863 info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00864 info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00865 updateVisibility();
00866 updateAllowedActions();
00867 workspace()->updateMinimizedOfTransients( this );
00868 decoration->shadeChange();
00869 updateWindowRules();
00870 }
00871
00872 void Client::shadeHover()
00873 {
00874 setShade( ShadeHover );
00875 cancelShadeHover();
00876 }
00877
00878 void Client::cancelShadeHover()
00879 {
00880 delete shadeHoverTimer;
00881 shadeHoverTimer = 0;
00882 }
00883
00884 void Client::toggleShade()
00885 {
00886
00887 setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00888 }
00889
00890 void Client::updateVisibility()
00891 {
00892 if( deleting )
00893 return;
00894 bool show = true;
00895 if( hidden )
00896 {
00897 setMappingState( IconicState );
00898 info->setState( NET::Hidden, NET::Hidden );
00899 setSkipTaskbar( true, false );
00900 rawHide();
00901 show = false;
00902 }
00903 else
00904 {
00905 setSkipTaskbar( original_skip_taskbar, false );
00906 }
00907 if( minimized )
00908 {
00909 setMappingState( IconicState );
00910 info->setState( NET::Hidden, NET::Hidden );
00911 rawHide();
00912 show = false;
00913 }
00914 if( show )
00915 info->setState( 0, NET::Hidden );
00916 if( !isOnCurrentDesktop())
00917 {
00918 setMappingState( IconicState );
00919 rawHide();
00920 show = false;
00921 }
00922 if( show )
00923 {
00924 bool belongs_to_desktop = false;
00925 for( ClientList::ConstIterator it = group()->members().begin();
00926 it != group()->members().end();
00927 ++it )
00928 if( (*it)->isDesktop())
00929 {
00930 belongs_to_desktop = true;
00931 break;
00932 }
00933 if( !belongs_to_desktop && workspace()->showingDesktop())
00934 workspace()->resetShowingDesktop( true );
00935 if( isShade())
00936 setMappingState( IconicState );
00937 else
00938 setMappingState( NormalState );
00939 rawShow();
00940 }
00941 }
00942
00947 void Client::setMappingState(int s)
00948 {
00949 assert( client != None );
00950 assert( !deleting || s == WithdrawnState );
00951 if( mapping_state == s )
00952 return;
00953 bool was_unmanaged = ( mapping_state == WithdrawnState );
00954 mapping_state = s;
00955 if( mapping_state == WithdrawnState )
00956 {
00957 XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
00958 return;
00959 }
00960 assert( s == NormalState || s == IconicState );
00961
00962 unsigned long data[2];
00963 data[0] = (unsigned long) s;
00964 data[1] = (unsigned long) None;
00965 XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
00966 PropModeReplace, (unsigned char *)data, 2);
00967
00968 if( was_unmanaged )
00969 postponeGeometryUpdates( false );
00970 }
00971
00976 void Client::rawShow()
00977 {
00978 if( decoration != NULL )
00979 decoration->widget()->show();
00980 XMapWindow( qt_xdisplay(), frame );
00981 if( !isShade())
00982 {
00983 XMapWindow( qt_xdisplay(), wrapper );
00984 XMapWindow( qt_xdisplay(), client );
00985 }
00986 }
00987
00993 void Client::rawHide()
00994 {
00995
00996
00997
00998
00999
01000
01001 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
01002 XUnmapWindow( qt_xdisplay(), frame );
01003 XUnmapWindow( qt_xdisplay(), wrapper );
01004 XUnmapWindow( qt_xdisplay(), client );
01005 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
01006 if( decoration != NULL )
01007 decoration->widget()->hide();
01008 workspace()->clientHidden( this );
01009 }
01010
01011 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
01012 {
01013 XEvent ev;
01014 long mask;
01015
01016 memset(&ev, 0, sizeof(ev));
01017 ev.xclient.type = ClientMessage;
01018 ev.xclient.window = w;
01019 ev.xclient.message_type = a;
01020 ev.xclient.format = 32;
01021 ev.xclient.data.l[0] = protocol;
01022 ev.xclient.data.l[1] = qt_x_time;
01023 ev.xclient.data.l[2] = data1;
01024 ev.xclient.data.l[3] = data2;
01025 ev.xclient.data.l[4] = data3;
01026 mask = 0L;
01027 if (w == qt_xrootwin())
01028 mask = SubstructureRedirectMask;
01029 XSendEvent(qt_xdisplay(), w, False, mask, &ev);
01030 }
01031
01032
01033
01034
01035 bool Client::isCloseable() const
01036 {
01037 return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
01038 }
01039
01044 void Client::closeWindow()
01045 {
01046 if( !isCloseable())
01047 return;
01048
01049 updateUserTime();
01050 if ( Pdeletewindow )
01051 {
01052 Notify::raise( Notify::Close );
01053 sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
01054 pingWindow();
01055 }
01056 else
01057 {
01058
01059
01060 killWindow();
01061 }
01062 }
01063
01064
01068 void Client::killWindow()
01069 {
01070 kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
01071
01072
01073 Notify::raise( Notify::Close );
01074
01075 if( isDialog())
01076 Notify::raise( Notify::TransDelete );
01077 if( isNormalWindow())
01078 Notify::raise( Notify::Delete );
01079 killProcess( false );
01080
01081 XKillClient(qt_xdisplay(), window() );
01082 destroyClient();
01083 }
01084
01085
01086
01087
01088 void Client::pingWindow()
01089 {
01090 if( !Pping )
01091 return;
01092 if( options->killPingTimeout == 0 )
01093 return;
01094 if( ping_timer != NULL )
01095 return;
01096 ping_timer = new QTimer( this );
01097 connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout()));
01098 ping_timer->start( options->killPingTimeout, true );
01099 ping_timestamp = qt_x_time;
01100 workspace()->sendPingToWindow( window(), ping_timestamp );
01101 }
01102
01103 void Client::gotPing( Time timestamp )
01104 {
01105 if( timestamp != ping_timestamp )
01106 return;
01107 delete ping_timer;
01108 ping_timer = NULL;
01109 if( process_killer != NULL )
01110 {
01111 process_killer->kill();
01112 delete process_killer;
01113 process_killer = NULL;
01114 }
01115 }
01116
01117 void Client::pingTimeout()
01118 {
01119 kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
01120 delete ping_timer;
01121 ping_timer = NULL;
01122 killProcess( true, ping_timestamp );
01123 }
01124
01125 void Client::killProcess( bool ask, Time timestamp )
01126 {
01127 if( process_killer != NULL )
01128 return;
01129 Q_ASSERT( !ask || timestamp != CurrentTime );
01130 QCString machine = wmClientMachine( true );
01131 pid_t pid = info->pid();
01132 if( pid <= 0 || machine.isEmpty())
01133 return;
01134 kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01135 if( !ask )
01136 {
01137 if( machine != "localhost" )
01138 {
01139 KProcess proc;
01140 proc << "xon" << machine << "kill" << pid;
01141 proc.start( KProcess::DontCare );
01142 }
01143 else
01144 ::kill( pid, SIGTERM );
01145 }
01146 else
01147 {
01148 process_killer = new KProcess( this );
01149 *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01150 << "--pid" << QCString().setNum( pid ) << "--hostname" << machine
01151 << "--windowname" << caption().utf8()
01152 << "--applicationname" << resourceClass()
01153 << "--wid" << QCString().setNum( window())
01154 << "--timestamp" << QCString().setNum( timestamp );
01155 connect