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

tdecore

  • tdecore
tdestartupinfo.cpp
1 /****************************************************************************
2 
3  $Id$
4 
5  Copyright (C) 2001-2003 Lubos Lunak <l.lunak@kde.org>
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE.
24 
25 ****************************************************************************/
26 
27 // kdDebug() can't be turned off in tdeinit
28 #if 0
29 #define KSTARTUPINFO_ALL_DEBUG
30 #warning Extra TDEStartupInfo debug messages enabled.
31 #endif
32 
33 #include <tqwidget.h>
34 
35 #include "config.h"
36 #ifdef TQ_WS_X11
37 //#ifdef TQ_WS_X11 // FIXME(E): Re-implement in a less X11 specific way
38 #include <tqglobal.h>
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 
43 #include "tdestartupinfo.h"
44 
45 #include <unistd.h>
46 #include <sys/time.h>
47 #include <stdlib.h>
48 #include <tqtimer.h>
49 #ifdef TQ_WS_X11
50 #include <netwm.h>
51 #endif
52 #include <kdebug.h>
53 #include <tdeapplication.h>
54 #include <signal.h>
55 #ifdef TQ_WS_X11
56 #include <twinmodule.h>
57 #include <kxmessages.h>
58 #include <twin.h>
59 #endif
60 
61 static const char* const NET_STARTUP_MSG = "_NET_STARTUP_INFO";
62 static const char* const NET_STARTUP_WINDOW = "_NET_STARTUP_ID";
63 // DESKTOP_STARTUP_ID is used also in tdeinit/wrapper.c ,
64 // tdesu in both tdelibs and tdebase and who knows where else
65 static const char* const NET_STARTUP_ENV = "DESKTOP_STARTUP_ID";
66 
67 static bool auto_app_started_sending = true;
68 
69 static long get_num( const TQString& item_P );
70 static unsigned long get_unum( const TQString& item_P );
71 static TQString get_str( const TQString& item_P );
72 static TQCString get_cstr( const TQString& item_P );
73 static TQStringList get_fields( const TQString& txt_P );
74 static TQString escape_str( const TQString& str_P );
75 
76 static Atom utf8_string_atom = None;
77 
78 class TDEStartupInfo::Data
79  : public TDEStartupInfoData
80  {
81  public:
82  Data() : TDEStartupInfoData(), age(0) {} // just because it's in a QMap
83  Data( const TQString& txt_P )
84  : TDEStartupInfoData( txt_P ), age( 0 ) {}
85  unsigned int age;
86  };
87 
88 struct TDEStartupInfoPrivate
89  {
90  public:
91  TQMap< TDEStartupInfoId, TDEStartupInfo::Data > startups;
92  // contains silenced ASN's only if !AnnounceSilencedChanges
93  TQMap< TDEStartupInfoId, TDEStartupInfo::Data > silent_startups;
94  // contains ASN's that had change: but no new: yet
95  TQMap< TDEStartupInfoId, TDEStartupInfo::Data > uninited_startups;
96 #ifdef TQ_WS_X11
97  KWinModule* wm_module;
98  KXMessages msgs;
99 #endif
100  TQTimer* cleanup;
101  int flags;
102  TDEStartupInfoPrivate( int flags_P )
103  :
104 #ifdef TQ_WS_X11
105  msgs( NET_STARTUP_MSG, NULL, false ),
106 #endif
107  flags( flags_P ) {}
108  };
109 
110 TDEStartupInfo::TDEStartupInfo( int flags_P, TQObject* parent_P, const char* name_P )
111  : TQObject( parent_P, name_P ),
112  timeout( 60 ), d( NULL )
113  {
114  init( flags_P );
115  }
116 
117 TDEStartupInfo::TDEStartupInfo( bool clean_on_cantdetect_P, TQObject* parent_P, const char* name_P )
118  : TQObject( parent_P, name_P ),
119  timeout( 60 ), d( NULL )
120  {
121  init( clean_on_cantdetect_P ? CleanOnCantDetect : 0 );
122  }
123 
124 void TDEStartupInfo::init( int flags_P )
125  {
126  // d == NULL means "disabled"
127  if( !TDEApplication::kApplication())
128  return;
129  if( !TDEApplication::kApplication()->getDisplay())
130  return;
131 
132  d = new TDEStartupInfoPrivate( flags_P );
133 #ifdef TQ_WS_X11
134  if( !( d->flags & DisableKWinModule ))
135  {
136  d->wm_module = new KWinModule( this );
137  connect( d->wm_module, TQ_SIGNAL( windowAdded( WId )), TQ_SLOT( slot_window_added( WId )));
138  connect( d->wm_module, TQ_SIGNAL( systemTrayWindowAdded( WId )), TQ_SLOT( slot_window_added( WId )));
139  }
140  else
141  d->wm_module = NULL;
142  connect( &d->msgs, TQ_SIGNAL( gotMessage( const TQString& )), TQ_SLOT( got_message( const TQString& )));
143 #endif
144  d->cleanup = new TQTimer( this, "cleanup" );
145  connect( d->cleanup, TQ_SIGNAL( timeout()), TQ_SLOT( startups_cleanup()));
146  }
147 
148 TDEStartupInfo::~TDEStartupInfo()
149  {
150  delete d;
151  }
152 
153 void TDEStartupInfo::got_message( const TQString& msg_P )
154  {
155 // TODO do something with SCREEN= ?
156  kdDebug( 172 ) << "[tdecore-tdestartupinfo] got:" << msg_P << endl;
157  TQString msg = msg_P.stripWhiteSpace();
158  if( msg.startsWith( "new:" )) // must match length below
159  got_startup_info( msg.mid( 4 ), false );
160  else if( msg.startsWith( "change:" )) // must match length below
161  got_startup_info( msg.mid( 7 ), true );
162  else if( msg.startsWith( "remove:" )) // must match length below
163  got_remove_startup_info( msg.mid( 7 ));
164  }
165 
166 // if the application stops responding for a while, KWinModule may get
167 // the information about the already mapped window before KXMessages
168 // actually gets the info about the started application (depends
169 // on their order in X11 event filter in TDEApplication)
170 // simply delay info from KWinModule a bit
171 // SELI???
172 namespace
173 {
174 class DelayedWindowEvent
175  : public TQCustomEvent
176  {
177  public:
178  DelayedWindowEvent( WId w_P )
179  : TQCustomEvent( TQEvent::User + 15 ), w( w_P ) {}
180  Window w;
181  };
182 }
183 
184 void TDEStartupInfo::slot_window_added( WId w_P )
185  {
186  kapp->postEvent( this, new DelayedWindowEvent( w_P ));
187  }
188 
189 void TDEStartupInfo::customEvent( TQCustomEvent* e_P )
190  {
191  if( e_P->type() == TQEvent::User + 15 )
192  window_added( static_cast< DelayedWindowEvent* >( e_P )->w );
193  else
194  TQObject::customEvent( e_P );
195  }
196 
197 void TDEStartupInfo::window_added( WId w_P )
198  {
199  TDEStartupInfoId id;
200  TDEStartupInfoData data;
201  startup_t ret = check_startup_internal( w_P, &id, &data );
202  switch( ret )
203  {
204  case Match:
205  kdDebug( 172 ) << "[tdecore-tdestartupinfo] new window match" << endl;
206  break;
207  case NoMatch:
208  break; // nothing
209  case CantDetect:
210  if( d->flags & CleanOnCantDetect )
211  clean_all_noncompliant();
212  break;
213  }
214  }
215 
216 void TDEStartupInfo::got_startup_info( const TQString& msg_P, bool update_P )
217  {
218  TDEStartupInfoId id( msg_P );
219  if( id.none())
220  return;
221  TDEStartupInfo::Data data( msg_P );
222  new_startup_info_internal( id, data, update_P );
223  }
224 
225 void TDEStartupInfo::new_startup_info_internal( const TDEStartupInfoId& id_P,
226  Data& data_P, bool update_P )
227  {
228  if( d == NULL )
229  return;
230  if( id_P.none())
231  return;
232  if( d->startups.contains( id_P ))
233  { // already reported, update
234  d->startups[ id_P ].update( data_P );
235  d->startups[ id_P ].age = 0; // CHECKME
236  kdDebug( 172 ) << "[tdecore-tdestartupinfo] updating" << endl;
237  if( d->startups[ id_P ].silent() == Data::Yes
238  && !( d->flags & AnnounceSilenceChanges ))
239  {
240  d->silent_startups[ id_P ] = d->startups[ id_P ];
241  d->startups.remove( id_P );
242  emit gotRemoveStartup( id_P, d->silent_startups[ id_P ] );
243  return;
244  }
245  emit gotStartupChange( id_P, d->startups[ id_P ] );
246  return;
247  }
248  if( d->silent_startups.contains( id_P ))
249  { // already reported, update
250  d->silent_startups[ id_P ].update( data_P );
251  d->silent_startups[ id_P ].age = 0; // CHECKME
252  kdDebug( 172 ) << "[tdecore-tdestartupinfo] updating silenced" << endl;
253  if( d->silent_startups[ id_P ].silent() != Data::Yes )
254  {
255  d->startups[ id_P ] = d->silent_startups[ id_P ];
256  d->silent_startups.remove( id_P );
257  emit gotNewStartup( id_P, d->startups[ id_P ] );
258  return;
259  }
260  emit gotStartupChange( id_P, d->silent_startups[ id_P ] );
261  return;
262  }
263  if( d->uninited_startups.contains( id_P ))
264  {
265  d->uninited_startups[ id_P ].update( data_P );
266  kdDebug( 172 ) << "[tdecore-tdestartupinfo] updating uninited" << endl;
267  if( !update_P ) // uninited finally got new:
268  {
269  d->startups[ id_P ] = d->uninited_startups[ id_P ];
270  d->uninited_startups.remove( id_P );
271  emit gotNewStartup( id_P, d->startups[ id_P ] );
272  return;
273  }
274  // no change announce, it's still uninited
275  return;
276  }
277  if( update_P ) // change: without any new: first
278  {
279  kdDebug( 172 ) << "[tdecore-tdestartupinfo] adding uninited" << endl;
280  d->uninited_startups.insert( id_P, data_P );
281  }
282  else if( data_P.silent() != Data::Yes || d->flags & AnnounceSilenceChanges )
283  {
284  kdDebug( 172 ) << "[tdecore-tdestartupinfo] adding" << endl;
285  d->startups.insert( id_P, data_P );
286  emit gotNewStartup( id_P, data_P );
287  }
288  else // new silenced, and silent shouldn't be announced
289  {
290  kdDebug( 172 ) << "[tdecore-tdestartupinfo] adding silent" << endl;
291  d->silent_startups.insert( id_P, data_P );
292  }
293  d->cleanup->start( 1000 ); // 1 sec
294  }
295 
296 void TDEStartupInfo::got_remove_startup_info( const TQString& msg_P )
297  {
298  TDEStartupInfoId id( msg_P );
299  TDEStartupInfoData data( msg_P );
300  if( data.pids().count() > 0 )
301  {
302  if( !id.none())
303  remove_startup_pids( id, data );
304  else
305  remove_startup_pids( data );
306  return;
307  }
308  remove_startup_info_internal( id );
309  }
310 
311 void TDEStartupInfo::remove_startup_info_internal( const TDEStartupInfoId& id_P )
312  {
313  if( d == NULL )
314  return;
315  if( d->startups.contains( id_P ))
316  {
317  kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing" << endl;
318  emit gotRemoveStartup( id_P, d->startups[ id_P ]);
319  d->startups.remove( id_P );
320  }
321  else if( d->silent_startups.contains( id_P ))
322  {
323  kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing silent" << endl;
324  d->silent_startups.remove( id_P );
325  }
326  else if( d->uninited_startups.contains( id_P ))
327  {
328  kdDebug( 172 ) << "[tdecore-tdestartupinfo] removing uninited" << endl;
329  d->uninited_startups.remove( id_P );
330  }
331  return;
332  }
333 
334 void TDEStartupInfo::remove_startup_pids( const TDEStartupInfoData& data_P )
335  { // first find the matching info
336  if( d == NULL )
337  return;
338  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
339  it != d->startups.end();
340  ++it )
341  {
342  if( ( *it ).hostname() != data_P.hostname())
343  continue;
344  if( !( *it ).is_pid( data_P.pids().first()))
345  continue; // not the matching info
346  remove_startup_pids( it.key(), data_P );
347  break;
348  }
349  }
350 
351 void TDEStartupInfo::remove_startup_pids( const TDEStartupInfoId& id_P,
352  const TDEStartupInfoData& data_P )
353  {
354  if( d == NULL )
355  return;
356  kdFatal( data_P.pids().count() == 0, 172 );
357  Data* data = NULL;
358  if( d->startups.contains( id_P ))
359  data = &d->startups[ id_P ];
360  else if( d->silent_startups.contains( id_P ))
361  data = &d->silent_startups[ id_P ];
362  else if( d->uninited_startups.contains( id_P ))
363  data = &d->uninited_startups[ id_P ];
364  else
365  return;
366  for( TQValueList< pid_t >::ConstIterator it2 = data_P.pids().begin();
367  it2 != data_P.pids().end();
368  ++it2 )
369  data->remove_pid( *it2 ); // remove all pids from the info
370  if( data->pids().count() == 0 ) // all pids removed -> remove info
371  remove_startup_info_internal( id_P );
372  }
373 
374 bool TDEStartupInfo::sendStartup( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
375  {
376  if( id_P.none())
377  return false;
378  KXMessages msgs;
379  TQString msg = TQString::fromLatin1( "new: %1 %2" )
380  .arg( id_P.to_text()).arg( data_P.to_text());
381  msg = check_required_startup_fields( msg, data_P, tqt_xscreen());
382  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
383  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
384  return true;
385  }
386 
387 bool TDEStartupInfo::sendStartupX( Display* disp_P, const TDEStartupInfoId& id_P,
388  const TDEStartupInfoData& data_P )
389  {
390  if( id_P.none())
391  return false;
392  TQString msg = TQString::fromLatin1( "new: %1 %2" )
393  .arg( id_P.to_text()).arg( data_P.to_text());
394  msg = check_required_startup_fields( msg, data_P, DefaultScreen( disp_P ));
395 #ifdef KSTARTUPINFO_ALL_DEBUG
396  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
397 #endif
398  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
399  }
400 
401 TQString TDEStartupInfo::check_required_startup_fields( const TQString& msg, const TDEStartupInfoData& data_P,
402  int screen )
403  {
404  TQString ret = msg;
405  if( data_P.name().isEmpty())
406  {
407 // kdWarning( 172 ) << "[tdecore-tdestartupinfo] NAME not specified in initial startup message" << endl;
408  TQString name = data_P.bin();
409  if( name.isEmpty())
410  name = "UNKNOWN";
411  ret += TQString( " NAME=\"%1\"" ).arg( escape_str( name ));
412  }
413  if( data_P.screen() == -1 ) // add automatically if needed
414  ret += TQString( " SCREEN=%1" ).arg( screen );
415  return ret;
416  }
417 
418 bool TDEStartupInfo::sendChange( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
419  {
420  if( id_P.none())
421  return false;
422  KXMessages msgs;
423  TQString msg = TQString::fromLatin1( "change: %1 %2" )
424  .arg( id_P.to_text()).arg( data_P.to_text());
425  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
426  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
427  return true;
428  }
429 
430 bool TDEStartupInfo::sendChangeX( Display* disp_P, const TDEStartupInfoId& id_P,
431  const TDEStartupInfoData& data_P )
432  {
433  if( id_P.none())
434  return false;
435  TQString msg = TQString::fromLatin1( "change: %1 %2" )
436  .arg( id_P.to_text()).arg( data_P.to_text());
437 #ifdef KSTARTUPINFO_ALL_DEBUG
438  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
439 #endif
440  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
441  }
442 
443 bool TDEStartupInfo::sendFinish( const TDEStartupInfoId& id_P )
444  {
445  if( id_P.none())
446  return false;
447  KXMessages msgs;
448  TQString msg = TQString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
449  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
450  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
451  return true;
452  }
453 
454 bool TDEStartupInfo::sendFinishX( Display* disp_P, const TDEStartupInfoId& id_P )
455  {
456  if( id_P.none())
457  return false;
458  TQString msg = TQString::fromLatin1( "remove: %1" ).arg( id_P.to_text());
459 #ifdef KSTARTUPINFO_ALL_DEBUG
460  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
461 #endif
462  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
463  }
464 
465 bool TDEStartupInfo::sendFinish( const TDEStartupInfoId& id_P, const TDEStartupInfoData& data_P )
466  {
467 // if( id_P.none()) // id may be none, the pids and hostname matter then
468 // return false;
469  KXMessages msgs;
470  TQString msg = TQString::fromLatin1( "remove: %1 %2" )
471  .arg( id_P.to_text()).arg( data_P.to_text());
472  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
473  msgs.broadcastMessage( NET_STARTUP_MSG, msg, -1, false );
474  return true;
475  }
476 
477 bool TDEStartupInfo::sendFinishX( Display* disp_P, const TDEStartupInfoId& id_P,
478  const TDEStartupInfoData& data_P )
479  {
480 // if( id_P.none()) // id may be none, the pids and hostname matter then
481 // return false;
482  TQString msg = TQString::fromLatin1( "remove: %1 %2" )
483  .arg( id_P.to_text()).arg( data_P.to_text());
484 #ifdef KSTARTUPINFO_ALL_DEBUG
485  kdDebug( 172 ) << "[tdecore-tdestartupinfo] sending " << msg << endl;
486 #endif
487  return KXMessages::broadcastMessageX( disp_P, NET_STARTUP_MSG, msg, -1, false );
488  }
489 
490 void TDEStartupInfo::appStarted()
491  {
492  if( kapp != NULL ) // TDEApplication constructor unsets the env. variable
493  appStarted( kapp->startupId());
494  else
495  appStarted( TDEStartupInfo::currentStartupIdEnv().id());
496  }
497 
498 void TDEStartupInfo::appStarted( const TQCString& startup_id )
499  {
500  TDEStartupInfoId id;
501  id.initId( startup_id );
502  if( id.none())
503  return;
504  if( kapp != NULL )
505  TDEStartupInfo::sendFinish( id );
506  else if( getenv( "DISPLAY" ) != NULL ) // don't rely on tqt_xdisplay()
507  {
508 #ifdef TQ_WS_X11
509  Display* disp = XOpenDisplay( NULL );
510  if( disp != NULL )
511  {
512  TDEStartupInfo::sendFinishX( disp, id );
513  XCloseDisplay( disp );
514  }
515 #endif
516  }
517  }
518 
519 void TDEStartupInfo::disableAutoAppStartedSending( bool disable )
520  {
521  auto_app_started_sending = !disable;
522  }
523 
524 void TDEStartupInfo::silenceStartup( bool silence )
525  {
526  TDEStartupInfoId id;
527  id.initId( kapp->startupId());
528  if( id.none())
529  return;
530  TDEStartupInfoData data;
531  data.setSilent( silence ? TDEStartupInfoData::Yes : TDEStartupInfoData::No );
532  sendChange( id, data );
533  }
534 
535 void TDEStartupInfo::handleAutoAppStartedSending()
536  {
537  if( auto_app_started_sending )
538  appStarted();
539  }
540 
541 void TDEStartupInfo::setNewStartupId( TQWidget* window, const TQCString& startup_id )
542  {
543  bool activate = true;
544  kapp->setStartupId( startup_id );
545  if( window != NULL )
546  {
547  if( !startup_id.isEmpty() && startup_id != "0" )
548  {
549  NETRootInfo i( tqt_xdisplay(), NET::Supported );
550  if( i.isSupported( NET::WM2StartupId ))
551  {
552  TDEStartupInfo::setWindowStartupId( window->winId(), startup_id );
553  activate = false; // WM will take care of it
554  }
555  }
556  if( activate )
557  {
558  KWin::setOnDesktop( window->winId(), KWin::currentDesktop());
559  // This is not very nice, but there's no way how to get any
560  // usable timestamp without ASN, so force activating the window.
561  // And even with ASN, it's not possible to get the timestamp here,
562  // so if the WM doesn't have support for ASN, it can't be used either.
563  KWin::forceActiveWindow( window->winId());
564  }
565  }
566  TDEStartupInfo::handleAutoAppStartedSending();
567  }
568 
569 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O,
570  TDEStartupInfoData& data_O )
571  {
572  return check_startup_internal( w_P, &id_O, &data_O );
573  }
574 
575 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O )
576  {
577  return check_startup_internal( w_P, &id_O, NULL );
578  }
579 
580 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoData& data_O )
581  {
582  return check_startup_internal( w_P, NULL, &data_O );
583  }
584 
585 TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P )
586  {
587  return check_startup_internal( w_P, NULL, NULL );
588  }
589 
590 TDEStartupInfo::startup_t TDEStartupInfo::check_startup_internal( WId w_P, TDEStartupInfoId* id_O,
591  TDEStartupInfoData* data_O )
592  {
593  if( d == NULL )
594  return NoMatch;
595  if( d->startups.count() == 0 )
596  return NoMatch; // no startups
597  // Strategy:
598  //
599  // Is this a compliant app ?
600  // - Yes - test for match
601  // - No - Is this a NET_WM compliant app ?
602  // - Yes - test for pid match
603  // - No - test for WM_CLASS match
604  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup" << endl;
605  TQCString id = windowStartupId( w_P );
606  if( !id.isNull())
607  {
608  if( id.isEmpty() || id == "0" ) // means ignore this window
609  {
610  kdDebug( 172 ) << "[tdecore-tdestartupinfo] ignore" << endl;
611  return NoMatch;
612  }
613  return find_id( id, id_O, data_O ) ? Match : NoMatch;
614  }
615 #ifdef TQ_WS_X11
616  NETWinInfo info( tqt_xdisplay(), w_P, tqt_xrootwin(),
617  NET::WMWindowType | NET::WMPid | NET::WMState );
618  pid_t pid = info.pid();
619  if( pid > 0 )
620  {
621  TQCString hostname = get_window_hostname( w_P );
622  if( !hostname.isEmpty()
623  && find_pid( pid, hostname, id_O, data_O ))
624  return Match;
625  // try XClass matching , this PID stuff sucks :(
626  }
627  XClassHint hint;
628  if( XGetClassHint( tqt_xdisplay(), w_P, &hint ) != 0 )
629  { // We managed to read the class hint
630  TQCString res_name = hint.res_name;
631  TQCString res_class = hint.res_class;
632  XFree( hint.res_name );
633  XFree( hint.res_class );
634  if( find_wclass( res_name, res_class, id_O, data_O ))
635  return Match;
636  }
637  // ignore NET::Tool and other special window types, if they can't be matched
638  NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask
639  | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
640  | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
641  if( type != NET::Normal
642  && type != NET::Override
643  && type != NET::Unknown
644  && type != NET::Dialog
645  && type != NET::Utility )
646 // && type != NET::Dock ) why did I put this here?
647  return NoMatch;
648  // lets see if this is a transient
649  Window transient_for;
650  if( XGetTransientForHint( tqt_xdisplay(), static_cast< Window >( w_P ), &transient_for )
651  && static_cast< WId >( transient_for ) != tqt_xrootwin()
652  && transient_for != None )
653  return NoMatch;
654 #endif
655  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup:cantdetect" << endl;
656  return CantDetect;
657  }
658 
659 bool TDEStartupInfo::find_id( const TQCString& id_P, TDEStartupInfoId* id_O,
660  TDEStartupInfoData* data_O )
661  {
662  if( d == NULL )
663  return false;
664  kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_id:" << id_P << endl;
665  TDEStartupInfoId id;
666  id.initId( id_P );
667  if( d->startups.contains( id ))
668  {
669  if( id_O != NULL )
670  *id_O = id;
671  if( data_O != NULL )
672  *data_O = d->startups[ id ];
673  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup_id:match" << endl;
674  return true;
675  }
676  return false;
677  }
678 
679 bool TDEStartupInfo::find_pid( pid_t pid_P, const TQCString& hostname_P,
680  TDEStartupInfoId* id_O, TDEStartupInfoData* data_O )
681  {
682  if( d == NULL )
683  return false;
684  kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_pid:" << pid_P << endl;
685  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
686  it != d->startups.end();
687  ++it )
688  {
689  if( ( *it ).is_pid( pid_P ) && ( *it ).hostname() == hostname_P )
690  { // Found it !
691  if( id_O != NULL )
692  *id_O = it.key();
693  if( data_O != NULL )
694  *data_O = *it;
695  // non-compliant, remove on first match
696  remove_startup_info_internal( it.key());
697  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup_pid:match" << endl;
698  return true;
699  }
700  }
701  return false;
702  }
703 
704 bool TDEStartupInfo::find_wclass( TQCString res_name, TQCString res_class,
705  TDEStartupInfoId* id_O, TDEStartupInfoData* data_O )
706  {
707  if( d == NULL )
708  return false;
709  res_name = res_name.lower();
710  res_class = res_class.lower();
711  kdDebug( 172 ) << "[tdecore-tdestartupinfo] find_wclass:" << res_name << ":" << res_class << endl;
712  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
713  it != d->startups.end();
714  ++it )
715  {
716  const TQCString wmclass = ( *it ).findWMClass();
717  if( wmclass.lower() == res_name || wmclass.lower() == res_class )
718  { // Found it !
719  if( id_O != NULL )
720  *id_O = it.key();
721  if( data_O != NULL )
722  *data_O = *it;
723  // non-compliant, remove on first match
724  remove_startup_info_internal( it.key());
725  kdDebug( 172 ) << "[tdecore-tdestartupinfo] check_startup_wclass:match" << endl;
726  return true;
727  }
728  }
729  return false;
730  }
731 
732 #ifdef TQ_WS_X11
733 static Atom net_startup_atom = None;
734 
735 static TQCString read_startup_id_property( WId w_P )
736  {
737  TQCString ret;
738  unsigned char *name_ret;
739  Atom type_ret;
740  int format_ret;
741  unsigned long nitems_ret = 0, after_ret = 0;
742  if( XGetWindowProperty( tqt_xdisplay(), w_P, net_startup_atom, 0l, 4096,
743  False, utf8_string_atom, &type_ret, &format_ret, &nitems_ret, &after_ret, &name_ret )
744  == Success )
745  {
746  if( type_ret == utf8_string_atom && format_ret == 8 && name_ret != NULL )
747  ret = reinterpret_cast< char* >( name_ret );
748  if ( name_ret != NULL )
749  XFree( name_ret );
750  }
751  return ret;
752  }
753 
754 #endif
755 
756 TQCString TDEStartupInfo::windowStartupId( WId w_P )
757  {
758 #ifdef TQ_WS_X11
759  if( net_startup_atom == None )
760  net_startup_atom = XInternAtom( tqt_xdisplay(), NET_STARTUP_WINDOW, False );
761  if( utf8_string_atom == None )
762  utf8_string_atom = XInternAtom( tqt_xdisplay(), "UTF8_STRING", False );
763  TQCString ret = read_startup_id_property( w_P );
764  if( ret.isEmpty())
765  { // retry with window group leader, as the spec says
766  XWMHints* hints = XGetWMHints( tqt_xdisplay(), w_P );
767  if( hints && ( hints->flags & WindowGroupHint ) != 0 )
768  ret = read_startup_id_property( hints->window_group );
769  if( hints )
770  XFree( hints );
771  }
772  return ret;
773 #else
774  return TQCString();
775 #endif
776  }
777 
778 void TDEStartupInfo::setWindowStartupId( WId w_P, const TQCString& id_P )
779  {
780 #ifdef TQ_WS_X11
781  if( id_P.isNull())
782  return;
783  if( net_startup_atom == None )
784  net_startup_atom = XInternAtom( tqt_xdisplay(), NET_STARTUP_WINDOW, False );
785  if( utf8_string_atom == None )
786  utf8_string_atom = XInternAtom( tqt_xdisplay(), "UTF8_STRING", False );
787  XChangeProperty( tqt_xdisplay(), w_P, net_startup_atom, utf8_string_atom, 8,
788  PropModeReplace, reinterpret_cast< unsigned char* >( const_cast<TQCString&>(id_P).data()), id_P.length());
789 #endif
790  }
791 
792 TQCString TDEStartupInfo::get_window_hostname( WId w_P )
793  {
794 #ifdef TQ_WS_X11
795  XTextProperty tp;
796  char** hh;
797  int cnt;
798  if( XGetWMClientMachine( tqt_xdisplay(), w_P, &tp ) != 0
799  && XTextPropertyToStringList( &tp, &hh, &cnt ) != 0 )
800  {
801  if( cnt == 1 )
802  {
803  TQCString hostname = hh[ 0 ];
804  XFreeStringList( hh );
805  return hostname;
806  }
807  XFreeStringList( hh );
808  }
809 #endif
810  // no hostname
811  return TQCString();
812  }
813 
814 void TDEStartupInfo::setTimeout( unsigned int secs_P )
815  {
816  timeout = secs_P;
817  // schedule removing entries that are older than the new timeout
818  TQTimer::singleShot( 0, this, TQ_SLOT( startups_cleanup_no_age()));
819  }
820 
821 void TDEStartupInfo::startups_cleanup_no_age()
822  {
823  startups_cleanup_internal( false );
824  }
825 
826 void TDEStartupInfo::startups_cleanup()
827  {
828  if( d == NULL )
829  return;
830  if( d->startups.count() == 0 && d->silent_startups.count() == 0
831  && d->uninited_startups.count() == 0 )
832  {
833  d->cleanup->stop();
834  return;
835  }
836  startups_cleanup_internal( true );
837  }
838 
839 void TDEStartupInfo::startups_cleanup_internal( bool age_P )
840  {
841  if( d == NULL )
842  return;
843  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
844  it != d->startups.end();
845  )
846  {
847  if( age_P )
848  ( *it ).age++;
849  unsigned int tout = timeout;
850  if( ( *it ).silent() == Data::Yes ) // TODO
851  tout *= 20;
852  if( ( *it ).age >= tout )
853  {
854  const TDEStartupInfoId& key = it.key();
855  ++it;
856  kdDebug( 172 ) << "[tdecore-tdestartupinfo] startups entry timeout:" << key.id() << endl;
857  remove_startup_info_internal( key );
858  }
859  else
860  ++it;
861  }
862  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->silent_startups.begin();
863  it != d->silent_startups.end();
864  )
865  {
866  if( age_P )
867  ( *it ).age++;
868  unsigned int tout = timeout;
869  if( ( *it ).silent() == Data::Yes ) // TODO
870  tout *= 20;
871  if( ( *it ).age >= tout )
872  {
873  const TDEStartupInfoId& key = it.key();
874  ++it;
875  kdDebug( 172 ) << "[tdecore-tdestartupinfo] silent entry timeout:" << key.id() << endl;
876  remove_startup_info_internal( key );
877  }
878  else
879  ++it;
880  }
881  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->uninited_startups.begin();
882  it != d->uninited_startups.end();
883  )
884  {
885  if( age_P )
886  ( *it ).age++;
887  unsigned int tout = timeout;
888  if( ( *it ).silent() == Data::Yes ) // TODO
889  tout *= 20;
890  if( ( *it ).age >= tout )
891  {
892  const TDEStartupInfoId& key = it.key();
893  ++it;
894  kdDebug( 172 ) << "[tdecore-tdestartupinfo] uninited entry timeout:" << key.id() << endl;
895  remove_startup_info_internal( key );
896  }
897  else
898  ++it;
899  }
900  }
901 
902 void TDEStartupInfo::clean_all_noncompliant()
903  {
904  if( d == NULL )
905  return;
906  for( TQMap< TDEStartupInfoId, Data >::Iterator it = d->startups.begin();
907  it != d->startups.end();
908  )
909  {
910  if( ( *it ).WMClass() != "0" )
911  {
912  ++it;
913  continue;
914  }
915  const TDEStartupInfoId& key = it.key();
916  ++it;
917  kdDebug( 172 ) << "[tdecore-tdestartupinfo] entry cleaning:" << key.id() << endl;
918  remove_startup_info_internal( key );
919  }
920  }
921 
922 TQCString TDEStartupInfo::createNewStartupId()
923  {
924  // Assign a unique id, use hostname+time+pid, that should be 200% unique.
925  // Also append the user timestamp (for focus stealing prevention).
926  struct timeval tm;
927  gettimeofday( &tm, NULL );
928  char hostname[ 256 ];
929  hostname[ 0 ] = '\0';
930  if (!gethostname( hostname, 255 ))
931  hostname[sizeof(hostname)-1] = '\0';
932  TQCString id = TQString(TQString( "%1;%2;%3;%4_TIME%5" ).arg( hostname ).arg( tm.tv_sec )
933  .arg( tm.tv_usec ).arg( getpid()).arg( get_tqt_x_user_time() )).utf8();
934  kdDebug( 172 ) << "[tdecore-tdestartupinfo] creating: " << id << ":" << tqAppName() << endl;
935  return id;
936  }
937 
938 
939 struct TDEStartupInfoIdPrivate
940  {
941  TDEStartupInfoIdPrivate() : id( "" ) {}
942  TQCString id; // id
943  };
944 
945 const TQCString& TDEStartupInfoId::id() const
946  {
947  return d->id;
948  }
949 
950 
951 TQString TDEStartupInfoId::to_text() const
952  {
953  return TQString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
954  }
955 
956 TDEStartupInfoId::TDEStartupInfoId( const TQString& txt_P )
957  {
958  d = new TDEStartupInfoIdPrivate;
959  TQStringList items = get_fields( txt_P );
960  const TQString id_str = TQString::fromLatin1( "ID=" );
961  for( TQStringList::Iterator it = items.begin();
962  it != items.end();
963  ++it )
964  {
965  if( ( *it ).startsWith( id_str ))
966  d->id = get_cstr( *it );
967  }
968  }
969 
970 void TDEStartupInfoId::initId( const TQCString& id_P )
971  {
972  if( !id_P.isEmpty())
973  {
974  d->id = id_P;
975 #ifdef KSTARTUPINFO_ALL_DEBUG
976  kdDebug( 172 ) << "[tdecore-tdestartupinfo] using: " << d->id << endl;
977 #endif
978  return;
979  }
980  const char* startup_env = getenv( NET_STARTUP_ENV );
981  if( startup_env != NULL && *startup_env != '\0' )
982  { // already has id
983  d->id = startup_env;
984 #ifdef KSTARTUPINFO_ALL_DEBUG
985  kdDebug( 172 ) << "[tdecore-tdestartupinfo] reusing: " << d->id << endl;
986 #endif
987  return;
988  }
989  d->id = TDEStartupInfo::createNewStartupId();
990  }
991 
992 bool TDEStartupInfoId::setupStartupEnv() const
993  {
994  if( id().isEmpty())
995  {
996  unsetenv( NET_STARTUP_ENV );
997  return false;
998  }
999  return setenv( NET_STARTUP_ENV, id(), true ) == 0;
1000  }
1001 
1002 TDEStartupInfoId TDEStartupInfo::currentStartupIdEnv()
1003  {
1004  const char* startup_env = getenv( NET_STARTUP_ENV );
1005  TDEStartupInfoId id;
1006  if( startup_env != NULL && *startup_env != '\0' )
1007  id.d->id = startup_env;
1008  else
1009  id.d->id = "0";
1010  return id;
1011  }
1012 
1013 void TDEStartupInfo::resetStartupEnv()
1014  {
1015  unsetenv( NET_STARTUP_ENV );
1016  }
1017 
1018 TDEStartupInfoId::TDEStartupInfoId()
1019  {
1020  d = new TDEStartupInfoIdPrivate;
1021  }
1022 
1023 TDEStartupInfoId::~TDEStartupInfoId()
1024  {
1025  delete d;
1026  }
1027 
1028 TDEStartupInfoId::TDEStartupInfoId( const TDEStartupInfoId& id_P )
1029  {
1030  d = new TDEStartupInfoIdPrivate( *id_P.d );
1031  }
1032 
1033 TDEStartupInfoId& TDEStartupInfoId::operator=( const TDEStartupInfoId& id_P )
1034  {
1035  if( &id_P == this )
1036  return *this;
1037  delete d;
1038  d = new TDEStartupInfoIdPrivate( *id_P.d );
1039  return *this;
1040  }
1041 
1042 bool TDEStartupInfoId::operator==( const TDEStartupInfoId& id_P ) const
1043  {
1044  return id() == id_P.id();
1045  }
1046 
1047 bool TDEStartupInfoId::operator!=( const TDEStartupInfoId& id_P ) const
1048  {
1049  return !(*this == id_P );
1050  }
1051 
1052 // needed for QMap
1053 bool TDEStartupInfoId::operator<( const TDEStartupInfoId& id_P ) const
1054  {
1055  return id() < id_P.id();
1056  }
1057 
1058 bool TDEStartupInfoId::none() const
1059  {
1060  return d->id.isEmpty() || d->id == "0";
1061  }
1062 
1063 unsigned long TDEStartupInfoId::timestamp() const
1064  {
1065  if( none())
1066  return 0;
1067  int pos = d->id.findRev( "_TIME" );
1068  if( pos >= 0 )
1069  {
1070  bool ok;
1071  unsigned long time = d->id.mid( pos + 5 ).toULong( &ok );
1072  if( !ok && d->id[ pos + 5 ] == '-' ) // try if it's as a negative signed number perhaps
1073  time = d->id.mid( pos + 5 ).toLong( &ok );
1074  if( ok )
1075  return time;
1076  }
1077  // libstartup-notification style :
1078  // snprintf (s, len, "%s/%s/%lu/%d-%d-%s",
1079  // canonicalized_launcher, canonicalized_launchee, (unsigned long) timestamp,
1080  // (int) getpid (), (int) sequence_number, hostbuf);
1081  int pos1 = d->id.findRev( '/' );
1082  if( pos1 > 0 )
1083  {
1084  int pos2 = d->id.findRev( '/', pos1 - 1 );
1085  if( pos2 >= 0 )
1086  {
1087  bool ok;
1088  unsigned long time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toULong( &ok );
1089  if( !ok && d->id[ pos2 + 1 ] == '-' ) // try if it's as a negative signed number perhaps
1090  time = d->id.mid( pos2 + 1, pos1 - pos2 - 1 ).toLong( &ok );
1091  if( ok )
1092  return time;
1093  }
1094  }
1095  // bah ... old TDEStartupInfo or a problem
1096  return 0;
1097  }
1098 
1099 struct TDEStartupInfoDataPrivate
1100  {
1101  TDEStartupInfoDataPrivate() : desktop( 0 ), wmclass( "" ), hostname( "" ),
1102  silent( TDEStartupInfoData::Unknown ), timestamp( -1U ), screen( -1 ), xinerama( -1 ), launched_by( 0 ) {}
1103  TQString bin;
1104  TQString name;
1105  TQString description;
1106  TQString icon;
1107  int desktop;
1108  TQValueList< pid_t > pids;
1109  TQCString wmclass;
1110  TQCString hostname;
1111  TDEStartupInfoData::TriState silent;
1112  unsigned long timestamp;
1113  int screen;
1114  int xinerama;
1115  WId launched_by;
1116  };
1117 
1118 TQString TDEStartupInfoData::to_text() const
1119  {
1120  TQString ret = "";
1121  if( !d->bin.isEmpty())
1122  ret += TQString::fromLatin1( " BIN=\"%1\"" ).arg( escape_str( d->bin ));
1123  if( !d->name.isEmpty())
1124  ret += TQString::fromLatin1( " NAME=\"%1\"" ).arg( escape_str( d->name ));
1125  if( !d->description.isEmpty())
1126  ret += TQString::fromLatin1( " DESCRIPTION=\"%1\"" ).arg( escape_str( d->description ));
1127  if( !d->icon.isEmpty())
1128  ret += TQString::fromLatin1( " ICON=%1" ).arg( d->icon );
1129  if( d->desktop != 0 )
1130  ret += TQString::fromLatin1( " DESKTOP=%1" )
1131  .arg( d->desktop == NET::OnAllDesktops ? NET::OnAllDesktops : d->desktop - 1 ); // spec counts from 0
1132  if( !d->wmclass.isEmpty())
1133  ret += TQString::fromLatin1( " WMCLASS=\"%1\"" ).arg( TQString(d->wmclass) );
1134  if( !d->hostname.isEmpty())
1135  ret += TQString::fromLatin1( " HOSTNAME=%1" ).arg( TQString(d->hostname) );
1136  for( TQValueList< pid_t >::ConstIterator it = d->pids.begin();
1137  it != d->pids.end();
1138  ++it )
1139  ret += TQString::fromLatin1( " PID=%1" ).arg( *it );
1140  if( d->silent != Unknown )
1141  ret += TQString::fromLatin1( " SILENT=%1" ).arg( d->silent == Yes ? 1 : 0 );
1142  if( d->timestamp != -1U )
1143  ret += TQString::fromLatin1( " TIMESTAMP=%1" ).arg( d->timestamp );
1144  if( d->screen != -1 )
1145  ret += TQString::fromLatin1( " SCREEN=%1" ).arg( d->screen );
1146  if( d->xinerama != -1 )
1147  ret += TQString::fromLatin1( " XINERAMA=%1" ).arg( d->xinerama );
1148  if( d->launched_by != 0 )
1149  ret += TQString::fromLatin1( " LAUNCHED_BY=%1" ).arg( d->launched_by );
1150  return ret;
1151  }
1152 
1153 TDEStartupInfoData::TDEStartupInfoData( const TQString& txt_P )
1154  {
1155  d = new TDEStartupInfoDataPrivate;
1156  TQStringList items = get_fields( txt_P );
1157  const TQString bin_str = TQString::fromLatin1( "BIN=" );
1158  const TQString name_str = TQString::fromLatin1( "NAME=" );
1159  const TQString description_str = TQString::fromLatin1( "DESCRIPTION=" );
1160  const TQString icon_str = TQString::fromLatin1( "ICON=" );
1161  const TQString desktop_str = TQString::fromLatin1( "DESKTOP=" );
1162  const TQString wmclass_str = TQString::fromLatin1( "WMCLASS=" );
1163  const TQString hostname_str = TQString::fromLatin1( "HOSTNAME=" ); // SELI nonstd
1164  const TQString pid_str = TQString::fromLatin1( "PID=" ); // SELI nonstd
1165  const TQString silent_str = TQString::fromLatin1( "SILENT=" );
1166  const TQString timestamp_str = TQString::fromLatin1( "TIMESTAMP=" );
1167  const TQString screen_str = TQString::fromLatin1( "SCREEN=" );
1168  const TQString xinerama_str = TQString::fromLatin1( "XINERAMA=" );
1169  const TQString launched_by_str = TQString::fromLatin1( "LAUNCHED_BY=" );
1170  for( TQStringList::Iterator it = items.begin();
1171  it != items.end();
1172  ++it )
1173  {
1174  if( ( *it ).startsWith( bin_str ))
1175  d->bin = get_str( *it );
1176  else if( ( *it ).startsWith( name_str ))
1177  d->name = get_str( *it );
1178  else if( ( *it ).startsWith( description_str ))
1179  d->description = get_str( *it );
1180  else if( ( *it ).startsWith( icon_str ))
1181  d->icon = get_str( *it );
1182  else if( ( *it ).startsWith( desktop_str ))
1183  {
1184  d->desktop = get_num( *it );
1185  if( d->desktop != NET::OnAllDesktops )
1186  ++d->desktop; // spec counts from 0
1187  }
1188  else if( ( *it ).startsWith( wmclass_str ))
1189  d->wmclass = get_cstr( *it );
1190  else if( ( *it ).startsWith( hostname_str ))
1191  d->hostname = get_cstr( *it );
1192  else if( ( *it ).startsWith( pid_str ))
1193  addPid( get_num( *it ));
1194  else if( ( *it ).startsWith( silent_str ))
1195  d->silent = get_num( *it ) != 0 ? Yes : No;
1196  else if( ( *it ).startsWith( timestamp_str ))
1197  d->timestamp = get_unum( *it );
1198  else if( ( *it ).startsWith( screen_str ))
1199  d->screen = get_num( *it );
1200  else if( ( *it ).startsWith( xinerama_str ))
1201  d->xinerama = get_num( *it );
1202  else if( ( *it ).startsWith( launched_by_str ))
1203  d->launched_by = get_num( *it );
1204  }
1205  }
1206 
1207 TDEStartupInfoData::TDEStartupInfoData( const TDEStartupInfoData& data )
1208 {
1209  d = new TDEStartupInfoDataPrivate( *data.d );
1210 }
1211 
1212 TDEStartupInfoData& TDEStartupInfoData::operator=( const TDEStartupInfoData& data )
1213 {
1214  if( &data == this )
1215  return *this;
1216  delete d;
1217  d = new TDEStartupInfoDataPrivate( *data.d );
1218  return *this;
1219 }
1220 
1221 void TDEStartupInfoData::update( const TDEStartupInfoData& data_P )
1222  {
1223  if( !data_P.bin().isEmpty())
1224  d->bin = data_P.bin();
1225  if( !data_P.name().isEmpty() && name().isEmpty()) // don't overwrite
1226  d->name = data_P.name();
1227  if( !data_P.description().isEmpty() && description().isEmpty()) // don't overwrite
1228  d->description = data_P.description();
1229  if( !data_P.icon().isEmpty() && icon().isEmpty()) // don't overwrite
1230  d->icon = data_P.icon();
1231  if( data_P.desktop() != 0 && desktop() == 0 ) // don't overwrite
1232  d->desktop = data_P.desktop();
1233  if( !data_P.d->wmclass.isEmpty())
1234  d->wmclass = data_P.d->wmclass;
1235  if( !data_P.d->hostname.isEmpty())
1236  d->hostname = data_P.d->hostname;
1237  for( TQValueList< pid_t >::ConstIterator it = data_P.d->pids.begin();
1238  it != data_P.d->pids.end();
1239  ++it )
1240  addPid( *it );
1241  if( data_P.silent() != Unknown )
1242  d->silent = data_P.silent();
1243  if( data_P.timestamp() != -1U && timestamp() == -1U ) // don't overwrite
1244  d->timestamp = data_P.timestamp();
1245  if( data_P.screen() != -1 )
1246  d->screen = data_P.screen();
1247  if( data_P.xinerama() != -1 && xinerama() != -1 ) // don't overwrite
1248  d->xinerama = data_P.xinerama();
1249  if( data_P.launchedBy() != 0 && launchedBy() != 0 ) // don't overwrite
1250  d->launched_by = data_P.launchedBy();
1251  }
1252 
1253 TDEStartupInfoData::TDEStartupInfoData()
1254 {
1255  d = new TDEStartupInfoDataPrivate;
1256 }
1257 
1258 TDEStartupInfoData::~TDEStartupInfoData()
1259 {
1260  delete d;
1261 }
1262 
1263 void TDEStartupInfoData::setBin( const TQString& bin_P )
1264  {
1265  d->bin = bin_P;
1266  }
1267 
1268 const TQString& TDEStartupInfoData::bin() const
1269  {
1270  return d->bin;
1271  }
1272 
1273 void TDEStartupInfoData::setName( const TQString& name_P )
1274  {
1275  d->name = name_P;
1276  }
1277 
1278 const TQString& TDEStartupInfoData::name() const
1279  {
1280  return d->name;
1281  }
1282 
1283 const TQString& TDEStartupInfoData::findName() const
1284  {
1285  if( !name().isEmpty())
1286  return name();
1287  return bin();
1288  }
1289 
1290 void TDEStartupInfoData::setDescription( const TQString& desc_P )
1291  {
1292  d->description = desc_P;
1293  }
1294 
1295 const TQString& TDEStartupInfoData::description() const
1296  {
1297  return d->description;
1298  }
1299 
1300 const TQString& TDEStartupInfoData::findDescription() const
1301  {
1302  if( !description().isEmpty())
1303  return description();
1304  return name();
1305  }
1306 
1307 void TDEStartupInfoData::setIcon( const TQString& icon_P )
1308  {
1309  d->icon = icon_P;
1310  }
1311 
1312 const TQString& TDEStartupInfoData::findIcon() const
1313  {
1314  if( !icon().isEmpty())
1315  return icon();
1316  return bin();
1317  }
1318 
1319 const TQString& TDEStartupInfoData::icon() const
1320  {
1321  return d->icon;
1322  }
1323 
1324 void TDEStartupInfoData::setDesktop( int desktop_P )
1325  {
1326  d->desktop = desktop_P;
1327  }
1328 
1329 int TDEStartupInfoData::desktop() const
1330  {
1331  return d->desktop;
1332  }
1333 
1334 void TDEStartupInfoData::setWMClass( const TQCString& wmclass_P )
1335  {
1336  d->wmclass = wmclass_P;
1337  }
1338 
1339 const TQCString TDEStartupInfoData::findWMClass() const
1340  {
1341  if( !WMClass().isEmpty() && WMClass() != "0" )
1342  return WMClass();
1343  return bin().utf8();
1344  }
1345 
1346 const TQCString& TDEStartupInfoData::WMClass() const
1347  {
1348  return d->wmclass;
1349  }
1350 
1351 void TDEStartupInfoData::setHostname( const TQCString& hostname_P )
1352  {
1353  if( !hostname_P.isNull())
1354  d->hostname = hostname_P;
1355  else
1356  {
1357  char tmp[ 256 ];
1358  tmp[ 0 ] = '\0';
1359  if (!gethostname( tmp, 255 ))
1360  tmp[sizeof(tmp)-1] = '\0';
1361  d->hostname = tmp;
1362  }
1363  }
1364 
1365 const TQCString& TDEStartupInfoData::hostname() const
1366  {
1367  return d->hostname;
1368  }
1369 
1370 void TDEStartupInfoData::addPid( pid_t pid_P )
1371  {
1372  if( !d->pids.contains( pid_P ))
1373  d->pids.append( pid_P );
1374  }
1375 
1376 void TDEStartupInfoData::remove_pid( pid_t pid_P )
1377  {
1378  d->pids.remove( pid_P );
1379  }
1380 
1381 const TQValueList< pid_t >& TDEStartupInfoData::pids() const
1382  {
1383  return d->pids;
1384  }
1385 
1386 bool TDEStartupInfoData::is_pid( pid_t pid_P ) const
1387  {
1388  return d->pids.contains( pid_P );
1389  }
1390 
1391 void TDEStartupInfoData::setSilent( TriState state_P )
1392  {
1393  d->silent = state_P;
1394  }
1395 
1396 TDEStartupInfoData::TriState TDEStartupInfoData::silent() const
1397  {
1398  return d->silent;
1399  }
1400 
1401 void TDEStartupInfoData::setTimestamp( unsigned long time )
1402  {
1403  d->timestamp = time;
1404  }
1405 
1406 unsigned long TDEStartupInfoData::timestamp() const
1407  {
1408  return d->timestamp;
1409  }
1410 
1411 void TDEStartupInfoData::setScreen( int screen )
1412  {
1413  d->screen = screen;
1414  }
1415 
1416 int TDEStartupInfoData::screen() const
1417  {
1418  return d->screen;
1419  }
1420 
1421 void TDEStartupInfoData::setXinerama( int xinerama )
1422  {
1423  d->xinerama = xinerama;
1424  }
1425 
1426 int TDEStartupInfoData::xinerama() const
1427  {
1428  return d->xinerama;
1429  }
1430 
1431 void TDEStartupInfoData::setLaunchedBy( WId window )
1432  {
1433  d->launched_by = window;
1434  }
1435 
1436 WId TDEStartupInfoData::launchedBy() const
1437  {
1438  return d->launched_by;
1439  }
1440 
1441 static
1442 long get_num( const TQString& item_P )
1443  {
1444  unsigned int pos = item_P.find( '=' );
1445  return item_P.mid( pos + 1 ).toLong();
1446  }
1447 
1448 static
1449 unsigned long get_unum( const TQString& item_P )
1450  {
1451  unsigned int pos = item_P.find( '=' );
1452  return item_P.mid( pos + 1 ).toULong();
1453  }
1454 
1455 static
1456 TQString get_str( const TQString& item_P )
1457  {
1458  unsigned int pos = item_P.find( '=' );
1459  if( item_P.length() > pos + 2 && item_P[ pos + 1 ] == (TQChar)'\"' )
1460  {
1461  int pos2 = item_P.left( pos + 2 ).find( '\"' );
1462  if( pos2 < 0 )
1463  return TQString::null; // 01234
1464  return item_P.mid( pos + 2, pos2 - 2 - pos ); // A="C"
1465  }
1466  return item_P.mid( pos + 1 );
1467  }
1468 
1469 static
1470 TQCString get_cstr( const TQString& item_P )
1471  {
1472  return get_str( item_P ).utf8();
1473  }
1474 
1475 static
1476 TQStringList get_fields( const TQString& txt_P )
1477  {
1478  TQString txt = txt_P.simplifyWhiteSpace();
1479  TQStringList ret;
1480  TQString item = "";
1481  bool in = false;
1482  bool escape = false;
1483  for( unsigned int pos = 0;
1484  pos < txt.length();
1485  ++pos )
1486  {
1487  if( escape )
1488  {
1489  item += txt[ pos ];
1490  escape = false;
1491  }
1492  else if( txt[ pos ] == '\\' )
1493  escape = true;
1494  else if( txt[ pos ] == '\"' )
1495  in = !in;
1496  else if( txt[ pos ] == ' ' && !in )
1497  {
1498  ret.append( item );
1499  item = "";
1500  }
1501  else
1502  item += txt[ pos ];
1503  }
1504  ret.append( item );
1505  return ret;
1506  }
1507 
1508 static TQString escape_str( const TQString& str_P )
1509  {
1510  TQString ret = "";
1511  for( unsigned int pos = 0;
1512  pos < str_P.length();
1513  ++pos )
1514  {
1515  if( str_P[ pos ] == (TQChar)'\\'
1516  || str_P[ pos ] == (TQChar)'"' )
1517  ret += '\\';
1518  ret += str_P[ pos ];
1519  }
1520  return ret;
1521  }
1522 
1523 #include "tdestartupinfo.moc"
1524 #endif
KWinModule
The class KWinModule provides information about the state of the window manager as required by window...
Definition: twinmodule.h:53
KWin::forceActiveWindow
static void forceActiveWindow(WId win, long time=0)
Sets window win to be the active window.
Definition: twin.cpp:249
KWin::setOnDesktop
static void setOnDesktop(WId win, int desktop)
Moves window win to desktop desktop.
Definition: twin.cpp:597
KWin::currentDesktop
static int currentDesktop()
Convenience function to access the current desktop.
Definition: twin.cpp:641
NET::WindowType
WindowType
Window type.
Definition: netwm_def.h:294
NET::Override
@ Override
Definition: netwm_def.h:302
NET::Utility
@ Utility
Definition: netwm_def.h:305
TDEApplication::kApplication
static TDEApplication * kApplication()
Returns the current application object.
Definition: tdeapplication.h:299
TDEGlobal::kdFatal
kdbgstream kdFatal(int area=0)
Returns a fatal error stream.
Definition: kdebug.cpp:378
TDEGlobal::kdDebug
kdbgstream kdDebug(int area=0)
Returns a debug stream.
Definition: kdebug.cpp:371
TDEGlobal::endl
kdbgstream & endl(kdbgstream &s)
Prints an "\n".
Definition: kdebug.h:430
KStdAction::name
const char * name(StdAction id)
TDEStdAccel::key
int key(StdAccel id)
Definition: tdestdaccel.cpp:383
TDEStdAccel::description
TQString description(StdAccel id)
Definition: tdestdaccel.cpp:381

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.1
This website is maintained by Timothy Pearson.