• 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
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the "Software"),
9to deal in the Software without restriction, including without limitation
10the rights to use, copy, modify, merge, publish, distribute, sublicense,
11and/or sell copies of the Software, and to permit persons to whom the
12Software is furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS 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
61static const char* const NET_STARTUP_MSG = "_NET_STARTUP_INFO";
62static 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
65static const char* const NET_STARTUP_ENV = "DESKTOP_STARTUP_ID";
66
67static bool auto_app_started_sending = true;
68
69static long get_num( const TQString& item_P );
70static unsigned long get_unum( const TQString& item_P );
71static TQString get_str( const TQString& item_P );
72static TQCString get_cstr( const TQString& item_P );
73static TQStringList get_fields( const TQString& txt_P );
74static TQString escape_str( const TQString& str_P );
75
76static Atom utf8_string_atom = None;
77
78class 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
88struct 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
110TDEStartupInfo::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
117TDEStartupInfo::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
124void TDEStartupInfo::init( int flags_P )
125 {
126 // d == NULL means "disabled"
127 if( !tdeApp)
128 return;
129 if( !tdeApp->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
148TDEStartupInfo::~TDEStartupInfo()
149 {
150 delete d;
151 }
152
153void 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???
172namespace
173{
174class 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
184void TDEStartupInfo::slot_window_added( WId w_P )
185 {
186 tdeApp->postEvent( this, new DelayedWindowEvent( w_P ));
187 }
188
189void 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
197void 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
216void 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
225void 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
296void 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
311void 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
334void 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
351void 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
374bool 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
387bool 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
401TQString 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
418bool 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
430bool 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
443bool 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
454bool 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
465bool 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
477bool 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
490void TDEStartupInfo::appStarted()
491 {
492 if( tdeApp != NULL ) // TDEApplication constructor unsets the env. variable
493 appStarted( tdeApp->startupId());
494 else
495 appStarted( TDEStartupInfo::currentStartupIdEnv().id());
496 }
497
498void TDEStartupInfo::appStarted( const TQCString& startup_id )
499 {
500 TDEStartupInfoId id;
501 id.initId( startup_id );
502 if( id.none())
503 return;
504 if( tdeApp != 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
519void TDEStartupInfo::disableAutoAppStartedSending( bool disable )
520 {
521 auto_app_started_sending = !disable;
522 }
523
524void TDEStartupInfo::silenceStartup( bool silence )
525 {
526 TDEStartupInfoId id;
527 id.initId( tdeApp->startupId());
528 if( id.none())
529 return;
530 TDEStartupInfoData data;
531 data.setSilent( silence ? TDEStartupInfoData::Yes : TDEStartupInfoData::No );
532 sendChange( id, data );
533 }
534
535void TDEStartupInfo::handleAutoAppStartedSending()
536 {
537 if( auto_app_started_sending )
538 appStarted();
539 }
540
541void TDEStartupInfo::setNewStartupId( TQWidget* window, const TQCString& startup_id )
542 {
543 bool activate = true;
544 tdeApp->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
569TDEStartupInfo::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
575TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoId& id_O )
576 {
577 return check_startup_internal( w_P, &id_O, NULL );
578 }
579
580TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P, TDEStartupInfoData& data_O )
581 {
582 return check_startup_internal( w_P, NULL, &data_O );
583 }
584
585TDEStartupInfo::startup_t TDEStartupInfo::checkStartup( WId w_P )
586 {
587 return check_startup_internal( w_P, NULL, NULL );
588 }
589
590TDEStartupInfo::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
659bool 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
679bool 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
704bool 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
733static Atom net_startup_atom = None;
734
735static 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
756TQCString 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
778void 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
792TQCString 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
814void 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
821void TDEStartupInfo::startups_cleanup_no_age()
822 {
823 startups_cleanup_internal( false );
824 }
825
826void 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
839void 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
902void 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
922TQCString 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
939struct TDEStartupInfoIdPrivate
940 {
941 TDEStartupInfoIdPrivate() : id( "" ) {}
942 TQCString id; // id
943 };
944
945const TQCString& TDEStartupInfoId::id() const
946 {
947 return d->id;
948 }
949
950
951TQString TDEStartupInfoId::to_text() const
952 {
953 return TQString::fromLatin1( " ID=\"%1\" " ).arg( escape_str( id()));
954 }
955
956TDEStartupInfoId::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
970void 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
992bool 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
1002TDEStartupInfoId 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
1013void TDEStartupInfo::resetStartupEnv()
1014 {
1015 unsetenv( NET_STARTUP_ENV );
1016 }
1017
1018TDEStartupInfoId::TDEStartupInfoId()
1019 {
1020 d = new TDEStartupInfoIdPrivate;
1021 }
1022
1023TDEStartupInfoId::~TDEStartupInfoId()
1024 {
1025 delete d;
1026 }
1027
1028TDEStartupInfoId::TDEStartupInfoId( const TDEStartupInfoId& id_P )
1029 {
1030 d = new TDEStartupInfoIdPrivate( *id_P.d );
1031 }
1032
1033TDEStartupInfoId& 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
1042bool TDEStartupInfoId::operator==( const TDEStartupInfoId& id_P ) const
1043 {
1044 return id() == id_P.id();
1045 }
1046
1047bool TDEStartupInfoId::operator!=( const TDEStartupInfoId& id_P ) const
1048 {
1049 return !(*this == id_P );
1050 }
1051
1052// needed for QMap
1053bool TDEStartupInfoId::operator<( const TDEStartupInfoId& id_P ) const
1054 {
1055 return id() < id_P.id();
1056 }
1057
1058bool TDEStartupInfoId::none() const
1059 {
1060 return d->id.isEmpty() || d->id == "0";
1061 }
1062
1063unsigned 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
1099struct 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
1118TQString 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
1153TDEStartupInfoData::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
1207TDEStartupInfoData::TDEStartupInfoData( const TDEStartupInfoData& data )
1208{
1209 d = new TDEStartupInfoDataPrivate( *data.d );
1210}
1211
1212TDEStartupInfoData& 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
1221void 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
1253TDEStartupInfoData::TDEStartupInfoData()
1254{
1255 d = new TDEStartupInfoDataPrivate;
1256}
1257
1258TDEStartupInfoData::~TDEStartupInfoData()
1259{
1260 delete d;
1261}
1262
1263void TDEStartupInfoData::setBin( const TQString& bin_P )
1264 {
1265 d->bin = bin_P;
1266 }
1267
1268const TQString& TDEStartupInfoData::bin() const
1269 {
1270 return d->bin;
1271 }
1272
1273void TDEStartupInfoData::setName( const TQString& name_P )
1274 {
1275 d->name = name_P;
1276 }
1277
1278const TQString& TDEStartupInfoData::name() const
1279 {
1280 return d->name;
1281 }
1282
1283const TQString& TDEStartupInfoData::findName() const
1284 {
1285 if( !name().isEmpty())
1286 return name();
1287 return bin();
1288 }
1289
1290void TDEStartupInfoData::setDescription( const TQString& desc_P )
1291 {
1292 d->description = desc_P;
1293 }
1294
1295const TQString& TDEStartupInfoData::description() const
1296 {
1297 return d->description;
1298 }
1299
1300const TQString& TDEStartupInfoData::findDescription() const
1301 {
1302 if( !description().isEmpty())
1303 return description();
1304 return name();
1305 }
1306
1307void TDEStartupInfoData::setIcon( const TQString& icon_P )
1308 {
1309 d->icon = icon_P;
1310 }
1311
1312const TQString& TDEStartupInfoData::findIcon() const
1313 {
1314 if( !icon().isEmpty())
1315 return icon();
1316 return bin();
1317 }
1318
1319const TQString& TDEStartupInfoData::icon() const
1320 {
1321 return d->icon;
1322 }
1323
1324void TDEStartupInfoData::setDesktop( int desktop_P )
1325 {
1326 d->desktop = desktop_P;
1327 }
1328
1329int TDEStartupInfoData::desktop() const
1330 {
1331 return d->desktop;
1332 }
1333
1334void TDEStartupInfoData::setWMClass( const TQCString& wmclass_P )
1335 {
1336 d->wmclass = wmclass_P;
1337 }
1338
1339const TQCString TDEStartupInfoData::findWMClass() const
1340 {
1341 if( !WMClass().isEmpty() && WMClass() != "0" )
1342 return WMClass();
1343 return bin().utf8();
1344 }
1345
1346const TQCString& TDEStartupInfoData::WMClass() const
1347 {
1348 return d->wmclass;
1349 }
1350
1351void 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
1365const TQCString& TDEStartupInfoData::hostname() const
1366 {
1367 return d->hostname;
1368 }
1369
1370void TDEStartupInfoData::addPid( pid_t pid_P )
1371 {
1372 if( !d->pids.contains( pid_P ))
1373 d->pids.append( pid_P );
1374 }
1375
1376void TDEStartupInfoData::remove_pid( pid_t pid_P )
1377 {
1378 d->pids.remove( pid_P );
1379 }
1380
1381const TQValueList< pid_t >& TDEStartupInfoData::pids() const
1382 {
1383 return d->pids;
1384 }
1385
1386bool TDEStartupInfoData::is_pid( pid_t pid_P ) const
1387 {
1388 return d->pids.contains( pid_P );
1389 }
1390
1391void TDEStartupInfoData::setSilent( TriState state_P )
1392 {
1393 d->silent = state_P;
1394 }
1395
1396TDEStartupInfoData::TriState TDEStartupInfoData::silent() const
1397 {
1398 return d->silent;
1399 }
1400
1401void TDEStartupInfoData::setTimestamp( unsigned long time )
1402 {
1403 d->timestamp = time;
1404 }
1405
1406unsigned long TDEStartupInfoData::timestamp() const
1407 {
1408 return d->timestamp;
1409 }
1410
1411void TDEStartupInfoData::setScreen( int screen )
1412 {
1413 d->screen = screen;
1414 }
1415
1416int TDEStartupInfoData::screen() const
1417 {
1418 return d->screen;
1419 }
1420
1421void TDEStartupInfoData::setXinerama( int xinerama )
1422 {
1423 d->xinerama = xinerama;
1424 }
1425
1426int TDEStartupInfoData::xinerama() const
1427 {
1428 return d->xinerama;
1429 }
1430
1431void TDEStartupInfoData::setLaunchedBy( WId window )
1432 {
1433 d->launched_by = window;
1434 }
1435
1436WId TDEStartupInfoData::launchedBy() const
1437 {
1438 return d->launched_by;
1439 }
1440
1441static
1442long get_num( const TQString& item_P )
1443 {
1444 unsigned int pos = item_P.find( '=' );
1445 return item_P.mid( pos + 1 ).toLong();
1446 }
1447
1448static
1449unsigned 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
1455static
1456TQString 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
1469static
1470TQCString get_cstr( const TQString& item_P )
1471 {
1472 return get_str( item_P ).utf8();
1473 }
1474
1475static
1476TQStringList 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
1508static 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
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.4
This website is maintained by Timothy Pearson.