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