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
01112 if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
01113 return;
01114 delete ping_timer;
01115 ping_timer = NULL;
01116 if( process_killer != NULL )
01117 {
01118 process_killer->kill();
01119 delete process_killer;
01120 process_killer = NULL;
01121 }
01122 }
01123
01124 void Client::pingTimeout()
01125 {
01126 kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
01127 delete ping_timer;
01128 ping_timer = NULL;
01129 killProcess( true, ping_timestamp );
01130 }
01131
01132 void Client::killProcess( bool ask, Time timestamp )
01133 {
01134 if( process_killer != NULL )
01135 return;
01136 Q_ASSERT( !ask || timestamp != CurrentTime );
01137 QCString machine = wmClientMachine( true );
01138 pid_t pid = info->pid();
01139 if( pid <= 0 || machine.isEmpty())
01140 return;
01141 kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01142 if( !ask )
01143 {
01144 if( machine != "localhost" )
01145 {
01146 KProcess proc;
01147 proc << "xon" << machine << "kill" << pid;
01148 proc.start( KProcess::DontCare );
01149 }
01150 else
01151 ::kill( pid, SIGTERM );
01152 }
01153 else
01154 {
01155 process_killer = new KProcess( this );
01156 *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01157 << "--pid" << QCString().setNum( pid ) << "--hostname" << machine
01158 << "--windowname" << caption().utf8()
01159 << "--applicationname" << resourceClass()
01160 << "--wid" << QCString().setNum( window())
01161 << "--timestamp" << QCString().setNum( timestamp );
01162 connect( process_killer, SIGNAL( processExited( KProcess* )),
01163 SLOT( processKillerExited()));
01164 if( !process_killer->start( KProcess::NotifyOnExit ))
01165 {
01166 delete process_killer;
01167 process_killer = NULL;
01168 return;
01169 }
01170 }
01171 }
01172
01173 void Client::processKillerExited()
01174 {
01175 kdDebug( 1212 ) << "Killer exited" << endl;
01176 delete process_killer;
01177 process_killer = NULL;
01178 }
01179
01180 void Client::setSkipTaskbar( bool b, bool from_outside )
01181 {
01182 int was_wants_tab_focus = wantsTabFocus();
01183 if( from_outside )
01184 {
01185 b = rules()->checkSkipTaskbar( b );
01186 original_skip_taskbar = b;
01187 }
01188 if ( b == skipTaskbar() )
01189 return;
01190 skip_taskbar = b;
01191 info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01192 updateWindowRules();
01193 if( was_wants_tab_focus != wantsTabFocus())
01194 workspace()->updateFocusChains( this,
01195 isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
01196 }
01197
01198 void Client::setSkipPager( bool b )
01199 {
01200 b = rules()->checkSkipPager( b );
01201 if ( b == skipPager() )
01202 return;
01203 skip_pager = b;
01204 info->setState( b?NET::SkipPager:0, NET::SkipPager );
01205 updateWindowRules();
01206 }
01207
01208 void Client::setModal( bool m )
01209 {
01210 if( modal == m )
01211 return;
01212 modal = m;
01213 if( !modal )
01214 return;
01215
01216
01217 }
01218
01219 void Client::setDesktop( int desktop )
01220 {
01221 if( desktop != NET::OnAllDesktops )
01222 desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
01223 desktop = rules()->checkDesktop( desktop );
01224 if( desk == desktop )
01225 return;
01226 int was_desk = desk;
01227 desk = desktop;
01228 info->setDesktop( desktop );
01229 if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01230 {
01231 if ( isShown( true ))
01232 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01233 workspace()->updateOnAllDesktopsOfTransients( this );
01234 }
01235 if( decoration != NULL )
01236 decoration->desktopChange();
01237 workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
01238 updateVisibility();
01239 updateWindowRules();
01240 }
01241
01242 void Client::setOnAllDesktops( bool b )
01243 {
01244 if(( b && isOnAllDesktops())
01245 || ( !b && !isOnAllDesktops()))
01246 return;
01247 if( b )
01248 setDesktop( NET::OnAllDesktops );
01249 else
01250 setDesktop( workspace()->currentDesktop());
01251 }
01252
01253 bool Client::isOnCurrentDesktop() const
01254 {
01255 return isOnDesktop( workspace()->currentDesktop());
01256 }
01257
01258
01259 void Client::takeActivity( int flags, bool handled, allowed_t )
01260 {
01261 if( !handled || !Ptakeactivity )
01262 {
01263 if( flags & ActivityFocus )
01264 takeFocus( Allowed );
01265 if( flags & ActivityRaise )
01266 workspace()->raiseClient( this );
01267 return;
01268 }
01269
01270 #ifndef NDEBUG
01271 static Time previous_activity_timestamp;
01272 static Client* previous_client;
01273 if( previous_activity_timestamp == qt_x_time && previous_client != this )
01274 {
01275 kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
01276 kdDebug( 1212 ) << kdBacktrace() << endl;
01277 }
01278 previous_activity_timestamp = qt_x_time;
01279 previous_client = this;
01280 #endif
01281 workspace()->sendTakeActivity( this, qt_x_time, flags );
01282 }
01283
01284
01285 void Client::takeFocus( allowed_t )
01286 {
01287 #ifndef NDEBUG
01288 static Time previous_focus_timestamp;
01289 static Client* previous_client;
01290 if( previous_focus_timestamp == qt_x_time && previous_client != this )
01291 {
01292 kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01293 kdDebug( 1212 ) << kdBacktrace() << endl;
01294 }
01295 previous_focus_timestamp = qt_x_time;
01296 previous_client = this;
01297 #endif
01298 if ( rules()->checkAcceptFocus( input ))
01299 {
01300 XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01301 }
01302 if ( Ptakefocus )
01303 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01304 workspace()->setShouldGetFocus( this );
01305 }
01306
01314 bool Client::providesContextHelp() const
01315 {
01316 return Pcontexthelp;
01317 }
01318
01319
01326 void Client::showContextHelp()
01327 {
01328 if ( Pcontexthelp )
01329 {
01330 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01331 QWhatsThis::enterWhatsThisMode();
01332 }
01333 }
01334
01335
01340 void Client::fetchName()
01341 {
01342 setCaption( readName());
01343 }
01344
01345 QString Client::readName() const
01346 {
01347 if ( info->name() && info->name()[ 0 ] != '\0' )
01348 return QString::fromUtf8( info->name() );
01349 else
01350 return KWin::readNameProperty( window(), XA_WM_NAME );
01351 }
01352
01353 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
01354
01355 void Client::setCaption( const QString& s, bool force )
01356 {
01357 if ( s != cap_normal || force )
01358 {
01359 bool reset_name = force;
01360 for( unsigned int i = 0;
01361 i < s.length();
01362 ++i )
01363 if( !s[ i ].isPrint())
01364 s[ i ] = ' ';
01365 cap_normal = s;
01366 bool was_suffix = ( !cap_suffix.isEmpty());
01367 QString machine_suffix;
01368 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
01369 machine_suffix = " <@" + wmClientMachine( true ) + ">";
01370 QString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
01371 cap_suffix = machine_suffix + shortcut_suffix;
01372 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
01373 {
01374 int i = 2;
01375 do
01376 {
01377 cap_suffix = machine_suffix + " <" + QString::number(i) + ">" + shortcut_suffix;
01378 i++;
01379 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
01380 info->setVisibleName( caption().utf8() );
01381 reset_name = false;
01382 }
01383 if(( was_suffix && cap_suffix.isEmpty()
01384 || reset_name ))
01385 {
01386 info->setVisibleName( "" );
01387 info->setVisibleIconName( "" );
01388 }
01389 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
01390 info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
01391
01392 if( isManaged() && decoration != NULL )
01393 decoration->captionChange();
01394 }
01395 }
01396
01397 void Client::updateCaption()
01398 {
01399 setCaption( cap_normal, true );
01400 }
01401
01402 void Client::fetchIconicName()
01403 {
01404 QString s;
01405 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
01406 s = QString::fromUtf8( info->iconName() );
01407 else
01408 s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
01409 if ( s != cap_iconic )
01410 {
01411 bool was_set = !cap_iconic.isEmpty();
01412 cap_iconic = s;
01413 if( !cap_suffix.isEmpty())
01414 {
01415 if( !cap_iconic.isEmpty())
01416 info->setVisibleIconName( ( s + cap_suffix ).utf8() );
01417 else if( was_set )
01418 info->setVisibleIconName( "" );
01419 }
01420 }
01421 }
01422
01425 QString Client::caption( bool full ) const
01426 {
01427 return full ? cap_normal + cap_suffix : cap_normal;
01428 }
01429
01430 void Client::getWMHints()
01431 {
01432 XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
01433 input = true;
01434 window_group = None;
01435 urgency = false;
01436 if ( hints )
01437 {
01438 if( hints->flags & InputHint )
01439 input = hints->input;
01440 if( hints->flags & WindowGroupHint )
01441 window_group = hints->window_group;
01442 urgency = ( hints->flags & UrgencyHint ) ? true : false;
01443 XFree( (char*)hints );
01444 }
01445 checkGroup();
01446 updateUrgency();
01447 updateAllowedActions();
01448 }
01449
01450 void Client::getMotifHints()
01451 {
01452 bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
01453 Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
01454 motif_noborder = mnoborder;
01455 if( !hasNETSupport())
01456 {
01457 motif_may_resize = mresize;
01458 motif_may_move = mmove;
01459 }
01460 else
01461 motif_may_resize = motif_may_move = true;
01462
01463
01464 motif_may_close = mclose;
01465 if( isManaged())
01466 updateDecoration( true );
01467 }
01468
01469 void Client::readIcons( Window win, QPixmap* icon, QPixmap* miniicon )
01470 {
01471
01472 if( icon != NULL )
01473 *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
01474 if( miniicon != NULL )
01475 if( icon == NULL || !icon->isNull())
01476 *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
01477 else
01478 *miniicon = QPixmap();
01479 }
01480
01481 void Client::getIcons()
01482 {
01483
01484 readIcons( window(), &icon_pix, &miniicon_pix );
01485 if( icon_pix.isNull())
01486 {
01487 icon_pix = group()->icon();
01488 miniicon_pix = group()->miniIcon();
01489 }
01490 if( icon_pix.isNull() && isTransient())
01491 {
01492 ClientList mainclients = mainClients();
01493 for( ClientList::ConstIterator it = mainclients.begin();
01494 it != mainclients.end() && icon_pix.isNull();
01495 ++it )
01496 {
01497 icon_pix = (*it)->icon();
01498 miniicon_pix = (*it)->miniIcon();
01499 }
01500 }
01501 if( icon_pix.isNull())
01502 {
01503 icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
01504 miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
01505 }
01506 if( isManaged() && decoration != NULL )
01507 decoration->iconChange();
01508 }
01509
01510 void Client::getWindowProtocols()
01511 {
01512 Atom *p;
01513 int i,n;
01514
01515 Pdeletewindow = 0;
01516 Ptakefocus = 0;
01517 Ptakeactivity = 0;
01518 Pcontexthelp = 0;
01519 Pping = 0;
01520
01521 if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
01522 {
01523 for (i = 0; i < n; i++)
01524 if (p[i] == atoms->wm_delete_window)
01525 Pdeletewindow = 1;
01526 else if (p[i] == atoms->wm_take_focus)
01527 Ptakefocus = 1;
01528 else if (p[i] == atoms->net_wm_take_activity)
01529 Ptakeactivity = 1;
01530 else if (p[i] == atoms->net_wm_context_help)
01531 Pcontexthelp = 1;
01532 else if (p[i] == atoms->net_wm_ping)
01533 Pping = 1;
01534 if (n>0)
01535 XFree(p);
01536 }
01537 }
01538
01539 static int nullErrorHandler(Display *, XErrorEvent *)
01540 {
01541 return 0;
01542 }
01543
01547 QCString Client::staticWindowRole(WId w)
01548 {
01549 return getStringProperty(w, qt_window_role).lower();
01550 }
01551
01555 QCString Client::staticSessionId(WId w)
01556 {
01557 return getStringProperty(w, qt_sm_client_id);
01558 }
01559
01563 QCString Client::staticWmCommand(WId w)
01564 {
01565 return getStringProperty(w, XA_WM_COMMAND, ' ');
01566 }
01567
01571 Window Client::staticWmClientLeader(WId w)
01572 {
01573 Atom type;
01574 int format, status;
01575 unsigned long nitems = 0;
01576 unsigned long extra = 0;
01577 unsigned char *data = 0;
01578 Window result = w;
01579 XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
01580 status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
01581 FALSE, XA_WINDOW, &type, &format,
01582 &nitems, &extra, &data );
01583 XSetErrorHandler(oldHandler);
01584 if (status == Success )
01585 {
01586 if (data && nitems > 0)
01587 result = *((Window*) data);
01588 XFree(data);
01589 }
01590 return result;
01591 }
01592
01593
01594 void Client::getWmClientLeader()
01595 {
01596 wmClientLeaderWin = staticWmClientLeader(window());
01597 }
01598
01603 QCString Client::sessionId()
01604 {
01605 QCString result = staticSessionId(window());
01606 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01607 result = staticSessionId(wmClientLeaderWin);
01608 return result;
01609 }
01610
01615 QCString Client::wmCommand()
01616 {
01617 QCString result = staticWmCommand(window());
01618 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01619 result = staticWmCommand(wmClientLeaderWin);
01620 return result;
01621 }
01622
01623 void Client::getWmClientMachine()
01624 {
01625 client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
01626 if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01627 client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
01628 if( client_machine.isEmpty())
01629 client_machine = "localhost";
01630 }
01631
01636 QCString Client::wmClientMachine( bool use_localhost ) const
01637 {
01638 QCString result = client_machine;
01639 if( use_localhost )
01640 {
01641 if( result != "localhost" && isLocalMachine( result ))
01642 result = "localhost";
01643 }
01644 return result;
01645 }
01646
01651 Window Client::wmClientLeader() const
01652 {
01653 if (wmClientLeaderWin)
01654 return wmClientLeaderWin;
01655 return window();
01656 }
01657
01658 bool Client::wantsTabFocus() const
01659 {
01660 return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
01661 }
01662
01663
01664 bool Client::wantsInput() const
01665 {
01666 return rules()->checkAcceptFocus( input || Ptakefocus );
01667 }
01668
01669 bool Client::isDesktop() const
01670 {
01671 return windowType() == NET::Desktop;
01672 }
01673
01674 bool Client::isDock() const
01675 {
01676 return windowType() == NET::Dock;
01677 }
01678
01679 bool Client::isTopMenu() const
01680 {
01681 return windowType() == NET::TopMenu;
01682 }
01683
01684
01685 bool Client::isMenu() const
01686 {
01687 return windowType() == NET::Menu && !isTopMenu();
01688 }
01689
01690 bool Client::isToolbar() const
01691 {
01692 return windowType() == NET::Toolbar;
01693 }
01694
01695 bool Client::isSplash() const
01696 {
01697 return windowType() == NET::Splash;
01698 }
01699
01700 bool Client::isUtility() const
01701 {
01702 return windowType() == NET::Utility;
01703 }
01704
01705 bool Client::isDialog() const
01706 {
01707 return windowType() == NET::Dialog;
01708 }
01709
01710 bool Client::isNormalWindow() const
01711 {
01712 return windowType() == NET::Normal;
01713 }
01714
01715 bool Client::isSpecialWindow() const
01716 {
01717 return isDesktop() || isDock() || isSplash() || isTopMenu()
01718 || isToolbar();
01719 }
01720
01721 NET::WindowType Client::windowType( bool direct, int supported_types ) const
01722 {
01723 NET::WindowType wt = info->windowType( supported_types );
01724 if( direct )
01725 return wt;
01726 NET::WindowType wt2 = rules()->checkType( wt );
01727 if( wt != wt2 )
01728 {
01729 wt = wt2;
01730 info->setWindowType( wt );
01731 }
01732
01733 if( wt == NET::Menu )
01734 {
01735
01736
01737
01738 if( x() == 0 && y() < 0 && y() > -10 && height() < 100
01739 && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
01740 wt = NET::TopMenu;
01741 }
01742
01743 const char* const oo_prefix = "openoffice.org";
01744
01745 if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
01746 wt = NET::Normal;
01747 if( wt == NET::Unknown )
01748 wt = isTransient() ? NET::Dialog : NET::Normal;
01749 return wt;
01750 }
01751
01756 void Client::setCursor( Position m )
01757 {
01758 if( !isResizable() || isShade())
01759 {
01760 m = PositionCenter;
01761 }
01762 switch ( m )
01763 {
01764 case PositionTopLeft:
01765 case PositionBottomRight:
01766 setCursor( sizeFDiagCursor );
01767 break;
01768 case PositionBottomLeft:
01769 case PositionTopRight:
01770 setCursor( sizeBDiagCursor );
01771 break;
01772 case PositionTop:
01773 case PositionBottom:
01774 setCursor( sizeVerCursor );
01775 break;
01776 case PositionLeft:
01777 case PositionRight:
01778 setCursor( sizeHorCursor );
01779 break;
01780 default:
01781 if( buttonDown && isMovable())
01782 setCursor( sizeAllCursor );
01783 else
01784 setCursor( arrowCursor );
01785 break;
01786 }
01787 }
01788
01789
01790 void Client::setCursor( const QCursor& c )
01791 {
01792 if( c.handle() == cursor.handle())
01793 return;
01794 cursor = c;
01795 if( decoration != NULL )
01796 decoration->widget()->setCursor( cursor );
01797 XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
01798 }
01799
01800 Client::Position Client::mousePosition( const QPoint& p ) const
01801 {
01802 if( decoration != NULL )
01803 return decoration->mousePosition( p );
01804 return PositionCenter;
01805 }
01806
01807 void Client::updateAllowedActions( bool force )
01808 {
01809 if( !isManaged() && !force )
01810 return;
01811 unsigned long old_allowed_actions = allowed_actions;
01812 allowed_actions = 0;
01813 if( isMovable())
01814 allowed_actions |= NET::ActionMove;
01815 if( isResizable())
01816 allowed_actions |= NET::ActionResize;
01817 if( isMinimizable())
01818 allowed_actions |= NET::ActionMinimize;
01819 if( isShadeable())
01820 allowed_actions |= NET::ActionShade;
01821
01822 if( isMaximizable())
01823 allowed_actions |= NET::ActionMax;
01824 if( userCanSetFullScreen())
01825 allowed_actions |= NET::ActionFullScreen;
01826 allowed_actions |= NET::ActionChangeDesktop;
01827 if( isCloseable())
01828 allowed_actions |= NET::ActionClose;
01829 if( old_allowed_actions == allowed_actions )
01830 return;
01831
01832 info->setAllowedActions( allowed_actions );
01833
01834 }
01835
01836 void Client::autoRaise()
01837 {
01838 workspace()->raiseClient( this );
01839 cancelAutoRaise();
01840 }
01841
01842 void Client::cancelAutoRaise()
01843 {
01844 delete autoRaiseTimer;
01845 autoRaiseTimer = 0;
01846 }
01847
01848 void Client::setOpacity(bool translucent, uint opacity)
01849 {
01850 if (isDesktop())
01851 return;
01852
01853
01854 if (!translucent || opacity == 0xFFFFFFFF)
01855 {
01856 opacity_ = 0xFFFFFFFF;
01857 XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
01858 XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity);
01859 }
01860 else{
01861 if(opacity == opacity_)
01862 return;
01863 opacity_ = opacity;
01864 long data = opacity;
01865 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01866 XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01867 }
01868 }
01869
01870 void Client::setShadowSize(uint shadowSize)
01871 {
01872
01873
01874 long data = shadowSize;
01875 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01876 }
01877
01878 void Client::updateOpacity()
01879
01880 {
01881 if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
01882 return;
01883 if (isActive())
01884 {
01885 if( ruleOpacityActive() )
01886 setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01887 else
01888 setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01889 if (isBMP())
01890
01891 {
01892 ClientList tmpGroupMembers = group()->members();
01893 ClientList activeGroupMembers;
01894 activeGroupMembers.append(this);
01895 tmpGroupMembers.remove(this);
01896 ClientList::Iterator it = tmpGroupMembers.begin();
01897 while (it != tmpGroupMembers.end())
01898
01899 {
01900 if ((*it) != this && (*it)->isBMP())
01901
01902 {
01903
01904 if ((*it)->touches(this))
01905 {
01906
01907 if( ruleOpacityActive() )
01908 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01909 else
01910 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01911
01912 (*it)->setShadowSize(options->activeWindowShadowSize);
01913 activeGroupMembers.append(*it);
01914 tmpGroupMembers.remove(it);
01915 it = tmpGroupMembers.begin();
01916 continue;
01917 }
01918 else
01919 {
01920 bool found = false;
01921 for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
01922 {
01923 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01924 {
01925
01926 if( ruleOpacityActive() )
01927 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01928 else
01929 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01930 (*it)->setShadowSize(options->activeWindowShadowSize);
01931 activeGroupMembers.append(*it);
01932 tmpGroupMembers.remove(it);
01933 it = tmpGroupMembers.begin();
01934 found = true;
01935
01936 break;
01937 }
01938 }
01939 if (found) continue;
01940 }
01941 }
01942 it++;
01943 }
01944 }
01945 else if (isNormalWindow())
01946
01947 {
01948 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
01949 if ((*it)->isDialog() || (*it)->isUtility())
01950 if( (*it)->ruleOpacityActive() )
01951 (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
01952 else
01953 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01954 }
01955 }
01956 else
01957 {
01958 if( ruleOpacityInactive() )
01959 setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
01960 else
01961 setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
01962 options->inactiveWindowOpacity);
01963
01964 if (isBMP())
01965
01966 {
01967 ClientList tmpGroupMembers = group()->members();
01968 ClientList inactiveGroupMembers;
01969 inactiveGroupMembers.append(this);
01970 tmpGroupMembers.remove(this);
01971 ClientList::Iterator it = tmpGroupMembers.begin();
01972 while ( it != tmpGroupMembers.end() )
01973
01974 {
01975 if ((*it) != this && (*it)->isBMP())
01976
01977 {
01978
01979 if ((*it)->touches(this))
01980 {
01981
01982 if( (*it)->ruleOpacityInactive() )
01983 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01984 else
01985 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
01986 (*it)->setShadowSize(options->inactiveWindowShadowSize);
01987
01988 inactiveGroupMembers.append(*it);
01989 tmpGroupMembers.remove(it);
01990 it = tmpGroupMembers.begin();
01991 continue;
01992 }
01993 else
01994 {
01995 bool found = false;
01996 for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
01997 {
01998 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01999 {
02000
02001 if( (*it)->ruleOpacityInactive() )
02002 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02003 else
02004 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02005 (*it)->setShadowSize(options->inactiveWindowShadowSize);
02006
02007 inactiveGroupMembers.append(*it);
02008 tmpGroupMembers.remove(it);
02009 it = tmpGroupMembers.begin();
02010 found = true;
02011 break;
02012 }
02013 }
02014 if (found) continue;
02015 }
02016 }
02017 it++;
02018 }
02019 }
02020 else if (isNormalWindow())
02021 {
02022 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02023 if ((*it)->isUtility())
02024 if( (*it)->ruleOpacityInactive() )
02025 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02026 else
02027 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02028 }
02029 }
02030 }
02031
02032 void Client::updateShadowSize()
02033
02034 {
02035 if (!(isNormalWindow() || isDialog() || isUtility() ))
02036 return;
02037 if (isActive())
02038 setShadowSize(options->activeWindowShadowSize);
02039 else
02040 setShadowSize(options->inactiveWindowShadowSize);
02041 }
02042
02043 uint Client::ruleOpacityInactive()
02044 {
02045 return rule_opacity_inactive;
02046 }
02047
02048 uint Client::ruleOpacityActive()
02049 {
02050 return rule_opacity_active;
02051 }
02052
02053 bool Client::getWindowOpacity()
02054 {
02055 unsigned char *data = 0;
02056 Atom actual;
02057 int format, result;
02058 unsigned long n, left;
02059 result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, &data);
02060 if (result == Success && data != None && format == 32 )
02061 {
02062 opacity_ = *reinterpret_cast< long* >( data );
02063 custom_opacity = true;
02064
02065 XFree ((char*)data);
02066 return TRUE;
02067 }
02068 return FALSE;
02069 }
02070
02071 void Client::setCustomOpacityFlag(bool custom)
02072 {
02073 custom_opacity = custom;
02074 }
02075
02076 uint Client::opacity()
02077 {
02078 return opacity_;
02079 }
02080
02081 int Client::opacityPercentage()
02082 {
02083 return int(100*((double)opacity_/0xffffffff));
02084 }
02085
02086 bool Client::touches(const Client* c)
02087
02088 {
02089 if (y() == c->y() + c->height())
02090 return TRUE;
02091 if (y() + height() == c->y())
02092 return TRUE;
02093 if (x() == c->x() + c->width())
02094 return TRUE;
02095 if (x() + width() == c->x())
02096 return TRUE;
02097 return FALSE;
02098 }
02099
02100 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
02101 {
02102 long data = (topHeight < 255 ? topHeight : 255) << 24 |
02103 (rightWidth < 255 ? rightWidth : 255) << 16 |
02104 (bottomHeight < 255 ? bottomHeight : 255) << 8 |
02105 (leftWidth < 255 ? leftWidth : 255);
02106 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02107 }
02108
02109 void Client::unsetDecoHashProperty()
02110 {
02111 XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
02112 }
02113
02114 #ifndef NDEBUG
02115 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
02116 {
02117 if( cl == NULL )
02118 return stream << "\'NULL_CLIENT\'";
02119 return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
02120 }
02121 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
02122 {
02123 stream << "LIST:(";
02124 bool first = true;
02125 for( ClientList::ConstIterator it = list.begin();
02126 it != list.end();
02127 ++it )
02128 {
02129 if( !first )
02130 stream << ":";
02131 first = false;
02132 stream << *it;
02133 }
02134 stream << ")";
02135 return stream;
02136 }
02137 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
02138 {
02139 stream << "LIST:(";
02140 bool first = true;
02141 for( ConstClientList::ConstIterator it = list.begin();
02142 it != list.end();
02143 ++it )
02144 {
02145 if( !first )
02146 stream << ":";
02147 first = false;
02148 stream << *it;
02149 }
02150 stream << ")";
02151 return stream;
02152 }
02153 #endif
02154
02155 QPixmap * kwin_get_menu_pix_hack()
02156 {
02157 static QPixmap p;
02158 if ( p.isNull() )
02159 p = SmallIcon( "bx2" );
02160 return &p;
02161 }
02162
02163 }
02164
02165 #include "client.moc"