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 int Client::screen() const
01259 {
01260 if( !options->xineramaEnabled )
01261 return 0;
01262 return workspace()->screenNumber( geometry().center());
01263 }
01264
01265 bool Client::isOnScreen( int screen ) const
01266 {
01267 if( !options->xineramaEnabled )
01268 return screen == 0;
01269 return workspace()->screenGeometry( screen ).intersects( geometry());
01270 }
01271
01272
01273 void Client::takeActivity( int flags, bool handled, allowed_t )
01274 {
01275 if( !handled || !Ptakeactivity )
01276 {
01277 if( flags & ActivityFocus )
01278 takeFocus( Allowed );
01279 if( flags & ActivityRaise )
01280 workspace()->raiseClient( this );
01281 return;
01282 }
01283
01284 #ifndef NDEBUG
01285 static Time previous_activity_timestamp;
01286 static Client* previous_client;
01287 if( previous_activity_timestamp == qt_x_time && previous_client != this )
01288 {
01289 kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
01290 kdDebug( 1212 ) << kdBacktrace() << endl;
01291 }
01292 previous_activity_timestamp = qt_x_time;
01293 previous_client = this;
01294 #endif
01295 workspace()->sendTakeActivity( this, qt_x_time, flags );
01296 }
01297
01298
01299 void Client::takeFocus( allowed_t )
01300 {
01301 #ifndef NDEBUG
01302 static Time previous_focus_timestamp;
01303 static Client* previous_client;
01304 if( previous_focus_timestamp == qt_x_time && previous_client != this )
01305 {
01306 kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01307 kdDebug( 1212 ) << kdBacktrace() << endl;
01308 }
01309 previous_focus_timestamp = qt_x_time;
01310 previous_client = this;
01311 #endif
01312 if ( rules()->checkAcceptFocus( input ))
01313 {
01314 XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01315 }
01316 if ( Ptakefocus )
01317 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01318 workspace()->setShouldGetFocus( this );
01319 }
01320
01328 bool Client::providesContextHelp() const
01329 {
01330 return Pcontexthelp;
01331 }
01332
01333
01340 void Client::showContextHelp()
01341 {
01342 if ( Pcontexthelp )
01343 {
01344 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01345 QWhatsThis::enterWhatsThisMode();
01346 }
01347 }
01348
01349
01354 void Client::fetchName()
01355 {
01356 setCaption( readName());
01357 }
01358
01359 QString Client::readName() const
01360 {
01361 if ( info->name() && info->name()[ 0 ] != '\0' )
01362 return QString::fromUtf8( info->name() );
01363 else
01364 return KWin::readNameProperty( window(), XA_WM_NAME );
01365 }
01366
01367 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
01368
01369 void Client::setCaption( const QString& s, bool force )
01370 {
01371 if ( s != cap_normal || force )
01372 {
01373 bool reset_name = force;
01374 for( unsigned int i = 0;
01375 i < s.length();
01376 ++i )
01377 if( !s[ i ].isPrint())
01378 s[ i ] = ' ';
01379 cap_normal = s;
01380 bool was_suffix = ( !cap_suffix.isEmpty());
01381 QString machine_suffix;
01382 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
01383 machine_suffix = " <@" + wmClientMachine( true ) + ">";
01384 QString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
01385 cap_suffix = machine_suffix + shortcut_suffix;
01386 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
01387 {
01388 int i = 2;
01389 do
01390 {
01391 cap_suffix = machine_suffix + " <" + QString::number(i) + ">" + shortcut_suffix;
01392 i++;
01393 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
01394 info->setVisibleName( caption().utf8() );
01395 reset_name = false;
01396 }
01397 if(( was_suffix && cap_suffix.isEmpty()
01398 || reset_name ))
01399 {
01400 info->setVisibleName( "" );
01401 info->setVisibleIconName( "" );
01402 }
01403 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
01404 info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
01405
01406 if( isManaged() && decoration != NULL )
01407 decoration->captionChange();
01408 }
01409 }
01410
01411 void Client::updateCaption()
01412 {
01413 setCaption( cap_normal, true );
01414 }
01415
01416 void Client::fetchIconicName()
01417 {
01418 QString s;
01419 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
01420 s = QString::fromUtf8( info->iconName() );
01421 else
01422 s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
01423 if ( s != cap_iconic )
01424 {
01425 bool was_set = !cap_iconic.isEmpty();
01426 cap_iconic = s;
01427 if( !cap_suffix.isEmpty())
01428 {
01429 if( !cap_iconic.isEmpty())
01430 info->setVisibleIconName( ( s + cap_suffix ).utf8() );
01431 else if( was_set )
01432 info->setVisibleIconName( "" );
01433 }
01434 }
01435 }
01436
01439 QString Client::caption( bool full ) const
01440 {
01441 return full ? cap_normal + cap_suffix : cap_normal;
01442 }
01443
01444 void Client::getWMHints()
01445 {
01446 XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
01447 input = true;
01448 window_group = None;
01449 urgency = false;
01450 if ( hints )
01451 {
01452 if( hints->flags & InputHint )
01453 input = hints->input;
01454 if( hints->flags & WindowGroupHint )
01455 window_group = hints->window_group;
01456 urgency = ( hints->flags & UrgencyHint ) ? true : false;
01457 XFree( (char*)hints );
01458 }
01459 checkGroup();
01460 updateUrgency();
01461 updateAllowedActions();
01462 }
01463
01464 void Client::getMotifHints()
01465 {
01466 bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
01467 Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
01468 motif_noborder = mnoborder;
01469 if( !hasNETSupport())
01470 {
01471 motif_may_resize = mresize;
01472 motif_may_move = mmove;
01473 }
01474 else
01475 motif_may_resize = motif_may_move = true;
01476
01477
01478 motif_may_close = mclose;
01479 if( isManaged())
01480 updateDecoration( true );
01481 }
01482
01483 void Client::readIcons( Window win, QPixmap* icon, QPixmap* miniicon )
01484 {
01485
01486 if( icon != NULL )
01487 *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
01488 if( miniicon != NULL )
01489 if( icon == NULL || !icon->isNull())
01490 *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
01491 else
01492 *miniicon = QPixmap();
01493 }
01494
01495 void Client::getIcons()
01496 {
01497
01498 readIcons( window(), &icon_pix, &miniicon_pix );
01499 if( icon_pix.isNull())
01500 {
01501 icon_pix = group()->icon();
01502 miniicon_pix = group()->miniIcon();
01503 }
01504 if( icon_pix.isNull() && isTransient())
01505 {
01506 ClientList mainclients = mainClients();
01507 for( ClientList::ConstIterator it = mainclients.begin();
01508 it != mainclients.end() && icon_pix.isNull();
01509 ++it )
01510 {
01511 icon_pix = (*it)->icon();
01512 miniicon_pix = (*it)->miniIcon();
01513 }
01514 }
01515 if( icon_pix.isNull())
01516 {
01517 icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
01518 miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
01519 }
01520 if( isManaged() && decoration != NULL )
01521 decoration->iconChange();
01522 }
01523
01524 void Client::getWindowProtocols()
01525 {
01526 Atom *p;
01527 int i,n;
01528
01529 Pdeletewindow = 0;
01530 Ptakefocus = 0;
01531 Ptakeactivity = 0;
01532 Pcontexthelp = 0;
01533 Pping = 0;
01534
01535 if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
01536 {
01537 for (i = 0; i < n; i++)
01538 if (p[i] == atoms->wm_delete_window)
01539 Pdeletewindow = 1;
01540 else if (p[i] == atoms->wm_take_focus)
01541 Ptakefocus = 1;
01542 else if (p[i] == atoms->net_wm_take_activity)
01543 Ptakeactivity = 1;
01544 else if (p[i] == atoms->net_wm_context_help)
01545 Pcontexthelp = 1;
01546 else if (p[i] == atoms->net_wm_ping)
01547 Pping = 1;
01548 if (n>0)
01549 XFree(p);
01550 }
01551 }
01552
01553 static int nullErrorHandler(Display *, XErrorEvent *)
01554 {
01555 return 0;
01556 }
01557
01561 QCString Client::staticWindowRole(WId w)
01562 {
01563 return getStringProperty(w, qt_window_role).lower();
01564 }
01565
01569 QCString Client::staticSessionId(WId w)
01570 {
01571 return getStringProperty(w, qt_sm_client_id);
01572 }
01573
01577 QCString Client::staticWmCommand(WId w)
01578 {
01579 return getStringProperty(w, XA_WM_COMMAND, ' ');
01580 }
01581
01585 Window Client::staticWmClientLeader(WId w)
01586 {
01587 Atom type;
01588 int format, status;
01589 unsigned long nitems = 0;
01590 unsigned long extra = 0;
01591 unsigned char *data = 0;
01592 Window result = w;
01593 XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
01594 status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
01595 FALSE, XA_WINDOW, &type, &format,
01596 &nitems, &extra, &data );
01597 XSetErrorHandler(oldHandler);
01598 if (status == Success )
01599 {
01600 if (data && nitems > 0)
01601 result = *((Window*) data);
01602 XFree(data);
01603 }
01604 return result;
01605 }
01606
01607
01608 void Client::getWmClientLeader()
01609 {
01610 wmClientLeaderWin = staticWmClientLeader(window());
01611 }
01612
01617 QCString Client::sessionId()
01618 {
01619 QCString result = staticSessionId(window());
01620 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01621 result = staticSessionId(wmClientLeaderWin);
01622 return result;
01623 }
01624
01629 QCString Client::wmCommand()
01630 {
01631 QCString result = staticWmCommand(window());
01632 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01633 result = staticWmCommand(wmClientLeaderWin);
01634 return result;
01635 }
01636
01637 void Client::getWmClientMachine()
01638 {
01639 client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
01640 if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
01641 client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
01642 if( client_machine.isEmpty())
01643 client_machine = "localhost";
01644 }
01645
01650 QCString Client::wmClientMachine( bool use_localhost ) const
01651 {
01652 QCString result = client_machine;
01653 if( use_localhost )
01654 {
01655 if( result != "localhost" && isLocalMachine( result ))
01656 result = "localhost";
01657 }
01658 return result;
01659 }
01660
01665 Window Client::wmClientLeader() const
01666 {
01667 if (wmClientLeaderWin)
01668 return wmClientLeaderWin;
01669 return window();
01670 }
01671
01672 bool Client::wantsTabFocus() const
01673 {
01674 return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
01675 }
01676
01677
01678 bool Client::wantsInput() const
01679 {
01680 return rules()->checkAcceptFocus( input || Ptakefocus );
01681 }
01682
01683 bool Client::isDesktop() const
01684 {
01685 return windowType() == NET::Desktop;
01686 }
01687
01688 bool Client::isDock() const
01689 {
01690 return windowType() == NET::Dock;
01691 }
01692
01693 bool Client::isTopMenu() const
01694 {
01695 return windowType() == NET::TopMenu;
01696 }
01697
01698
01699 bool Client::isMenu() const
01700 {
01701 return windowType() == NET::Menu && !isTopMenu();
01702 }
01703
01704 bool Client::isToolbar() const
01705 {
01706 return windowType() == NET::Toolbar;
01707 }
01708
01709 bool Client::isSplash() const
01710 {
01711 return windowType() == NET::Splash;
01712 }
01713
01714 bool Client::isUtility() const
01715 {
01716 return windowType() == NET::Utility;
01717 }
01718
01719 bool Client::isDialog() const
01720 {
01721 return windowType() == NET::Dialog;
01722 }
01723
01724 bool Client::isNormalWindow() const
01725 {
01726 return windowType() == NET::Normal;
01727 }
01728
01729 bool Client::isSpecialWindow() const
01730 {
01731 return isDesktop() || isDock() || isSplash() || isTopMenu()
01732 || isToolbar();
01733 }
01734
01735 NET::WindowType Client::windowType( bool direct, int supported_types ) const
01736 {
01737 NET::WindowType wt = info->windowType( supported_types );
01738 if( direct )
01739 return wt;
01740 NET::WindowType wt2 = rules()->checkType( wt );
01741 if( wt != wt2 )
01742 {
01743 wt = wt2;
01744 info->setWindowType( wt );
01745 }
01746
01747 if( wt == NET::Menu )
01748 {
01749
01750
01751
01752 if( x() == 0 && y() < 0 && y() > -10 && height() < 100
01753 && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
01754 wt = NET::TopMenu;
01755 }
01756
01757 const char* const oo_prefix = "openoffice.org";
01758
01759 if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
01760 wt = NET::Normal;
01761 if( wt == NET::Unknown )
01762 wt = isTransient() ? NET::Dialog : NET::Normal;
01763 return wt;
01764 }
01765
01770 void Client::setCursor( Position m )
01771 {
01772 if( !isResizable() || isShade())
01773 {
01774 m = PositionCenter;
01775 }
01776 switch ( m )
01777 {
01778 case PositionTopLeft:
01779 case PositionBottomRight:
01780 setCursor( sizeFDiagCursor );
01781 break;
01782 case PositionBottomLeft:
01783 case PositionTopRight:
01784 setCursor( sizeBDiagCursor );
01785 break;
01786 case PositionTop:
01787 case PositionBottom:
01788 setCursor( sizeVerCursor );
01789 break;
01790 case PositionLeft:
01791 case PositionRight:
01792 setCursor( sizeHorCursor );
01793 break;
01794 default:
01795 if( buttonDown && isMovable())
01796 setCursor( sizeAllCursor );
01797 else
01798 setCursor( arrowCursor );
01799 break;
01800 }
01801 }
01802
01803
01804 void Client::setCursor( const QCursor& c )
01805 {
01806 if( c.handle() == cursor.handle())
01807 return;
01808 cursor = c;
01809 if( decoration != NULL )
01810 decoration->widget()->setCursor( cursor );
01811 XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
01812 }
01813
01814 Client::Position Client::mousePosition( const QPoint& p ) const
01815 {
01816 if( decoration != NULL )
01817 return decoration->mousePosition( p );
01818 return PositionCenter;
01819 }
01820
01821 void Client::updateAllowedActions( bool force )
01822 {
01823 if( !isManaged() && !force )
01824 return;
01825 unsigned long old_allowed_actions = allowed_actions;
01826 allowed_actions = 0;
01827 if( isMovable())
01828 allowed_actions |= NET::ActionMove;
01829 if( isResizable())
01830 allowed_actions |= NET::ActionResize;
01831 if( isMinimizable())
01832 allowed_actions |= NET::ActionMinimize;
01833 if( isShadeable())
01834 allowed_actions |= NET::ActionShade;
01835
01836 if( isMaximizable())
01837 allowed_actions |= NET::ActionMax;
01838 if( userCanSetFullScreen())
01839 allowed_actions |= NET::ActionFullScreen;
01840 allowed_actions |= NET::ActionChangeDesktop;
01841 if( isCloseable())
01842 allowed_actions |= NET::ActionClose;
01843 if( old_allowed_actions == allowed_actions )
01844 return;
01845
01846 info->setAllowedActions( allowed_actions );
01847
01848 }
01849
01850 void Client::autoRaise()
01851 {
01852 workspace()->raiseClient( this );
01853 cancelAutoRaise();
01854 }
01855
01856 void Client::cancelAutoRaise()
01857 {
01858 delete autoRaiseTimer;
01859 autoRaiseTimer = 0;
01860 }
01861
01862 void Client::setOpacity(bool translucent, uint opacity)
01863 {
01864 if (isDesktop())
01865 return;
01866
01867
01868 if (!translucent || opacity == 0xFFFFFFFF)
01869 {
01870 opacity_ = 0xFFFFFFFF;
01871 XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
01872 XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity);
01873 }
01874 else{
01875 if(opacity == opacity_)
01876 return;
01877 opacity_ = opacity;
01878 long data = opacity;
01879 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01880 XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01881 }
01882 }
01883
01884 void Client::setShadowSize(uint shadowSize)
01885 {
01886
01887
01888 long data = shadowSize;
01889 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
01890 }
01891
01892 void Client::updateOpacity()
01893
01894 {
01895 if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
01896 return;
01897 if (isActive())
01898 {
01899 if( ruleOpacityActive() )
01900 setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01901 else
01902 setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01903 if (isBMP())
01904
01905 {
01906 ClientList tmpGroupMembers = group()->members();
01907 ClientList activeGroupMembers;
01908 activeGroupMembers.append(this);
01909 tmpGroupMembers.remove(this);
01910 ClientList::Iterator it = tmpGroupMembers.begin();
01911 while (it != tmpGroupMembers.end())
01912
01913 {
01914 if ((*it) != this && (*it)->isBMP())
01915
01916 {
01917
01918 if ((*it)->touches(this))
01919 {
01920
01921 if( ruleOpacityActive() )
01922 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01923 else
01924 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01925
01926 (*it)->setShadowSize(options->activeWindowShadowSize);
01927 activeGroupMembers.append(*it);
01928 tmpGroupMembers.remove(it);
01929 it = tmpGroupMembers.begin();
01930 continue;
01931 }
01932 else
01933 {
01934 bool found = false;
01935 for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
01936 {
01937 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
01938 {
01939
01940 if( ruleOpacityActive() )
01941 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
01942 else
01943 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01944 (*it)->setShadowSize(options->activeWindowShadowSize);
01945 activeGroupMembers.append(*it);
01946 tmpGroupMembers.remove(it);
01947 it = tmpGroupMembers.begin();
01948 found = true;
01949
01950 break;
01951 }
01952 }
01953 if (found) continue;
01954 }
01955 }
01956 it++;
01957 }
01958 }
01959 else if (isNormalWindow())
01960
01961 {
01962 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
01963 if ((*it)->isDialog() || (*it)->isUtility())
01964 if( (*it)->ruleOpacityActive() )
01965 (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
01966 else
01967 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
01968 }
01969 }
01970 else
01971 {
01972 if( ruleOpacityInactive() )
01973 setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
01974 else
01975 setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
01976 options->inactiveWindowOpacity);
01977
01978 if (isBMP())
01979
01980 {
01981 ClientList tmpGroupMembers = group()->members();
01982 ClientList inactiveGroupMembers;
01983 inactiveGroupMembers.append(this);
01984 tmpGroupMembers.remove(this);
01985 ClientList::Iterator it = tmpGroupMembers.begin();
01986 while ( it != tmpGroupMembers.end() )
01987
01988 {
01989 if ((*it) != this && (*it)->isBMP())
01990
01991 {
01992
01993 if ((*it)->touches(this))
01994 {
01995
01996 if( (*it)->ruleOpacityInactive() )
01997 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
01998 else
01999 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02000 (*it)->setShadowSize(options->inactiveWindowShadowSize);
02001
02002 inactiveGroupMembers.append(*it);
02003 tmpGroupMembers.remove(it);
02004 it = tmpGroupMembers.begin();
02005 continue;
02006 }
02007 else
02008 {
02009 bool found = false;
02010 for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
02011 {
02012 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
02013 {
02014
02015 if( (*it)->ruleOpacityInactive() )
02016 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02017 else
02018 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02019 (*it)->setShadowSize(options->inactiveWindowShadowSize);
02020
02021 inactiveGroupMembers.append(*it);
02022 tmpGroupMembers.remove(it);
02023 it = tmpGroupMembers.begin();
02024 found = true;
02025 break;
02026 }
02027 }
02028 if (found) continue;
02029 }
02030 }
02031 it++;
02032 }
02033 }
02034 else if (isNormalWindow())
02035 {
02036 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02037 if ((*it)->isUtility())
02038 if( (*it)->ruleOpacityInactive() )
02039 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02040 else
02041 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02042 }
02043 }
02044 }
02045
02046 void Client::updateShadowSize()
02047
02048 {
02049 if (!(isNormalWindow() || isDialog() || isUtility() ))
02050 return;
02051 if (isActive())
02052 setShadowSize(options->activeWindowShadowSize);
02053 else
02054 setShadowSize(options->inactiveWindowShadowSize);
02055 }
02056
02057 uint Client::ruleOpacityInactive()
02058 {
02059 return rule_opacity_inactive;
02060 }
02061
02062 uint Client::ruleOpacityActive()
02063 {
02064 return rule_opacity_active;
02065 }
02066
02067 bool Client::getWindowOpacity()
02068 {
02069 unsigned char *data = 0;
02070 Atom actual;
02071 int format, result;
02072 unsigned long n, left;
02073 result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, &data);
02074 if (result == Success && data != None && format == 32 )
02075 {
02076 opacity_ = *reinterpret_cast< long* >( data );
02077 custom_opacity = true;
02078
02079 XFree ((char*)data);
02080 return TRUE;
02081 }
02082 return FALSE;
02083 }
02084
02085 void Client::setCustomOpacityFlag(bool custom)
02086 {
02087 custom_opacity = custom;
02088 }
02089
02090 uint Client::opacity()
02091 {
02092 return opacity_;
02093 }
02094
02095 int Client::opacityPercentage()
02096 {
02097 return int(100*((double)opacity_/0xffffffff));
02098 }
02099
02100 bool Client::touches(const Client* c)
02101
02102 {
02103 if (y() == c->y() + c->height())
02104 return TRUE;
02105 if (y() + height() == c->y())
02106 return TRUE;
02107 if (x() == c->x() + c->width())
02108 return TRUE;
02109 if (x() + width() == c->x())
02110 return TRUE;
02111 return FALSE;
02112 }
02113
02114 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
02115 {
02116 long data = (topHeight < 255 ? topHeight : 255) << 24 |
02117 (rightWidth < 255 ? rightWidth : 255) << 16 |
02118 (bottomHeight < 255 ? bottomHeight : 255) << 8 |
02119 (leftWidth < 255 ? leftWidth : 255);
02120 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02121 }
02122
02123 void Client::unsetDecoHashProperty()
02124 {
02125 XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
02126 }
02127
02128 #ifndef NDEBUG
02129 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
02130 {
02131 if( cl == NULL )
02132 return stream << "\'NULL_CLIENT\'";
02133 return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
02134 }
02135 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
02136 {
02137 stream << "LIST:(";
02138 bool first = true;
02139 for( ClientList::ConstIterator it = list.begin();
02140 it != list.end();
02141 ++it )
02142 {
02143 if( !first )
02144 stream << ":";
02145 first = false;
02146 stream << *it;
02147 }
02148 stream << ")";
02149 return stream;
02150 }
02151 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
02152 {
02153 stream << "LIST:(";
02154 bool first = true;
02155 for( ConstClientList::ConstIterator it = list.begin();
02156 it != list.end();
02157 ++it )
02158 {
02159 if( !first )
02160 stream << ":";
02161 first = false;
02162 stream << *it;
02163 }
02164 stream << ")";
02165 return stream;
02166 }
02167 #endif
02168
02169 QPixmap * kwin_get_menu_pix_hack()
02170 {
02171 static QPixmap p;
02172 if ( p.isNull() )
02173 p = SmallIcon( "bx2" );
02174 return &p;
02175 }
02176
02177 }
02178
02179 #include "client.moc"