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