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