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