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