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