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