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