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
00031 #include <X11/extensions/shape.h>
00032
00033
00034
00035
00036 extern Atom qt_wm_state;
00037 extern Time qt_x_time;
00038 extern Atom qt_window_role;
00039 extern Atom qt_sm_client_id;
00040
00041 namespace KWinInternal
00042 {
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00068 Client::Client( Workspace *ws )
00069 : QObject( NULL ),
00070 client( None ),
00071 wrapper( None ),
00072 frame( None ),
00073 decoration( NULL ),
00074 wspace( ws ),
00075 bridge( new Bridge( this )),
00076 move_faked_activity( false ),
00077 move_resize_grab_window( None ),
00078 transient_for( NULL ),
00079 transient_for_id( None ),
00080 original_transient_for_id( None ),
00081 in_group( NULL ),
00082 window_group( None ),
00083 in_layer( UnknownLayer ),
00084 ping_timer( NULL ),
00085 process_killer( NULL ),
00086 user_time( CurrentTime ),
00087 allowed_actions( 0 ),
00088 block_geometry( 0 ),
00089 shade_geometry_change( false ),
00090 border_left( 0 ),
00091 border_right( 0 ),
00092 border_top( 0 ),
00093 border_bottom( 0 )
00094
00095 {
00096 autoRaiseTimer = 0;
00097 shadeHoverTimer = 0;
00098
00099
00100 mapping_state = WithdrawnState;
00101 desk = 0;
00102
00103 mode = PositionCenter;
00104 buttonDown = FALSE;
00105 moveResizeMode = FALSE;
00106
00107 info = NULL;
00108
00109 shade_mode = ShadeNone;
00110 active = FALSE;
00111 keep_above = FALSE;
00112 keep_below = FALSE;
00113 is_shape = FALSE;
00114 motif_may_move = TRUE;
00115 motif_may_resize = TRUE;
00116 motif_may_close = TRUE;
00117 fullscreen_mode = FullScreenNone;
00118 skip_taskbar = FALSE;
00119 original_skip_taskbar = false;
00120 minimized = false;
00121 hidden = false;
00122 modal = false;
00123 noborder = false;
00124 user_noborder = false;
00125 not_obscured = false;
00126 urgency = false;
00127 ignore_focus_stealing = false;
00128 check_active_modal = false;
00129
00130 Pdeletewindow = 0;
00131 Ptakefocus = 0;
00132 Pcontexthelp = 0;
00133 Pping = 0;
00134 input = FALSE;
00135 store_settings = FALSE;
00136 skip_pager = FALSE;
00137
00138
00139 max_mode = MaximizeRestore;
00140
00141 cmap = None;
00142
00143 frame_geometry = QRect( 0, 0, 100, 100 );
00144 client_size = QSize( 100, 100 );
00145
00146
00147 }
00148
00152 Client::~Client()
00153 {
00154 assert(!moveResizeMode);
00155 assert( client == None );
00156 assert( frame == None && wrapper == None );
00157 assert( decoration == NULL );
00158 assert( block_geometry == 0 );
00159
00160 delete info;
00161 delete bridge;
00162 }
00163
00164
00165 void Client::deleteClient( Client* c, allowed_t )
00166 {
00167 delete c;
00168 }
00169
00173 void Client::releaseWindow( bool on_shutdown )
00174 {
00175 if (moveResizeMode)
00176 leaveMoveResize();
00177 setModal( false );
00178 hidden = true;
00179 if( !on_shutdown )
00180 workspace()->clientHidden( this );
00181 XUnmapWindow( qt_xdisplay(), frameId());
00182 destroyDecoration();
00183 cleanGrouping();
00184 if( !on_shutdown )
00185 {
00186 workspace()->removeClient( this, Allowed );
00187
00188
00189 info->setDesktop( 0 );
00190 desk = 0;
00191 info->setState( 0, info->state());
00192 }
00193 XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
00194
00195 XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
00196 XRemoveFromSaveSet( qt_xdisplay(), client );
00197 XSelectInput( qt_xdisplay(), client, NoEventMask );
00198 if( on_shutdown )
00199 {
00200 XMapWindow( qt_xdisplay(), client );
00201
00202 }
00203 else
00204 {
00205
00206
00207 XUnmapWindow( qt_xdisplay(), client );
00208 }
00209 setMappingState( WithdrawnState );
00210 client = None;
00211 XDestroyWindow( qt_xdisplay(), wrapper );
00212 wrapper = None;
00213 XDestroyWindow( qt_xdisplay(), frame );
00214 frame = None;
00215 deleteClient( this, Allowed );
00216 }
00217
00218
00219
00220 void Client::destroyClient()
00221 {
00222 if (moveResizeMode)
00223 leaveMoveResize();
00224 ++block_geometry;
00225 setModal( false );
00226 hidden = true;
00227 workspace()->clientHidden( this );
00228 destroyDecoration();
00229 cleanGrouping();
00230 workspace()->removeClient( this, Allowed );
00231 client = None;
00232 XDestroyWindow( qt_xdisplay(), wrapper );
00233 wrapper = None;
00234 XDestroyWindow( qt_xdisplay(), frame );
00235 frame = None;
00236 --block_geometry;
00237 deleteClient( this, Allowed );
00238 }
00239
00240 void Client::updateDecoration( bool check_workspace_pos, bool force )
00241 {
00242 if( !force && (( decoration == NULL && noBorder())
00243 || ( decoration != NULL && !noBorder())))
00244 return;
00245 bool do_show = false;
00246 ++block_geometry;
00247 if( force )
00248 destroyDecoration();
00249 if( !noBorder())
00250 {
00251 decoration = workspace()->createDecoration( bridge );
00252
00253 decoration->init();
00254 decoration->widget()->installEventFilter( this );
00255 XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
00256 decoration->widget()->lower();
00257 decoration->borders( border_left, border_right, border_top, border_bottom );
00258 int save_workarea_diff_x = workarea_diff_x;
00259 int save_workarea_diff_y = workarea_diff_y;
00260 move( calculateGravitation( false ));
00261 if( !isShade())
00262 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00263 else
00264 plainResize( sizeForClientSize( QSize( clientSize().width(), 0 ), SizemodeShaded ), ForceGeometrySet );
00265 workarea_diff_x = save_workarea_diff_x;
00266 workarea_diff_y = save_workarea_diff_y;
00267 do_show = true;
00268 }
00269 else
00270 destroyDecoration();
00271 if( check_workspace_pos )
00272 checkWorkspacePosition();
00273 --block_geometry;
00274 setGeometry( geometry(), ForceGeometrySet );
00275 if( do_show )
00276 decoration->widget()->show();
00277 updateFrameStrut();
00278 }
00279
00280 void Client::destroyDecoration()
00281 {
00282 if( decoration != NULL )
00283 {
00284 delete decoration;
00285 decoration = NULL;
00286 QPoint grav = calculateGravitation( true );
00287 border_left = border_right = border_top = border_bottom = 0;
00288 setMask( QRegion());
00289 int save_workarea_diff_x = workarea_diff_x;
00290 int save_workarea_diff_y = workarea_diff_y;
00291 if( !isShade())
00292 plainResize( clientSize(), ForceGeometrySet );
00293 else
00294 plainResize( QSize( clientSize().width(), 0 ), ForceGeometrySet );
00295 move( grav );
00296 workarea_diff_x = save_workarea_diff_x;
00297 workarea_diff_y = save_workarea_diff_y;
00298 }
00299 }
00300
00301 void Client::checkBorderSizes()
00302 {
00303 if( decoration == NULL )
00304 return;
00305 int new_left, new_right, new_top, new_bottom;
00306 decoration->borders( new_left, new_right, new_top, new_bottom );
00307 if( new_left == border_left && new_right == border_right
00308 && new_top == border_top && new_bottom == border_bottom )
00309 return;
00310 ++block_geometry;
00311 move( calculateGravitation( true ));
00312 border_left = new_left;
00313 border_right = new_right;
00314 border_top = new_top;
00315 border_bottom = new_bottom;
00316 move( calculateGravitation( false ));
00317 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00318 checkWorkspacePosition();
00319 --block_geometry;
00320 setGeometry( geometry(), ForceGeometrySet );
00321 }
00322
00323 void Client::detectNoBorder()
00324 {
00325 if( Shape::hasShape( window()) || Motif::noBorder( window()))
00326 {
00327 noborder = true;
00328 return;
00329 }
00330 switch( windowType())
00331 {
00332 case NET::Desktop :
00333 case NET::Dock :
00334 case NET::TopMenu :
00335 case NET::Override :
00336 case NET::Splash :
00337 noborder = true;
00338 break;
00339 case NET::Unknown :
00340 case NET::Normal :
00341 case NET::Toolbar :
00342 case NET::Menu :
00343 case NET::Dialog :
00344 case NET::Utility :
00345 noborder = false;
00346 break;
00347 default:
00348 assert( false );
00349 }
00350 }
00351
00352 void Client::updateFrameStrut()
00353 {
00354
00355 NETStrut strut;
00356 strut.left = border_left;
00357 strut.right = border_right;
00358 strut.top = border_top;
00359 strut.bottom = border_bottom;
00360 info->setKDEFrameStrut( strut );
00361 }
00362
00363
00364
00365
00366
00367
00368 void Client::resizeDecoration( const QSize& s )
00369 {
00370 if( decoration == NULL )
00371 return;
00372 QSize oldsize = decoration->widget()->size();
00373 decoration->resize( s );
00374 if( oldsize == s )
00375 {
00376 QResizeEvent e( s, oldsize );
00377 QApplication::sendEvent( decoration->widget(), &e );
00378 }
00379 }
00380
00381 bool Client::noBorder() const
00382 {
00383 return noborder || isFullScreen() || user_noborder;
00384 }
00385
00386 bool Client::userCanSetNoBorder() const
00387 {
00388 return !noborder && !isFullScreen() && !isShade();
00389 }
00390
00391 bool Client::isUserNoBorder() const
00392 {
00393 return user_noborder;
00394 }
00395
00396 void Client::setUserNoBorder( bool set )
00397 {
00398 if( !userCanSetNoBorder())
00399 return;
00400 if( user_noborder == set )
00401 return;
00402 user_noborder = set;
00403 updateDecoration( true, false );
00404 }
00405
00406 void Client::updateShape()
00407 {
00408 if ( shape() )
00409 XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
00410 clientPos().x(), clientPos().y(),
00411 window(), ShapeBounding, ShapeSet);
00412 else
00413 XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00414 None, ShapeSet);
00415
00416 if( shape() && !noBorder())
00417 {
00418 noborder = true;
00419 updateDecoration( true );
00420 }
00421 }
00422
00423 void Client::setMask( const QRegion& reg, int mode )
00424 {
00425 _mask = reg;
00426 if( reg.isNull())
00427 XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00428 None, ShapeSet );
00429 else if( mode == X::Unsorted )
00430 XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00431 reg.handle(), ShapeSet );
00432 else
00433 {
00434 QMemArray< QRect > rects = reg.rects();
00435 XRectangle* xrects = new XRectangle[ rects.count() ];
00436 for( unsigned int i = 0;
00437 i < rects.count();
00438 ++i )
00439 {
00440 xrects[ i ].x = rects[ i ].x();
00441 xrects[ i ].y = rects[ i ].y();
00442 xrects[ i ].width = rects[ i ].width();
00443 xrects[ i ].height = rects[ i ].height();
00444 }
00445 XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00446 xrects, rects.count(), ShapeSet, mode );
00447 delete[] xrects;
00448 }
00449 }
00450
00451 QRegion Client::mask() const
00452 {
00453 if( _mask.isEmpty())
00454 return QRegion( 0, 0, width(), height());
00455 return _mask;
00456 }
00457
00458 void Client::hideClient( bool hide )
00459 {
00460 if( hidden == hide )
00461 return;
00462 hidden = hide;
00463 info->setState( hidden ? NET::Hidden : 0, NET::Hidden );
00464 if( hidden )
00465 {
00466 setMappingState( IconicState );
00467 rawHide();
00468 setSkipTaskbar( true, false );
00469 }
00470 else
00471 {
00472 setSkipTaskbar( original_skip_taskbar, false );
00473 if( isOnCurrentDesktop())
00474 {
00475 if( isShown( false ))
00476 setMappingState( NormalState );
00477 rawShow();
00478 }
00479 }
00480 }
00481
00482
00483
00484
00485 bool Client::isMinimizable() const
00486 {
00487 if( isSpecialWindow() && !isOverride())
00488 return false;
00489 if( isTransient() && !wantsTabFocus())
00490 {
00491 bool shown_mainwindow = false;
00492 ClientList mainclients = mainClients();
00493 for( ClientList::ConstIterator it = mainclients.begin();
00494 it != mainclients.end();
00495 ++it )
00496 {
00497 if( (*it)->isShown( true ))
00498 shown_mainwindow = true;
00499 }
00500 if( !shown_mainwindow )
00501 return true;
00502 }
00503
00504
00505
00506 if( transientFor() != NULL )
00507 return false;
00508 if( !wantsTabFocus())
00509 return false;
00510 return true;
00511 }
00512
00516 void Client::minimize()
00517 {
00518 if ( !isMinimizable() || isMinimized())
00519 return;
00520
00521 minimized = true;
00522
00523 Notify::raise( Notify::Minimize );
00524
00525
00526 if ( mainClients().isEmpty() && isOnCurrentDesktop())
00527 animateMinimizeOrUnminimize( true );
00528
00529 setMappingState( IconicState );
00530 info->setState( NET::Hidden, NET::Hidden );
00531 rawHide();
00532 updateAllowedActions();
00533 workspace()->updateMinimizedOfTransients( this );
00534 }
00535
00536 void Client::unminimize()
00537 {
00538 if( !isMinimized())
00539 return;
00540
00541 Notify::raise( Notify::UnMinimize );
00542 minimized = false;
00543 info->setState( 0, NET::Hidden );
00544 if( isOnCurrentDesktop())
00545 {
00546 if( mainClients().isEmpty())
00547 animateMinimizeOrUnminimize( FALSE );
00548 if( isShown( false ))
00549 setMappingState( NormalState );
00550 rawShow();
00551 }
00552 updateAllowedActions();
00553 workspace()->updateMinimizedOfTransients( this );
00554 }
00555
00556 extern bool blockAnimation;
00557
00558 void Client::animateMinimizeOrUnminimize( bool minimize )
00559 {
00560 if ( blockAnimation )
00561 return;
00562 if ( !options->animateMinimize )
00563 return;
00564
00565 if( decoration != NULL && decoration->animateMinimize( minimize ))
00566 return;
00567
00568
00569
00570
00571
00572 float lf,rf,tf,bf,step;
00573
00574 int speed = options->animateMinimizeSpeed;
00575 if ( speed > 10 )
00576 speed = 10;
00577 if ( speed < 0 )
00578 speed = 0;
00579
00580 step = 40. * (11 - speed );
00581
00582 NETRect r = info->iconGeometry();
00583 QRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00584 if ( !icongeom.isValid() )
00585 return;
00586
00587 QPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
00588
00589 QRect before, after;
00590 if ( minimize )
00591 {
00592 before = QRect( x(), y(), width(), pm.height() );
00593 after = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00594 }
00595 else
00596 {
00597 before = QRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00598 after = QRect( x(), y(), width(), pm.height() );
00599 }
00600
00601 lf = (after.left() - before.left())/step;
00602 rf = (after.right() - before.right())/step;
00603 tf = (after.top() - before.top())/step;
00604 bf = (after.bottom() - before.bottom())/step;
00605
00606 grabXServer();
00607
00608 QRect area = before;
00609 QRect area2;
00610 QPixmap pm2;
00611
00612 QTime t;
00613 t.start();
00614 float diff;
00615
00616 QPainter p ( workspace()->desktopWidget() );
00617 bool need_to_clear = FALSE;
00618 QPixmap pm3;
00619 do
00620 {
00621 if (area2 != area)
00622 {
00623 pm = animationPixmap( area.width() );
00624 pm2 = QPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
00625 p.drawPixmap( area.x(), area.y(), pm );
00626 if ( need_to_clear )
00627 {
00628 p.drawPixmap( area2.x(), area2.y(), pm3 );
00629 need_to_clear = FALSE;
00630 }
00631 area2 = area;
00632 }
00633 XFlush(qt_xdisplay());
00634 XSync( qt_xdisplay(), FALSE );
00635 diff = t.elapsed();
00636 if (diff > step)
00637 diff = step;
00638 area.setLeft(before.left() + int(diff*lf));
00639 area.setRight(before.right() + int(diff*rf));
00640 area.setTop(before.top() + int(diff*tf));
00641 area.setBottom(before.bottom() + int(diff*bf));
00642 if (area2 != area )
00643 {
00644 if ( area2.intersects( area ) )
00645 p.drawPixmap( area2.x(), area2.y(), pm2 );
00646 else
00647 {
00648 pm3 = pm2;
00649 need_to_clear = TRUE;
00650 }
00651 }
00652 } while ( t.elapsed() < step);
00653 if (area2 == area || need_to_clear )
00654 p.drawPixmap( area2.x(), area2.y(), pm2 );
00655
00656 p.end();
00657 ungrabXServer();
00658 }
00659
00660
00664 QPixmap Client::animationPixmap( int w )
00665 {
00666 QFont font = options->font(isActive());
00667 QFontMetrics fm( font );
00668 QPixmap pm( w, fm.lineSpacing() );
00669 pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
00670 QPainter p( &pm );
00671 p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
00672 p.setFont(options->font(isActive()));
00673 p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
00674 return pm;
00675 }
00676
00677
00678 bool Client::isShadeable() const
00679 {
00680 return !isSpecialWindow() && !noBorder();
00681 }
00682
00683 void Client::setShade( ShadeMode mode )
00684 {
00685 if( !isShadeable())
00686 return;
00687 if( shade_mode == mode )
00688 return;
00689 bool was_shade = isShade();
00690 ShadeMode was_shade_mode = shade_mode;
00691 shade_mode = mode;
00692 if( was_shade == isShade())
00693 return;
00694
00695 if( shade_mode == ShadeNormal )
00696 {
00697 if ( isShown( true ) && isOnCurrentDesktop())
00698 Notify::raise( Notify::ShadeUp );
00699 }
00700 else if( shade_mode == ShadeNone )
00701 {
00702 if( isShown( true ) && isOnCurrentDesktop())
00703 Notify::raise( Notify::ShadeDown );
00704 }
00705
00706 assert( decoration != NULL );
00707 ++block_geometry;
00708
00709 decoration->borders( border_left, border_right, border_top, border_bottom );
00710
00711 int as = options->animateShade? 10 : 1;
00712
00713 if ( isShade())
00714 {
00715 int h = height();
00716 shade_geometry_change = true;
00717 QSize s( sizeForClientSize( QSize( clientSize().width(), 0), SizemodeShaded ) );
00718 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
00719 XUnmapWindow( qt_xdisplay(), wrapper );
00720 XUnmapWindow( qt_xdisplay(), client );
00721 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00722
00723
00724
00725 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00726 do
00727 {
00728 h -= step;
00729 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00730 resizeDecoration( QSize( s.width(), h ));
00731 QApplication::syncX();
00732 } while ( h > s.height() + step );
00733
00734
00735 shade_geometry_change = false;
00736 plainResize( s );
00737 if( isActive())
00738 {
00739 if( was_shade_mode == ShadeHover )
00740 workspace()->activateNextClient( this );
00741 else
00742 workspace()->focusToNull();
00743 }
00744 }
00745 else
00746 {
00747 int h = height();
00748 shade_geometry_change = true;
00749 QSize s( sizeForClientSize( clientSize(), SizemodeShaded ));
00750
00751
00752 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00753 do
00754 {
00755 h += step;
00756 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00757 resizeDecoration( QSize( s.width(), h ));
00758
00759
00760
00761 QApplication::syncX();
00762 } while ( h < s.height() - step );
00763
00764
00765 shade_geometry_change = false;
00766 plainResize( s );
00767 if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00768 setActive( TRUE );
00769 XMapWindow( qt_xdisplay(), wrapperId());
00770 XMapWindow( qt_xdisplay(), window());
00771 if ( isActive() )
00772 workspace()->requestFocus( this );
00773 }
00774 --block_geometry;
00775 setGeometry( geometry(), ForceGeometrySet );
00776 info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00777 info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00778 setMappingState( isShown( false ) && isOnCurrentDesktop() ? NormalState : IconicState );
00779 updateAllowedActions();
00780 workspace()->updateMinimizedOfTransients( this );
00781 decoration->shadeChange();
00782 }
00783
00784 void Client::shadeHover()
00785 {
00786 setShade( ShadeHover );
00787 delete shadeHoverTimer;
00788 shadeHoverTimer = 0;
00789 }
00790
00791 void Client::toggleShade()
00792 {
00793
00794 setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00795 }
00796
00797 void Client::virtualDesktopChange()
00798 {
00799 if( hidden || minimized )
00800 return;
00801
00802 if( isOnCurrentDesktop())
00803 {
00804 if( !isShade())
00805 setMappingState( NormalState );
00806 rawShow();
00807 }
00808 else
00809 {
00810 if( !isShade())
00811 setMappingState( IconicState );
00812 rawHide();
00813 }
00814 }
00815
00820 void Client::setMappingState(int s)
00821 {
00822 assert( client != None );
00823 if( mapping_state == s )
00824 return;
00825 bool was_unmanaged = ( mapping_state == WithdrawnState );
00826 mapping_state = s;
00827 if( mapping_state == WithdrawnState )
00828 {
00829 XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
00830 return;
00831 }
00832 assert( s == NormalState || s == IconicState );
00833
00834 unsigned long data[2];
00835 data[0] = (unsigned long) s;
00836 data[1] = (unsigned long) None;
00837 XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
00838 PropModeReplace, (unsigned char *)data, 2);
00839
00840 if( was_unmanaged )
00841 {
00842 assert( block_geometry == 1 );
00843 --block_geometry;
00844 setGeometry( frame_geometry, ForceGeometrySet );
00845 }
00846 }
00847
00852 void Client::rawShow()
00853 {
00854 if( decoration != NULL )
00855 decoration->widget()->show();
00856 XMapWindow( qt_xdisplay(), frame );
00857 if( !isShade())
00858 {
00859 XMapWindow( qt_xdisplay(), wrapper );
00860 XMapWindow( qt_xdisplay(), client );
00861 }
00862 }
00863
00869 void Client::rawHide()
00870 {
00871
00872
00873
00874
00875
00876
00877 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
00878 XUnmapWindow( qt_xdisplay(), frame );
00879 XUnmapWindow( qt_xdisplay(), wrapper );
00880 XUnmapWindow( qt_xdisplay(), client );
00881 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00882 if( decoration != NULL )
00883 decoration->widget()->hide();
00884 workspace()->clientHidden( this );
00885 }
00886
00887 static void sendClientMessage(Window w, Atom a, long x)
00888 {
00889 XEvent ev;
00890 long mask;
00891
00892 memset(&ev, 0, sizeof(ev));
00893 ev.xclient.type = ClientMessage;
00894 ev.xclient.window = w;
00895 ev.xclient.message_type = a;
00896 ev.xclient.format = 32;
00897 ev.xclient.data.l[0] = x;
00898 ev.xclient.data.l[1] = qt_x_time;
00899 mask = 0L;
00900 if (w == qt_xrootwin())
00901 mask = SubstructureRedirectMask;
00902 XSendEvent(qt_xdisplay(), w, False, mask, &ev);
00903 }
00904
00905
00906
00907
00908 bool Client::isCloseable() const
00909 {
00910 return motif_may_close && ( !isSpecialWindow() || isOverride());
00911 }
00912
00917 void Client::closeWindow()
00918 {
00919 if( !isCloseable())
00920 return;
00921
00922
00923
00924
00925 group()->updateUserTime();
00926 if ( Pdeletewindow )
00927 {
00928 Notify::raise( Notify::Close );
00929 sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
00930 pingWindow();
00931 }
00932 else
00933 {
00934
00935
00936 killWindow();
00937 }
00938 }
00939
00940
00944 void Client::killWindow()
00945 {
00946 kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
00947
00948
00949 Notify::raise( Notify::Close );
00950
00951 if( isDialog())
00952 Notify::raise( Notify::TransDelete );
00953 if( isNormalWindow())
00954 Notify::raise( Notify::Delete );
00955 killProcess( false );
00956
00957 XKillClient(qt_xdisplay(), window() );
00958 destroyClient();
00959 }
00960
00961
00962
00963
00964 void Client::pingWindow()
00965 {
00966 if( !Pping )
00967 return;
00968 if( ping_timer != NULL )
00969 return;
00970 ping_timer = new QTimer( this );
00971 connect( ping_timer, SIGNAL( timeout()), SLOT( pingTimeout()));
00972 ping_timer->start( 5000, true );
00973 ping_timestamp = qt_x_time;
00974 workspace()->sendPingToWindow( window(), ping_timestamp );
00975 }
00976
00977 void Client::gotPing( Time timestamp )
00978 {
00979 if( timestamp != ping_timestamp )
00980 return;
00981 delete ping_timer;
00982 ping_timer = NULL;
00983 if( process_killer != NULL )
00984 {
00985 process_killer->kill();
00986 delete process_killer;
00987 process_killer = NULL;
00988 }
00989 }
00990
00991 void Client::pingTimeout()
00992 {
00993 kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
00994 delete ping_timer;
00995 ping_timer = NULL;
00996 killProcess( true, ping_timestamp );
00997 }
00998
00999 void Client::killProcess( bool ask, Time timestamp )
01000 {
01001 if( process_killer != NULL )
01002 return;
01003 Q_ASSERT( !ask || timestamp != CurrentTime );
01004 QCString machine = wmClientMachine();
01005 pid_t pid = info->pid();
01006 if( pid <= 0 || machine.isEmpty())
01007 return;
01008 kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01009 if( !ask )
01010 {
01011 if( machine != "localhost" )
01012 {
01013 KProcess proc;
01014 proc << "xon" << machine << "kill" << pid;
01015 proc.start( KProcess::DontCare );
01016 }
01017 else
01018 ::kill( pid, SIGTERM );
01019 }
01020 else
01021 {
01022 process_killer = new KProcess( this );
01023 *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01024 << "--pid" << QCString().setNum( pid ) << "--hostname" << machine
01025 << "--windowname" << caption().utf8()
01026 << "--applicationname" << resourceClass()
01027 << "--wid" << QCString().setNum( window())
01028 << "--timestamp" << QCString().setNum( timestamp );
01029 connect( process_killer, SIGNAL( processExited( KProcess* )),
01030 SLOT( processKillerExited()));
01031 if( !process_killer->start( KProcess::NotifyOnExit ))
01032 {
01033 delete process_killer;
01034 process_killer = NULL;
01035 return;
01036 }
01037 }
01038 }
01039
01040 void Client::processKillerExited()
01041 {
01042 kdDebug( 1212 ) << "Killer exited" << endl;
01043 delete process_killer;
01044 process_killer = NULL;
01045 }
01046
01047 void Client::setSkipTaskbar( bool b, bool from_outside )
01048 {
01049 if( from_outside )
01050 original_skip_taskbar = b;
01051 if ( b == skipTaskbar() )
01052 return;
01053 skip_taskbar = b;
01054 info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01055 }
01056
01057 void Client::setSkipPager( bool b )
01058 {
01059 if ( b == skipPager() )
01060 return;
01061 skip_pager = b;
01062 info->setState( b?NET::SkipPager:0, NET::SkipPager );
01063 }
01064
01065 void Client::setModal( bool m )
01066 {
01067 if( modal == m )
01068 return;
01069 modal = m;
01070 if( !modal )
01071 return;
01072
01073
01074 }
01075
01076 void Client::toggleOnAllDesktops()
01077 {
01078 setOnAllDesktops( !isOnAllDesktops());
01079 }
01080
01081 void Client::setDesktop( int desktop )
01082 {
01083 if( desktop != NET::OnAllDesktops )
01084 desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
01085 if( desk == desktop )
01086 return;
01087 int was_desk = desk;
01088 desk = desktop;
01089 info->setDesktop( desktop );
01090 if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01091 {
01092 if ( isShown( true ))
01093 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01094 workspace()->updateOnAllDesktopsOfTransients( this );
01095 }
01096 if( decoration != NULL )
01097 decoration->desktopChange();
01098 virtualDesktopChange();
01099 }
01100
01101 void Client::setOnAllDesktops( bool b )
01102 {
01103 if(( b && isOnAllDesktops())
01104 || ( !b && !isOnAllDesktops()))
01105 return;
01106 if( b )
01107 setDesktop( NET::OnAllDesktops );
01108 else
01109 setDesktop( workspace()->currentDesktop());
01110 }
01111
01112 bool Client::isOnCurrentDesktop() const
01113 {
01114 return isOnDesktop( workspace()->currentDesktop());
01115 }
01116
01121 void Client::takeFocus( bool force, allowed_t )
01122 {
01123 if ( !force && ( isTopMenu() || isDock() || isSplash()) )
01124 return;
01125
01126 #ifndef NDEBUG
01127 static Time previous_focus_timestamp;
01128 static Client* previous_client;
01129 if( previous_focus_timestamp == qt_x_time && previous_client != this )
01130 {
01131 kdWarning( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01132 kdDebug( 1212 ) << kdBacktrace() << endl;
01133 }
01134 previous_focus_timestamp = qt_x_time;
01135 previous_client = this;
01136 #endif
01137 if ( input )
01138 {
01139 XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01140 }
01141 if ( Ptakefocus )
01142 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01143 }
01144
01152 bool Client::providesContextHelp() const
01153 {
01154 return Pcontexthelp;
01155 }
01156
01157
01164 void Client::showContextHelp()
01165 {
01166 if ( Pcontexthelp )
01167 {
01168 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01169 QWhatsThis::enterWhatsThisMode();
01170 }
01171 }
01172
01173
01178 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
01179
01180 void Client::fetchName()
01181 {
01182 QString s;
01183
01184 if ( info->name() && info->name()[ 0 ] != '\0' )
01185 s = QString::fromUtf8( info->name() );
01186 else
01187 s = KWin::readNameProperty( window(), XA_WM_NAME );
01188 if ( s != cap_normal )
01189 {
01190 bool reset_name = cap_normal.isEmpty();
01191 for( unsigned int i = 0;
01192 i < s.length();
01193 ++i )
01194 if( !s[ i ].isPrint())
01195 s[ i ] = ' ';
01196 cap_normal = s;
01197 bool was_suffix = ( !cap_suffix.isEmpty());
01198 cap_suffix = QString::null;
01199 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
01200 {
01201 int i = 2;
01202 do
01203 {
01204 cap_suffix = " <" + QString::number(i) + ">";
01205 i++;
01206 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
01207 info->setVisibleName( caption().utf8() );
01208 reset_name = false;
01209 }
01210 if(( was_suffix && cap_suffix.isEmpty()
01211 || reset_name ))
01212 {
01213 info->setVisibleName( "" );
01214 info->setVisibleIconName( "" );
01215 }
01216 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
01217 info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
01218
01219 if( isManaged() && decoration != NULL )
01220 decoration->captionChange();
01221 }
01222 }
01223
01224 void Client::fetchIconicName()
01225 {
01226 QString s;
01227
01228 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
01229 s = QString::fromUtf8( info->iconName() );
01230 else
01231 s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
01232 if ( s != cap_iconic )
01233 {
01234 cap_iconic = s;
01235 if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
01236 info->setVisibleIconName( ( s + cap_suffix ).utf8() );
01237 }
01238 }
01239
01242 QString Client::caption() const
01243 {
01244 return cap_normal + cap_suffix;
01245 }
01246
01247 void Client::getWMHints()
01248 {
01249 XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
01250 input = true;
01251 window_group = None;
01252 urgency = false;
01253 if ( hints )
01254 {
01255 if( hints->flags & InputHint )
01256 input = hints->input;
01257 if( hints->flags & WindowGroupHint )
01258 window_group = hints->window_group;
01259 urgency = ( hints->flags & UrgencyHint ) ? true : false;
01260 XFree( (char*)hints );
01261 }
01262 checkGroup();
01263 updateUrgency();
01264 updateAllowedActions();
01265 }
01266
01267 void Client::readIcons( Window win, QPixmap* icon, QPixmap* miniicon )
01268 {
01269
01270 if( icon != NULL )
01271 *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
01272 if( miniicon != NULL )
01273 if( icon == NULL || !icon->isNull())
01274 *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
01275 else
01276 *miniicon = QPixmap();
01277 }
01278
01279 void Client::getIcons()
01280 {
01281
01282 readIcons( window(), &icon_pix, &miniicon_pix );
01283 if( icon_pix.isNull())
01284 {
01285 icon_pix = group()->icon();
01286 miniicon_pix = group()->miniIcon();
01287 }
01288 if( icon_pix.isNull() && isTransient())
01289 {
01290 ClientList mainclients = mainClients();
01291 for( ClientList::ConstIterator it = mainclients.begin();
01292 it != mainclients.end() && icon_pix.isNull();
01293 ++it )
01294 {
01295 icon_pix = (*it)->icon();
01296 miniicon_pix = (*it)->miniIcon();
01297 }
01298 }
01299 if( icon_pix.isNull())
01300 {
01301 icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
01302 miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
01303 }
01304 if( isManaged() && decoration != NULL )
01305 decoration->iconChange();
01306 }
01307
01308 void Client::getWindowProtocols()
01309 {
01310 Atom *p;
01311 int i,n;
01312
01313 Pdeletewindow = 0;
01314 Ptakefocus = 0;
01315 Pcontexthelp = 0;
01316 Pping = 0;
01317
01318 if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
01319 {
01320 for (i = 0; i < n; i++)
01321 if (p[i] == atoms->wm_delete_window)
01322 Pdeletewindow = 1;
01323 else if (p[i] == atoms->wm_take_focus)
01324 Ptakefocus = 1;
01325 else if (p[i] == atoms->net_wm_context_help)
01326 Pcontexthelp = 1;
01327 else if (p[i] == atoms->net_wm_ping)
01328 Pping = 1;
01329 if (n>0)
01330 XFree(p);
01331 }
01332 }
01333
01334 static int nullErrorHandler(Display *, XErrorEvent *)
01335 {
01336 return 0;
01337 }
01338
01342 QCString Client::staticWindowRole(WId w)
01343 {
01344 return getStringProperty(w, qt_window_role);
01345 }
01346
01350 QCString Client::staticSessionId(WId w)
01351 {
01352 return getStringProperty(w, qt_sm_client_id);
01353 }
01354
01358 QCString Client::staticWmCommand(WId w)
01359 {
01360 return getStringProperty(w, XA_WM_COMMAND, ' ');
01361 }
01362
01367 QCString Client::staticWmClientMachine(WId w)
01368 {
01369 QCString result = getStringProperty(w, XA_WM_CLIENT_MACHINE);
01370 if (result.isEmpty())
01371 {
01372 result = "localhost";
01373 }
01374 else
01375 {
01376
01377 char hostnamebuf[80];
01378 if (gethostname (hostnamebuf, sizeof hostnamebuf) >= 0)
01379 {
01380 hostnamebuf[sizeof(hostnamebuf)-1] = 0;
01381 if (result == hostnamebuf)
01382 result = "localhost";
01383 char *dot = strchr(hostnamebuf, '.');
01384 if (dot && !(*dot = 0) && result == hostnamebuf)
01385 result = "localhost";
01386 }
01387 }
01388 return result;
01389 }
01390
01394 Window Client::staticWmClientLeader(WId w)
01395 {
01396 Atom type;
01397 int format, status;
01398 unsigned long nitems = 0;
01399 unsigned long extra = 0;
01400 unsigned char *data = 0;
01401 Window result = w;
01402 XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
01403 status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
01404 FALSE, XA_WINDOW, &type, &format,
01405 &nitems, &extra, &data );
01406 XSetErrorHandler(oldHandler);
01407 if (status == Success )
01408 {
01409 if (data && nitems > 0)
01410 result = *((Window*) data);
01411 XFree(data);
01412 }
01413 return result;
01414 }
01415
01416
01417 void Client::getWmClientLeader()
01418 {
01419 wmClientLeaderWin = staticWmClientLeader(window());
01420 }
01421
01426 QCString Client::sessionId()
01427 {
01428 QCString result = staticSessionId(window());
01429 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01430 result = staticSessionId(wmClientLeaderWin);
01431 return result;
01432 }
01433
01438 QCString Client::wmCommand()
01439 {
01440 QCString result = staticWmCommand(window());
01441 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01442 result = staticWmCommand(wmClientLeaderWin);
01443 return result;
01444 }
01445
01450 QCString Client::wmClientMachine() const
01451 {
01452 QCString result = staticWmClientMachine(window());
01453 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01454 result = staticWmClientMachine(wmClientLeaderWin);
01455 return result;
01456 }
01457
01462 Window Client::wmClientLeader() const
01463 {
01464 if (wmClientLeaderWin)
01465 return wmClientLeaderWin;
01466 return window();
01467 }
01468
01469 bool Client::wantsTabFocus() const
01470 {
01471 return ( isNormalWindow() || isDialog() || isOverride())
01472 && ( input || Ptakefocus ) && !skip_taskbar;
01473 }
01474
01475
01476 bool Client::wantsInput() const
01477 {
01478 return input;
01479 }
01480
01485 bool Client::isMovable() const
01486 {
01487 return motif_may_move && !isFullScreen() &&
01488 ( !isSpecialWindow() || isOverride() || isSplash() || isToolbar()) &&
01489 ( maximizeMode() != MaximizeFull || options->moveResizeMaximizedWindows() );
01490 }
01491
01492 bool Client::isDesktop() const
01493 {
01494 return windowType() == NET::Desktop;
01495 }
01496
01497 bool Client::isDock() const
01498 {
01499 return windowType() == NET::Dock;
01500 }
01501
01502 bool Client::isTopMenu() const
01503 {
01504 return windowType() == NET::TopMenu;
01505 }
01506
01507
01508 bool Client::isMenu() const
01509 {
01510 return windowType() == NET::Menu && !isTopMenu();
01511 }
01512
01513 bool Client::isToolbar() const
01514 {
01515 return windowType() == NET::Toolbar;
01516 }
01517
01518 bool Client::isOverride() const
01519 {
01520 return windowType() == NET::Override;
01521 }
01522
01523 bool Client::isSplash() const
01524 {
01525 return windowType() == NET::Splash;
01526 }
01527
01528 bool Client::isUtility() const
01529 {
01530 return windowType() == NET::Utility;
01531 }
01532
01533 bool Client::isDialog() const
01534 {
01535 return windowType() == NET::Dialog;
01536 }
01537
01538 bool Client::isNormalWindow() const
01539 {
01540 return windowType() == NET::Normal;
01541 }
01542
01543 bool Client::isSpecialWindow() const
01544 {
01545 return isDesktop() || isDock() || isSplash() || isTopMenu()
01546 || ( isOverride() && !isFullScreen())
01547 || isToolbar();
01548 }
01549
01550 NET::WindowType Client::windowType( bool strict, int supported_types ) const
01551 {
01552 NET::WindowType wt = info->windowType( supported_types );
01553
01554 if( !strict )
01555 {
01556 if( wt == NET::Menu )
01557 {
01558
01559
01560
01561 if( x() == 0 && y() < 0 && y() > -10 && height() < 100
01562 && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
01563 wt = NET::TopMenu;
01564 }
01565 const char* const oo_prefix = "openoffice.org";
01566
01567 if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
01568 wt = NET::Normal;
01569 if( wt == NET::Unknown )
01570 wt = isTransient() ? NET::Dialog : NET::Normal;
01571 }
01572 return wt;
01573 }
01574
01579 void Client::setCursor( Position m )
01580 {
01581 if ( !isResizable() || isShade() || noBorder())
01582 {
01583 setCursor( arrowCursor );
01584 return;
01585 }
01586 switch ( m )
01587 {
01588 case PositionTopLeft:
01589 case PositionBottomRight:
01590 setCursor( sizeFDiagCursor );
01591 break;
01592 case PositionBottomLeft:
01593 case PositionTopRight:
01594 setCursor( sizeBDiagCursor );
01595 break;
01596 case PositionTop:
01597 case PositionBottom:
01598 setCursor( sizeVerCursor );
01599 break;
01600 case PositionLeft:
01601 case PositionRight:
01602 setCursor( sizeHorCursor );
01603 break;
01604 default:
01605 if( buttonDown )
01606 setCursor( sizeAllCursor );
01607 else
01608 setCursor( arrowCursor );
01609 break;
01610 }
01611 }
01612
01613
01614 void Client::setCursor( const QCursor& c )
01615 {
01616 if( c.handle() == cursor.handle())
01617 return;
01618 cursor = c;
01619 if( decoration != NULL )
01620 decoration->widget()->setCursor( cursor );
01621 XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
01622 }
01623
01624 Client::Position Client::mousePosition( const QPoint& p ) const
01625 {
01626 if( decoration != NULL )
01627 return decoration->mousePosition( p );
01628 return PositionCenter;
01629 }
01630
01631 void Client::updateAllowedActions( bool force )
01632 {
01633 if( !isManaged() && !force )
01634 return;
01635 unsigned long old_allowed_actions = allowed_actions;
01636 allowed_actions = 0;
01637 if( isMovable())
01638 allowed_actions |= NET::ActionMove;
01639 if( isResizable())
01640 allowed_actions |= NET::ActionResize;
01641 if( isMinimizable())
01642 allowed_actions |= NET::ActionMinimize;
01643 if( isShadeable())
01644 allowed_actions |= NET::ActionShade;
01645
01646 if( isMaximizable())
01647 allowed_actions |= NET::ActionMax;
01648 if( userCanSetFullScreen())
01649 allowed_actions |= NET::ActionFullScreen;
01650 allowed_actions |= NET::ActionChangeDesktop;
01651 if( isCloseable())
01652 allowed_actions |= NET::ActionClose;
01653 if( old_allowed_actions == allowed_actions )
01654 return;
01655
01656 info->setAllowedActions( allowed_actions );
01657
01658 }
01659
01660 void Client::autoRaise()
01661 {
01662 workspace()->raiseClient( this );
01663 delete autoRaiseTimer;
01664 autoRaiseTimer = 0;
01665 }
01666
01667 void Client::cancelAutoRaise()
01668 {
01669 delete autoRaiseTimer;
01670 autoRaiseTimer = 0;
01671 }
01672
01673 #ifdef NDEBUG
01674 kndbgstream& operator<<( kndbgstream& stream, const Client* ) { return stream; }
01675 kndbgstream& operator<<( kndbgstream& stream, const ClientList& ) { return stream; }
01676 kndbgstream& operator<<( kndbgstream& stream, const ConstClientList& ) { return stream; }
01677 #else
01678 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
01679 {
01680 if( cl == NULL )
01681 return stream << "\'NULL_CLIENT\'";
01682 return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
01683 }
01684 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
01685 {
01686 stream << "LIST:(";
01687 bool first = true;
01688 for( ClientList::ConstIterator it = list.begin();
01689 it != list.end();
01690 ++it )
01691 {
01692 if( !first )
01693 stream << ":";
01694 first = false;
01695 stream << *it;
01696 }
01697 stream << ")";
01698 return stream;
01699 }
01700 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
01701 {
01702 stream << "LIST:(";
01703 bool first = true;
01704 for( ConstClientList::ConstIterator it = list.begin();
01705 it != list.end();
01706 ++it )
01707 {
01708 if( !first )
01709 stream << ":";
01710 first = false;
01711 stream << *it;
01712 }
01713 stream << ")";
01714 return stream;
01715 }
01716 #endif
01717
01718 QPixmap * kwin_get_menu_pix_hack()
01719 {
01720 static QPixmap p;
01721 if ( p.isNull() )
01722 p = SmallIcon( "bx2" );
01723 return &p;
01724 }
01725
01726 }
01727
01728 #include "client.moc"