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