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