• 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 
5 Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
6 Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
7 
8 You can Freely distribute this program under the GNU General Public
9 License. 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 
28 namespace KWinInternal
29 {
30 
36 bool 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()
554 void 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::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
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::desktop
int desktop() const
Definition: client.h:753
KWinInternal::Client::staticWindowRole
static TQCString staticWindowRole(WId)
Definition: client.cpp:2501
KWinInternal::Client
The Client class encapsulates a window decoration frame.
Definition: client.h:46
KWinInternal::Client::isMovable
bool isMovable() const
Definition: geometry.cpp:1649
KWinInternal
Definition: activation.cpp:34

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.8.13
This website is maintained by Timothy Pearson.