• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • twin
 

twin

  • twin
client.cpp
1/*****************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7
8You can Freely distribute this program under the GNU General Public
9License. See the file "COPYING" for the exact licensing terms.
10******************************************************************/
11
12#include "client.h"
13
14#include <math.h>
15
16#include <tqapplication.h>
17#include <tqpainter.h>
18#include <tqdatetime.h>
19#include <tqimage.h>
20#include <tqfile.h>
21#include <tdeprocess.h>
22#include <unistd.h>
23#include <tdestandarddirs.h>
24#include <tqwhatsthis.h>
25#include <twin.h>
26#include <kiconloader.h>
27#include <tdelocale.h>
28#include <stdlib.h>
29
30#ifdef Q_OS_SOLARIS
31#include <procfs.h>
32#include <libgen.h>
33#endif /* SunOS */
34
35#include "bridge.h"
36#include "group.h"
37#include "workspace.h"
38#include "atoms.h"
39#include "notifications.h"
40#include "rules.h"
41
42#include <X11/extensions/shape.h>
43
44// put all externs before the namespace statement to allow the linker
45// to resolve them properly
46
47extern Atom tqt_wm_state;
48extern Atom tqt_window_role;
49extern Atom tqt_sm_client_id;
50
51// wait 200 ms before drawing shadow after move/resize
52static const int SHADOW_DELAY = 200;
53
54namespace KWinInternal
55{
56
57/* TODO: Remove this once X has real translucency.
58 *
59 * A list of the regions covered by all shadows and the Clients to which they
60 * belong. Used to redraw shadows when a window overlapping or underlying a
61 * shadow is moved, resized, or hidden.
62 */
63struct ShadowRegion
64 {
65 TQRegion region;
66 Client *client;
67 };
68static TQValueList<ShadowRegion> shadowRegions;
69
70/*
71
72 Creating a client:
73 - only by calling Workspace::createClient()
74 - it creates a new client and calls manage() for it
75
76 Destroying a client:
77 - destroyClient() - only when the window itself has been destroyed
78 - releaseWindow() - the window is kept, only the client itself is destroyed
79
80*/
81
82
94Client::Client( Workspace *ws )
95 : TQObject( NULL ),
96 client( None ),
97 wrapper( None ),
98 frame( None ),
99 decoration( NULL ),
100 wspace( ws ),
101 bridge( new Bridge( this )),
102 inhibitConfigureRequests(false),
103 move_faked_activity( false ),
104 move_resize_grab_window( None ),
105 transient_for( NULL ),
106 transient_for_id( None ),
107 original_transient_for_id( None ),
108 in_group( NULL ),
109 window_group( None ),
110 in_layer( UnknownLayer ),
111 ping_timer( NULL ),
112 process_killer( NULL ),
113 process_resumer( NULL ),
114 user_time( CurrentTime ), // not known yet
115 allowed_actions( 0 ),
116 postpone_geometry_updates( 0 ),
117 pending_geometry_update( false ),
118 shade_geometry_change( false ),
119 border_left( 0 ),
120 border_right( 0 ),
121 border_top( 0 ),
122 border_bottom( 0 ),
123 opacity_( Opacity::Opaque ),
124 demandAttentionKNotifyTimer( NULL ),
125 activeMaximizing(false),
126 activeTiled(false)
127// SELI do all as initialization
128 {
129 autoRaiseTimer = 0;
130 shadeHoverTimer = 0;
131
132 configureRequestTimer = new TQTimer(this);
133 connect(configureRequestTimer, TQ_SIGNAL(timeout()), TQ_SLOT(configureRequestTimeout()));
134
135 shadowDelayTimer = new TQTimer(this);
136 opacityCache = &activeOpacityCache;
137 shadowAfterClient = NULL;
138 shadowWidget = NULL;
139 shadowMe = true;
140 connect(shadowDelayTimer, TQ_SIGNAL(timeout()), TQ_SLOT(drawShadow()));
141
142 // set the initial mapping state
143 mapping_state = WithdrawnState;
144 desk = 0; // no desktop yet
145
146 mode = PositionCenter;
147 buttonDown = false;
148 moveResizeMode = false;
149
150 info = NULL;
151
152 shade_mode = ShadeNone;
153 active = false;
154 deleting = false;
155 keep_above = false;
156 keep_below = false;
157 is_shape = false;
158 motif_noborder = false;
159 motif_may_move = true;
160 motif_may_resize = true;
161 motif_may_close = true;
162 fullscreen_mode = FullScreenNone;
163 skip_taskbar = false;
164 original_skip_taskbar = false;
165 minimized = false;
166 hidden = false;
167 modal = false;
168 noborder = false;
169 user_noborder = false;
170 user_noborder_forced = false;
171 urgency = false;
172 ignore_focus_stealing = false;
173 demands_attention = false;
174 check_active_modal = false;
175
176 Pdeletewindow = 0;
177 Ptakefocus = 0;
178 Ptakeactivity = 0;
179 Pcontexthelp = 0;
180 Pping = 0;
181 input = false;
182 skip_pager = false;
183
184 max_mode = MaximizeRestore;
185 maxmode_restore = MaximizeRestore;
186
187 cmap = None;
188
189 frame_geometry = TQRect( 0, 0, 100, 100 ); // so that decorations don't start with size being (0,0)
190 client_size = TQSize( 100, 100 );
191 custom_opacity = false;
192 rule_opacity_active = 0; //translucency rules
193 rule_opacity_inactive = 0; //dito.
194
195 // SELI initialize xsizehints??
196 }
197
201Client::~Client()
202 {
203 assert(!moveResizeMode);
204 assert( client == None );
205 assert( frame == None && wrapper == None );
206 assert( decoration == NULL );
207 assert( postpone_geometry_updates == 0 );
208 assert( !check_active_modal );
209 delete info;
210 delete bridge;
211 }
212
213// use destroyClient() or releaseWindow(), Client instances cannot be deleted directly
214void Client::deleteClient( Client* c, allowed_t )
215 {
216 delete c;
217 }
218
222void Client::releaseWindow( bool on_shutdown )
223 {
224 assert( !deleting );
225 deleting = true;
226 workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
227 StackingUpdatesBlocker blocker( workspace());
228 if (!custom_opacity) setOpacity(Opacity::Opaque);
229 if (moveResizeMode)
230 leaveMoveResize();
231 removeShadow();
232 drawIntersectingShadows();
233 finishWindowRules();
234 ++postpone_geometry_updates;
235 // grab X during the release to make removing of properties, setting to withdrawn state
236 // and repareting to root an atomic operation (http://lists.kde.org/?l=kde-devel&m=116448102901184&w=2)
237 grabXServer();
238 setMappingState( WithdrawnState );
239 setModal( false ); // otherwise its mainwindow wouldn't get focus
240 hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
241 if( !on_shutdown )
242 workspace()->clientHidden( this );
243 XUnmapWindow( tqt_xdisplay(), frameId()); // destroying decoration would cause ugly visual effect
244 destroyDecoration();
245 cleanGrouping();
246 if( !on_shutdown )
247 {
248 workspace()->removeClient( this, Allowed );
249 // only when the window is being unmapped, not when closing down KWin
250 // (NETWM sections 5.5,5.7)
251 info->setDesktop( 0 );
252 desk = 0;
253 info->setState( 0, info->state()); // reset all state flags
254 }
255 XDeleteProperty( tqt_xdisplay(), client, atoms->kde_net_wm_user_creation_time);
256 XDeleteProperty( tqt_xdisplay(), client, atoms->net_frame_extents );
257 XDeleteProperty( tqt_xdisplay(), client, atoms->kde_net_wm_frame_strut );
258 XReparentWindow( tqt_xdisplay(), client, workspace()->rootWin(), x(), y());
259 XRemoveFromSaveSet( tqt_xdisplay(), client );
260 XSelectInput( tqt_xdisplay(), client, NoEventMask );
261 if( on_shutdown )
262 { // map the window, so it can be found after another WM is started
263 XMapWindow( tqt_xdisplay(), client );
264 // TODO preserve minimized, shaded etc. state?
265 }
266 else
267 {
268 // Make sure it's not mapped if the app unmapped it (#65279). The app
269 // may do map+unmap before we initially map the window by calling rawShow() from manage().
270 XUnmapWindow( tqt_xdisplay(), client );
271 }
272 client = None;
273 XDestroyWindow( tqt_xdisplay(), wrapper );
274 wrapper = None;
275 XDestroyWindow( tqt_xdisplay(), frame );
276 frame = None;
277 --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
278 checkNonExistentClients();
279 deleteClient( this, Allowed );
280 ungrabXServer();
281 }
282
283// like releaseWindow(), but this one is called when the window has been already destroyed
284// (e.g. the application closed it)
285void Client::destroyClient()
286 {
287 assert( !deleting );
288 deleting = true;
289 workspace()->discardUsedWindowRules( this, true ); // remove ForceTemporarily rules
290 StackingUpdatesBlocker blocker( workspace());
291 if (moveResizeMode)
292 leaveMoveResize();
293 removeShadow();
294 drawIntersectingShadows();
295 finishWindowRules();
296 ++postpone_geometry_updates;
297 setModal( false );
298 hidden = true; // so that it's not considered visible anymore
299 workspace()->clientHidden( this );
300 destroyDecoration();
301 cleanGrouping();
302 workspace()->removeClient( this, Allowed );
303 client = None; // invalidate
304 XDestroyWindow( tqt_xdisplay(), wrapper );
305 wrapper = None;
306 XDestroyWindow( tqt_xdisplay(), frame );
307 frame = None;
308 --postpone_geometry_updates; // don't use GeometryUpdatesBlocker, it would now set the geometry
309 checkNonExistentClients();
310 deleteClient( this, Allowed );
311 }
312
313void Client::updateDecoration( bool check_workspace_pos, bool force )
314 {
315 if( !force && (( decoration == NULL && noBorder())
316 || ( decoration != NULL && !noBorder())))
317 return;
318 bool do_show = false;
319 postponeGeometryUpdates( true );
320 if( force )
321 destroyDecoration();
322 if( !noBorder())
323 {
324 setMask( TQRegion()); // reset shape mask
325 decoration = workspace()->createDecoration( bridge );
326 // TODO check decoration's minimum size?
327 decoration->init();
328 decoration->widget()->installEventFilter( this );
329 XReparentWindow( tqt_xdisplay(), decoration->widget()->winId(), frameId(), 0, 0 );
330 decoration->widget()->lower();
331 decoration->borders( border_left, border_right, border_top, border_bottom );
332 int save_workarea_diff_x = workarea_diff_x;
333 int save_workarea_diff_y = workarea_diff_y;
334 move( calculateGravitation( false ));
335 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
336 workarea_diff_x = save_workarea_diff_x;
337 workarea_diff_y = save_workarea_diff_y;
338 do_show = true;
339 }
340 else
341 destroyDecoration();
342 if( check_workspace_pos )
343 checkWorkspacePosition();
344 postponeGeometryUpdates( false );
345 if( do_show )
346 decoration->widget()->show();
347 updateFrameExtents();
348 updateOpacityCache();
349 }
350
351void Client::destroyDecoration()
352 {
353 if( decoration != NULL )
354 {
355 delete decoration;
356 decoration = NULL;
357 TQPoint grav = calculateGravitation( true );
358 border_left = border_right = border_top = border_bottom = 0;
359 setMask( TQRegion()); // reset shape mask
360 int save_workarea_diff_x = workarea_diff_x;
361 int save_workarea_diff_y = workarea_diff_y;
362 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
363 move( grav );
364 workarea_diff_x = save_workarea_diff_x;
365 workarea_diff_y = save_workarea_diff_y;
366 }
367 }
368
369void Client::checkBorderSizes()
370 {
371 if( decoration == NULL )
372 return;
373 int new_left, new_right, new_top, new_bottom;
374 decoration->borders( new_left, new_right, new_top, new_bottom );
375 if( new_left == border_left && new_right == border_right
376 && new_top == border_top && new_bottom == border_bottom )
377 return;
378 GeometryUpdatesPostponer blocker( this );
379 move( calculateGravitation( true ));
380 border_left = new_left;
381 border_right = new_right;
382 border_top = new_top;
383 border_bottom = new_bottom;
384 if (border_left != new_left ||
385 border_right != new_right ||
386 border_top != new_top ||
387 border_bottom != new_bottom)
388 move( calculateGravitation( false ));
389 plainResize( sizeForClientSize( clientSize()), ForceGeometrySet );
390 checkWorkspacePosition();
391 }
392
393void Client::detectNoBorder()
394 {
395 if( Shape::hasShape( window()))
396 {
397 noborder = true;
398 return;
399 }
400 switch( windowType())
401 {
402 case NET::Desktop :
403 case NET::Dock :
404 case NET::TopMenu :
405 case NET::Splash :
406 noborder = true;
407 break;
408 case NET::Unknown :
409 case NET::Normal :
410 case NET::Toolbar :
411 case NET::Menu :
412 case NET::Dialog :
413 case NET::Utility :
414 noborder = false;
415 break;
416 default:
417 assert( false );
418 }
419 // NET::Override is some strange beast without clear definition, usually
420 // just meaning "noborder", so let's treat it only as such flag, and ignore it as
421 // a window type otherwise (SUPPORTED_WINDOW_TYPES_MASK doesn't include it)
422 if( info->windowType( SUPPORTED_WINDOW_TYPES_MASK | NET::OverrideMask ) == NET::Override )
423 noborder = true;
424 }
425
426void Client::detectShapable()
427 {
428 if( Shape::hasShape( window()))
429 return;
430 switch( windowType())
431 {
432 case NET::Desktop :
433 case NET::Dock :
434 case NET::TopMenu :
435 case NET::Splash :
436 break;
437 case NET::Unknown :
438 case NET::Normal :
439 case NET::Toolbar :
440 case NET::Menu :
441 case NET::Dialog :
442 case NET::Utility :
443 setShapable(false);
444 break;
445 default:
446 assert( false );
447 }
448 }
449
450void Client::updateFrameExtents()
451 {
452 NETStrut strut;
453 strut.left = border_left;
454 strut.right = border_right;
455 strut.top = border_top;
456 strut.bottom = border_bottom;
457 info->setFrameExtents( strut );
458 }
459
460// Resizes the decoration, and makes sure the decoration widget gets resize event
461// even if the size hasn't changed. This is needed to make sure the decoration
462// re-layouts (e.g. when options()->moveResizeMaximizedWindows() changes,
463// the decoration may turn on/off some borders, but the actual size
464// of the decoration stays the same).
465void Client::resizeDecoration( const TQSize& s )
466 {
467 if( decoration == NULL )
468 return;
469 TQSize oldsize = decoration->widget()->size();
470 decoration->resize( s );
471 if( oldsize == s )
472 {
473 TQResizeEvent e( s, oldsize );
474 TQApplication::sendEvent( decoration->widget(), &e );
475 }
476 if (!moveResizeMode && options->shadowEnabled(isActive()))
477 {
478 // If the user is manually resizing, let Client::leaveMoveResize()
479 // decide when to redraw the shadow
480 updateOpacityCache();
481 }
482 }
483
484bool Client::noBorder() const
485 {
486 return noborder || isFullScreen() || user_noborder || ( !user_noborder_forced && motif_noborder );
487 }
488
489bool Client::userCanSetNoBorder() const
490 {
491 return !noborder && !isFullScreen() && !isShade();
492 }
493
494bool Client::isUserNoBorder() const
495 {
496 return user_noborder;
497 }
498
499void Client::setUserNoBorder( bool set )
500 {
501 setUserNoBorder(set, true);
502 }
503
504void Client::setUserNoBorder( bool set, bool forced )
505 {
506 if( !userCanSetNoBorder())
507 return;
508 auto noBorderApply = rules()->applyNoBorder( set );
509 set = noBorderApply.value;
510 forced |= noBorderApply.wasApplied;
511
512 if( user_noborder == set && user_noborder_forced == forced )
513 return;
514 user_noborder = set;
515 user_noborder_forced = forced;
516 updateDecoration( true, false );
517 updateWindowRules();
518 }
519
520bool Client::isUserNoBorderForced() const
521 {
522 return user_noborder_forced;
523 }
524
525bool Client::isModalSystemNotification() const
526 {
527 unsigned char *data = 0;
528 Atom actual;
529 int format, result;
530 unsigned long n, left;
531 result = XGetWindowProperty(tqt_xdisplay(), window(), atoms->net_wm_system_modal_notification, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
532 if (result == Success && data && format == 32 )
533 {
534 return true;
535 }
536 return false;
537 }
538
539void Client::updateShape()
540 {
541 // workaround for #19644 - shaped windows shouldn't have decoration
542 if( shape() && !noBorder())
543 {
544 noborder = true;
545 updateDecoration( true );
546 }
547 updateOpacityCache();
548 if ( shape() )
549 {
550 XShapeCombineShape(tqt_xdisplay(), frameId(), ShapeBounding,
551 clientPos().x(), clientPos().y(),
552 window(), ShapeBounding, ShapeSet);
553 setShapable(true);
554 }
555 // !shape() mask setting is done in setMask() when the decoration
556 // calls it or when the decoration is created/destroyed
557
558 if( Shape::version() >= 0x11 ) // 1.1, has input shape support
559 { // There appears to be no way to find out if a window has input
560 // shape set or not, so always propagate the input shape
561 // (it's the same like the bounding shape by default).
562 // Also, build the shape using a helper window, not directly
563 // in the frame window, because the sequence set-shape-to-frame,
564 // remove-shape-of-client, add-input-shape-of-client has the problem
565 // that after the second step there's a hole in the input shape
566 // until the real shape of the client is added and that can make
567 // the window lose focus (which is a problem with mouse focus policies)
568 static Window helper_window = None;
569 if( helper_window == None )
570 helper_window = XCreateSimpleWindow( tqt_xdisplay(), tqt_xrootwin(),
571 0, 0, 1, 1, 0, 0, 0 );
572 XResizeWindow( tqt_xdisplay(), helper_window, width(), height());
573 XShapeCombineShape( tqt_xdisplay(), helper_window, ShapeInput, 0, 0,
574 frameId(), ShapeBounding, ShapeSet );
575 XShapeCombineShape( tqt_xdisplay(), helper_window, ShapeInput,
576 clientPos().x(), clientPos().y(),
577 window(), ShapeBounding, ShapeSubtract );
578 XShapeCombineShape( tqt_xdisplay(), helper_window, ShapeInput,
579 clientPos().x(), clientPos().y(),
580 window(), ShapeInput, ShapeUnion );
581 XShapeCombineShape( tqt_xdisplay(), frameId(), ShapeInput, 0, 0,
582 helper_window, ShapeInput, ShapeSet );
583 }
584 }
585
586void Client::setMask( const TQRegion& reg, int mode )
587 {
588 _mask = reg;
589 if( reg.isNull())
590 XShapeCombineMask( tqt_xdisplay(), frameId(), ShapeBounding, 0, 0,
591 None, ShapeSet );
592 else if( mode == X::Unsorted )
593 XShapeCombineRegion( tqt_xdisplay(), frameId(), ShapeBounding, 0, 0,
594 reg.handle(), ShapeSet );
595 else
596 {
597 TQMemArray< TQRect > rects = reg.rects();
598 XRectangle* xrects = new XRectangle[ rects.count() ];
599 for( unsigned int i = 0;
600 i < rects.count();
601 ++i )
602 {
603 xrects[ i ].x = rects[ i ].x();
604 xrects[ i ].y = rects[ i ].y();
605 xrects[ i ].width = rects[ i ].width();
606 xrects[ i ].height = rects[ i ].height();
607 }
608 XShapeCombineRectangles( tqt_xdisplay(), frameId(), ShapeBounding, 0, 0,
609 xrects, rects.count(), ShapeSet, mode );
610 delete[] xrects;
611 }
612 updateShape();
613 }
614
615TQRegion Client::mask() const
616 {
617 if( _mask.isEmpty())
618 return TQRegion( 0, 0, width(), height());
619 return _mask;
620 }
621
622void Client::setShapable(bool b)
623 {
624 long tmp = b?1:0;
625 XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shapable, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &tmp, 1L);
626 }
627
628void Client::hideClient( bool hide )
629 {
630 if( hidden == hide )
631 return;
632 hidden = hide;
633 updateVisibility();
634 }
635
639bool Client::isMinimizable() const
640 {
641 if( isSpecialWindow())
642 return false;
643 if( isModalSystemNotification())
644 return false;
645 if( isTransient())
646 { // #66868 - let other xmms windows be minimized when the mainwindow is minimized
647 bool shown_mainwindow = false;
648 ClientList mainclients = mainClients();
649 for( ClientList::ConstIterator it = mainclients.begin();
650 it != mainclients.end();
651 ++it )
652 {
653 if( (*it)->isShown( true ))
654 shown_mainwindow = true;
655 }
656 if( !shown_mainwindow )
657 return true;
658 }
659 // this is here because kicker's taskbar doesn't provide separate entries
660 // for windows with an explicitly given parent
661 // TODO perhaps this should be redone
662 if( transientFor() != NULL )
663 return false;
664 if( !wantsTabFocus()) // SELI - NET::Utility? why wantsTabFocus() - skiptaskbar? ?
665 return false;
666 return true;
667 }
668
672bool Client::keepAbove() const
673 {
674 if( isModalSystemNotification())
675 return true;
676 return keep_above;
677 }
678
682void Client::minimize( bool avoid_animation )
683 {
684 if ( !isMinimizable() || isMinimized())
685 return;
686
687 if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
688 info->setState(0, NET::Shaded);
689
690 Notify::raise( Notify::Minimize );
691
692 // SELI mainClients().isEmpty() ??? - and in unminimize() too
693 if ( mainClients().isEmpty() && isOnCurrentDesktop() && isShown( true ) && !avoid_animation )
694 animateMinimizeOrUnminimize( true ); // was visible or shaded
695
696 minimized = true;
697
698 updateVisibility();
699 updateAllowedActions();
700 workspace()->updateMinimizedOfTransients( this );
701 updateWindowRules();
702 workspace()->updateFocusChains( this, Workspace::FocusChainMakeLast );
703 }
704
705void Client::unminimize( bool avoid_animation )
706 {
707 if (!queryUserSuspendedResume())
708 return;
709
710 if( !isMinimized())
711 return;
712
713 if (isShade()) // NETWM restriction - KWindowInfo::isMinimized() == Hidden && !Shaded
714 info->setState(NET::Shaded, NET::Shaded);
715
716 Notify::raise( Notify::UnMinimize );
717 minimized = false;
718 if( isOnCurrentDesktop() && isShown( true ))
719 {
720 if( mainClients().isEmpty() && !avoid_animation )
721 animateMinimizeOrUnminimize( false );
722 }
723 updateVisibility();
724 updateAllowedActions();
725 workspace()->updateMinimizedOfTransients( this );
726 updateWindowRules();
727 }
728
729extern bool blockAnimation;
730
731void Client::animateMinimizeOrUnminimize( bool minimize )
732 {
733 if ( blockAnimation )
734 return;
735 if ( !options->animateMinimize )
736 return;
737
738 if( decoration != NULL && decoration->animateMinimize( minimize ))
739 return; // decoration did it
740
741 // the function is a bit tricky since it will ensure that an
742 // animation action needs always the same time regardless of the
743 // performance of the machine or the X-Server.
744
745 float lf,rf,tf,bf,step;
746
747 int speed = options->animateMinimizeSpeed;
748 if ( speed > 10 )
749 speed = 10;
750 if ( speed < 0 )
751 speed = 0;
752
753 step = 40. * (11 - speed );
754
755 NETRect r = info->iconGeometry();
756 TQRect icongeom( r.pos.x, r.pos.y, r.size.width, r.size.height );
757 if ( !icongeom.isValid() )
758 return;
759
760 TQPixmap pm = animationPixmap( minimize ? width() : icongeom.width() );
761
762 TQRect before, after;
763 if ( minimize )
764 {
765 before = TQRect( x(), y(), width(), pm.height() );
766 after = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
767 }
768 else
769 {
770 before = TQRect( icongeom.x(), icongeom.y(), icongeom.width(), pm.height() );
771 after = TQRect( x(), y(), width(), pm.height() );
772 }
773
774 lf = (after.left() - before.left())/step;
775 rf = (after.right() - before.right())/step;
776 tf = (after.top() - before.top())/step;
777 bf = (after.bottom() - before.bottom())/step;
778
779 grabXServer();
780
781 TQRect area = before;
782 TQRect area2;
783 TQPixmap pm2;
784
785 TQTime t;
786 t.start();
787 float diff;
788
789 TQPainter p ( workspace()->desktopWidget() );
790 bool need_to_clear = false;
791 TQPixmap pm3;
792 do
793 {
794 if (area2 != area)
795 {
796 pm = animationPixmap( area.width() );
797 pm2 = TQPixmap::grabWindow( tqt_xrootwin(), area.x(), area.y(), area.width(), area.height() );
798 p.drawPixmap( area.x(), area.y(), pm );
799 if ( need_to_clear )
800 {
801 p.drawPixmap( area2.x(), area2.y(), pm3 );
802 need_to_clear = false;
803 }
804 area2 = area;
805 }
806 XFlush(tqt_xdisplay());
807 XSync( tqt_xdisplay(), False );
808 diff = t.elapsed();
809 if (diff > step)
810 diff = step;
811 area.setLeft(before.left() + int(diff*lf));
812 area.setRight(before.right() + int(diff*rf));
813 area.setTop(before.top() + int(diff*tf));
814 area.setBottom(before.bottom() + int(diff*bf));
815 if (area2 != area )
816 {
817 if ( area2.intersects( area ) )
818 p.drawPixmap( area2.x(), area2.y(), pm2 );
819 else
820 { // no overlap, we can clear later to avoid flicker
821 pm3 = pm2;
822 need_to_clear = true;
823 }
824 }
825 } while ( t.elapsed() < step);
826 if (area2 == area || need_to_clear )
827 p.drawPixmap( area2.x(), area2.y(), pm2 );
828
829 p.end();
830 ungrabXServer();
831 }
832
833
837TQPixmap Client::animationPixmap( int w )
838 {
839 TQFont font = options->font(isActive());
840 TQFontMetrics fm( font );
841 TQPixmap pm( w, fm.lineSpacing() );
842 pm.fill( options->color(Options::ColorTitleBar, isActive() || isMinimized() ) );
843 TQPainter p( &pm );
844 p.setPen(options->color(Options::ColorFont, isActive() || isMinimized() ));
845 p.setFont(options->font(isActive()));
846 p.drawText( pm.rect(), AlignLeft|AlignVCenter|SingleLine, caption() );
847 return pm;
848 }
849
850
851bool Client::isShadeable() const
852 {
853 return !isSpecialWindow() && !noBorder();
854 }
855
856void Client::setShade( ShadeMode mode )
857 {
858 if( !isShadeable())
859 return;
860 if( isModalSystemNotification())
861 return;
862 mode = rules()->checkShade( mode );
863 if( shade_mode == mode )
864 return;
865 bool was_shade = isShade();
866 ShadeMode was_shade_mode = shade_mode;
867 shade_mode = mode;
868 if( was_shade == isShade())
869 {
870 if( decoration != NULL ) // decoration may want to update after e.g. hover-shade changes
871 decoration->shadeChange();
872 return; // no real change in shaded state
873 }
874
875 if( shade_mode == ShadeNormal )
876 {
877 if ( isShown( true ) && isOnCurrentDesktop())
878 Notify::raise( Notify::ShadeUp );
879 }
880 else if( shade_mode == ShadeNone )
881 {
882 if( isShown( true ) && isOnCurrentDesktop())
883 Notify::raise( Notify::ShadeDown );
884 }
885
886 assert( decoration != NULL ); // noborder windows can't be shaded
887 GeometryUpdatesPostponer blocker( this );
888 // decorations may turn off some borders when shaded
889 decoration->borders( border_left, border_right, border_top, border_bottom );
890
891 int as = options->animateShade? 10 : 1;
892// TODO all this unmapping, resizing etc. feels too much duplicated from elsewhere
893 if ( isShade())
894 { // shade_mode == ShadeNormal
895 // we're about to shade, texx xcompmgr to prepare
896 long _shade = 1;
897 XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
898 // shade
899 int h = height();
900 shade_geometry_change = true;
901 TQSize s( sizeForClientSize( TQSize( clientSize())));
902 s.setHeight( border_top + border_bottom );
903 XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
904 XUnmapWindow( tqt_xdisplay(), wrapper );
905 XUnmapWindow( tqt_xdisplay(), client );
906 XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
907 //as we hid the unmap event, xcompmgr didn't recognize the client wid has vanished, so we'll extra inform it
908 //done xcompmgr workaround
909// FRAME repaint( false );
910// bool wasStaticContents = testWFlags( WStaticContents );
911// setWFlags( WStaticContents );
912 int step = TQMAX( 4, TQABS( h - s.height() ) / as )+1;
913 do
914 {
915 h -= step;
916 XResizeWindow( tqt_xdisplay(), frameId(), s.width(), h );
917 resizeDecoration( TQSize( s.width(), h ));
918 TQApplication::syncX();
919 } while ( h > s.height() + step );
920// if ( !wasStaticContents )
921// clearWFlags( WStaticContents );
922 plainResize( s );
923 shade_geometry_change = false;
924 if( isActive())
925 {
926 if( was_shade_mode == ShadeHover )
927 workspace()->activateNextClient( this );
928 else
929 workspace()->focusToNull();
930 }
931 // tell xcompmgr shade's done
932 _shade = 2;
933 XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shade, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &_shade, 1L);
934 }
935 else
936 {
937 int h = height();
938 shade_geometry_change = true;
939 TQSize s( sizeForClientSize( clientSize()));
940// FRAME bool wasStaticContents = testWFlags( WStaticContents );
941// setWFlags( WStaticContents );
942 int step = TQMAX( 4, TQABS( h - s.height() ) / as )+1;
943 do
944 {
945 h += step;
946 XResizeWindow( tqt_xdisplay(), frameId(), s.width(), h );
947 resizeDecoration( TQSize( s.width(), h ));
948 // assume a border
949 // we do not have time to wait for X to send us paint events
950// FRAME repaint( 0, h - step-5, width(), step+5, true);
951 TQApplication::syncX();
952 } while ( h < s.height() - step );
953// if ( !wasStaticContents )
954// clearWFlags( WStaticContents );
955 shade_geometry_change = false;
956 plainResize( s );
957 if( shade_mode == ShadeHover || shade_mode == ShadeActivated )
958 setActive( true );
959 XMapWindow( tqt_xdisplay(), wrapperId());
960 XMapWindow( tqt_xdisplay(), window());
961 XDeleteProperty (tqt_xdisplay(), client, atoms->net_wm_window_shade);
962 if (options->shadowEnabled(false))
963 {
964 for (ClientList::ConstIterator it = transients().begin();
965 it != transients().end(); ++it)
966 {
967 (*it)->removeShadow();
968 (*it)->drawDelayedShadow();
969 }
970 }
971
972 if ( isActive() )
973 workspace()->requestFocus( this );
974 }
975 checkMaximizeGeometry();
976 info->setState( (isShade() && !isMinimized()) ? NET::Shaded : 0, NET::Shaded );
977 info->setState( isShown( false ) ? 0 : NET::Hidden, NET::Hidden );
978 updateVisibility();
979 updateAllowedActions();
980 workspace()->updateMinimizedOfTransients( this );
981 decoration->shadeChange();
982 updateWindowRules();
983 }
984
985void Client::configureRequestTimeout()
986 {
987 inhibitConfigureRequests = false;
988 sendSyntheticConfigureNotify();
989 }
990
991void Client::shadeHover()
992 {
993 setShade( ShadeHover );
994 cancelShadeHover();
995 }
996
997void Client::cancelShadeHover()
998 {
999 delete shadeHoverTimer;
1000 shadeHoverTimer = 0;
1001 }
1002
1003void Client::toggleShade()
1004 {
1005 // if the mode is ShadeHover or ShadeActive, cancel shade too
1006 setShade( shade_mode == ShadeNone ? ShadeNormal : ShadeNone );
1007 }
1008
1009void Client::updateVisibility()
1010 {
1011 if( deleting )
1012 return;
1013 bool show = true;
1014 if( hidden )
1015 {
1016 setMappingState( IconicState );
1017 info->setState( NET::Hidden, NET::Hidden );
1018 setSkipTaskbar( true, false ); // also hide from taskbar
1019 rawHide();
1020 show = false;
1021 }
1022 else
1023 {
1024 setSkipTaskbar( original_skip_taskbar, false );
1025 }
1026 if( minimized )
1027 {
1028 setMappingState( IconicState );
1029 info->setState( NET::Hidden, NET::Hidden );
1030 rawHide();
1031 show = false;
1032 }
1033 if( show )
1034 info->setState( 0, NET::Hidden );
1035 if( !isOnCurrentDesktop())
1036 {
1037 setMappingState( IconicState );
1038 rawHide();
1039 show = false;
1040 }
1041 if( show )
1042 {
1043 bool belongs_to_desktop = false;
1044 for( ClientList::ConstIterator it = group()->members().begin();
1045 it != group()->members().end();
1046 ++it )
1047 if( (*it)->isDesktop())
1048 {
1049 belongs_to_desktop = true;
1050 break;
1051 }
1052 if( !belongs_to_desktop && workspace()->showingDesktop())
1053 workspace()->resetShowingDesktop( true );
1054 if( isShade())
1055 setMappingState( IconicState );
1056 else
1057 setMappingState( NormalState );
1058 rawShow();
1059 }
1060 }
1061
1062void Client::setShadowed(bool shadowed)
1063{
1064 bool wasShadowed;
1065
1066 wasShadowed = isShadowed();
1067 shadowMe = options->shadowEnabled(isActive()) ? shadowed : false;
1068
1069 if (shadowMe) {
1070 if (!wasShadowed)
1071 drawShadow();
1072 }
1073 else {
1074 if (wasShadowed) {
1075 removeShadow();
1076
1077 if (!activeOpacityCache.isNull())
1078 activeOpacityCache.resize(0);
1079 if (!inactiveOpacityCache.isNull())
1080 inactiveOpacityCache.resize(0);
1081 }
1082 }
1083}
1084
1085void Client::updateOpacityCache()
1086{
1087 if (!activeOpacityCache.isNull())
1088 activeOpacityCache.resize(0);
1089 if (!inactiveOpacityCache.isNull())
1090 inactiveOpacityCache.resize(0);
1091
1092 if (!moveResizeMode) {
1093 // If the user is manually resizing, let Client::finishMoveResize()
1094 // decide when to redraw the shadow
1095 removeShadow();
1096 drawIntersectingShadows();
1097 if (options->shadowEnabled(isActive()))
1098 drawDelayedShadow();
1099 }
1100}
1101
1106void Client::drawIntersectingShadows() {
1107 //Client *reshadowClient;
1108 TQRegion region;
1109 //TQPtrList<Client> reshadowClients;
1110 TQValueList<Client *> reshadowClients;
1111 TQValueListIterator<ShadowRegion> it;
1112 TQValueListIterator<Client *> it2;
1113
1114 if (!options->shadowEnabled(false))
1115 // No point in redrawing overlapping/overlapped shadows if only the
1116 // active window has a shadow.
1117 return;
1118
1119 region = shapeBoundingRegion;
1120
1121 // Generate list of Clients whose shadows need to be redrawn. That is,
1122 // those that are currently intersecting or intersected by other windows or
1123 // shadows.
1124 for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
1125 if ((isOnAllDesktops() || (*it).client->isOnCurrentDesktop()) &&
1126 !(*it).region.intersect(region).isEmpty())
1127 reshadowClients.append((*it).client);
1128
1129 // Redraw shadows for each of the Clients in the list generated above
1130 for (it2 = reshadowClients.begin(); it2 != reshadowClients.end();
1131 ++it2) {
1132 (*it2)->removeShadow();
1133 (*it2)->drawDelayedShadow();
1134 }
1135}
1136
1142void Client::drawOverlappingShadows(bool waitForMe)
1143{
1144 Client *aClient;
1145 TQRegion region;
1146 TQValueList<Client *> reshadowClients;
1147 ClientList stacking_order;
1148 ClientList::ConstIterator it;
1149 TQValueListIterator<ShadowRegion> it2;
1150 TQValueListIterator<Client *> it3;
1151
1152 if (!options->shadowEnabled(false))
1153 // No point in redrawing overlapping/overlapped shadows if only the
1154 // active window has a shadow.
1155 return;
1156
1157 region = shapeBoundingRegion;
1158
1159 stacking_order = workspace()->stackingOrder();
1160 for (it = stacking_order.fromLast(); it != stacking_order.end(); --it) {
1161 // Find the position of this window in the stacking order.
1162 if ((*it) == this)
1163 break;
1164 }
1165 ++it;
1166 while (it != stacking_order.end()) {
1167 if ((*it)->windowType() == NET::Dock) {
1168 // This function is only interested in windows whose shadows don't
1169 // have weird stacking rules.
1170 ++it;
1171 continue;
1172 }
1173
1174 // Generate list of Clients whose shadows need to be redrawn. That is,
1175 // those that are currently overlapping or overlapped by other windows
1176 // or shadows. The list should be in order from bottom to top in the
1177 // stacking order.
1178 for (it2 = shadowRegions.begin(); it2 != shadowRegions.end(); ++it2) {
1179 if ((*it2).client == (*it)) {
1180 if ((isOnAllDesktops() || (*it2).client->isOnCurrentDesktop())
1181 && !(*it2).region.intersect(region).isEmpty())
1182 reshadowClients.append((*it2).client);
1183 }
1184 }
1185 ++it;
1186 }
1187
1188 // Redraw shadows for each of the Clients in the list generated above
1189 for (it3 = reshadowClients.begin(); it3 != reshadowClients.end(); ++it3) {
1190 (*it3)->removeShadow();
1191 if (it3 == reshadowClients.begin()) {
1192 if (waitForMe)
1193 (*it3)->drawShadowAfter(this);
1194 else
1195 (*it3)->drawDelayedShadow();
1196 }
1197 else {
1198 --it3;
1199 aClient = (*it3);
1200 ++it3;
1201 (*it3)->drawShadowAfter(aClient);
1202 }
1203 }
1204}
1205
1210void Client::drawDelayedShadow()
1211{
1212 shadowDelayTimer->stop();
1213 shadowDelayTimer->start(SHADOW_DELAY, true);
1214}
1215
1219void Client::drawShadowAfter(Client *after)
1220{
1221 shadowAfterClient = after;
1222 connect(after, TQ_SIGNAL(shadowDrawn()), TQ_SLOT(drawShadow()));
1223}
1224
1228void Client::drawShadow()
1229{
1230 Window shadows[2];
1231 XRectangle *shapes;
1232 int i, count, ordering;
1233
1234 // If we are waiting for another Client's shadow to be drawn, stop waiting now
1235 if (shadowAfterClient != NULL) {
1236 disconnect(shadowAfterClient, TQ_SIGNAL(shadowDrawn()), this, TQ_SLOT(drawShadow()));
1237 shadowAfterClient = NULL;
1238 }
1239
1240 if (!isOnCurrentDesktop())
1241 return;
1242
1243 /* Store this window's ShapeBoundingRegion even if shadows aren't drawn for
1244 * this type of window. Otherwise, drawIntersectingShadows() won't update
1245 * properly when this window is moved/resized/hidden/closed.
1246 */
1247 shapes = XShapeGetRectangles(tqt_xdisplay(), frameId(), ShapeBounding,
1248 &count, &ordering);
1249 if (!shapes)
1250 // XShape extension not supported
1251 shapeBoundingRegion = TQRegion(x(), y(), width(), height());
1252 else {
1253 shapeBoundingRegion = TQRegion();
1254 for (i = 0; i < count; i++) {
1255 // Translate XShaped window into a TQRegion
1256 TQRegion shapeRectangle(shapes[i].x, shapes[i].y, shapes[i].width,
1257 shapes[i].height);
1258 shapeBoundingRegion += shapeRectangle;
1259 }
1260 if (isShade())
1261 // Since XResize() doesn't change a window's XShape regions, ensure that
1262 // shapeBoundingRegion is not taller than the window's shaded height,
1263 // or the bottom shadow will appear to be missing
1264 shapeBoundingRegion &= TQRegion(0, 0, width(), height());
1265 shapeBoundingRegion.translate(x(), y());
1266 }
1267
1268 if (!isShadowed() || hidden || isMinimized() ||
1269 maximizeMode() == MaximizeFull ||
1270 !options->shadowWindowType(windowType())) {
1271 XFree(shapes);
1272
1273 // Tell whatever Clients are listening that this Client's shadow has been drawn.
1274 // It hasn't, but there's no sense waiting for something that won't happen.
1275 emit shadowDrawn();
1276
1277 return;
1278 }
1279
1280 removeShadow();
1281
1282 TQMemArray<TQRgb> pixelData;
1283 TQPixmap shadowPixmap;
1284 TQRect shadow;
1285 TQRegion exposedRegion;
1286 ShadowRegion shadowRegion;
1287 int thickness, xOffset, yOffset;
1288
1289 thickness = options->shadowThickness(isActive());
1290 xOffset = options->shadowXOffset(isActive());
1291 yOffset = options->shadowYOffset(isActive());
1292 opacityCache = active? &activeOpacityCache : &inactiveOpacityCache;
1293
1294 shadow.setRect(x() - thickness + xOffset, y() - thickness + yOffset,
1295 width() + thickness * 2, height() + thickness * 2);
1296 shadowPixmap.resize(shadow.size());
1297
1298 // Create a fake drop-down shadow effect via blended Xwindows
1299 shadowWidget = new TQWidget(0, 0, (WFlags)(WStyle_Customize | WX11BypassWM));
1300 shadowWidget->setGeometry(shadow);
1301 XSelectInput(tqt_xdisplay(), shadowWidget->winId(),
1302 ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
1303 shadowWidget->installEventFilter(this);
1304
1305 if (!shapes) {
1306 // XShape extension not supported
1307 exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
1308 shadow.y(), shadow.width(), shadow.height(), thickness,
1309 xOffset, yOffset);
1310 shadowRegion.region = exposedRegion;
1311 shadowRegion.client = this;
1312 shadowRegions.append(shadowRegion);
1313
1314 if (opacityCache->isNull())
1315 imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
1316 exposedRegion, thickness,
1317 options->shadowOpacity(isActive()));
1318 else
1319 imposeCachedShadow(shadowPixmap, exposedRegion);
1320 }
1321 else {
1322 TQMemArray<TQRect> exposedRects;
1323 TQMemArray<TQRect>::Iterator it, itEnd;
1324 XRectangle *shadowShapes;
1325
1326 exposedRegion = getExposedRegion(shapeBoundingRegion, shadow.x(),
1327 shadow.y(), shadow.width(), shadow.height(), thickness,
1328 xOffset, yOffset);
1329 shadowRegion.region = exposedRegion;
1330 shadowRegion.client = this;
1331 shadowRegions.append(shadowRegion);
1332
1333 // XShape the shadow
1334 exposedRects = exposedRegion.rects();
1335 i = 0;
1336 itEnd = exposedRects.end();
1337 shadowShapes = new XRectangle[exposedRects.count()];
1338 for (it = exposedRects.begin(); it != itEnd; ++it) {
1339 shadowShapes[i].x = (*it).x();
1340 shadowShapes[i].y = (*it).y();
1341 shadowShapes[i].width = (*it).width();
1342 shadowShapes[i].height = (*it).height();
1343 i++;
1344 }
1345 XShapeCombineRectangles(tqt_xdisplay(), shadowWidget->winId(),
1346 ShapeBounding, -x() + thickness - xOffset,
1347 -y() + thickness - yOffset, shadowShapes, i, ShapeSet,
1348 Unsorted);
1349 delete [] shadowShapes;
1350
1351 if (opacityCache->isNull())
1352 imposeRegionShadow(shadowPixmap, shapeBoundingRegion,
1353 exposedRegion, thickness,
1354 options->shadowOpacity(isActive()));
1355 else
1356 imposeCachedShadow(shadowPixmap, exposedRegion);
1357 }
1358
1359 XFree(shapes);
1360
1361 // Set the background pixmap
1362 //shadowPixmap.convertFromImage(shadowImage);
1363 shadowWidget->setErasePixmap(shadowPixmap);
1364
1365 // Restack shadows under this window so that shadows drawn for a newly
1366 // focused (but not raised) window don't overlap any windows above it.
1367 if (isDock()) {
1368 ClientList stacking_order = workspace()->stackingOrder();
1369 for (ClientList::ConstIterator it = stacking_order.begin(); it != stacking_order.end(); ++it)
1370 if ((*it)->isDesktop())
1371 {
1372 ++it;
1373 shadows[0] = (*it)->frameId();
1374 shadows[1] = shadowWidget->winId();
1375 }
1376 }
1377 else {
1378 shadows[0] = frameId();
1379 if (shadowWidget != NULL)
1380 shadows[1] = shadowWidget->winId();
1381 }
1382
1383 XRestackWindows(tqt_xdisplay(), shadows, 2);
1384
1385 // Don't use TQWidget::show() so we don't confuse QEffects, thus causing
1386 // broken focus.
1387 XMapWindow(tqt_xdisplay(), shadowWidget->winId());
1388
1389 // Tell whatever Clients are listening that this Client's shadow has been drawn.
1390 emit shadowDrawn();
1391}
1392
1396void Client::removeShadow()
1397{
1398 TQValueList<ShadowRegion>::Iterator it;
1399
1400 shadowDelayTimer->stop();
1401
1402 if (shadowWidget != NULL) {
1403 for (it = shadowRegions.begin(); it != shadowRegions.end(); ++it)
1404 if ((*it).client == this) {
1405 shadowRegions.remove(it);
1406 break;
1407 }
1408 delete shadowWidget;
1409 shadowWidget = NULL;
1410 }
1411}
1412
1417TQRegion Client::getExposedRegion(TQRegion occludedRegion, int x, int y, int w,
1418 int h, int thickness, int xOffset, int yOffset)
1419{
1420 TQRegion exposedRegion;
1421
1422 exposedRegion = TQRegion(x, y, w, h);
1423 exposedRegion -= occludedRegion;
1424
1425 if (thickness > 0) {
1426 // Limit exposedRegion to include only where a shadow of the specified
1427 // thickness will be drawn
1428 TQMemArray<TQRect> occludedRects;
1429 TQMemArray<TQRect>::Iterator it, itEnd;
1430 TQRegion shadowRegion;
1431
1432 occludedRects = occludedRegion.rects();
1433 itEnd = occludedRects.end();
1434 for (it = occludedRects.begin(); it != itEnd; ++it) {
1435 // Expand each of the occluded region's shape rectangles to contain
1436 // where a shadow of the specified thickness will be drawn. Create
1437 // a new TQRegion that contains the expanded occluded region
1438 it->setTop(it->top() - thickness + yOffset);
1439 it->setLeft(it->left() - thickness + xOffset);
1440 it->setRight(it->right() + thickness + xOffset);
1441 it->setBottom(it->bottom() + thickness + yOffset);
1442 shadowRegion += TQRegion(*it);
1443 }
1444 exposedRegion -= exposedRegion - shadowRegion;
1445 }
1446
1447 return exposedRegion;
1448}
1449
1453void Client::imposeCachedShadow(TQPixmap &pixmap, TQRegion exposed)
1454{
1455 TQRgb pixel;
1456 double opacity;
1457 int red, green, blue, pixelRed, pixelGreen, pixelBlue;
1458 int subW, subH, w, x, y, zeroX, zeroY;
1459 TQImage image;
1460 TQMemArray<TQRect>::Iterator it, itEnd;
1461 TQMemArray<TQRect> rectangles;
1462 TQPixmap subPixmap;
1463 Window rootWindow;
1464 int thickness, windowX, windowY, xOffset, yOffset;
1465
1466 rectangles = exposed.rects();
1467 rootWindow = tqt_xrootwin();
1468 thickness = options->shadowThickness(isActive());
1469 windowX = this->x();
1470 windowY = this->y();
1471 xOffset = options->shadowXOffset(isActive());
1472 yOffset = options->shadowYOffset(isActive());
1473 options->shadowColour(isActive()).rgb(&red, &green, &blue);
1474 w = pixmap.width();
1475
1476 itEnd = rectangles.end();
1477 for (it = rectangles.begin(); it != itEnd; ++it) {
1478 subW = (*it).width();
1479 subH = (*it).height();
1480 subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
1481 subW, subH);
1482 zeroX = (*it).x() - windowX + thickness - xOffset;
1483 zeroY = (*it).y() - windowY + thickness - yOffset;
1484 image = subPixmap.convertToImage();
1485
1486 for (x = 0; x < subW; x++) {
1487 for (y = 0; y < subH; y++) {
1488 opacity = (*(opacityCache))[(zeroY + y) * w + zeroX + x];
1489 pixel = image.pixel(x, y);
1490 pixelRed = tqRed(pixel);
1491 pixelGreen = tqGreen(pixel);
1492 pixelBlue = tqBlue(pixel);
1493 image.setPixel(x, y,
1494 tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
1495 (int)(pixelGreen + (green - pixelGreen) * opacity),
1496 (int)(pixelBlue + (blue - pixelBlue) * opacity)));
1497 }
1498 }
1499
1500 subPixmap.convertFromImage(image);
1501 bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
1502 }
1503}
1504
1508void Client::imposeRegionShadow(TQPixmap &pixmap, TQRegion occluded,
1509 TQRegion exposed, int thickness, double maxOpacity)
1510{
1511 int distance, intersectCount, i, j, x, y;
1512 TQRgb pixel;
1513 double decay, factor, opacity;
1514 int red, green, blue, pixelRed, pixelGreen, pixelBlue;
1515 int lineIntersects, maxIntersects, maxY;
1516 int irBottom, irLeft, irRight, irTop, yIncrement;
1517 int subW, subH, w, h, zeroX, zeroY;
1518 TQImage image;
1519 TQMemArray<TQRect>::Iterator it, itEnd;
1520 TQMemArray<TQRect> rectangles;
1521 TQPixmap subPixmap;
1522 Window rootWindow;
1523 int windowX, windowY, xOffset, yOffset;
1524
1525 rectangles = exposed.rects();
1526 rootWindow = tqt_xrootwin();
1527 windowX = this->x();
1528 windowY = this->y();
1529 xOffset = options->shadowXOffset(isActive());
1530 yOffset = options->shadowYOffset(isActive());
1531 options->shadowColour(isActive()).rgb(&red, &green, &blue);
1532 maxIntersects = thickness * thickness * 4 + (thickness * 4) + 1;
1533 lineIntersects = thickness * 2 + 1;
1534 factor = maxIntersects / maxOpacity;
1535 decay = (lineIntersects / 0.0125 - factor) / pow((double)maxIntersects, 3.0);
1536 w = pixmap.width();
1537 h = pixmap.height();
1538 xOffset = options->shadowXOffset(isActive());
1539 yOffset = options->shadowYOffset(isActive());
1540
1541 opacityCache->resize(0);
1542 opacityCache->resize(w * h);
1543 occluded.translate(-windowX + thickness, -windowY + thickness);
1544
1545 itEnd = rectangles.end();
1546 for (it = rectangles.begin(); it != itEnd; ++it) {
1547 subW = (*it).width();
1548 subH = (*it).height();
1549 subPixmap = TQPixmap::grabWindow(rootWindow, (*it).x(), (*it).y(),
1550 subW, subH);
1551 maxY = subH;
1552 zeroX = (*it).x() - windowX + thickness - xOffset;
1553 zeroY = (*it).y() - windowY + thickness - yOffset;
1554 image = subPixmap.convertToImage();
1555
1556 intersectCount = 0;
1557 opacity = -1;
1558 y = 0;
1559 yIncrement = 1;
1560 for (x = 0; x < subW; x++) {
1561 irLeft = zeroX + x - thickness;
1562 irRight = zeroX + x + thickness;
1563
1564 while (y != maxY) {
1565 // horizontal row about to leave the intersect region, not
1566 // necessarily the top row
1567 irTop = zeroY + y - thickness * yIncrement;
1568 // horizontal row that just came into the intersect region,
1569 // not necessarily the bottom row
1570 irBottom = zeroY + y + thickness * yIncrement;
1571
1572 if (opacity == -1) {
1573 // If occluded pixels caused an intersect count to be
1574 // skipped, recount it
1575 intersectCount = 0;
1576
1577 for (j = irTop; j != irBottom; j += yIncrement) {
1578 // irTop is not necessarily larger than irBottom and
1579 // yIncrement isn't necessarily positive
1580 for (i = irLeft; i <= irRight; i++) {
1581 if (occluded.contains(TQPoint(i, j)))
1582 intersectCount++;
1583 }
1584 }
1585 }
1586 else {
1587 if (intersectCount < 0)
1588 intersectCount = 0;
1589
1590 for (i = irLeft; i <= irRight; i++) {
1591 if (occluded.contains(TQPoint(i, irBottom)))
1592 intersectCount++;
1593 }
1594 }
1595
1596 distance = maxIntersects - intersectCount;
1597 opacity = intersectCount / (factor + pow((double)distance, 3.0) * decay);
1598
1599 (*(opacityCache))[(zeroY + y) * w + zeroX + x] = opacity;
1600 pixel = image.pixel(x, y);
1601 pixelRed = tqRed(pixel);
1602 pixelGreen = tqGreen(pixel);
1603 pixelBlue = tqBlue(pixel);
1604 image.setPixel(x, y,
1605 tqRgb((int)(pixelRed + (red - pixelRed) * opacity),
1606 (int)(pixelGreen + (green - pixelGreen) * opacity),
1607 (int)(pixelBlue + (blue - pixelBlue) * opacity)));
1608
1609 for (i = irLeft; i <= irRight; i++) {
1610 if (occluded.contains(TQPoint(i, irTop)))
1611 intersectCount--;
1612 }
1613
1614 y += yIncrement;
1615 }
1616 y -= yIncrement;
1617
1618 irTop += yIncrement;
1619 for (j = irTop; j != irBottom; j += yIncrement) {
1620 if (occluded.contains(TQPoint(irLeft, j)))
1621 intersectCount--;
1622 }
1623 irRight++;
1624 for (j = irTop; j != irBottom; j += yIncrement) {
1625 if (occluded.contains(TQPoint(irRight, j)))
1626 intersectCount++;
1627 }
1628
1629 yIncrement *= -1;
1630 if (yIncrement < 0)
1631 // Scan Y-axis bottom-up for next X-coordinate iteration
1632 maxY = -1;
1633 else
1634 // Scan Y-axis top-down for next X-coordinate iteration
1635 maxY = subH;
1636 }
1637
1638 subPixmap.convertFromImage(image);
1639 bitBlt(&pixmap, zeroX, zeroY, &subPixmap);
1640 }
1641}
1642
1647void Client::setMappingState(int s)
1648 {
1649 assert( client != None );
1650 assert( !deleting || s == WithdrawnState );
1651 if( mapping_state == s )
1652 return;
1653 bool was_unmanaged = ( mapping_state == WithdrawnState );
1654 mapping_state = s;
1655 if( mapping_state == WithdrawnState )
1656 {
1657 XDeleteProperty( tqt_xdisplay(), window(), tqt_wm_state );
1658 return;
1659 }
1660 assert( s == NormalState || s == IconicState );
1661
1662 unsigned long data[2];
1663 data[0] = (unsigned long) s;
1664 data[1] = (unsigned long) None;
1665 XChangeProperty(tqt_xdisplay(), window(), tqt_wm_state, tqt_wm_state, 32,
1666 PropModeReplace, (unsigned char *)data, 2);
1667
1668 if( was_unmanaged ) // manage() did postpone_geometry_updates = 1, now it's ok to finally set the geometry
1669 postponeGeometryUpdates( false );
1670 }
1671
1676void Client::rawShow()
1677 {
1678 if( decoration != NULL )
1679 decoration->widget()->show(); // not really necessary, but let it know the state
1680 XMapWindow( tqt_xdisplay(), frame );
1681 if( !isShade())
1682 {
1683 XMapWindow( tqt_xdisplay(), wrapper );
1684 XMapWindow( tqt_xdisplay(), client );
1685 }
1686 if (options->shadowEnabled(isActive()))
1687 drawDelayedShadow();
1688 }
1689
1695void Client::rawHide()
1696 {
1697// Here it may look like a race condition, as some other client might try to unmap
1698// the window between these two XSelectInput() calls. However, they're supposed to
1699// use XWithdrawWindow(), which also sends a synthetic event to the root window,
1700// which won't be missed, so this shouldn't be a problem. The chance the real UnmapNotify
1701// will be missed is also very minimal, so I don't think it's needed to grab the server
1702// here.
1703 removeShadow();
1704 drawIntersectingShadows();
1705 XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask ); // avoid getting UnmapNotify
1706 XUnmapWindow( tqt_xdisplay(), frame );
1707 XUnmapWindow( tqt_xdisplay(), wrapper );
1708 XUnmapWindow( tqt_xdisplay(), client );
1709 XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
1710 if( decoration != NULL )
1711 decoration->widget()->hide(); // not really necessary, but let it know the state
1712 workspace()->clientHidden( this );
1713 }
1714
1715void Client::sendClientMessage(Window w, Atom a, Atom protocol, long data1, long data2, long data3)
1716 {
1717 XEvent ev;
1718 long mask;
1719
1720 memset(&ev, 0, sizeof(ev));
1721 ev.xclient.type = ClientMessage;
1722 ev.xclient.window = w;
1723 ev.xclient.message_type = a;
1724 ev.xclient.format = 32;
1725 ev.xclient.data.l[0] = protocol;
1726 ev.xclient.data.l[1] = get_tqt_x_time();
1727 ev.xclient.data.l[2] = data1;
1728 ev.xclient.data.l[3] = data2;
1729 ev.xclient.data.l[4] = data3;
1730 mask = 0L;
1731 if (w == tqt_xrootwin())
1732 mask = SubstructureRedirectMask; /* magic! */
1733 XSendEvent(tqt_xdisplay(), w, False, mask, &ev);
1734 }
1735
1736/*
1737 Returns whether the window may be closed (have a close button)
1738 */
1739bool Client::isCloseable() const
1740 {
1741 if( isModalSystemNotification())
1742 return false;
1743 return rules()->checkCloseable( motif_may_close && !isSpecialWindow());
1744 }
1745
1750void Client::closeWindow()
1751 {
1752 if( !isCloseable())
1753 return;
1754 // Update user time, because the window may create a confirming dialog.
1755 updateUserTime();
1756 if ( Pdeletewindow )
1757 {
1758 Notify::raise( Notify::Close );
1759 sendClientMessage( window(), atoms->wm_protocols, atoms->wm_delete_window);
1760 pingWindow();
1761 }
1762 else
1763 {
1764 // client will not react on wm_delete_window. We have not choice
1765 // but destroy his connection to the XServer.
1766 killWindow();
1767 }
1768 }
1769
1770
1774void Client::killWindow()
1775 {
1776 kdDebug( 1212 ) << "Client::killWindow():" << caption() << endl;
1777 // not sure if we need an Notify::Kill or not.. until then, use
1778 // Notify::Close
1779 Notify::raise( Notify::Close );
1780
1781 if( isDialog())
1782 Notify::raise( Notify::TransDelete );
1783 if( isNormalWindow())
1784 Notify::raise( Notify::Delete );
1785 killProcess( false );
1786 // always kill this client at the server
1787 XKillClient(tqt_xdisplay(), window() );
1788 destroyClient();
1789 }
1790
1791// send a ping to the window using _NET_WM_PING if possible
1792// if it doesn't respond within a reasonable time, it will be
1793// killed
1794void Client::pingWindow()
1795 {
1796 if( !Pping )
1797 return; // can't ping :(
1798 if( options->killPingTimeout == 0 )
1799 return; // turned off
1800 if( ping_timer != NULL )
1801 return; // pinging already
1802 ping_timer = new TQTimer( this );
1803 connect( ping_timer, TQ_SIGNAL( timeout()), TQ_SLOT( pingTimeout()));
1804 ping_timer->start( options->killPingTimeout, true );
1805 ping_timestamp = get_tqt_x_time();
1806 workspace()->sendPingToWindow( window(), ping_timestamp );
1807 }
1808
1809void Client::gotPing( Time timestamp )
1810 {
1811 // just plain compare is not good enough because of 64bit and truncating and whatnot
1812 if( NET::timestampCompare( timestamp, ping_timestamp ) != 0 )
1813 return;
1814 delete ping_timer;
1815 ping_timer = NULL;
1816 if( process_killer != NULL )
1817 {
1818 process_killer->kill();
1819 delete process_killer;
1820 process_killer = NULL;
1821 }
1822 }
1823
1824void Client::pingTimeout()
1825 {
1826 kdDebug( 1212 ) << "Ping timeout:" << caption() << endl;
1827 delete ping_timer;
1828 ping_timer = NULL;
1829 killProcess( true, ping_timestamp );
1830 }
1831
1832void Client::killProcess( bool ask, Time timestamp )
1833 {
1834 if( process_killer != NULL )
1835 return;
1836 Q_ASSERT( !ask || timestamp != CurrentTime );
1837 TQCString machine = wmClientMachine( true );
1838 pid_t pid = info->pid();
1839 if( pid <= 0 || machine.isEmpty()) // needed properties missing
1840 return;
1841 kdDebug( 1212 ) << "Kill process:" << pid << "(" << machine << ")" << endl;
1842 if( !ask )
1843 {
1844 if( machine != "localhost" )
1845 {
1846 TDEProcess proc;
1847 proc << "xon" << machine << "kill" << pid;
1848 proc.start( TDEProcess::DontCare );
1849 }
1850 else
1851 ::kill( pid, SIGTERM );
1852 }
1853 else
1854 { // SELI TODO handle the window created by handler specially (on top,urgent?)
1855 process_killer = new TDEProcess( this );
1856 *process_killer << TDEStandardDirs::findExe( "twin_killer_helper" )
1857 << "--pid" << TQCString().setNum( pid ) << "--hostname" << machine
1858 << "--windowname" << caption().utf8()
1859 << "--applicationname" << resourceClass()
1860 << "--wid" << TQCString().setNum( window())
1861 << "--timestamp" << TQCString().setNum( timestamp );
1862 connect( process_killer, TQ_SIGNAL( processExited( TDEProcess* )),
1863 TQ_SLOT( processKillerExited()));
1864 if( !process_killer->start( TDEProcess::NotifyOnExit ))
1865 {
1866 delete process_killer;
1867 process_killer = NULL;
1868 return;
1869 }
1870 }
1871 }
1872
1873bool Client::isSuspendable() const
1874 {
1875 bool cansuspend = true;
1876 if( skipTaskbar() || skipPager() )
1877 return false;
1878 TQCString machine = wmClientMachine( true );
1879 pid_t pid = info->pid();
1880 if( pid <= 0 || machine.isEmpty()) // needed properties missing
1881 return false;
1882 kdDebug( 1212 ) << "Check suspendable process:" << pid << "(" << machine << ")" << endl;
1883 if( machine != "localhost" )
1884 {
1885 return false;
1886 }
1887 else
1888 {
1889#ifdef Q_OS_SOLARIS
1890 TQFile procStatFile(TQString("/proc/%1/lwp/1/lwpsinfo").arg(pid));
1891#else /* default */
1892 TQFile procStatFile(TQString("/proc/%1/stat").arg(pid));
1893#endif
1894 if (procStatFile.open(IO_ReadOnly))
1895 {
1896 TQByteArray statRaw = procStatFile.readAll();
1897 procStatFile.close();
1898#ifdef Q_OS_SOLARIS
1899 lwpsinfo_t *inf = (lwpsinfo_t *)statRaw.data();
1900 char tbuf[PATH_MAX];
1901 TQString tcomm;
1902 TQString state(TQChar(inf->pr_sname));
1903
1904 readlink(TQString("/proc/%1/path/a.out").arg(pid).latin1(),
1905 tbuf, sizeof(tbuf));
1906 tcomm = basename(tbuf);
1907#else /* default */
1908 TQString statString(statRaw);
1909 TQStringList statFields = TQStringList::split(" ", statString, true);
1910 TQString tcomm = statFields[1];
1911 TQString state = statFields[2];
1912#endif /* default */
1913 if( state != "T" )
1914 {
1915 // Make sure no windows of this process are special
1916 for ( ClientList::ConstIterator it = workspace()->clients.begin(); it != workspace()->clients.end(); ++it)
1917 {
1918 Client* nextclient = *it;
1919 pid_t nextpid = nextclient->info->pid();
1920 TQCString nextmachine = nextclient->wmClientMachine( true );
1921 if( nextpid > 0 && (!nextmachine.isEmpty()))
1922 {
1923 if( ( nextmachine == "localhost" ) && ( pid == nextpid ) )
1924 {
1925 if( nextclient->skipTaskbar() || nextclient->skipPager() )
1926 cansuspend = false;
1927 }
1928 }
1929 }
1930 // Process exception list
1931 TQString execname(tcomm);
1932 execname.truncate(execname.length()-1);
1933 execname = execname.remove(0,1);
1934 // FIXME This list should not be hardcoded
1935 if( (execname == "kdesktop") || (execname == "kicker") )
1936 return false;
1937 else
1938 return cansuspend;
1939 }
1940 else
1941 {
1942 return false;
1943 }
1944 }
1945 else
1946 {
1947 return false;
1948 }
1949 }
1950 }
1951
1952bool Client::isResumeable() const
1953 {
1954 TQCString machine = wmClientMachine( true );
1955 pid_t pid = info->pid();
1956 if( pid <= 0 || machine.isEmpty()) // needed properties missing
1957 return false;
1958 kdDebug( 1212 ) << "Check resumeable process:" << pid << "(" << machine << ")" << endl;
1959 if( machine != "localhost" )
1960 {
1961 return false;
1962 }
1963 else
1964 {
1965#ifdef Q_OS_SOLARIS
1966 TQFile procStatFile(TQString("/proc/%1/lwp/1/lwpsinfo").arg(pid));
1967#else /* default */
1968 TQFile procStatFile(TQString("/proc/%1/stat").arg(pid));
1969#endif
1970 if (procStatFile.open(IO_ReadOnly))
1971 {
1972 TQByteArray statRaw = procStatFile.readAll();
1973 procStatFile.close();
1974#ifdef Q_OS_SOLARIS
1975 lwpsinfo_t *inf = (lwpsinfo_t *)statRaw.data();
1976 TQString state(TQChar(inf->pr_sname));
1977#else /* default */
1978 TQString statString(statRaw);
1979 TQStringList statFields = TQStringList::split(" ", statString, true);
1980 TQString tcomm = statFields[1];
1981 TQString state = statFields[2];
1982#endif /* default */
1983 if( state == "T" )
1984 {
1985 return true;
1986 }
1987 else
1988 {
1989 return false;
1990 }
1991 }
1992 else
1993 {
1994 return false;
1995 }
1996 }
1997 }
1998
1999bool Client::queryUserSuspendedResume()
2000 {
2001 if (isResumeable())
2002 {
2003 if (process_resumer != NULL)
2004 {
2005 return false;
2006 }
2007 // FIXME We should display a busy cursor until twin_resumer_helper loads
2008 process_resumer = new TDEProcess( this );
2009 *process_resumer << TDEStandardDirs::findExe( "twin_resumer_helper" )
2010 << "--pid" << TQCString().setNum( info->pid() ) << "--hostname" << wmClientMachine( true )
2011 << "--windowname" << caption().utf8()
2012 << "--applicationname" << resourceClass()
2013 << "--wid" << TQCString().setNum( window());
2014 connect( process_resumer, TQ_SIGNAL( processExited( TDEProcess* )),
2015 TQ_SLOT( processResumerExited()));
2016 if( !process_resumer->start( TDEProcess::NotifyOnExit ))
2017 {
2018 delete process_resumer;
2019 process_resumer = NULL;
2020 return true;
2021 }
2022 return false;
2023 }
2024 else
2025 {
2026 return true;
2027 }
2028 }
2029
2030void Client::suspendWindow()
2031 {
2032 TQCString machine = wmClientMachine( true );
2033 pid_t pid = info->pid();
2034 if( pid <= 0 || machine.isEmpty()) // needed properties missing
2035 return;
2036 kdDebug( 1212 ) << "Suspend process:" << pid << "(" << machine << ")" << endl;
2037 if( machine != "localhost" )
2038 {
2039 return;
2040 }
2041 else
2042 {
2043 for ( ClientList::ConstIterator it = workspace()->clients.begin(); it != workspace()->clients.end(); ++it)
2044 {
2045 Client* nextclient = *it;
2046 pid_t nextpid = nextclient->info->pid();
2047 TQCString nextmachine = nextclient->wmClientMachine( true );
2048 if( nextpid > 0 && (!nextmachine.isEmpty()))
2049 {
2050 if( ( nextmachine == "localhost" ) && ( pid == nextpid ) )
2051 {
2052 TQString newCaption = TQString(readName()).append(" <").append(i18n("Suspended")).append(">");
2053 nextclient->info->setVisibleName(newCaption.utf8());
2054 nextclient->info->setVisibleIconName(newCaption.utf8());
2055 nextclient->minimized_before_suspend = nextclient->isMinimized();
2056 nextclient->minimize(true);
2057 }
2058 }
2059 }
2060 ::kill( pid, SIGSTOP );
2061 }
2062 }
2063
2064void Client::resumeWindow()
2065 {
2066 TQCString machine = wmClientMachine( true );
2067 pid_t pid = info->pid();
2068 if( pid <= 0 || machine.isEmpty()) // needed properties missing
2069 return;
2070 kdDebug( 1212 ) << "Resume process:" << pid << "(" << machine << ")" << endl;
2071 if( machine != "localhost" )
2072 {
2073 return;
2074 }
2075 else
2076 {
2077 ::kill( pid, SIGCONT );
2078 for ( ClientList::ConstIterator it = workspace()->clients.begin(); it != workspace()->clients.end(); ++it)
2079 {
2080 Client* nextclient = *it;
2081 pid_t nextpid = nextclient->info->pid();
2082 TQCString nextmachine = nextclient->wmClientMachine( true );
2083 if( nextpid > 0 && (!nextmachine.isEmpty()))
2084 {
2085 if( ( nextmachine == "localhost" ) && ( pid == nextpid ) )
2086 {
2087 if (!nextclient->minimized_before_suspend)
2088 {
2089 nextclient->unminimize(true);
2090 }
2091 nextclient->updateCaption();
2092 }
2093 }
2094 }
2095 }
2096 }
2097
2098void Client::processKillerExited()
2099 {
2100 kdDebug( 1212 ) << "Killer exited" << endl;
2101 delete process_killer;
2102 process_killer = NULL;
2103 }
2104
2105void Client::processResumerExited()
2106 {
2107 kdDebug( 1212 ) << "Resumer exited" << endl;
2108 // 0 means the user clicked Resume; 2 means that the resumer dialog failed to launch somehow
2109 if ((process_resumer->exitStatus() == 0) || (process_resumer->exitStatus() == 2))
2110 {
2111 resumeWindow();
2112 takeFocus( Allowed );
2113 }
2114 delete process_resumer;
2115 process_resumer = NULL;
2116 }
2117
2118void Client::setSkipTaskbar( bool b, bool from_outside )
2119 {
2120 int was_wants_tab_focus = wantsTabFocus();
2121 if( from_outside )
2122 {
2123 b = rules()->checkSkipTaskbar( b );
2124 original_skip_taskbar = b;
2125 }
2126 if ( b == skipTaskbar() )
2127 return;
2128 skip_taskbar = b;
2129 info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar );
2130 updateWindowRules();
2131 if( was_wants_tab_focus != wantsTabFocus())
2132 workspace()->updateFocusChains( this,
2133 isActive() ? Workspace::FocusChainMakeFirst : Workspace::FocusChainUpdate );
2134 }
2135
2136void Client::setSkipPager( bool b )
2137 {
2138 b = rules()->checkSkipPager( b );
2139 if ( b == skipPager() )
2140 return;
2141 skip_pager = b;
2142 info->setState( b?NET::SkipPager:0, NET::SkipPager );
2143 updateWindowRules();
2144 }
2145
2146void Client::setModal( bool m )
2147 { // Qt-3.2 can have even modal normal windows :(
2148 if( modal == m )
2149 return;
2150 modal = m;
2151 if( !modal )
2152 return;
2153 // changing modality for a mapped window is weird (?)
2154 // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
2155 }
2156
2157void Client::setDesktop( int desktop )
2158 {
2159 if( desktop != NET::OnAllDesktops ) // do range check
2160 desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
2161 desktop = rules()->checkDesktop( desktop );
2162 if( desk == desktop )
2163 return;
2164 int was_desk = desk;
2165 desk = desktop;
2166 info->setDesktop( desktop );
2167 if(( was_desk == NET::OnAllDesktops ) != ( desktop == NET::OnAllDesktops ))
2168 { // onAllDesktops changed
2169 if ( isShown( true ))
2170 Notify::raise( isOnAllDesktops() ? Notify::OnAllDesktops : Notify::NotOnAllDesktops );
2171 workspace()->updateOnAllDesktopsOfTransients( this );
2172 }
2173 if( decoration != NULL )
2174 decoration->desktopChange();
2175 workspace()->updateFocusChains( this, Workspace::FocusChainMakeFirst );
2176 updateVisibility();
2177 updateWindowRules();
2178 }
2179
2180void Client::setOnAllDesktops( bool b )
2181 {
2182 if(( b && isOnAllDesktops())
2183 || ( !b && !isOnAllDesktops()))
2184 return;
2185 if( b )
2186 setDesktop( NET::OnAllDesktops );
2187 else
2188 setDesktop( workspace()->currentDesktop());
2189 }
2190
2191bool Client::isOnCurrentDesktop() const
2192 {
2193 return isOnDesktop( workspace()->currentDesktop());
2194 }
2195
2196int Client::screen() const
2197 {
2198 if( !options->xineramaEnabled )
2199 return 0;
2200 return workspace()->screenNumber( geometry().center());
2201 }
2202
2203bool Client::isOnScreen( int screen ) const
2204 {
2205 if( !options->xineramaEnabled )
2206 return screen == 0;
2207 return workspace()->screenGeometry( screen ).intersects( geometry());
2208 }
2209
2210// performs activation and/or raising of the window
2211void Client::takeActivity( int flags, bool handled, allowed_t )
2212 {
2213 if( !handled || !Ptakeactivity )
2214 {
2215 if( flags & ActivityFocus )
2216 takeFocus( Allowed );
2217 if( flags & ActivityRaise )
2218 workspace()->raiseClient( this );
2219 return;
2220 }
2221
2222#ifndef NDEBUG
2223 static Time previous_activity_timestamp;
2224 static Client* previous_client;
2225 if( previous_activity_timestamp == get_tqt_x_time() && previous_client != this )
2226 {
2227 kdDebug( 1212 ) << "Repeated use of the same X timestamp for activity" << endl;
2228 kdDebug( 1212 ) << kdBacktrace() << endl;
2229 }
2230 previous_activity_timestamp = get_tqt_x_time();
2231 previous_client = this;
2232#endif
2233 workspace()->sendTakeActivity( this, get_tqt_x_time(), flags );
2234 }
2235
2236// performs the actual focusing of the window using XSetInputFocus and WM_TAKE_FOCUS
2237void Client::takeFocus( allowed_t )
2238 {
2239#ifndef NDEBUG
2240 static Time previous_focus_timestamp;
2241 static Client* previous_client;
2242 if( previous_focus_timestamp == get_tqt_x_time() && previous_client != this )
2243 {
2244 kdDebug( 1212 ) << "Repeated use of the same X timestamp for focus" << endl;
2245 kdDebug( 1212 ) << kdBacktrace() << endl;
2246 }
2247 previous_focus_timestamp = get_tqt_x_time();
2248 previous_client = this;
2249#endif
2250 if ( rules()->checkAcceptFocus( input ))
2251 {
2252 XSetInputFocus( tqt_xdisplay(), window(), RevertToPointerRoot, get_tqt_x_time() );
2253 }
2254 if ( Ptakefocus )
2255 {
2256 sendClientMessage(window(), atoms->wm_protocols, atoms->wm_take_focus);
2257 }
2258 workspace()->setShouldGetFocus( this );
2259 }
2260
2268bool Client::providesContextHelp() const
2269 {
2270 if (isModalSystemNotification())
2271 return false;
2272 return Pcontexthelp;
2273 }
2274
2275
2282void Client::showContextHelp()
2283 {
2284 if ( Pcontexthelp )
2285 {
2286 sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_context_help);
2287 TQWhatsThis::enterWhatsThisMode(); // SELI?
2288 }
2289 }
2290
2291
2296void Client::fetchName()
2297 {
2298 setCaption( readName());
2299 }
2300
2301TQString Client::readName() const
2302 {
2303 if ( info->name() && info->name()[ 0 ] != '\0' )
2304 return TQString::fromUtf8( info->name() );
2305 else
2306 return KWin::readNameProperty( window(), XA_WM_NAME );
2307 }
2308
2309KWIN_COMPARE_PREDICATE( FetchNameInternalPredicate, const Client*, (!cl->isSpecialWindow() || cl->isToolbar()) && cl != value && cl->caption() == value->caption());
2310
2311void Client::setCaption( const TQString& s, bool force )
2312 {
2313 if ( s != cap_normal || force )
2314 {
2315 bool reset_name = force;
2316 for( unsigned int i = 0;
2317 i < s.length();
2318 ++i )
2319 if( !s[ i ].isPrint())
2320 s[ i ] = ' ';
2321 cap_normal = s;
2322 bool was_suffix = ( !cap_suffix.isEmpty());
2323 TQString machine_suffix;
2324 if( wmClientMachine( false ) != "localhost" && !isLocalMachine( wmClientMachine( false )))
2325 machine_suffix = " <@" + wmClientMachine( true ) + ">";
2326 TQString shortcut_suffix = !shortcut().isNull() ? ( " {" + shortcut().toString() + "}" ) : "";
2327 cap_suffix = machine_suffix + shortcut_suffix;
2328 if ( ( !isSpecialWindow() || isToolbar()) && workspace()->findClient( FetchNameInternalPredicate( this )))
2329 {
2330 int i = 2;
2331 do
2332 {
2333 cap_suffix = machine_suffix + " <" + TQString::number(i) + ">" + shortcut_suffix;
2334 i++;
2335 } while ( workspace()->findClient( FetchNameInternalPredicate( this )));
2336 info->setVisibleName( caption().utf8() );
2337 reset_name = false;
2338 }
2339 if(( (was_suffix && cap_suffix.isEmpty())
2340 || reset_name )) // if it was new window, it may have old value still set, if the window is reused
2341 {
2342 info->setVisibleName( "" ); // remove
2343 info->setVisibleIconName( "" ); // remove
2344 }
2345 else if( !cap_suffix.isEmpty() && !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
2346 info->setVisibleIconName( ( cap_iconic + cap_suffix ).utf8() );
2347
2348 if( isManaged() && decoration != NULL )
2349 decoration->captionChange();
2350 }
2351 }
2352
2353void Client::updateCaption()
2354 {
2355 setCaption( cap_normal, true );
2356 }
2357
2358void Client::fetchIconicName()
2359 {
2360 TQString s;
2361 if ( info->iconName() && info->iconName()[ 0 ] != '\0' )
2362 s = TQString::fromUtf8( info->iconName() );
2363 else
2364 s = KWin::readNameProperty( window(), XA_WM_ICON_NAME );
2365 if ( s != cap_iconic )
2366 {
2367 bool was_set = !cap_iconic.isEmpty();
2368 cap_iconic = s;
2369 if( !cap_suffix.isEmpty())
2370 {
2371 if( !cap_iconic.isEmpty()) // keep the same suffix in iconic name if it's set
2372 info->setVisibleIconName( ( s + cap_suffix ).utf8() );
2373 else if( was_set )
2374 info->setVisibleIconName( "" ); //remove
2375 }
2376 }
2377 }
2378
2381TQString Client::caption( bool full ) const
2382 {
2383 return full ? cap_normal + cap_suffix : cap_normal;
2384 }
2385
2386void Client::getWMHints()
2387 {
2388 XWMHints *hints = XGetWMHints(tqt_xdisplay(), window() );
2389 input = true;
2390 window_group = None;
2391 urgency = false;
2392 if ( hints )
2393 {
2394 if( hints->flags & InputHint )
2395 input = hints->input;
2396 if( hints->flags & WindowGroupHint )
2397 window_group = hints->window_group;
2398 urgency = ( hints->flags & UrgencyHint ) ? true : false; // true/false needed, it's uint bitfield
2399 XFree( (char*)hints );
2400 }
2401 checkGroup();
2402 updateUrgency();
2403 updateAllowedActions(); // group affects isMinimizable()
2404 }
2405
2406void Client::getMotifHints()
2407 {
2408 bool mnoborder, mresize, mmove, mminimize, mmaximize, mclose;
2409 Motif::readFlags( client, mnoborder, mresize, mmove, mminimize, mmaximize, mclose );
2410 motif_noborder = mnoborder;
2411 if( !hasNETSupport()) // NETWM apps should set type and size constraints
2412 {
2413 motif_may_resize = mresize; // this should be set using minsize==maxsize, but oh well
2414 motif_may_move = mmove;
2415 }
2416 else
2417 motif_may_resize = motif_may_move = true;
2418 // mminimize; - ignore, bogus - e.g. shading or sending to another desktop is "minimizing" too
2419 // mmaximize; - ignore, bogus - maximizing is basically just resizing
2420 motif_may_close = mclose; // motif apps like to crash when they set this hint and WM closes them anyway
2421 if( isManaged())
2422 updateDecoration( true ); // check if noborder state has changed
2423 }
2424
2425void Client::readIcons( Window win, TQPixmap* icon, TQPixmap* miniicon )
2426 {
2427 // get the icons, allow scaling
2428 if( icon != NULL )
2429 *icon = KWin::icon( win, 32, 32, true, KWin::NETWM | KWin::WMHints );
2430 if( miniicon != NULL )
2431 {
2432 if( icon == NULL || !icon->isNull())
2433 *miniicon = KWin::icon( win, 16, 16, true, KWin::NETWM | KWin::WMHints );
2434 else
2435 *miniicon = TQPixmap();
2436 }
2437 }
2438
2439void Client::getIcons()
2440 {
2441 // first read icons from the window itself
2442 readIcons( window(), &icon_pix, &miniicon_pix );
2443 if( icon_pix.isNull())
2444 { // then try window group
2445 icon_pix = group()->icon();
2446 miniicon_pix = group()->miniIcon();
2447 }
2448 if( icon_pix.isNull() && isTransient())
2449 { // then mainclients
2450 ClientList mainclients = mainClients();
2451 for( ClientList::ConstIterator it = mainclients.begin();
2452 it != mainclients.end() && icon_pix.isNull();
2453 ++it )
2454 {
2455 icon_pix = (*it)->icon();
2456 miniicon_pix = (*it)->miniIcon();
2457 }
2458 }
2459 if( icon_pix.isNull())
2460 { // and if nothing else, load icon from classhint or xapp icon
2461 icon_pix = KWin::icon( window(), 32, 32, true, KWin::ClassHint | KWin::XApp );
2462 miniicon_pix = KWin::icon( window(), 16, 16, true, KWin::ClassHint | KWin::XApp );
2463 }
2464 if( isManaged() && decoration != NULL )
2465 decoration->iconChange();
2466 }
2467
2468void Client::getWindowProtocols()
2469 {
2470 Atom *p;
2471 int i,n;
2472
2473 Pdeletewindow = 0;
2474 Ptakefocus = 0;
2475 Ptakeactivity = 0;
2476 Pcontexthelp = 0;
2477 Pping = 0;
2478
2479 if (XGetWMProtocols(tqt_xdisplay(), window(), &p, &n))
2480 {
2481 for (i = 0; i < n; i++)
2482 if (p[i] == atoms->wm_delete_window)
2483 Pdeletewindow = 1;
2484 else if (p[i] == atoms->wm_take_focus)
2485 Ptakefocus = 1;
2486 else if (p[i] == atoms->net_wm_take_activity)
2487 Ptakeactivity = 1;
2488 else if (p[i] == atoms->net_wm_context_help)
2489 Pcontexthelp = 1;
2490 else if (p[i] == atoms->net_wm_ping)
2491 Pping = 1;
2492 if (n>0)
2493 XFree(p);
2494 }
2495 }
2496
2497static int nullErrorHandler(Display *, XErrorEvent *)
2498 {
2499 return 0;
2500 }
2501
2505TQCString Client::staticWindowRole(WId w)
2506 {
2507 return getStringProperty(w, tqt_window_role).lower();
2508 }
2509
2513TQCString Client::staticSessionId(WId w)
2514 {
2515 return getStringProperty(w, tqt_sm_client_id);
2516 }
2517
2521TQCString Client::staticWmCommand(WId w)
2522 {
2523 return getStringProperty(w, XA_WM_COMMAND, ' ');
2524 }
2525
2529Window Client::staticWmClientLeader(WId w)
2530 {
2531 Atom type;
2532 int format, status;
2533 unsigned long nitems = 0;
2534 unsigned long extra = 0;
2535 unsigned char *data = 0;
2536 Window result = w;
2537 XErrorHandler oldHandler = XSetErrorHandler(nullErrorHandler);
2538 status = XGetWindowProperty( tqt_xdisplay(), w, atoms->wm_client_leader, 0, 10000,
2539 False, XA_WINDOW, &type, &format,
2540 &nitems, &extra, &data );
2541 XSetErrorHandler(oldHandler);
2542 if (status == Success )
2543 {
2544 if (data && nitems > 0)
2545 result = *((Window*) data);
2546 XFree(data);
2547 }
2548 return result;
2549 }
2550
2551
2552void Client::getWmClientLeader()
2553 {
2554 wmClientLeaderWin = staticWmClientLeader(window());
2555 }
2556
2561TQCString Client::sessionId()
2562 {
2563 TQCString result = staticSessionId(window());
2564 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
2565 result = staticSessionId(wmClientLeaderWin);
2566 return result;
2567 }
2568
2573TQCString Client::wmCommand()
2574 {
2575 TQCString result = staticWmCommand(window());
2576 if (result.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
2577 result = staticWmCommand(wmClientLeaderWin);
2578 return result;
2579 }
2580
2581void Client::getWmClientMachine()
2582 {
2583 client_machine = getStringProperty(window(), XA_WM_CLIENT_MACHINE);
2584 if( client_machine.isEmpty() && wmClientLeaderWin && wmClientLeaderWin!=window())
2585 client_machine = getStringProperty(wmClientLeaderWin, XA_WM_CLIENT_MACHINE);
2586 if( client_machine.isEmpty())
2587 client_machine = "localhost";
2588 }
2589
2594TQCString Client::wmClientMachine( bool use_localhost ) const
2595 {
2596 TQCString result = client_machine;
2597 if( use_localhost )
2598 { // special name for the local machine (localhost)
2599 if( result != "localhost" && isLocalMachine( result ))
2600 result = "localhost";
2601 }
2602 return result;
2603 }
2604
2609Window Client::wmClientLeader() const
2610 {
2611 if (wmClientLeaderWin)
2612 return wmClientLeaderWin;
2613 return window();
2614 }
2615
2616bool Client::wantsTabFocus() const
2617 {
2618 return ( isNormalWindow() || isDialog()) && wantsInput() && !skip_taskbar;
2619 }
2620
2621
2622bool Client::wantsInput() const
2623 {
2624 return rules()->checkAcceptFocus( input || Ptakefocus );
2625 }
2626
2627bool Client::isDesktop() const
2628 {
2629 return windowType() == NET::Desktop;
2630 }
2631
2632bool Client::isDock() const
2633 {
2634 return windowType() == NET::Dock;
2635 }
2636
2637bool Client::isTopMenu() const
2638 {
2639 return windowType() == NET::TopMenu;
2640 }
2641
2642
2643bool Client::isMenu() const
2644 {
2645 return windowType() == NET::Menu && !isTopMenu(); // because of backwards comp.
2646 }
2647
2648bool Client::isToolbar() const
2649 {
2650 return windowType() == NET::Toolbar;
2651 }
2652
2653bool Client::isSplash() const
2654 {
2655 return windowType() == NET::Splash;
2656 }
2657
2658bool Client::isUtility() const
2659 {
2660 return windowType() == NET::Utility;
2661 }
2662
2663bool Client::isDialog() const
2664 {
2665 return windowType() == NET::Dialog;
2666 }
2667
2668bool Client::isNormalWindow() const
2669 {
2670 return windowType() == NET::Normal;
2671 }
2672
2673bool Client::isSpecialWindow() const
2674 {
2675 return isDesktop() || isDock() || isSplash() || isTopMenu()
2676 || isToolbar(); // TODO
2677 }
2678
2679NET::WindowType Client::windowType( bool direct, int supported_types ) const
2680 {
2681 NET::WindowType wt = info->windowType( supported_types );
2682 if( direct )
2683 return wt;
2684 NET::WindowType wt2 = rules()->checkType( wt );
2685 if( wt != wt2 )
2686 {
2687 wt = wt2;
2688 info->setWindowType( wt ); // force hint change
2689 }
2690 // hacks here
2691 if( wt == NET::Menu )
2692 {
2693 // ugly hack to support the times when NET::Menu meant NET::TopMenu
2694 // if it's as wide as the screen, not very high and has its upper-left
2695 // corner a bit above the screen's upper-left cornet, it's a topmenu
2696 if( x() == 0 && y() < 0 && y() > -10 && height() < 100
2697 && abs( width() - workspace()->clientArea( FullArea, this ).width()) < 10 )
2698 wt = NET::TopMenu;
2699 }
2700 // TODO change this to rule
2701 const char* const oo_prefix = "openoffice.org"; // TQCString has no startsWith()
2702 // oo_prefix is lowercase, because resourceClass() is forced to be lowercase
2703 if( tqstrncmp( resourceClass(), oo_prefix, strlen( oo_prefix )) == 0 && wt == NET::Dialog )
2704 wt = NET::Normal; // see bug #66065
2705 if( wt == NET::Unknown ) // this is more or less suggested in NETWM spec
2706 wt = isTransient() ? NET::Dialog : NET::Normal;
2707 return wt;
2708 }
2709
2714void Client::setCursor( Position m )
2715 {
2716 if( !isResizable() || isShade())
2717 {
2718 m = PositionCenter;
2719 }
2720 switch ( m )
2721 {
2722 case PositionTopLeft:
2723 case PositionBottomRight:
2724 setCursor( TQt::sizeFDiagCursor );
2725 break;
2726 case PositionBottomLeft:
2727 case PositionTopRight:
2728 setCursor( TQt::sizeBDiagCursor );
2729 break;
2730 case PositionTop:
2731 case PositionBottom:
2732 setCursor( TQt::sizeVerCursor );
2733 break;
2734 case PositionLeft:
2735 case PositionRight:
2736 setCursor( TQt::sizeHorCursor );
2737 break;
2738 default:
2739 if( buttonDown && isMovable())
2740 setCursor( TQt::sizeAllCursor );
2741 else
2742 setCursor( TQt::arrowCursor );
2743 break;
2744 }
2745 }
2746
2747// TODO mit nejake checkCursor(), ktere se zavola v manage() a pri vecech, kdy by se kurzor mohl zmenit?
2748// TRANSLATION: TODO: have a checkCursor() function, which is called both in manage() and in cases where the cursor might change
2749void Client::setCursor( const TQCursor& c )
2750 {
2751 if( c.handle() == cursor.handle())
2752 return;
2753 cursor = c;
2754 if( decoration != NULL )
2755 decoration->widget()->setCursor( cursor );
2756 XDefineCursor( tqt_xdisplay(), frameId(), cursor.handle());
2757 }
2758
2759Client::Position Client::mousePosition( const TQPoint& p ) const
2760 {
2761 if( decoration != NULL )
2762 return decoration->mousePosition( p );
2763 return PositionCenter;
2764 }
2765
2766void Client::updateAllowedActions( bool force )
2767 {
2768 if( !isManaged() && !force )
2769 return;
2770 unsigned long old_allowed_actions = allowed_actions;
2771 allowed_actions = 0;
2772 if( isMovable())
2773 allowed_actions |= NET::ActionMove;
2774 if( isResizable())
2775 allowed_actions |= NET::ActionResize;
2776 if( isMinimizable())
2777 allowed_actions |= NET::ActionMinimize;
2778 if( isShadeable())
2779 allowed_actions |= NET::ActionShade;
2780 // sticky state not supported
2781 if( isMaximizable())
2782 allowed_actions |= NET::ActionMax;
2783 if( userCanSetFullScreen())
2784 allowed_actions |= NET::ActionFullScreen;
2785 allowed_actions |= NET::ActionChangeDesktop; // always (pagers shouldn't show Docks etc.)
2786 if( isCloseable())
2787 allowed_actions |= NET::ActionClose;
2788 if( old_allowed_actions == allowed_actions )
2789 return;
2790 // TODO this could be delayed and compressed - it's only for pagers etc. anyway
2791 info->setAllowedActions( allowed_actions );
2792 // TODO this should also tell the decoration, so that it can update the buttons
2793 }
2794
2795void Client::autoRaise()
2796 {
2797 workspace()->raiseClient( this );
2798 cancelAutoRaise();
2799 }
2800
2801void Client::cancelAutoRaise()
2802 {
2803 delete autoRaiseTimer;
2804 autoRaiseTimer = 0;
2805 }
2806
2807void Client::setOpacity(uint opacity)
2808 {
2809 if (isDesktop())
2810 return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
2811// tqWarning("setting opacity for %d",tqt_xdisplay());
2812 if (opacity == Opacity::Opaque && !custom_opacity)
2813 { // Note: if it is custom_opacity we want to keep the properties in case of WM restart
2814 XDeleteProperty (tqt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
2815 XDeleteProperty (tqt_xdisplay(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
2816 }
2817 else{
2818 if(opacity == opacity_)
2819 return;
2820 long data = opacity; // 32bit XChangeProperty needs long
2821 XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2822 XChangeProperty(tqt_xdisplay(), window(), atoms->net_wm_window_opacity, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2823 }
2824 opacity_ = opacity;
2825 }
2826
2827void Client::setShadowSize(uint shadowSize)
2828 {
2829 // ignoring all individual settings - if we control a window, we control it's shadow
2830 // TODO somehow handle individual settings for docks (besides custom sizes)
2831 long data = shadowSize;
2832 XChangeProperty(tqt_xdisplay(), frameId(), atoms->net_wm_window_shadow, XA_CARDINAL, 32, PropModeReplace, (unsigned char *) &data, 1L);
2833 }
2834
2835uint Client::defaultOpacity()
2836 {
2837 return defaultOpacity(isActive() || (keepAbove() && options->keepAboveAsActive));
2838 }
2839
2840uint Client::defaultOpacity(bool active)
2841 {
2842 if (active)
2843 {
2844 if( ruleOpacityActive() )
2845 return rule_opacity_active;
2846 else
2847 return options->translucentActiveWindows ? options->activeWindowOpacity : Opacity::Opaque;
2848 }
2849 else
2850 {
2851 if( ruleOpacityInactive() )
2852 return rule_opacity_inactive;
2853 else
2854 return options->translucentInactiveWindows ? options->inactiveWindowOpacity : Opacity::Opaque;
2855 }
2856 }
2857
2858void Client::updateOpacity()
2859// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
2860 {
2861 if (!(isNormalWindow() || isDialog() || isUtility() )|| custom_opacity)
2862 return;
2863 uint opacity = defaultOpacity();
2864 setOpacity(opacity);
2865
2866 if (isBMP())
2867 // beep-media-player, only undecorated windows (gtk2 xmms, xmms doesn't work with compmgr at all - s.e.p. :P )
2868 {
2869 ClientList tmpGroupMembers = group()->members();
2870 ClientList groupMembers;
2871 groupMembers.append(this);
2872 tmpGroupMembers.remove(this);
2873 ClientList::Iterator it = tmpGroupMembers.begin();
2874 while (it != tmpGroupMembers.end())
2875 // search for next attached and not activated client and repeat if found
2876 {
2877 if ((*it) != this && (*it)->isBMP())
2878 // potential "to activate" client found
2879 {
2880// tqWarning("client found");
2881 if ((*it)->touches(this)) // first test, if the new client touches the just activated one
2882 {
2883// tqWarning("found client touches me");
2884 (*it)->setOpacity(opacity);
2885// tqWarning("(de)activated, search restarted (1)");
2886 (*it)->setShadowSize(options->activeWindowShadowSize);
2887 groupMembers.append(*it);
2888 tmpGroupMembers.remove(it);
2889 it = tmpGroupMembers.begin(); // restart, search next client
2890 continue;
2891 }
2892 else
2893 { // pot. client does not touch c, so we have to search if it touches some other activated client
2894 bool found = false;
2895 for( ClientList::ConstIterator it2 = groupMembers.begin(); it2 != groupMembers.end(); it2++ )
2896 {
2897 if ((*it2) != this && (*it2) != (*it) && (*it)->touches(*it2))
2898 {
2899// tqWarning("found client touches other active client");
2900 (*it)->setOpacity(opacity);
2901 (*it)->setShadowSize(isActive() ? options->activeWindowShadowSize : options->inactiveWindowShadowSize);
2902 groupMembers.append(*it);
2903 tmpGroupMembers.remove(it);
2904 it = tmpGroupMembers.begin(); // reset potential client search
2905 found = true;
2906// tqWarning("(de)activated, search restarted (2)");
2907 break; // skip this loop
2908 }
2909 }
2910 if (found) continue;
2911 }
2912 }
2913 it++;
2914 }
2915 }
2916 else if (isNormalWindow())
2917 // activate/deactivate dependend minor windows as well
2918 {
2919 for( ClientList::ConstIterator it = group()->members().begin(); it != group()->members().end(); it++ )
2920 if ((*it)->isUtility() || ((*it)->isDialog() && isActive() )) // note: don't deactivate dialogs...
2921 (*it)->setOpacity(opacity);
2922 }
2923 }
2924
2925void Client::updateShadowSize()
2926// extra syncscreen flag allows to avoid double syncs when active state changes (as it will usually change for two windows)
2927 {
2928 if (!(isNormalWindow() || isDialog() || isUtility() ))
2929 return;
2930 if (isActive())
2931 setShadowSize(options->activeWindowShadowSize);
2932 else
2933 setShadowSize(options->inactiveWindowShadowSize);
2934 }
2935
2936uint Client::ruleOpacityInactive()
2937 {
2938 return rule_opacity_inactive;// != 0 ;
2939 }
2940
2941uint Client::ruleOpacityActive()
2942 {
2943 return rule_opacity_active;// != 0;
2944 }
2945
2946bool Client::getWindowOpacity() //query translucency settings from X, returns true if window opacity is set
2947 {
2948 unsigned char *data = 0;
2949 Atom actual;
2950 int format, result;
2951 unsigned long n, left;
2952 result = XGetWindowProperty(tqt_xdisplay(), window(), atoms->net_wm_window_opacity, 0L, 1L, False, XA_CARDINAL, &actual, &format, &n, &left, /*(unsigned char **)*/ &data);
2953 if (result == Success && data && format == 32 )
2954 {
2955 opacity_ = *reinterpret_cast< long* >( data );
2956 // Don't set custom_opacity flag during initialization if the opacity looks like what it
2957 // supposed to be for the given type of window. As in a such case it is likely set by us
2958 // and the WM is just restarting
2959 if ( !(Workspace::self()->initializing()
2960 && ( opacity_ == defaultOpacity(/*active*/ false)
2961 || opacity_ == defaultOpacity(/*active*/ true) ) ) )
2962 {
2963 custom_opacity = true;
2964 }
2965// setOpacity(opacity_);
2966 XFree ((char*)data);
2967 return true;
2968 }
2969 return false;
2970 }
2971
2972void Client::setCustomOpacityFlag(bool custom)
2973 {
2974 custom_opacity = custom;
2975 }
2976
2977uint Client::opacity()
2978 {
2979 return opacity_;
2980 }
2981
2982int Client::opacityPercentage()
2983 {
2984 return opacity_ / ( 0xffffffff / 100 );
2985 }
2986
2987bool Client::touches(const Client* c)
2988// checks if this client borders c, needed to test beep media player window state
2989 {
2990 if (y() == c->y() + c->height()) // this bottom to c
2991 return true;
2992 if (y() + height() == c->y()) // this top to c
2993 return true;
2994 if (x() == c->x() + c->width()) // this right to c
2995 return true;
2996 if (x() + width() == c->x()) // this left to c
2997 return true;
2998 return false;
2999 }
3000
3001#ifndef NDEBUG
3002kdbgstream& operator<<( kdbgstream& stream, const Client* cl )
3003 {
3004 if( cl == NULL )
3005 return stream << "\'NULL_CLIENT\'";
3006 return stream << "\'ID:" << cl->window() << ";WMCLASS:" << cl->resourceClass() << ":" << cl->resourceName() << ";Caption:" << cl->caption() << "\'";
3007 }
3008kdbgstream& operator<<( kdbgstream& stream, const ClientList& list )
3009 {
3010 stream << "LIST:(";
3011 bool first = true;
3012 for( ClientList::ConstIterator it = list.begin();
3013 it != list.end();
3014 ++it )
3015 {
3016 if( !first )
3017 stream << ":";
3018 first = false;
3019 stream << *it;
3020 }
3021 stream << ")";
3022 return stream;
3023 }
3024kdbgstream& operator<<( kdbgstream& stream, const ConstClientList& list )
3025 {
3026 stream << "LIST:(";
3027 bool first = true;
3028 for( ConstClientList::ConstIterator it = list.begin();
3029 it != list.end();
3030 ++it )
3031 {
3032 if( !first )
3033 stream << ":";
3034 first = false;
3035 stream << *it;
3036 }
3037 stream << ")";
3038 return stream;
3039 }
3040#endif
3041
3042TQPixmap * twin_get_menu_pix_hack()
3043 {
3044 static TQPixmap p;
3045 if ( p.isNull() )
3046 p = SmallIcon( "bx2" );
3047 return &p;
3048 }
3049
3050} // namespace
3051
3052#include "client.moc"
KWinInternal::Client::desktop
int desktop() const
Definition: client.h:765
KWinInternal::Client::showContextHelp
void showContextHelp()
Definition: client.cpp:2282
KWinInternal::Client::staticWmClientLeader
static Window staticWmClientLeader(WId)
Definition: client.cpp:2529
KWinInternal::Client::sessionId
TQCString sessionId()
Definition: client.cpp:2561
KWinInternal::Client::providesContextHelp
bool providesContextHelp() const
Definition: client.cpp:2268
KWinInternal::Client::killWindow
void killWindow()
Definition: client.cpp:1774
KWinInternal::Client::setActive
void setActive(bool, bool updateOpacity=true)
Definition: activation.cpp:856
KWinInternal::Client::isMovable
bool isMovable() const
Definition: geometry.cpp:1649
KWinInternal::Client::isMinimizable
bool isMinimizable() const
Definition: client.cpp:639
KWinInternal::Client::keepAbove
bool keepAbove() const
Definition: client.cpp:672
KWinInternal::Client::Client
Client(Workspace *ws)
Definition: client.cpp:94
KWinInternal::Client::minimize
void minimize(bool avoid_animation=false)
Definition: client.cpp:682
KWinInternal::Client::staticSessionId
static TQCString staticSessionId(WId)
Definition: client.cpp:2513
KWinInternal::Client::wmClientMachine
TQCString wmClientMachine(bool use_localhost) const
Definition: client.cpp:2594
KWinInternal::Client::isResizable
bool isResizable() const
Definition: geometry.cpp:1665
KWinInternal::Client::staticWindowRole
static TQCString staticWindowRole(WId)
Definition: client.cpp:2505
KWinInternal::Client::staticWmCommand
static TQCString staticWmCommand(WId)
Definition: client.cpp:2521
KWinInternal::Client::updateUserTime
void updateUserTime(Time time=CurrentTime)
Definition: activation.cpp:674
KWinInternal::Client::isOnDesktop
bool isOnDesktop(int d) const
Definition: client.h:778
KWinInternal::Client::wmCommand
TQCString wmCommand()
Definition: client.cpp:2573
KWinInternal::Client::releaseWindow
void releaseWindow(bool on_shutdown=false)
Definition: client.cpp:222
KWinInternal::Client::closeWindow
void closeWindow()
Definition: client.cpp:1750
KWinInternal::Client::wmClientLeader
Window wmClientLeader() const
Definition: client.cpp:2609
KWinInternal::Client::caption
TQString caption(bool full=true) const
Definition: client.cpp:2381
KWinInternal::Client::move
void move(int x, int y, ForceGeometry_t force=NormalGeometrySet)
Definition: geometry.cpp:1831

twin

Skip menu "twin"
  • Main Page
  • Modules
  • Alphabetical List
  • Class List
  • File List
  • Class Members

twin

Skip menu "twin"
  • kate
  • libkonq
  • twin
  •   lib
Generated for twin by doxygen 1.9.4
This website is maintained by Timothy Pearson.