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 demandAttentionKNotifyTimer( NULL )
00097
00098 {
00099 autoRaiseTimer = 0;
00100 shadeHoverTimer = 0;
00101
00102
00103 mapping_state = WithdrawnState;
00104 desk = 0;
00105
00106 mode = PositionCenter;
00107 buttonDown = FALSE;
00108 moveResizeMode = FALSE;
00109
00110 info = NULL;
00111
00112 shade_mode = ShadeNone;
00113 active = FALSE;
00114 deleting = false;
00115 keep_above = FALSE;
00116 keep_below = FALSE;
00117 is_shape = FALSE;
00118 motif_noborder = false;
00119 motif_may_move = TRUE;
00120 motif_may_resize = TRUE;
00121 motif_may_close = TRUE;
00122 fullscreen_mode = FullScreenNone;
00123 skip_taskbar = FALSE;
00124 original_skip_taskbar = false;
00125 minimized = false;
00126 hidden = false;
00127 modal = false;
00128 noborder = false;
00129 user_noborder = false;
00130 not_obscured = 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 decoration = workspace()->createDecoration( bridge );
00275
00276 decoration->init();
00277 decoration->widget()->installEventFilter( this );
00278 XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
00279 decoration->widget()->lower();
00280 decoration->borders( border_left, border_right, border_top, border_bottom );
00281 options->onlyDecoTranslucent ?
00282 setDecoHashProperty(border_top, border_right, border_bottom, border_left):
00283 unsetDecoHashProperty();
00284 int save_workarea_diff_x = workarea_diff_x;
00285 int save_workarea_diff_y = workarea_diff_y;
00286 move( calculateGravitation( false ));
00287 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00288 workarea_diff_x = save_workarea_diff_x;
00289 workarea_diff_y = save_workarea_diff_y;
00290 do_show = true;
00291 }
00292 else
00293 destroyDecoration();
00294 if( check_workspace_pos )
00295 checkWorkspacePosition();
00296 postponeGeometryUpdates( false );
00297 if( do_show )
00298 decoration->widget()->show();
00299 updateFrameExtents();
00300 }
00301
00302 void Client::destroyDecoration()
00303 {
00304 if( decoration != NULL )
00305 {
00306 delete decoration;
00307 decoration = NULL;
00308 QPoint grav = calculateGravitation( true );
00309 border_left = border_right = border_top = border_bottom = 0;
00310 setMask( QRegion());
00311 int save_workarea_diff_x = workarea_diff_x;
00312 int save_workarea_diff_y = workarea_diff_y;
00313 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00314 move( grav );
00315 workarea_diff_x = save_workarea_diff_x;
00316 workarea_diff_y = save_workarea_diff_y;
00317 }
00318 }
00319
00320 void Client::checkBorderSizes()
00321 {
00322 if( decoration == NULL )
00323 return;
00324 int new_left, new_right, new_top, new_bottom;
00325 decoration->borders( new_left, new_right, new_top, new_bottom );
00326 if( new_left == border_left && new_right == border_right
00327 && new_top == border_top && new_bottom == border_bottom )
00328 return;
00329 GeometryUpdatesPostponer blocker( this );
00330 move( calculateGravitation( true ));
00331 border_left = new_left;
00332 border_right = new_right;
00333 border_top = new_top;
00334 border_bottom = new_bottom;
00335 if (border_left != new_left ||
00336 border_right != new_right ||
00337 border_top != new_top ||
00338 border_bottom != new_bottom)
00339 options->onlyDecoTranslucent ?
00340 setDecoHashProperty(new_top, new_right, new_bottom, new_left):
00341 unsetDecoHashProperty();
00342 move( calculateGravitation( false ));
00343 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00344 checkWorkspacePosition();
00345 }
00346
00347 void Client::detectNoBorder()
00348 {
00349 if( Shape::hasShape( window()))
00350 {
00351 noborder = true;
00352 return;
00353 }
00354 switch( windowType())
00355 {
00356 case NET::Desktop :
00357 case NET::Dock :
00358 case NET::TopMenu :
00359 case NET::Splash :
00360 noborder = true;
00361 break;
00362 case NET::Unknown :
00363 case NET::Normal :
00364 case NET::Toolbar :
00365 case NET::Menu :
00366 case NET::Dialog :
00367 case NET::Utility :
00368 noborder = false;
00369 break;
00370 default:
00371 assert( false );
00372 }
00373
00374
00375
00376 if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
00377 noborder = true;
00378 }
00379
00380 void Client::detectShapable()
00381 {
00382 if( Shape::hasShape( window()))
00383 return;
00384 switch( windowType())
00385 {
00386 case NET::Desktop :
00387 case NET::Dock :
00388 case NET::TopMenu :
00389 case NET::Splash :
00390 break;
00391 case NET::Unknown :
00392 case NET::Normal :
00393 case NET::Toolbar :
00394 case NET::Menu :
00395 case NET::Dialog :
00396 case NET::Utility :
00397 setShapable(FALSE);
00398 break;
00399 default:
00400 assert( false );
00401 }
00402 }
00403
00404 void Client::updateFrameExtents()
00405 {
00406 NETStrut strut;
00407 strut.left = border_left;
00408 strut.right = border_right;
00409 strut.top = border_top;
00410 strut.bottom = border_bottom;
00411 info->setFrameExtents( strut );
00412 }
00413
00414
00415
00416
00417
00418
00419 void Client::resizeDecoration( const QSize& s )
00420 {
00421 if( decoration == NULL )
00422 return;
00423 QSize oldsize = decoration->widget()->size();
00424 decoration->resize( s );
00425 if( oldsize == s )
00426 {
00427 QResizeEvent e( s, oldsize );
00428 QApplication::sendEvent( decoration->widget(), &e );
00429 }
00430 }
00431
00432 bool Client::noBorder() const
00433 {
00434 return noborder || isFullScreen() || user_noborder || motif_noborder;
00435 }
00436
00437 bool Client::userCanSetNoBorder() const
00438 {
00439 return !noborder && !isFullScreen() && !isShade();
00440 }
00441
00442 bool Client::isUserNoBorder() const
00443 {
00444 return user_noborder;
00445 }
00446
00447 void Client::setUserNoBorder( bool set )
00448 {
00449 if( !userCanSetNoBorder())
00450 return;
00451 set = rules()->checkNoBorder( set );
00452 if( user_noborder == set )
00453 return;
00454 user_noborder = set;
00455 updateDecoration( true, false );
00456 updateWindowRules();
00457 }
00458
00459 void Client::updateShape()
00460 {
00461 setShapable(TRUE);
00462 if ( shape() )
00463 {
00464 XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
00465 clientPos().x(), clientPos().y(),
00466 window(), ShapeBounding, ShapeSet);
00467 }
00468 else
00469 {
00470 XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00471 None, ShapeSet);
00472 }
00473
00474 if( shape() && !noBorder())
00475 {
00476 noborder = true;
00477 updateDecoration( true );
00478 }
00479 }
00480
00481 void Client::setMask( const QRegion& reg, int mode )
00482 {
00483 _mask = reg;
00484 if( reg.isNull())
00485 XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00486 None, ShapeSet );
00487 else if( mode == X::Unsorted )
00488 XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00489 reg.handle(), ShapeSet );
00490 else
00491 {
00492 QMemArray< QRect > rects = reg.rects();
00493 XRectangle* xrects = new XRectangle[ rects.count() ];
00494 for( unsigned int i = 0;
00495 i < rects.count();
00496 ++i )
00497 {
00498 xrects[ i ].x = rects[ i ].x();
00499 xrects[ i ].y = rects[ i ].y();
00500 xrects[ i ].width = rects[ i ].width();
00501 xrects[ i ].height = rects[ i ].height();
00502 }
00503 XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00504 xrects, rects.count(), ShapeSet, mode );
00505 delete[] xrects;
00506 }
00507 }
00508
00509 QRegion Client::mask() const
00510 {
00511 if( _mask.isEmpty())
00512 return QRegion( 0, 0, width(), height());
00513 return _mask;
00514 }
00515
00516 void Client::setShapable(bool b)
00517 {
00518 long tmp = b?1:0;
00519 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
00520 }
00521
00522 void Client::hideClient( bool hide )
00523 {
00524 if( hidden == hide )
00525 return;
00526 hidden = hide;
00527 updateVisibility();
00528 }
00529
00530
00531
00532
00533 bool Client::isMinimizable() const
00534 {
00535 if( isSpecialWindow())
00536 return false;
00537 if( isTransient())
00538 {
00539 bool shown_mainwindow = false;
00540 ClientList mainclients = mainClients();
00541 for( ClientList::ConstIterator it = mainclients.begin();
00542 it != mainclients.end();
00543 ++it )
00544 {
00545 if( (*it)->isShown( true ))
00546 shown_mainwindow = true;
00547 }
00548 if( !shown_mainwindow )
00549 return true;
00550 }
00551
00552
00553
00554 if( transientFor() != NULL )
00555 return false;
00556 if( !wantsTabFocus())
00557 return false;
00558 return true;
00559 }
00560
00564 void Client::minimize( bool avoid_animation )
00565 {
00566 if ( !isMinimizable() || isMinimized())
00567 return;
00568
00569 Notify::raise( Notify::Minimize );
00570
00571
00572 if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
00573 animateMinimizeOrUnminimize( true );
00574
00575 minimized = true;
00576
00577 updateVisibility();
00578 updateAllowedActions();
00579 workspace()->updateMinimizedOfTransients( this );
00580 updateWindowRules();
00581 workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
00582 }
00583
00584 void Client::unminimize( bool avoid_animation )
00585 {
00586 if( !isMinimized())
00587 return;
00588
00589 Notify::raise( Notify::UnMinimize );
00590 minimized = false;
00591 if( isOnCurrentDesktop() && isShown( true ))
00592 {
00593 if( mainClients().isEmpty() && !avoid_animation )
00594 animateMinimizeOrUnminimize( FALSE );
00595 }
00596 updateVisibility();
00597 updateAllowedActions();
00598 workspace()->updateMinimizedOfTransients( this );
00599 updateWindowRules();
00600 }
00601
00602 extern bool blockAnimation;
00603
00604 void Client::animateMinimizeOrUnminimize( bool minimize )
00605 {
00606 if ( blockAnimation )
00607 return;
00608 if ( !options->animateMinimize )
00609 return;
00610
00611 if( decoration != NULL && decoration->animateMinimize( minimize ))
00612 return;
00613
00614
00615
00616
00617
00618 float lf,rf,tf,bf,step;
00619
00620 int speed = options->animateMinimizeSpeed;
00621 if ( speed > 10 )
00622 speed = 10;
00623 if ( speed < 0 )
00624 speed = 0;
00625
00626 step = 40. * (11 - speed );
00627
00628 NETRect r = info->iconGeometry();
00629 QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00630 if ( !icongeom.isValid() )
00631 return;
00632
00633 QPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
00634
00635 QRect before, after;
00636 if ( minimize )
00637 {
00638 before = QRect( x(), y(), width(), pm.height() );
00639 after = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00640 }
00641 else
00642 {
00643 before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00644 after = QRect( x(), y(), width(), pm.height() );
00645 }
00646
00647 lf = (after.left() - before.left())/step;
00648 rf = (after.right() - before.right())/step;
00649 tf = (after.top() - before.top())/step;
00650 bf = (after.bottom() - before.bottom())/step;
00651
00652 grabXServer();
00653
00654 QRect area = before;
00655 QRect area2;
00656 QPixmap pm2;
00657
00658 QTime t;
00659 t.start();
00660 float diff;
00661
00662 QPainter p ( workspace()->desktopWidget() );
00663 bool need_to_clear = FALSE;
00664 QPixmap pm3;
00665 do
00666 {
00667 if (area2 != area)
00668 {
00669 pm = animationPixmap( area.width() );
00670 pm2 = QPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
00671 p.drawPixmap( area.x(), area.y(), pm );
00672 if ( need_to_clear )
00673 {
00674 p.drawPixmap( area2.x(), area2.y(), pm3 );
00675 need_to_clear = FALSE;
00676 }
00677 area2 = area;
00678 }
00679 XFlush(qt_xdisplay());
00680 XSync( qt_xdisplay(), FALSE );
00681 diff = t.elapsed();
00682 if (diff > step)
00683 diff = step;
00684 area.setLeft(before.left() + int(diff*lf));
00685 area.setRight(before.right() + int(diff*rf));
00686 area.setTop(before.top() + int(diff*tf));
00687 area.setBottom(before.bottom() + int(diff*bf));
00688 if (area2 != area )
00689 {
00690 if ( area2.intersects( area ) )
00691 p.drawPixmap( area2.x(), area2.y(), pm2 );
00692 else
00693 {
00694 pm3 = pm2;
00695 need_to_clear = TRUE;
00696 }
00697 }
00698 } while ( t.elapsed() < step);
00699 if (area2 == area || need_to_clear )
00700 p.drawPixmap( area2.x(), area2.y(), pm2 );
00701
00702 p.end();
00703 ungrabXServer();
00704 }
00705
00706
00710 QPixmap Client::animationPixmap( int w )
00711 {
00712 QFont font = options->font(isActive());
00713 QFontMetrics fm( font );
00714 QPixmap pm( w, fm.lineSpacing() );
00715 pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
00716 QPainter p( &pm );
00717 p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
00718 p.setFont(options->font(isActive()));
00719 p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
00720 return pm;
00721 }
00722
00723
00724 bool Client::isShadeable() const
00725 {
00726 return !isSpecialWindow() && !noBorder();
00727 }
00728
00729 void Client::setShade( ShadeMode mode )
00730 {
00731 if( !isShadeable())
00732 return;
00733 mode = rules()->checkShade( mode );
00734 if( shade_mode == mode )
00735 return;
00736 bool was_shade = isShade();
00737 ShadeMode was_shade_mode = shade_mode;
00738 shade_mode = mode;
00739 if( was_shade == isShade())
00740 {
00741 if( decoration != NULL )
00742 decoration->shadeChange();
00743 return;
00744 }
00745
00746 if( shade_mode == ShadeNormal )
00747 {
00748 if ( isShown( true ) && isOnCurrentDesktop())
00749 Notify::raise( Notify::ShadeUp );
00750 }
00751 else if( shade_mode == ShadeNone )
00752 {
00753 if( isShown( true ) && isOnCurrentDesktop())
00754 Notify::raise( Notify::ShadeDown );
00755 }
00756
00757 assert( decoration != NULL );
00758 GeometryUpdatesPostponer blocker( this );
00759
00760 decoration->borders( border_left, border_right, border_top, border_bottom );
00761
00762 int as = options->animateShade? 10 : 1;
00763
00764 if ( isShade())
00765 {
00766
00767 long _shade = 1;
00768 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00769
00770 int h = height();
00771 shade_geometry_change = true;
00772 QSize s( sizeForClientSize( QSize( clientSize())));
00773 s.setHeight( border_top + border_bottom );
00774 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
00775 XUnmapWindow( qt_xdisplay(), wrapper );
00776 XUnmapWindow( qt_xdisplay(), client );
00777 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00778
00779
00780
00781
00782
00783 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00784 do
00785 {
00786 h -= step;
00787 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00788 resizeDecoration( QSize( s.width(), h ));
00789 QApplication::syncX();
00790 } while ( h > s.height() + step );
00791
00792
00793 plainResize( s );
00794 shade_geometry_change = false;
00795 if( isActive())
00796 {
00797 if( was_shade_mode == ShadeHover )
00798 workspace()->activateNextClient( this );
00799 else
00800 workspace()->focusToNull();
00801 }
00802
00803 _shade = 2;
00804 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00805 }
00806 else
00807 {
00808 int h = height();
00809 shade_geometry_change = true;
00810 QSize s( sizeForClientSize( clientSize()));
00811
00812
00813 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00814 do
00815 {
00816 h += step;
00817 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00818 resizeDecoration( QSize( s.width(), h ));
00819
00820
00821
00822 QApplication::syncX();
00823 } while ( h < s.height() - step );
00824
00825
00826 shade_geometry_change = false;
00827 plainResize( s );
00828 if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00829 setActive( TRUE );
00830 XMapWindow( qt_xdisplay(), wrapperId());
00831 XMapWindow( qt_xdisplay(), window());
00832 XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
00833 if ( isActive() )
00834 workspace()->requestFocus( this );
00835 }
00836 checkMaximizeGeometry();
00837 info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00838 info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00839 updateVisibility();
00840 updateAllowedActions();
00841 workspace()->updateMinimizedOfTransients( this );
00842 decoration->shadeChange();
00843 updateWindowRules();
00844 }
00845
00846 void Client::shadeHover()
00847 {
00848 setShade( ShadeHover );
00849 cancelShadeHover();
00850 }
00851
00852 void Client::cancelShadeHover()
00853 {
00854 delete shadeHoverTimer;
00855 shadeHoverTimer = 0;
00856 }
00857
00858 void Client::toggleShade()
00859 {
00860
00861 setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00862 }
00863
00864 void Client::updateVisibility()
00865 {
00866 if( deleting )
00867 return;
00868 bool show = true;
00869 if( hidden )
00870 {
00871 setMappingState( IconicState );
00872 info->setState( NET::Hidden, NET::Hidden );
00873 setSkipTaskbar( true, false );
00874 rawHide();
00875 show = false;
00876 }
00877 else
00878 {
00879 setSkipTaskbar( original_skip_taskbar, false );
00880 }
00881 if( minimized )
00882 {
00883 setMappingState( IconicState );
00884 info->setState( NET::Hidden, NET::Hidden );
00885 rawHide();
00886 show = false;
00887 }
00888 if( show )
00889 info->setState( 0, NET::Hidden );
00890 if( !isOnCurrentDesktop())
00891 {
00892 setMappingState( IconicState );
00893 rawHide();
00894 show = false;
00895 }
00896 if( show )
00897 {
00898 bool belongs_to_desktop = false;
00899 for( ClientList::ConstIterator it = group()->members().begin();
00900 it != group()->members().end();
00901 ++it )
00902 if( (*it)->isDesktop())
00903 {
00904 belongs_to_desktop = true;
00905 break;
00906 }
00907 if( !belongs_to_desktop && workspace()->showingDesktop())
00908 workspace()->resetShowingDesktop( true );
00909 if( isShade())
00910 setMappingState( IconicState );
00911 else
00912 setMappingState( NormalState );
00913 rawShow();
00914 }
00915 }
00916
00921 void Client::setMappingState(int s)
00922 {
00923 assert( client != None );
00924 assert( !deleting || s == WithdrawnState );
00925 if( mapping_state == s )
00926 return;
00927 bool was_unmanaged = ( mapping_state == WithdrawnState );
00928 mapping_state = s;
00929 if( mapping_state == WithdrawnState )
00930 {
00931 XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
00932 return;
00933 }
00934 assert( s == NormalState || s == IconicState );
00935
00936 unsigned long data[2];
00937 data[0] = (unsigned long) s;
00938 data[1] = (unsigned long) None;
00939 XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
00940 PropModeReplace, (unsigned char *)data, 2);
00941
00942 if( was_unmanaged )
00943 postponeGeometryUpdates( false );
00944 }
00945
00950 void Client::rawShow()
00951 {
00952 if( decoration != NULL )
00953 decoration->widget()->show();
00954 XMapWindow( qt_xdisplay(), frame );
00955 if( !isShade())
00956 {
00957 XMapWindow( qt_xdisplay(), wrapper );
00958 XMapWindow( qt_xdisplay(), client );
00959 }
00960 }
00961
00967 void Client::rawHide()
00968 {
00969
00970
00971
00972
00973
00974
00975 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
00976 XUnmapWindow( qt_xdisplay(), frame );
00977 XUnmapWindow( qt_xdisplay(), wrapper );
00978 XUnmapWindow( qt_xdisplay(), client );
00979 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00980 if( decoration != NULL )
00981 decoration->widget()->hide();
00982 workspace()->clientHidden( this );
00983 }
00984
00985 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
00986 {
00987 XEvent ev;
00988 long mask;
00989
00990 memset(&ev, 0, sizeof(ev));
00991 ev.xclient.type = ClientMessage;
00992 ev.xclient.window = w;
00993 ev.xclient.message_type = a;
00994 ev.xclient.format = 32;
00995 ev.xclient.data.l[0] = protocol;
00996 ev.xclient.data.l[1] = qt_x_time;
00997 ev.xclient.data.l[2] = data1;
00998 ev.xclient.data.l[3] = data2;
00999 ev.xclient.data.l[4] = data3;
01000 mask = 0L;
01001 if (w == qt_xrootwin())
01002 mask = SubstructureRedirectMask;
01003 XSendEvent(qt_xdisplay(), w, False, mask, &ev);
01004 }
01005
01006
01007
01008
01009 bool Client::isCloseable() const
01010 {
01011 return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
01012 }
01013
01018 void Client::closeWindow()
01019 {
01020 if( !isCloseable())
01021 return;
01022
01023 updateUserTime();
01024 if ( Pdeletewindow )
01025 {
01026 Notify::raise( Notify::Close );
01027 sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
01028 pingWindow();
01029 }
01030 else
01031 {
01032
01033
01034 killWindow();
01035 }
01036 }
01037
01038
01042 void Client::killWindow()
01043 {
01044 kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
01045
01046
01047 Notify::raise( Notify::Close );
01048
01049 if( isDialog())
01050 Notify::raise( Notify::TransDelete );
01051 if( isNormalWindow())
01052 Notify::raise( Notify::Delete );
01053 killProcess( false );
01054
01055 XKillClient(qt_xdisplay(), window() );
01056 destroyClient();
01057 }
01058
01059
01060
01061
01062 void Client::pingWindow()
01063 {
01064 if( !Pping )
01065 return;
01066 if( options->killPingTimeout == 0 )
01067 return;
01068 if( ping_timer != NULL )
01069 return;
01070 ping_timer = new QTimer( this );
01071 connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout()));
01072 ping_timer->start( options->killPingTimeout, true );
01073 ping_timestamp = qt_x_time;
01074 workspace()->sendPingToWindow( window(), ping_timestamp );
01075 }
01076
01077 void Client::gotPing( Time timestamp )
01078 {
01079 if( timestamp != ping_timestamp )
01080 return;
01081 delete ping_timer;
01082 ping_timer = NULL;
01083 if( process_killer != NULL )
01084 {
01085 process_killer->kill();
01086 delete process_killer;
01087 process_killer = NULL;
01088 }
01089 }
01090
01091 void Client::pingTimeout()
01092 {
01093 kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
01094 delete ping_timer;
01095 ping_timer = NULL;
01096 killProcess( true, ping_timestamp );
01097 }
01098
01099 void Client::killProcess( bool ask, Time timestamp )
01100 {
01101 if( process_killer != NULL )
01102 return;
01103 Q_ASSERT( !ask || timestamp != CurrentTime );
01104 QCString machine = wmClientMachine( true );
01105 pid_t pid = info->pid();
01106 if( pid <= 0 || machine.isEmpty())
01107 return;
01108 kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01109 if( !ask )
01110 {
01111 if( machine != "localhost" )
01112 {
01113 KProcess proc;
01114 proc << "xon" << machine << "kill" << pid;
01115 proc.start( KProcess::DontCare );
01116 }
01117 else
01118 ::kill( pid, SIGTERM );
01119 }
01120 else
01121 {
01122 process_killer = new KProcess( this );
01123 *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01124 << "--pid" << QCString().setNum( pid ) << "--hostname" << machine
01125 << "--windowname" << caption().utf8()
01126 << "--applicationname" << resourceClass()
01127 << "--wid" << QCString().setNum( window())
01128 << "--timestamp" << QCString().setNum( timestamp );
01129 connect( process_killer, SIGNAL( processExited( KProcess* )),
01130 SLOT( processKillerExited()));
01131 if( !process_killer->start( KProcess::NotifyOnExit ))
01132 {
01133 delete process_killer;
01134 process_killer = NULL;
01135 return;
01136 }
01137 }
01138 }
01139
01140 void Client::processKillerExited()
01141 {
01142 kdDebug( 1212 ) << "Killer exited" << endl;
01143 delete process_killer;
01144 process_killer = NULL;
01145 }
01146
01147 void Client::setSkipTaskbar( bool b, bool from_outside )
01148 {
01149 int was_wants_tab_focus = wantsTabFocus();
01150 if( from_outside )
01151 {
01152 b = rules()->checkSkipTaskbar( b );
01153 original_skip_taskbar = b;
01154 }
01155 if ( b == skipTaskbar() )
01156 return;
01157 skip_taskbar = b;
01158 info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01159 updateWindowRules();
01160 if( was_wants_tab_focus != wantsTabFocus())
01161 workspace()->updateFocusChains( this,
01162 isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
01163 }
01164
01165 void Client::setSkipPager( bool b )
01166 {
01167 b = rules()->checkSkipPager( b );
01168 if ( b == skipPager() )
01169 return;
01170 skip_pager = b;
01171 info->setState( b?NET::SkipPager:0, NET::SkipPager );
01172 updateWindowRules();
01173 }
01174
01175 void Client::setModal( bool m )
01176 {
01177 if( modal == m )
01178 return;
01179 modal = m;
01180 if( !modal )
01181 return;
01182
01183
01184 }
01185
01186 void Client::setDesktop( int desktop )
01187 {
01188 if( desktop != NET::OnAllDesktops )
01189 desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
01190 desktop = rules()->checkDesktop( desktop );
01191 if( desk == desktop )
01192 return;
01193 int was_desk = desk;
01194 desk = desktop;
01195 info->setDesktop( desktop );
01196 if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01197 {
01198 if ( isShown( true ))
01199 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01200 workspace()->updateOnAllDesktopsOfTransients( this );
01201 }
01202 if( decoration != NULL )
01203 decoration->desktopChange();
01204 workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
01205 updateVisibility();
01206 updateWindowRules();
01207 }
01208
01209 void Client::setOnAllDesktops( bool b )
01210 {
01211 if(( b && isOnAllDesktops())
01212 || ( !b && !isOnAllDesktops()))
01213 return;
01214 if( b )
01215 setDesktop( NET::OnAllDesktops );
01216 else
01217 setDesktop( workspace()->currentDesktop());
01218 }
01219
01220 bool Client::isOnCurrentDesktop() const
01221 {
01222 return isOnDesktop( workspace()->currentDesktop());
01223 }
01224
01225
01226 void Client::takeActivity( int flags, bool handled, allowed_t )
01227 {
01228 if( !handled || !Ptakeactivity )
01229 {
01230 if( flags & ActivityFocus )
01231 takeFocus( Allowed );
01232 if( flags & ActivityRaise )
01233 workspace()->raiseClient( this );
01234 return;
01235 }
01236
01237 #ifndef NDEBUG
01238 static Time previous_activity_timestamp;
01239 static Client* previous_client;
01240 if( previous_activity_timestamp == qt_x_time && previous_client != this )
01241 {
01242 kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
01243 kdDebug( 1212 ) << kdBacktrace() << endl;
01244 }
01245 previous_activity_timestamp = qt_x_time;
01246 previous_client = this;
01247 #endif
01248 workspace()->sendTakeActivity( this, qt_x_time, flags );
01249 }
01250
01251
01252 void Client::takeFocus( allowed_t )
01253 {
01254 #ifndef NDEBUG
01255 static Time previous_focus_timestamp;
01256 static Client* previous_client;
01257 if( previous_focus_timestamp == qt_x_time && previous_client != this )
01258 {
01259 kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01260 kdDebug( 1212 ) << kdBacktrace() << endl;
01261 }
01262 previous_focus_timestamp = qt_x_time;
01263 previous_client = this;
01264 #endif
01265 if ( rules()->checkAcceptFocus( input ))
01266 {
01267 XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01268 }
01269 if ( Ptakefocus )
01270 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01271 workspace()->setShouldGetFocus( this );
01272 }
01273
01281 bool Client::providesContextHelp() const
01282 {
01283 return Pcontexthelp;
01284 }
01285
01286
01293 void Client::showContextHelp()
01294 {
01295 if ( Pcontexthelp )
01296 {
01297 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01298 QWhatsThis::enterWhatsThisMode();
01299 }
01300 }
01301
01302
01307 void Client::fetchName()
01308 {
01309 setCaption( readName());
01310 }
01311
01312 QString Client::readName() const
01313 {
01314 if ( info->name() && info->name()[ 0 ] != '\0' )
01315 return QString::fromUtf8( info->name() );
01316 else
01317 return KWin::readNameProperty( window(), XA_WM_NAME );
01318 }
01319
01320 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
01321
01322 void Client::setCaption( const QString& s, bool force )
01323 {
01324 if ( s != cap_normal || force )
01325 {
01326 bool reset_name = force;
01327 for( unsigned int i = 0;
01328 i < s.length();
01329 ++i )
01330 if( !s[ i ].isPrint())
01331 s[ i ] = ' ';
01332 cap_normal = s;
01333 bool was_suffix = ( !cap_suffix.isEmpty());
01334 QString machine_suffix;
01335 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
01336 machine_suffix = " <@" + wmClientMachine( true ) + ">";
01337 QString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
01338 cap_suffix = machine_suffix + shortcut_suffix;
01339 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
01340 {
01341 int i = 2;
01342 do
01343 {
01344 cap_suffix = machine_suffix + " <" + QString::number(i) + ">" + shortcut_suffix;
01345 i++;
01346 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
01347 info->setVisibleName( caption().utf8() );
01348 reset_name = false;
01349 }
01350 if(( was_suffix && cap_suffix.isEmpty()
01351 || reset_name ))
01352 {
01353 info->setVisibleName( "" );
01354 info->setVisibleIconName( "" );
01355 }
01356 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
01357 info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
01358
01359 if( isManaged() && decoration != NULL )
01360 decoration->captionChange();
01361 }
01362 }
01363
01364 void Client::updateCaption()
01365 {
01366 setCaption( cap_normal, true );
01367 }
01368
01369 void Client::fetchIconicName()
01370 {
01371 QString s;
01372 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
01373 s = QString::fromUtf8( info->iconName() );
01374 else
01375 s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
01376 if ( s != cap_iconic )
01377 {
01378 bool was_set = !cap_iconic.isEmpty();
01379 cap_iconic = s;
01380 if( !cap_suffix.isEmpty())
01381 {
01382 if( !cap_iconic.isEmpty())
01383 info->setVisibleIconName( ( s + cap_suffix ).utf8() );
01384 else if( was_set )
01385 info->setVisibleIconName( "" );
01386 }
01387 }
01388 }
01389
01392 QString Client::caption( bool full ) const
01393 {
01394 return full ? cap_normal + cap_suffix : cap_normal;
01395 }
01396
01397 void Client::getWMHints()
01398 {
01399 XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
01400 input = true;
01401 window_group = None;
01402 urgency = false;
01403 if ( hints )
01404 {
01405 if( hints->flags & InputHint )
01406 input = hints->input;
01407 if( hints->flags & WindowGroupHint )
01408 window_group = hints->window_group;
01409 urgency = ( hints->flags & UrgencyHint ) ? true : false;
01410 XFree( (char*)hints );
01411 }
01412 checkGroup();
01413 updateUrgency();
01414 updateAllowedActions();
01415 }
01416
01417 void Client::getMotifHints()
01418 {
01419 bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
01420 Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
01421 motif_noborder = mnoborder;
01422 if( !hasNETSupport())
01423 {
01424 motif_may_resize = mresize;
01425 motif_may_move = mmove;
01426 }
01427 else
01428 motif_may_resize = motif_may_move = true;
01429
01430
01431 motif_may_close = mclose;
01432 if( isManaged())
01433 updateDecoration( true );
01434 }
01435
01436 void Client::readIcons( Window win, QPixmap* icon, QPixmap* miniicon )
01437 {
01438
01439 if( icon != NULL )
01440 *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
01441 if( miniicon != NULL )
01442 if( icon == NULL || !icon->isNull())
01443 *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
01444 else
01445 *miniicon = QPixmap();
01446 }
01447
01448 void Client::getIcons()
01449 {
01450
01451 readIcons( window(), &icon_pix, &miniicon_pix );
01452 if( icon_pix.isNull())
01453 {
01454 icon_pix = group()->icon();
01455 miniicon_pix = group()->miniIcon();
01456 }
01457 if( icon_pix.isNull() && isTransient())
01458 {
01459 ClientList mainclients = mainClients();
01460 for( ClientList::ConstIterator it = mainclients.begin();
01461 it != mainclients.end() && icon_pix.isNull();
01462 ++it )
01463 {
01464 icon_pix = (*it)->icon();
01465 miniicon_pix = (*it)->miniIcon();
01466 }
01467 }
01468 if( icon_pix.isNull())
01469 {
01470 icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
01471 miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
01472 }
01473 if( isManaged() && decoration != NULL )
01474 decoration->iconChange();
01475 }
01476
01477 void Client::getWindowProtocols()
01478 {
01479 Atom *p;
01480 int i,n;
01481
01482 Pdeletewindow = 0;
01483 Ptakefocus = 0;
01484 Ptakeactivity = 0;
01485 Pcontexthelp = 0;
01486 Pping = 0;
01487
01488 if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
01489 {
01490 for (i = 0; i < n; i++)
01491 if (p[i] == atoms->wm_delete_window)
01492 Pdeletewindow = 1;
01493 else if (p[i] == atoms->wm_take_focus)
01494 Ptakefocus = 1;
01495 else if (p[i] == atoms->net_wm_take_activity)
01496 Ptakeactivity = 1;
01497 else if (p[i] == atoms->net_wm_context_help)
01498 Pcontexthelp = 1;
01499 else if (p[i] == atoms->net_wm_ping)
01500 Pping = 1;
01501 if (n>0)
01502 XFree(p);
01503 }
01504 }
01505
01506 static int nullErrorHandler(Display *, XErrorEvent *)
01507 {
01508 return 0;
01509 }
01510
01514 QCString Client::staticWindowRole(WId w)
01515 {
01516 return getStringProperty(w, qt_window_role).lower();
01517 }
01518
01522 QCString Client::staticSessionId(WId w)
01523 {
01524 return getStringProperty(w, qt_sm_client_id);
01525 }
01526
01530 QCString Client::staticWmCommand(WId w)
01531 {
01532 return getStringProperty(w, XA_WM_COMMAND, ' ');
01533 }
01534
01538 Window Client::staticWmClientLeader(WId w)
01539 {
01540 Atom type;
01541 int format, status;
01542 unsigned long nitems = 0;
01543 unsigned long extra = 0;
01544 unsigned char *data = 0;
01545 Window result = w;
01546 XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
01547 status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
01548 FALSE, XA_WINDOW, &type, &format,
01549 &nitems, &extra, &data );
01550 XSetErrorHandler(oldHandler);
01551 if (status == Success )
01552 {
01553 if (data && nitems > 0)
01554 result = *((Window*) data);
01555 XFree(data);
01556 }
01557 return result;
01558 }
01559
01560
01561 void Client::getWmClientLeader()
01562 {
01563 wmClientLeaderWin = staticWmClientLeader(window());
01564 }
01565
01570 QCString Client::sessionId()
01571 {
01572 QCString result = staticSessionId(window());
01573 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01574 result = staticSessionId(wmClientLeaderWin);
01575 return result;
01576 }
01577
01582 QCString Client::wmCommand()
01583 {
01584 QCString result = staticWmCommand(window());
01585 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01586 result = staticWmCommand(wmClientLeaderWin);
01587 return result;
01588 }
01589
01590 void Client::getWmClientMachine()
01591 {
01592 client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
01593 if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01594 client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
01595 if( client_machine.isEmpty())
01596 client_machine = "localhost";
01597 }
01598
01603 QCString Client::wmClientMachine( bool use_localhost ) const
01604 {
01605 QCString result = client_machine;
01606 if( use_localhost )
01607 {
01608 if( result != "localhost" && isLocalMachine( result ))
01609 result = "localhost";
01610 }
01611 return result;
01612 }
01613
01618 Window Client::wmClientLeader() const
01619 {
01620 if (wmClientLeaderWin)
01621 return wmClientLeaderWin;
01622 return window();
01623 }
01624
01625 bool Client::wantsTabFocus() const
01626 {
01627 return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
01628 }
01629
01630
01631 bool Client::wantsInput() const
01632 {
01633 return rules()->checkAcceptFocus( input || Ptakefocus );
01634 }
01635
01636 bool Client::isDesktop() const
01637 {
01638 return windowType() == NET::Desktop;
01639 }
01640
01641 bool Client::isDock() const
01642 {
01643 return windowType() == NET::Dock;
01644 }
01645
01646 bool Client::isTopMenu() const
01647 {
01648 return windowType() == NET::TopMenu;
01649 }
01650
01651
01652 bool Client::isMenu() const
01653 {
01654 return windowType() == NET::Menu && !isTopMenu();
01655 }
01656
01657 bool Client::isToolbar() const
01658 {
01659 return windowType() == NET::Toolbar;
01660 }
01661
01662 bool Client::isSplash() const
01663 {
01664 return windowType() == NET::Splash;
01665 }
01666
01667 bool Client::isUtility() const
01668 {
01669 return windowType() == NET::Utility;
01670 }
01671
01672 bool Client::isDialog() const
01673 {
01674 return windowType() == NET::Dialog;
01675 }
01676
01677 bool Client::isNormalWindow() const
01678 {
01679 return windowType() == NET::Normal;
01680 }
01681
01682 bool Client::isSpecialWindow() const
01683 {
01684 return isDesktop() || isDock() || isSplash() || isTopMenu()
01685 || isToolbar();
01686 }
01687
01688 NET::WindowType Client::windowType( bool direct, int supported_types ) const
01689 {
01690 NET::WindowType wt = info->windowType( supported_types );
01691 if( direct )
01692 return wt;
01693 NET::WindowType wt2 = rules()->checkType( wt );
01694 if( wt != wt2 )
01695 {
01696 wt = wt2;
01697 info->setWindowType( wt );
01698 }
01699
01700 if( wt == NET::Menu )
01701 {
01702
01703
01704
01705 if( x() == 0 && y() < 0 && y() > -10 && height() < 100
01706 && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
01707 wt = NET::TopMenu;
01708 }
01709
01710 const char* const oo_prefix = "openoffice.org";
01711
01712 if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
01713 wt = NET::Normal;
01714 if( wt == NET::Unknown )
01715 wt = isTransient() ? NET::Dialog : NET::Normal;
01716 return wt;
01717 }
01718
01723 void Client::setCursor( Position m )
01724 {
01725 if( !isResizable() || isShade())
01726 {
01727 m = PositionCenter;
01728 }
01729 switch ( m )
01730 {
01731 case PositionTopLeft:
01732 case PositionBottomRight:
01733 setCursor( sizeFDiagCursor );
01734 break;
01735 case PositionBottomLeft:
01736 case PositionTopRight:
01737 setCursor( sizeBDiagCursor );
01738 break;
01739 case PositionTop:
01740 case PositionBottom:
01741 setCursor( sizeVerCursor );
01742 break;
01743 case PositionLeft:
01744 case PositionRight:
01745 setCursor( sizeHorCursor );
01746 break;
01747 default:
01748 if( buttonDown && isMovable())
01749 setCursor( sizeAllCursor );
01750 else
01751 setCursor( arrowCursor );
01752 break;
01753 }
01754 }
01755
01756
01757 void Client::setCursor( const QCursor& c )
01758 {
01759 if( c.handle() == cursor.handle())
01760 return;
01761 cursor = c;
01762 if( decoration != NULL )
01763 decoration->widget()->setCursor( cursor );
01764 XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
01765 }
01766
01767 Client::Position Client::mousePosition( const QPoint& p ) const
01768 {
01769 if( decoration != NULL )
01770 return decoration->mousePosition( p );
01771 return PositionCenter;
01772 }
01773
01774 void Client::updateAllowedActions( bool force )
01775 {
01776 if( !isManaged() && !force )
01777 return;
01778 unsigned long old_allowed_actions = allowed_actions;
01779 allowed_actions = 0;
01780 if( isMovable())
01781 allowed_actions |= NET::ActionMove;
01782 if( isResizable())
01783 allowed_actions |= NET::ActionResize;
01784 if( isMinimizable())
01785 allowed_actions |= NET::ActionMinimize;
01786 if( isShadeable())
01787 allowed_actions |= NET::ActionShade;
01788
01789 if( isMaximizable())
01790 allowed_actions |= NET::ActionMax;
01791 if( userCanSetFullScreen())
01792 allowed_actions |= NET::ActionFullScreen;
01793 allowed_actions |= NET::ActionChangeDesktop;
01794 if( isCloseable())
01795 allowed_actions |= NET::ActionClose;
01796 if( old_allowed_actions == allowed_actions )
01797 return;
01798
01799 info->setAllowedActions( allowed_actions );
01800
01801 }
01802
01803 void Client::autoRaise()
01804 {
01805 workspace()->raiseClient( this );
01806 cancelAutoRaise();
01807 }
01808
01809 void Client::cancelAutoRaise()
01810 {
01811 delete autoRaiseTimer;
01812 autoRaiseTimer = 0;
01813 }
01814
01815 void Client::setOpacity(bool translucent, uint opacity)
01816 {
01817 if (isDesktop())
01818 return;
01819
01820
01821 if (!translucent || opacity == 0xFFFFFFFF)
01822 {
01823 opacity_ = 0xFFFFFFFF;
01824 XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
01825 XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity);
01826 }
01827 else{
01828 if(opacity == opacity_)
01829 return;
01830 opacity_ = opacity;
01831 long data = opacity;
01832 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01833 XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01834 }
01835 }
01836
01837 void Client::setShadowSize(uint shadowSize)
01838 {
01839
01840
01841 long data = shadowSize;
01842 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01843 }
01844
01845 void Client::updateOpacity()
01846
01847 {
01848 if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
01849 return;
01850 if (isActive())
01851 {
01852 if( ruleOpacityActive() )
01853 setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01854 else
01855 setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01856 if (isBMP())
01857
01858 {
01859 ClientList tmpGroupMembers = group()->members();
01860 ClientList activeGroupMembers;
01861 activeGroupMembers.append(this);
01862 tmpGroupMembers.remove(this);
01863 ClientList::Iterator it = tmpGroupMembers.begin();
01864 while (it != tmpGroupMembers.end())
01865
01866 {
01867 if ((*it) != this && (*it)->isBMP())
01868
01869 {
01870
01871 if ((*it)->touches(this))
01872 {
01873
01874 if( ruleOpacityActive() )
01875 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01876 else
01877 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01878
01879 (*it)->setShadowSize(options->activeWindowShadowSize);
01880 activeGroupMembers.append(*it);
01881 tmpGroupMembers.remove(it);
01882 it = tmpGroupMembers.begin();
01883 continue;
01884 }
01885 else
01886 {
01887 bool found = false;
01888 for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
01889 {
01890 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01891 {
01892
01893 if( ruleOpacityActive() )
01894 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01895 else
01896 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01897 (*it)->setShadowSize(options->activeWindowShadowSize);
01898 activeGroupMembers.append(*it);
01899 tmpGroupMembers.remove(it);
01900 it = tmpGroupMembers.begin();
01901 found = true;
01902
01903 break;
01904 }
01905 }
01906 if (found) continue;
01907 }
01908 }
01909 it++;
01910 }
01911 }
01912 else if (isNormalWindow())
01913
01914 {
01915 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
01916 if ((*it)->isDialog() || (*it)->isUtility())
01917 if( (*it)->ruleOpacityActive() )
01918 (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
01919 else
01920 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01921 }
01922 }
01923 else
01924 {
01925 if( ruleOpacityInactive() )
01926 setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
01927 else
01928 setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
01929 options->inactiveWindowOpacity);
01930
01931 if (isBMP())
01932
01933 {
01934 ClientList tmpGroupMembers = group()->members();
01935 ClientList inactiveGroupMembers;
01936 inactiveGroupMembers.append(this);
01937 tmpGroupMembers.remove(this);
01938 ClientList::Iterator it = tmpGroupMembers.begin();
01939 while ( it != tmpGroupMembers.end() )
01940
01941 {
01942 if ((*it) != this && (*it)->isBMP())
01943
01944 {
01945
01946 if ((*it)->touches(this))
01947 {
01948
01949 if( (*it)->ruleOpacityInactive() )
01950 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01951 else
01952 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
01953 (*it)->setShadowSize(options->inactiveWindowShadowSize);
01954
01955 inactiveGroupMembers.append(*it);
01956 tmpGroupMembers.remove(it);
01957 it = tmpGroupMembers.begin();
01958 continue;
01959 }
01960 else
01961 {
01962 bool found = false;
01963 for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
01964 {
01965 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01966 {
01967
01968 if( (*it)->ruleOpacityInactive() )
01969 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01970 else
01971 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
01972 (*it)->setShadowSize(options->inactiveWindowShadowSize);
01973
01974 inactiveGroupMembers.append(*it);
01975 tmpGroupMembers.remove(it);
01976 it = tmpGroupMembers.begin();
01977 found = true;
01978 break;
01979 }
01980 }
01981 if (found) continue;
01982 }
01983 }
01984 it++;
01985 }
01986 }
01987 else if (isNormalWindow())
01988 {
01989 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
01990 if ((*it)->isUtility())
01991 if( (*it)->ruleOpacityInactive() )
01992 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01993 else
01994 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
01995 }
01996 }
01997 }
01998
01999 void Client::updateShadowSize()
02000
02001 {
02002 if (!(isNormalWindow() || isDialog() || isUtility() ))
02003 return;
02004 if (isActive())
02005 setShadowSize(options->activeWindowShadowSize);
02006 else
02007 setShadowSize(options->inactiveWindowShadowSize);
02008 }
02009
02010 uint Client::ruleOpacityInactive()
02011 {
02012 return rule_opacity_inactive;
02013 }
02014
02015 uint Client::ruleOpacityActive()
02016 {
02017 return rule_opacity_active;
02018 }
02019
02020 bool Client::getWindowOpacity()
02021 {
02022 unsigned char *data = 0;
02023 Atom actual;
02024 int format, result;
02025 unsigned long n, left;
02026 result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, &data);
02027 if (result == Success && data != None && format == 32 )
02028 {
02029 opacity_ = *reinterpret_cast< long* >( data );
02030 custom_opacity = true;
02031
02032 XFree ((char*)data);
02033 return TRUE;
02034 }
02035 return FALSE;
02036 }
02037
02038 void Client::setCustomOpacityFlag(bool custom)
02039 {
02040 custom_opacity = custom;
02041 }
02042
02043 uint Client::opacity()
02044 {
02045 return opacity_;
02046 }
02047
02048 int Client::opacityPercentage()
02049 {
02050 return int(100*((double)opacity_/0xffffffff));
02051 }
02052
02053 bool Client::touches(const Client* c)
02054
02055 {
02056 if (y() == c->y() + c->height())
02057 return TRUE;
02058 if (y() + height() == c->y())
02059 return TRUE;
02060 if (x() == c->x() + c->width())
02061 return TRUE;
02062 if (x() + width() == c->x())
02063 return TRUE;
02064 return FALSE;
02065 }
02066
02067 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
02068 {
02069 long data = (topHeight < 255 ? topHeight : 255) << 24 |
02070 (rightWidth < 255 ? rightWidth : 255) << 16 |
02071 (bottomHeight < 255 ? bottomHeight : 255) << 8 |
02072 (leftWidth < 255 ? leftWidth : 255);
02073 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02074 }
02075
02076 void Client::unsetDecoHashProperty()
02077 {
02078 XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
02079 }
02080
02081 #ifndef NDEBUG
02082 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
02083 {
02084 if( cl == NULL )
02085 return stream << "\'NULL_CLIENT\'";
02086 return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
02087 }
02088 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
02089 {
02090 stream << "LIST:(";
02091 bool first = true;
02092 for( ClientList::ConstIterator it = list.begin();
02093 it != list.end();
02094 ++it )
02095 {
02096 if( !first )
02097 stream << ":";
02098 first = false;
02099 stream << *it;
02100 }
02101 stream << ")";
02102 return stream;
02103 }
02104 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
02105 {
02106 stream << "LIST:(";
02107 bool first = true;
02108 for( ConstClientList::ConstIterator it = list.begin();
02109 it != list.end();
02110 ++it )
02111 {
02112 if( !first )
02113 stream << ":";
02114 first = false;
02115 stream << *it;
02116 }
02117 stream << ")";
02118 return stream;
02119 }
02120 #endif
02121
02122 QPixmap * kwin_get_menu_pix_hack()
02123 {
02124 static QPixmap p;
02125 if ( p.isNull() )
02126 p = SmallIcon( "bx2" );
02127 return &p;
02128 }
02129
02130 }
02131
02132 #include "client.moc"