00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "client.h"
00013
00014 #include <math.h>
00015
00016 #include <tqapplication.h>
00017 #include <tqpainter.h>
00018 #include <tqdatetime.h>
00019 #include <tqimage.h>
00020 #include <kprocess.h>
00021 #include <unistd.h>
00022 #include <kstandarddirs.h>
00023 #include <tqwhatsthis.h>
00024 #include <kwin.h>
00025 #include <kiconloader.h>
00026 #include <stdlib.h>
00027
00028 #include "bridge.h"
00029 #include "group.h"
00030 #include "workspace.h"
00031 #include "atoms.h"
00032 #include "notifications.h"
00033 #include "rules.h"
00034
00035 #include <X11/extensions/shape.h>
00036
00037
00038
00039
00040 extern Atom qt_wm_state;
00041 extern Time qt_x_time;
00042 extern Atom qt_window_role;
00043 extern Atom qt_sm_client_id;
00044
00045
00046 static const int SHADOW_DELAY = 200;
00047
00048 namespace KWinInternal
00049 {
00050
00051
00052
00053
00054
00055
00056
00057 struct ShadowRegion
00058 {
00059 TQRegion region;
00060 Client *client;
00061 };
00062 static TQValueList<ShadowRegion> shadowRegions;
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00088 Client::Client( Workspace *ws )
00089 : TQObject( NULL ),
00090 client( None ),
00091 wrapper( None ),
00092 frame( None ),
00093 decoration( NULL ),
00094 wspace( ws ),
00095 bridge( new Bridge( this )),
00096 move_faked_activity( false ),
00097 move_resize_grab_window( None ),
00098 transient_for( NULL ),
00099 transient_for_id( None ),
00100 original_transient_for_id( None ),
00101 in_group( NULL ),
00102 window_group( None ),
00103 in_layer( UnknownLayer ),
00104 ping_timer( NULL ),
00105 process_killer( NULL ),
00106 user_time( CurrentTime ),
00107 allowed_actions( 0 ),
00108 postpone_geometry_updates( 0 ),
00109 pending_geometry_update( false ),
00110 shade_geometry_change( false ),
00111 border_left( 0 ),
00112 border_right( 0 ),
00113 border_top( 0 ),
00114 border_bottom( 0 ),
00115 opacity_( 0 ),
00116 demandAttentionKNotifyTimer( NULL )
00117
00118 {
00119 autoRaiseTimer = 0;
00120 shadeHoverTimer = 0;
00121
00122 shadowDelayTimer = new TQTimer(this);
00123 opacityCache = &activeOpacityCache;
00124 shadowAfterClient = NULL;
00125 shadowWidget = NULL;
00126 shadowMe = true;
00127 connect(shadowDelayTimer, TQT_SIGNAL(timeout()), TQT_SLOT(drawShadow()));
00128
00129
00130 mapping_state = WithdrawnState;
00131 desk = 0;
00132
00133 mode = PositionCenter;
00134 buttonDown = FALSE;
00135 moveResizeMode = FALSE;
00136
00137 info = NULL;
00138
00139 shade_mode = ShadeNone;
00140 active = FALSE;
00141 deleting = false;
00142 keep_above = FALSE;
00143 keep_below = FALSE;
00144 is_shape = FALSE;
00145 motif_noborder = false;
00146 motif_may_move = TRUE;
00147 motif_may_resize = TRUE;
00148 motif_may_close = TRUE;
00149 fullscreen_mode = FullScreenNone;
00150 skip_taskbar = FALSE;
00151 original_skip_taskbar = false;
00152 minimized = false;
00153 hidden = false;
00154 modal = false;
00155 noborder = false;
00156 user_noborder = false;
00157 urgency = false;
00158 ignore_focus_stealing = false;
00159 demands_attention = false;
00160 check_active_modal = false;
00161
00162 Pdeletewindow = 0;
00163 Ptakefocus = 0;
00164 Ptakeactivity = 0;
00165 Pcontexthelp = 0;
00166 Pping = 0;
00167 input = FALSE;
00168 skip_pager = FALSE;
00169
00170 max_mode = MaximizeRestore;
00171 maxmode_restore = MaximizeRestore;
00172
00173 cmap = None;
00174
00175 frame_geometry = TQRect( 0, 0, 100, 100 );
00176 client_size = TQSize( 100, 100 );
00177 custom_opacity = false;
00178 rule_opacity_active = 0;;
00179 rule_opacity_inactive = 0;
00180
00181
00182 }
00183
00187 Client::~Client()
00188 {
00189 assert(!moveResizeMode);
00190 assert( client == None );
00191 assert( frame == None && wrapper == None );
00192 assert( decoration == NULL );
00193 assert( postpone_geometry_updates == 0 );
00194 assert( !check_active_modal );
00195 delete info;
00196 delete bridge;
00197 }
00198
00199
00200 void Client::deleteClient( Client* c, allowed_t )
00201 {
00202 delete c;
00203 }
00204
00208 void Client::releaseWindow( bool on_shutdown )
00209 {
00210 assert( !deleting );
00211 deleting = true;
00212 workspace()->discardUsedWindowRules( this, true );
00213 StackingUpdatesBlocker blocker( workspace());
00214 if (!custom_opacity) setOpacity(FALSE);
00215 if (moveResizeMode)
00216 leaveMoveResize();
00217 removeShadow();
00218 drawIntersectingShadows();
00219 finishWindowRules();
00220 ++postpone_geometry_updates;
00221
00222
00223 grabXServer();
00224 setMappingState( WithdrawnState );
00225 setModal( false );
00226 hidden = true;
00227 if( !on_shutdown )
00228 workspace()->clientHidden( this );
00229 XUnmapWindow( qt_xdisplay(), frameId());
00230 destroyDecoration();
00231 cleanGrouping();
00232 if( !on_shutdown )
00233 {
00234 workspace()->removeClient( this, Allowed );
00235
00236
00237 info->setDesktop( 0 );
00238 desk = 0;
00239 info->setState( 0, info->state());
00240 }
00241 XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
00242 XDeleteProperty( qt_xdisplay(), client, atoms->net_frame_extents );
00243 XDeleteProperty( qt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
00244 XReparentWindow( qt_xdisplay(), client, workspace()->rootWin(), x(), y());
00245 XRemoveFromSaveSet( qt_xdisplay(), client );
00246 XSelectInput( qt_xdisplay(), client, NoEventMask );
00247 if( on_shutdown )
00248 {
00249 XMapWindow( qt_xdisplay(), client );
00250
00251 }
00252 else
00253 {
00254
00255
00256 XUnmapWindow( qt_xdisplay(), client );
00257 }
00258 client = None;
00259 XDestroyWindow( qt_xdisplay(), wrapper );
00260 wrapper = None;
00261 XDestroyWindow( qt_xdisplay(), frame );
00262 frame = None;
00263 --postpone_geometry_updates;
00264 checkNonExistentClients();
00265 deleteClient( this, Allowed );
00266 ungrabXServer();
00267 }
00268
00269
00270
00271 void Client::destroyClient()
00272 {
00273 assert( !deleting );
00274 deleting = true;
00275 workspace()->discardUsedWindowRules( this, true );
00276 StackingUpdatesBlocker blocker( workspace());
00277 if (moveResizeMode)
00278 leaveMoveResize();
00279 removeShadow();
00280 drawIntersectingShadows();
00281 finishWindowRules();
00282 ++postpone_geometry_updates;
00283 setModal( false );
00284 hidden = true;
00285 workspace()->clientHidden( this );
00286 destroyDecoration();
00287 cleanGrouping();
00288 workspace()->removeClient( this, Allowed );
00289 client = None;
00290 XDestroyWindow( qt_xdisplay(), wrapper );
00291 wrapper = None;
00292 XDestroyWindow( qt_xdisplay(), frame );
00293 frame = None;
00294 --postpone_geometry_updates;
00295 checkNonExistentClients();
00296 deleteClient( this, Allowed );
00297 }
00298
00299 void Client::updateDecoration( bool check_workspace_pos, bool force )
00300 {
00301 if( !force && (( decoration == NULL && noBorder())
00302 || ( decoration != NULL && !noBorder())))
00303 return;
00304 bool do_show = false;
00305 postponeGeometryUpdates( true );
00306 if( force )
00307 destroyDecoration();
00308 if( !noBorder())
00309 {
00310 setMask( TQRegion());
00311 decoration = workspace()->createDecoration( bridge );
00312
00313 decoration->init();
00314 decoration->widget()->installEventFilter( this );
00315 XReparentWindow( qt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
00316 decoration->widget()->lower();
00317 decoration->borders( border_left, border_right, border_top, border_bottom );
00318 options->onlyDecoTranslucent ?
00319 setDecoHashProperty(border_top, border_right, border_bottom, border_left):
00320 unsetDecoHashProperty();
00321 int save_workarea_diff_x = workarea_diff_x;
00322 int save_workarea_diff_y = workarea_diff_y;
00323 move( calculateGravitation( false ));
00324 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00325 workarea_diff_x = save_workarea_diff_x;
00326 workarea_diff_y = save_workarea_diff_y;
00327 do_show = true;
00328 }
00329 else
00330 destroyDecoration();
00331 if( check_workspace_pos )
00332 checkWorkspacePosition();
00333 postponeGeometryUpdates( false );
00334 if( do_show )
00335 decoration->widget()->show();
00336 updateFrameExtents();
00337 updateOpacityCache();
00338 }
00339
00340 void Client::destroyDecoration()
00341 {
00342 if( decoration != NULL )
00343 {
00344 delete decoration;
00345 decoration = NULL;
00346 TQPoint grav = calculateGravitation( true );
00347 border_left = border_right = border_top = border_bottom = 0;
00348 setMask( TQRegion());
00349 int save_workarea_diff_x = workarea_diff_x;
00350 int save_workarea_diff_y = workarea_diff_y;
00351 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00352 move( grav );
00353 workarea_diff_x = save_workarea_diff_x;
00354 workarea_diff_y = save_workarea_diff_y;
00355 }
00356 }
00357
00358 void Client::checkBorderSizes()
00359 {
00360 if( decoration == NULL )
00361 return;
00362 int new_left, new_right, new_top, new_bottom;
00363 decoration->borders( new_left, new_right, new_top, new_bottom );
00364 if( new_left == border_left && new_right == border_right
00365 && new_top == border_top && new_bottom == border_bottom )
00366 return;
00367 GeometryUpdatesPostponer blocker( this );
00368 move( calculateGravitation( true ));
00369 border_left = new_left;
00370 border_right = new_right;
00371 border_top = new_top;
00372 border_bottom = new_bottom;
00373 if (border_left != new_left ||
00374 border_right != new_right ||
00375 border_top != new_top ||
00376 border_bottom != new_bottom)
00377 options->onlyDecoTranslucent ?
00378 setDecoHashProperty(new_top, new_right, new_bottom, new_left):
00379 unsetDecoHashProperty();
00380 move( calculateGravitation( false ));
00381 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
00382 checkWorkspacePosition();
00383 }
00384
00385 void Client::detectNoBorder()
00386 {
00387 if( Shape::hasShape( window()))
00388 {
00389 noborder = true;
00390 return;
00391 }
00392 switch( windowType())
00393 {
00394 case NET::Desktop :
00395 case NET::Dock :
00396 case NET::TopMenu :
00397 case NET::Splash :
00398 noborder = true;
00399 break;
00400 case NET::Unknown :
00401 case NET::Normal :
00402 case NET::Toolbar :
00403 case NET::Menu :
00404 case NET::Dialog :
00405 case NET::Utility :
00406 noborder = false;
00407 break;
00408 default:
00409 assert( false );
00410 }
00411
00412
00413
00414 if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
00415 noborder = true;
00416 }
00417
00418 void Client::detectShapable()
00419 {
00420 if( Shape::hasShape( window()))
00421 return;
00422 switch( windowType())
00423 {
00424 case NET::Desktop :
00425 case NET::Dock :
00426 case NET::TopMenu :
00427 case NET::Splash :
00428 break;
00429 case NET::Unknown :
00430 case NET::Normal :
00431 case NET::Toolbar :
00432 case NET::Menu :
00433 case NET::Dialog :
00434 case NET::Utility :
00435 setShapable(FALSE);
00436 break;
00437 default:
00438 assert( false );
00439 }
00440 }
00441
00442 void Client::updateFrameExtents()
00443 {
00444 NETStrut strut;
00445 strut.left = border_left;
00446 strut.right = border_right;
00447 strut.top = border_top;
00448 strut.bottom = border_bottom;
00449 info->setFrameExtents( strut );
00450 }
00451
00452
00453
00454
00455
00456
00457 void Client::resizeDecoration( const TQSize& s )
00458 {
00459 if( decoration == NULL )
00460 return;
00461 TQSize oldsize = decoration->widget()->size();
00462 decoration->resize( s );
00463 if( oldsize == s )
00464 {
00465 TQResizeEvent e( s, oldsize );
00466 TQApplication::sendEvent( decoration->widget(), &e );
00467 }
00468 if (!moveResizeMode && options->shadowEnabled(isActive()))
00469 {
00470
00471
00472 updateOpacityCache();
00473 }
00474 }
00475
00476 bool Client::noBorder() const
00477 {
00478 return noborder || isFullScreen() || user_noborder || motif_noborder;
00479 }
00480
00481 bool Client::userCanSetNoBorder() const
00482 {
00483 return !noborder && !isFullScreen() && !isShade();
00484 }
00485
00486 bool Client::isUserNoBorder() const
00487 {
00488 return user_noborder;
00489 }
00490
00491 void Client::setUserNoBorder( bool set )
00492 {
00493 if( !userCanSetNoBorder())
00494 return;
00495 set = rules()->checkNoBorder( set );
00496 if( user_noborder == set )
00497 return;
00498 user_noborder = set;
00499 updateDecoration( true, false );
00500 updateWindowRules();
00501 }
00502
00503 void Client::updateShape()
00504 {
00505
00506 if( shape() && !noBorder())
00507 {
00508 noborder = true;
00509 updateDecoration( true );
00510 }
00511 updateOpacityCache();
00512 if ( shape() )
00513 {
00514 XShapeCombineShape(qt_xdisplay(), frameId(), ShapeBounding,
00515 clientPos().x(), clientPos().y(),
00516 window(), ShapeBounding, ShapeSet);
00517 setShapable(TRUE);
00518 }
00519
00520
00521
00522 if( Shape::version() >= 0x11 )
00523 {
00524
00525
00526
00527
00528
00529
00530
00531
00532 static Window helper_window = None;
00533 if( helper_window == None )
00534 helper_window = XCreateSimpleWindow( qt_xdisplay(), qt_xrootwin(),
00535 0, 0, 1, 1, 0, 0, 0 );
00536 XResizeWindow( qt_xdisplay(), helper_window, width(), height());
00537 XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput, 0, 0,
00538 frameId(), ShapeBounding, ShapeSet );
00539 XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
00540 clientPos().x(), clientPos().y(),
00541 window(), ShapeBounding, ShapeSubtract );
00542 XShapeCombineShape( qt_xdisplay(), helper_window, ShapeInput,
00543 clientPos().x(), clientPos().y(),
00544 window(), ShapeInput, ShapeUnion );
00545 XShapeCombineShape( qt_xdisplay(), frameId(), ShapeInput, 0, 0,
00546 helper_window, ShapeInput, ShapeSet );
00547 }
00548 }
00549
00550 void Client::setMask( const TQRegion& reg, int mode )
00551 {
00552 _mask = reg;
00553 if( reg.isNull())
00554 XShapeCombineMask( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00555 None, ShapeSet );
00556 else if( mode == X::Unsorted )
00557 XShapeCombineRegion( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00558 reg.handle(), ShapeSet );
00559 else
00560 {
00561 TQMemArray< TQRect > rects = reg.rects();
00562 XRectangle* xrects = new XRectangle[ rects.count() ];
00563 for( unsigned int i = 0;
00564 i < rects.count();
00565 ++i )
00566 {
00567 xrects[ i ].x = rects[ i ].x();
00568 xrects[ i ].y = rects[ i ].y();
00569 xrects[ i ].width = rects[ i ].width();
00570 xrects[ i ].height = rects[ i ].height();
00571 }
00572 XShapeCombineRectangles( qt_xdisplay(), frameId(), ShapeBounding, 0, 0,
00573 xrects, rects.count(), ShapeSet, mode );
00574 delete[] xrects;
00575 }
00576 updateShape();
00577 }
00578
00579 TQRegion Client::mask() const
00580 {
00581 if( _mask.isEmpty())
00582 return TQRegion( 0, 0, width(), height());
00583 return _mask;
00584 }
00585
00586 void Client::setShapable(bool b)
00587 {
00588 long tmp = b?1:0;
00589 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
00590 }
00591
00592 void Client::hideClient( bool hide )
00593 {
00594 if( hidden == hide )
00595 return;
00596 hidden = hide;
00597 updateVisibility();
00598 }
00599
00600
00601
00602
00603 bool Client::isMinimizable() const
00604 {
00605 if( isSpecialWindow())
00606 return false;
00607 if( isTransient())
00608 {
00609 bool shown_mainwindow = false;
00610 ClientList mainclients = mainClients();
00611 for( ClientList::ConstIterator it = mainclients.begin();
00612 it != mainclients.end();
00613 ++it )
00614 {
00615 if( (*it)->isShown( true ))
00616 shown_mainwindow = true;
00617 }
00618 if( !shown_mainwindow )
00619 return true;
00620 }
00621
00622
00623
00624 if( transientFor() != NULL )
00625 return false;
00626 if( !wantsTabFocus())
00627 return false;
00628 return true;
00629 }
00630
00634 void Client::minimize( bool avoid_animation )
00635 {
00636 if ( !isMinimizable() || isMinimized())
00637 return;
00638
00639 Notify::raise( Notify::Minimize );
00640
00641
00642 if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
00643 animateMinimizeOrUnminimize( true );
00644
00645 minimized = true;
00646
00647 updateVisibility();
00648 updateAllowedActions();
00649 workspace()->updateMinimizedOfTransients( this );
00650 updateWindowRules();
00651 workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
00652 }
00653
00654 void Client::unminimize( bool avoid_animation )
00655 {
00656 if( !isMinimized())
00657 return;
00658
00659 Notify::raise( Notify::UnMinimize );
00660 minimized = false;
00661 if( isOnCurrentDesktop() && isShown( true ))
00662 {
00663 if( mainClients().isEmpty() && !avoid_animation )
00664 animateMinimizeOrUnminimize( FALSE );
00665 }
00666 updateVisibility();
00667 updateAllowedActions();
00668 workspace()->updateMinimizedOfTransients( this );
00669 updateWindowRules();
00670 }
00671
00672 extern bool blockAnimation;
00673
00674 void Client::animateMinimizeOrUnminimize( bool minimize )
00675 {
00676 if ( blockAnimation )
00677 return;
00678 if ( !options->animateMinimize )
00679 return;
00680
00681 if( decoration != NULL && decoration->animateMinimize( minimize ))
00682 return;
00683
00684
00685
00686
00687
00688 float lf,rf,tf,bf,step;
00689
00690 int speed = options->animateMinimizeSpeed;
00691 if ( speed > 10 )
00692 speed = 10;
00693 if ( speed < 0 )
00694 speed = 0;
00695
00696 step = 40. * (11 - speed );
00697
00698 NETRect r = info->iconGeometry();
00699 TQRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
00700 if ( !icongeom.isValid() )
00701 return;
00702
00703 TQPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
00704
00705 TQRect before, after;
00706 if ( minimize )
00707 {
00708 before = TQRect( x(), y(), width(), pm.height() );
00709 after = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00710 }
00711 else
00712 {
00713 before = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
00714 after = TQRect( x(), y(), width(), pm.height() );
00715 }
00716
00717 lf = (after.left() - before.left())/step;
00718 rf = (after.right() - before.right())/step;
00719 tf = (after.top() - before.top())/step;
00720 bf = (after.bottom() - before.bottom())/step;
00721
00722 grabXServer();
00723
00724 TQRect area = before;
00725 TQRect area2;
00726 TQPixmap pm2;
00727
00728 TQTime t;
00729 t.start();
00730 float diff;
00731
00732 TQPainter p ( workspace()->desktopWidget() );
00733 bool need_to_clear = FALSE;
00734 TQPixmap pm3;
00735 do
00736 {
00737 if (area2 != area)
00738 {
00739 pm = animationPixmap( area.width() );
00740 pm2 = TQPixmap::grabWindow( qt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
00741 p.drawPixmap( area.x(), area.y(), pm );
00742 if ( need_to_clear )
00743 {
00744 p.drawPixmap( area2.x(), area2.y(), pm3 );
00745 need_to_clear = FALSE;
00746 }
00747 area2 = area;
00748 }
00749 XFlush(qt_xdisplay());
00750 XSync( qt_xdisplay(), FALSE );
00751 diff = t.elapsed();
00752 if (diff > step)
00753 diff = step;
00754 area.setLeft(before.left() + int(diff*lf));
00755 area.setRight(before.right() + int(diff*rf));
00756 area.setTop(before.top() + int(diff*tf));
00757 area.setBottom(before.bottom() + int(diff*bf));
00758 if (area2 != area )
00759 {
00760 if ( area2.intersects( area ) )
00761 p.drawPixmap( area2.x(), area2.y(), pm2 );
00762 else
00763 {
00764 pm3 = pm2;
00765 need_to_clear = TRUE;
00766 }
00767 }
00768 } while ( t.elapsed() < step);
00769 if (area2 == area || need_to_clear )
00770 p.drawPixmap( area2.x(), area2.y(), pm2 );
00771
00772 p.end();
00773 ungrabXServer();
00774 }
00775
00776
00780 TQPixmap Client::animationPixmap( int w )
00781 {
00782 TQFont font = options->font(isActive());
00783 TQFontMetrics fm( font );
00784 TQPixmap pm( w, fm.lineSpacing() );
00785 pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
00786 TQPainter p( &pm );
00787 p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
00788 p.setFont(options->font(isActive()));
00789 p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
00790 return pm;
00791 }
00792
00793
00794 bool Client::isShadeable() const
00795 {
00796 return !isSpecialWindow() && !noBorder();
00797 }
00798
00799 void Client::setShade( ShadeMode mode )
00800 {
00801 if( !isShadeable())
00802 return;
00803 mode = rules()->checkShade( mode );
00804 if( shade_mode == mode )
00805 return;
00806 bool was_shade = isShade();
00807 ShadeMode was_shade_mode = shade_mode;
00808 shade_mode = mode;
00809 if( was_shade == isShade())
00810 {
00811 if( decoration != NULL )
00812 decoration->shadeChange();
00813 return;
00814 }
00815
00816 if( shade_mode == ShadeNormal )
00817 {
00818 if ( isShown( true ) && isOnCurrentDesktop())
00819 Notify::raise( Notify::ShadeUp );
00820 }
00821 else if( shade_mode == ShadeNone )
00822 {
00823 if( isShown( true ) && isOnCurrentDesktop())
00824 Notify::raise( Notify::ShadeDown );
00825 }
00826
00827 assert( decoration != NULL );
00828 GeometryUpdatesPostponer blocker( this );
00829
00830 decoration->borders( border_left, border_right, border_top, border_bottom );
00831
00832 int as = options->animateShade? 10 : 1;
00833
00834 if ( isShade())
00835 {
00836
00837 long _shade = 1;
00838 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00839
00840 int h = height();
00841 shade_geometry_change = true;
00842 TQSize s( sizeForClientSize( TQSize( clientSize())));
00843 s.setHeight( border_top + border_bottom );
00844 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
00845 XUnmapWindow( qt_xdisplay(), wrapper );
00846 XUnmapWindow( qt_xdisplay(), client );
00847 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
00848
00849
00850
00851
00852
00853 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00854 do
00855 {
00856 h -= step;
00857 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00858 resizeDecoration( TQSize( s.width(), h ));
00859 TQApplication::syncX();
00860 } while ( h > s.height() + step );
00861
00862
00863 plainResize( s );
00864 shade_geometry_change = false;
00865 if( isActive())
00866 {
00867 if( was_shade_mode == ShadeHover )
00868 workspace()->activateNextClient( this );
00869 else
00870 workspace()->focusToNull();
00871 }
00872
00873 _shade = 2;
00874 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
00875 }
00876 else
00877 {
00878 int h = height();
00879 shade_geometry_change = true;
00880 TQSize s( sizeForClientSize( clientSize()));
00881
00882
00883 int step = QMAX( 4, QABS( h - s.height() ) / as )+1;
00884 do
00885 {
00886 h += step;
00887 XResizeWindow( qt_xdisplay(), frameId(), s.width(), h );
00888 resizeDecoration( TQSize( s.width(), h ));
00889
00890
00891
00892 TQApplication::syncX();
00893 } while ( h < s.height() - step );
00894
00895
00896 shade_geometry_change = false;
00897 plainResize( s );
00898 if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
00899 setActive( TRUE );
00900 XMapWindow( qt_xdisplay(), wrapperId());
00901 XMapWindow( qt_xdisplay(), window());
00902 XDeleteProperty (qt_xdisplay(), client, atoms->net_wm_window_shade);
00903 if (options->shadowEnabled(false))
00904 {
00905 for (ClientList::ConstIterator it = transients().begin();
00906 it != transients().end(); ++it)
00907 {
00908 (*it)->removeShadow();
00909 (*it)->drawDelayedShadow();
00910 }
00911 }
00912
00913 if ( isActive() )
00914 workspace()->requestFocus( this );
00915 }
00916 checkMaximizeGeometry();
00917 info->setState( isShade() ? NET::Shaded : 0, NET::Shaded );
00918 info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
00919 updateVisibility();
00920 updateAllowedActions();
00921 workspace()->updateMinimizedOfTransients( this );
00922 decoration->shadeChange();
00923 updateWindowRules();
00924 }
00925
00926 void Client::shadeHover()
00927 {
00928 setShade( ShadeHover );
00929 cancelShadeHover();
00930 }
00931
00932 void Client::cancelShadeHover()
00933 {
00934 delete shadeHoverTimer;
00935 shadeHoverTimer = 0;
00936 }
00937
00938 void Client::toggleShade()
00939 {
00940
00941 setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
00942 }
00943
00944 void Client::updateVisibility()
00945 {
00946 if( deleting )
00947 return;
00948 bool show = true;
00949 if( hidden )
00950 {
00951 setMappingState( IconicState );
00952 info->setState( NET::Hidden, NET::Hidden );
00953 setSkipTaskbar( true, false );
00954 rawHide();
00955 show = false;
00956 }
00957 else
00958 {
00959 setSkipTaskbar( original_skip_taskbar, false );
00960 }
00961 if( minimized )
00962 {
00963 setMappingState( IconicState );
00964 info->setState( NET::Hidden, NET::Hidden );
00965 rawHide();
00966 show = false;
00967 }
00968 if( show )
00969 info->setState( 0, NET::Hidden );
00970 if( !isOnCurrentDesktop())
00971 {
00972 setMappingState( IconicState );
00973 rawHide();
00974 show = false;
00975 }
00976 if( show )
00977 {
00978 bool belongs_to_desktop = false;
00979 for( ClientList::ConstIterator it = group()->members().begin();
00980 it != group()->members().end();
00981 ++it )
00982 if( (*it)->isDesktop())
00983 {
00984 belongs_to_desktop = true;
00985 break;
00986 }
00987 if( !belongs_to_desktop && workspace()->showingDesktop())
00988 workspace()->resetShowingDesktop( true );
00989 if( isShade())
00990 setMappingState( IconicState );
00991 else
00992 setMappingState( NormalState );
00993 rawShow();
00994 }
00995 }
00996
00997 void Client::setShadowed(bool shadowed)
00998 {
00999 bool wasShadowed;
01000
01001 wasShadowed = isShadowed();
01002 shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
01003
01004 if (shadowMe) {
01005 if (!wasShadowed)
01006 drawShadow();
01007 }
01008 else {
01009 if (wasShadowed) {
01010 removeShadow();
01011
01012 if (!activeOpacityCache.isNull())
01013 activeOpacityCache.resize(0);
01014 if (!inactiveOpacityCache.isNull())
01015 inactiveOpacityCache.resize(0);
01016 }
01017 }
01018 }
01019
01020 void Client::updateOpacityCache()
01021 {
01022 if (!activeOpacityCache.isNull())
01023 activeOpacityCache.resize(0);
01024 if (!inactiveOpacityCache.isNull())
01025 inactiveOpacityCache.resize(0);
01026
01027 if (!moveResizeMode) {
01028
01029
01030 removeShadow();
01031 drawIntersectingShadows();
01032 if (options->shadowEnabled(isActive()))
01033 drawDelayedShadow();
01034 }
01035 }
01036
01041 void Client::drawIntersectingShadows() {
01042
01043 TQRegion region;
01044
01045 TQValueList<Client *> reshadowClients;
01046 TQValueListIterator<ShadowRegion> it;
01047 TQValueListIterator<Client *> it2;
01048
01049 if (!options->shadowEnabled(false))
01050
01051
01052 return;
01053
01054 region = shapeBoundingRegion;
01055
01056
01057
01058
01059 for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
01060 if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
01061 !(*it).region.intersect(region).isEmpty())
01062 reshadowClients.append((*it).client);
01063
01064
01065 for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
01066 ++it2) {
01067 (*it2)->removeShadow();
01068 (*it2)->drawDelayedShadow();
01069 }
01070 }
01071
01077 void Client::drawOverlappingShadows(bool waitForMe)
01078 {
01079 Client *aClient;
01080 TQRegion region;
01081 TQValueList<Client *> reshadowClients;
01082 ClientList stacking_order;
01083 ClientList::ConstIterator it;
01084 TQValueListIterator<ShadowRegion> it2;
01085 TQValueListIterator<Client *> it3;
01086
01087 if (!options->shadowEnabled(false))
01088
01089
01090 return;
01091
01092 region = shapeBoundingRegion;
01093
01094 stacking_order = workspace()->stackingOrder();
01095 for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
01096
01097 if ((*it) == this)
01098 break;
01099 }
01100 ++it;
01101 while (it != stacking_order.end()) {
01102 if ((*it)->windowType() == NET::Dock) {
01103
01104
01105 ++it;
01106 continue;
01107 }
01108
01109
01110
01111
01112
01113 for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
01114 if ((*it2).client == (*it)) {
01115 if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
01116 && !(*it2).region.intersect(region).isEmpty())
01117 reshadowClients.append((*it2).client);
01118 }
01119 }
01120 ++it;
01121 }
01122
01123
01124 for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
01125 (*it3)->removeShadow();
01126 if (it3 == reshadowClients.begin()) {
01127 if (waitForMe)
01128 (*it3)->drawShadowAfter(this);
01129 else
01130 (*it3)->drawDelayedShadow();
01131 }
01132 else {
01133 --it3;
01134 aClient = (*it3);
01135 ++it3;
01136 (*it3)->drawShadowAfter(aClient);
01137 }
01138 }
01139 }
01140
01145 void Client::drawDelayedShadow()
01146 {
01147 shadowDelayTimer->stop();
01148 shadowDelayTimer->start(SHADOW_DELAY, true);
01149 }
01150
01154 void Client::drawShadowAfter(Client *after)
01155 {
01156 shadowAfterClient = after;
01157 connect(after, TQT_SIGNAL(shadowDrawn()), TQT_SLOT(drawShadow()));
01158 }
01159
01163 void Client::drawShadow()
01164 {
01165 Window shadows[2];
01166 XRectangle *shapes;
01167 int i, count, ordering;
01168
01169
01170 if (shadowAfterClient != NULL) {
01171 disconnect(shadowAfterClient, TQT_SIGNAL(shadowDrawn()), this, TQT_SLOT(drawShadow()));
01172 shadowAfterClient = NULL;
01173 }
01174
01175 if (!isOnCurrentDesktop())
01176 return;
01177
01178
01179
01180
01181
01182 shapes = XShapeGetRectangles(qt_xdisplay(), frameId(), ShapeBounding,
01183 &count, &ordering);
01184 if (!shapes)
01185
01186 shapeBoundingRegion = TQRegion(x(), y(), width(), height());
01187 else {
01188 shapeBoundingRegion = TQRegion();
01189 for (i = 0; i < count; i++) {
01190
01191 TQRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width,
01192 shapes[i].height);
01193 shapeBoundingRegion += shapeRectangle;
01194 }
01195 if (isShade())
01196
01197
01198
01199 shapeBoundingRegion &= TQRegion(0, 0, width(), height());
01200 shapeBoundingRegion.translate(x(), y());
01201 }
01202
01203 if (!isShadowed() || hidden || isMinimized() ||
01204 maximizeMode() == MaximizeFull ||
01205 !options->shadowWindowType(windowType())) {
01206 XFree(shapes);
01207
01208
01209
01210 emit shadowDrawn();
01211
01212 return;
01213 }
01214
01215 removeShadow();
01216
01217 TQMemArray<QRgb> pixelData;
01218 TQPixmap shadowPixmap;
01219 TQRect shadow;
01220 TQRegion exposedRegion;
01221 ShadowRegion shadowRegion;
01222 int thickness, xOffset, yOffset;
01223
01224 thickness = options->shadowThickness(isActive());
01225 xOffset = options->shadowXOffset(isActive());
01226 yOffset = options->shadowYOffset(isActive());
01227 opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
01228
01229 shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
01230 width() + thickness * 2, height() + thickness * 2);
01231 shadowPixmap.resize(shadow.size());
01232
01233
01234 shadowWidget = new TQWidget(0, 0, WStyle_Customize | WX11BypassWM);
01235 shadowWidget->setGeometry(shadow);
01236 XSelectInput(qt_xdisplay(), shadowWidget->winId(),
01237 ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
01238 shadowWidget->installEventFilter(this);
01239
01240 if (!shapes) {
01241
01242 exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
01243 shadow.y(), shadow.width(), shadow.height(), thickness,
01244 xOffset, yOffset);
01245 shadowRegion.region = exposedRegion;
01246 shadowRegion.client = this;
01247 shadowRegions.append(shadowRegion);
01248
01249 if (opacityCache->isNull())
01250 imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
01251 exposedRegion, thickness,
01252 options->shadowOpacity(isActive()));
01253 else
01254 imposeCachedShadow(shadowPixmap, exposedRegion);
01255 }
01256 else {
01257 TQMemArray<TQRect> exposedRects;
01258 TQMemArray<TQRect>::Iterator it, itEnd;
01259 XRectangle *shadowShapes;
01260
01261 exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
01262 shadow.y(), shadow.width(), shadow.height(), thickness,
01263 xOffset, yOffset);
01264 shadowRegion.region = exposedRegion;
01265 shadowRegion.client = this;
01266 shadowRegions.append(shadowRegion);
01267
01268
01269 exposedRects = exposedRegion.rects();
01270 i = 0;
01271 itEnd = exposedRects.end();
01272 shadowShapes = new XRectangle[exposedRects.count()];
01273 for (it = exposedRects.begin(); it != itEnd; ++it) {
01274 shadowShapes[i].x = (*it).x();
01275 shadowShapes[i].y = (*it).y();
01276 shadowShapes[i].width = (*it).width();
01277 shadowShapes[i].height = (*it).height();
01278 i++;
01279 }
01280 XShapeCombineRectangles(qt_xdisplay(), shadowWidget->winId(),
01281 ShapeBounding, -x() + thickness - xOffset,
01282 -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
01283 Unsorted);
01284 delete [] shadowShapes;
01285
01286 if (opacityCache->isNull())
01287 imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
01288 exposedRegion, thickness,
01289 options->shadowOpacity(isActive()));
01290 else
01291 imposeCachedShadow(shadowPixmap, exposedRegion);
01292 }
01293
01294 XFree(shapes);
01295
01296
01297
01298 shadowWidget->setErasePixmap(shadowPixmap);
01299
01300
01301
01302 if (isDock()) {
01303 ClientList stacking_order = workspace()->stackingOrder();
01304 for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
01305 if ((*it)->isDesktop())
01306 {
01307 ++it;
01308 shadows[0] = (*it)->frameId();
01309 shadows[1] = shadowWidget->winId();
01310 }
01311 }
01312 else {
01313 shadows[0] = frameId();
01314 if (shadowWidget != NULL)
01315 shadows[1] = shadowWidget->winId();
01316 }
01317
01318 XRestackWindows(qt_xdisplay(), shadows, 2);
01319
01320
01321
01322 XMapWindow(qt_xdisplay(), shadowWidget->winId());
01323
01324
01325 emit shadowDrawn();
01326 }
01327
01331 void Client::removeShadow()
01332 {
01333 TQValueList<ShadowRegion>::Iterator it;
01334
01335 shadowDelayTimer->stop();
01336
01337 if (shadowWidget != NULL) {
01338 for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
01339 if ((*it).client == this) {
01340 shadowRegions.remove(it);
01341 break;
01342 }
01343 delete shadowWidget;
01344 shadowWidget = NULL;
01345 }
01346 }
01347
01352 TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
01353 int h, int thickness, int xOffset, int yOffset)
01354 {
01355 TQRegion exposedRegion;
01356
01357 exposedRegion = TQRegion(x, y, w, h);
01358 exposedRegion -= occludedRegion;
01359
01360 if (thickness > 0) {
01361
01362
01363 TQMemArray<TQRect> occludedRects;
01364 TQMemArray<TQRect>::Iterator it, itEnd;
01365 TQRegion shadowRegion;
01366
01367 occludedRects = occludedRegion.rects();
01368 itEnd = occludedRects.end();
01369 for (it = occludedRects.begin(); it != itEnd; ++it) {
01370
01371
01372
01373 it->setTop(it->top() - thickness + yOffset);
01374 it->setLeft(it->left() - thickness + xOffset);
01375 it->setRight(it->right() + thickness + xOffset);
01376 it->setBottom(it->bottom() + thickness + yOffset);
01377 shadowRegion += TQRegion(*it);
01378 }
01379 exposedRegion -= exposedRegion - shadowRegion;
01380 }
01381
01382 return exposedRegion;
01383 }
01384
01388 void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
01389 {
01390 QRgb pixel;
01391 double opacity;
01392 int red, green, blue, pixelRed, pixelGreen, pixelBlue;
01393 int subW, subH, w, h, x, y, zeroX, zeroY;
01394 TQImage image;
01395 TQMemArray<TQRect>::Iterator it, itEnd;
01396 TQMemArray<TQRect> rectangles;
01397 TQPixmap subPixmap;
01398 Window rootWindow;
01399 int thickness, windowX, windowY, xOffset, yOffset;
01400
01401 rectangles = exposed.rects();
01402 rootWindow = qt_xrootwin();
01403 thickness = options->shadowThickness(isActive());
01404 windowX = this->x();
01405 windowY = this->y();
01406 xOffset = options->shadowXOffset(isActive());
01407 yOffset = options->shadowYOffset(isActive());
01408 options->shadowColour(isActive()).rgb(&red, &green, &blue);
01409 w = pixmap.width();
01410 h = pixmap.height();
01411
01412 itEnd = rectangles.end();
01413 for (it = rectangles.begin(); it != itEnd; ++it) {
01414 subW = (*it).width();
01415 subH = (*it).height();
01416 subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
01417 subW, subH);
01418 zeroX = (*it).x() - windowX + thickness - xOffset;
01419 zeroY = (*it).y() - windowY + thickness - yOffset;
01420 image = subPixmap.convertToImage();
01421
01422 for (x = 0; x < subW; x++) {
01423 for (y = 0; y < subH; y++) {
01424 opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
01425 pixel = image.pixel(x, y);
01426 pixelRed = qRed(pixel);
01427 pixelGreen = qGreen(pixel);
01428 pixelBlue = qBlue(pixel);
01429 image.setPixel(x, y,
01430 qRgb((int)(pixelRed + (red - pixelRed) * opacity),
01431 (int)(pixelGreen + (green - pixelGreen) * opacity),
01432 (int)(pixelBlue + (blue - pixelBlue) * opacity)));
01433 }
01434 }
01435
01436 subPixmap.convertFromImage(image);
01437 bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
01438 }
01439 }
01440
01444 void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
01445 TQRegion exposed, int thickness, double maxOpacity)
01446 {
01447 register int distance, intersectCount, i, j, x, y;
01448 QRgb pixel;
01449 double decay, factor, opacity;
01450 int red, green, blue, pixelRed, pixelGreen, pixelBlue;
01451 int halfMaxIntersects, lineIntersects, maxIntersects, maxY;
01452 int irBottom, irLeft, irRight, irTop, yIncrement;
01453 int subW, subH, w, h, zeroX, zeroY;
01454 TQImage image;
01455 TQMemArray<TQRect>::Iterator it, itEnd;
01456 TQMemArray<TQRect> rectangles;
01457 TQPixmap subPixmap;
01458 Window rootWindow;
01459 int windowX, windowY, xOffset, yOffset;
01460
01461 rectangles = exposed.rects();
01462 rootWindow = qt_xrootwin();
01463 windowX = this->x();
01464 windowY = this->y();
01465 xOffset = options->shadowXOffset(isActive());
01466 yOffset = options->shadowYOffset(isActive());
01467 options->shadowColour(isActive()).rgb(&red, &green, &blue);
01468 maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
01469 halfMaxIntersects = maxIntersects / 2;
01470 lineIntersects = thickness * 2 + 1;
01471 factor = maxIntersects / maxOpacity;
01472 decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
01473 w = pixmap.width();
01474 h = pixmap.height();
01475 xOffset = options->shadowXOffset(isActive());
01476 yOffset = options->shadowYOffset(isActive());
01477
01478 opacityCache->resize(0);
01479 opacityCache->resize(w * h);
01480 occluded.translate(-windowX + thickness, -windowY + thickness);
01481
01482 itEnd = rectangles.end();
01483 for (it = rectangles.begin(); it != itEnd; ++it) {
01484 subW = (*it).width();
01485 subH = (*it).height();
01486 subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
01487 subW, subH);
01488 maxY = subH;
01489 zeroX = (*it).x() - windowX + thickness - xOffset;
01490 zeroY = (*it).y() - windowY + thickness - yOffset;
01491 image = subPixmap.convertToImage();
01492
01493 intersectCount = 0;
01494 opacity = -1;
01495 y = 0;
01496 yIncrement = 1;
01497 for (x = 0; x < subW; x++) {
01498 irLeft = zeroX + x - thickness;
01499 irRight = zeroX + x + thickness;
01500
01501 while (y != maxY) {
01502
01503
01504 irTop = zeroY + y - thickness * yIncrement;
01505
01506
01507 irBottom = zeroY + y + thickness * yIncrement;
01508
01509 if (opacity == -1) {
01510
01511
01512 intersectCount = 0;
01513
01514 for (j = irTop; j != irBottom; j += yIncrement) {
01515
01516
01517 for (i = irLeft; i <= irRight; i++) {
01518 if (occluded.contains(TQPoint(i, j)))
01519 intersectCount++;
01520 }
01521 }
01522 }
01523 else {
01524 if (intersectCount < 0)
01525 intersectCount = 0;
01526
01527 for (i = irLeft; i <= irRight; i++) {
01528 if (occluded.contains(TQPoint(i, irBottom)))
01529 intersectCount++;
01530 }
01531 }
01532
01533 distance = maxIntersects - intersectCount;
01534 opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
01535
01536 (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
01537 pixel = image.pixel(x, y);
01538 pixelRed = qRed(pixel);
01539 pixelGreen = qGreen(pixel);
01540 pixelBlue = qBlue(pixel);
01541 image.setPixel(x, y,
01542 qRgb((int)(pixelRed + (red - pixelRed) * opacity),
01543 (int)(pixelGreen + (green - pixelGreen) * opacity),
01544 (int)(pixelBlue + (blue - pixelBlue) * opacity)));
01545
01546 for (i = irLeft; i <= irRight; i++) {
01547 if (occluded.contains(TQPoint(i, irTop)))
01548 intersectCount--;
01549 }
01550
01551 y += yIncrement;
01552 }
01553 y -= yIncrement;
01554
01555 irTop += yIncrement;
01556 for (j = irTop; j != irBottom; j += yIncrement) {
01557 if (occluded.contains(TQPoint(irLeft, j)))
01558 intersectCount--;
01559 }
01560 irRight++;
01561 for (j = irTop; j != irBottom; j += yIncrement) {
01562 if (occluded.contains(TQPoint(irRight, j)))
01563 intersectCount++;
01564 }
01565
01566 yIncrement *= -1;
01567 if (yIncrement < 0)
01568
01569 maxY = -1;
01570 else
01571
01572 maxY = subH;
01573 }
01574
01575 subPixmap.convertFromImage(image);
01576 bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
01577 }
01578 }
01579
01584 void Client::setMappingState(int s)
01585 {
01586 assert( client != None );
01587 assert( !deleting || s == WithdrawnState );
01588 if( mapping_state == s )
01589 return;
01590 bool was_unmanaged = ( mapping_state == WithdrawnState );
01591 mapping_state = s;
01592 if( mapping_state == WithdrawnState )
01593 {
01594 XDeleteProperty( qt_xdisplay(), window(), qt_wm_state );
01595 return;
01596 }
01597 assert( s == NormalState || s == IconicState );
01598
01599 unsigned long data[2];
01600 data[0] = (unsigned long) s;
01601 data[1] = (unsigned long) None;
01602 XChangeProperty(qt_xdisplay(), window(), qt_wm_state, qt_wm_state, 32,
01603 PropModeReplace, (unsigned char *)data, 2);
01604
01605 if( was_unmanaged )
01606 postponeGeometryUpdates( false );
01607 }
01608
01613 void Client::rawShow()
01614 {
01615 if( decoration != NULL )
01616 decoration->widget()->show();
01617 XMapWindow( qt_xdisplay(), frame );
01618 if( !isShade())
01619 {
01620 XMapWindow( qt_xdisplay(), wrapper );
01621 XMapWindow( qt_xdisplay(), client );
01622 }
01623 if (options->shadowEnabled(isActive()))
01624 drawDelayedShadow();
01625 }
01626
01632 void Client::rawHide()
01633 {
01634
01635
01636
01637
01638
01639
01640 removeShadow();
01641 drawIntersectingShadows();
01642 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask );
01643 XUnmapWindow( qt_xdisplay(), frame );
01644 XUnmapWindow( qt_xdisplay(), wrapper );
01645 XUnmapWindow( qt_xdisplay(), client );
01646 XSelectInput( qt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
01647 if( decoration != NULL )
01648 decoration->widget()->hide();
01649 workspace()->clientHidden( this );
01650 }
01651
01652 void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
01653 {
01654 XEvent ev;
01655 long mask;
01656
01657 memset(&ev, 0, sizeof(ev));
01658 ev.xclient.type = ClientMessage;
01659 ev.xclient.window = w;
01660 ev.xclient.message_type = a;
01661 ev.xclient.format = 32;
01662 ev.xclient.data.l[0] = protocol;
01663 ev.xclient.data.l[1] = qt_x_time;
01664 ev.xclient.data.l[2] = data1;
01665 ev.xclient.data.l[3] = data2;
01666 ev.xclient.data.l[4] = data3;
01667 mask = 0L;
01668 if (w == qt_xrootwin())
01669 mask = SubstructureRedirectMask;
01670 XSendEvent(qt_xdisplay(), w, False, mask, &ev);
01671 }
01672
01673
01674
01675
01676 bool Client::isCloseable() const
01677 {
01678 return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
01679 }
01680
01685 void Client::closeWindow()
01686 {
01687 if( !isCloseable())
01688 return;
01689
01690 updateUserTime();
01691 if ( Pdeletewindow )
01692 {
01693 Notify::raise( Notify::Close );
01694 sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
01695 pingWindow();
01696 }
01697 else
01698 {
01699
01700
01701 killWindow();
01702 }
01703 }
01704
01705
01709 void Client::killWindow()
01710 {
01711 kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
01712
01713
01714 Notify::raise( Notify::Close );
01715
01716 if( isDialog())
01717 Notify::raise( Notify::TransDelete );
01718 if( isNormalWindow())
01719 Notify::raise( Notify::Delete );
01720 killProcess( false );
01721
01722 XKillClient(qt_xdisplay(), window() );
01723 destroyClient();
01724 }
01725
01726
01727
01728
01729 void Client::pingWindow()
01730 {
01731 if( !Pping )
01732 return;
01733 if( options->killPingTimeout == 0 )
01734 return;
01735 if( ping_timer != NULL )
01736 return;
01737 ping_timer = new TQTimer( this );
01738 connect( ping_timer, TQT_SIGNAL( timeout()), TQT_SLOT( pingTimeout()));
01739 ping_timer->start( options->killPingTimeout, true );
01740 ping_timestamp = qt_x_time;
01741 workspace()->sendPingToWindow( window(), ping_timestamp );
01742 }
01743
01744 void Client::gotPing( Time timestamp )
01745 {
01746
01747 if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
01748 return;
01749 delete ping_timer;
01750 ping_timer = NULL;
01751 if( process_killer != NULL )
01752 {
01753 process_killer->kill();
01754 delete process_killer;
01755 process_killer = NULL;
01756 }
01757 }
01758
01759 void Client::pingTimeout()
01760 {
01761 kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
01762 delete ping_timer;
01763 ping_timer = NULL;
01764 killProcess( true, ping_timestamp );
01765 }
01766
01767 void Client::killProcess( bool ask, Time timestamp )
01768 {
01769 if( process_killer != NULL )
01770 return;
01771 Q_ASSERT( !ask || timestamp != CurrentTime );
01772 TQCString machine = wmClientMachine( true );
01773 pid_t pid = info->pid();
01774 if( pid <= 0 || machine.isEmpty())
01775 return;
01776 kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
01777 if( !ask )
01778 {
01779 if( machine != "localhost" )
01780 {
01781 KProcess proc;
01782 proc << "xon" << machine << "kill" << pid;
01783 proc.start( KProcess::DontCare );
01784 }
01785 else
01786 ::kill( pid, SIGTERM );
01787 }
01788 else
01789 {
01790 process_killer = new KProcess( this );
01791 *process_killer << KStandardDirs::findExe( "kwin_killer_helper" )
01792 << "--pid" << TQCString().setNum( pid ) << "--hostname" << machine
01793 << "--windowname" << caption().utf8()
01794 << "--applicationname" << resourceClass()
01795 << "--wid" << TQCString().setNum( window())
01796 << "--timestamp" << TQCString().setNum( timestamp );
01797 connect( process_killer, TQT_SIGNAL( processExited( KProcess* )),
01798 TQT_SLOT( processKillerExited()));
01799 if( !process_killer->start( KProcess::NotifyOnExit ))
01800 {
01801 delete process_killer;
01802 process_killer = NULL;
01803 return;
01804 }
01805 }
01806 }
01807
01808 void Client::processKillerExited()
01809 {
01810 kdDebug( 1212 ) << "Killer exited" << endl;
01811 delete process_killer;
01812 process_killer = NULL;
01813 }
01814
01815 void Client::setSkipTaskbar( bool b, bool from_outside )
01816 {
01817 int was_wants_tab_focus = wantsTabFocus();
01818 if( from_outside )
01819 {
01820 b = rules()->checkSkipTaskbar( b );
01821 original_skip_taskbar = b;
01822 }
01823 if ( b == skipTaskbar() )
01824 return;
01825 skip_taskbar = b;
01826 info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
01827 updateWindowRules();
01828 if( was_wants_tab_focus != wantsTabFocus())
01829 workspace()->updateFocusChains( this,
01830 isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
01831 }
01832
01833 void Client::setSkipPager( bool b )
01834 {
01835 b = rules()->checkSkipPager( b );
01836 if ( b == skipPager() )
01837 return;
01838 skip_pager = b;
01839 info->setState( b?NET::SkipPager:0, NET::SkipPager );
01840 updateWindowRules();
01841 }
01842
01843 void Client::setModal( bool m )
01844 {
01845 if( modal == m )
01846 return;
01847 modal = m;
01848 if( !modal )
01849 return;
01850
01851
01852 }
01853
01854 void Client::setDesktop( int desktop )
01855 {
01856 if( desktop != NET::OnAllDesktops )
01857 desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
01858 desktop = rules()->checkDesktop( desktop );
01859 if( desk == desktop )
01860 return;
01861 int was_desk = desk;
01862 desk = desktop;
01863 info->setDesktop( desktop );
01864 if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
01865 {
01866 if ( isShown( true ))
01867 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
01868 workspace()->updateOnAllDesktopsOfTransients( this );
01869 }
01870 if( decoration != NULL )
01871 decoration->desktopChange();
01872 workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
01873 updateVisibility();
01874 updateWindowRules();
01875 }
01876
01877 void Client::setOnAllDesktops( bool b )
01878 {
01879 if(( b && isOnAllDesktops())
01880 || ( !b && !isOnAllDesktops()))
01881 return;
01882 if( b )
01883 setDesktop( NET::OnAllDesktops );
01884 else
01885 setDesktop( workspace()->currentDesktop());
01886 }
01887
01888 bool Client::isOnCurrentDesktop() const
01889 {
01890 return isOnDesktop( workspace()->currentDesktop());
01891 }
01892
01893 int Client::screen() const
01894 {
01895 if( !options->xineramaEnabled )
01896 return 0;
01897 return workspace()->screenNumber( geometry().center());
01898 }
01899
01900 bool Client::isOnScreen( int screen ) const
01901 {
01902 if( !options->xineramaEnabled )
01903 return screen == 0;
01904 return workspace()->screenGeometry( screen ).intersects( geometry());
01905 }
01906
01907
01908 void Client::takeActivity( int flags, bool handled, allowed_t )
01909 {
01910 if( !handled || !Ptakeactivity )
01911 {
01912 if( flags & ActivityFocus )
01913 takeFocus( Allowed );
01914 if( flags & ActivityRaise )
01915 workspace()->raiseClient( this );
01916 return;
01917 }
01918
01919 #ifndef NDEBUG
01920 static Time previous_activity_timestamp;
01921 static Client* previous_client;
01922 if( previous_activity_timestamp == qt_x_time && previous_client != this )
01923 {
01924 kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
01925 kdDebug( 1212 ) << kdBacktrace() << endl;
01926 }
01927 previous_activity_timestamp = qt_x_time;
01928 previous_client = this;
01929 #endif
01930 workspace()->sendTakeActivity( this, qt_x_time, flags );
01931 }
01932
01933
01934 void Client::takeFocus( allowed_t )
01935 {
01936 #ifndef NDEBUG
01937 static Time previous_focus_timestamp;
01938 static Client* previous_client;
01939 if( previous_focus_timestamp == qt_x_time && previous_client != this )
01940 {
01941 kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
01942 kdDebug( 1212 ) << kdBacktrace() << endl;
01943 }
01944 previous_focus_timestamp = qt_x_time;
01945 previous_client = this;
01946 #endif
01947 if ( rules()->checkAcceptFocus( input ))
01948 {
01949 XSetInputFocus( qt_xdisplay(), window(), RevertToPointerRoot, qt_x_time );
01950 }
01951 if ( Ptakefocus )
01952 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
01953 workspace()->setShouldGetFocus( this );
01954 }
01955
01963 bool Client::providesContextHelp() const
01964 {
01965 return Pcontexthelp;
01966 }
01967
01968
01975 void Client::showContextHelp()
01976 {
01977 if ( Pcontexthelp )
01978 {
01979 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
01980 TQWhatsThis::enterWhatsThisMode();
01981 }
01982 }
01983
01984
01989 void Client::fetchName()
01990 {
01991 setCaption( readName());
01992 }
01993
01994 TQString Client::readName() const
01995 {
01996 if ( info->name() && info->name()[ 0 ] != '\0' )
01997 return TQString::fromUtf8( info->name() );
01998 else
01999 return KWin::readNameProperty( window(), XA_WM_NAME );
02000 }
02001
02002 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
02003
02004 void Client::setCaption( const TQString& s, bool force )
02005 {
02006 if ( s != cap_normal || force )
02007 {
02008 bool reset_name = force;
02009 for( unsigned int i = 0;
02010 i < s.length();
02011 ++i )
02012 if( !s[ i ].isPrint())
02013 s[ i ] = ' ';
02014 cap_normal = s;
02015 bool was_suffix = ( !cap_suffix.isEmpty());
02016 TQString machine_suffix;
02017 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
02018 machine_suffix = " <@" + wmClientMachine( true ) + ">";
02019 TQString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
02020 cap_suffix = machine_suffix + shortcut_suffix;
02021 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
02022 {
02023 int i = 2;
02024 do
02025 {
02026 cap_suffix = machine_suffix + " <" + TQString::number(i) + ">" + shortcut_suffix;
02027 i++;
02028 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
02029 info->setVisibleName( caption().utf8() );
02030 reset_name = false;
02031 }
02032 if(( was_suffix && cap_suffix.isEmpty()
02033 || reset_name ))
02034 {
02035 info->setVisibleName( "" );
02036 info->setVisibleIconName( "" );
02037 }
02038 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty())
02039 info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
02040
02041 if( isManaged() && decoration != NULL )
02042 decoration->captionChange();
02043 }
02044 }
02045
02046 void Client::updateCaption()
02047 {
02048 setCaption( cap_normal, true );
02049 }
02050
02051 void Client::fetchIconicName()
02052 {
02053 TQString s;
02054 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
02055 s = TQString::fromUtf8( info->iconName() );
02056 else
02057 s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
02058 if ( s != cap_iconic )
02059 {
02060 bool was_set = !cap_iconic.isEmpty();
02061 cap_iconic = s;
02062 if( !cap_suffix.isEmpty())
02063 {
02064 if( !cap_iconic.isEmpty())
02065 info->setVisibleIconName( ( s + cap_suffix ).utf8() );
02066 else if( was_set )
02067 info->setVisibleIconName( "" );
02068 }
02069 }
02070 }
02071
02074 TQString Client::caption( bool full ) const
02075 {
02076 return full ? cap_normal + cap_suffix : cap_normal;
02077 }
02078
02079 void Client::getWMHints()
02080 {
02081 XWMHints *hints = XGetWMHints(qt_xdisplay(), window() );
02082 input = true;
02083 window_group = None;
02084 urgency = false;
02085 if ( hints )
02086 {
02087 if( hints->flags & InputHint )
02088 input = hints->input;
02089 if( hints->flags & WindowGroupHint )
02090 window_group = hints->window_group;
02091 urgency = ( hints->flags & UrgencyHint ) ? true : false;
02092 XFree( (char*)hints );
02093 }
02094 checkGroup();
02095 updateUrgency();
02096 updateAllowedActions();
02097 }
02098
02099 void Client::getMotifHints()
02100 {
02101 bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
02102 Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
02103 motif_noborder = mnoborder;
02104 if( !hasNETSupport())
02105 {
02106 motif_may_resize = mresize;
02107 motif_may_move = mmove;
02108 }
02109 else
02110 motif_may_resize = motif_may_move = true;
02111
02112
02113 motif_may_close = mclose;
02114 if( isManaged())
02115 updateDecoration( true );
02116 }
02117
02118 void Client::readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon )
02119 {
02120
02121 if( icon != NULL )
02122 *icon = KWin::icon( win, 32, 32, TRUE, KWin::NETWM | KWin::WMHints );
02123 if( miniicon != NULL )
02124 if( icon == NULL || !icon->isNull())
02125 *miniicon = KWin::icon( win, 16, 16, TRUE, KWin::NETWM | KWin::WMHints );
02126 else
02127 *miniicon = TQPixmap();
02128 }
02129
02130 void Client::getIcons()
02131 {
02132
02133 readIcons( window(), &icon_pix, &miniicon_pix );
02134 if( icon_pix.isNull())
02135 {
02136 icon_pix = group()->icon();
02137 miniicon_pix = group()->miniIcon();
02138 }
02139 if( icon_pix.isNull() && isTransient())
02140 {
02141 ClientList mainclients = mainClients();
02142 for( ClientList::ConstIterator it = mainclients.begin();
02143 it != mainclients.end() && icon_pix.isNull();
02144 ++it )
02145 {
02146 icon_pix = (*it)->icon();
02147 miniicon_pix = (*it)->miniIcon();
02148 }
02149 }
02150 if( icon_pix.isNull())
02151 {
02152 icon_pix = KWin::icon( window(), 32, 32, TRUE, KWin::ClassHint | KWin::XApp );
02153 miniicon_pix = KWin::icon( window(), 16, 16, TRUE, KWin::ClassHint | KWin::XApp );
02154 }
02155 if( isManaged() && decoration != NULL )
02156 decoration->iconChange();
02157 }
02158
02159 void Client::getWindowProtocols()
02160 {
02161 Atom *p;
02162 int i,n;
02163
02164 Pdeletewindow = 0;
02165 Ptakefocus = 0;
02166 Ptakeactivity = 0;
02167 Pcontexthelp = 0;
02168 Pping = 0;
02169
02170 if (XGetWMProtocols(qt_xdisplay(), window(), &p, &n))
02171 {
02172 for (i = 0; i < n; i++)
02173 if (p[i] == atoms->wm_delete_window)
02174 Pdeletewindow = 1;
02175 else if (p[i] == atoms->wm_take_focus)
02176 Ptakefocus = 1;
02177 else if (p[i] == atoms->net_wm_take_activity)
02178 Ptakeactivity = 1;
02179 else if (p[i] == atoms->net_wm_context_help)
02180 Pcontexthelp = 1;
02181 else if (p[i] == atoms->net_wm_ping)
02182 Pping = 1;
02183 if (n>0)
02184 XFree(p);
02185 }
02186 }
02187
02188 static int nullErrorHandler(Display *, XErrorEvent *)
02189 {
02190 return 0;
02191 }
02192
02196 TQCString Client::staticWindowRole(WId w)
02197 {
02198 return getStringProperty(w, qt_window_role).lower();
02199 }
02200
02204 TQCString Client::staticSessionId(WId w)
02205 {
02206 return getStringProperty(w, qt_sm_client_id);
02207 }
02208
02212 TQCString Client::staticWmCommand(WId w)
02213 {
02214 return getStringProperty(w, XA_WM_COMMAND, ' ');
02215 }
02216
02220 Window Client::staticWmClientLeader(WId w)
02221 {
02222 Atom type;
02223 int format, status;
02224 unsigned long nitems = 0;
02225 unsigned long extra = 0;
02226 unsigned char *data = 0;
02227 Window result = w;
02228 XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
02229 status = XGetWindowProperty( qt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
02230 FALSE, XA_WINDOW, &type, &format,
02231 &nitems, &extra, &data );
02232 XSetErrorHandler(oldHandler);
02233 if (status == Success )
02234 {
02235 if (data && nitems > 0)
02236 result = *((Window*) data);
02237 XFree(data);
02238 }
02239 return result;
02240 }
02241
02242
02243 void Client::getWmClientLeader()
02244 {
02245 wmClientLeaderWin = staticWmClientLeader(window());
02246 }
02247
02252 TQCString Client::sessionId()
02253 {
02254 TQCString result = staticSessionId(window());
02255 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
02256 result = staticSessionId(wmClientLeaderWin);
02257 return result;
02258 }
02259
02264 TQCString Client::wmCommand()
02265 {
02266 TQCString result = staticWmCommand(window());
02267 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
02268 result = staticWmCommand(wmClientLeaderWin);
02269 return result;
02270 }
02271
02272 void Client::getWmClientMachine()
02273 {
02274 client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
02275 if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
02276 client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
02277 if( client_machine.isEmpty())
02278 client_machine = "localhost";
02279 }
02280
02285 TQCString Client::wmClientMachine( bool use_localhost ) const
02286 {
02287 TQCString result = client_machine;
02288 if( use_localhost )
02289 {
02290 if( result != "localhost" && isLocalMachine( result ))
02291 result = "localhost";
02292 }
02293 return result;
02294 }
02295
02300 Window Client::wmClientLeader() const
02301 {
02302 if (wmClientLeaderWin)
02303 return wmClientLeaderWin;
02304 return window();
02305 }
02306
02307 bool Client::wantsTabFocus() const
02308 {
02309 return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
02310 }
02311
02312
02313 bool Client::wantsInput() const
02314 {
02315 return rules()->checkAcceptFocus( input || Ptakefocus );
02316 }
02317
02318 bool Client::isDesktop() const
02319 {
02320 return windowType() == NET::Desktop;
02321 }
02322
02323 bool Client::isDock() const
02324 {
02325 return windowType() == NET::Dock;
02326 }
02327
02328 bool Client::isTopMenu() const
02329 {
02330 return windowType() == NET::TopMenu;
02331 }
02332
02333
02334 bool Client::isMenu() const
02335 {
02336 return windowType() == NET::Menu && !isTopMenu();
02337 }
02338
02339 bool Client::isToolbar() const
02340 {
02341 return windowType() == NET::Toolbar;
02342 }
02343
02344 bool Client::isSplash() const
02345 {
02346 return windowType() == NET::Splash;
02347 }
02348
02349 bool Client::isUtility() const
02350 {
02351 return windowType() == NET::Utility;
02352 }
02353
02354 bool Client::isDialog() const
02355 {
02356 return windowType() == NET::Dialog;
02357 }
02358
02359 bool Client::isNormalWindow() const
02360 {
02361 return windowType() == NET::Normal;
02362 }
02363
02364 bool Client::isSpecialWindow() const
02365 {
02366 return isDesktop() || isDock() || isSplash() || isTopMenu()
02367 || isToolbar();
02368 }
02369
02370 NET::WindowType Client::windowType( bool direct, int supported_types ) const
02371 {
02372 NET::WindowType wt = info->windowType( supported_types );
02373 if( direct )
02374 return wt;
02375 NET::WindowType wt2 = rules()->checkType( wt );
02376 if( wt != wt2 )
02377 {
02378 wt = wt2;
02379 info->setWindowType( wt );
02380 }
02381
02382 if( wt == NET::Menu )
02383 {
02384
02385
02386
02387 if( x() == 0 && y() < 0 && y() > -10 && height() < 100
02388 && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
02389 wt = NET::TopMenu;
02390 }
02391
02392 const char* const oo_prefix = "openoffice.org";
02393
02394 if( qstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
02395 wt = NET::Normal;
02396 if( wt == NET::Unknown )
02397 wt = isTransient() ? NET::Dialog : NET::Normal;
02398 return wt;
02399 }
02400
02405 void Client::setCursor( Position m )
02406 {
02407 if( !isResizable() || isShade())
02408 {
02409 m = PositionCenter;
02410 }
02411 switch ( m )
02412 {
02413 case PositionTopLeft:
02414 case PositionBottomRight:
02415 setCursor( sizeFDiagCursor );
02416 break;
02417 case PositionBottomLeft:
02418 case PositionTopRight:
02419 setCursor( sizeBDiagCursor );
02420 break;
02421 case PositionTop:
02422 case PositionBottom:
02423 setCursor( sizeVerCursor );
02424 break;
02425 case PositionLeft:
02426 case PositionRight:
02427 setCursor( sizeHorCursor );
02428 break;
02429 default:
02430 if( buttonDown && isMovable())
02431 setCursor( sizeAllCursor );
02432 else
02433 setCursor( arrowCursor );
02434 break;
02435 }
02436 }
02437
02438
02439 void Client::setCursor( const TQCursor& c )
02440 {
02441 if( c.handle() == cursor.handle())
02442 return;
02443 cursor = c;
02444 if( decoration != NULL )
02445 decoration->widget()->setCursor( cursor );
02446 XDefineCursor( qt_xdisplay(), frameId(), cursor.handle());
02447 }
02448
02449 Client::Position Client::mousePosition( const TQPoint& p ) const
02450 {
02451 if( decoration != NULL )
02452 return decoration->mousePosition( p );
02453 return PositionCenter;
02454 }
02455
02456 void Client::updateAllowedActions( bool force )
02457 {
02458 if( !isManaged() && !force )
02459 return;
02460 unsigned long old_allowed_actions = allowed_actions;
02461 allowed_actions = 0;
02462 if( isMovable())
02463 allowed_actions |= NET::ActionMove;
02464 if( isResizable())
02465 allowed_actions |= NET::ActionResize;
02466 if( isMinimizable())
02467 allowed_actions |= NET::ActionMinimize;
02468 if( isShadeable())
02469 allowed_actions |= NET::ActionShade;
02470
02471 if( isMaximizable())
02472 allowed_actions |= NET::ActionMax;
02473 if( userCanSetFullScreen())
02474 allowed_actions |= NET::ActionFullScreen;
02475 allowed_actions |= NET::ActionChangeDesktop;
02476 if( isCloseable())
02477 allowed_actions |= NET::ActionClose;
02478 if( old_allowed_actions == allowed_actions )
02479 return;
02480
02481 info->setAllowedActions( allowed_actions );
02482
02483 }
02484
02485 void Client::autoRaise()
02486 {
02487 workspace()->raiseClient( this );
02488 cancelAutoRaise();
02489 }
02490
02491 void Client::cancelAutoRaise()
02492 {
02493 delete autoRaiseTimer;
02494 autoRaiseTimer = 0;
02495 }
02496
02497 void Client::setOpacity(bool translucent, uint opacity)
02498 {
02499 if (isDesktop())
02500 return;
02501
02502
02503 if (!translucent || opacity == 0xFFFFFFFF)
02504 {
02505 opacity_ = 0xFFFFFFFF;
02506 XDeleteProperty (qt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
02507 XDeleteProperty (qt_xdisplay(), window(), atoms->net_wm_window_opacity);
02508 }
02509 else{
02510 if(opacity == opacity_)
02511 return;
02512 opacity_ = opacity;
02513 long data = opacity;
02514 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02515 XChangeProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02516 }
02517 }
02518
02519 void Client::setShadowSize(uint shadowSize)
02520 {
02521
02522
02523 long data = shadowSize;
02524 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02525 }
02526
02527 void Client::updateOpacity()
02528
02529 {
02530 if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
02531 return;
02532 if (isActive())
02533 {
02534 if( ruleOpacityActive() )
02535 setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
02536 else
02537 setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02538 if (isBMP())
02539
02540 {
02541 ClientList tmpGroupMembers = group()->members();
02542 ClientList activeGroupMembers;
02543 activeGroupMembers.append(this);
02544 tmpGroupMembers.remove(this);
02545 ClientList::Iterator it = tmpGroupMembers.begin();
02546 while (it != tmpGroupMembers.end())
02547
02548 {
02549 if ((*it) != this && (*it)->isBMP())
02550
02551 {
02552
02553 if ((*it)->touches(this))
02554 {
02555
02556 if( ruleOpacityActive() )
02557 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
02558 else
02559 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02560
02561 (*it)->setShadowSize(options->activeWindowShadowSize);
02562 activeGroupMembers.append(*it);
02563 tmpGroupMembers.remove(it);
02564 it = tmpGroupMembers.begin();
02565 continue;
02566 }
02567 else
02568 {
02569 bool found = false;
02570 for( ClientList::ConstIterator it2 = activeGroupMembers.begin(); it2 != activeGroupMembers.end(); it2++ )
02571 {
02572 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
02573 {
02574
02575 if( ruleOpacityActive() )
02576 (*it)->setOpacity(rule_opacity_active < 0xFFFFFFFF, rule_opacity_active);
02577 else
02578 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02579 (*it)->setShadowSize(options->activeWindowShadowSize);
02580 activeGroupMembers.append(*it);
02581 tmpGroupMembers.remove(it);
02582 it = tmpGroupMembers.begin();
02583 found = true;
02584
02585 break;
02586 }
02587 }
02588 if (found) continue;
02589 }
02590 }
02591 it++;
02592 }
02593 }
02594 else if (isNormalWindow())
02595
02596 {
02597 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02598 if ((*it)->isDialog() || (*it)->isUtility())
02599 if( (*it)->ruleOpacityActive() )
02600 (*it)->setOpacity((*it)->ruleOpacityActive() < 0xFFFFFFFF, (*it)->ruleOpacityActive());
02601 else
02602 (*it)->setOpacity(options->translucentActiveWindows, options->activeWindowOpacity);
02603 }
02604 }
02605 else
02606 {
02607 if( ruleOpacityInactive() )
02608 setOpacity(rule_opacity_inactive < 0xFFFFFFFF, rule_opacity_inactive);
02609 else
02610 setOpacity(options->translucentInactiveWindows && !(keepAbove() && options->keepAboveAsActive),
02611 options->inactiveWindowOpacity);
02612
02613 if (isBMP())
02614
02615 {
02616 ClientList tmpGroupMembers = group()->members();
02617 ClientList inactiveGroupMembers;
02618 inactiveGroupMembers.append(this);
02619 tmpGroupMembers.remove(this);
02620 ClientList::Iterator it = tmpGroupMembers.begin();
02621 while ( it != tmpGroupMembers.end() )
02622
02623 {
02624 if ((*it) != this && (*it)->isBMP())
02625
02626 {
02627
02628 if ((*it)->touches(this))
02629 {
02630
02631 if( (*it)->ruleOpacityInactive() )
02632 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02633 else
02634 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02635 (*it)->setShadowSize(options->inactiveWindowShadowSize);
02636
02637 inactiveGroupMembers.append(*it);
02638 tmpGroupMembers.remove(it);
02639 it = tmpGroupMembers.begin();
02640 continue;
02641 }
02642 else
02643 {
02644 bool found = false;
02645 for( ClientList::ConstIterator it2 = inactiveGroupMembers.begin(); it2 != inactiveGroupMembers.end(); it2++ )
02646 {
02647 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
02648 {
02649
02650 if( (*it)->ruleOpacityInactive() )
02651 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02652 else
02653 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02654 (*it)->setShadowSize(options->inactiveWindowShadowSize);
02655
02656 inactiveGroupMembers.append(*it);
02657 tmpGroupMembers.remove(it);
02658 it = tmpGroupMembers.begin();
02659 found = true;
02660 break;
02661 }
02662 }
02663 if (found) continue;
02664 }
02665 }
02666 it++;
02667 }
02668 }
02669 else if (isNormalWindow())
02670 {
02671 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
02672 if ((*it)->isUtility())
02673 if( (*it)->ruleOpacityInactive() )
02674 (*it)->setOpacity((*it)->ruleOpacityInactive() < 0xFFFFFFFF, (*it)->ruleOpacityInactive());
02675 else
02676 (*it)->setOpacity(options->translucentInactiveWindows && !((*it)->keepAbove() && options->keepAboveAsActive), options->inactiveWindowOpacity);
02677 }
02678 }
02679 }
02680
02681 void Client::updateShadowSize()
02682
02683 {
02684 if (!(isNormalWindow() || isDialog() || isUtility() ))
02685 return;
02686 if (isActive())
02687 setShadowSize(options->activeWindowShadowSize);
02688 else
02689 setShadowSize(options->inactiveWindowShadowSize);
02690 }
02691
02692 uint Client::ruleOpacityInactive()
02693 {
02694 return rule_opacity_inactive;
02695 }
02696
02697 uint Client::ruleOpacityActive()
02698 {
02699 return rule_opacity_active;
02700 }
02701
02702 bool Client::getWindowOpacity()
02703 {
02704 unsigned char *data = 0;
02705 Atom actual;
02706 int format, result;
02707 unsigned long n, left;
02708 result = XGetWindowProperty(qt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, &data);
02709 if (result == Success && data != None && format == 32 )
02710 {
02711 opacity_ = *reinterpret_cast< long* >( data );
02712 custom_opacity = true;
02713
02714 XFree ((char*)data);
02715 return TRUE;
02716 }
02717 return FALSE;
02718 }
02719
02720 void Client::setCustomOpacityFlag(bool custom)
02721 {
02722 custom_opacity = custom;
02723 }
02724
02725 uint Client::opacity()
02726 {
02727 return opacity_;
02728 }
02729
02730 int Client::opacityPercentage()
02731 {
02732 return int(100*((double)opacity_/0xffffffff));
02733 }
02734
02735 bool Client::touches(const Client* c)
02736
02737 {
02738 if (y() == c->y() + c->height())
02739 return TRUE;
02740 if (y() + height() == c->y())
02741 return TRUE;
02742 if (x() == c->x() + c->width())
02743 return TRUE;
02744 if (x() + width() == c->x())
02745 return TRUE;
02746 return FALSE;
02747 }
02748
02749 void Client::setDecoHashProperty(uint topHeight, uint rightWidth, uint bottomHeight, uint leftWidth)
02750 {
02751 long data = (topHeight < 255 ? topHeight : 255) << 24 |
02752 (rightWidth < 255 ? rightWidth : 255) << 16 |
02753 (bottomHeight < 255 ? bottomHeight : 255) << 8 |
02754 (leftWidth < 255 ? leftWidth : 255);
02755 XChangeProperty(qt_xdisplay(), frameId(), atoms->net_wm_window_decohash, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
02756 }
02757
02758 void Client::unsetDecoHashProperty()
02759 {
02760 XDeleteProperty( qt_xdisplay(), frameId(), atoms->net_wm_window_decohash);
02761 }
02762
02763 #ifndef NDEBUG
02764 kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
02765 {
02766 if( cl == NULL )
02767 return stream << "\'NULL_CLIENT\'";
02768 return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
02769 }
02770 kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
02771 {
02772 stream << "LIST:(";
02773 bool first = true;
02774 for( ClientList::ConstIterator it = list.begin();
02775 it != list.end();
02776 ++it )
02777 {
02778 if( !first )
02779 stream << ":";
02780 first = false;
02781 stream << *it;
02782 }
02783 stream << ")";
02784 return stream;
02785 }
02786 kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
02787 {
02788 stream << "LIST:(";
02789 bool first = true;
02790 for( ConstClientList::ConstIterator it = list.begin();
02791 it != list.end();
02792 ++it )
02793 {
02794 if( !first )
02795 stream << ":";
02796 first = false;
02797 stream << *it;
02798 }
02799 stream << ")";
02800 return stream;
02801 }
02802 #endif
02803
02804 TQPixmap * kwin_get_menu_pix_hack()
02805 {
02806 static TQPixmap p;
02807 if ( p.isNull() )
02808 p = SmallIcon( "bx2" );
02809 return &p;
02810 }
02811
02812 }
02813
02814 #include "client.moc"