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

twin

  • twin
manage.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/*
13
14 This file contains things relevant to handling incoming events.
15
16*/
17
18#include "client.h"
19
20#include <tdestartupinfo.h>
21#include <tdeglobal.h>
22#include <X11/extensions/shape.h>
23
24#include "notifications.h"
25#include "rules.h"
26#include "group.h"
27
28namespace KWinInternal
29{
30
36bool Client::manage( Window w, bool isMapped )
37 {
38 XWindowAttributes attr;
39 if( !XGetWindowAttributes(tqt_xdisplay(), w, &attr))
40 return false;
41
42 grabXServer();
43
44 // from this place on, manage() mustn't return false
45 postpone_geometry_updates = 1;
46 pending_geometry_update = true; // force update when finishing with geometry changes
47
48 embedClient( w, attr );
49
50 // SELI order all these things in some sane manner
51
52 bool init_minimize = false;
53 XWMHints * hints = XGetWMHints(tqt_xdisplay(), w );
54 if (hints && (hints->flags & StateHint) && hints->initial_state == IconicState)
55 init_minimize = true;
56 if (hints)
57 XFree(hints);
58 if( isMapped )
59 init_minimize = false; // if it's already mapped, ignore hint
60
61 unsigned long properties[ 2 ];
62 properties[ WinInfo::PROTOCOLS ] =
63 NET::WMDesktop |
64 NET::WMState |
65 NET::WMWindowType |
66 NET::WMStrut |
67 NET::WMName |
68 NET::WMIconGeometry |
69 NET::WMIcon |
70 NET::WMPid |
71 NET::WMIconName |
72 0;
73 properties[ WinInfo::PROTOCOLS2 ] =
74 NET::WM2UserTime |
75 NET::WM2StartupId |
76 NET::WM2ExtendedStrut |
77 0;
78
79 info = new WinInfo( this, tqt_xdisplay(), client, tqt_xrootwin(), properties, 2 );
80
81 cmap = attr.colormap;
82
83 XClassHint classHint;
84 if ( XGetClassHint( tqt_xdisplay(), client, &classHint ) )
85 {
86 // Qt3.2 and older had this all lowercase, Qt3.3 capitalized resource class
87 // force lowercase, so that workarounds listing resource classes still work
88 resource_name = TQCString( classHint.res_name ).lower();
89 resource_class = TQCString( classHint.res_class ).lower();
90 XFree( classHint.res_name );
91 XFree( classHint.res_class );
92 }
93 ignore_focus_stealing = options->checkIgnoreFocusStealing( this ); // TODO change to rules
94
95 window_role = staticWindowRole( w );
96 getWmClientLeader();
97 getWmClientMachine();
98 // first only read the caption text, so that setupWindowRules() can use it for matching,
99 // and only then really set the caption using setCaption(), which checks for duplicates etc.
100 // and also relies on rules already existing
101 cap_normal = readName();
102 setupWindowRules( false );
103 setCaption( cap_normal, true );
104
105 detectNoBorder();
106 detectShapable();
107 fetchIconicName();
108 getWMHints(); // needs to be done before readTransient() because of reading the group
109 modal = ( info->state() & NET::Modal ) != 0; // needs to be valid before handling groups
110 readTransient();
111 getIcons();
112 getWindowProtocols();
113 getWmNormalHints(); // get xSizeHint
114 getMotifHints();
115
116 // TODO try to obey all state information from info->state()
117
118 original_skip_taskbar = skip_taskbar = ( info->state() & NET::SkipTaskbar) != 0;
119 skip_pager = ( info->state() & NET::SkipPager) != 0;
120
121 TDEStartupInfoId asn_id;
122 TDEStartupInfoData asn_data;
123 bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
124
125 workspace()->updateClientLayer( this );
126
127 SessionInfo* session = workspace()->takeSessionInfo( this );
128
129 if ( session )
130 {
131 if ( session->minimized )
132 init_minimize = true;
133 if( session->userNoBorder )
134 setUserNoBorder( true );
135 }
136
137 setShortcut( rules()->checkShortcut( session ? session->shortcut : TQString::null, true ));
138
139 init_minimize = rules()->checkMinimize( init_minimize, !isMapped );
140 if( rules()->checkNoBorder( false, !isMapped ))
141 setUserNoBorder( true );
142
143 checkAndSetInitialRuledOpacity();
144
145 // initial desktop placement
146 if ( session )
147 {
148 desk = session->desktop;
149 if( session->onAllDesktops )
150 desk = NET::OnAllDesktops;
151 }
152 else
153 {
154 // if this window is transient, ensure that it is opened on the
155 // same window as its parent. this is necessary when an application
156 // starts up on a different desktop than is currently displayed
157 if( isTransient())
158 {
159 ClientList mainclients = mainClients();
160 bool on_current = false;
161 Client* maincl = NULL;
162 // this is slightly duplicated from Placement::placeOnMainWindow()
163 for( ClientList::ConstIterator it = mainclients.begin();
164 it != mainclients.end();
165 ++it )
166 {
167 if( mainclients.count() > 1 && (*it)->isSpecialWindow())
168 continue; // don't consider toolbars etc when placing
169 maincl = *it;
170 if( (*it)->isOnCurrentDesktop())
171 on_current = true;
172 }
173 if( on_current )
174 desk = workspace()->currentDesktop();
175 else if( maincl != NULL )
176 desk = maincl->desktop();
177 }
178 if ( info->desktop() )
179 desk = info->desktop(); // window had the initial desktop property, force it
180 if( desktop() == 0 && asn_valid && asn_data.desktop() != 0 )
181 desk = asn_data.desktop();
182 }
183 if ( desk == 0 ) // assume window wants to be visible on the current desktop
184 desk = workspace()->currentDesktop();
185 desk = rules()->checkDesktop( desk, !isMapped );
186 if( desk != NET::OnAllDesktops ) // do range check
187 desk = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desk ));
188 info->setDesktop( desk );
189 workspace()->updateOnAllDesktopsOfTransients( this ); // SELI
190// onAllDesktopsChange(); decoration doesn't exist here yet
191
192 TQRect geom( attr.x, attr.y, attr.width, attr.height );
193 bool placementDone = FALSE;
194
195 if ( session )
196 geom = session->geometry;
197
198 TQRect area;
199 bool partial_keep_in_area = isMapped || session;
200 if( isMapped || session )
201 area = workspace()->clientArea( FullArea, geom.center(), desktop());
202 else if( options->xineramaPlacementEnabled )
203 {
204 int screen = options->xineramaPlacementScreen;
205 if( screen == -1 ) // active screen
206 screen = asn_data.xinerama() == -1 ? workspace()->activeScreen() : asn_data.xinerama();
207 area = workspace()->clientArea( PlacementArea, workspace()->screenGeometry( screen ).center(), desktop());
208 }
209 else
210 area = workspace()->clientArea( PlacementArea, TQCursor::pos(), desktop());
211
212 if( int type = checkFullScreenHack( geom ))
213 {
214 fullscreen_mode = FullScreenHack;
215 if( rules()->checkStrictGeometry( false ))
216 {
217 geom = type == 2 // 1 - it's xinerama-aware fullscreen hack, 2 - it's full area
218 ? workspace()->clientArea( FullArea, geom.center(), desktop())
219 : workspace()->clientArea( ScreenArea, geom.center(), desktop());
220 }
221 else
222 geom = workspace()->clientArea( FullScreenArea, geom.center(), desktop());
223 placementDone = true;
224 }
225
226 if ( isDesktop() )
227 {
228 // desktops are treated slightly special
229 geom = workspace()->clientArea( FullArea, geom.center(), desktop());
230 placementDone = true;
231 }
232
233 bool usePosition = false;
234 if ( isMapped || session || placementDone )
235 placementDone = true; // use geometry
236 else if( isTransient() && !isUtility() && !isDialog() && !isSplash())
237 usePosition = true;
238 else if( isTransient() && !hasNETSupport())
239 usePosition = true;
240 else if( isDialog() && hasNETSupport())
241 // if the dialog is actually non-NETWM transient window, don't try to apply placement to it,
242 // it breaks with too many things (xmms, display)
243 {
244 if( mainClients().count() >= 1 )
245 {
246#if 1
247 // TODO #78082 - Ok, it seems there are after all some cases when an application has a good
248 // reason to specify a position for its dialog. Too bad other WMs have never bothered
249 // with placement for dialogs, so apps always specify positions for their dialogs,
250 // including such silly positions like always centered on the screen or under mouse.
251 // Using ignoring requested position in window-specific settings helps, but at least
252 // for Qt apps this should work better.
253 usePosition = true;
254#else
255 ; // force using placement policy
256#endif
257 }
258 else
259 usePosition = true;
260 }
261 else if( isSplash())
262 ; // force using placement policy
263 else
264 usePosition = true;
265 if( !rules()->checkIgnoreGeometry( !usePosition ))
266 {
267 bool ignorePPosition = ( options->ignorePositionClasses.contains(TQString::fromLatin1(resourceClass())));
268
269 if ( ( (xSizeHint.flags & PPosition) && !ignorePPosition ) ||
270 (xSizeHint.flags & USPosition) )
271 {
272 placementDone = TRUE;
273 // disobey xinerama placement option for now (#70943)
274 area = workspace()->clientArea( PlacementArea, geom.center(), desktop());
275 }
276 }
277 if( true ) // size is always obeyed for now, only with constraints applied
278 if ( (xSizeHint.flags & USSize) || (xSizeHint.flags & PSize) )
279 {
280 // keep in mind that we now actually have a size :-)
281 }
282
283 if (xSizeHint.flags & PMaxSize)
284 geom.setSize( geom.size().boundedTo(
285 rules()->checkMaxSize( TQSize(xSizeHint.max_width, xSizeHint.max_height ) ) ) );
286 if (xSizeHint.flags & PMinSize)
287 geom.setSize( geom.size().expandedTo(
288 rules()->checkMinSize( TQSize(xSizeHint.min_width, xSizeHint.min_height ) ) ) );
289
290 if( isMovable())
291 {
292 if( geom.x() > area.right() || geom.y() > area.bottom())
293 placementDone = FALSE; // weird, do not trust.
294 }
295
296 if ( placementDone )
297 move( geom.x(), geom.y() ); // before gravitating
298
299 updateDecoration( false ); // also gravitates
300 // TODO is CentralGravity right here, when resizing is done after gravitating?
301 plainResize( rules()->checkSize( sizeForClientSize( geom.size()), !isMapped ));
302
303 TQPoint forced_pos = rules()->checkPosition( invalidPoint, !isMapped );
304 if( forced_pos != invalidPoint )
305 {
306 move( forced_pos );
307 placementDone = true;
308 // don't keep inside workarea if the window has specially configured position
309 partial_keep_in_area = true;
310 area = workspace()->clientArea( FullArea, geom.center(), desktop());
311 }
312 if( !placementDone )
313 { // placement needs to be after setting size
314 workspace()->place( this, area );
315 placementDone = TRUE;
316 }
317
318 if(( !isSpecialWindow() || isToolbar()) && isMovable())
319 keepInArea( area, partial_keep_in_area );
320
321 XShapeSelectInput( tqt_xdisplay(), window(), ShapeNotifyMask );
322 is_shape = Shape::hasShape( window());
323 updateShape();
324
325 //CT extra check for stupid jdk 1.3.1. But should make sense in general
326 // if client has initial state set to Iconic and is transient with a parent
327 // window that is not Iconic, set init_state to Normal
328 if( init_minimize && isTransient())
329 {
330 ClientList mainclients = mainClients();
331 for( ClientList::ConstIterator it = mainclients.begin();
332 it != mainclients.end();
333 ++it )
334 if( (*it)->isShown( true ))
335 init_minimize = false; // SELI even e.g. for NET::Utility?
336 }
337 // if a dialog is shown for minimized window, minimize it too
338 if( !init_minimize && isTransient() && mainClients().count() > 0 )
339 {
340 bool visible_parent = false;
341 ClientList mainclients = mainClients();
342 for( ClientList::ConstIterator it = mainclients.begin();
343 it != mainclients.end();
344 ++it )
345 if( (*it)->isShown( true ))
346 visible_parent = true;
347 if( !visible_parent )
348 {
349 init_minimize = true;
350 demandAttention();
351 }
352 }
353
354 if( init_minimize )
355 minimize( true ); // no animation
356
357 // SELI this seems to be mainly for kstart and ksystraycmd
358 // probably should be replaced by something better
359 bool doNotShow = false;
360 if ( workspace()->isNotManaged( caption() ) )
361 doNotShow = TRUE;
362
363 // other settings from the previous session
364 if ( session )
365 {
366 // session restored windows are not considered to be new windows WRT rules,
367 // i.e. obey only forcing rules
368 setKeepAbove( session->keepAbove );
369 setKeepBelow( session->keepBelow );
370 setSkipTaskbar( session->skipTaskbar, true );
371 setSkipPager( session->skipPager );
372 setShade( session->shaded ? ShadeNormal : ShadeNone );
373 setShadowed( session->shadowed );
374 if( session->maximized != MaximizeRestore )
375 {
376 maximize( (MaximizeMode) session->maximized );
377 geom_restore = session->restore;
378 }
379 if( session->fullscreen == FullScreenHack )
380 ; // nothing, this should be already set again above
381 else if( session->fullscreen != FullScreenNone )
382 {
383 setFullScreen( true, false );
384 geom_fs_restore = session->fsrestore;
385 }
386 }
387 else
388 {
389 geom_restore = geometry(); // remember restore geometry
390 if ( isMaximizable()
391 && ( width() >= area.width() || height() >= area.height() ) )
392 {
393 // window is too large for the screen, maximize in the
394 // directions necessary
395 if ( width() >= area.width() && height() >= area.height() )
396 {
397 maximize( Client::MaximizeFull );
398 geom_restore = TQRect(); // use placement when unmaximizing
399 }
400 else if ( width() >= area.width() )
401 {
402 maximize( Client::MaximizeHorizontal );
403 geom_restore = TQRect(); // use placement when unmaximizing
404 geom_restore.setY( y()); // but only for horizontal direction
405 geom_restore.setHeight( height());
406 }
407 else if ( height() >= area.height() )
408 {
409 maximize( Client::MaximizeVertical );
410 geom_restore = TQRect(); // use placement when unmaximizing
411 geom_restore.setX( x()); // but only for vertical direction
412 geom_restore.setWidth( width());
413 }
414 }
415 // window may want to be maximized
416 // done after checking that the window isn't larger than the workarea, so that
417 // the restore geometry from the checks above takes precedence, and window
418 // isn't restored larger than the workarea
419 MaximizeMode maxmode = static_cast< MaximizeMode >
420 ((( info->state() & NET::MaxVert ) ? MaximizeVertical : 0 )
421 | (( info->state() & NET::MaxHoriz ) ? MaximizeHorizontal : 0 ));
422 MaximizeMode forced_maxmode = rules()->checkMaximize( maxmode, !isMapped );
423 // either hints were set to maximize, or is forced to maximize,
424 // or is forced to non-maximize and hints were set to maximize
425 if( forced_maxmode != MaximizeRestore || maxmode != MaximizeRestore )
426 maximize( forced_maxmode );
427
428 // read other initial states
429 setShade( rules()->checkShade( info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped ));
430 setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped ));
431 setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped ));
432 setSkipTaskbar( rules()->checkSkipTaskbar( info->state() & NET::SkipTaskbar, !isMapped ), true );
433 setSkipPager( rules()->checkSkipPager( info->state() & NET::SkipPager, !isMapped ));
434 if( info->state() & NET::DemandsAttention )
435 demandAttention();
436 if( info->state() & NET::Modal )
437 setModal( true );
438 if( fullscreen_mode != FullScreenHack && isFullScreenable())
439 setFullScreen( rules()->checkFullScreen( info->state() & NET::FullScreen, !isMapped ), false );
440 }
441
442 updateAllowedActions( true );
443
444 // TODO this should avoid flicker, because real restacking is done
445 // only after manage() finishes, but the window is shown sooner
446 // - keep it?
447 XLowerWindow( tqt_xdisplay(), frameId());
448
449 // set initial user time directly
450 user_time = readUserTimeMapTimestamp( asn_valid ? &asn_id : NULL, asn_valid ? &asn_data : NULL, session );
451 group()->updateUserTime( user_time ); // and do what Client::updateUserTime() does
452
453 if( isTopMenu()) // they're shown in Workspace::addClient() if their mainwindow
454 hideClient( true ); // is the active one
455
456 if( isShown( true ) && !doNotShow )
457 {
458 if( isDialog())
459 Notify::raise( Notify::TransNew );
460 if( isNormalWindow())
461 Notify::raise( Notify::New );
462
463 bool allow;
464 if( session )
465 allow = session->active
466 && ( !workspace()->wasUserInteraction()
467 || workspace()->activeClient() == NULL || workspace()->activeClient()->isDesktop());
468 else
469 allow = workspace()->allowClientActivation( this, userTime(), false );
470
471 // if session saving, force showing new windows (i.e. "save file?" dialogs etc.)
472 // also force if activation is allowed
473 if( !isOnCurrentDesktop() && !isMapped && !session && ( allow || workspace()->sessionSaving()))
474 workspace()->setCurrentDesktop( desktop());
475
476 bool belongs_to_desktop = false;
477 for( ClientList::ConstIterator it = group()->members().begin();
478 it != group()->members().end();
479 ++it )
480 if( (*it)->isDesktop())
481 {
482 belongs_to_desktop = true;
483 break;
484 }
485 if( !belongs_to_desktop && workspace()->showingDesktop())
486 workspace()->resetShowingDesktop( options->showDesktopIsMinimizeAll );
487
488 if( isOnCurrentDesktop() && !isMapped && !allow )
489 workspace()->restackClientUnderActive( this );
490 else
491 workspace()->raiseClient( this );
492
493 updateVisibility();
494
495 if( !isMapped )
496 {
497 if( allow && isOnCurrentDesktop())
498 {
499 if( !isSpecialWindow())
500 if ( options->focusPolicyIsReasonable() && wantsTabFocus() )
501 workspace()->requestFocus( this );
502 }
503 else
504 {
505 if( !session && !isSpecialWindow())
506 demandAttention();
507 }
508 }
509 }
510 else if( !doNotShow ) // if( !isShown( true ) && !doNotShow )
511 {
512 updateVisibility();
513 }
514 else // doNotShow
515 { // SELI HACK !!!
516 hideClient( true );
517 setMappingState( IconicState );
518 }
519 assert( mappingState() != WithdrawnState );
520
521 if( user_time == CurrentTime || user_time == -1U ) // no known user time, set something old
522 {
523 user_time = get_tqt_x_time() - 1000000;
524 if( user_time == CurrentTime || user_time == -1U ) // let's be paranoid
525 user_time = get_tqt_x_time() - 1000000 + 10;
526 }
527
528 updateWorkareaDiffs();
529
530// sendSyntheticConfigureNotify(); done when setting mapping state
531
532 delete session;
533
534 ungrabXServer();
535
536 client_rules.discardTemporary();
537 applyWindowRules(); // just in case
538 workspace()->discardUsedWindowRules( this, false ); // remove ApplyNow rules
539 updateWindowRules(); // was blocked while !isManaged()
540
541// Handle suspended processes
542 if (isResumeable())
543 {
544 suspendWindow(); // It won't hurt to stop the process again, and this will update the displayed captions
545 }
546
547// TODO there's a small problem here - isManaged() depends on the mapping state,
548// but this client is not yet in Workspace's client list at this point, will
549// be only done in addClient()
550 return true;
551 }
552
553// called only from manage()
554void Client::embedClient( Window w, const XWindowAttributes &attr )
555 {
556 assert( client == None );
557 assert( frame == None );
558 assert( wrapper == None );
559 client = w;
560 // we don't want the window to be destroyed when we are destroyed
561 XAddToSaveSet( tqt_xdisplay(), client );
562 XSelectInput( tqt_xdisplay(), client, NoEventMask );
563 XUnmapWindow( tqt_xdisplay(), client );
564 XWindowChanges wc; // set the border width to 0
565 wc.border_width = 0; // TODO possibly save this, and also use it for initial configuring of the window
566 XConfigureWindow( tqt_xdisplay(), client, CWBorderWidth, &wc );
567
568 XSetWindowAttributes swa;
569 swa.colormap = attr.colormap;
570 swa.background_pixmap = None;
571 swa.border_pixel = 0;
572
573 frame = XCreateWindow( tqt_xdisplay(), tqt_xrootwin(), 0, 0, 1, 1, 0,
574 attr.depth, InputOutput, attr.visual,
575 CWColormap | CWBackPixmap | CWBorderPixel, &swa );
576 wrapper = XCreateWindow( tqt_xdisplay(), frame, 0, 0, 1, 1, 0,
577 attr.depth, InputOutput, attr.visual,
578 CWColormap | CWBackPixmap | CWBorderPixel, &swa );
579
580 XDefineCursor( tqt_xdisplay(), frame, TQt::arrowCursor.handle());
581 // some apps are stupid and don't define their own cursor - set the arrow one for them
582 XDefineCursor( tqt_xdisplay(), wrapper, TQt::arrowCursor.handle());
583 XReparentWindow( tqt_xdisplay(), client, wrapper, 0, 0 );
584 XSelectInput( tqt_xdisplay(), frame,
585 KeyPressMask | KeyReleaseMask |
586 ButtonPressMask | ButtonReleaseMask |
587 KeymapStateMask |
588 ButtonMotionMask |
589 PointerMotionMask |
590 EnterWindowMask | LeaveWindowMask |
591 FocusChangeMask |
592 ExposureMask |
593 PropertyChangeMask |
594 StructureNotifyMask | SubstructureRedirectMask );
595 XSelectInput( tqt_xdisplay(), wrapper, ClientWinMask | SubstructureNotifyMask );
596 XSelectInput( tqt_xdisplay(), client,
597 FocusChangeMask |
598 PropertyChangeMask |
599 ColormapChangeMask |
600 EnterWindowMask | LeaveWindowMask |
601 KeyPressMask | KeyReleaseMask
602 );
603 updateMouseGrab();
604 }
605
606} // namespace
KWinInternal::Client
The Client class encapsulates a window decoration frame.
Definition: client.h:47
KWinInternal::Client::desktop
int desktop() const
Definition: client.h:751
KWinInternal::Client::isMovable
bool isMovable() const
Definition: geometry.cpp:1649
KWinInternal::Client::manage
bool manage(Window w, bool isMapped)
Definition: manage.cpp:36
KWinInternal::Client::minimize
void minimize(bool avoid_animation=false)
Definition: client.cpp:673
KWinInternal::Client::staticWindowRole
static TQCString staticWindowRole(WId)
Definition: client.cpp:2501
KWinInternal::Client::caption
TQString caption(bool full=true) const
Definition: client.cpp:2377
KWinInternal::Client::move
void move(int x, int y, ForceGeometry_t force=NormalGeometrySet)
Definition: geometry.cpp:1831

twin

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

twin

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