1 /********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *********************************************************************/
24 #include <QApplication>
29 #include <kstandarddirs.h>
31 #include <kwindowsystem.h>
32 #include <kiconloader.h>
38 #include "workspace.h"
40 #include "notifications.h"
46 #include <X11/extensions/shape.h>
50 #include <X11/extensions/sync.h>
53 // Put all externs before the namespace statement to allow the linker
54 // to resolve them properly
60 // - only by calling Workspace::createClient()
61 // - it creates a new client and calls manage() for it
63 // Destroying a client:
64 // - destroyClient() - only when the window itself has been destroyed
65 // - releaseWindow() - the window is kept, only the client itself is destroyed
68 * \class Client client.h
69 * \brief The Client class encapsulates a window decoration frame.
73 * This ctor is "dumb" - it only initializes data. All the real initialization
74 * is done in manage().
76 Client::Client( Workspace
* ws
)
81 , bridge( new Bridge( this ))
82 , move_faked_activity( false )
83 , move_resize_grab_window( None
)
84 , move_resize_has_keyboard_grab( false )
85 , transient_for( NULL
)
86 , transient_for_id( None
)
87 , original_transient_for_id( None
)
88 , autoRaiseTimer( NULL
)
89 , shadeHoverTimer( NULL
)
90 , delayedMoveResizeTimer( NULL
)
92 , window_group( None
)
93 , in_layer( UnknownLayer
)
95 , process_killer( NULL
)
96 , user_time( CurrentTime
) // Not known yet
97 , allowed_actions( 0 )
98 , block_geometry_updates( 0 )
99 , pending_geometry_update( PendingGeometryNone
)
100 , shade_geometry_change( false )
102 , sync_counter( None
)
105 , sync_timeout( NULL
)
106 , sync_resize_pending( false )
111 , sm_stacking_order( -1 )
112 , demandAttentionKNotifyTimer( NULL
)
113 { // TODO: Do all as initialization
115 // Set the initial mapping state
116 mapping_state
= Withdrawn
;
117 desk
= 0; // No desktop yet
119 mode
= PositionCenter
;
121 moveResizeMode
= false;
125 shade_mode
= ShadeNone
;
130 motif_may_move
= true;
131 motif_may_resize
= true;
132 motif_may_close
= true;
133 fullscreen_mode
= FullScreenNone
;
134 skip_taskbar
= false;
135 original_skip_taskbar
= false;
140 app_noborder
= false;
142 ignore_focus_stealing
= false;
143 demands_attention
= false;
144 check_active_modal
= false;
154 max_mode
= MaximizeRestore
;
155 maxmode_restore
= MaximizeRestore
;
159 geom
= QRect( 0, 0, 100, 100 ); // So that decorations don't start with size being (0,0)
160 client_size
= QSize( 100, 100 );
161 #if defined(HAVE_XSYNC) || defined(HAVE_XDAMAGE)
162 ready_for_painting
= false; // wait for first damage or sync reply
165 // SELI TODO: Initialize xsizehints??
174 if( sync_alarm
!= None
)
175 XSyncDestroyAlarm( display(), sync_alarm
);
177 assert(!moveResizeMode
);
178 assert( client
== None
);
179 assert( wrapper
== None
);
180 //assert( frameId() == None );
181 assert( decoration
== NULL
);
182 assert( block_geometry_updates
== 0 );
183 assert( !check_active_modal
);
187 // Use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
188 void Client::deleteClient( Client
* c
, allowed_t
)
194 * Releases the window. The client has done its job and the window is still existing.
196 void Client::releaseWindow( bool on_shutdown
)
200 Deleted
* del
= Deleted::create( this );
203 static_cast<EffectsHandlerImpl
*>(effects
)->windowClosed( effectWindow());
204 scene
->windowClosed( this, del
);
207 workspace()->discardUsedWindowRules( this, true ); // Remove ForceTemporarily rules
208 StackingUpdatesBlocker
blocker( workspace());
212 ++block_geometry_updates
;
213 if( isOnCurrentDesktop() && isShown( true ))
214 addWorkspaceRepaint( geometry());
215 // Grab X during the release to make removing of properties, setting to withdrawn state
216 // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
218 exportMappingState( WithdrawnState
);
219 setModal( false ); // Otherwise its mainwindow wouldn't get focus
220 hidden
= true; // So that it's not considered visible anymore (can't use hideClient(), it would set flags)
222 workspace()->clientHidden( this );
223 XUnmapWindow( display(), frameId()); // Destroying decoration would cause ugly visual effect
228 workspace()->removeClient( this, Allowed
);
229 // Only when the window is being unmapped, not when closing down KWin (NETWM sections 5.5,5.7)
230 info
->setDesktop( 0 );
232 info
->setState( 0, info
->state()); // Reset all state flags
234 XDeleteProperty( display(), client
, atoms
->kde_net_wm_user_creation_time
);
235 XDeleteProperty( display(), client
, atoms
->net_frame_extents
);
236 XDeleteProperty( display(), client
, atoms
->kde_net_wm_frame_strut
);
237 XReparentWindow( display(), client
, rootWindow(), x(), y());
238 XRemoveFromSaveSet( display(), client
);
239 XSelectInput( display(), client
, NoEventMask
);
241 // Map the window, so it can be found after another WM is started
242 XMapWindow( display(), client
);
243 // TODO: Preserve minimized, shaded etc. state?
244 else // Make sure it's not mapped if the app unmapped it (#65279). The app
245 // may do map+unmap before we initially map the window by calling rawShow() from manage().
246 XUnmapWindow( display(), client
);
248 XDestroyWindow( display(), wrapper
);
250 XDestroyWindow( display(), frameId());
252 --block_geometry_updates
; // Don't use GeometryUpdatesBlocker, it would now set the geometry
253 disownDataPassedToDeleted();
255 checkNonExistentClients();
256 deleteClient( this, Allowed
);
261 * Like releaseWindow(), but this one is called when the window has been already destroyed
262 * (E.g. The application closed it)
264 void Client::destroyClient()
268 Deleted
* del
= Deleted::create( this );
271 static_cast<EffectsHandlerImpl
*>(effects
)->windowClosed( effectWindow());
272 scene
->windowClosed( this, del
);
275 workspace()->discardUsedWindowRules( this, true ); // Remove ForceTemporarily rules
276 StackingUpdatesBlocker
blocker( workspace());
280 ++block_geometry_updates
;
281 if( isOnCurrentDesktop() && isShown( true ))
282 addWorkspaceRepaint( geometry());
284 hidden
= true; // So that it's not considered visible anymore
285 workspace()->clientHidden( this );
288 workspace()->removeClient( this, Allowed
);
289 client
= None
; // invalidate
290 XDestroyWindow( display(), wrapper
);
292 XDestroyWindow( display(), frameId());
294 --block_geometry_updates
; // Don't use GeometryUpdatesBlocker, it would now set the geometry
295 disownDataPassedToDeleted();
297 checkNonExistentClients();
298 deleteClient( this, Allowed
);
301 void Client::updateDecoration( bool check_workspace_pos
, bool force
)
304 (( decoration
== NULL
&& noBorder() ) || ( decoration
!= NULL
&& !noBorder() )))
306 bool do_show
= false;
307 QRect oldgeom
= geometry();
308 blockGeometryUpdates( true );
313 setMask( QRegion()); // Reset shape mask
314 decoration
= workspace()->createDecoration( bridge
);
315 // TODO: Check decoration's minimum size?
317 decoration
->widget()->installEventFilter( this );
318 XReparentWindow( display(), decoration
->widget()->winId(), frameId(), 0, 0 );
319 decoration
->widget()->lower();
320 decoration
->borders( border_left
, border_right
, border_top
, border_bottom
);
321 int save_workarea_diff_x
= workarea_diff_x
;
322 int save_workarea_diff_y
= workarea_diff_y
;
323 move( calculateGravitation( false ));
324 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet
);
325 workarea_diff_x
= save_workarea_diff_x
;
326 workarea_diff_y
= save_workarea_diff_y
;
329 discardWindowPixmap();
331 scene
->windowGeometryShapeChanged( this );
332 if( effects
!= NULL
)
333 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), oldgeom
);
337 if( check_workspace_pos
)
338 checkWorkspacePosition();
339 blockGeometryUpdates( false );
341 decoration
->widget()->show();
342 updateFrameExtents();
345 void Client::destroyDecoration()
347 QRect oldgeom
= geometry();
348 if( decoration
!= NULL
)
352 QPoint grav
= calculateGravitation( true );
353 border_left
= border_right
= border_top
= border_bottom
= 0;
354 setMask( QRegion()); // Reset shape mask
355 int save_workarea_diff_x
= workarea_diff_x
;
356 int save_workarea_diff_y
= workarea_diff_y
;
357 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet
);
359 workarea_diff_x
= save_workarea_diff_x
;
360 workarea_diff_y
= save_workarea_diff_y
;
362 discardWindowPixmap();
363 if( scene
!= NULL
&& !deleting
)
364 scene
->windowGeometryShapeChanged( this );
365 if( effects
!= NULL
&& !deleting
)
366 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), oldgeom
);
370 bool Client::checkBorderSizes( bool also_resize
)
372 if( decoration
== NULL
)
374 int new_left
, new_right
, new_top
, new_bottom
;
375 decoration
->borders( new_left
, new_right
, new_top
, new_bottom
);
376 if( new_left
== border_left
&& new_right
== border_right
&&
377 new_top
== border_top
&& new_bottom
== border_bottom
)
381 border_left
= new_left
;
382 border_right
= new_right
;
383 border_top
= new_top
;
384 border_bottom
= new_bottom
;
387 GeometryUpdatesBlocker
blocker( this );
388 move( calculateGravitation( true ));
389 border_left
= new_left
;
390 border_right
= new_right
;
391 border_top
= new_top
;
392 border_bottom
= new_bottom
;
393 move( calculateGravitation( false ));
394 plainResize( sizeForClientSize( clientSize() ), ForceGeometrySet
);
395 checkWorkspacePosition();
399 void Client::repaintDecoration()
401 if( decoration
!= NULL
)
402 decoration
->widget()->update();
405 void Client::detectNoBorder()
413 switch( windowType())
433 // NET::Override is some strange beast without clear definition, usually
434 // just meaning "noborder", so let's treat it only as such flag, and ignore it as
435 // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
436 if( info
->windowType( SUPPORTED_MANAGED_WINDOW_TYPES_MASK
| NET::OverrideMask
) == NET::Override
)
443 void Client::updateFrameExtents()
446 strut
.left
= border_left
;
447 strut
.right
= border_right
;
448 strut
.top
= border_top
;
449 strut
.bottom
= border_bottom
;
450 info
->setFrameExtents( strut
);
454 * Resizes the decoration, and makes sure the decoration widget gets resize event
455 * even if the size hasn't changed. This is needed to make sure the decoration
456 * re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
457 * the decoration may turn on/off some borders, but the actual size
458 * of the decoration stays the same).
460 void Client::resizeDecoration( const QSize
& s
)
462 if( decoration
== NULL
)
464 QSize oldsize
= decoration
->widget()->size();
465 decoration
->resize( s
);
468 QResizeEvent
e( s
, oldsize
);
469 QApplication::sendEvent( decoration
->widget(), &e
);
473 bool Client::noBorder() const
475 return noborder
|| isFullScreen();
478 bool Client::userCanSetNoBorder() const
480 return !isFullScreen() && !isShade();
483 void Client::setNoBorder( bool set
)
485 if( !userCanSetNoBorder() )
487 set
= rules()->checkNoBorder( set
);
488 if( noborder
== set
)
491 updateDecoration( true, false );
495 void Client::updateShape()
498 { // Workaround for #19644 - Shaped windows shouldn't have decoration
500 { // Only when shape is detected for the first time, still let the user to override
503 updateDecoration( true );
506 if( shape() && noBorder() )
507 XShapeCombineShape( display(), frameId(), ShapeBounding
,
508 clientPos().x(), clientPos().y(), window(), ShapeBounding
, ShapeSet
);
510 // Decoration mask (i.e. 'else' here) setting is done in setMask()
511 // when the decoration calls it or when the decoration is created/destroyed
516 addWorkspaceRepaint( geometry()); // In case shape change removes part of this window
519 scene
->windowGeometryShapeChanged( this );
520 if( effects
!= NULL
)
521 static_cast<EffectsHandlerImpl
*>(effects
)->windowGeometryShapeChanged( effectWindow(), geometry());
524 static Window shape_helper_window
= None
;
526 void Client::updateInputShape()
528 if( hiddenPreview() ) // Sets it to none, don't change
530 if( Extensions::shapeInputAvailable())
531 { // There appears to be no way to find out if a window has input
532 // shape set or not, so always propagate the input shape
533 // (it's the same like the bounding shape by default).
534 // Also, build the shape using a helper window, not directly
535 // in the frame window, because the sequence set-shape-to-frame,
536 // remove-shape-of-client, add-input-shape-of-client has the problem
537 // that after the second step there's a hole in the input shape
538 // until the real shape of the client is added and that can make
539 // the window lose focus (which is a problem with mouse focus policies)
540 // TODO: It seems there is, after all - XShapeGetRectangles() - but maybe this is better
541 if( shape_helper_window
== None
)
542 shape_helper_window
= XCreateSimpleWindow( display(), rootWindow(),
543 0, 0, 1, 1, 0, 0, 0 );
544 XResizeWindow( display(), shape_helper_window
, width(), height());
545 XShapeCombineShape( display(), shape_helper_window
, ShapeInput
, 0, 0,
546 frameId(), ShapeBounding
, ShapeSet
);
547 XShapeCombineShape( display(), shape_helper_window
, ShapeInput
,
548 clientPos().x(), clientPos().y(), window(), ShapeBounding
, ShapeSubtract
);
549 XShapeCombineShape( display(), shape_helper_window
, ShapeInput
,
550 clientPos().x(), clientPos().y(), window(), ShapeInput
, ShapeUnion
);
551 XShapeCombineShape( display(), frameId(), ShapeInput
, 0, 0,
552 shape_helper_window
, ShapeInput
, ShapeSet
);
556 void Client::setMask( const QRegion
& reg
, int mode
)
561 Window shape_window
= frameId();
563 { // The same way of applying a shape without strange intermediate states like above
564 if( shape_helper_window
== None
)
565 shape_helper_window
= XCreateSimpleWindow( display(), rootWindow(),
566 0, 0, 1, 1, 0, 0, 0 );
567 shape_window
= shape_helper_window
;
570 XShapeCombineMask( display(), shape_window
, ShapeBounding
, 0, 0, None
, ShapeSet
);
571 else if( mode
== X::Unsorted
)
572 XShapeCombineRegion( display(), shape_window
, ShapeBounding
, 0, 0, reg
.handle(), ShapeSet
);
575 QVector
< QRect
> rects
= reg
.rects();
576 XRectangle
* xrects
= new XRectangle
[rects
.count()];
577 for( int i
= 0; i
< rects
.count(); ++i
)
579 xrects
[i
].x
= rects
[i
].x();
580 xrects
[i
].y
= rects
[i
].y();
581 xrects
[i
].width
= rects
[i
].width();
582 xrects
[i
].height
= rects
[i
].height();
584 XShapeCombineRectangles( display(), shape_window
, ShapeBounding
, 0, 0,
585 xrects
, rects
.count(), ShapeSet
, mode
);
589 { // The rest of the applyign using a temporary window
590 XRectangle rec
= { 0, 0, clientSize().width(), clientSize().height() };
591 XShapeCombineRectangles( display(), shape_helper_window
, ShapeBounding
,
592 clientPos().x(), clientPos().y(), &rec
, 1, ShapeSubtract
, Unsorted
);
593 XShapeCombineShape( display(), shape_helper_window
, ShapeBounding
,
594 clientPos().x(), clientPos().y(), window(), ShapeBounding
, ShapeUnion
);
595 XShapeCombineShape( display(), frameId(), ShapeBounding
, 0, 0,
596 shape_helper_window
, ShapeBounding
, ShapeSet
);
599 scene
->windowGeometryShapeChanged( this );
600 if( effects
!= NULL
)
601 static_cast<EffectsHandlerImpl
*>( effects
)->windowGeometryShapeChanged( effectWindow(), geometry() );
605 QRegion
Client::mask() const
607 if( _mask
.isEmpty() )
608 return QRegion( 0, 0, width(), height() );
612 void Client::hideClient( bool hide
)
621 * Returns whether the window is minimizable or not
623 bool Client::isMinimizable() const
625 if( isSpecialWindow() )
628 { // #66868 - Let other xmms windows be minimized when the mainwindow is minimized
629 bool shown_mainwindow
= false;
630 ClientList mainclients
= mainClients();
631 for( ClientList::ConstIterator it
= mainclients
.constBegin();
632 it
!= mainclients
.constEnd();
634 if( (*it
)->isShown( true ))
635 shown_mainwindow
= true;
636 if( !shown_mainwindow
)
640 // This is here because kicker's taskbar doesn't provide separate entries
641 // for windows with an explicitly given parent
642 // TODO: perhaps this should be redone
643 // Disabled for now, since at least modal dialogs should be minimizable
644 // (resulting in the mainwindow being minimized too).
645 if( transientFor() != NULL
)
648 if( !wantsTabFocus() ) // SELI, TODO: - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
654 * Minimizes this client plus its transients
656 void Client::minimize( bool avoid_animation
)
658 if( !isMinimizable() || isMinimized() )
661 Notify::raise( Notify::Minimize
);
666 updateAllowedActions();
667 workspace()->updateMinimizedOfTransients( this );
669 workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast
);
670 if( effects
&& !avoid_animation
) // TODO: Shouldn't it tell effects at least about the change?
671 static_cast<EffectsHandlerImpl
*>(effects
)->windowMinimized( effectWindow());
674 void Client::unminimize( bool avoid_animation
)
679 Notify::raise( Notify::UnMinimize
);
682 updateAllowedActions();
683 workspace()->updateMinimizedOfTransients( this );
685 if( effects
&& !avoid_animation
)
686 static_cast<EffectsHandlerImpl
*>( effects
)->windowUnminimized( effectWindow() );
689 QRect
Client::iconGeometry() const
691 NETRect r
= info
->iconGeometry();
692 QRect
geom( r
.pos
.x
, r
.pos
.y
, r
.size
.width
, r
.size
.height
);
696 { // Check all mainwindows of this window (recursively)
697 foreach( Client
* mainwin
, mainClients() )
699 geom
= mainwin
->iconGeometry();
703 // No mainwindow (or their parents) with icon geometry was found
708 bool Client::isShadeable() const
710 return !isSpecialWindow() && !noBorder();
713 void Client::setShade( ShadeMode mode
)
717 mode
= rules()->checkShade( mode
);
718 if( shade_mode
== mode
)
720 bool was_shade
= isShade();
721 ShadeMode was_shade_mode
= shade_mode
;
723 if( was_shade
== isShade())
725 if( decoration
!= NULL
) // Decoration may want to update after e.g. hover-shade changes
726 decoration
->shadeChange();
727 return; // No real change in shaded state
730 if( shade_mode
== ShadeNormal
)
732 if( isShown( true ) && isOnCurrentDesktop() )
733 Notify::raise( Notify::ShadeUp
);
735 else if( shade_mode
== ShadeNone
)
737 if( isShown( true ) && isOnCurrentDesktop() )
738 Notify::raise( Notify::ShadeDown
);
741 assert( decoration
!= NULL
); // noborder windows can't be shaded
742 GeometryUpdatesBlocker
blocker( this );
743 // Decorations may turn off some borders when shaded
744 decoration
->borders( border_left
, border_right
, border_top
, border_bottom
);
746 // TODO: All this unmapping, resizing etc. feels too much duplicated from elsewhere
748 { // shade_mode == ShadeNormal
749 addWorkspaceRepaint( geometry() );
751 shade_geometry_change
= true;
752 QSize
s( sizeForClientSize( QSize( clientSize() )));
753 s
.setHeight( border_top
+ border_bottom
);
754 XSelectInput( display(), wrapper
, ClientWinMask
); // Avoid getting UnmapNotify
755 XUnmapWindow( display(), wrapper
);
756 XUnmapWindow( display(), client
);
757 XSelectInput( display(), wrapper
, ClientWinMask
| SubstructureNotifyMask
);
759 shade_geometry_change
= false;
762 if( was_shade_mode
== ShadeHover
)
763 workspace()->activateNextClient( this );
765 workspace()->focusToNull();
770 shade_geometry_change
= true;
771 QSize
s( sizeForClientSize( clientSize() ));
772 shade_geometry_change
= false;
774 if( shade_mode
== ShadeHover
|| shade_mode
== ShadeActivated
)
776 XMapWindow( display(), wrapperId() );
777 XMapWindow( display(), window() );
779 workspace()->requestFocus( this );
781 checkMaximizeGeometry();
782 info
->setState( isShade() ? NET::Shaded
: 0, NET::Shaded
);
783 info
->setState( isShown( false ) ? 0 : NET::Hidden
, NET::Hidden
);
784 discardWindowPixmap();
786 updateAllowedActions();
787 workspace()->updateMinimizedOfTransients( this );
788 decoration
->shadeChange();
792 void Client::shadeHover()
794 setShade( ShadeHover
);
795 cancelShadeHoverTimer();
798 void Client::shadeUnhover()
800 setShade( ShadeNormal
);
801 cancelShadeHoverTimer();
804 void Client::cancelShadeHoverTimer()
806 delete shadeHoverTimer
;
810 void Client::toggleShade()
811 { // If the mode is ShadeHover or ShadeActive, cancel shade too
812 setShade( shade_mode
== ShadeNone
? ShadeNormal
: ShadeNone
);
815 void Client::updateVisibility()
821 info
->setState( NET::Hidden
, NET::Hidden
);
822 setSkipTaskbar( true, false ); // Also hide from taskbar
823 if( compositing() && options
->hiddenPreviews
== HiddenPreviewsAlways
)
824 internalKeep( Allowed
);
826 internalHide( Allowed
);
829 setSkipTaskbar( original_skip_taskbar
, false ); // Reset from 'hidden'
832 info
->setState( NET::Hidden
, NET::Hidden
);
833 if( compositing() && options
->hiddenPreviews
== HiddenPreviewsAlways
)
834 internalKeep( Allowed
);
836 internalHide( Allowed
);
839 info
->setState( 0, NET::Hidden
);
840 if( !isOnCurrentDesktop())
842 if( compositing() && options
->hiddenPreviews
!= HiddenPreviewsNever
)
843 internalKeep( Allowed
);
845 internalHide( Allowed
);
848 bool belongs_to_desktop
= false;
849 for( ClientList::ConstIterator it
= group()->members().constBegin();
850 it
!= group()->members().constEnd();
852 if( (*it
)->isDesktop() )
854 belongs_to_desktop
= true;
857 if( !belongs_to_desktop
&& workspace()->showingDesktop())
858 workspace()->resetShowingDesktop( true );
859 internalShow( Allowed
);
863 * Sets the client window's mapping state. Possible values are
864 * WithdrawnState, IconicState, NormalState.
866 void Client::exportMappingState( int s
)
868 assert( client
!= None
);
869 assert( !deleting
|| s
== WithdrawnState
);
870 if( s
== WithdrawnState
)
872 XDeleteProperty( display(), window(), atoms
->wm_state
);
875 assert( s
== NormalState
|| s
== IconicState
);
877 unsigned long data
[2];
878 data
[0] = (unsigned long) s
;
879 data
[1] = (unsigned long) None
;
880 XChangeProperty(display(), window(), atoms
->wm_state
, atoms
->wm_state
, 32,
881 PropModeReplace
, (unsigned char*)( data
), 2);
884 void Client::internalShow( allowed_t
)
886 if( mapping_state
== Mapped
)
888 MappingState old
= mapping_state
;
889 mapping_state
= Mapped
;
890 if( old
== Unmapped
|| old
== Withdrawn
)
893 updateHiddenPreview();
894 workspace()->checkUnredirect();
897 void Client::internalHide( allowed_t
)
899 if( mapping_state
== Unmapped
)
901 MappingState old
= mapping_state
;
902 mapping_state
= Unmapped
;
903 if( old
== Mapped
|| old
== Kept
)
906 updateHiddenPreview();
907 addWorkspaceRepaint( geometry() );
908 workspace()->clientHidden( this );
909 workspace()->checkUnredirect();
912 void Client::internalKeep( allowed_t
)
914 assert( compositing() );
915 if( mapping_state
== Kept
)
917 MappingState old
= mapping_state
;
918 mapping_state
= Kept
;
919 if( old
== Unmapped
|| old
== Withdrawn
)
921 updateHiddenPreview();
922 addWorkspaceRepaint( geometry() );
923 workspace()->clientHidden( this );
924 workspace()->checkUnredirect();
928 * Maps (shows) the client. Note that it is mapping state of the frame,
929 * not necessarily the client window itself (i.e. a shaded window is here
930 * considered mapped, even though it is in IconicState).
932 void Client::map( allowed_t
)
934 // XComposite invalidates backing pixmaps on unmap (minimize, different
935 // virtual desktop, etc.). We kept the last known good pixmap around
936 // for use in effects, but now we want to have access to the new pixmap
938 discardWindowPixmap();
939 if( decoration
!= NULL
)
940 decoration
->widget()->show(); // Not really necessary, but let it know the state
941 XMapWindow( display(), frameId());
944 XMapWindow( display(), wrapper
);
945 XMapWindow( display(), client
);
946 exportMappingState( NormalState
);
949 exportMappingState( IconicState
);
953 * Unmaps the client. Again, this is about the frame.
955 void Client::unmap( allowed_t
)
957 // Here it may look like a race condition, as some other client might try to unmap
958 // the window between these two XSelectInput() calls. However, they're supposed to
959 // use XWithdrawWindow(), which also sends a synthetic event to the root window,
960 // which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
961 // will be missed is also very minimal, so I don't think it's needed to grab the server
963 XSelectInput( display(), wrapper
, ClientWinMask
); // Avoid getting UnmapNotify
964 XUnmapWindow( display(), frameId() );
965 XUnmapWindow( display(), wrapper
);
966 XUnmapWindow( display(), client
);
967 XSelectInput( display(), wrapper
, ClientWinMask
| SubstructureNotifyMask
);
968 if( decoration
!= NULL
)
969 decoration
->widget()->hide(); // Not really necessary, but let it know the state
970 exportMappingState( IconicState
);
974 * XComposite doesn't keep window pixmaps of unmapped windows, which means
975 * there wouldn't be any previews of windows that are minimized or on another
976 * virtual desktop. Therefore rawHide() actually keeps such windows mapped.
977 * However special care needs to be taken so that such windows don't interfere.
978 * Therefore they're put very low in the stacking order and they have input shape
979 * set to none, which hopefully is enough. If there's no input shape available,
980 * then it's hoped that there will be some other desktop above it *shrug*.
981 * Using normal shape would be better, but that'd affect other things, e.g. painting
982 * of the actual preview.
984 void Client::updateHiddenPreview()
986 if( hiddenPreview() )
988 workspace()->forceRestacking();
989 if( Extensions::shapeInputAvailable() )
990 XShapeCombineRectangles( display(), frameId(), ShapeInput
, 0, 0, NULL
, 0, ShapeSet
, Unsorted
);
994 workspace()->forceRestacking();
999 void Client::sendClientMessage( Window w
, Atom a
, Atom protocol
, long data1
, long data2
, long data3
)
1004 memset( &ev
, 0, sizeof( ev
));
1005 ev
.xclient
.type
= ClientMessage
;
1006 ev
.xclient
.window
= w
;
1007 ev
.xclient
.message_type
= a
;
1008 ev
.xclient
.format
= 32;
1009 ev
.xclient
.data
.l
[0] = protocol
;
1010 ev
.xclient
.data
.l
[1] = xTime();
1011 ev
.xclient
.data
.l
[2] = data1
;
1012 ev
.xclient
.data
.l
[3] = data2
;
1013 ev
.xclient
.data
.l
[4] = data3
;
1015 if( w
== rootWindow() )
1016 mask
= SubstructureRedirectMask
; // Magic!
1017 XSendEvent( display(), w
, False
, mask
, &ev
);
1021 * Returns whether the window may be closed (have a close button)
1023 bool Client::isCloseable() const
1025 return rules()->checkCloseable( motif_may_close
&& !isSpecialWindow() );
1029 * Closes the window by either sending a delete_window message or using XKill.
1031 void Client::closeWindow()
1033 if( !isCloseable() )
1036 // Update user time, because the window may create a confirming dialog.
1039 if ( Pdeletewindow
)
1041 Notify::raise( Notify::Close
);
1042 sendClientMessage( window(), atoms
->wm_protocols
, atoms
->wm_delete_window
);
1045 else // Client will not react on wm_delete_window. We have not choice
1046 // but destroy his connection to the XServer.
1052 * Kills the window via XKill
1054 void Client::killWindow()
1056 kDebug( 1212 ) << "Client::killWindow():" << caption();
1058 // Not sure if we need an Notify::Kill or not.. until then, use
1060 Notify::raise( Notify::Close
);
1063 Notify::raise( Notify::TransDelete
);
1064 if( isNormalWindow() )
1065 Notify::raise( Notify::Delete
);
1066 killProcess( false );
1067 XKillClient(display(), window() ); // Always kill this client at the server
1072 * Send a ping to the window using _NET_WM_PING if possible if it
1073 * doesn't respond within a reasonable time, it will be killed.
1075 void Client::pingWindow()
1078 return; // Can't ping :(
1079 if( options
->killPingTimeout
== 0 )
1080 return; // Turned off
1081 if( ping_timer
!= NULL
)
1082 return; // Pinging already
1083 ping_timer
= new QTimer( this );
1084 connect( ping_timer
, SIGNAL( timeout() ), SLOT( pingTimeout() ));
1085 ping_timer
->setSingleShot( true );
1086 ping_timer
->start( options
->killPingTimeout
);
1087 ping_timestamp
= xTime();
1088 workspace()->sendPingToWindow( window(), ping_timestamp
);
1091 void Client::gotPing( Time timestamp
)
1093 // Just plain compare is not good enough because of 64bit and truncating and whatnot
1094 if( NET::timestampCompare( timestamp
, ping_timestamp
) != 0 )
1098 if( process_killer
!= NULL
)
1100 process_killer
->kill();
1101 // Recycle when the process manager has noticed that the process exited
1102 // a delete process_killer here sometimes causes a hang in waitForFinished
1103 connect(process_killer
, SIGNAL( finished(int, QProcess::ExitStatus
) ),
1104 process_killer
, SLOT( deleteLater() ));
1105 process_killer
= NULL
;
1109 void Client::pingTimeout()
1111 kDebug( 1212 ) << "Ping timeout:" << caption();
1112 ping_timer
->deleteLater();
1114 killProcess( true, ping_timestamp
);
1117 void Client::killProcess( bool ask
, Time timestamp
)
1119 if( process_killer
!= NULL
)
1121 Q_ASSERT( !ask
|| timestamp
!= CurrentTime
);
1122 QByteArray machine
= wmClientMachine( true );
1123 pid_t pid
= info
->pid();
1124 if( pid
<= 0 || machine
.isEmpty()) // Needed properties missing
1126 kDebug( 1212 ) << "Kill process:" << pid
<< "(" << machine
<< ")";
1129 if( machine
!= "localhost" )
1132 lst
<< machine
<< "kill" << QString::number( pid
);
1133 QProcess::startDetached( "xon",lst
);
1136 ::kill( pid
, SIGTERM
);
1140 process_killer
= new QProcess( this );
1141 connect( process_killer
, SIGNAL( error(QProcess::ProcessError
) ), SLOT( processKillerExited() ));
1142 connect( process_killer
, SIGNAL( finished(int, QProcess::ExitStatus
) ), SLOT( processKillerExited() ));
1143 process_killer
->start( KStandardDirs::findExe( "kwin_killer_helper" ),
1144 QStringList() << "--pid" << QByteArray().setNum( unsigned( pid
)) << "--hostname" << machine
1145 << "--windowname" << caption()
1146 << "--applicationname" << resourceClass()
1147 << "--wid" << QString::number( window() )
1148 << "--timestamp" << QString::number( timestamp
));
1152 void Client::processKillerExited()
1154 kDebug( 1212 ) << "Killer exited";
1155 delete process_killer
;
1156 process_killer
= NULL
;
1159 void Client::setSkipTaskbar( bool b
, bool from_outside
)
1161 int was_wants_tab_focus
= wantsTabFocus();
1164 b
= rules()->checkSkipTaskbar( b
);
1165 original_skip_taskbar
= b
;
1167 if( b
== skipTaskbar() )
1170 info
->setState( b
? NET::SkipTaskbar
: 0, NET::SkipTaskbar
);
1171 updateWindowRules();
1172 if( was_wants_tab_focus
!= wantsTabFocus())
1173 workspace()->updateFocusChains( this,
1174 isActive() ? Workspace::FocusChainMakeFirst
: Workspace::FocusChainUpdate
);
1177 void Client::setSkipPager( bool b
)
1179 b
= rules()->checkSkipPager( b
);
1180 if( b
== skipPager() )
1183 info
->setState( b
? NET::SkipPager
: 0, NET::SkipPager
);
1184 updateWindowRules();
1187 void Client::setModal( bool m
)
1188 { // Qt-3.2 can have even modal normal windows :(
1194 // Changing modality for a mapped window is weird (?)
1195 // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
1198 void Client::setDesktop( int desktop
)
1200 if( desktop
!= NET::OnAllDesktops
) // Do range check
1201 desktop
= qMax( 1, qMin( workspace()->numberOfDesktops(), desktop
));
1202 desktop
= qMin( workspace()->numberOfDesktops(), rules()->checkDesktop( desktop
));
1203 if( desk
== desktop
)
1205 int was_desk
= desk
;
1207 info
->setDesktop( desktop
);
1208 if(( was_desk
== NET::OnAllDesktops
) != ( desktop
== NET::OnAllDesktops
))
1209 { // onAllDesktops changed
1210 if( isShown( true ))
1211 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops
: Notify::NotOnAllDesktops
);
1212 workspace()->updateOnAllDesktopsOfTransients( this );
1214 if( decoration
!= NULL
)
1215 decoration
->desktopChange();
1216 workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst
);
1218 updateWindowRules();
1222 * Returns the virtual desktop within the workspace() the client window
1223 * is located in, 0 if it isn't located on any special desktop (not mapped yet),
1224 * or NET::OnAllDesktops. Do not use desktop() directly, use
1225 * isOnDesktop() instead.
1227 int Client::desktop() const
1232 void Client::setOnAllDesktops( bool b
)
1234 if(( b
&& isOnAllDesktops() ) ||
1235 ( !b
&& !isOnAllDesktops() ))
1238 setDesktop( NET::OnAllDesktops
);
1240 setDesktop( workspace()->currentDesktop());
1244 * Performs activation and/or raising of the window
1246 void Client::takeActivity( int flags
, bool handled
, allowed_t
)
1248 if( !handled
|| !Ptakeactivity
)
1250 if( flags
& ActivityFocus
)
1251 takeFocus( Allowed
);
1252 if( flags
& ActivityRaise
)
1253 workspace()->raiseClient( this );
1258 static Time previous_activity_timestamp
;
1259 static Client
* previous_client
;
1261 //if( previous_activity_timestamp == xTime() && previous_client != this )
1263 // kDebug( 1212 ) << "Repeated use of the same X timestamp for activity";
1264 // kDebug( 1212 ) << kBacktrace();
1267 previous_activity_timestamp
= xTime();
1268 previous_client
= this;
1271 workspace()->sendTakeActivity( this, xTime(), flags
);
1275 * Performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
1277 void Client::takeFocus( allowed_t
)
1280 static Time previous_focus_timestamp
;
1281 static Client
* previous_client
;
1283 //if( previous_focus_timestamp == xTime() && previous_client != this )
1285 // kDebug( 1212 ) << "Repeated use of the same X timestamp for focus";
1286 // kDebug( 1212 ) << kBacktrace();
1289 previous_focus_timestamp
= xTime();
1290 previous_client
= this;
1292 if( rules()->checkAcceptFocus( input
))
1293 XSetInputFocus( display(), window(), RevertToPointerRoot
, xTime() );
1295 sendClientMessage( window(), atoms
->wm_protocols
, atoms
->wm_take_focus
);
1296 workspace()->setShouldGetFocus( this );
1300 * Returns whether the window provides context help or not. If it does,
1301 * you should show a help menu item or a help button like '?' and call
1302 * contextHelp() if this is invoked.
1306 bool Client::providesContextHelp() const
1308 return Pcontexthelp
;
1312 * Invokes context help on the window. Only works if the window
1313 * actually provides context help.
1315 * \sa providesContextHelp()
1317 void Client::showContextHelp()
1321 sendClientMessage( window(), atoms
->wm_protocols
, atoms
->net_wm_context_help
);
1322 QWhatsThis::enterWhatsThisMode(); // SELI TODO: ?
1327 * Fetches the window's caption (WM_NAME property). It will be
1328 * stored in the client's caption().
1330 void Client::fetchName()
1332 setCaption( readName());
1335 QString
Client::readName() const
1337 if( info
->name() && info
->name()[0] != '\0' )
1338 return QString::fromUtf8( info
->name() );
1340 return KWindowSystem::readNameProperty( window(), XA_WM_NAME
);
1343 KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate
, Client
, const Client
*, (!cl
->isSpecialWindow() || cl
->isToolbar()) && cl
!= value
&& cl
->caption() == value
->caption());
1345 // The list is taken from http://www.unicode.org/reports/tr9/ (#154840)
1354 void Client::setCaption( const QString
& _s
, bool force
)
1357 if( s
!= cap_normal
|| force
)
1359 bool reset_name
= force
;
1360 for( int i
= 0; i
< s
.length(); ++i
)
1361 if( !s
[i
].isPrint() )
1362 s
[i
] = QChar( ' ' );
1364 bool was_suffix
= ( !cap_suffix
.isEmpty() );
1365 QString machine_suffix
;
1366 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
1367 machine_suffix
= QString( " <@" ) + wmClientMachine( true ) + '>' + LRM
;
1368 QString shortcut_suffix
= !shortcut().isEmpty() ? ( " {" + shortcut().toString() + '}' ) : QString();
1369 cap_suffix
= machine_suffix
+ shortcut_suffix
;
1370 if(( !isSpecialWindow() || isToolbar() ) && workspace()->findClient( FetchNameInternalPredicate( this )))
1375 cap_suffix
= machine_suffix
+ " <" + QString::number(i
) + '>' + LRM
+ shortcut_suffix
;
1377 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
1378 info
->setVisibleName( caption().toUtf8() );
1381 if(( was_suffix
&& cap_suffix
.isEmpty() ) || reset_name
)
1382 { // If it was new window, it may have old value still set, if the window is reused
1383 info
->setVisibleName( "" );
1384 info
->setVisibleIconName( "" );
1386 else if( !cap_suffix
.isEmpty() && !cap_iconic
.isEmpty())
1387 // Keep the same suffix in iconic name if it's set
1388 info
->setVisibleIconName( ( cap_iconic
+ cap_suffix
).toUtf8() );
1390 if( isManaged() && decoration
!= NULL
)
1391 decoration
->captionChange();
1395 void Client::updateCaption()
1397 setCaption( cap_normal
, true );
1400 void Client::fetchIconicName()
1403 if( info
->iconName() && info
->iconName()[0] != '\0' )
1404 s
= QString::fromUtf8( info
->iconName() );
1406 s
= KWindowSystem::readNameProperty( window(), XA_WM_ICON_NAME
);
1407 if( s
!= cap_iconic
)
1409 bool was_set
= !cap_iconic
.isEmpty();
1411 if( !cap_suffix
.isEmpty())
1413 if( !cap_iconic
.isEmpty()) // Keep the same suffix in iconic name if it's set
1414 info
->setVisibleIconName( ( s
+ cap_suffix
).toUtf8() );
1416 info
->setVisibleIconName( "" );
1424 QString
Client::caption( bool full
) const
1426 return full
? cap_normal
+ cap_suffix
: cap_normal
;
1429 void Client::getWMHints()
1431 XWMHints
* hints
= XGetWMHints( display(), window() );
1433 window_group
= None
;
1437 if( hints
->flags
& InputHint
)
1438 input
= hints
->input
;
1439 if( hints
->flags
& WindowGroupHint
)
1440 window_group
= hints
->window_group
;
1441 urgency
= !!( hints
->flags
& UrgencyHint
); // Need boolean, it's a uint bitfield
1442 XFree( (char*)hints
);
1446 updateAllowedActions(); // Group affects isMinimizable()
1449 void Client::getMotifHints()
1451 bool mnoborder
, mresize
, mmove
, mminimize
, mmaximize
, mclose
;
1452 Motif::readFlags( client
, mnoborder
, mresize
, mmove
, mminimize
, mmaximize
, mclose
);
1456 app_noborder
= true;
1458 if( !hasNETSupport() )
1459 { // NETWM apps should set type and size constraints
1460 motif_may_resize
= mresize
; // This should be set using minsize==maxsize, but oh well
1461 motif_may_move
= mmove
;
1464 motif_may_resize
= motif_may_move
= true;
1466 // mminimize; - Ignore, bogus - E.g. shading or sending to another desktop is "minimizing" too
1467 // mmaximize; - Ignore, bogus - Maximizing is basically just resizing
1468 motif_may_close
= mclose
; // Motif apps like to crash when they set this hint and WM closes them anyway
1470 updateDecoration( true ); // Check if noborder state has changed
1473 void Client::readIcons( Window win
, QPixmap
* icon
, QPixmap
* miniicon
)
1475 // Get the icons, allow scaling
1477 *icon
= KWindowSystem::icon( win
, 32, 32, true, KWindowSystem::NETWM
| KWindowSystem::WMHints
);
1478 if( miniicon
!= NULL
)
1480 if( icon
== NULL
|| !icon
->isNull() )
1481 *miniicon
= KWindowSystem::icon( win
, 16, 16, true, KWindowSystem::NETWM
| KWindowSystem::WMHints
);
1483 *miniicon
= QPixmap();
1487 void Client::getIcons()
1489 // First read icons from the window itself
1490 readIcons( window(), &icon_pix
, &miniicon_pix
);
1491 if( icon_pix
.isNull() )
1492 { // Then try window group
1493 icon_pix
= group()->icon();
1494 miniicon_pix
= group()->miniIcon();
1496 if( icon_pix
.isNull() && isTransient() )
1497 { // Then mainclients
1498 ClientList mainclients
= mainClients();
1499 for( ClientList::ConstIterator it
= mainclients
.constBegin();
1500 it
!= mainclients
.constEnd() && icon_pix
.isNull();
1503 icon_pix
= (*it
)->icon();
1504 miniicon_pix
= (*it
)->miniIcon();
1507 if( icon_pix
.isNull())
1508 { // And if nothing else, load icon from classhint or xapp icon
1509 icon_pix
= KWindowSystem::icon( window(), 32, 32, true, KWindowSystem::ClassHint
| KWindowSystem::XApp
);
1510 miniicon_pix
= KWindowSystem::icon( window(), 16, 16, true, KWindowSystem::ClassHint
| KWindowSystem::XApp
);
1512 if( isManaged() && decoration
!= NULL
)
1513 decoration
->iconChange();
1516 void Client::getWindowProtocols()
1527 if( XGetWMProtocols( display(), window(), &p
, &n
))
1529 for( i
= 0; i
< n
; i
++ )
1531 if( p
[i
] == atoms
->wm_delete_window
)
1533 else if( p
[i
] == atoms
->wm_take_focus
)
1535 else if( p
[i
] == atoms
->net_wm_take_activity
)
1537 else if( p
[i
] == atoms
->net_wm_context_help
)
1539 else if( p
[i
] == atoms
->net_wm_ping
)
1547 void Client::getSyncCounter()
1550 if( !Extensions::syncAvailable() )
1554 unsigned long nItemRet
;
1555 unsigned long byteRet
;
1557 unsigned char* propRet
;
1558 int ret
= XGetWindowProperty( display(), window(), atoms
->net_wm_sync_request_counter
,
1559 0, 1, false, XA_CARDINAL
, &retType
, &formatRet
, &nItemRet
, &byteRet
, &propRet
);
1561 if( ret
== Success
&& formatRet
== 32 )
1563 sync_counter
= *(long*)( propRet
);
1564 XSyncIntToValue( &sync_counter_value
, 0 );
1566 XSyncIntToValue( &zero
, 0 );
1567 XSyncSetCounter( display(), sync_counter
, zero
);
1568 if( sync_alarm
== None
)
1570 XSyncAlarmAttributes attrs
;
1571 attrs
.trigger
.counter
= sync_counter
;
1572 attrs
.trigger
.value_type
= XSyncRelative
;
1573 attrs
.trigger
.test_type
= XSyncPositiveTransition
;
1574 XSyncIntToValue( &attrs
.trigger
.wait_value
, 1 );
1575 XSyncIntToValue( &attrs
.delta
, 1 );
1576 sync_alarm
= XSyncCreateAlarm( display(),
1577 XSyncCACounter
| XSyncCAValueType
| XSyncCATestType
| XSyncCADelta
| XSyncCAValue
,
1585 * Send the client a _NET_SYNC_REQUEST
1587 void Client::sendSyncRequest()
1590 if( sync_counter
== None
)
1593 // We increment before the notify so that after the notify
1594 // syncCounterSerial will equal the value we are expecting
1595 // in the acknowledgement
1598 XSyncIntToValue( &one
, 1 );
1599 #undef XSyncValueAdd // It causes a warning :-/
1600 XSyncValueAdd( &sync_counter_value
, sync_counter_value
, one
, &overflow
);
1602 // Send the message to client
1604 ev
.xclient
.type
= ClientMessage
;
1605 ev
.xclient
.window
= window();
1606 ev
.xclient
.format
= 32;
1607 ev
.xclient
.message_type
= atoms
->wm_protocols
;
1608 ev
.xclient
.data
.l
[0] = atoms
->net_wm_sync_request
;
1609 ev
.xclient
.data
.l
[1] = xTime();
1610 ev
.xclient
.data
.l
[2] = XSyncValueLow32( sync_counter_value
);
1611 ev
.xclient
.data
.l
[3] = XSyncValueHigh32( sync_counter_value
);
1612 ev
.xclient
.data
.l
[4] = 0;
1613 XSendEvent( display(), window(), False
, NoEventMask
, &ev
);
1614 XSync( display(), false );
1618 bool Client::wantsTabFocus() const
1620 return ( isNormalWindow() || isDialog() ) && wantsInput();
1623 bool Client::wantsInput() const
1625 return rules()->checkAcceptFocus( input
|| Ptakefocus
);
1628 bool Client::isSpecialWindow() const
1630 return isDesktop() || isDock() || isSplash() || isTopMenu() || isToolbar();
1634 * Sets an appropriate cursor shape for the logical mouse position \a m
1636 void Client::updateCursor()
1639 if( !isResizable() || isShade() )
1644 case PositionTopLeft
:
1645 case PositionBottomRight
:
1646 c
= Qt::SizeFDiagCursor
;
1648 case PositionBottomLeft
:
1649 case PositionTopRight
:
1650 c
= Qt::SizeBDiagCursor
;
1653 case PositionBottom
:
1654 c
= Qt::SizeVerCursor
;
1658 c
= Qt::SizeHorCursor
;
1661 if( moveResizeMode
)
1662 c
= Qt::SizeAllCursor
;
1664 c
= Qt::ArrowCursor
;
1667 if( c
.handle() == cursor
.handle())
1670 if( decoration
!= NULL
)
1671 decoration
->widget()->setCursor( cursor
);
1672 XDefineCursor( display(), frameId(), cursor
.handle() );
1673 if( moveResizeMode
) // XDefineCursor doesn't change cursor if there's pointer grab active
1674 XChangeActivePointerGrab( display(),
1675 ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
| EnterWindowMask
| LeaveWindowMask
,
1676 cursor
.handle(), xTime());
1679 Client::Position
Client::mousePosition( const QPoint
& p
) const
1681 if( decoration
!= NULL
)
1682 return decoration
->mousePosition( p
);
1683 return PositionCenter
;
1686 void Client::updateAllowedActions( bool force
)
1688 if( !isManaged() && !force
)
1690 unsigned long old_allowed_actions
= allowed_actions
;
1691 allowed_actions
= 0;
1693 allowed_actions
|= NET::ActionMove
;
1695 allowed_actions
|= NET::ActionResize
;
1696 if( isMinimizable() )
1697 allowed_actions
|= NET::ActionMinimize
;
1699 allowed_actions
|= NET::ActionShade
;
1700 // Sticky state not supported
1701 if( isMaximizable() )
1702 allowed_actions
|= NET::ActionMax
;
1703 if( userCanSetFullScreen() )
1704 allowed_actions
|= NET::ActionFullScreen
;
1705 allowed_actions
|= NET::ActionChangeDesktop
; // Always (Pagers shouldn't show Docks etc.)
1707 allowed_actions
|= NET::ActionClose
;
1708 if( old_allowed_actions
== allowed_actions
)
1710 // TODO: This could be delayed and compressed - It's only for pagers etc. anyway
1711 info
->setAllowedActions( allowed_actions
);
1712 // TODO: This should also tell the decoration, so that it can update the buttons
1715 void Client::autoRaise()
1717 workspace()->raiseClient( this );
1721 void Client::cancelAutoRaise()
1723 delete autoRaiseTimer
;
1727 void Client::debug( kdbgstream
& stream
) const
1729 stream
<< "\'ID:" << window() << ";WMCLASS:" << resourceClass() << ":"
1730 << resourceName() << ";Caption:" << caption() << "\'";
1733 QPixmap
* kwin_get_menu_pix_hack()
1737 p
= SmallIcon( "bx2" );
1743 #include "client.moc"