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

twin

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

twin

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