1 //=============================================================================
2 //
3 // File : KviApplication.cpp
4 // Creation date : Sun Jun 18 2000 12:39:45 by Szymon Stefanek
5 //
6 // This file is part of the KVIrc IRC client distribution
7 // Copyright (C) 2000-2010 Szymon Stefanek (pragma at kvirc dot net)
8 //
9 // This program is FREE software. You can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the HOPE that it will be USEFUL,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 // See the GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, write to the Free Software Foundation,
21 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24
25 #define _KVI_APP_CPP_
26
27 #include "kvi_socket.h"
28 #include "KviApplication.h"
29 #include "kvi_debug.h"
30 #include "KviMainWindow.h"
31 #include "KviMessageBox.h"
32 #include "KviIconManager.h"
33 #include "KviInput.h"
34 #include "KviInputHistory.h"
35 #include "KviConfigurationFile.h"
36 #include "KviColorSelectionWindow.h"
37 #include "KviWindow.h"
38 #include "KviIrcServerDataBase.h"
39 #include "KviProxyDataBase.h"
40 #include "KviMenuBar.h"
41 #include "KviOptions.h"
42 #include "KviIrcServerParser.h"
43 #include "KviModuleManager.h"
44 #include "KviMediaManager.h"
45 #include "KviRegisteredUserDataBase.h"
46 #include "KviThread.h"
47 #include "KviSharedFilesManager.h"
48 #include "kvi_confignames.h"
49 #include "KviWindowListBase.h"
50 #include "kvi_defaults.h"
51 #include "KviLocale.h"
52 #include "kvi_out.h"
53 #include "KviNickServRuleSet.h"
54 #include "KviIdentityProfileSet.h"
55 #include "KviDefaultScript.h"
56 #include "KviXlib.h"
57 #include "KviTextIconManager.h"
58 #include "KviTextIconWindow.h"
59 #include "KviHistoryWindow.h"
60 #include "KviCtcpPageDialog.h"
61 #include "KviRegisteredChannelDataBase.h"
62 #include "KviModuleExtension.h"
63 #include "KviInternalCommand.h"
64 #include "KviFileTransfer.h"
65 #include "KviControlCodes.h"
66 #include "KviIrcUrl.h"
67 #include "KviAvatarCache.h"
68 #include "KviActionManager.h"
69 #include "KviCustomToolBarManager.h"
70 #include "KviFileUtils.h"
71 #include "KviTimeUtils.h"
72 #include "KviStringConversion.h"
73 #include "KviUserIdentityManager.h"
74 #include "KviIrcView.h"
75 #include "KviEnvironment.h"
76 #include "KviAnimatedPixmapCache.h"
77 #include "KviKvs.h"
78 #include "KviKvsScript.h"
79 #include "KviKvsPopupManager.h"
80 #include "KviKvsKernel.h"
81 #include "KviKvsObjectController.h"
82 #include "KviKvsEventTriggers.h"
83 #include "kvi_sourcesdate.h"
84 #include "KviPointerHashTable.h"
85 #include "KviQueryWindow.h"
86 #include "KviCaster.h"
87 #include "KviSignalHandler.h"
88 #include "KviPtrListIterator.h"
89 #include "KviIrcNetwork.h"
90 #include "KviRuntimeInfo.h"
91
92 #include <QMenu>
93 #include <QPainter>
94 #include <algorithm>
95
96 #ifndef COMPILE_NO_IPC
97 #include "KviIpcSentinel.h"
98 #endif
99
100 #ifdef COMPILE_CRYPT_SUPPORT
101 #include "KviCryptEngineManager.h"
102 #endif
103
104 #ifdef COMPILE_SSL_SUPPORT
105 #include "KviSSL.h"
106 #endif
107
108 #include <QFileInfo>
109 #include <QSplitter>
110 #include <QClipboard>
111 #include <QMessageBox>
112 #include <QTextCodec>
113 #include <QMetaObject>
114 #include <QCommonStyle>
115
116 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
117 #include <QPluginLoader>
118 #include <QtWin>
119 #endif
120
121 #ifdef COMPILE_DBUS_SUPPORT
122 #include <QDBusInterface>
123 #endif
124
125 #ifdef COMPILE_KDE_SUPPORT
126 #ifdef COMPILE_KDE4_SUPPORT
127 #include <KStandardDirs>
128 #else
129 #include <QStandardPaths>
130 #endif
131 #include <KNotification>
132 #endif
133
134 #ifdef COMPILE_QX11INFO_SUPPORT
135 #include <QX11Info>
136 #endif
137
138 /*
139 HACK These 2 hacks are defined because X11 defines Unsorted and None
140 which conflicts with QDir and KviApplication::KvircSubdir
141 DO NOT REMOVE THEM EVEN IF THEY ARE DEFINED ALSO IN KviApplication.h
142 */
143 #ifdef Unsorted
144 #undef Unsorted
145 #endif
146
147 #ifdef None
148 #undef None
149 #endif
150
151 #include <QDir>
152
153 #include <cstdlib> // rand & srand
154 #include <ctime> // time() in srand()
155 #include <map> // std::map<>
156
157 // Global application pointer
158 KVIRC_API KviApplication * g_pApp = nullptr;
159
160 KviConfigurationFile * g_pWinPropertiesConfig = nullptr;
161 KVIRC_API KviIrcServerDataBase * g_pServerDataBase = nullptr;
162 KVIRC_API KviProxyDataBase * g_pProxyDataBase = nullptr;
163
164 // Global windows
165 KVIRC_API KviColorWindow * g_pColorWindow = nullptr;
166 KVIRC_API KviTextIconWindow * g_pTextIconWindow = nullptr;
167 KVIRC_API QMenu * g_pInputPopup = nullptr;
168 KVIRC_API QStringList * g_pRecentTopicList = nullptr;
169 KVIRC_API std::map<QString, KviWindow *> g_pGlobalWindowDict;
170 KVIRC_API KviMediaManager * g_pMediaManager = nullptr;
171 KVIRC_API KviSharedFilesManager * g_pSharedFilesManager = nullptr;
172 KVIRC_API KviNickServRuleSet * g_pNickServRuleSet = nullptr;
173 KVIRC_API KviCtcpPageDialog * g_pCtcpPageDialog = nullptr;
174 KVIRC_API KviRegisteredChannelDataBase * g_pRegisteredChannelDataBase = nullptr;
175 KVIRC_API KviHistoryWindowWidget * g_pHistoryWindow = nullptr;
176
177 // this is eventually set by libkviident
178 KVIRC_API int g_iIdentDaemonRunningUsers = 0;
179
180 // Loaded and destroyed by KviIconManager
181 QPixmap * g_pUserChanStatePixmap = nullptr;
182 QPixmap * g_pActivityMeterPixmap = nullptr;
183
184 #ifdef COMPILE_PSEUDO_TRANSPARENCY
185
186 #include <QImage>
187
188 KVIRC_API QPixmap * g_pShadedParentGlobalDesktopBackground = nullptr; // the pixmap that we use for MdiManager
189 KVIRC_API QPixmap * g_pShadedChildGlobalDesktopBackground = nullptr; // the pixmap that we use for MdiChild
190 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
191 #include <winuser.h>
192 #include <QDesktopWidget>
193 #endif
194 #endif
195
196 #ifdef COMPILE_CRYPT_SUPPORT
197 #include "KviCryptEngine.h"
198 // global crypt engine manager
199 KVIRC_API KviCryptEngineManager * g_pCryptEngineManager = nullptr;
200 #endif
201
202 #include <QStyleFactory>
203
KviApplication(int & argc,char ** argv)204 KviApplication::KviApplication(int & argc, char ** argv)
205 : KviTalApplication(argc, argv)
206 {
207 setApplicationName("KVIrc");
208 setApplicationVersion(KVIRC_VERSION_RELEASE);
209 setOrganizationDomain("kvirc.net");
210 setOrganizationName("KVIrc");
211
212 // Ok...everything begins here
213 g_pApp = this;
214 m_szConfigFile = QString();
215 m_bCreateConfig = false;
216 m_bUpdateGuiPending = false;
217 m_pRecentChannelDict = nullptr;
218 #ifndef COMPILE_NO_IPC
219 m_pIpcSentinel = nullptr;
220 #endif
221 m_iHeartbeatTimerId = -1;
222 m_fntDefaultFont = font();
223 m_bSetupDone = false;
224 m_bClosingDown = false;
225 kvi_socket_flushTrafficCounters();
226 // don't let qt quit the application by itself
227 setQuitOnLastWindowClosed(false);
228 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
229 m_bPortable = KviFileUtils::fileExists(g_pApp->applicationDirPath() + KVI_PATH_SEPARATOR_CHAR + "portable");
230 #endif
231
232 //note: the early qApp->style() call leads to a crash on osx
233 #if !defined(COMPILE_ENABLE_GTKSTYLE) && !defined(COMPILE_ON_MAC)
234 // workaround for gtk+ style forcing a crappy white background (ticket #777, #964, #1009, ..)
235 if(QString("QGtkStyle").compare(qApp->style()->metaObject()->className()) == 0)
236 {
237 setStyle(QStyleFactory::create("Fusion"));
238 setPalette(style()->standardPalette());
239 }
240 #endif
241 }
242
setup()243 void KviApplication::setup()
244 {
245 // Here we start up all the substystems.
246 // This is a really critical phase since in general subsystems depend
247 // on each other and we must activate them in the right order.
248 // Don't move stuff around unless you really know what you're doing.
249
250 // Initialize the random number generator
251 ::srand(::time(nullptr));
252
253 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
254 // setup winsock.dll
255 WSADATA w;
256 WSAStartup(MAKELONG((unsigned short)2, (unsigned short)0), &w);
257 #endif
258
259 #ifndef COMPILE_NO_IPC
260 // Create this very early
261 // FIXME: this is still not early enough... we actually HAVE race conditions (should use a file for locking this ?)
262 createIpcSentinel();
263 #endif
264
265 // Initialize the thread manager early
266 KviThreadManager::globalInit();
267
268 #ifdef COMPILE_SSL_SUPPORT
269 KviSSL::globalInit();
270 #endif
271
272 ::kvi_signalHandlerSetup();
273
274 // Setup our filesystem and initialize locale
275 loadDirectories();
276 KviStringConversion::init(m_szGlobalKvircDir, m_szLocalKvircDir);
277
278 g_pIconManager = new KviIconManager();
279
280 // add KVIrc common dirs to QT searchpath
281 QString szPath;
282 getLocalKvircDirectory(szPath, None, "avatars");
283 QDir::addSearchPath("avatars", szPath);
284 getLocalKvircDirectory(szPath, None, "pics");
285 QDir::addSearchPath("pics", szPath);
286 getLocalKvircDirectory(szPath, None, "audio");
287 QDir::addSearchPath("audio", szPath);
288
289 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
290 // need to load image plugins :(
291 QString szPluginsDir;
292 getGlobalKvircDirectory(szPluginsDir, None, "qt-plugins/");
293 addLibraryPath(szPluginsDir);
294 //MessageBox(0,QApplication::libraryPaths().join(";").toLocal8Bit().data(),"KVIrc",0);
295 //KviMessageBox::information(libraryPaths().join(";"));
296 //qDebug("%1",loader.isLoaded());
297 #endif
298
299 // Make sure that the C strings are translated to utf8
300 // This is a fallback solution anyway: we should use the appropriate
301 // encoding every time.
302 QTextCodec * pUTF8Codec = KviLocale::instance()->codecForName("UTF-8");
303 if(pUTF8Codec)
304 QTextCodec::setCodecForLocale(pUTF8Codec);
305 else
306 qDebug("Aaargh... have no UTF-8 codec?");
307
308 QString szTmp;
309
310 // Initialize the scripting engine
311 KviKvs::init();
312
313 // Initialize the action manager
314 KviActionManager::init();
315
316 // Create the module manager early: so the other managers can load modules
317 g_pModuleExtensionManager = new KviModuleExtensionManager();
318
319 g_pModuleManager = new KviModuleManager();
320
321 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_USERACTIONS))
322 KviActionManager::instance()->load(szTmp);
323
324 // Initialize and load the identities
325 KviUserIdentityManager::init();
326
327 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_IDENTITIES))
328 KviUserIdentityManager::instance()->load(szTmp);
329
330 KviAnimatedPixmapCache::init();
331
332 // Load the remaining configuration
333 // Note that loadOptions() assumes that the current progress is 12 and
334 // will bump it up to 45 in small steps
335 loadOptions();
336
337 // set the global font if needed
338 updateApplicationFont();
339
340 #ifdef COMPILE_PSEUDO_TRANSPARENCY
341 updatePseudoTransparency();
342 #endif
343
344 // enforce our "icon in popups" option - this is done also in each updateGui() call
345 setAttribute(Qt::AA_DontShowIconsInMenus, !KVI_OPTION_BOOL(KviOption_boolShowIconsInPopupMenus));
346
347 // Load the win properties config
348 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_WINPROPERTIES);
349 g_pWinPropertiesConfig = new KviConfigurationFile(szTmp, KviConfigurationFile::ReadWrite);
350
351 // Load the server database
352 g_pServerDataBase = new KviIrcServerDataBase();
353 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_SERVERDB))
354 g_pServerDataBase->load(szTmp);
355
356 // Load the proxy database
357 g_pProxyDataBase = new KviProxyDataBase();
358 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_PROXYDB))
359 g_pProxyDataBase->load(szTmp);
360
361 // Event manager
362 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_EVENTS))
363 KviKvs::loadAppEvents(szTmp);
364
365 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_RAWEVENTS))
366 KviKvs::loadRawEvents(szTmp);
367
368 // Popup manager
369 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_POPUPS))
370 KviKvs::loadPopups(szTmp);
371
372 KviCustomToolBarManager::init();
373 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_CUSTOMTOOLBARS))
374 KviCustomToolBarManager::instance()->load(szTmp);
375
376 // Alias manager
377 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_ALIASES))
378 KviKvs::loadAliases(szTmp);
379
380 // Script addons manager (this in fact has delayed loading, so we don't even care
381 // about showing up an entry in the splash screen)
382 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_SCRIPTADDONS))
383 KviKvs::loadScriptAddons(szTmp);
384
385 g_pTextIconManager = new KviTextIconManager();
386 g_pTextIconManager->load();
387
388 // load the recent data lists
389 g_pRecentTopicList = new QStringList();
390 //g_pBookmarkList = new QStringList();
391 loadRecentEntries();
392
393 // media manager
394 g_pMediaManager = new KviMediaManager();
395 g_pMediaManager->lock();
396 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_MEDIATYPES))
397 g_pMediaManager->load(szTmp);
398 g_pMediaManager->unlock();
399
400 // registered user data base
401 g_pRegisteredUserDataBase = new KviRegisteredUserDataBase();
402 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_REGUSERDB))
403 g_pRegisteredUserDataBase->load(szTmp);
404
405 // registered channel data base
406 g_pRegisteredChannelDataBase = new KviRegisteredChannelDataBase();
407 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_REGCHANDB))
408 g_pRegisteredChannelDataBase->load(szTmp);
409
410 // file trader
411 g_pSharedFilesManager = new KviSharedFilesManager();
412 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_SHAREDFILES))
413 g_pSharedFilesManager->load(szTmp);
414
415 // nick serv data base
416 g_pNickServRuleSet = new KviNickServRuleSet();
417 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_NICKSERVDATABASE))
418 g_pNickServRuleSet->load(szTmp);
419
420 // Identity profiles database
421 KviIdentityProfileSet::init();
422 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_PROFILESDATABASE))
423 KviIdentityProfileSet::instance()->load(szTmp);
424
425 KviAvatarCache::init();
426 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_AVATARCACHE))
427 KviAvatarCache::instance()->load(szTmp);
428
429 KviInputHistory::init();
430 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_INPUTHISTORY))
431 KviInputHistory::instance()->load(szTmp);
432
433 KviDefaultScriptManager::init();
434 if(getReadOnlyConfigPath(szTmp, KVI_CONFIGFILE_DEFAULTSCRIPT))
435 KviDefaultScriptManager::instance()->load(szTmp);
436 else
437 KviDefaultScriptManager::instance()->loadEmptyConfig();
438
439 // Eventually initialize the crypt engine manager
440 #ifdef COMPILE_CRYPT_SUPPORT
441 g_pCryptEngineManager = new KviCryptEngineManager();
442 #endif
443
444 // and the input popup
445 g_pInputPopup = new QMenu();
446
447 // create the server parser
448 g_pServerParser = new KviIrcServerParser();
449
450 // Script object controller
451 //g_pScriptObjectController = new KviScriptObjectController(); gone
452
453 // Cache the QStyle theme before it's overriden
454 (void)KviRuntimeInfo::qtTheme();
455
456 // create the frame window, we're almost up and running...
457 createFrame();
458
459 // ok, we also have an UI now
460
461 // check if this is the first time this version of KVIrc runs...
462 if(firstTimeRun())
463 {
464 // Finish the setup...
465 setupFinish();
466 // ensure mainwindow is visible
467 g_pMainWindow->show();
468 }
469
470 // hello world!
471 m_bSetupDone = true;
472
473 // We're REALLY up and running!
474 // kill the splash screen
475
476 if(KVI_OPTION_BOOL(KviOption_boolShowServersConnectDialogOnStart))
477 g_pMainWindow->executeInternalCommand(KVI_INTERNALCOMMAND_SERVERSJOIN_OPEN);
478
479 // check if we're in trouble...
480 checkSuggestRestoreDefaultScript();
481
482 // start our heartbeat now
483 m_iHeartbeatTimerId = startTimer(1000);
484 }
485
frameDestructorCallback()486 void KviApplication::frameDestructorCallback()
487 {
488 // here we should kill anything that depends on g_pMainWindow, g_pActiveWindow and related being non zero...
489 // kill all the objects, while we have windows...
490 if(KviKvsKernel::instance())
491 {
492 if(KviKvsKernel::instance()->objectController())
493 {
494 KviKvsKernel::instance()->objectController()->clearInstances();
495 }
496 }
497 }
498
~KviApplication()499 KviApplication::~KviApplication()
500 {
501 // Another critical phase.
502 // We shutdown our subsystems in the right order here.
503
504 m_bClosingDown = true;
505
506 #ifndef COMPILE_NO_IPC
507 destroyIpcSentinel();
508 #endif
509
510 // if we still have a frame: kill it
511 if(g_pMainWindow)
512 delete g_pMainWindow;
513 g_pActiveWindow = nullptr; // .. but it should be already 0 anyway
514
515 if(g_pCtcpPageDialog)
516 delete g_pCtcpPageDialog;
517
518 if(!m_bSetupDone)
519 return; // killed with IPC (nothing except the m_pFrameList was created yet)
520
521 KviFileTransferManager::cleanup();
522
523 // No more events are triggered from now on and no KVS commands are executed
524
525 // Dangerous part.... we're unloading all the modules
526 // We need to unload them early since they may use other subsystems
527 // that we are going to kill now.
528 delete g_pModuleManager;
529 delete g_pModuleExtensionManager;
530 // No more external modules exist: all that happens from now is generated
531 // from inside the kvirc core.
532
533 // We should have almost no UI here: only certain dialogs or popup windows may
534 // still exist: they should be harmless tough.
535 saveOptions();
536 saveIdentities();
537 KviUserIdentityManager::done();
538 if(m_pRecentChannelDict)
539 delete m_pRecentChannelDict;
540 // now kill the stuff that the frame depends on
541 saveIrcServerDataBase();
542 delete g_pServerDataBase;
543 saveProxyDataBase();
544 delete g_pProxyDataBase;
545 delete g_pWinPropertiesConfig;
546 saveTextIcons();
547 if(g_pTextIconWindow)
548 delete g_pTextIconWindow;
549 delete g_pTextIconManager;
550 delete g_pIconManager;
551 delete g_pServerParser;
552 saveMediaTypes();
553 delete g_pMediaManager;
554 saveRecentEntries();
555 saveAvatarCache();
556 KviAvatarCache::done();
557 //delete g_pBookmarkList;
558 delete g_pRecentTopicList;
559 saveRegisteredUsers();
560 delete g_pRegisteredUserDataBase;
561 saveRegisteredChannels();
562 delete g_pRegisteredChannelDataBase;
563 saveNickServ();
564 delete g_pNickServRuleSet;
565 saveIdentityProfiles();
566 KviIdentityProfileSet::done();
567 saveDefaultScripts();
568 KviDefaultScriptManager::done();
569 saveSharedFiles();
570 delete g_pSharedFilesManager;
571 saveAppEvents();
572 saveRawEvents();
573 saveToolBars();
574 KviCustomToolBarManager::done();
575 savePopups();
576 saveAliases();
577 g_pGlobalWindowDict.clear();
578 saveScriptAddons();
579 // kill the remaining resources
580 delete g_pColorWindow;
581 if(g_pHistoryWindow)
582 delete g_pHistoryWindow;
583 saveInputHistory();
584 KviInputHistory::done();
585 delete g_pInputPopup;
586 //delete g_pScriptObjectController;
587 #ifdef COMPILE_CRYPT_SUPPORT
588 delete g_pCryptEngineManager;
589 #endif
590 #ifdef COMPILE_PSEUDO_TRANSPARENCY
591 destroyPseudoTransparency();
592 #endif
593 m_PendingAvatarChanges.clear();
594 KviAnimatedPixmapCache::done();
595 // Kill the thread manager.... all the slave threads should have been already terminated ...
596 #ifdef COMPILE_SSL_SUPPORT
597 KviSSL::globalDestroy();
598 #endif
599 KviThreadManager::globalDestroy();
600 // kill the scripting engine
601 KviKvs::done();
602 // shut up the action manager
603 saveActions();
604 KviActionManager::done();
605
606 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
607 WSACleanup();
608 #endif
609
610 KviLocale::done();
611 // goodbye cruel world...
612 }
613
614 static int g_iGloballyUniqueId = 0;
615
getGloballyUniqueId()616 int KviApplication::getGloballyUniqueId()
617 {
618 g_iGloballyUniqueId++;
619 return g_iGloballyUniqueId;
620 }
621
supportsCompositing()622 bool KviApplication::supportsCompositing()
623 {
624 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
625 //we need >= win2000
626 return true;
627 #endif
628
629 #ifdef COMPILE_QX11INFO_SUPPORT
630 // Qt5 does not support QX11Info::isCompositingManagerRunning()
631 // Well...assume we're compositing capable, should be true on all recent Linux distros
632 return true;
633 #endif // COMPILE_QX11INFO_SUPPORT
634 #ifdef COMPILE_ON_MAC
635 return true;
636 #endif
637 return false;
638 };
639
notifierMessage(KviWindow * pWnd,int iIconId,const QString & szMsg,unsigned int uMessageLifetime)640 void KviApplication::notifierMessage(KviWindow * pWnd, int iIconId, const QString & szMsg, unsigned int uMessageLifetime)
641 {
642 /*
643 We have different behaviour depending on support enabled at compile time (env)
644 and options enabled by the user (opt).
645 Let's see the scheme to understand which is chosen:
646
647 1: env: DBus, KDE
648 opt: a: enabled, enabled -> KDE
649 b: enabled, disabled -> DBus
650 c: disabled, disabled -> KVIrc
651
652 2: env: DBus, no KDE
653 opt: a: enabled -> DBus
654 b: disabled -> KVIrc
655
656 3: env: no DBus, no KDE -> KVIrc
657 ______ __________ ______________
658 | | | Want KDE | | Scheme 1a |
659 | KDE |---YES-->| Notifier |---YES-->| KDE Notifier |
660 |______| |__________| |______________|
661 | |
662 NO NO
663 | |
664 __V___ _____V_____ _______________
665 | | | Want DBus | | Schemes 1b-2a |
666 | DBus |--YES-->| Notifier |---YES-->| DBus Notifier |
667 |______| |___________| |_______________|
668 | |
669 NO NO
670 | |
671 __V__________________V_____
672 | Schemes 1c - 2b - 3 |
673 | KVIrc |
674 |___________________________|
675
676 :)
677 */
678
679 if(!pWnd)
680 return;
681
682 QString szTitle = __tr2qs("KVIrc Messaging");
683 QString szText = __tr2qs("Message from %1:\n\n").arg(pWnd->target());
684 szText += KviControlCodes::stripControlBytes(szMsg);
685
686 #ifdef COMPILE_KDE_SUPPORT
687 if(KVI_OPTION_BOOL(KviOption_boolUseKDENotifier))
688 {
689 // Scheme 1a: KDE
690 static bool bKNotifyConfigFileChecked = false;
691
692 if(!bKNotifyConfigFileChecked)
693 {
694 #ifdef COMPILE_KDE4_SUPPORT
695 QString szFileName = KStandardDirs::locateLocal("data", QString::fromUtf8("kvirc/kvirc.notifyrc"));
696 #else
697 QString szFileName = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/" + QString::fromUtf8("kvirc/kvirc.notifyrc");
698 #endif
699 if(szFileName.isEmpty())
700 szFileName = QString::fromUtf8("%1/.kde/share/apps/kvirc/kvirc.notifyrc").arg(QDir::homePath());
701
702 QFileInfo inf(szFileName);
703
704 if(!inf.exists())
705 {
706 KviFileUtils::makeDir(inf.absolutePath());
707
708 QString szKNotifyConfig = QString::fromUtf8(
709 "[Global]\n"
710 "IconName=kvirc\n"
711 "Comment=The K-Visual IRC Client\n"
712 "Name=kvirc\n"
713 "\n"
714 "[Event/incomingMessage]\n"
715 "Name=KVIrc\n"
716 "Comment=Someone sent us a message\n"
717 "Action=Popup|Taskbar\n"
718 "Persistent=true\n");
719
720 KviFileUtils::writeFile(szFileName, szKNotifyConfig);
721 }
722
723 bKNotifyConfigFileChecked = true;
724 }
725
726 QStringList actions;
727 actions << __tr2qs("View");
728 actions << __tr2qs("Ignore");
729
730 QPixmap * pIcon = nullptr;
731 KviIconManager::SmallIcon eIcon = KviIconManager::None;
732 switch(pWnd->type())
733 {
734 case KviWindow::Console:
735 eIcon = KviIconManager::Links;
736 break;
737 case KviWindow::Channel:
738 eIcon = KviIconManager::Channel;
739 break;
740 case KviWindow::Query:
741 {
742 KviQueryWindow * pQuery = KVI_DYNAMIC(KviQueryWindow *, pWnd);
743 if(!pQuery)
744 break;
745
746 KviUserListEntry * pEntry = pQuery->userListView()->findEntry(pWnd->target());
747 if(!pEntry)
748 break;
749
750 KviAvatar * pAvatar = pEntry->globalData()->avatar();
751 if(!pAvatar)
752 break;
753
754 pIcon = pAvatar->pixmap();
755 if(!pIcon)
756 eIcon = KviIconManager::Query;
757 }
758 break;
759 case KviWindow::SocketSpy:
760 eIcon = KviIconManager::Spy;
761 break;
762 case KviWindow::DccChat:
763 eIcon = KviIconManager::DccMsg;
764 break;
765 case KviWindow::DccTransfer:
766 eIcon = KviIconManager::Dcc;
767 break;
768 case KviWindow::UserWindow:
769 eIcon = KviIconManager::UserWindow;
770 break;
771 case KviWindow::Debug:
772 eIcon = KviIconManager::Bomb;
773 break;
774 //KviWindow::DeadChannel
775 //KviWindow::DeadQuery
776 //KviWindow::Editor
777 //KviWindow::Help
778 //KviWindow::Terminal
779 //KviWindow::Links
780 //KviWindow::List
781 //KviWindow::DccCanvas
782 //KviWindow::DccVoice
783 //KviWindow::DccVideo
784 //KviWindow::Tool
785 //KviWindow::IOGraph
786 //KviWindow::ScriptEditor
787 //KviWindow::ScriptObject
788 //KviWindow::LogView
789 //KviWindow::Offer
790 case KviWindow::Unknown:
791 default:
792 eIcon = KviIconManager::KVIrc;
793 break;
794 }
795
796 if(!pIcon)
797 pIcon = g_pIconManager->getSmallIcon(eIcon);
798
799 KNotification * pNotify = nullptr;
800 #if defined(COMPILE_KDE4_SUPPORT)
801 #if KDE_IS_VERSION(4, 4, 0)
802 pNotify = new KNotification("incomingMessage", KNotification::CloseWhenWidgetActivated, this);
803 #else
804 pNotify = new KNotification("incomingMessage", g_pMainWindow, KNotification::CloseWhenWidgetActivated);
805 #endif
806 #else
807 pNotify = new KNotification("incomingMessage", g_pMainWindow, KNotification::CloseWhenWidgetActivated);
808 #endif
809 pNotify->setFlags(KNotification::Persistent);
810 pNotify->setTitle(szTitle);
811 pNotify->setText(szText);
812 pNotify->setActions(actions);
813 pNotify->setPixmap(*pIcon);
814
815 #if defined(COMPILE_KDE4_SUPPORT)
816 pNotify->setComponentData(KComponentData(aboutData()));
817 #else
818 pNotify->setComponentName("kvirc");
819 #endif
820
821 connect(pNotify, SIGNAL(activated()), this, SLOT(showParentFrame()));
822 connect(pNotify, SIGNAL(action1Activated()), this, SLOT(showParentFrame()));
823 connect(pNotify, SIGNAL(action2Activated()), pNotify, SLOT(close()));
824 connect(pNotify, SIGNAL(ignored()), pNotify, SLOT(close()));
825
826 pNotify->sendEvent();
827 }
828 else
829 {
830 #endif // COMPILE_KDE_SUPPORT
831 #ifdef COMPILE_DBUS_SUPPORT
832 if(KVI_OPTION_BOOL(KviOption_boolUseDBusNotifier))
833 {
834 // Scheme 1b-2a: DBus
835 QString szIcon = g_pIconManager->getSmallIconName(KviIconManager::KVIrc);
836
837 // org.freedesktop.Notifications.Notify
838 QVariantList args;
839 args << QString("KVIrc"); // application name
840 args << QVariant(QVariant::UInt); // notification id
841 args << szIcon; // application icon
842 args << szTitle; // summary text
843 args << szText; // detailed text
844 args << QStringList(); // actions, optional
845 args << QVariantMap(); // hints, optional
846 args << static_cast<int>(uMessageLifetime * 1000); // timeout in msecs
847
848 QDBusInterface * pNotify = new QDBusInterface("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus(), this);
849 QDBusMessage reply = pNotify->callWithArgumentList(QDBus::Block, "Notify", args);
850 if(reply.type() == QDBusMessage::ErrorMessage)
851 {
852 QDBusError err = reply;
853 qDebug("D-Bus notify error\nID: %u\nName: %s\nMessage: %s\n", reply.arguments().first().toUInt(), qPrintable(err.name()), qPrintable(err.message()));
854 }
855 }
856 else
857 {
858 #endif // COMPILE_DBUS_SUPPORT
859 // Scheme 1c-2b-3: KVIrc
860 KviModule * m = g_pModuleManager->getModule("notifier");
861 if(!m)
862 return;
863
864 KviNotifierMessageParam s;
865 s.pWindow = pWnd;
866 s.szIcon.sprintf("%d", iIconId);
867 s.szMessage = szMsg;
868 s.uMessageLifetime = uMessageLifetime;
869
870 m->ctrl("notifier::message", (void *)&s);
871 #ifdef COMPILE_DBUS_SUPPORT
872 }
873 #endif // COMPILE_DBUS_SUPPORT
874 #ifdef COMPILE_KDE_SUPPORT
875 }
876 #endif // COMPILE_KDE_SUPPORT
877 }
878
showParentFrame()879 void KviApplication::showParentFrame()
880 {
881 if(!g_pMainWindow)
882 return;
883
884 if(g_pMainWindow->isMinimized())
885 g_pMainWindow->setWindowState(g_pMainWindow->windowState() & (~Qt::WindowMinimized | Qt::WindowActive));
886
887 g_pMainWindow->showMaximized();
888 }
889
defaultTextCodec()890 QTextCodec * KviApplication::defaultTextCodec()
891 {
892 QTextCodec * pCodec = nullptr;
893 if(!KVI_OPTION_STRING(KviOption_stringDefaultTextEncoding).isEmpty())
894 {
895 pCodec = KviLocale::instance()->codecForName(KVI_OPTION_STRING(KviOption_stringDefaultTextEncoding).toLatin1());
896 if(pCodec)
897 return pCodec;
898 }
899 pCodec = QTextCodec::codecForLocale();
900 if(pCodec)
901 return pCodec;
902 pCodec = KviLocale::instance()->codecForName("UTF-8");
903 if(!pCodec)
904 qDebug("KviApplication::defaultTextCodec(): can't find a suitable text codec for locale :/");
905 return pCodec;
906 }
907
defaultSrvCodec()908 QTextCodec * KviApplication::defaultSrvCodec()
909 {
910 QTextCodec * pCodec = nullptr;
911 if(!KVI_OPTION_STRING(KviOption_stringDefaultSrvEncoding).isEmpty())
912 {
913 pCodec = KviLocale::instance()->codecForName(KVI_OPTION_STRING(KviOption_stringDefaultSrvEncoding).toLatin1());
914 if(pCodec)
915 return pCodec;
916 }
917 pCodec = QTextCodec::codecForLocale();
918 if(pCodec)
919 return pCodec;
920 pCodec = KviLocale::instance()->codecForName("UTF-8");
921 if(!pCodec)
922 qDebug("KviApplication::defaultSrcCodec(): can't find a suitable text codec for locale :/");
923 return pCodec;
924 }
925
loadDefaultScript(QString szItem)926 void KviApplication::loadDefaultScript(QString szItem)
927 {
928 QString szCmd;
929
930 if(szItem.isEmpty())
931 szItem = "default";
932
933 getGlobalKvircDirectory(szCmd, KviApplication::DefScript, QString("%1.kvs").arg(szItem));
934 szCmd.prepend("parse \"");
935 szCmd.append("\"");
936 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
937 szCmd.replace("\\", "\\\\");
938 #endif
939 KviKvsScript::run(szCmd, g_pMainWindow->firstConsole());
940 }
941
checkSuggestRestoreDefaultScript()942 void KviApplication::checkSuggestRestoreDefaultScript()
943 {
944 static bool bSuggestedOnce = false;
945 if(KVI_OPTION_BOOL(KviOption_boolDoNotSuggestRestoreDefaultScript))
946 return;
947
948 if(bSuggestedOnce)
949 return; // already suggested in this kvirc session
950
951 // first: check if the user configuration has ever been updated to the current version
952 if(!KviDefaultScriptManager::instance()->isDefscriptUpToDate())
953 {
954 switch(
955 QMessageBox::question(nullptr, __tr2qs("Update Default Scripts - KVIrc"),
956 __tr2qs("<b>Your KVirc installation has been updated successfully.</b><br><br>"
957 "KVIrc's default scripts should also be updated. "
958 "<b>Do you want to restore the default scripts?</b><br><br>"
959 "Hint: If you choose \"No\" you can always restore the "
960 "default scripts by selecting the appropriate entry from the \"Scripting\" menu later."),
961 __tr2qs("No and Don't Ask Me Again"), __tr2qs("No"), __tr2qs("Yes"), 1, 1))
962 {
963 case 0:
964 KVI_OPTION_BOOL(KviOption_boolDoNotSuggestRestoreDefaultScript) = true;
965 return;
966 break;
967 case 1:
968 // we want to execute the next checks, don't return now
969 break;
970 default:
971 restoreDefaultScript();
972 // we want to execute the next checks after the attempted restore, don't return now
973 break;
974 }
975 }
976
977 //second, check for some common corruptions in scripts
978 int iScore = 0;
979
980 if(KviCustomToolBarManager::instance()->descriptorCount() < 1)
981 iScore += 100; // straight suggest
982 else if(KviKvsPopupManager::instance()->popupCount() < 1)
983 iScore += 100; // straight suggest
984 else
985 {
986 // other stuff is not that critical
987 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnChannelNickPopupRequest))
988 iScore += 80;
989 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnDCCChatPopupRequest))
990 iScore += 20;
991 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnConsolePopupRequest))
992 iScore += 20;
993 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnChannelPopupRequest))
994 iScore += 20;
995 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnChannelNickPopupRequest))
996 iScore += 20;
997 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnQueryPopupRequest))
998 iScore += 20;
999 if(!KviKvsEventManager::instance()->hasAppHandlers(KviEvent_OnQueryNickPopupRequest))
1000 iScore += 20;
1001 if(KviCustomToolBarManager::instance()->descriptorCount() < 4)
1002 iScore += 20;
1003 if(KviKvsPopupManager::instance()->popupCount() < 3)
1004 iScore += 20;
1005 if(KviCustomToolBarManager::instance()->visibleToolBarCount() < 2)
1006 {
1007 iScore += 20;
1008 if(KviCustomToolBarManager::instance()->visibleToolBarCount() < 1)
1009 iScore += 20;
1010 }
1011 }
1012
1013 if(iScore < 100)
1014 return;
1015
1016 bSuggestedOnce = true;
1017
1018 switch(
1019 QMessageBox::question(nullptr, __tr2qs("Detected Installation Issues - KVIrc"),
1020 __tr2qs("<b>Your KVIrc installation is incomplete.</b><br><br>"
1021 "You seem to be missing some of the features that the KVIrc default scripts provide. "
1022 "<b>Do you want to restore the default scripts?</b><br><br>"
1023 "Hint: If you choose \"No\" you can always restore the "
1024 "default scripts by selecting the appropriate entry from the \"Scripting\" menu later."),
1025 __tr2qs("No and Don't Ask Me Again"), __tr2qs("No"), __tr2qs("Yes"), 1, 1))
1026 {
1027 case 0:
1028 KVI_OPTION_BOOL(KviOption_boolDoNotSuggestRestoreDefaultScript) = true;
1029 return;
1030 break;
1031 case 1:
1032 return;
1033 break;
1034 default:
1035 restoreDefaultScript();
1036 break;
1037 }
1038 }
1039
restoreDefaultScript()1040 void KviApplication::restoreDefaultScript()
1041 {
1042 KviDefaultScriptManager::instance()->restore();
1043 }
1044
1045 #ifndef COMPILE_NO_IPC
createIpcSentinel()1046 void KviApplication::createIpcSentinel()
1047 {
1048 m_pIpcSentinel = new KviIpcSentinel();
1049 }
1050
destroyIpcSentinel()1051 void KviApplication::destroyIpcSentinel()
1052 {
1053 delete m_pIpcSentinel;
1054 m_pIpcSentinel = nullptr;
1055 }
1056
ipcMessage(char * pcMessage)1057 void KviApplication::ipcMessage(char * pcMessage)
1058 {
1059 if(!g_pMainWindow)
1060 return;
1061 KviConsoleWindow * pConsole = g_pMainWindow->firstConsole();
1062 if(!pConsole)
1063 return;
1064 if(_OUTPUT_VERBOSE)
1065 {
1066 KviCString szCmd = pcMessage;
1067 if(szCmd.len() > 30)
1068 szCmd.cutRight(szCmd.len() - 30);
1069 int iIdx = szCmd.findFirstIdx('\n');
1070 if(iIdx != -1)
1071 szCmd.cutRight(szCmd.len() - (iIdx + 1));
1072 pConsole->output(KVI_OUT_SYSTEMMESSAGE, __tr2qs("Remote command received (%s ...)"), szCmd.ptr());
1073 }
1074 if (kvi_strEqualCIN(pcMessage, "openurl ", 8))
1075 {
1076 // there actually is no reliable way of raising the main window, but we try our best!
1077 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1078 SetForegroundWindow((HWND)g_pMainWindow->winId());
1079 #endif
1080 g_pMainWindow->activateWindow();
1081 }
1082 KviKvsScript::run(pcMessage, pConsole);
1083 }
1084 #endif // COMPILE_NO_IPC
1085
setAvatarFromOptions()1086 void KviApplication::setAvatarFromOptions()
1087 {
1088 for(auto & it : g_pGlobalWindowDict)
1089 {
1090 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1091 if(pWindow)
1092 pWindow->setAvatarFromOptions();
1093 }
1094 }
1095
setAvatarOnFileReceived(KviConsoleWindow * pConsole,const QString & szRemoteUrl,const QString & szNick,const QString & szUser,const QString & szHost)1096 void KviApplication::setAvatarOnFileReceived(
1097 KviConsoleWindow * pConsole,
1098 const QString & szRemoteUrl,
1099 const QString & szNick,
1100 const QString & szUser,
1101 const QString & szHost)
1102 {
1103 if(m_PendingAvatarChanges.size() >= KVI_MAX_PENDING_AVATARS) // can't be...
1104 // kill an entry to make space
1105 m_PendingAvatarChanges.erase(m_PendingAvatarChanges.begin());
1106
1107 std::unique_ptr<KviPendingAvatarChange> pAvatar(new KviPendingAvatarChange());
1108 pAvatar->pConsole = pConsole;
1109 pAvatar->szRemoteUrl = szRemoteUrl;
1110 pAvatar->szNick = szNick;
1111 pAvatar->szUser = szUser;
1112 pAvatar->szHost = szHost;
1113
1114 m_PendingAvatarChanges.emplace(pAvatar.get(), std::move(pAvatar));
1115 }
1116
findPendingAvatarChange(KviConsoleWindow * pConsole,const QString & szNick,const QString & szRemoteUrl)1117 KviPendingAvatarChange * KviApplication::findPendingAvatarChange(
1118 KviConsoleWindow * pConsole,
1119 const QString & szNick,
1120 const QString & szRemoteUrl)
1121 {
1122 for(auto & upAvatarPair : m_PendingAvatarChanges)
1123 {
1124 KviPendingAvatarChange * pAvatar = upAvatarPair.second.get();
1125 if(!pConsole || (pAvatar->pConsole == pConsole))
1126 {
1127 if(szNick.isNull() || (szNick == pAvatar->szNick))
1128 {
1129 if(szRemoteUrl == pAvatar->szRemoteUrl)
1130 return pAvatar;
1131 }
1132 }
1133 }
1134
1135 return nullptr;
1136 }
1137
fileDownloadTerminated(bool bSuccess,const QString & szRemoteUrl,const QString & szLocalFileName,const QString & szNick,const QString & szError,bool bQuiet)1138 void KviApplication::fileDownloadTerminated(
1139 bool bSuccess,
1140 const QString & szRemoteUrl,
1141 const QString & szLocalFileName,
1142 const QString & szNick,
1143 const QString & szError,
1144 bool bQuiet)
1145 {
1146
1147 KviPendingAvatarChange * pAvatar = findPendingAvatarChange(nullptr, szNick, szRemoteUrl);
1148
1149 if(pAvatar == nullptr)
1150 {
1151 // signal dcc completion only for NON-avatars
1152 // FIXME: This option is misnamed and misplaced in the options dialog :(
1153 // it seems to refer only to DCC while it refers to any file transfer
1154 if(KVI_OPTION_BOOL(KviOption_boolNotifyDccSendSuccessInNotifier) && (!bQuiet))
1155 {
1156 if(!g_pActiveWindow)
1157 return;
1158 if(g_pActiveWindow->hasAttention(KviWindow::MainWindowIsVisible))
1159 return;
1160 QString szMsg;
1161 int iIconId;
1162 if(!bSuccess)
1163 {
1164 iIconId = KviIconManager::DccError;
1165 if(szNick.isEmpty())
1166 szMsg = __tr2qs("File download failed");
1167 else
1168 szMsg = __tr2qs("File download from %1 failed").arg(szNick);
1169 szMsg += ": ";
1170 szMsg += szError;
1171 szMsg += " (";
1172 szMsg += szLocalFileName;
1173 szMsg += ")";
1174 }
1175 else
1176 {
1177 iIconId = KviIconManager::DccMsg;
1178 if(szNick.isEmpty())
1179 szMsg = __tr2qs("File download successfully complete");
1180 else
1181 szMsg = __tr2qs("File download from %1 successfully complete").arg(szNick);
1182 szMsg += " (";
1183 szMsg += szLocalFileName;
1184 szMsg += ")";
1185 }
1186 notifierMessage(nullptr, iIconId, KviQString::toHtmlEscaped(szMsg), KVI_OPTION_UINT(KviOption_uintNotifierAutoHideTime));
1187 }
1188 return;
1189 }
1190
1191 if(bSuccess)
1192 {
1193 if(windowExists(pAvatar->pConsole))
1194 {
1195 pAvatar->pConsole->setAvatar(
1196 pAvatar->szNick,
1197 pAvatar->szUser,
1198 pAvatar->szHost,
1199 szLocalFileName,
1200 (KviQString::equalCIN("http://", szRemoteUrl, 7) || KviQString::equalCIN("https://", szRemoteUrl, 8)) ? szRemoteUrl : QString());
1201 }
1202 }
1203 else
1204 {
1205 if((!_OUTPUT_MUTE) && (!bQuiet))
1206 {
1207 pAvatar->pConsole->output(KVI_OUT_AVATAR, __tr2qs("Avatar download failed for %Q!%Q@%Q and URL %Q: %Q"),
1208 &(pAvatar->szNick), &(pAvatar->szUser), &(pAvatar->szHost), &(szRemoteUrl), &(szError));
1209 }
1210 }
1211
1212 m_PendingAvatarChanges.erase(pAvatar);
1213 }
1214
1215 #ifdef COMPILE_PSEUDO_TRANSPARENCY
destroyPseudoTransparency()1216 void KviApplication::destroyPseudoTransparency()
1217 {
1218 if(g_pShadedParentGlobalDesktopBackground)
1219 {
1220 delete g_pShadedParentGlobalDesktopBackground;
1221 g_pShadedParentGlobalDesktopBackground = nullptr;
1222 }
1223 if(g_pShadedChildGlobalDesktopBackground)
1224 {
1225 delete g_pShadedChildGlobalDesktopBackground;
1226 g_pShadedChildGlobalDesktopBackground = nullptr;
1227 }
1228 }
1229
triggerUpdatePseudoTransparency()1230 void KviApplication::triggerUpdatePseudoTransparency()
1231 {
1232 if(m_bUpdatePseudoTransparencyPending)
1233 return;
1234 m_bUpdatePseudoTransparencyPending = true;
1235 QTimer::singleShot(0, this, SLOT(updatePseudoTransparency()));
1236 }
1237
createGlobalBackgrounds(QPixmap * pix)1238 void KviApplication::createGlobalBackgrounds(QPixmap * pix)
1239 {
1240 // create shaded copies...
1241 if(g_pShadedParentGlobalDesktopBackground)
1242 delete g_pShadedParentGlobalDesktopBackground;
1243 if(g_pShadedChildGlobalDesktopBackground)
1244 delete g_pShadedChildGlobalDesktopBackground;
1245 g_pShadedParentGlobalDesktopBackground = new QPixmap(pix->width(), pix->height());
1246 g_pShadedChildGlobalDesktopBackground = new QPixmap(pix->width(), pix->height());
1247 QPainter p;
1248 p.begin(g_pShadedParentGlobalDesktopBackground);
1249 p.drawPixmap(0, 0, *pix);
1250 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
1251 if(KVI_OPTION_UINT(KviOption_uintGlobalTransparencyParentFadeFactor) > 100)
1252 KVI_OPTION_UINT(KviOption_uintGlobalTransparencyParentFadeFactor) = 100;
1253 p.setOpacity((float)((float)KVI_OPTION_UINT(KviOption_uintGlobalTransparencyParentFadeFactor) / (float)100));
1254 p.fillRect(0, 0, pix->width(), pix->height(), QBrush(KVI_OPTION_COLOR(KviOption_colorGlobalTransparencyFade)));
1255 p.end();
1256
1257 p.begin(g_pShadedChildGlobalDesktopBackground);
1258 p.drawPixmap(0, 0, *pix);
1259 p.setCompositionMode(QPainter::CompositionMode_SourceAtop);
1260 if(KVI_OPTION_UINT(KviOption_uintGlobalTransparencyChildFadeFactor) > 100)
1261 KVI_OPTION_UINT(KviOption_uintGlobalTransparencyChildFadeFactor) = 100;
1262 p.setOpacity((float)((float)KVI_OPTION_UINT(KviOption_uintGlobalTransparencyChildFadeFactor) / (float)100));
1263 p.fillRect(0, 0, pix->width(), pix->height(), QBrush(KVI_OPTION_COLOR(KviOption_colorGlobalTransparencyFade)));
1264 p.end();
1265
1266 if(g_pMainWindow)
1267 g_pMainWindow->updatePseudoTransparency();
1268 }
1269 #endif //COMPILE_PSEUDO_TRANSPARENCY
1270
updatePseudoTransparency()1271 void KviApplication::updatePseudoTransparency()
1272 {
1273 #ifdef COMPILE_PSEUDO_TRANSPARENCY
1274 m_bUpdatePseudoTransparencyPending = false;
1275 if(KVI_OPTION_BOOL(KviOption_boolUseGlobalPseudoTransparency))
1276 {
1277 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1278 if(KVI_OPTION_BOOL(KviOption_boolUseWindowsDesktopForTransparency))
1279 {
1280 QSize size = g_pApp->desktop()->screenGeometry(g_pApp->desktop()->primaryScreen()).size();
1281 // get the Program Manager
1282 HWND hWnd = FindWindow(TEXT("Progman"), TEXT("Program Manager"));
1283 // Create and setup bitmap
1284 const HDC displayDc = GetDC(0);
1285 HDC bitmap_dc = CreateCompatibleDC(displayDc);
1286 HBITMAP bitmap = CreateCompatibleBitmap(displayDc, size.width(), size.height());
1287 HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
1288
1289 PrintWindow(hWnd, bitmap_dc, 0);
1290
1291 SelectObject(bitmap_dc, null_bitmap);
1292 DeleteDC(bitmap_dc);
1293 ReleaseDC(0, displayDc);
1294 QPixmap pix = QtWin::fromHBITMAP(bitmap);
1295
1296 DeleteObject(bitmap);
1297
1298 createGlobalBackgrounds(&pix);
1299 }
1300 else
1301 #endif // COMPILE_ON_WINDOWS || COMPILE_ON_MINGW
1302
1303 if(KVI_OPTION_PIXMAP(KviOption_pixmapGlobalTransparencyBackground).pixmap())
1304 {
1305 createGlobalBackgrounds(KVI_OPTION_PIXMAP(KviOption_pixmapGlobalTransparencyBackground).pixmap());
1306 }
1307 else
1308 {
1309 //destroy pseudo transparency pixmaps
1310 destroyPseudoTransparency();
1311 //if we get here, no pseudo transparency method can be used / is enabled.
1312 #ifdef COMPILE_X11_SUPPORT
1313 //under x11, we still have to check real transparency methods
1314 if(!KVI_OPTION_BOOL(KviOption_boolUseCompositingForTransparency))
1315 {
1316 //real transparency is off => turn off transparency support at all
1317 KVI_OPTION_BOOL(KviOption_boolUseGlobalPseudoTransparency) = false;
1318 }
1319 #else
1320 // on other platforms, no way to proceed
1321 KVI_OPTION_BOOL(KviOption_boolUseGlobalPseudoTransparency) = false;
1322 #endif // COMPILE_X11_SUPPORT
1323 }
1324 }
1325 else
1326 {
1327 //transparency is disabled
1328 //destroy pseudo transparency pixmaps
1329 destroyPseudoTransparency();
1330 //make sure real transparency is disabled
1331 KVI_OPTION_BOOL(KviOption_boolUseCompositingForTransparency) = false;
1332
1333 //update widgets
1334 if(g_pMainWindow)
1335 g_pMainWindow->updatePseudoTransparency();
1336 }
1337 #endif //COMPILE_PSEUDO_TRANSPARENCY
1338 }
1339
triggerUpdateGui()1340 void KviApplication::triggerUpdateGui()
1341 {
1342 if(m_bUpdateGuiPending)
1343 return;
1344 m_bUpdateGuiPending = true;
1345 QTimer::singleShot(0, this, SLOT(updateGui()));
1346 }
1347
updateGui()1348 void KviApplication::updateGui()
1349 {
1350 m_bUpdateGuiPending = false;
1351 // enforce our "icon in popups" option
1352 setAttribute(Qt::AA_DontShowIconsInMenus, !KVI_OPTION_BOOL(KviOption_boolShowIconsInPopupMenus));
1353 g_pMainWindow->applyOptions();
1354 }
1355
updateApplicationFont()1356 void KviApplication::updateApplicationFont()
1357 {
1358 if(KVI_OPTION_BOOL(KviOption_boolUseGlobalApplicationFont))
1359 {
1360 setFont(KVI_OPTION_FONT(KviOption_fontApplication));
1361 if(g_pMainWindow)
1362 g_pMainWindow->setFont(font());
1363 }
1364 else
1365 {
1366 setFont(m_fntDefaultFont);
1367 if(g_pMainWindow)
1368 g_pMainWindow->setFont(m_fntDefaultFont);
1369 }
1370 }
1371
loadRecentEntries()1372 void KviApplication::loadRecentEntries()
1373 {
1374 QString szTmp;
1375 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_RECENT);
1376 KviConfigurationFile cfg(szTmp, KviConfigurationFile::Read);
1377 *g_pRecentTopicList = cfg.readStringListEntry("RecentTopicList", QStringList());
1378 }
1379
saveRecentEntries()1380 void KviApplication::saveRecentEntries()
1381 {
1382 QString szTmp;
1383 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_RECENT);
1384 KviConfigurationFile cfg(szTmp, KviConfigurationFile::Write);
1385 cfg.writeEntry("RecentTopicList", *g_pRecentTopicList);
1386 }
1387
saveAvatarCache()1388 void KviApplication::saveAvatarCache()
1389 {
1390 QString szTmp;
1391 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_AVATARCACHE);
1392 KviAvatarCache::instance()->save(szTmp);
1393 }
1394
saveToolBars()1395 void KviApplication::saveToolBars()
1396 {
1397 QString szTmp;
1398 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_CUSTOMTOOLBARS);
1399 KviCustomToolBarManager::instance()->save(szTmp);
1400 }
1401
savePopups()1402 void KviApplication::savePopups()
1403 {
1404 QString szTmp;
1405 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_POPUPS);
1406 KviKvs::savePopups(szTmp);
1407 }
1408
saveInputHistory()1409 void KviApplication::saveInputHistory()
1410 {
1411 if(KVI_OPTION_BOOL(KviOption_boolEnableInputHistory))
1412 {
1413 QString szTmp;
1414 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_INPUTHISTORY);
1415 KviInputHistory::instance()->save(szTmp);
1416 }
1417 }
1418
saveAliases()1419 void KviApplication::saveAliases()
1420 {
1421 QString szTmp;
1422 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_ALIASES);
1423 KviKvs::saveAliases(szTmp);
1424 }
1425
saveScriptAddons()1426 void KviApplication::saveScriptAddons()
1427 {
1428 QString szTmp;
1429 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_SCRIPTADDONS);
1430 KviKvs::saveScriptAddons(szTmp);
1431 }
1432
saveTextIcons()1433 void KviApplication::saveTextIcons()
1434 {
1435 g_pTextIconManager->save();
1436 }
1437
saveAppEvents()1438 void KviApplication::saveAppEvents()
1439 {
1440 QString szTmp;
1441 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_EVENTS);
1442 KviKvs::saveAppEvents(szTmp);
1443 }
1444
saveRawEvents()1445 void KviApplication::saveRawEvents()
1446 {
1447 QString szTmp;
1448 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_RAWEVENTS);
1449 KviKvs::saveRawEvents(szTmp);
1450 }
1451
saveMediaTypes()1452 void KviApplication::saveMediaTypes()
1453 {
1454 QString szTmp;
1455 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_MEDIATYPES);
1456 g_pMediaManager->lock();
1457 g_pMediaManager->save(szTmp);
1458 g_pMediaManager->unlock();
1459 }
1460
saveIrcServerDataBase()1461 void KviApplication::saveIrcServerDataBase()
1462 {
1463 QString szTmp;
1464 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_SERVERDB);
1465 g_pServerDataBase->save(szTmp);
1466 }
1467
saveProxyDataBase()1468 void KviApplication::saveProxyDataBase()
1469 {
1470 QString szTmp;
1471 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_PROXYDB);
1472 g_pProxyDataBase->save(szTmp);
1473 }
1474
saveRegisteredUsers()1475 void KviApplication::saveRegisteredUsers()
1476 {
1477 QString szTmp;
1478 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_REGUSERDB);
1479 g_pRegisteredUserDataBase->save(szTmp);
1480 }
1481
saveRegisteredChannels()1482 void KviApplication::saveRegisteredChannels()
1483 {
1484 QString szTmp;
1485 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_REGCHANDB);
1486 g_pRegisteredChannelDataBase->save(szTmp);
1487 }
1488
saveNickServ()1489 void KviApplication::saveNickServ()
1490 {
1491 QString szTmp;
1492 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_NICKSERVDATABASE);
1493 g_pNickServRuleSet->save(szTmp);
1494 }
1495
saveIdentityProfiles()1496 void KviApplication::saveIdentityProfiles()
1497 {
1498 QString szTmp;
1499 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_PROFILESDATABASE);
1500 KviIdentityProfileSet::instance()->save(szTmp);
1501 }
1502
saveDefaultScripts()1503 void KviApplication::saveDefaultScripts()
1504 {
1505 QString szTmp;
1506 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_DEFAULTSCRIPT);
1507 KviDefaultScriptManager::instance()->save(szTmp);
1508 }
1509
saveSharedFiles()1510 void KviApplication::saveSharedFiles()
1511 {
1512 QString szTmp;
1513 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_SHAREDFILES);
1514 g_pSharedFilesManager->save(szTmp);
1515 }
1516
saveActions()1517 void KviApplication::saveActions()
1518 {
1519 QString szTmp;
1520 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_USERACTIONS);
1521 KviActionManager::instance()->save(szTmp);
1522 }
1523
saveIdentities()1524 void KviApplication::saveIdentities()
1525 {
1526 QString szTmp;
1527 getLocalKvircDirectory(szTmp, Config, KVI_CONFIGFILE_IDENTITIES);
1528 KviUserIdentityManager::instance()->save(szTmp);
1529 }
1530
saveConfiguration()1531 void KviApplication::saveConfiguration()
1532 {
1533 // this is NOT called when the application is closing down
1534 KviCustomToolBarManager::instance()->storeVisibilityState();
1535 saveOptions();
1536 saveIdentities();
1537 saveActions();
1538 saveIrcServerDataBase();
1539 saveProxyDataBase();
1540 saveRecentEntries();
1541 saveAvatarCache();
1542 saveAppEvents();
1543 saveRawEvents();
1544 saveMediaTypes();
1545 saveRegisteredUsers();
1546 saveRegisteredChannels();
1547 saveNickServ();
1548 saveIdentityProfiles();
1549 saveDefaultScripts();
1550 saveSharedFiles();
1551 savePopups();
1552 saveToolBars();
1553 saveAliases();
1554 saveTextIcons();
1555 saveInputHistory();
1556 saveScriptAddons();
1557 KviKvs::flushUserClasses();
1558 g_pWinPropertiesConfig->sync();
1559 }
1560
autoConnectToServers()1561 void KviApplication::autoConnectToServers()
1562 {
1563 KviPointerList<KviIrcServer> * pList = g_pServerDataBase->autoConnectOnStartupServers();
1564 if(pList)
1565 {
1566 for(auto & pServer : pList)
1567 {
1568 QString szCommand = "server -u \"id:";
1569 if(pServer.id().isEmpty())
1570 pServer.generateUniqueId();
1571 szCommand += pServer.id();
1572 szCommand += "\"";
1573 KviKvsScript::run(szCommand, activeConsole());
1574 }
1575 g_pServerDataBase->clearAutoConnectOnStartupServers();
1576 }
1577
1578 KviPointerList<KviIrcNetwork> * pListNet = g_pServerDataBase->autoConnectOnStartupNetworks();
1579 if(pListNet)
1580 {
1581 for(auto & pNetwork : pListNet)
1582 {
1583 QString szCommandx = "server -u \"net:";
1584 szCommandx += pNetwork.name();
1585 szCommandx += "\"";
1586 KviKvsScript::run(szCommandx, activeConsole());
1587 }
1588 g_pServerDataBase->clearAutoConnectOnStartupNetworks();
1589 }
1590 }
1591
createFrame()1592 void KviApplication::createFrame()
1593 {
1594 Q_ASSERT(g_pMainWindow == nullptr);
1595
1596 #if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
1597 if(KVI_OPTION_BOOL(KviOption_boolShowTaskBarButton))
1598 new KviMainWindow(0);
1599 else
1600 new KviMainWindow(new QWidget(0, 0));
1601 #else
1602 new KviMainWindow(nullptr);
1603 #endif
1604
1605 Q_ASSERT(g_pMainWindow != nullptr);
1606
1607 g_pMainWindow->createNewConsole(true);
1608
1609 if(!m_szExecAfterStartup.isEmpty())
1610 {
1611 KviKvsScript::run(m_szExecAfterStartup, g_pMainWindow->firstConsole());
1612 m_szExecAfterStartup = "";
1613 }
1614
1615 // auto connect to servers if needed
1616 if(g_pServerDataBase->autoConnectOnStartupServers() || g_pServerDataBase->autoConnectOnStartupNetworks())
1617 autoConnectToServers();
1618
1619 if(KVI_OPTION_BOOL(KviOption_boolShowDockExtension))
1620 g_pMainWindow->executeInternalCommand(KVI_INTERNALCOMMAND_TRAYICON_SHOW);
1621
1622 if(KVI_OPTION_BOOL(KviOption_boolStartupMinimized))
1623 g_pMainWindow->showMinimized();
1624 else
1625 g_pMainWindow->show();
1626 }
1627
connectionExists(KviIrcConnection * pConn)1628 bool KviApplication::connectionExists(KviIrcConnection * pConn)
1629 {
1630 for(auto & it : g_pGlobalWindowDict)
1631 {
1632 if(it.second->connection() == pConn)
1633 return true;
1634 }
1635 return false;
1636 }
1637
windowExists(KviWindow * pWnd)1638 bool KviApplication::windowExists(KviWindow * pWnd)
1639 {
1640 for(auto & it : g_pGlobalWindowDict)
1641 {
1642 if(it.second == pWnd)
1643 return true;
1644 }
1645 return false;
1646 }
1647
windowCount()1648 unsigned int KviApplication::windowCount()
1649 {
1650 return g_pGlobalWindowDict.size();
1651 }
1652
findConsole(QString & szServer,QString & szNick)1653 KviConsoleWindow * KviApplication::findConsole(QString & szServer, QString & szNick)
1654 {
1655 for(auto & it : g_pGlobalWindowDict)
1656 {
1657 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1658 if(!(pWindow && pWindow->type() == KviWindow::Console && pWindow->isConnected()))
1659 continue;
1660
1661 if(!szServer.isEmpty())
1662 {
1663 if(KviQString::equalCI(szServer, pWindow->connection()->currentServerName()))
1664 {
1665 if(szNick.isEmpty())
1666 return pWindow;
1667
1668 if(KviQString::equalCI(szNick, pWindow->connection()->currentNickName()))
1669 return pWindow;
1670 }
1671 }
1672 else
1673 {
1674 if(!szNick.isEmpty())
1675 {
1676 if(KviQString::equalCI(szNick, pWindow->connection()->currentNickName()))
1677 return pWindow;
1678 }
1679 }
1680 }
1681 return nullptr;
1682 }
1683
restartLagMeters()1684 void KviApplication::restartLagMeters()
1685 {
1686 for(auto & it : g_pGlobalWindowDict)
1687 {
1688 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1689 if(pWindow && pWindow->type() == KviWindow::Console && pWindow->connection())
1690 pWindow->connection()->restartLagMeter();
1691 }
1692 }
1693
restartNotifyLists()1694 void KviApplication::restartNotifyLists()
1695 {
1696 for(auto & it : g_pGlobalWindowDict)
1697 {
1698 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1699 if(pWindow && pWindow->type() == KviWindow::Console && pWindow->connection())
1700 pWindow->connection()->restartNotifyList();
1701 }
1702 }
1703
resetAvatarForMatchingUsers(KviRegisteredUser * pUser)1704 void KviApplication::resetAvatarForMatchingUsers(KviRegisteredUser * pUser)
1705 {
1706 for(auto & it : g_pGlobalWindowDict)
1707 {
1708 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1709 if(pWindow && pWindow->type() == KviWindow::Console)
1710 pWindow->resetAvatarForMatchingUsers(pUser);
1711 }
1712 }
1713
findConsole(unsigned int uIrcContextId)1714 KviConsoleWindow * KviApplication::findConsole(unsigned int uIrcContextId)
1715 {
1716 for(auto & it : g_pGlobalWindowDict)
1717 {
1718 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1719 if(pWindow && pWindow->context()->id() == uIrcContextId)
1720 return pWindow;
1721 }
1722 return nullptr;
1723 }
1724
topmostConnectedConsole()1725 KviConsoleWindow * KviApplication::topmostConnectedConsole()
1726 {
1727 // check the foreground window console
1728
1729 KviConsoleWindow * pConsole = activeConsole();
1730 if(!pConsole)
1731 return nullptr;
1732 if(pConsole->isConnected())
1733 return pConsole;
1734
1735 // try ANY connected console
1736
1737 for(auto & it : g_pGlobalWindowDict)
1738 {
1739 KviConsoleWindow * pWindow = dynamic_cast<KviConsoleWindow *>(it.second);
1740 if(pWindow && pWindow->type() == KviWindow::Console && pWindow->isConnected())
1741 return pWindow;
1742 }
1743
1744 return nullptr;
1745 }
1746
findWindow(const QString & szWindowId)1747 KviWindow * KviApplication::findWindow(const QString & szWindowId)
1748 {
1749 auto search = g_pGlobalWindowDict.find(szWindowId);
1750 return search != g_pGlobalWindowDict.end() ? search->second : nullptr;
1751 }
1752
findWindowByCaption(const QString & szWindowCaption,int iContextId)1753 KviWindow * KviApplication::findWindowByCaption(const QString & szWindowCaption, int iContextId)
1754 {
1755 for(auto & it : g_pGlobalWindowDict)
1756 {
1757 if(KviQString::equalCI(szWindowCaption, it.second->plainTextCaption()) && (iContextId == -1 || it.second->context()->id() == static_cast<uint>(iContextId)))
1758 return it.second;
1759 }
1760
1761 return nullptr;
1762 }
1763
registerWindow(KviWindow * pWnd)1764 void KviApplication::registerWindow(KviWindow * pWnd)
1765 {
1766 g_pGlobalWindowDict.emplace(pWnd->id(), pWnd);
1767 }
1768
unregisterWindow(KviWindow * pWnd)1769 void KviApplication::unregisterWindow(KviWindow * pWnd)
1770 {
1771 g_pGlobalWindowDict.erase(pWnd->id());
1772 }
1773
activeConsole()1774 KviConsoleWindow * KviApplication::activeConsole()
1775 {
1776 if(!g_pMainWindow)
1777 return nullptr;
1778 if(g_pActiveWindow)
1779 {
1780 if(g_pActiveWindow->console())
1781 return g_pActiveWindow->console();
1782 }
1783 return g_pMainWindow->firstConsole();
1784 }
1785
1786 //
1787 // RECENT STUFF LISTS & POPUPS HANDLING
1788 //
1789
1790 // Helper for KviApplication::addRecent*()
merge_to_stringlist_option(const QString & szItem,int iOption,int iMaxEntries)1791 static void merge_to_stringlist_option(const QString & szItem, int iOption, int iMaxEntries)
1792 {
1793 for(QStringList::Iterator it = KVI_OPTION_STRINGLIST(iOption).begin();
1794 it != KVI_OPTION_STRINGLIST(iOption).end(); ++it)
1795 {
1796 // Do a case-insensitive search (for nicknames, servers, and channels)
1797 if(!QString::compare(szItem.toLower(), (*it).toLower()))
1798 {
1799 // In the recent list, remove and put as first so more recent items
1800 // are always first
1801 it = KVI_OPTION_STRINGLIST(iOption).erase(it);
1802 --it;
1803 }
1804 }
1805 while(KVI_OPTION_STRINGLIST(iOption).count() >= iMaxEntries)
1806 {
1807 KVI_OPTION_STRINGLIST(iOption)
1808 .erase(KVI_OPTION_STRINGLIST(iOption).isEmpty() ? KVI_OPTION_STRINGLIST(iOption).end() : --KVI_OPTION_STRINGLIST(iOption).end());
1809 }
1810 KVI_OPTION_STRINGLIST(iOption)
1811 .prepend(szItem);
1812 }
1813
addRecentUrl(const QString & szText)1814 void KviApplication::addRecentUrl(const QString & szText)
1815 {
1816 merge_to_stringlist_option(szText, KviOption_stringlistRecentIrcUrls, 50);
1817 emit(recentUrlsChanged());
1818 }
1819
addRecentNickname(const QString & szNewNick)1820 void KviApplication::addRecentNickname(const QString & szNewNick)
1821 {
1822 merge_to_stringlist_option(szNewNick, KviOption_stringlistRecentNicknames, KVI_MAX_RECENT_NICKNAMES);
1823 }
1824
addRecentChannel(const QString & szChan,const QString & szNet)1825 void KviApplication::addRecentChannel(const QString & szChan, const QString & szNet)
1826 {
1827 if(!m_pRecentChannelDict)
1828 buildRecentChannels();
1829
1830 QStringList * pList = m_pRecentChannelDict->find(szNet);
1831 if(!pList)
1832 {
1833 pList = new QStringList(szChan);
1834 m_pRecentChannelDict->insert(szNet, pList);
1835 }
1836
1837 if(!pList->contains(szChan))
1838 pList->append(szChan);
1839 }
1840
buildRecentChannels()1841 void KviApplication::buildRecentChannels()
1842 {
1843 if(m_pRecentChannelDict)
1844 delete m_pRecentChannelDict;
1845
1846 m_pRecentChannelDict = new KviPointerHashTable<QString, QStringList>;
1847 m_pRecentChannelDict->setAutoDelete(true);
1848
1849 QString szChan, szNet;
1850
1851 for(auto & it : KVI_OPTION_STRINGLIST(KviOption_stringlistRecentChannels))
1852 {
1853 if(it.isEmpty())
1854 continue;
1855
1856 szChan = it.section(KVI_RECENT_CHANNELS_SEPARATOR, 0, 0);
1857 szNet = it.section(KVI_RECENT_CHANNELS_SEPARATOR, 1);
1858
1859 if(szNet.isEmpty())
1860 continue;
1861
1862 QStringList * pList = m_pRecentChannelDict->find(szNet);
1863 if(!pList)
1864 {
1865 pList = new QStringList(szChan);
1866 m_pRecentChannelDict->insert(szNet, pList);
1867 }
1868
1869 if(!pList->contains(szChan))
1870 pList->append(szChan);
1871 }
1872 }
1873
saveRecentChannels()1874 void KviApplication::saveRecentChannels()
1875 {
1876 if(!m_pRecentChannelDict)
1877 return;
1878
1879 QString szTmp;
1880
1881 KVI_OPTION_STRINGLIST(KviOption_stringlistRecentChannels)
1882 .clear();
1883
1884 KviPointerHashTableIterator<QString, QStringList> it(*m_pRecentChannelDict);
1885
1886 for(; it.current(); ++it)
1887 {
1888 for(QStringList::Iterator it_str = it.current()->begin(); it_str != it.current()->end(); ++it_str)
1889 {
1890 szTmp = *it_str;
1891 szTmp.append(KVI_RECENT_CHANNELS_SEPARATOR);
1892 szTmp.append(it.currentKey());
1893 KVI_OPTION_STRINGLIST(KviOption_stringlistRecentChannels)
1894 .append(szTmp);
1895 }
1896 }
1897 }
1898
recentChannelsForNetwork(const QString & szNet)1899 QStringList * KviApplication::recentChannelsForNetwork(const QString & szNet)
1900 {
1901 if(!m_pRecentChannelDict)
1902 buildRecentChannels();
1903 return m_pRecentChannelDict->find(szNet);
1904 }
1905
addRecentServer(const QString & szServer)1906 void KviApplication::addRecentServer(const QString & szServer)
1907 {
1908 merge_to_stringlist_option(szServer, KviOption_stringlistRecentServers, KVI_MAX_RECENT_SERVERS);
1909 }
1910
fillRecentServersPopup(QMenu * pMenu)1911 void KviApplication::fillRecentServersPopup(QMenu * pMenu)
1912 {
1913 // FIXME: #warning "MAYBE DISABLE THE SERVERS THAT WE ARE ALREADY CONNECTED TO ?"
1914 pMenu->clear();
1915 for(auto & it : KVI_OPTION_STRINGLIST(KviOption_stringlistRecentServers))
1916 {
1917 if(it == "")
1918 continue;
1919 pMenu->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Server)), it);
1920 }
1921 }
1922
fillRecentNicknamesPopup(QMenu * pMenu,KviConsoleWindow * pConsole)1923 void KviApplication::fillRecentNicknamesPopup(QMenu * pMenu, KviConsoleWindow * pConsole)
1924 {
1925 pMenu->clear();
1926 QAction * pAction;
1927 bool bAlreadyFound = false;
1928 for(auto & it : KVI_OPTION_STRINGLIST(KviOption_stringlistRecentNicknames))
1929 {
1930 if(it == "")
1931 continue;
1932 pAction = pMenu->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Nick)), it);
1933 if(!pConsole->isConnected())
1934 pAction->setEnabled(false);
1935 else
1936 {
1937 if(!bAlreadyFound)
1938 {
1939 bool bIsCurrent = KviQString::equalCS(pConsole->connection()->currentNickName(), it);
1940 pAction->setEnabled(!bIsCurrent);
1941 if(bIsCurrent)
1942 bAlreadyFound = true;
1943 }
1944 }
1945 }
1946 }
1947
fillRecentChannelsPopup(QMenu * pMenu,KviConsoleWindow * pConsole)1948 void KviApplication::fillRecentChannelsPopup(QMenu * pMenu, KviConsoleWindow * pConsole)
1949 {
1950 pMenu->clear();
1951 QAction * pAction;
1952 QStringList * pList = recentChannelsForNetwork(pConsole->currentNetworkName());
1953 if(pList)
1954 {
1955 for(auto & it : *pList)
1956 {
1957 if(it == "")
1958 continue; // ?
1959 pAction = pMenu->addAction(*(g_pIconManager->getSmallIcon(KviIconManager::Channel)), it);
1960 if(!pConsole->isConnected())
1961 pAction->setEnabled(false);
1962 else
1963 pAction->setEnabled(!(pConsole->connection()->findChannel(it)));
1964 }
1965 }
1966 }
1967
heartbeat(kvi_time_t tNow)1968 void KviApplication::heartbeat(kvi_time_t tNow)
1969 {
1970 const struct tm * pTm = localtime(&tNow);
1971
1972 if(g_pApp->topmostConnectedConsole())
1973 {
1974 // FIXME: this has huge precision problems...
1975 KVI_OPTION_UINT(KviOption_uintTotalConnectionTime)
1976 ++;
1977 }
1978
1979 if(pTm && !pTm->tm_hour && !pTm->tm_min && !pTm->tm_sec)
1980 {
1981 for(auto & it : g_pGlobalWindowDict)
1982 {
1983 if(it.second->view() && it.second->view()->isLogging())
1984 it.second->view()->startLogging(nullptr);
1985 }
1986 }
1987 }
1988
timerEvent(QTimerEvent * e)1989 void KviApplication::timerEvent(QTimerEvent * e)
1990 {
1991 if(e->timerId() != m_iHeartbeatTimerId)
1992 {
1993 QObject::timerEvent(e);
1994 return;
1995 }
1996
1997 // our heartbeat
1998
1999 kvi_time_t tNow = kvi_unixTime();
2000
2001 heartbeat(tNow);
2002 }
2003
2004 // qvariant.h uses this, and it is included by the qt generated moc file for Qt >= 3.0.0
2005 #ifdef Bool
2006 #undef Bool
2007 #endif
2008