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

twin

Skip menu "twin"
  • Main Page
  • 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.