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

twin

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

twin

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